// ----------------------------------------------------------------------- void DisplayObjectErrorsAndWarnings(List <ErrorWarning> errors, List <ErrorWarning> warnings) { // -- Determine wich objects have errors or warnings -- var objectIds = P.append(P.map(e => e.ObjectId, errors), P.map(w => w.ObjectId, warnings)); objectIds = P.removeDuplicates(objectIds); // -- Display the errors/warnings on the objects in the graph -- foreach (var id in objectIds) { // -- Determine if node is visible -- var node = IStorage[id]; if (!DisplayRoot.IsParentOf(node)) { continue; } var pos = node.GlobalPosition; if (!VisibleGraphRect.Contains(pos)) { continue; } // -- Determine errors/warnings for this particular node -- var nodeErrors = P.filter(e => e.ObjectId == id, errors); var nodeWarnings = P.filter(w => w.ObjectId == id, warnings); // -- Display the appropriate error/warning icon -- var r = Math3D.BuildRectCenteredAt(pos, 32f, 32f); r = myGraphics.TranslateAndScale(r); DisplayErrorsAndWarningAt(r, nodeErrors, nodeWarnings); } }
// ---------------------------------------------------------------------- public static iCS_EditorObject WrapMultiSelectionInPackage(iCS_IStorage iStorage) { if (iStorage == null) { return(null); } if (!IsCreationAllowed()) { return(null); } var selectedObjects = iStorage.FilterMultiSelectionForWrapInPackage(); if (selectedObjects == null || selectedObjects.Length == 0) { return(null); } iCS_EditorObject package = null; OpenTransaction(iStorage); try { iStorage.AnimateGraph(null, _ => { var childrenRects = P.map(n => n.GlobalRect, selectedObjects); package = iStorage.WrapInPackage(selectedObjects); if (package != null) { var r = Math3D.Union(childrenRects); var pos = Math3D.Middle(r); package.SetInitialPosition(Math3D.Middle(r)); iStorage.ForcedRelayoutOfTree(); package.myAnimatedRect.StartValue = BuildRect(pos, Vector2.zero); for (int i = 0; i < selectedObjects.Length; ++i) { selectedObjects[i].SetInitialPosition(iCS_EditorObject.PositionFrom(childrenRects[i])); selectedObjects[i].LocalSize = iCS_EditorObject.SizeFrom(childrenRects[i]); } iStorage.ForcedRelayoutOfTree(); iStorage.ReduceCollisionOffset(); } else { Debug.LogWarning("iCanScript: Unable to create a suitable package."); } } ); } catch (System.Exception) { CancelTransaction(iStorage); return(null); } if (package == null) { CancelTransaction(iStorage); return(null); } CloseTransaction(iStorage, "Wrap Selection"); SystemEvents.AnnounceVisualScriptElementAdded(package); return(package); }
// ------------------------------------------------------------------- /// Generate the code for the class fields. /// /// @param indentSize The indentation needed for the class definition. /// @return The class fileds code. /// string GenerateClassFields(int indentSize) { var indent = ToIndent(indentSize); var result = new StringBuilder(1024); // Fields var publicFields = P.filter(f => f.IsPublic, myFields); var privateFields = P.filter(f => !f.IsPublic, myFields); if (publicFields.Count != 0) { result.Append(GenerateCodeBanner(indent, "PUBLIC FIELDS")); foreach (var f in publicFields) { result.Append(f.GenerateCode(indentSize)); } result.Append("\n"); } if (privateFields.Count != 0) { result.Append(GenerateCodeBanner(indent, "PRIVATE FIELDS")); foreach (var f in privateFields) { result.Append(f.GenerateCode(indentSize)); } result.Append("\n"); } return(result.ToString()); }
// ---------------------------------------------------------------------- // Updates the global Rect arround the children nodes. It is assume that // the children have previously been layed out. The anchor position and // layout size will be updated accordingly. // NOTE: This function must not be called for iconized nodes. // ---------------------------------------------------------------------- // Revised: feb 10, 2014 public void WrapAroundChildrenNodes() { // Nothing to do if node is not visible. if (!IsVisibleInLayout || IsIconizedInLayout) { return; } if (IsFoldedInLayout) { var r = NodeRectFromChildrenRectWithMargins(new Rect(0, 0, 0, 0)); LocalSize = new Vector2(r.width, r.height); return; } var childNodes = BuildListOfVisibleChildNodes(n => !n.IsFloating); var childRects = P.map(n => n.LocalRect, childNodes); // WrapAroundChildRects(childRects); var totalChildRect = GetRectWithMargins(childRects); var parentRect = NodeRectFromChildrenRectWithMargins(totalChildRect); var center = PositionFrom(parentRect); WrappingOffset = center; LocalSize = SizeFrom(parentRect); // Restore child global position. for (int i = 0; i < childNodes.Length; ++i) { childNodes[i].CollisionOffset -= center; } }
// ---------------------------------------------------------------------- public static void DeleteKeepChildren(iCS_EditorObject obj) { if (!IsDeletionAllowed()) { return; } var iStorage = obj.IStorage; OpenTransaction(iStorage); try { var newParent = obj.ParentNode; var childNodes = obj.BuildListOfChildNodes(_ => true); var childPos = P.map(n => n.GlobalPosition, childNodes); iStorage.AnimateGraph(obj, _ => { // Move the selection to the parent node var parent = obj.ParentNode; iStorage.SelectedObject = parent; P.forEach(n => { iStorage.ChangeParent(n, newParent); }, childNodes); SystemEvents.AnnounceVisualScriptElementWillBeRemoved(obj); iStorage.DestroyInstance(obj.InstanceId); P.zipWith((n, p) => { n.LocalAnchorFromGlobalPosition = p; }, childNodes, childPos); iStorage.ForcedRelayoutOfTree(); } ); } catch (System.Exception) { CancelTransaction(iStorage); return; } CloseTransaction(iStorage, "Delete " + obj.DisplayName); }
// ------------------------------------------------------------------------- public bool ToggleMultiSelection(iCS_EditorObject obj) { if (!IsMultiSelectionAllowed(obj)) { return(false); } if (IsSelectedOrMultiSelected(obj)) { RemoveFromSelectedObjects(obj); return(false); } // Ignore display root if selected if (P.length(mySelectedObjects) == 1 && mySelectedObjects[0] == DisplayRoot) { mySelectedObjects.Clear(); } // Update SelectedObject if multi-select list is empty. if (P.length(mySelectedObjects) == 0) { SelectedObject = obj; } else { AddToSelectedObjects(obj); } return(true); }
// ---------------------------------------------------------------------- public List <iCS_EditorObject> Filter(Func <iCS_EditorObject, bool> cond) { return(P.filter( c => c != null && c.IsValid && cond(c), EditorObjects )); }
// =================================================================== /// Return the first shared parent between two visual script objects. /// /// @param vsObj1 The first visual script object. /// @param vsObj2 The second visual script object. /// @return The first shared parent. /// public static iCS_EditorObject GetCommonParent(iCS_EditorObject vsObj1, iCS_EditorObject vsObj2) { if (vsObj1 == null) { return(vsObj2); } if (vsObj2 == null) { return(vsObj1); } var l1 = BuildListOfParentNodes(vsObj1); var l2 = BuildListOfParentNodes(vsObj2); l1 = P.insertAt(vsObj1, l1.Length, l1); l2 = P.insertAt(vsObj2, l2.Length, l2); iCS_EditorObject commonParent = null; for (int i = 0; i < l1.Length && i < l2.Length; ++i) { if (l1[i] != l2[i]) { break; } commonParent = l1[i]; } return(commonParent); }
// ======================================================================= // Errors/Warning display functionality // ----------------------------------------------------------------------- void DisplayErrorsAndWarnings() { // -- Nothing to display if no error/warning exists -- if (!ErrorController.IsErrorOrWarning) { return; } // -- Update the repaint timer -- UpdateErrorRepaintTimer(); // -- Get errors/warnings for this visual script -- var errors = ErrorController.GetErrorsFor(VisualScript); var warnings = ErrorController.GetWarningsFor(VisualScript); // -- Filter out invalid objects -- errors = P.filter(e => IStorage.IsValid(e.ObjectId), errors); warnings = P.filter(w => IStorage.IsValid(w.ObjectId), warnings); // -- Return if no errors or warnings -- if ((errors.Count + warnings.Count) == 0) { return; } // -- Show scene errors/warnings -- DisplayVisualScriptErrorsAndWarnings(errors, warnings); // -- Show errors/warnings on the nodes of our visual script -- DisplayObjectErrorsAndWarnings(errors, warnings); }
// ---------------------------------------------------------------------- public void ReduceChildrenAnchorPosition() { var childNodes = BuildListOfChildNodes(_ => true); if (childNodes.Length == 0) { return; } // Reduce Local anchor position var max = P.fold( (acc, n) => { var lap = n.LocalAnchorPosition; return(new Vector2(Mathf.Max(acc.x, lap.x), Mathf.Max(acc.y, lap.y))); }, childNodes[0].LocalAnchorPosition, childNodes ); var min = P.fold( (acc, n) => { var lap = n.LocalAnchorPosition; return(new Vector2(Mathf.Min(acc.x, lap.x), Mathf.Min(acc.y, lap.y))); }, childNodes[0].LocalAnchorPosition, childNodes ); var delta = (max - min) / 2; var offset = max - delta; P.forEach(n => n.LocalAnchorPosition = n.LocalAnchorPosition - offset, childNodes); }
// ======================================================================= // General Iterations // ----------------------------------------------------------------------- // Executes for each valid engine object public static void ForEach(Action <iCS_EngineObject> fnc, iCS_IVisualScriptData vsd) { P.forEach(o => { if (IsValid(o, vsd)) { fnc(o); } }, vsd.EngineObjects); }
// ================================================================================= /// Ask the user to provide the needed information to create a project. void CreatePackage() { // -- Header. -- ourHeaderTextStyle.normal.textColor = ourSelectedColor; GUI.Label(ourCreatePackageTextRect, ourCreatePackageText, ourHeaderTextStyle); // -- Project fields. -- myNewPackage.PackageName = EditorGUI.TextField(GetFieldPosition(0), "Package Name", myNewPackage.PackageName, ourTextFieldStyle); var allPackages = BuildPackageSelection(); var packageNames = P.map(p => p == null ? "-- None --" : p.PackageName, allPackages); myParentSelection = EditorGUI.Popup(GetFieldPosition(1), "Parent Package", myParentSelection, packageNames /*, ourPopupStyle*/); myNewPackage.ParentPackage = allPackages[myParentSelection]; EditorGUI.BeginDisabledGroup(true); EditorGUI.TextField(GetFieldPosition(3), "Package Folder", myNewPackage.GetRelativePackageFolder(), ourTextFieldStyle); EditorGUI.TextField(GetFieldPosition(4), "Engine Namespace", myNewPackage.GetEngineNamespace(), ourTextFieldStyle); EditorGUI.TextField(GetFieldPosition(5), "Editor Namespace", myNewPackage.GetEditorNamespace(), ourTextFieldStyle); EditorGUI.EndDisabledGroup(); // -- Compute button area. -- var totalWidth = ourListAreaRect.width; var width = totalWidth / 4f; var buttonWidth = width - kSpacer; var buttonXMax = ourListAreaRect.xMax; var buttonY = position.height - kSpacer - 20.0f; // -- Show project already exists error message. -- bool packageAlreadyExists = myNewPackage.AlreadyExists; if (packageAlreadyExists) { var x = buttonXMax - 2f * width; var y = buttonY - 60f; var w = 2f * width - kSpacer; var h = 40f; EditorGUI.HelpBox(new Rect(x, y, w, h), "PROJECT ALREADY EXISTS:\n--> " + myNewPackage.GetRelativeFileNamePath(), MessageType.Error); } // -- Process "Save" button. -- EditorGUI.BeginDisabledGroup(packageAlreadyExists); if (GUI.Button(new Rect(buttonXMax - width, buttonY, buttonWidth, 20.0f), "Save")) { if (!packageAlreadyExists) { myNewPackage.Save(); PackageController.UpdatePackageDatabase(); myMenuSelection = 0; } } EditorGUI.EndDisabledGroup(); // -- Process "Cancel" button. -- if (GUI.Button(new Rect(buttonXMax - 2f * width, buttonY, buttonWidth, 20.0f), "Cancel")) { myMenuSelection = 0; } }
public Type[] GetParamTypes(List <iCS_EngineObject> engineObjects) { iCS_EngineObject[] ports = GetChildPortsExcludingControlPorts(engineObjects); Type[] result = new Type[NbOfParams]; for (int i = 0; i < P.length(result); ++i) { result[i] = ports[i].RuntimeType; } return(result); }
// =================================================================== /// Builds a list of parent nodes. /// /// The list is sorted from the top most parent to the bottom most leaf. /// /// @param vsObject The object from which to build the list. /// @return An array of parents where index 0 is the top most parent. // public static iCS_EditorObject[] BuildListOfParentNodes(iCS_EditorObject vsObject) { var result = new List <iCS_EditorObject>(); for (var parent = vsObject.ParentNode; parent != null; parent = parent.ParentNode) { result.Add(parent); } return(P.reverse(result).ToArray()); }
// ---------------------------------------------------------------------- private void ResolveCollisionOnChildrenImp(iCS_EditorObject[] children, ref Rect[] childRect) { // Resolve collisions. int r = 0; bool didCollide = true; while (didCollide) { didCollide = false; iCS_EditorObject lowest = null; for (int i = 0; i < children.Length - 1; ++i) { var c1 = children[i]; for (int j = i + 1; j < P.length(children); ++j) { var c2 = children[j]; if (c1.ResolveCollisionBetweenTwoNodes(c2, ref childRect[i], ref childRect[j])) { didCollide = true; #if NEW_COLLISION if (c1.LayoutPriority < c2.LayoutPriority) { c2.LayoutPriority = c1.LayoutPriority + 1; } if (c2.LayoutPriority < c1.LayoutPriority) { c1.LayoutPriority = c2.LayoutPriority + 1; } #else --c1.LayoutPriority; --c2.LayoutPriority; #endif } if (c1.LayoutPriority > c2.LayoutPriority) { lowest = c1; } else if (c2.LayoutPriority > c1.LayoutPriority) { lowest = c2; } } } if (++r > 10) { if (lowest == null || lowest.LayoutPriority <= 1) { break; } lowest.LayoutPriority = lowest.LayoutPriority - 1; r = 0; } } }
// ---------------------------------------------------------------------- public void FilterWith(Func <iCS_EditorObject, Action <iCS_EditorObject>, bool> cond, Action <iCS_EditorObject> fnc) { P.filterWith( c => c != null && c.IsValid && cond(c, fnc), fnc, EditorObjects ); }
// ------------------------------------------------------------------- /// Builds the list of function parameters. protected override void BuildParameterList() { var parameters = GetParameters(VSObject); parameters = P.filter(p => p.IsFixDataPort, parameters); myParameters = new FunctionDefinitionParameter[parameters.Length]; foreach (var p in parameters) { myParameters[p.PortIndex] = new FunctionDefinitionParameter(p, this); } }
// ====================================================================== // Collision Functions // ---------------------------------------------------------------------- // Resolves the collision between children. "true" is returned if a // collision has occured. // ---------------------------------------------------------------------- public void ResolveCollisionOnChildrenNodes() { // Get a snapshot of the children state. var children = BuildListOfVisibleChildNodes(c => !c.IsFloating); var childPos = P.map(n => n.LocalAnchorPosition + n.WrappingOffset, children); var childRect = P.map(n => BuildRect(n.LocalAnchorPosition + n.WrappingOffset, n.LocalSize), children); // Resolve collisions. ResolveCollisionOnChildrenImp(children, ref childRect); // Update child position. for (int i = 0; i < P.length(children); ++i) { children[i].CollisionOffset = PositionFrom(childRect[i]) - childPos[i]; } }
// ---------------------------------------------------------------------- public static string[] FilterAndSort(string search, string[] lst, float minScore) { var scores = GetScores(search, lst); var ts = P.zip(scores, lst); var filtered = P.filter((t) => t.Item1 > minScore, ts); P.sort( filtered, (t1, t2) => { var diff = t2.Item1 - t1.Item1; return(Math3D.IsZero(diff) ? 0 : (diff < 0 ? -1 : 1)); } ); return(P.map((t) => P.uncurry((score, str) => str, t), filtered)); }
// ---------------------------------------------------------------------- public static void AddEngineObject(iCS_IVisualScriptData vsd, iCS_EngineObject toAdd) { // Try to find an available empty slot. int emptySlot = P.findFirst(o => o.InstanceId == -1, (i, o) => i, -1, vsd.EngineObjects); // Grow engine object array if no free slot exists. if (emptySlot != -1) { toAdd.InstanceId = emptySlot; vsd.EngineObjects[emptySlot] = toAdd; return; } toAdd.InstanceId = P.length(vsd.EngineObjects); vsd.EngineObjects.Add(toAdd); }
// ---------------------------------------------------------------------- public static string[] SortAndTake(string search, string[] lst, int maxNbOfResults) { var scores = GetScores(search, lst); var toSort = P.zip(scores, lst); P.sort( toSort, (t1, t2) => { var diff = t2.Item1 - t1.Item1; return(Math3D.IsZero(diff) ? 0 : (diff < 0 ? -1 : 1)); } ); var result = P.take(maxNbOfResults, toSort); return(P.map((t) => P.uncurry((score, str) => str, t), result)); }
// ------------------------------------------------------------------- /// Builds the list of function parameters. protected virtual void BuildParameterList() { var parameters = GetParameters(VSObject); parameters = P.filter(p => p.IsInDataPort && p.ProducerPort == null, parameters); myParameters = new FunctionDefinitionParameter[parameters.Length]; foreach (var p in parameters) { if (p.PortIndex >= parameters.Length) { Debug.LogWarning("iCanScript: Internal error: Port index out of range: " + p.PortIndex); } else { myParameters[p.PortIndex] = new FunctionDefinitionParameter(p, this); } } }
// ------------------------------------------------------------------------- /// Returns the list of enable ports that affects the function call /// /// @param funcNode Visual script representing the function call. /// @return Array of all enable ports that affects the function call. /// public static iCS_EditorObject[] GetAllRelatedEnablePorts(iCS_EditorObject funcNode) { // -- Gather all enable ports -- var enablePorts = new List <iCS_EditorObject>(); while (funcNode != null) { var enables = GetEnablePorts(funcNode); if (enables.Length != 0 && !IsAtLeastOneEnableAlwaysTrue(enables)) { enables = P.filter(e => !IsEnableAlwaysFalse(e), enables); enablePorts.AddRange(enables); } funcNode = funcNode.ParentNode; } // -- Reorder ports starting from parent -- enablePorts.Reverse(); return(enablePorts.ToArray()); }
// ---------------------------------------------------------------------- void CanvasMenu(iCS_EditorObject selectedObject, iCS_IStorage iStorage) { // Don't show any menu if behaviour not visible. if (selectedObject.IsIconizedInLayout || selectedObject.IsFoldedInLayout) { return; } iCS_MenuContext[] menu = new iCS_MenuContext[3]; menu[0] = new iCS_MenuContext(VariableCreationStr); menu[1] = new iCS_MenuContext(FunctionCreationStr); menu[2] = new iCS_MenuContext(NestedTypeCreationStr); // Add Unity message handlers var baseType = CodeGenerationUtility.GetBaseType(iStorage); if (iCS_Types.IsA <MonoBehaviour>(baseType)) { var libraryType = LibraryController.LibraryDatabase.GetLibraryType(typeof(MonoBehaviour)); var eventHandlers = libraryType.GetMembers <LibraryEventHandler>(); int len = P.length(eventHandlers); int idx = GrowMenuBy(ref menu, len); for (int i = 0; i < len; ++i) { var eventHandler = eventHandlers[i]; string nodeName = eventHandler.nodeName; string displayString = eventHandler.displayString; if (iCS_AllowedChildren.CanAddChildNode(nodeName, VSObjectType.InstanceMessage, selectedObject, iStorage)) { menu[idx + i] = new iCS_MenuContext(String.Concat("+ " + AddUnityEventStr, displayString), eventHandler); } else { menu[idx + i] = new iCS_MenuContext(String.Concat("#+ " + AddUnityEventStr, displayString), eventHandler); } } } ShowMenu(menu, selectedObject, iStorage); }
// ----------------------------------------------------------------------- /// Display the error/warning details inside the given area. /// /// @param r The area in which to display the error/warning details. /// @param errors The error details. /// @param warnings The warning details. /// public static void DisplayErrorAndWarningDetails(Rect r, List <ErrorWarning> errors, List <ErrorWarning> warnings) { // -- We must have at least one item to display -- var nbErrors = errors != null ? errors.Count : 0; var nbWarnings = warnings != null ? warnings.Count : 0; if (nbErrors == 0 && nbWarnings == 0) { return; } // -- convert ErrorWarning to their string representation -- string[] errorsStrings = null; string[] warningStrings = null; if (nbErrors != 0) { errorsStrings = P.map(e => e.Message, errors).ToArray(); } if (nbWarnings != 0) { warningStrings = P.map(w => w.Message, warnings).ToArray(); } DisplayErrorAndWarningDetails(r, errorsStrings, warningStrings); }
// ---------------------------------------------------------------------- /// Returns the members of type T installed on this type. /// /// @return The array of member <T> installed on this type. /// public T[] GetMembers <T>() where T : LibraryObject { var events = P.filter(p => p is T, children); return(P.map(p => p as T, events).ToArray()); }
// ================================================================================= /// Ask the user to provide the needed information to create a project. void Create() { // -- Label column -- var pos = GetLabelColumnPositions(6); GUI.Label(pos[0], "Package Name"); GUI.Label(pos[1], "Parent Package"); GUI.Label(pos[3], "Package Folder"); GUI.Label(pos[4], "Engine Namespace"); GUI.Label(pos[5], "Editor Namespace"); // -- Value column -- pos = GetValueColumnPositions(6); myProject.PackageName = EditorGUI.TextField(pos[0], myProject.PackageName); var allPackages = BuildPackageSelection(); var packageNames = P.map(p => p == null ? "-- None --" : p.PackageName, allPackages); myParentSelection = EditorGUI.Popup(pos[1], myParentSelection, packageNames); myProject.ParentPackage = allPackages[myParentSelection]; EditorGUI.BeginDisabledGroup(true); EditorGUI.TextField(pos[3], myProject.GetRelativePackageFolder()); EditorGUI.TextField(pos[4], myProject.GetEngineNamespace()); EditorGUI.TextField(pos[5], myProject.GetEditorNamespace()); EditorGUI.EndDisabledGroup(); // -- Compute button area. -- var totalWidth = kColumn2Width + kColumn3Width; var width = totalWidth / 3f; var buttonWidth = width - 2f * kMargin; var buttonX = kColumn2X + 2 * kMargin; var buttonY = position.height - kMargin - 20.0f; // -- Show project already exists error message. -- bool projectAlreadyExists = myProject.AlreadyExists; if (projectAlreadyExists) { var x = buttonX - kMargin; var y = buttonY - 3f * pos[0].height; var w = totalWidth; var h = 2f * pos[0].height; EditorGUI.HelpBox(new Rect(x, y, w, h), "PROJECT ALREADY EXISTS:\n--> " + myProject.GetRelativeFileNamePath(), MessageType.Error); } // -- Process "Save" button. -- EditorGUI.BeginDisabledGroup(projectAlreadyExists); if (GUI.Button(new Rect(buttonX + width, buttonY, buttonWidth, 20.0f), "Save")) { if (!projectAlreadyExists) { myProject.Save(); PackageController.UpdatePackageDatabase(); Close(); } } EditorGUI.EndDisabledGroup(); // -- Process "Cancel" button. -- if (GUI.Button(new Rect(buttonX + 2f * width, buttonY, buttonWidth, 20.0f), "Cancel")) { Close(); } }
// ------------------------------------------------------------------------- /// Returns the list of output ports. iCS_EditorObject[] GetOutputDataPorts() { var parameters = GetParameters(VSObject); return(P.filter(p => p.IsOutDataPort, parameters)); }
// ---------------------------------------------------------------------- public static float[] GetScores(string search, string[] lst) { return(P.map(x => GetScore(search, x), lst)); }
// ---------------------------------------------------------------------- public static string[] SortAndTake_(string search, string[] lst, int maxNbOfResults = 0, float minScore = 0.5f) { // Define local sort function Action <P.Tuple <float, string>[]> sort = (ts) => { P.sort( ts, (t1, t2) => { var diff = t2.Item1 - t1.Item1; return(Math3D.IsZero(diff) ? 0 : (diff < 0 ? -1 : 1)); } ); }; // Correctly size result. var len = lst.Length; if (maxNbOfResults == 0) { maxNbOfResults = len; } if (maxNbOfResults > len) { maxNbOfResults = len; } var result = new P.Tuple <float, string> [maxNbOfResults]; int resultLen = 0; // Filter out the input list bool isSorted = false; foreach (var l in lst) { var score = GetScore(search, l); if (score <= minScore) { continue; } if (resultLen < maxNbOfResults) { result[resultLen] = P.curry(t => P.id(t), score, l); ++resultLen; if (resultLen == maxNbOfResults) { sort(result); isSorted = true; } } else { if (score > result[resultLen - 1].Item1) { result[resultLen - 1] = P.curry(t => P.id(t), score, l); sort(result); isSorted = true; } } // TODO: finish SortAndTake_ } // Perform a last sort in case we have not filled the max number of results. if (isSorted == false) { result = P.take(resultLen, result); sort(result); } return(P.map((t) => P.uncurry((score, str) => str, t), result)); }