internal IEnumerable <ICollapsible> GetCollapsiblesForCurrentSelection(IOutliningManager outliningManager, ITextView textView)
        {
            if (outliningManager == null)
            {
                return(null);
            }

            // Try for all collapsibles which are contained within the selection span
            SnapshotSpan  selectionSnapshotSpan    = textView.Selection.StreamSelectionSpan.SnapshotSpan;
            ITextSnapshot selectionSnapshot        = selectionSnapshotSpan.Snapshot;
            var           intersectingCollapsibles = outliningManager.GetAllRegions(selectionSnapshotSpan);
            var           filteredCollapsibles     = intersectingCollapsibles.Where(collapsible => selectionSnapshotSpan.Contains(collapsible.Extent.GetSpan(selectionSnapshot)));
            var           tornoffCollapsibles      = GetTornoffCollapsibles(filteredCollapsibles);

            if (tornoffCollapsibles != null)
            {
                return(tornoffCollapsibles);
            }

            // Try for innermost collapsibles which intersect and start within the selection span
            filteredCollapsibles = intersectingCollapsibles.Where(collapsible => selectionSnapshotSpan.Contains(collapsible.Extent.GetSpan(selectionSnapshot).Start));
            tornoffCollapsibles  = GetInnermostCollapsibles(selectionSnapshot, filteredCollapsibles);
            if (tornoffCollapsibles != null)
            {
                return(tornoffCollapsibles);
            }

            // Try for all collapsibles which are contained within the selection's first line
            ITextSnapshotLine selectionStartLine = selectionSnapshot.GetLineFromPosition(selectionSnapshotSpan.Start);
            SnapshotSpan      selectionFirstLine = new SnapshotSpan(selectionSnapshot, selectionStartLine.Start, selectionStartLine.Length);

            intersectingCollapsibles = outliningManager.GetAllRegions(selectionFirstLine);
            filteredCollapsibles     = intersectingCollapsibles.Where(collapsible => selectionFirstLine.Contains(collapsible.Extent.GetSpan(selectionSnapshot)));
            tornoffCollapsibles      = GetTornoffCollapsibles(filteredCollapsibles);
            if (tornoffCollapsibles != null)
            {
                return(tornoffCollapsibles);
            }

            // Try for innermost collapsibles which intersect and start within the selection's first line
            filteredCollapsibles = intersectingCollapsibles.Where(collapsible => selectionFirstLine.Contains(collapsible.Extent.GetSpan(selectionSnapshot).Start));
            tornoffCollapsibles  = GetInnermostCollapsibles(selectionSnapshot, filteredCollapsibles);
            if (tornoffCollapsibles != null)
            {
                return(tornoffCollapsibles);
            }

            // Try for innermost collapsibles which simply intersect the selection's first line
            tornoffCollapsibles = GetInnermostCollapsibles(selectionSnapshot, intersectingCollapsibles);
            if (tornoffCollapsibles != null)
            {
                return(tornoffCollapsibles);
            }

            return(null);
        }
Example #2
0
        private ReadOnlyCollection <ITagSpan <MarkGlyphTag> > GetTags(SnapshotSpan span)
        {
            if (_glyphPairs.Count == 0)
            {
                return(s_emptyTagList);
            }

            var snapshot = span.Snapshot;
            var list     = new List <ITagSpan <MarkGlyphTag> >();

            VimTrace.TraceInfo($"MarkGlyphTagger::GetTags: starting...");
            foreach (var pair in _glyphPairs)
            {
                var chars      = pair.Item1;
                var lineNumber = pair.Item2;

                if (lineNumber < snapshot.LineCount)
                {
                    var line      = snapshot.GetLineFromLineNumber(lineNumber);
                    var startSpan = new SnapshotSpan(line.Start, 0);
                    if (span.Contains(startSpan))
                    {
                        VimTrace.TraceInfo($"MarkGlyphTagger::GetTags: tag {lineNumber} {chars}");
                        var tag     = new MarkGlyphTag(chars);
                        var tagSpan = new TagSpan <MarkGlyphTag>(startSpan, tag);
                        list.Add(tagSpan);
                    }
                }
            }
            return(list.ToReadOnlyCollectionShallow());
        }
Example #3
0
        public IList <ITagSpan <TTag> > GetNonIntersectingSpans(SnapshotSpan snapshotSpan)
        {
            var snapshot = snapshotSpan.Snapshot;

            Contract.Requires(snapshot.TextBuffer == _textBuffer);

            var introspector = new IntervalIntrospector(snapshot);

            var beforeSpan = new SnapshotSpan(snapshot, 0, snapshotSpan.Start);
            var before     = _tree.GetIntersectingIntervals(beforeSpan.Start, beforeSpan.Length, introspector)
                             .Where(n => beforeSpan.Contains(n.Span.GetSpan(snapshot)));

            var afterSpan = new SnapshotSpan(snapshot, snapshotSpan.End, snapshot.Length - snapshotSpan.End);
            var after     = _tree.GetIntersectingIntervals(afterSpan.Start, afterSpan.Length, introspector)
                            .Where(n => afterSpan.Contains(n.Span.GetSpan(snapshot)));

            List <ITagSpan <TTag> > result = null;

            foreach (var tagNode in before.Concat(after))
            {
                result = result ?? new List <ITagSpan <TTag> >();
                result.Add(new TagSpan <TTag>(tagNode.Span.GetSpan(snapshot), tagNode.Tag));
            }

            return(result ?? SpecializedCollections.EmptyList <ITagSpan <TTag> >());
        }
        private ValueTuple <int, int> FindBlockRange(SnapshotSpan span, Span range)
        {
            ValueTuple <int, int> result = new ValueTuple <int, int>();
            int firstIndex = this.FindBlockIndex(span, range.Start, false);

            result.Item1 = firstIndex;
            int lastIndex = this.trackedBlocks.Count - 1;
            int position  = range.End;

            while (firstIndex <= lastIndex)
            {
                int          currentIndex     = (firstIndex + lastIndex) / 2;
                SnapshotSpan trackedBlockSpan = this.trackedBlocks[currentIndex].Block.GetSpan(span.Snapshot);
                if (trackedBlockSpan.Contains(position))
                {
                    result.Item2 = currentIndex;
                    return(result);
                }
                else if (position < trackedBlockSpan.Start)
                {
                    lastIndex = currentIndex - 1;
                }
                else if (position >= trackedBlockSpan.End)
                {
                    firstIndex = currentIndex + 1;
                }
            }
            if (firstIndex >= this.trackedBlocks.Count)
            {
                firstIndex = this.trackedBlocks.Count - 1;
            }
            result.Item2 = firstIndex;
            return(result);
        }
        private int FindBlockIndex(SnapshotSpan span, int position, bool inside)
        {
            int firstIndex = 0;
            int lastIndex  = this.trackedBlocks.Count - 1;

            while (firstIndex <= lastIndex)
            {
                int          currentIndex     = (firstIndex + lastIndex) / 2;
                SnapshotSpan trackedBlockSpan = this.trackedBlocks[currentIndex].Block.GetSpan(span.Snapshot);
                if (trackedBlockSpan.Contains(position))
                {
                    return(currentIndex);
                }
                else if (position < trackedBlockSpan.Start)
                {
                    lastIndex = currentIndex - 1;
                }
                else if (position >= trackedBlockSpan.End)
                {
                    firstIndex = currentIndex + 1;
                }
            }
            if (inside)
            {
                return(-1);
            }
            else
            {
                return(firstIndex);
            }
        }
Example #6
0
        void HighlightNodeRanges(SyntaxNode node, SnapshotSpan span)
        {
            _SyntaxNodeRangeAdornment.AddAdornment(span, null, new GeometryAdornment(ThemeHelper.MenuHoverBackgroundColor, _View.TextViewLines.GetMarkerGeometry(span), 3));
            var p = _View.Caret.Position.BufferPosition;

            if (span.Contains(p) == false)
            {
                return;
            }
            var n = _SemanticContext.GetNode(p, false, false);

            while (n != null && node.Contains(n))
            {
                if (n.Span.Start != span.Start &&
                    n.Span.Length != span.Length)
                {
                    var nodeKind = n.Kind();
                    if (nodeKind != SyntaxKind.Block)
                    {
                        span = n.Span.CreateSnapshotSpan(_View.TextSnapshot);
                        _SyntaxNodeRangeAdornment.AddAdornment(span, null, new GeometryAdornment(ThemeHelper.MenuHoverBackgroundColor, _View.TextViewLines.GetMarkerGeometry(span), nodeKind.IsSyntaxBlock() || nodeKind.IsDeclaration() ? 1 : 0));
                    }
                }
                n = n.Parent;
            }
        }
