/// <summary>
        /// Determines if a code element is within a specific tree node.
        /// </summary>
        /// <param name="treeNode">The source CodeElementWrapper object.</param>
        /// <param name="tp">The TextPoint cursor position in the source file.</param>
        /// <returns>The CodeElementWrapper object that contains the text point.</returns>
        private CodeElementWrapper FindBestMatch(CodeElementWrapper treeNode, TextPoint tp)
        {
            CodeElementWrapper cewBestMatch = null;

            // Is the tp between the start and end point of this CodeElement.
            if ((treeNode.StartPoint.EqualTo(tp))
                    || (treeNode.StartPoint.LessThan(tp) && treeNode.EndPoint.GreaterThan(tp)))
            {
                cewBestMatch = treeNode;
                CodeElementWrapper closestCEWInChildren = FindBestMatchInCollection(treeNode.Nodes, tp);
                if (closestCEWInChildren != null)
                {
                    cewBestMatch = closestCEWInChildren;
                }
            }

            return cewBestMatch;
        }
        /// <summary>
        /// Locates a specific element in the flat view by ID.
        /// </summary>
        /// <param name="codeElement">The CodeElementWrapper object to locate.</param>
        /// <returns>The CodeElementWrapper object containing the element.</returns>
        private CodeElementWrapper FindElementInFilterView(CodeElementWrapper codeElementWrapper)
        {
            CodeElementWrapper codeElementWrapperOut = null;
            string strElementID = codeElementWrapper.UniqueElementId;

            // Use sequential search.
            foreach (CodeElementWrapper node in FilterView.Nodes)
            {
                if (strElementID == node.UniqueElementId)
                {
                    codeElementWrapperOut = node;
                    break;
                }
            }

            return codeElementWrapperOut;
        }
        /// <summary>
        /// Locates an element by name within a set of nodes.
        /// </summary>
        /// <param name="codeElementWrapperParent">The CodeElementWrapper object to search.</param>
        /// <param name="codeElement">The CodeElement object to locate.</param>
        /// <param name="listCodeElementWrapperOut">The List of elements found.</param>
        private static void FindChildrenByName(CodeElementWrapper codeElementWrapperParent,
            CodeElement codeElement,
            out System.Collections.Generic.List<CodeElementWrapper> listCodeElementWrapperOut)
        {
            listCodeElementWrapperOut = new System.Collections.Generic.List<CodeElementWrapper>();
            string strElementName = codeElement.Name;

            int matches = 0;
            foreach (CodeElementWrapper node in codeElementWrapperParent.Nodes)
            {
                if (node.ElementName == strElementName)
                {
                    listCodeElementWrapperOut.Add(node);
                    matches++;
                }
            }
        }
        /// <summary>
        /// Adds a new element to the tree views.
        /// </summary>
        /// <param name="codeElementWrapper">The new element as a CodeElementWrapper object.</param>
        private void AddNodeToInternalStructures(CodeElementWrapper codeElementWrapper)
        {
            try
            {
                // Add the element to the tree view map.
                _mapElementIDToTreeViewCodeElementWrapper.Add(codeElementWrapper.UniqueElementId, codeElementWrapper);
            }
            catch (System.ArgumentException e)
            {
                Utils.DisplayMessage(Resources.ErrorPrefix, "Adding duplicate to _mapElementIDToTreeViewCodeElementWrapper: " + e.Message);
            }

            // Add to filtered (flat) tree.
            CodeElementWrapper codeElementWrapperFilterView = new CodeElementWrapper(codeElementWrapper.CodeElement);
            FilterView.Nodes.Add(codeElementWrapperFilterView);

            try
            {
                // Add the element to the filter view map.
                _mapElementIDToFilterViewCodeElementWrapper.Add(codeElementWrapper.UniqueElementId, codeElementWrapperFilterView);
            }
            catch (System.ArgumentException e)
            {
                Utils.DisplayMessage(Resources.ErrorPrefix, "Adding duplicate to _mapElementIDToFilterViewCodeElementWrapper: " + e.Message);
            }

            // Add the node to the array.
            CodeElementWrapper codeElementWrapperClone = new CodeElementWrapper(codeElementWrapper.CodeElement);
            _codeElementWrapperArray.AddCodeElementWrapper(codeElementWrapperClone);
        }
        /// <summary>
        /// Removes a node and all of its children.
        /// </summary>
        /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to delete.</param>
        /// <param name="codeElementWrapperParent">The CodeElementWrapper parent of the object to delete.</param>
        private void RemoveElementRecursive(CodeElementWrapper codeElementWrapperToDelete,
            CodeElementWrapper codeElementWrapperParent)
        {
            CodeElementWrapper codeElementWrapper;

            // Remove the children before the node, deleting upwards from last to first.
            for (int i = codeElementWrapperToDelete.Nodes.Count - 1; i >= 0; i--)
            {
                CodeElementWrapper node = codeElementWrapperToDelete.Nodes[i] as CodeElementWrapper;
                RemoveElementRecursive(node, codeElementWrapperToDelete);
            }

            // Remove the element from the outline view.
            RemoveElementFromTree(codeElementWrapperToDelete, codeElementWrapperParent);

            // Remove the element from the filter view.
            codeElementWrapper = FindElementInFilterView(codeElementWrapperToDelete);
            if (codeElementWrapper != null)
            {
                RemoveElementFromFilterView(codeElementWrapper);
            }

            // Remove the element from the array.
            codeElementWrapper = FindElementInWrapperArray(codeElementWrapperToDelete);
            if (codeElementWrapper != null)
            {
                RemoveElementFromWrapperArray(codeElementWrapper);
            }
        }
        /// <summary>
        /// Occurs when a new code element is added to the text window,
        /// and adds the new element to the appropriate place in the outline.
        /// </summary>
        /// <param name="newElement">The new code element.</param>
        public void OnCodeModelElementAdd(CodeElement newElement)
        {
            if ((newElement == null) || !CodeModelHelpers.IsInterestingKind(newElement.Kind))
            {
                return;
            }

            try
            {
                int line = newElement.StartPoint.Line;
            }
            catch
            {
                // An exception can be thrown here when an element is being edited, so ignore it.
                return;
            }

            // Update the tree.
            if (newElement.Kind == vsCMElement.vsCMElementParameter)
            {
                FindBestMatchCodeElementToRefreshFrom(newElement);
                return;
            }

            // Get the start point from the wrapper object and not from the CodeElement directly.
            CodeElementWrapper temp = new CodeElementWrapper(newElement);
            TextPoint tp = temp.StartPoint;
            CodeElementWrapper cew = GetClosestCodeElementInTreeView(TreeView, tp);

            if (cew == null)
            {
                // Nothing found, this must be the first element drawn.
                ReadCodeModelElementsRecursive(newElement, TreeView.Nodes, false);
            }
            else
            {
                CodeElementWrapper newNode = new CodeElementWrapper(newElement);

                // Note that the add could result from a paste, and the editor only informs
                // regarding the outer element that was added if the language is C# or VB;
                // the C++ language raises an event for each element.
                AddNodeToInternalStructures(newNode);
                ReadCodeModelChildrenElementsRecursive(newNode, false);

                newNode.ExpandAll();

                int index = 0;

                // Insert this element in the correct place.
                foreach (CodeElementWrapper n in cew.Nodes)
                {
                    if (n.Location > newNode.Location)
                    {
                        // Insert prior to n.
                        cew.Nodes.Insert(index, newNode);
                        newNode = null;
                        break;
                    }
                    else
                    {
                        index++;
                    }
                }

                // If it was not inserted, append it.

                if (newNode != null)
                {
                    cew.Nodes.Add(newNode);
                }
            }

            // Update the filter view.
            _codeElementWrapperIndexTable = new CodeElementWrapperIndexTable(_codeElementWrapperArray);
            _currentResults = _codeElementWrapperIndexTable.GenerateResultsTable(_searchCriteria);
            this.FilterText = _currentFilterText;
        }
        /// <summary>
        /// Removes an element from the outline tree view by ID.
        /// </summary>
        /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to delete.</param>
        /// <param name="codeElementWrapperParent">The CodeElementWrapper parent of the object to delete.</param>
        private void RemoveElementFromTree(CodeElementWrapper codeElementWrapperToDelete,
            CodeElementWrapper codeElementWrapperParent)
        {
            // Remove the element from the tree view.
            codeElementWrapperParent.Nodes.Remove(codeElementWrapperToDelete);

            // Remove the element from the map.
            _mapElementIDToTreeViewCodeElementWrapper.Remove(codeElementWrapperToDelete.UniqueElementId);
        }
 /// <summary>
 /// Removes an element from the wrapper array.
 /// </summary>
 /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to remove.</param>
 private void RemoveElementFromWrapperArray(CodeElementWrapper codeElementWrapperToDelete)
 {
     // Remove the element from the array.
     _codeElementWrapperArray.Remove(codeElementWrapperToDelete);
 }
        /// <summary>
        /// Refreshes a specific tree node with a specific element.
        /// </summary>
        /// <param name="codeElementWrapper">The CodeElementWrapper to refresh.</param>
        /// <param name="codeElement">The CodeElement to refresh with.</param>
        private void RefreshCodeModelForElement(ref CodeElementWrapper codeElementWrapper,
            CodeElement codeElement)
        {
            TreeNode treeNodeFilterView = null;
            TreeNode treeNodeTreeView = null;

            try
            {
                treeNodeFilterView = FilterView.SelectedNode;
                treeNodeTreeView = TreeView.SelectedNode;

                TreeView.BeginUpdate();
                FilterView.BeginUpdate();

                BeginTransaction();

                // Update the element itself.
                codeElementWrapper.CodeElement = codeElement;

                // Remove elements from the parent in reverse order.
                for (int i = codeElementWrapper.Nodes.Count - 1; i >= 0; i--)
                {
                    CodeElementWrapper node = codeElementWrapper.Nodes[i] as CodeElementWrapper;
                    RemoveElementRecursive(node, codeElementWrapper);
                }

                codeElementWrapper.Nodes.Clear();

                ReadCodeModelChildrenElementsRecursive(codeElementWrapper, false);

                // Update the copy of the codeElementWrapper in the wrapper array.
                CodeElementWrapper codeElementWrapperClone = FindElementInWrapperArray(codeElementWrapper);
                if (codeElementWrapperClone != null)
                {
                    RemoveElementFromWrapperArray(codeElementWrapperClone);
                }
                codeElementWrapperClone = new CodeElementWrapper(codeElementWrapper.CodeElement);
                _codeElementWrapperArray.AddCodeElementWrapper(codeElementWrapperClone);

            }
            finally
            {
                EndTransaction();

                TreeView.ExpandAll();

                FilterView.EndUpdate();
                TreeView.EndUpdate();

                FilterView.SelectedNode = treeNodeFilterView;
                TreeView.SelectedNode = treeNodeTreeView;
            }
        }
        /// <summary>
        /// Removes an element from the flat view by ID.
        /// </summary>
        /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to delete.</param>
        private void RemoveElementFromFilterView(CodeElementWrapper codeElementWrapperToDelete)
        {
            // Remove the element from the filter view.
            FilterView.Nodes.Remove(codeElementWrapperToDelete);

            // Remove the element from the map.
            _mapElementIDToFilterViewCodeElementWrapper.Remove(codeElementWrapperToDelete.UniqueElementId);
        }
        /// <summary>
        /// Iterates through the code model starting at a specified element
        /// and adds the discovered elements to a tree.
        /// </summary>
        /// <param name="codeElement">The starting CodeElement.</param>
        /// <param name="nodes">The TreeNodeCollection to add the element to.</param>
        /// <param name="interruptible">true if this method can be interrupted (is background), otherwise false.</param>
        /// <returns>true if the method completed, otherwise false.</returns>
        private bool ReadCodeModelElementsRecursive(EnvDTE.CodeElement codeElement, TreeNodeCollection nodes, bool interruptible)
        {
            if (interruptible)
            {
                yieldCount0++;
                if (yieldCount0 >= 5)
                {
                    yieldCount0 = 0;
                    NemerlePackage pkg = _sourceOutlinerToolWindow.Package as NemerlePackage;
                    if ((pkg != null) && (!pkg.CanContinueIdle))
                        return false;
                }
            }

            if (codeElement == null)
            {
                return true;
            }

            // Test whether this is a code element of interest.
            if (!CodeModelHelpers.IsInterestingKind(codeElement.Kind))
            {
                return true;
            }

            if (codeElement.InfoLocation != EnvDTE.vsCMInfoLocation.vsCMInfoLocationProject)
            {
                return true;
            }

            CodeElementWrapper treenode = null;
            string uniqueID = CodeModelHelpers.GetUniqueElementId(codeElement);

            // See if this node has finished processing.
            _mapElementIDToTreeViewCodeElementWrapper.TryGetValue(uniqueID, out treenode);
            if (treenode != null)
            {
                if (treenode.FinishedLoading)
                    return true;
            }
            else
            {
                treenode = new CodeElementWrapper(codeElement);
                nodes.Add(treenode);
                AddNodeToInternalStructures(treenode);
            }

            treenode.FinishedLoading = ReadCodeModelChildrenElementsRecursive(treenode, interruptible);

            return treenode.FinishedLoading;
        }
        /// <summary>
        /// Iterates through the children of a code model element.
        /// </summary>
        /// <param name="codeElementWrapper">The CodeElementWrapper to process.</param>
        /// <param name="interruptible">true if this method can be interrupted (is background), otherwise false.</param>
        /// <returns>true if the method completed, otherwise false.</returns>
        private bool ReadCodeModelChildrenElementsRecursive(CodeElementWrapper codeElementWrapper, bool interruptible)
        {
            if (interruptible)
            {
                yieldCount1++;
                if (yieldCount1 >= 5)
                {
                    yieldCount1 = 0;
                    NemerlePackage pkg = _sourceOutlinerToolWindow.Package as NemerlePackage;
                    if ((pkg != null) && (!pkg.CanContinueIdle))
                        return false;
                }
            }

            bool childrenRead;

            CodeElements members = CodeModelHelpers.GetMembersOf(codeElementWrapper.CodeElement);
            if (members != null)
            {
                foreach (CodeElement codeElementMember in members)
                {
                    string uniqueID = CodeModelHelpers.GetUniqueElementId(codeElementMember);
                    CodeElementWrapper node = null;
                    _mapElementIDToTreeViewCodeElementWrapper.TryGetValue(uniqueID, out node);
                    if (node != null)
                    {
                        if (node.FinishedLoading)
                            continue;
                    }

                    // Prevent a recursive call if the code element is not of interest.
                    if (CodeModelHelpers.IsInterestingKind(codeElementMember.Kind))
                    {
                        childrenRead = ReadCodeModelElementsRecursive(codeElementMember, codeElementWrapper.Nodes, interruptible);
                        if (!childrenRead)
                        {
                            // Children failed to be read, so leave.
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// Locates an element in the wrapper array.
        /// </summary>
        /// <param name="codeElementWrapper">The CodeElementWrapper object to locate.</param>
        /// <returns>The CodeElementWrapper node that was located in the array.</returns>
        private CodeElementWrapper FindElementInWrapperArray(CodeElementWrapper codeElementWrapper)
        {
            CodeElementWrapper codeElementWrapperOut = null;

            try
            {
                codeElementWrapperOut = _codeElementWrapperArray.FindCodeElementWrapper(codeElementWrapper);
            }
            catch (Exception)
            {
                // If not found in the map, use a sequential search.
                string strElementID = codeElementWrapper.UniqueElementId;
                foreach (CodeElementWrapper node in _codeElementWrapperArray)
                {
                    if (strElementID == node.UniqueElementId)
                    {
                        codeElementWrapperOut = node;
                        break;
                    }
                }
            }

            return codeElementWrapperOut;
        }
        /// <summary>
        /// Locates a specific element in a tree node by ID, recursively.
        /// </summary>
        /// <param name="codeElement">The CodeElement object to locate.</param>
        /// <param name="codeElementWrapperNode">The CodeElementWrapper node to search.</param>
        /// <returns>The CodeElementWrapper object containing the element.</returns>
        private CodeElementWrapper FindElementInTreeRecursive(CodeElement codeElement, CodeElementWrapper codeElementWrapperNode)
        {
            string strCodeElementID = CodeModelHelpers.GetUniqueElementId(codeElement);

            if (strCodeElementID == codeElementWrapperNode.UniqueElementId)
            {
                return codeElementWrapperNode;
            }

            // If this is not it, check the children.
            CodeElementWrapper codeElementWrapper = null;
            foreach (CodeElementWrapper node in codeElementWrapperNode.Nodes)
            {
                codeElementWrapper = FindElementInTreeRecursive(codeElement, node);
                if (codeElementWrapper != null)
                {
                    break;
                }
            }

            return codeElementWrapper;
        }
Beispiel #15
0
        /// <summary>
        /// This method is used to determine on which argument position the user is. It's able to determine if the user is inside the INPUT/OUTPUT/IN-OUT argument section.
        /// </summary>
        /// <param name="procedure">The detected procedure</param>
        /// <param name="wrappedCodeElement">One codeElement containing arrangedTokens concerning a procedure CALL</param>
        /// <param name="position">Cursors position in the document</param>
        /// <returns></returns>
        public static int?SignatureHelperParameterSelecter(FunctionDeclaration procedure, CodeElementWrapper wrappedCodeElement, Position position)
        {
            int activeParameter      = 0;
            var closestTokenToCursor = wrappedCodeElement.ArrangedConsumedTokens.Where(
                t => (t.Line == position.line + 1 && t.StartIndex <= position.character && t.StopIndex + 1 > position.character))
                                       .OrderBy(t => Math.Abs(position.character - t.StopIndex + 1)) //Allows to get the token closest to the cursor and ignoring the one where the cursor is
                                       .FirstOrDefault();

            //Get the last significant token before cursor (INPUT / OUTPUT / IN-OUT)
            var closestSignificantTokenToCursor = wrappedCodeElement.ArrangedConsumedTokens.LastOrDefault(
                t => (t.TokenType == TokenType.INPUT || t.TokenType == TokenType.OUTPUT || t.TokenType == TokenType.IN_OUT) && t.Line <= position.line + 1);


            if (closestSignificantTokenToCursor == null)
            {
                return(null);//No argument have to be selected for now we will wait until the user typed (input/output/in-out)
            }
            var alreadyGivenTokens = wrappedCodeElement.ArrangedConsumedTokens
                                     .SkipWhile(t => t != closestSignificantTokenToCursor).Skip(1)
                                     .TakeWhile(t => t.TokenType != TokenType.OUTPUT && t.TokenType != TokenType.IN_OUT)
                                     .Where(t => (t.StartIndex < position.character && t.Line == position.line + 1) || t.Line < position.line + 1);


            int       alreadyGivenParametersCount = 0;
            TokenType?previousTokenType           = null;

            //Loop that allows to ignore qualified name parameters.
            foreach (var givenToken in alreadyGivenTokens)
            {
                if (givenToken.TokenType == TokenType.UserDefinedWord && (previousTokenType == null || previousTokenType.Value == TokenType.UserDefinedWord))
                {
                    alreadyGivenParametersCount++;
                }
                previousTokenType = givenToken.TokenType;
            }


            if (closestSignificantTokenToCursor.TokenType == TokenType.INPUT)
            {
                activeParameter = alreadyGivenParametersCount;
            }
            else if (closestSignificantTokenToCursor.TokenType == TokenType.IN_OUT)
            {
                //Count total input parameters
                //add alreadyGivenParametersCount
                activeParameter = procedure.Profile.InputParameters.Count + alreadyGivenParametersCount;
            }
            else if (closestSignificantTokenToCursor.TokenType == TokenType.OUTPUT)
            {
                //Count total input & inout parameters
                //add alreadyGivenParametersCount
                activeParameter = procedure.Profile.InputParameters.Count +
                                  procedure.Profile.InoutParameters.Count +
                                  alreadyGivenParametersCount;
            }

            if (closestTokenToCursor != null && (closestTokenToCursor.TokenType == TokenType.UserDefinedWord || closestTokenToCursor.TokenType == TokenType.QualifiedNameSeparator) &&
                position.character <= closestTokenToCursor.StopIndex + 1 && activeParameter > 0)
            {
                activeParameter--; //The cursor is still on this argument so the user is not willing the next argument.
            }

            return(activeParameter);
        }