Пример #1
0
        public SnapshotSpan GetSpanOfEnclosing(SnapshotSpan activeSpan)
        {
            if (!XmlBackgroundParser.TryGetParser(activeSpan.Snapshot.TextBuffer, out var parser))
            {
                return(codeNavigator.GetSpanOfEnclosing(activeSpan));
            }

            // use last parse if it's up to date, which is most likely will be
            // else use a spine from the end of the selection and update as needed
            var            lastParse = parser.LastOutput;
            List <XObject> nodePath;
            XmlSpineParser spine = null;

            if (lastParse != null && lastParse.TextSnapshot.Version.VersionNumber == activeSpan.Snapshot.Version.VersionNumber)
            {
                var n = lastParse.XDocument.FindAtOrBeforeOffset(activeSpan.Start.Position);
                nodePath = n.GetPath();
            }
            else
            {
                spine    = parser.GetSpineParser(activeSpan.Start);
                nodePath = spine.AdvanceToNodeEndAndGetNodePath(activeSpan.Snapshot);
            }

            // this is a little odd because it was ported from MonoDevelop, where it has to maintain its own stack of state
            // for contract selection. it describes the current semantic selection as a node path, the index of the node in that path
            // that's selected, and the kind of selection that node has.
            int            selectedNodeIndex = nodePath.Count;
            SelectionLevel selectionLevel    = default;

            // keep on expanding the selection until we find one that contains the current selection but is a little bigger
            while (ExpandSelection(nodePath, spine, activeSpan, ref selectedNodeIndex, ref selectionLevel))
            {
                var selectionSpan = GetSelectionSpan(activeSpan.Snapshot, nodePath, ref selectedNodeIndex, ref selectionLevel);
                if (selectionSpan is TextSpan s && s.Start <= activeSpan.Start && s.End >= activeSpan.End && s.Length > activeSpan.Length)
                {
                    var selectionSnapshotSpan = new SnapshotSpan(activeSpan.Snapshot, s.Start, s.Length);

                    // if we're in content, the code navigator may be able to make a useful smaller expansion
                    if (selectionLevel == SelectionLevel.Content)
                    {
                        var codeNavigatorSpan = codeNavigator.GetSpanOfEnclosing(activeSpan);
                        if (selectionSnapshotSpan.Contains(codeNavigatorSpan))
                        {
                            return(codeNavigatorSpan);
                        }
                    }
                    return(selectionSnapshotSpan);
                }
            }

            return(codeNavigator.GetSpanOfEnclosing(activeSpan));
        }
Пример #2
0
        public static MSBuildResolveResult Resolve(
            XmlSpineParser spineParser,
            ITextSource textSource,
            MSBuildDocument context,
            IFunctionTypeProvider functionTypeProvider,
            CancellationToken cancellationToken = default)
        {
            int offset = spineParser.Position;

            var nodePath = spineParser.AdvanceToNodeEndAndGetNodePath(textSource);

            nodePath.ConnectParents();

            //need to look up element by walking how the path, since at each level, if the parent has special children,
            //then that gives us information to identify the type of its children
            MSBuildElementSyntax   languageElement   = null;
            MSBuildAttributeSyntax languageAttribute = null;
            XElement   el  = null;
            XAttribute att = null;

            foreach (var node in nodePath)
            {
                if (node is XAttribute xatt && xatt.Name.Prefix == null)
                {
                    att = xatt;
                    languageAttribute = languageElement?.GetAttribute(att.Name.Name);
                    break;
                }

                //if children of parent is known to be arbitrary data, don't go into it
                if (languageElement != null && languageElement.ValueKind == MSBuildValueKind.Data)
                {
                    break;
                }

                //code completion is forgiving, all we care about best guess resolve for deepest child
                if (node is XElement xel && xel.Name.Prefix == null)
                {
                    el = xel;
                    languageElement = MSBuildElementSyntax.Get(el.Name.Name, languageElement);
                    if (languageElement != null)
                    {
                        continue;
                    }
                }

                if (node is XText)
                {
                    continue;
                }

                if (node is XClosingTag ct && ct == el.ClosingTag)
                {
                    continue;
                }

                languageElement = null;
            }

            if (languageElement == null)
            {
                return(null);
            }

            var rr = new MSBuildResolveResult {
                ElementSyntax   = languageElement,
                AttributeSyntax = languageAttribute,
                Element         = el,
                Attribute       = att
            };

            var rv = new MSBuildResolveVisitor(offset, rr, functionTypeProvider);

            try {
                rv.Run(el, languageElement, textSource, context, token: cancellationToken);
            } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
            {
                // callers always have to handle the possibility this returns null
                // so this means callers don't need to handle cancellation exceptions explciitly
                return(null);
            }

            return(rr);
        }