Example #7
0
 private static bool ContainedBySpan(SnapshotSpan searchRange, SnapshotPoint startingPosition)
 {
     // We make an exception for spans to contain points if the end point of the span matches the startingPosition.
     // For backwards searches, this allows the consumer to find a point at the very end of the searchRange, for
     // forward searches, this has no effect.
     return(searchRange.Contains(startingPosition) || searchRange.End == startingPosition);
 }
Example #8
0
            private void Buffer_Changed(object sender, TextContentChangedEventArgs e)
            {
                AssertIsForeground();

                if (!_buffer.GetOption(InternalFeatureOnOffOptions.RenameTracking))
                {
                    // When disabled, ignore all text buffer changes and do not trigger retagging
                    return;
                }

                using (Logger.LogBlock(FunctionId.Rename_Tracking_BufferChanged, CancellationToken.None))
                {
                    // When the buffer changes, several things might be happening:
                    // 1. If a non-identifer character has been added or deleted, we stop tracking
                    //    completely.
                    // 2. Otherwise, if the changes are completely contained an existing session, then
                    //    continue that session.
                    // 3. Otherwise, we're starting a new tracking session. Find and track the span of
                    //    the relevant word in the foreground, and use a task to figure out whether the
                    //    original word was a renamable identifier or not.

                    if (e.Changes.Count != 1 || ShouldClearTrackingSession(e.Changes.Single()))
                    {
                        ClearTrackingSession();
                        return;
                    }

                    // The change is trackable. Figure out whether we should continue an existing
                    // session

                    var change = e.Changes.Single();

                    if (this.TrackingSession == null)
                    {
                        StartTrackingSession(e);
                        return;
                    }

                    // There's an existing session. Continue that session if the current change is
                    // contained inside the tracking span.

                    SnapshotSpan trackingSpanInNewSnapshot = this.TrackingSession.TrackingSpan.GetSpan(e.After);
                    if (trackingSpanInNewSnapshot.Contains(change.NewSpan))
                    {
                        // Continuing an existing tracking session. If there may have been a tag
                        // showing, then update the tags.
                        if (this.TrackingSession.IsDefinitelyRenamableIdentifier())
                        {
                            this.TrackingSession.CheckNewIdentifier(this, _buffer.CurrentSnapshot);
                            TrackingSessionUpdated();
                        }
                    }
                    else
                    {
                        StartTrackingSession(e);
                    }
                }
            }
Example #9
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));
        }
Example #10
0
 public Collection <TextBounds> GetNormalizedTextBounds(SnapshotSpan bufferSpan)
 {
     if (bufferSpan.OverlapsWith(lineSpan))
     {
         double leading = 0;
         if (lineSpan.Contains(bufferSpan.Start))
         {
             leading = textEditor.LocationToPoint(textEditor.OffsetToLocation(bufferSpan.Start)).X;
         }
         var    endLoc = textEditor.OffsetToLocation(lineSpan.Contains(bufferSpan.End) ? bufferSpan.End : lineSpan.End);
         double endPos = textEditor.LocationToPoint(endLoc).X;
         return(new Collection <TextBounds>(new List <TextBounds>()
         {
             new TextBounds(leading, Top, endPos - leading, TextHeight, TextTop, TextHeight)
         }));
     }
     else
     {
         return(new Collection <TextBounds>());
     }
 }
Example #11
0
        public SyntaxList <SyntaxToken> GetTokensInSpan(SnapshotSpan span)
        {
            var builder = SyntaxList.CreateBuilder <SyntaxToken>();

            foreach (var token in Tokens)
            {
                if (span.Contains(token.SnapshotSpan))
                {
                    builder.Add(token);
                }
            }
            return(builder.ToList());
        }
Example #12
0
        private void AddNonIntersectingSpans(
            SnapshotSpan span, IntervalIntrospector introspector, List <ITagSpan <TTag> > spans)
        {
            var snapshot = span.Snapshot;

            foreach (var tagNode in _tree.GetIntervalsThatIntersectWith(span.Start, span.Length, introspector))
            {
                var tagNodeSpan = tagNode.Span.GetSpan(snapshot);
                if (span.Contains(tagNodeSpan))
                {
                    spans.Add(new TagSpan <TTag>(tagNodeSpan, tagNode.Tag));
                }
            }
        }
Example #13
0
 protected virtual bool IsSnapshotPointContainedInSpan(ITextSnapshot snapshot,
                                                       SnapshotPoint snapshotPoint,
                                                       SnapshotSpan sourceSpan)
 {
     if (snapshot != sourceSpan.Snapshot)
     {
         // need to map to the new snapshot before we can detect overlap
         sourceSpan = sourceSpan.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
     }
     if (snapshot != snapshotPoint.Snapshot)
     {
         // need to map to the new snapshot before we can detect overlap
         snapshotPoint = snapshotPoint.TranslateTo(snapshot, PointTrackingMode.Positive);
     }
     return(sourceSpan.Contains(snapshotPoint));
 }
Example #14
0
 protected virtual bool IsSpanContainedInTargetSpan(ITextSnapshot snapshot,
                                                    SnapshotSpan sourceSpan,
                                                    SnapshotSpan targetSpan)
 {
     if (snapshot != sourceSpan.Snapshot)
     {
         // need to map to the new snapshot before we can detect overlap
         sourceSpan = sourceSpan.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
     }
     if (snapshot != targetSpan.Snapshot)
     {
         // need to map to the new snapshot before we can detect overlap
         targetSpan = targetSpan.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
     }
     return(sourceSpan.Contains(targetSpan));
 }
Example #15
0
        private bool ShouldClearToolTipOnMouseMove(Point pointRelativeToView)
        {
            var view = WpfTextView;

            if (view == null || view.TextViewLines == null)
            {
                return(true);
            }

            // If the point isn't over a valid line, dismiss.
            ITextViewLine line = view.TextViewLines.GetTextViewLineContainingYCoordinate(pointRelativeToView.Y);

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

            if (this.PresentationSpan == null)

            {
                return(false);
            }

            SnapshotSpan  span     = this.PresentationSpan.GetSpan(view.TextSnapshot);
            SnapshotPoint?position = line.GetBufferPositionFromXCoordinate(pointRelativeToView.X, true);

            //Special case handling for the last line on the buffer: we want to treat the mouse hovering near the end
            //of the line as a "hit"
            if ((!position.HasValue) && (line.End == line.Snapshot.Length))
            {
                if ((pointRelativeToView.X >= line.TextLeft) && (pointRelativeToView.X < line.TextRight + line.EndOfLineWidth))
                {
                    position = line.End;
                }
            }

            // If the position is valid and within the start/end of the visual span, inclusive, we
            // don't need to dismiss.
            if (position.HasValue && (span.Contains(position.Value) || span.End == position.Value))
            {
                return(false);
            }

            // No match, dismiss the tooltip.
            return(true);
        }
Example #16
0
        public override IEnumerable <INavigateToTarget> GoToSourceImpl(VSOBJGOTOSRCTYPE gotoSourceType, [NotNull] ITrackingPoint triggerPoint)
        {
            Requires.NotNull(triggerPoint, nameof(triggerPoint));

            if (triggerPoint == null)
            {
                return(new INavigateToTarget[0]);
            }

            ITextSnapshot currentSnapshot = triggerPoint.TextBuffer.CurrentSnapshot;
            SnapshotPoint point           = triggerPoint.GetPoint(currentSnapshot);

            foreach (var span in this.ClassificationTagAggregator.GetTags(new SnapshotSpan(point, point)))
            {
                if (!span.Tag.ClassificationType.IsOfType(AntlrClassificationTypeNames.LexerRule) &&
                    !span.Tag.ClassificationType.IsOfType(AntlrClassificationTypeNames.ParserRule))
                {
                    continue;
                }

                NormalizedSnapshotSpanCollection spans = span.Span.GetSpans(currentSnapshot);
                if (spans.Count == 1)
                {
                    SnapshotSpan span2 = spans[0];
                    SnapshotSpan span3 = span.Span.GetSpans(span.Span.AnchorBuffer)[0];
                    if (span2.Length == span3.Length)
                    {
                        SnapshotSpan span4 = spans[0];
                        if (span4.Contains(point))
                        {
                            string ruleName = span2.GetText();
                            var    rules    = BackgroundParser.RuleSpans;
                            KeyValuePair <ITrackingSpan, ITrackingPoint> value;
                            if (rules != null && rules.TryGetValue(ruleName, out value))
                            {
                                return new INavigateToTarget[] { new SnapshotSpanNavigateToTarget(TextView, new SnapshotSpan(value.Value.GetPoint(currentSnapshot), value.Value.GetPoint(currentSnapshot))) }
                            }
                            ;
                        }
                    }
                }
            }

            return(new INavigateToTarget[0]);
        }
Example #17
0
        private static IEnumerable <Tuple <SnapshotSpan, string> > FindMultiline(SnapshotPoint startPosition, SnapshotSpan searchRange, FindOptions options, string searchPattern, string replacePattern = null)
        {
            Debug.Assert(searchRange.Contains(startPosition) || searchRange.End == startPosition);

            // This is pretty disgusting since we have to search including line endings
            // we have to look at the entire string. There can be optimizations done for specific cases
            // where one can count the number of line endings that a search pattern could at most include
            // and then search chunks with that many line endings at a time, but for patterns where the quantifier
            // is * this can't be done; e.g. a.*[\n]*.*b
            string rangeText = searchRange.GetText();

            bool wrap = (options & FindOptions.Wrap) == FindOptions.Wrap;

            foreach (var result in FindInString(searchRange.Start, startPosition - searchRange.Start, rangeText, options, searchPattern, replacePattern))
            {
                yield return(result);
            }

            if (wrap)
            {
                bool reverse = (options & FindOptions.SearchReverse) == FindOptions.SearchReverse;

                foreach (var result in FindInString(searchRange.Start, reverse ? rangeText.Length : 0, rangeText, options, searchPattern, replacePattern))
                {
                    // Since we are wrapping, check the validity of the result to ensure it was not returned
                    // in our first search above
                    if (reverse)
                    {
                        if (result.Item1.End <= startPosition)
                        {
                            break;
                        }
                    }
                    else
                    {
                        if (result.Item1.Start >= startPosition)
                        {
                            break;
                        }
                    }

                    yield return(result);
                }
            }
        }
Example #18
0
        public override IEnumerable <INavigateToTarget> GoToSourceImpl(VSOBJGOTOSRCTYPE gotoSourceType, ITrackingPoint triggerPoint)
        {
            if (triggerPoint == null)
            {
                return(new INavigateToTarget[0]);
            }

            ITextSnapshot currentSnapshot = triggerPoint.TextBuffer.CurrentSnapshot;
            SnapshotPoint point           = triggerPoint.GetPoint(currentSnapshot);

            foreach (var span in this.ClassificationTagAggregator.GetTags(new SnapshotSpan(point, point)))
            {
                if (!span.Tag.ClassificationType.IsOfType(AntlrClassificationTypeNames.LexerRule) &&
                    !span.Tag.ClassificationType.IsOfType(AntlrClassificationTypeNames.ParserRule))
                {
                    continue;
                }

                NormalizedSnapshotSpanCollection spans = span.Span.GetSpans(currentSnapshot);
                if (spans.Count == 1)
                {
                    SnapshotSpan span2 = spans[0];
                    SnapshotSpan span3 = span.Span.GetSpans(span.Span.AnchorBuffer)[0];
                    if (span2.Length == span3.Length)
                    {
                        SnapshotSpan span4 = spans[0];
                        if (span4.Contains(point))
                        {
                            string ruleName = span2.GetText();
                            var    rules    = EditorNavigationSourceAggregator.GetNavigationTargets().ToArray();
                            var    rule     = rules.FirstOrDefault(x => string.Equals(x.Name, ruleName));
                            if (rule != null)
                            {
                                var snapshot     = rule.Seek.Snapshot;
                                var trackingSeek = snapshot.CreateTrackingSpan(rule.Seek.Span, SpanTrackingMode.EdgeExclusive);
                                var seek         = trackingSeek.GetSpan(TextView.TextBuffer.CurrentSnapshot);
                                return(new INavigateToTarget[] { new SnapshotSpanNavigateToTarget(TextView, seek) });
                            }
                        }
                    }
                }
            }

            return(new INavigateToTarget[0]);
        }
        static bool RemoveItemFromRoot(T item, SnapshotSpan span, TrackingSpanNode <T> root)
        {
            if (root.Children.Count == 0)
            {
                return(false);
            }

            var result = FindChild(span.Start, root.Children, left: true);

            if (result.Index < 0 || result.Index >= root.Children.Count)
            {
                return(false);
            }

            // Search from this index onward (there may be empty regions in the way)
            for (int i = result.Index; i < root.Children.Count; i++)
            {
                var          child     = root.Children[i];
                SnapshotSpan childSpan = child.TrackingSpan.GetSpan(span.Snapshot);

                // Check to see if we've walked past it
                if (childSpan.Start > span.End)
                {
                    return(false);
                }
                else if (childSpan == span && object.Equals(child.Item, item))
                {
                    root.Children.RemoveAt(i);
                    root.Children.InsertRange(i, child.Children);
                    return(true);
                }
                else if (childSpan.Contains(span))
                {
                    if (RemoveItemFromRoot(item, span, child))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        private void InvalidateBlock(SnapshotSpan span, TrackedBlock block)
        {
            Span blockSpan = block.Block.GetSpan(span.Snapshot);

            if (span.Contains(blockSpan))
            {
                return;
            }
            if (span.Start.Position > blockSpan.Start && span.Start.Position < blockSpan.End)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, blockSpan.Start, span.Start.Position));
            }
            if (span.End.Position > blockSpan.Start && span.End.Position < blockSpan.End)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, span.End.Position, blockSpan.End));
            }
            if (span.Start.Position >= blockSpan.End || span.End.Position <= blockSpan.Start)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, blockSpan.Start, blockSpan.End));
            }
        }
Example #21
0
        internal bool InnerShouldClearToolTipOnMouseMove(Point mousePt)
        {
            if ((mousePt.X >= 0.0) && (mousePt.X < _textView.ViewportWidth) &&
                (mousePt.Y >= 0.0) && (mousePt.Y < _textView.ViewportHeight))
            {
                ITextViewLine line = _textView.TextViewLines.GetTextViewLineContainingYCoordinate(mousePt.Y + _textView.ViewportTop);
                if (line != null)
                {
                    SnapshotSpan span = _visualSpan.GetSpan(_textView.TextSnapshot);
                    if (span.IntersectsWith(line.ExtentIncludingLineBreak))
                    {
                        double x = mousePt.X + _textView.ViewportLeft;

                        //The mouse could be over text in the line ... see if it is over the tip
                        //This code essentially duplicates the logic in WpfTextView with respect
                        //to determining the logical position of the hover event.
                        int?position = line.GetBufferPositionFromXCoordinate(x, true);
                        if ((!position.HasValue) && (line.LineBreakLength == 0) && line.IsLastTextViewLineForSnapshotLine)
                        {
                            //For purposes of clearing tips, pretend the last line in the buffer
                            //actually is padded by the EndOfLineWidth (even though it is not).
                            if ((line.TextRight <= x) && (x < line.TextRight + line.EndOfLineWidth))
                            {
                                //position is at the end of the buffer. Return true if the span
                                //doesn't extend to the end of the buffer.
                                return(span.End < _textView.TextSnapshot.Length);
                            }
                        }

                        if (position.HasValue)
                        {
                            //A span that ends at the end of the buffer contains a position at the end of the buffer.
                            return(!span.Contains(position.Value));
                        }
                    }
                }
            }

            return(true);
        }
Example #22
0
 public IEnumerable <ErrorTask> GetErrorMessagesAtPoint(string fileName, SnapshotPoint pt)
 {
     foreach (var task in (from t in Tasks.Cast <ErrorTask>() where string.Equals(t.Document, fileName, StringComparison.OrdinalIgnoreCase) select t))
     {
         var span = task.Span;
         if (span.HasValue)
         {
             if (span.Value.Contains(pt.TranslateTo(task.GetSnapshot(pt.Snapshot), PointTrackingMode.Positive)))
             {
                 yield return(task);
             }
         }
         else
         {
             var taskLine = task.GetSnapshot(pt.Snapshot).GetLineFromLineNumber(task.Line);
             var taskSpan = new SnapshotSpan(taskLine.Start, taskLine.End);
             if (taskSpan.Contains(pt.TranslateTo(taskSpan.Snapshot, PointTrackingMode.Positive)))
             {
                 yield return(task);
             }
         }
     }
 }
        private void InvalidateBlockEdge(SnapshotSpan span, TrackedBlock block)
        {
            Span blockSpan = block.Block.GetSpan(span.Snapshot);

            if (span.Contains(blockSpan))
            {
                return;
            }
            int startIndex = -1;
            int endIndex   = -1;

            for (int i = 0; i < block.CachedClassifications.Count; i++)
            {
                Span classificationSpan = block.CachedClassifications[i].Span.Span;
                if (classificationSpan.Contains(span.Start.Position))
                {
                    startIndex = i;
                }
                if (classificationSpan.Contains(span.End.Position))
                {
                    endIndex = i;
                    break;
                }
            }
            if (startIndex >= 0)
            {
                Span classificationSpan = block.CachedClassifications[startIndex].Span.Span;
                if (classificationSpan.Start < span.Start.Position)
                {
                    this.Invalidate(this.CreateSnapshotSpan(span, classificationSpan.Start, span.Start.Position));
                }
            }
            if (span.End.Position > blockSpan.Start && span.End.Position < blockSpan.End)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, span.End.Position, blockSpan.End));
            }
        }