Пример #3
0
        public SnapshotSpan GetSpanOfEnclosing(SnapshotSpan activeSpan)
        {
            if (!XmlBackgroundParser.TryGetParser(activeSpan.Snapshot.TextBuffer, out var parser))
            {
                return(xmlNavigator.GetSpanOfEnclosing(activeSpan));
            }

            // use last parse if it's up to date, which is most likely will be
            // else use a spine from the end of the selection and update as needed
            var            lastParse = parser.LastOutput;
            List <XObject> nodePath;
            XmlSpineParser spine = null;

            if (lastParse != null && lastParse.TextSnapshot.Version.VersionNumber == activeSpan.Snapshot.Version.VersionNumber)
            {
                var n = lastParse.XDocument.FindAtOrBeforeOffset(activeSpan.Start.Position);
                nodePath = n.GetPath();
            }
            else
            {
                spine    = parser.GetSpineParser(activeSpan.Start);
                nodePath = spine.AdvanceToNodeEndAndGetNodePath(activeSpan.Snapshot);
            }

            if (nodePath.Count > 0)
            {
                var leaf = nodePath[nodePath.Count - 1];
                if (leaf is XAttribute || leaf is XText)
                {
                    var syntax = MSBuildElementSyntax.Get(nodePath);
                    if (syntax != null)
                    {
                        int    offset;
                        string text;
                        bool   isCondition = false;
                        if (leaf is XText t)
                        {
                            offset = t.Span.Start;
                            text   = t.Text;
                        }
                        else
                        {
                            var att = (XAttribute)leaf;
                            offset      = att.ValueOffset;
                            text        = att.Value;
                            isCondition = true;
                        }

                        var expr = isCondition
                                                        ? ExpressionParser.ParseCondition(text, offset)
                                                        : ExpressionParser.Parse(text, ExpressionOptions.ItemsMetadataAndLists, offset);

                        var expansion = Expand(activeSpan, expr, out var isText);

                        if (expansion is SnapshotSpan expandedSpan)
                        {
                            if (isText)
                            {
                                var xmlNavigatorSpan = xmlNavigator.GetSpanOfEnclosing(activeSpan);
                                if (expandedSpan.Contains(xmlNavigatorSpan))
                                {
                                    return(xmlNavigatorSpan);
                                }
                            }
                            return(expandedSpan);
                        }
                    }
                }
            }

            return(xmlNavigator.GetSpanOfEnclosing(activeSpan));
        }
 /// <summary>
 /// Advances the parser to end the node at the current position and gets that node's path.
 /// </summary>
 /// <param name="parser">A spine parser. Its state will be modified.</param>
 /// <param name="snapshot">The text snapshot corresponding to the parser.</param>
 /// <returns></returns>
 public static List <XObject> AdvanceToNodeEndAndGetNodePath(this XmlSpineParser parser, ITextSnapshot snapshot, int maximumReadahead = DEFAULT_READAHEAD_LIMIT)
 => parser.AdvanceToNodeEndAndGetNodePath(new SnapshotTextSource(snapshot), maximumReadahead);