Example #24
0
        private void OnSelectionChanged(object sender, object e)
        {
            try
            {
                String selectedText = this.View.Selection.StreamSelectionSpan.GetText();
                if (!string.IsNullOrEmpty(selectedText) && !string.IsNullOrWhiteSpace(selectedText))
                {
                    // where are we
                    SnapshotPoint       currentRequest = this.View.Selection.Start.Position;
                    List <SnapshotSpan> wordSpans      = new List <SnapshotSpan>();
                    // Search for me please
                    TextExtent word      = TextStructureNavigator.GetExtentOfWord(currentRequest);
                    bool       foundWord = true;
                    //
                    if (!WordExtentIsValid(currentRequest, word))
                    {
                        //Same context ?
                        if (word.Span.Start != currentRequest ||
                            currentRequest == currentRequest.GetContainingLine().Start ||
                            char.IsWhiteSpace((currentRequest - 1).GetChar()))
                        {
                            foundWord = false;
                        }
                        else
                        {
                            // Move back, and start again
                            word = TextStructureNavigator.GetExtentOfWord(currentRequest - 1);

                            //If the word still isn't valid, we're done
                            if (!WordExtentIsValid(currentRequest, word))
                            {
                                foundWord = false;
                            }
                        }
                    }

                    if (!foundWord)
                    {
                        //If we couldn't find a word, clear out the existing markers
                        SynchronousUpdate(new NormalizedSnapshotSpanCollection());
                        return;
                    }
                    SnapshotSpan currentWord = word.Span;
                    selectedWord = this.View.Selection.StreamSelectionSpan.SnapshotSpan;


                    //If this is the current word, and the caret moved within a word, we're done.
                    if (!(selectedWord.HasValue && currentWord == selectedWord))
                    {
                        return;
                    }
                    //Find the new spans
                    FindData findData = new FindData(currentWord.GetText(), currentWord.Snapshot);
                    findData.FindOptions = FindOptions.WholeWord | FindOptions.MatchCase;
                    // Values are zero-based
                    SnapshotPoint point = View.Caret.Position.BufferPosition;
                    // Retrieve the XFile
                    XSharpModel.XFile xFile = this.View.TextBuffer.GetFile();
                    if (xFile != null)
                    {
                        // Now, retrieve the current member
                        XSharpModel.XMemberDefinition member = XSharpTokenTools.FindMemberAtPosition(point.Position, xFile);
                        if (member == null)
                        {
                            return;
                        }
                        // Ok, so we now have the "range" of the Member, and will only select text in THIS member
                        SnapshotSpan memberSpan = new SnapshotSpan(currentWord.Snapshot, member.Interval.Start, member.Interval.Width);
                        // Get all the corresponding Words
                        Collection <SnapshotSpan> allFound    = TextSearchService.FindAll(findData);
                        Collection <SnapshotSpan> memberFound = new Collection <SnapshotSpan>();
                        foreach (SnapshotSpan ssp in allFound)
                        {
                            // Inside the Member ?
                            if (memberSpan.Contains(ssp))
                            {
                                memberFound.Add(ssp);
                            }
                        }
                        //
                        wordSpans.AddRange(memberFound);
                        // Show please
                        SynchronousUpdate(new NormalizedSnapshotSpanCollection(wordSpans));
                    }
                }
            }
            catch (Exception ex)
            {
                XSettings.DisplayOutputMessage("HighlightWordTag Exception: " + ex.Message);
            }
        }
Example #25
0
        /// <inheritdoc />
        public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> quickInfoContent,
                                            out ITrackingSpan applicableToSpan)
        {
            applicableToSpan = null;

            var tagAggregator = provider.AggregatorFactory.CreateTagAggregator <IClassificationTag>(session.TextView);
            var triggerPoint  = session.GetTriggerPoint(textBuffer.CurrentSnapshot);

            if (triggerPoint != null)
            {
                SnapshotSpan tagSpan;
                var          lineSpan = triggerPoint.Value.GetContainingLine();
                string       elementName = null, attrName = null, identifier = null, name;
                UIElement    content;

                // Get the tags for the line containing the mouse point
                foreach (IMappingTagSpan <IClassificationTag> curTag in tagAggregator.GetTags(
                             new SnapshotSpan(lineSpan.Start, lineSpan.End)))
                {
                    name    = curTag.Tag.ClassificationType.Classification.ToLowerInvariant();
                    tagSpan = curTag.Span.GetSpans(textBuffer).First();

                    if (name.IndexOf("identifier", StringComparison.Ordinal) != -1)
                    {
                        name = "identifier";
                    }

                    switch (name)
                    {
                    case "xml doc tag":
                        // Track the last seen element or attribute.  The classifier in VS2013 and earlier does
                        // not break up the XML comments into elements and attributes so we may get a mix of text
                        // in the "tag".
                        attrName = tagSpan.GetText();

                        // If it contains "cref", tne next XML doc attribute value will be the target
                        if (attrName.IndexOf("cref=", StringComparison.Ordinal) != -1 && enableInCRef)
                        {
                            attrName = "cref";
                        }

                        // As above, for conceptualLink, the next XML doc attribute will be the target
                        if (attrName.StartsWith("<conceptualLink", StringComparison.Ordinal))
                        {
                            attrName = "conceptualLink";
                        }

                        // For token, the next XML doc comment will contain the token name
                        if (attrName == "<token>")
                        {
                            attrName = "token";
                        }
                        break;

                    case "xml doc attribute":
                        if ((attrName == "cref" || attrName == "conceptualLink") &&
                            tagSpan.Contains(triggerPoint.Value) && tagSpan.Length > 2)
                        {
                            // Drop the quotes from the span
                            var span = new SnapshotSpan(tagSpan.Snapshot, tagSpan.Start + 1,
                                                        tagSpan.Length - 2);

                            content = this.CreateInfoText(attrName, span.GetText());

                            if (content != null)
                            {
                                applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(span,
                                                                                                 SpanTrackingMode.EdgeExclusive);

                                quickInfoContent.Add(content);
                            }

                            return;
                        }
                        break;

                    case "xml doc comment":
                        if (attrName == "token" && tagSpan.Contains(triggerPoint.Value) && tagSpan.Length > 1)
                        {
                            content = this.CreateInfoText(attrName, tagSpan.GetText());

                            if (content != null)
                            {
                                applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(tagSpan,
                                                                                                 SpanTrackingMode.EdgeExclusive);

                                quickInfoContent.Add(content);
                            }

                            return;
                        }
                        break;

                    // VS2015 is more specific in its classifications
                    case "xml doc comment - name":
                        elementName = tagSpan.GetText().Trim();
                        break;

                    case "xml doc comment - attribute name":
                        attrName   = tagSpan.GetText().Trim();
                        identifier = null;

                        if (attrName == "cref" && !enableInCRef)
                        {
                            attrName = null;
                        }
                        break;

                    case "xml doc comment - attribute value":
                        if ((attrName == "cref" || (elementName == "conceptualLink" && attrName == "target")) &&
                            tagSpan.Contains(triggerPoint.Value) && tagSpan.Length > 1)
                        {
                            content = this.CreateInfoText((attrName == "cref") ? attrName : elementName,
                                                          tagSpan.GetText());

                            if (content != null)
                            {
                                applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(tagSpan,
                                                                                                 SpanTrackingMode.EdgeExclusive);

                                quickInfoContent.Add(content);
                            }

                            return;
                        }
                        break;

                    case "identifier":
                    case "keyword":
                    case "operator":
                        if (attrName != null)
                        {
                            identifier += tagSpan.GetText();

                            if (name == "keyword")
                            {
                                identifier += " ";
                            }
                        }
                        break;

                    case "punctuation":
                        if (identifier != null)
                        {
                            identifier += tagSpan.GetText();
                        }
                        break;

                    case "xml doc comment - attribute quotes":
                        if (identifier != null)
                        {
                            // Set the span to that of the identifier
                            var span = new SnapshotSpan(tagSpan.Snapshot, tagSpan.Start - identifier.Length,
                                                        identifier.Length);

                            if (span.Contains(triggerPoint.Value) && span.Length > 1)
                            {
                                content = this.CreateInfoText("cref", span.GetText());

                                if (content != null)
                                {
                                    applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(span,
                                                                                                     SpanTrackingMode.EdgeExclusive);

                                    quickInfoContent.Add(content);
                                }
                            }

                            return;
                        }
                        break;

                    case "xml doc comment - text":
                        if (elementName == "token" && tagSpan.Contains(triggerPoint.Value) &&
                            tagSpan.Length > 1)
                        {
                            content = this.CreateInfoText(elementName, tagSpan.GetText());

                            if (content != null)
                            {
                                applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(tagSpan,
                                                                                                 SpanTrackingMode.EdgeExclusive);

                                quickInfoContent.Add(content);
                            }

                            return;
                        }
                        break;

                    default:
                        break;
                    }
                }
            }
        }
Example #26
0
        public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> quickInfoContent, out ITrackingSpan applicableToSpan)
        {
            applicableToSpan = null;

            if (session.TextView.TextBuffer == this.TextBuffer)
            {
                ITextSnapshot currentSnapshot = this.TextBuffer.CurrentSnapshot;
                SnapshotPoint?triggerPoint    = session.GetTriggerPoint(currentSnapshot);
                if (!triggerPoint.HasValue)
                {
                    return;
                }

                foreach (var span in this.Aggregator.GetTags(new SnapshotSpan(triggerPoint.Value, triggerPoint.Value)))
                {
                    if (!span.Tag.ClassificationType.IsOfType(AntlrClassificationTypeNames.LexerRule) &&
                        !span.Tag.ClassificationType.IsOfType(AntlrClassificationTypeNames.ParserRule))
                    {
                        continue;
                    }

                    NormalizedSnapshotSpanCollection spans = span.Span.GetSpans(currentSnapshot);
                    if (spans.Count == 1)
                    {
                        SnapshotSpan span2 = spans[0];
                        SnapshotSpan span3 = span.Span.GetSpans(span.Span.AnchorBuffer)[0];
                        if (span2.Length == span3.Length)
                        {
                            SnapshotSpan span4 = spans[0];
                            if (span4.Contains(triggerPoint.Value))
                            {
                                StringBuilder builder  = new StringBuilder();
                                string        ruleName = span2.GetText();
                                var           rules    = BackgroundParser.RuleSpans;
                                KeyValuePair <ITrackingSpan, ITrackingPoint> value;
                                if (rules == null || !rules.TryGetValue(ruleName, out value))
                                {
#if DEBUG
                                    if (span.Tag.ClassificationType.IsOfType(AntlrClassificationTypeNames.LexerRule))
                                    {
                                        builder.Append("Found an unknown lexer rule.");
                                    }
                                    else
                                    {
                                        builder.Append("Found an unknown parser rule.");
                                    }
#else
                                    return;
#endif
                                }
                                else
                                {
                                    SnapshotPoint ruleSeek = value.Value.GetPoint(triggerPoint.Value.Snapshot);
                                    if (span2.Contains(ruleSeek))
                                    {
                                        return;
                                    }

                                    builder.Append(value.Key.GetText(span2.Snapshot));
                                }

                                //builder.AppendLine(span.Tag.Url.OriginalString);
                                //builder.Append(Strings.UrlQuickInfoFollowLink);
                                quickInfoContent.Add(builder.ToString());
                                applicableToSpan = currentSnapshot.CreateTrackingSpan((Span)spans[0], SpanTrackingMode.EdgeExclusive);
                            }
                        }
                    }
                }
            }
        }
        static IEnumerable <TrackingSpanNode <T> > FindNodes(NormalizedSnapshotSpanCollection spans, TrackingSpanNode <T> root, bool recurse = true, bool contained = false)
        {
            if (spans == null || spans.Count == 0 || root.Children.Count == 0)
            {
                yield break;
            }

            int          requestIndex   = 0;
            SnapshotSpan currentRequest = spans[requestIndex];

            // Find the first child
            FindResult findResult = FindChild(currentRequest.Start, root.Children, left: true);
            int        childIndex = findResult.Index;

            if (childIndex >= root.Children.Count)
            {
                yield break;
            }

            ITextSnapshot snapshot     = currentRequest.Snapshot;
            SnapshotSpan  currentChild = root.Children[childIndex].TrackingSpan.GetSpan(snapshot);

            while (requestIndex < spans.Count && childIndex < root.Children.Count)
            {
                if (currentRequest.Start > currentChild.End)
                {
                    // Find the next child
                    childIndex = FindNextChild(root, currentRequest.Start, childIndex);

                    if (childIndex < root.Children.Count)
                    {
                        currentChild = root.Children[childIndex].TrackingSpan.GetSpan(snapshot);
                    }
                }
                else if (currentChild.Start > currentRequest.End)
                {
                    // Skip to the next request
                    if (++requestIndex < spans.Count)
                    {
                        currentRequest = spans[requestIndex];
                    }
                }
                else
                {
                    // Yield the region then move to the next
                    if (!contained || currentRequest.Contains(currentChild))
                    {
                        yield return(root.Children[childIndex]);
                    }

                    if (recurse)
                    {
                        foreach (var result in FindNodes(spans, root.Children[childIndex], recurse, contained))
                        {
                            yield return(result);
                        }
                    }

                    // Find the next child
                    childIndex = FindNextChild(root, currentRequest.Start, childIndex);

                    if (childIndex < root.Children.Count)
                    {
                        currentChild = root.Children[childIndex].TrackingSpan.GetSpan(snapshot);
                    }
                }
            }
        }
        //=====================================================================

        /// <inheritdoc />
        protected override bool ProcessSpans(SnapshotSpan mousePoint, IList<ClassificationSpan> spans)
        {
            string elementName = null, attrName = null, identifier = null;

            foreach(var classification in spans)
            {
                string name = classification.ClassificationType.Classification.ToLowerInvariant();

                // Not supporting VB for now due to problems looking up identifiers
                //if(name.StartsWith("vb ", StringComparison.Ordinal))
                //    name = name.Substring(3);

                if(name.IndexOf("identifier", StringComparison.Ordinal) != -1)
                    name = "identifier";

                // Highlight the span if it matches what we are looking for and it contains the mouse span
                switch(name)
                {
                    case "xml doc tag":
                        // Track the last seen element or attribute.  The classifier in VS2013 and earlier does
                        // not break up the XML comments into elements and attributes so we may get a mix of text
                        // in the "tag".
                        attrName = classification.Span.GetText();

                        // If it contains "cref", the next XML doc attribute value will be the target
                        if(attrName.IndexOf("cref=", StringComparison.Ordinal) != -1 && enableInCRef)
                            attrName = "cref";

                        // As above, for conceptualLink, the next XML doc attribute will be the target
                        if(attrName.StartsWith("<conceptualLink", StringComparison.Ordinal))
                            attrName = "conceptualLink";

                        // For token, the next XML doc comment will contain the token name
                        if(attrName == "<token>")
                            attrName = "token";
                        break;

                    case "xml doc attribute":
                        if((attrName == "cref" || attrName == "conceptualLink") &&
                          classification.Span.Contains(mousePoint) && classification.Span.Length > 2)
                        {
                            // Drop the quotes from the span
                            var span = new SnapshotSpan(classification.Span.Snapshot, classification.Span.Start + 1,
                                classification.Span.Length - 2);

                            if(this.SetHighlightSpan(span, (attrName == "cref") ? "codeEntityReference" : "link"))
                                return true;
                        }
                        break;

                    case "xml doc comment":
                        if(attrName == "token" && classification.Span.Contains(mousePoint) &&
                          classification.Span.Length > 1)
                        {
                            if(this.SetHighlightSpan(classification.Span, "token"))
                                return true;
                        }
                        break;

                    // VS2015 is more specific in its classifications
                    case "xml doc comment - name":
                        elementName = classification.Span.GetText().Trim();
                        break;

                    case "xml doc comment - attribute name":
                        attrName = classification.Span.GetText().Trim();
                        identifier = null;

                        if(attrName == "cref" && !enableInCRef)
                            attrName = null;
                        break;

                    case "xml doc comment - attribute value":
                        if((attrName == "cref" || (elementName == "conceptualLink" && attrName == "target")) &&
                          classification.Span.Contains(mousePoint) && classification.Span.Length > 1)
                        {
                            if(this.SetHighlightSpan(classification.Span,
                              (attrName == "cref") ? "codeEntityReference" : "link"))
                                return true;
                        }
                        break;

                    case "identifier":
                    case "keyword":
                    case "operator":
                        if(attrName != null)
                        {
                            identifier += classification.Span.GetText();

                            if(name == "keyword")
                                identifier += " ";
                        }
                        break;

                    case "punctuation":
                        if(identifier != null)
                            identifier += classification.Span.GetText();
                        break;

                    case "xml doc comment - attribute quotes":
                        if(identifier != null)
                        {
                            // Set the span to that of the identifier
                            var span = new SnapshotSpan(classification.Span.Snapshot,
                                classification.Span.Start - identifier.Length, identifier.Length);

                            if(span.Contains(mousePoint) && span.Length > 1 &&
                              this.SetHighlightSpan(span, "codeEntityReference"))
                                return true;
                        }
                        break;

                    case "xml doc comment - text":
                        if(elementName == "token" && classification.Span.Contains(mousePoint) &&
                          classification.Span.Length > 1)
                        {
                            if(this.SetHighlightSpan(classification.Span, "token"))
                                return true;
                        }
                        break;

                    default:
                        break;
                }
            }

            return false;
        }
        /// <inheritdoc />
        public void AugmentQuickInfoSession(IQuickInfoSession session, IList<object> quickInfoContent,
          out ITrackingSpan applicableToSpan)
        {
            applicableToSpan = null;

            var tagAggregator = provider.AggregatorFactory.CreateTagAggregator<IClassificationTag>(session.TextView);
            var triggerPoint = session.GetTriggerPoint(textBuffer.CurrentSnapshot);

            if(triggerPoint != null)
            {
                SnapshotSpan tagSpan;
                var lineSpan = triggerPoint.Value.GetContainingLine();
                string elementName = null, attrName = null, identifier = null, name;
                UIElement content;

                // Get the tags for the line containing the mouse point
                foreach(IMappingTagSpan<IClassificationTag> curTag in tagAggregator.GetTags(
                  new SnapshotSpan(lineSpan.Start, lineSpan.End)))
                {
                    name = curTag.Tag.ClassificationType.Classification.ToLowerInvariant();
                    tagSpan = curTag.Span.GetSpans(textBuffer).First();

                    if(name.IndexOf("identifier", StringComparison.Ordinal) != -1)
                        name = "identifier";

                    switch(name)
                    {
                        case "xml doc tag":
                            // Track the last seen element or attribute.  The classifier in VS2013 and earlier does
                            // not break up the XML comments into elements and attributes so we may get a mix of text
                            // in the "tag".
                            attrName = tagSpan.GetText();

                            // If it contains "cref", ten next XML doc attribute value will be the target
                            if(attrName.IndexOf("cref=", StringComparison.Ordinal) != -1 && enableInCRef)
                                attrName = "cref";

                            // As above, for conceptualLink, the next XML doc attribute will be the target
                            if(attrName.StartsWith("<conceptualLink", StringComparison.Ordinal))
                                attrName = "conceptualLink";

                            // For token, the next XML doc comment will contain the token name
                            if(attrName == "<token>")
                                attrName = "token";
                            break;

                        case "xml doc attribute":
                            if((attrName == "cref" || attrName == "conceptualLink") &&
                              tagSpan.Contains(triggerPoint.Value) && tagSpan.Length > 2)
                            {
                                // Drop the quotes from the span
                                var span = new SnapshotSpan(tagSpan.Snapshot, tagSpan.Start + 1,
                                    tagSpan.Length - 2);

                                content = this.CreateInfoText(attrName, span.GetText());

                                if(content != null)
                                {
                                    applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(span,
                                        SpanTrackingMode.EdgeExclusive);

                                    quickInfoContent.Add(content);
                                }

                                return;
                            }
                            break;

                        case "xml doc comment":
                            if(attrName == "token" && tagSpan.Contains(triggerPoint.Value) && tagSpan.Length > 1)
                            {
                                content = this.CreateInfoText(attrName, tagSpan.GetText());

                                if(content != null)
                                {
                                    applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(tagSpan,
                                        SpanTrackingMode.EdgeExclusive);

                                    quickInfoContent.Add(content);
                                }

                                return;
                            }
                            break;

                        // VS2015 is more specific in its classifications
                        case "xml doc comment - name":
                            elementName = tagSpan.GetText().Trim();
                            break;

                        case "xml doc comment - attribute name":
                            attrName = tagSpan.GetText().Trim();
                            identifier = null;

                            if(attrName == "cref" && !enableInCRef)
                                attrName = null;
                            break;

                        case "xml doc comment - attribute value":
                            if((attrName == "cref" || (elementName == "conceptualLink" && attrName == "target")) &&
                              tagSpan.Contains(triggerPoint.Value) && tagSpan.Length > 1)
                            {
                                content = this.CreateInfoText((attrName == "cref") ? attrName : elementName,
                                    tagSpan.GetText());

                                if(content != null)
                                {
                                    applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(tagSpan,
                                        SpanTrackingMode.EdgeExclusive);

                                    quickInfoContent.Add(content);
                                }

                                return;
                            }
                            break;

                        case "identifier":
                        case "keyword":
                        case "operator":
                            if(attrName != null)
                            {
                                identifier += tagSpan.GetText();

                                if(name == "keyword")
                                    identifier += " ";
                            }
                            break;

                        case "punctuation":
                            if(identifier != null)
                                identifier += tagSpan.GetText();
                            break;

                        case "xml doc comment - attribute quotes":
                            if(identifier != null)
                            {
                                // Set the span to that of the identifier
                                var span = new SnapshotSpan(tagSpan.Snapshot, tagSpan.Start - identifier.Length,
                                    identifier.Length);

                                if(span.Contains(triggerPoint.Value) && span.Length > 1)
                                {
                                    content = this.CreateInfoText("cref", span.GetText());

                                    if(content != null)
                                    {
                                        applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(span,
                                            SpanTrackingMode.EdgeExclusive);

                                        quickInfoContent.Add(content);
                                    }
                                }

                                return;
                            }
                            break;

                        case "xml doc comment - text":
                            if(elementName == "token" && tagSpan.Contains(triggerPoint.Value) &&
                              tagSpan.Length > 1)
                            {
                                content = this.CreateInfoText(elementName, tagSpan.GetText());

                                if(content != null)
                                {
                                    applicableToSpan = textBuffer.CurrentSnapshot.CreateTrackingSpan(tagSpan,
                                        SpanTrackingMode.EdgeExclusive);

                                    quickInfoContent.Add(content);
                                }

                                return;
                            }
                            break;

                        default:
                            break;
                    }
                }
            }
        }
Example #30
0
        /// <summary>
        /// This is used to process the spans and try to figure out whether or not we have something we can use
        /// for Go To Definition and, i so, the definition type.
        /// </summary>
        /// <param name="cursorPos">The cursor position.</param>
        /// <param name="spans">The spans to process.</param>
        /// <param name="definitionType">On return, this contains the definition type if one was found or null
        /// if not.</param>
        /// <returns>The snapshot span for the definition if one was found, null if not</returns>
        private SnapshotSpan?ProcessSpans(SnapshotPoint cursorPos, IList <ClassificationSpan> spans,
                                          out string definitionType)
        {
            string elementName = null, attrName = null, identifier = null, spanText;

            definitionType = null;

            foreach (var classification in spans)
            {
                string name = classification.ClassificationType.Classification.ToLowerInvariant();

                // Not supporting VB for now due to problems looking up identifiers
                //if(name.StartsWith("vb ", StringComparison.Ordinal))
                //    name = name.Substring(3);

                if (name.IndexOf("identifier", StringComparison.Ordinal) != -1)
                {
                    name = "identifier";
                }

                // Return the span if it matches what we are looking for and it contains the cursor
                switch (name)
                {
                case "xml name":
                    elementName = classification.Span.GetText();
                    break;

                case "xml attribute":
                    attrName = classification.Span.GetText();
                    break;

                case "xml attribute value":
                    if (classification.Span.Contains(cursorPos))
                    {
                        if ((elementName == "image" || elementName == "link") && attrName == "xlink:href")
                        {
                            definitionType = elementName;
                            return(classification.Span);
                        }

                        return(null);
                    }
                    break;

                case "xml text":
                    if (classification.Span.Contains(cursorPos))
                    {
                        spanText = classification.Span.GetText().Trim();

                        switch (elementName)
                        {
                        case "codeEntityReference":
                            if (spanText.IsCodeEntityReference())
                            {
                                definitionType = elementName;
                                return(classification.Span);
                            }
                            break;

                        case "codeReference":
                            if (spanText.IsCodeReferenceId())
                            {
                                definitionType = elementName;
                                return(classification.Span);
                            }
                            break;

                        case "token":
                            definitionType = elementName;
                            return(classification.Span);

                        default:
                            // We only get info about the current line so we may just get some XML text
                            // if the starting tag is on a prior line.  In such cases, see if the text
                            // looks like an entity reference or a code reference ID.  If so, return it
                            // as the definition.  If not, ignore it.
                            if (String.IsNullOrWhiteSpace(elementName))
                            {
                                // Ignore any leading whitespace on the span
                                string highlightText = classification.Span.GetText();

                                int offset   = highlightText.Length - highlightText.TrimStart().Length;
                                var textSpan = new SnapshotSpan(classification.Span.Snapshot,
                                                                classification.Span.Start.Position + offset,
                                                                classification.Span.Length - offset);

                                if (spanText.IsCodeEntityReference())
                                {
                                    definitionType = "codeEntityReference";
                                    return(textSpan);
                                }
                                else
                                if (spanText.IsCodeReferenceId())
                                {
                                    definitionType = "codeReference";
                                    return(textSpan);
                                }
                            }
                            break;
                        }

                        return(null);
                    }
                    break;

                case "xml doc tag":
                    // Track the last seen element or attribute.  The classifier in VS2013 and earlier does
                    // not break up the XML comments into elements and attributes so we may get a mix of text
                    // in the "tag".
                    attrName = classification.Span.GetText();

                    // If it contains "cref", tne next XML doc attribute value will be the target
                    if (attrName.IndexOf("cref=") != -1 && enableInCRef)
                    {
                        attrName = "cref";
                    }

                    // As above, for conceptualLink, the next XML doc attribute will be the target
                    if (attrName.StartsWith("<conceptualLink", StringComparison.Ordinal))
                    {
                        attrName = "conceptualLink";
                    }

                    // For token, the next XML doc comment will contain the token name
                    if (attrName == "<token>")
                    {
                        attrName = "token";
                    }
                    break;

                case "xml doc attribute":
                    if ((attrName == "cref" || attrName == "conceptualLink") &&
                        classification.Span.Contains(cursorPos) && classification.Span.Length > 2)
                    {
                        // Drop the quotes from the span
                        var span = new SnapshotSpan(classification.Span.Snapshot, classification.Span.Start + 1,
                                                    classification.Span.Length - 2);

                        definitionType = (attrName == "cref") ? "codeEntityReference" : "conceptualLink";
                        return(span);
                    }
                    break;

                case "xml doc comment":
                    if (attrName == "token" && classification.Span.Contains(cursorPos) &&
                        classification.Span.Length > 1)
                    {
                        definitionType = "token";
                        return(classification.Span);
                    }
                    break;

                // VS2015 is more specific in its classifications
                case "xml doc comment - name":
                    elementName = classification.Span.GetText().Trim();
                    break;

                case "xml doc comment - attribute name":
                    attrName   = classification.Span.GetText().Trim();
                    identifier = null;

                    if (attrName == "cref" && !enableInCRef)
                    {
                        attrName = null;
                    }
                    break;

                case "xml doc comment - attribute value":
                    if ((attrName == "cref" || (elementName == "conceptualLink" && attrName == "target")) &&
                        classification.Span.Contains(cursorPos) && classification.Span.Length > 1)
                    {
                        definitionType = (attrName == "cref") ? "codeEntityReference" : "conceptualLink";
                        return(classification.Span);
                    }
                    break;

                case "identifier":
                case "keyword":
                case "operator":
                    if (attrName != null)
                    {
                        identifier += classification.Span.GetText();

                        if (name == "keyword")
                        {
                            identifier += " ";
                        }
                    }
                    break;

                case "punctuation":
                    if (identifier != null)
                    {
                        identifier += classification.Span.GetText();
                    }
                    break;

                case "xml doc comment - attribute quotes":
                    if (identifier != null)
                    {
                        // Set the span to that of the identifier
                        var span = new SnapshotSpan(classification.Span.Snapshot,
                                                    classification.Span.Start - identifier.Length, identifier.Length);

                        if (span.Contains(cursorPos) && span.Length > 1)
                        {
                            definitionType = "codeEntityReference";
                            return(span);
                        }
                    }
                    break;

                case "xml doc comment - text":
                    if (elementName == "token" && classification.Span.Contains(cursorPos) &&
                        classification.Span.Length > 1)
                    {
                        definitionType = "token";
                        return(classification.Span);
                    }
                    break;

                default:
                    break;
                }
            }

            return(null);
        }
Example #31
0
        //=====================================================================

        /// <inheritdoc />
        protected override bool ProcessSpans(SnapshotSpan mousePoint, IList <ClassificationSpan> spans)
        {
            string elementName = null, attrName = null, identifier = null;

            foreach (var classification in spans)
            {
                string name = classification.ClassificationType.Classification.ToLowerInvariant();

                // Not supporting VB for now due to problems looking up identifiers
                //if(name.StartsWith("vb ", StringComparison.Ordinal))
                //    name = name.Substring(3);

                if (name.IndexOf("identifier", StringComparison.Ordinal) != -1)
                {
                    name = "identifier";
                }

                // Highlight the span if it matches what we are looking for and it contains the mouse span
                switch (name)
                {
                case "xml doc tag":
                    // Track the last seen element or attribute.  The classifier in VS2013 and earlier does
                    // not break up the XML comments into elements and attributes so we may get a mix of text
                    // in the "tag".
                    attrName = classification.Span.GetText();

                    // If it contains "cref", the next XML doc attribute value will be the target
                    if (attrName.IndexOf("cref=", StringComparison.Ordinal) != -1 && enableInCRef)
                    {
                        attrName = "cref";
                    }

                    // As above, for conceptualLink, the next XML doc attribute will be the target
                    if (attrName.StartsWith("<conceptualLink", StringComparison.Ordinal))
                    {
                        attrName = "conceptualLink";
                    }

                    // For token, the next XML doc comment will contain the token name
                    if (attrName == "<token>")
                    {
                        attrName = "token";
                    }
                    break;

                case "xml doc attribute":
                    if ((attrName == "cref" || attrName == "conceptualLink") &&
                        classification.Span.Contains(mousePoint) && classification.Span.Length > 2)
                    {
                        // Drop the quotes from the span
                        var span = new SnapshotSpan(classification.Span.Snapshot, classification.Span.Start + 1,
                                                    classification.Span.Length - 2);

                        if (this.SetHighlightSpan(span, (attrName == "cref") ? "codeEntityReference" : "link"))
                        {
                            return(true);
                        }
                    }
                    break;

                case "xml doc comment":
                    if (attrName == "token" && classification.Span.Contains(mousePoint) &&
                        classification.Span.Length > 1)
                    {
                        if (this.SetHighlightSpan(classification.Span, "token"))
                        {
                            return(true);
                        }
                    }
                    break;

                // VS2015 is more specific in its classifications
                case "xml doc comment - name":
                    elementName = classification.Span.GetText().Trim();
                    break;

                case "xml doc comment - attribute name":
                    attrName   = classification.Span.GetText().Trim();
                    identifier = null;

                    if (attrName == "cref" && !enableInCRef)
                    {
                        attrName = null;
                    }
                    break;

                case "xml doc comment - attribute value":
                    if ((attrName == "cref" || (elementName == "conceptualLink" && attrName == "target")) &&
                        classification.Span.Contains(mousePoint) && classification.Span.Length > 1)
                    {
                        if (this.SetHighlightSpan(classification.Span,
                                                  (attrName == "cref") ? "codeEntityReference" : "link"))
                        {
                            return(true);
                        }
                    }
                    break;

                case "identifier":
                case "keyword":
                case "operator":
                    if (attrName != null)
                    {
                        identifier += classification.Span.GetText();

                        if (name == "keyword")
                        {
                            identifier += " ";
                        }
                    }
                    break;

                case "punctuation":
                    if (identifier != null)
                    {
                        identifier += classification.Span.GetText();
                    }
                    break;

                case "xml doc comment - attribute quotes":
                    if (identifier != null)
                    {
                        // Set the span to that of the identifier
                        var span = new SnapshotSpan(classification.Span.Snapshot,
                                                    classification.Span.Start - identifier.Length, identifier.Length);

                        if (span.Contains(mousePoint) && span.Length > 1 &&
                            this.SetHighlightSpan(span, "codeEntityReference"))
                        {
                            return(true);
                        }
                    }
                    break;

                case "xml doc comment - text":
                    if (elementName == "token" && classification.Span.Contains(mousePoint) &&
                        classification.Span.Length > 1)
                    {
                        if (this.SetHighlightSpan(classification.Span, "token"))
                        {
                            return(true);
                        }
                    }
                    break;

                default:
                    break;
                }
            }

            return(false);
        }
        /// <summary>
        /// This is used to process the spans and try to figure out whether or not we have something we can use
        /// for Go To Definition and, i so, the definition type.
        /// </summary>
        /// <param name="cursorPos">The cursor position.</param>
        /// <param name="spans">The spans to process.</param>
        /// <param name="definitionType">On return, this contains the definition type if one was found or null
        /// if not.</param>
        /// <returns>The snapshot span for the definition if one was found, null if not</returns>
        private SnapshotSpan? ProcessSpans(SnapshotPoint cursorPos, IList<ClassificationSpan> spans,
          out string definitionType)
        {
            string elementName = null, attrName = null, identifier = null, spanText;

            definitionType = null;

            foreach(var classification in spans)
            {
                string name = classification.ClassificationType.Classification.ToLowerInvariant();

                // Not supporting VB for now due to problems looking up identifiers
                //if(name.StartsWith("vb ", StringComparison.Ordinal))
                //    name = name.Substring(3);

                if(name.IndexOf("identifier", StringComparison.Ordinal) != -1)
                    name = "identifier";

                // Return the span if it matches what we are looking for and it contains the cursor
                switch(name)
                {
                    case "xml name":
                        elementName = classification.Span.GetText();
                        break;

                    case "xml attribute":
                        attrName = classification.Span.GetText();
                        break;

                    case "xml attribute value":
                        if(classification.Span.Contains(cursorPos))
                        {
                            if((elementName == "image" || elementName == "link") && attrName == "xlink:href")
                            {
                                definitionType = elementName;
                                return classification.Span;
                            }

                            return null;
                        }
                        break;

                    case "xml text":
                        if(classification.Span.Contains(cursorPos))
                        {
                            spanText = classification.Span.GetText().Trim();

                            switch(elementName)
                            {
                                case "codeEntityReference":
                                    if(spanText.IsCodeEntityReference())
                                    {
                                        definitionType = elementName;
                                        return classification.Span;
                                    }
                                    break;

                                case "codeReference":
                                    if(spanText.IsCodeReferenceId())
                                    {
                                        definitionType = elementName;
                                        return classification.Span;
                                    }
                                    break;

                                case "token":
                                    definitionType = elementName;
                                    return classification.Span;

                                default:
                                    // We only get info about the current line so we may just get some XML text
                                    // if the starting tag is on a prior line.  In such cases, see if the text
                                    // looks like an entity reference or a code reference ID.  If so, return it
                                    // as the definition.  If not, ignore it.
                                    if(String.IsNullOrWhiteSpace(elementName))
                                    {
                                        // Ignore any leading whitespace on the span
                                        string highlightText = classification.Span.GetText();

                                        int offset = highlightText.Length - highlightText.TrimStart().Length;
                                        var textSpan = new SnapshotSpan(classification.Span.Snapshot,
                                            classification.Span.Start.Position + offset,
                                            classification.Span.Length - offset);

                                        if(spanText.IsCodeEntityReference())
                                        {
                                            definitionType = "codeEntityReference";
                                            return textSpan;
                                        }
                                        else
                                            if(spanText.IsCodeReferenceId())
                                            {
                                                definitionType = "codeReference";
                                                return textSpan;
                                            }
                                    }
                                    break;
                            }

                            return null;
                        }
                        break;

                    case "xml doc tag":
                        // Track the last seen element or attribute.  The classifier in VS2013 and earlier does
                        // not break up the XML comments into elements and attributes so we may get a mix of text
                        // in the "tag".
                        attrName = classification.Span.GetText();

                        // If it contains "cref", ten next XML doc attribute value will be the target
                        if(attrName.IndexOf("cref=", StringComparison.Ordinal) != -1 && enableInCRef)
                            attrName = "cref";

                        // As above, for conceptualLink, the next XML doc attribute will be the target
                        if(attrName.StartsWith("<conceptualLink", StringComparison.Ordinal))
                            attrName = "conceptualLink";

                        // For token, the next XML doc comment will contain the token name
                        if(attrName == "<token>")
                            attrName = "token";
                        break;

                    case "xml doc attribute":
                        if((attrName == "cref" || attrName == "conceptualLink") &&
                          classification.Span.Contains(cursorPos) && classification.Span.Length > 2)
                        {
                            // Drop the quotes from the span
                            var span = new SnapshotSpan(classification.Span.Snapshot, classification.Span.Start + 1,
                                classification.Span.Length - 2);

                            definitionType = (attrName == "cref") ? "codeEntityReference" : "conceptualLink";
                            return span;
                        }
                        break;

                    case "xml doc comment":
                        if(attrName == "token" && classification.Span.Contains(cursorPos) &&
                          classification.Span.Length > 1)
                        {
                            definitionType = "token";
                            return classification.Span;
                        }
                        break;

                    // VS2015 is more specific in its classifications
                    case "xml doc comment - name":
                        elementName = classification.Span.GetText().Trim();
                        break;

                    case "xml doc comment - attribute name":
                        attrName = classification.Span.GetText().Trim();
                        identifier = null;

                        if(attrName == "cref" && !enableInCRef)
                            attrName = null;
                        break;

                    case "xml doc comment - attribute value":
                        if((attrName == "cref" || (elementName == "conceptualLink" && attrName == "target")) &&
                          classification.Span.Contains(cursorPos) && classification.Span.Length > 1)
                        {
                            definitionType = (attrName == "cref") ? "codeEntityReference" : "conceptualLink";
                            return classification.Span;
                        }
                        break;

                    case "identifier":
                    case "keyword":
                    case "operator":
                        if(attrName != null)
                        {
                            identifier += classification.Span.GetText();

                            if(name == "keyword")
                                identifier += " ";
                        }
                        break;

                    case "punctuation":
                        if(identifier != null)
                            identifier += classification.Span.GetText();
                        break;

                    case "xml doc comment - attribute quotes":
                        if(identifier != null)
                        {
                            // Set the span to that of the identifier
                            var span = new SnapshotSpan(classification.Span.Snapshot,
                                classification.Span.Start - identifier.Length, identifier.Length);

                            if(span.Contains(cursorPos) && span.Length > 1)
                            {
                                definitionType = "codeEntityReference";
                                return span;
                            }
                        }
                        break;

                    case "xml doc comment - text":
                        if(elementName == "token" && classification.Span.Contains(cursorPos) &&
                          classification.Span.Length > 1)
                        {
                            definitionType = "token";
                            return classification.Span;
                        }
                        break;

                    default:
                        break;
                }
            }

            return null;
        }
Example #33
0
        private static IEnumerable <Tuple <SnapshotSpan, string> > FindSingleLine(SnapshotPoint startPosition, SnapshotSpan searchRange, FindOptions options, string searchPattern, string replacePattern = null)
        {
            Debug.Assert(searchRange.Contains(startPosition) || searchRange.End == startPosition);

            bool reverse = (options & FindOptions.SearchReverse) == FindOptions.SearchReverse;
            bool regEx   = (options & FindOptions.UseRegularExpressions) == FindOptions.UseRegularExpressions;
            bool wrap    = (options & FindOptions.Wrap) == FindOptions.Wrap;

            ITextSnapshot     snapshot  = startPosition.Snapshot;
            ITextSnapshotLine startLine = startPosition.GetContainingLine();
            int lineIncrement           = reverse ? -1 : 1;
            int startLineNumber         = startLine.LineNumber;
            int searchLineStart         = searchRange.Start.GetContainingLine().LineNumber;
            int searchLineEnd           = searchRange.End.GetContainingLine().LineNumber;

            SnapshotSpan firstLineSpan = startLine.ExtentIncludingLineBreak.Intersection(searchRange).Value;

            // Find results in "first part" of the first line, then search the rest of the range. If wrap is on, afterwards wrap and search
            // the rest of the range, then finally check the first line again and search its "second part".

            // We are effecitvely splitting the first line into the following two portions:
            //
            // FirstLineStart --------------------- startPosition --------------------- FirstLineEnd
            //
            // Depending on the direction of the search, one of the pieces will be searched first, and the other will be searched if
            // wrap is on towards the bottom of the algorithm after all other lines have been searched.

            // Examine first line (regEx can match 0 length strings so we can't exclude that case).
            if ((firstLineSpan.Length > 0) || regEx)
            {
                // Regular expression searches start from the index passed - 1 in reverse direction, as such, if we are at a line boundary
                // we need to be examining the line before
                bool skip = regEx && reverse && startPosition != 0 && startLine.Start == startPosition;

                if (!skip)
                {
                    foreach (var result in FindInString(firstLineSpan.Start, startPosition - firstLineSpan.Start, firstLineSpan.GetText(), options, searchPattern, replacePattern))
                    {
                        yield return(result);
                    }
                }
            }

            // Examine the rest of the range in the original direction
            for (int i = startLineNumber + lineIncrement; (i >= searchLineStart && i <= searchLineEnd); i += lineIncrement)
            {
                foreach (var result in FindInLine(i, searchRange, options, searchPattern, replacePattern))
                {
                    yield return(result);
                }
            }

            // If wrap is enabled, now wrap around the search boundary and continue the search
            if (wrap)
            {
                for (int i = reverse ? searchLineEnd : searchLineStart; i != startLineNumber; i += lineIncrement)
                {
                    foreach (var result in FindInLine(i, searchRange, options, searchPattern, replacePattern))
                    {
                        yield return(result);
                    }
                }

                // Finally look at the remainder of the first line
                foreach (var result in FindInString(firstLineSpan.Start, reverse ? firstLineSpan.End - firstLineSpan.Start : 0,
                                                    firstLineSpan.GetText(), options, searchPattern, replacePattern))
                {
                    // Since we are wrapping, check the validity of the result to ensure it was not returned
                    // in our first search of the first line before wrapping
                    if (reverse)
                    {
                        if (result.Item1.End.Position <= startPosition.Position)
                        {
                            break;
                        }
                    }
                    else
                    {
                        if (result.Item1.Start >= startPosition)
                        {
                            break;
                        }
                    }

                    yield return(result);
                }
            }
        }