public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span) {
            var result = new List<ClassificationSpan>();

            var parseResult = ParserService.ParseResult;
            if (parseResult == null) {
                return result;
            }

            var extent = TextExtent.FromBounds(span.Start.Position, span.End.Position);
            foreach(var token in parseResult.SyntaxTree.Tokens[extent, includeOverlapping: true]) {

                IClassificationType ct;
                _classificationMap.TryGetValue(token.Classification, out ct);
                if (ct == null) {
                    continue;
                }

                var tokenSpan = new SnapshotSpan(parseResult.Snapshot, new Span(token.Start, token.Length));
                
                var classification = new ClassificationSpan(
                        tokenSpan.TranslateTo(span.Snapshot, SpanTrackingMode.EdgeExclusive),
                        ct);

                result.Add(classification);
            }

            return result;
        }
        public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span) {
            var result = new List<ClassificationSpan>();
            
            var semanticModelResult = SemanticModelService.SemanticModelResult;
            if(semanticModelResult == null) {
                return result;
            }

            var classificationType = ClassificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.DeadCode);

            var extent      = TextExtent.FromBounds(span.Start.Position, span.End.Position);
            var diagnostics = semanticModelResult.CompilationUnit.Diagnostics;
            var candidates  = diagnostics.Where(diagnostic => diagnostic.Category == DiagnosticCategory.DeadCode)
                                         .Where(d => d.Location.Extent.IntersectsWith(extent)); 

            foreach (var diagnostic in candidates) {
                var diagnosticSpan = new SnapshotSpan(semanticModelResult.Snapshot, new Span(diagnostic.Location.Start, diagnostic.Location.Length));

                var classification = new ClassificationSpan(
                        diagnosticSpan.TranslateTo(span.Snapshot, SpanTrackingMode.EdgeExclusive),
                        classificationType);


                result.Add(classification);
            }
            
            return result;
        }
        private static SnapshotSpan MapTo(IBufferGraphFactoryService bufferGraphFactoryService, SnapshotSpan span, ITextSnapshot snapshot, SpanTrackingMode spanTrackingMode)
        {
            if (span.Snapshot.TextBuffer == snapshot.TextBuffer)
                return span.TranslateTo(snapshot, spanTrackingMode);

            var graph = bufferGraphFactoryService.CreateBufferGraph(snapshot.TextBuffer);
            var mappingSpan = graph.CreateMappingSpan(span, spanTrackingMode);
            var mapped = mappingSpan.GetSpans(snapshot);
            if (mapped.Count == 1)
                return mapped[0];

            return new SnapshotSpan(mapped[0].Start, mapped[mapped.Count - 1].End);
        }
Example #4
0
        /// <summary>
        /// Visits the specified UVSS document and returns a list of classification spans that
        /// intersect with the specified span.
        /// </summary>
        /// <param name="document">The document to visit.</param>
        /// <param name="span">The span for which to retrieve classification spans.</param>
        /// <returns>The classification spans that intersect with the specified span.</returns>
        public IList<ClassificationSpan> VisitDocument(UvssTextParserResult result, SnapshotSpan span)
        {
            if (result.Document == null)
                return null;

			span = span.TranslateTo(result.Snapshot, SpanTrackingMode.EdgeExclusive);
            
            var results = new List<ClassificationSpan>();
            var visitor = new UvssClassifierVisitor(registry, (start, width, type, kind) =>
            {
                var nodeSpan = new SnapshotSpan(span.Snapshot, start, width);
                if (nodeSpan.IntersectsWith(span))
                    results.Add(new ClassificationSpan(nodeSpan, type));
            });
            visitor.Visit(result.Document);
            
            return results;
        }
Example #5
0
        private void Commit(
            CompletionItem item, Model model, char? commitChar,
            ITextSnapshot initialTextSnapshot, Action nextHandler)
        {
            AssertIsForeground();

            // We could only be called if we had a model at this point.
            Contract.ThrowIfNull(model);

            // Now that we've captured the model at this point, we can stop ourselves entirely.
            // This is also desirable as we may have reentrancy problems when we call into
            // custom commit completion providers.  I.e. if the custom provider moves the caret,
            // then we do not want to process that move as it may put us into an unexpected state.
            //
            // TODO(cyrusn): We still have a general reentrancy problem where calling into a custom
            // commit provider (or just calling into the editor) may cause something to call back
            // into us.  However, for now, we just hope that no such craziness will occur.
            this.DismissSessionIfActive();

            CompletionChange completionChange;
            using (var transaction = CaretPreservingEditTransaction.TryCreate(
                EditorFeaturesResources.IntelliSense, TextView, _undoHistoryRegistry, _editorOperationsFactoryService))
            {
                if (transaction == null)
                {
                    // This text buffer has no undo history and has probably been unmapped.
                    // (Workflow unmaps its projections when losing focus (such as double clicking the completion list)).
                    // Bail on committing completion because we won't be able to find a Document to update either.

                    return;
                }

                // We want to merge with any of our other programmatic edits (e.g. automatic brace completion)
                transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance;

                var provider = GetCompletionProvider(item) as ICustomCommitCompletionProvider;
                if (provider != null)
                {
                    provider.Commit(item, this.TextView, this.SubjectBuffer, model.TriggerSnapshot, commitChar);
                }
                else
                {
                    // Right before calling Commit, we may have passed the commitChar through to the
                    // editor.  That was so that undoing completion will get us back to the state we
                    // we would be in if completion had done nothing.  However, now that we're going
                    // to actually commit, we want to roll back to where we were before we pushed
                    // commit character into the buffer.  This has multiple benefits:
                    //
                    //   1) the buffer is in a state we expect it to be in.  i.e. we don't have to
                    //      worry about what might have happened (like brace-completion) when the
                    //      commit char was inserted.
                    //   2) after we commit the item, we'll pass the commit character again into the
                    //      buffer (unless the items asks us not to).  By doing this, we can make sure
                    //      that things like brace-completion or formatting trigger as we expect them
                    //      to.
                    var characterWasSentIntoBuffer = commitChar != null &&
                                                     initialTextSnapshot.Version.VersionNumber != this.SubjectBuffer.CurrentSnapshot.Version.VersionNumber;
                    if (characterWasSentIntoBuffer)
                    {
                        RollbackToBeforeTypeChar(initialTextSnapshot);
                    }

                    // Now, get the change the item wants to make.  Note that the change will be relative
                    // to the initial snapshot/document the item was triggered from.  We'll map that change
                    // forward, then apply it to our current snapshot.
                    var triggerDocument = model.TriggerDocument;
                    var triggerSnapshot = model.TriggerSnapshot;

                    var completionService = CompletionService.GetService(triggerDocument);
                    Contract.ThrowIfNull(completionService, nameof(completionService));

                    completionChange = completionService.GetChangeAsync(
                        triggerDocument, item, commitChar, CancellationToken.None).WaitAndGetResult(CancellationToken.None);
                    var textChange = completionChange.TextChange;

                    var triggerSnapshotSpan = new SnapshotSpan(triggerSnapshot, textChange.Span.ToSpan());
                    var mappedSpan = triggerSnapshotSpan.TranslateTo(
                        this.SubjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive);

                    // Now actually make the text change to the document.
                    using (var textEdit = this.SubjectBuffer.CreateEdit(EditOptions.None, reiteratedVersionNumber: null, editTag: null))
                    {
                        var adjustedNewText = AdjustForVirtualSpace(textChange);

                        textEdit.Replace(mappedSpan.Span, adjustedNewText);
                        textEdit.Apply();
                    }

                    // adjust the caret position if requested by completion service
                    if (completionChange.NewPosition != null)
                    {
                        TextView.Caret.MoveTo(new SnapshotPoint(
                            this.SubjectBuffer.CurrentSnapshot, completionChange.NewPosition.Value));
                    }

                    // Now, pass along the commit character unless the completion item said not to
                    if (characterWasSentIntoBuffer && !completionChange.IncludesCommitCharacter)
                    {
                        nextHandler();
                    }

                    // If the insertion is long enough, the caret will scroll out of the visible area.
                    // Re-center the view.
                    this.TextView.Caret.EnsureVisible();
                }

                transaction.Complete();
            }

            // Let the completion rules know that this item was committed.
            this.MakeMostRecentItem(item.DisplayText);
        }
            private void AddClassifiedSpansForPreviousTree(
                IEditorClassificationService classificationService, SnapshotSpan span, ITextSnapshot lastSnapshot, Document lastDocument, List<ClassifiedSpan> classifiedSpans)
            {
                // Slightly more complicated case.  They're asking for the classifications for a
                // different snapshot than what we have a parse tree for.  So we first translate the span
                // that they're asking for so that is maps onto the tree that we have spans for.  We then
                // get the classifications from that tree.  We then take the results and translate them
                // back to the snapshot they want.  Finally, as some of the classifications may have
                // changed, we check for some common cases and touch them up manually so that things
                // look right for the user.

                // Note the handling of SpanTrackingModes here: We do EdgeExclusive while mapping back ,
                // and EdgeInclusive mapping forward. What I've convinced myself is that EdgeExclusive
                // is best when mapping back over a deletion, so that we don't end up classifying all of
                // the deleted code.  In most addition/modification cases, there will be overlap with
                // existing spans, and so we'll end up classifying well.  In the worst case, there is a
                // large addition that doesn't exist when we map back, and so we don't have any
                // classifications for it. That's probably okay, because: 

                // 1. If it's that large, it's likely that in reality there are multiple classification
                // spans within it.

                // 2.We'll eventually call ClassificationsChanged and re-classify that region anyway.

                // When mapping back forward, we use EdgeInclusive so that in the common typing cases we
                // don't end up with half a token colored differently than the other half.

                // See bugs like http://vstfdevdiv:8080/web/wi.aspx?id=6176 for an example of what can
                // happen when this goes wrong.

                // 1) translate the requested span onto the right span for the snapshot that corresponds
                //    to the syntax tree.
                var translatedSpan = span.TranslateTo(lastSnapshot, SpanTrackingMode.EdgeExclusive);
                if (translatedSpan.IsEmpty)
                {
                    // well, there is no information we can get from previous tree, use lexer to
                    // classify given span. soon we will re-classify the region.
                    AddClassifiedSpansForTokens(classificationService, span, classifiedSpans);
                    return;
                }

                var tempList = ClassificationUtilities.GetOrCreateClassifiedSpanList();
                AddClassifiedSpansForCurrentTree(classificationService, translatedSpan, lastDocument, tempList);

                var currentSnapshot = span.Snapshot;
                var currentText = currentSnapshot.AsText();
                foreach (var lastClassifiedSpan in tempList)
                {
                    // 2) Translate those classifications forward so that they correspond to the true
                    //    requested snapshot.
                    var lastSnapshotSpan = lastClassifiedSpan.TextSpan.ToSnapshotSpan(lastSnapshot);
                    var currentSnapshotSpan = lastSnapshotSpan.TranslateTo(currentSnapshot, SpanTrackingMode.EdgeInclusive);

                    var currentClassifiedSpan = new ClassifiedSpan(lastClassifiedSpan.ClassificationType, currentSnapshotSpan.Span.ToTextSpan());

                    // 3) The classifications may be incorrect due to changes in the text.  For example,
                    //    if "clss" becomes "class", then we want to changes the classification from
                    //    'identifier' to 'keyword'.
                    currentClassifiedSpan = classificationService.AdjustStaleClassification(currentText, currentClassifiedSpan);

                    classifiedSpans.Add(currentClassifiedSpan);
                }

                ClassificationUtilities.ReturnClassifiedSpanList(tempList);
            }
Example #7
0
#pragma warning restore 67

    public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan processedSpan)
    {
      var currentSnapshot = processedSpan.Snapshot;
      var result = new List<ClassificationSpan>();

      for (int i = 0; i < _spanInfos.Length; i++)
      {
        var snapshot  = _snapshots[i];
        var spanInfos = _spanInfos[i];
        var translatesSnapshot = processedSpan.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
        var processedSpanInfo = new SpanInfo(new NSpan(translatesSnapshot.Span.Start, translatesSnapshot.Span.End), -1);
        var index = spanInfos.BinarySearch(processedSpanInfo, SpanInfo.Comparer);
        if (index < 0)
          index = ~index;

        for (int k = index; k < spanInfos.Length; k++)
        {
          var spanInfo = spanInfos[k];
          var span     = spanInfo.Span;
          var newSpan  = new SnapshotSpan(snapshot, new Span(span.StartPos, span.Length))
                              .TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive);

          if (!newSpan.IntersectsWith(processedSpan))
            break;

          var classificationType = ClassificationMap[spanInfo.SpanClassId];
          result.Add(new ClassificationSpan(newSpan, classificationType));
        }
      }

      return result;
    }
Example #8
0
            // From DynamicParserLanguageServiceItem
            SnapshotSpan GetCurrentSpan(ITextSnapshot snapshot, SourceSpan span)
            {
                ITextSnapshot currentSnapshot = this.bufferView.TextBuffer.CurrentSnapshot;
                // TODO (dougwa): deal with line/column spans
                TextSnapshot cloneSnapshot = new TextSnapshot(snapshot, (TextBufferClone)this.bufferView.TextBuffer);
                SnapshotSpan oldSpan = new SnapshotSpan(cloneSnapshot, span.Start.Index, span.Length);

                SnapshotSpan newSpan = oldSpan.TranslateTo(currentSnapshot, SpanTrackingMode.EdgePositive);
                return newSpan;
            }
        private void Commit(
            PresentationItem item, Model model, char?commitChar,
            ITextSnapshot initialTextSnapshot, Action nextHandler)
        {
            AssertIsForeground();

            // We could only be called if we had a model at this point.
            Contract.ThrowIfNull(model);

            // Now that we've captured the model at this point, we can stop ourselves entirely.
            // This is also desirable as we may have reentrancy problems when we call into
            // custom commit completion providers.  I.e. if the custom provider moves the caret,
            // then we do not want to process that move as it may put us into an unexpected state.
            //
            // TODO(cyrusn): We still have a general reentrancy problem where calling into a custom
            // commit provider (or just calling into the editor) may cause something to call back
            // into us.  However, for now, we just hope that no such craziness will occur.
            this.StopModelComputation();

            CompletionChange completionChange;

            using (var transaction = new CaretPreservingEditTransaction(
                       EditorFeaturesResources.IntelliSense, TextView, _undoHistoryRegistry, _editorOperationsFactoryService))
            {
                // We want to merge with any of our other programmatic edits (e.g. automatic brace completion)
                transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance;

                var provider = GetCompletionProvider(item.Item) as ICustomCommitCompletionProvider;
                if (provider != null)
                {
                    provider.Commit(item.Item, this.TextView, this.SubjectBuffer, model.TriggerSnapshot, commitChar);
                }
                else
                {
                    // Right before calling Commit, we may have passed the commitChar through to the
                    // editor.  That was so that undoing completion will get us back to the state we
                    // we would be in if completion had done nothing.  However, now that we're going
                    // to actually commit, we want to roll back to where we were before we pushed
                    // commit character into the buffer.  This has multiple benefits:
                    //
                    //   1) the buffer is in a state we expect it to be in.  i.e. we don't have to
                    //      worry about what might have happened (like brace-completion) when the
                    //      commit char was inserted.
                    //   2) after we commit the item, we'll pass the commit character again into the
                    //      buffer (unless the items asks us not to).  By doing this, we can make sure
                    //      that things like brace-completion or formatting trigger as we expect them
                    //      to.
                    var characterWasSentIntoBuffer = commitChar != null &&
                                                     initialTextSnapshot.Version.VersionNumber != this.SubjectBuffer.CurrentSnapshot.Version.VersionNumber;
                    if (characterWasSentIntoBuffer)
                    {
                        RollbackToBeforeTypeChar(initialTextSnapshot);
                    }

                    // Now, get the change the item wants to make.  Note that the change will be relative
                    // to the initial snapshot/document the item was triggered from.  We'll map that change
                    // forward, then apply it to our current snapshot.
                    var triggerDocument = model.TriggerDocument;
                    var triggerSnapshot = model.TriggerSnapshot;

                    var completionService = CompletionService.GetService(triggerDocument);
                    Contract.ThrowIfNull(completionService, nameof(completionService));

                    completionChange = completionService.GetChangeAsync(
                        triggerDocument, item.Item, commitChar, CancellationToken.None).WaitAndGetResult(CancellationToken.None);
                    var textChange = completionChange.TextChange;

                    var triggerSnapshotSpan = new SnapshotSpan(triggerSnapshot, textChange.Span.ToSpan());
                    var mappedSpan          = triggerSnapshotSpan.TranslateTo(
                        this.SubjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive);

                    // Now actually make the text change to the document.
                    using (var textEdit = this.SubjectBuffer.CreateEdit(EditOptions.None, reiteratedVersionNumber: null, editTag: null))
                    {
                        var adjustedNewText = AdjustForVirtualSpace(textChange);

                        textEdit.Replace(mappedSpan.Span, adjustedNewText);
                        textEdit.Apply();
                    }

                    // adjust the caret position if requested by completion service
                    if (completionChange.NewPosition != null)
                    {
                        TextView.Caret.MoveTo(new SnapshotPoint(
                                                  this.SubjectBuffer.CurrentSnapshot, completionChange.NewPosition.Value));
                    }

                    // Now, pass along the commit character unless the completion item said not to
                    if (characterWasSentIntoBuffer && !completionChange.IncludesCommitCharacter)
                    {
                        nextHandler();
                    }

                    // If the insertion is long enough, the caret will scroll out of the visible area.
                    // Re-center the view.
                    this.TextView.Caret.EnsureVisible();
                }

                transaction.Complete();
            }

            // Let the completion rules know that this item was committed.
            this.MakeMostRecentItem(item.Item.DisplayText);
        }
Example #10
0
        private AsyncCompletionData.CommitResult Commit(
            IAsyncCompletionSession session,
            Document document,
            CompletionService completionService,
            ITextBuffer subjectBuffer,
            RoslynCompletionItem roslynItem,
            TextSpan completionListSpan,
            char?commitCharacter,
            ITextSnapshot triggerSnapshot,
            CompletionRules rules,
            string filterText,
            CancellationToken cancellationToken)
        {
            AssertIsForeground();

            bool includesCommitCharacter;

            if (!subjectBuffer.CheckEditAccess())
            {
                // We are on the wrong thread.
                FatalError.ReportWithoutCrash(new InvalidOperationException("Subject buffer did not provide Edit Access"));
                return(new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.None));
            }

            if (subjectBuffer.EditInProgress)
            {
                FatalError.ReportWithoutCrash(new InvalidOperationException("Subject buffer is editing by someone else."));
                return(new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.None));
            }

            var disallowAddingImports = session.Properties.ContainsProperty(CompletionSource.DisallowAddingImports);

            CompletionChange change;

            // We met an issue when external code threw an OperationCanceledException and the cancellationToken is not cancelled.
            // Catching this scenario for further investigations.
            // See https://github.com/dotnet/roslyn/issues/38455.
            try
            {
                change = completionService.GetChangeAsync(document, roslynItem, completionListSpan, commitCharacter, disallowAddingImports, cancellationToken).WaitAndGetResult(cancellationToken);
            }
            catch (OperationCanceledException e) when(e.CancellationToken != cancellationToken && FatalError.ReportWithoutCrash(e))
            {
                return(CommitResultUnhandled);
            }

            cancellationToken.ThrowIfCancellationRequested();

            var view = session.TextView;

            if (GetCompletionProvider(completionService, roslynItem) is ICustomCommitCompletionProvider provider)
            {
                provider.Commit(roslynItem, view, subjectBuffer, triggerSnapshot, commitCharacter);
                return(new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.None));
            }

            var textChange          = change.TextChange;
            var triggerSnapshotSpan = new SnapshotSpan(triggerSnapshot, textChange.Span.ToSpan());
            var mappedSpan          = triggerSnapshotSpan.TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive);

            using (var edit = subjectBuffer.CreateEdit(EditOptions.DefaultMinimalChange, reiteratedVersionNumber: null, editTag: null))
            {
                edit.Replace(mappedSpan.Span, change.TextChange.NewText);

                // edit.Apply() may trigger changes made by extensions.
                // updatedCurrentSnapshot will contain changes made by Roslyn but not by other extensions.
                var updatedCurrentSnapshot = edit.Apply();

                if (change.NewPosition.HasValue)
                {
                    // Roslyn knows how to positionate the caret in the snapshot we just created.
                    // If there were more edits made by extensions, TryMoveCaretToAndEnsureVisible maps the snapshot point to the most recent one.
                    view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(updatedCurrentSnapshot, change.NewPosition.Value));
                }
                else
                {
                    // Or, If we're doing a minimal change, then the edit that we make to the
                    // buffer may not make the total text change that places the caret where we
                    // would expect it to go based on the requested change. In this case,
                    // determine where the item should go and set the care manually.

                    // Note: we only want to move the caret if the caret would have been moved
                    // by the edit.  i.e. if the caret was actually in the mapped span that
                    // we're replacing.
                    var caretPositionInBuffer = view.GetCaretPoint(subjectBuffer);
                    if (caretPositionInBuffer.HasValue && mappedSpan.IntersectsWith(caretPositionInBuffer.Value))
                    {
                        view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(subjectBuffer.CurrentSnapshot, mappedSpan.Start.Position + textChange.NewText.Length));
                    }
                    else
                    {
                        view.Caret.EnsureVisible();
                    }
                }

                includesCommitCharacter = change.IncludesCommitCharacter;

                if (roslynItem.Rules.FormatOnCommit)
                {
                    // The edit updates the snapshot however other extensions may make changes there.
                    // Therefore, it is required to use subjectBuffer.CurrentSnapshot for further calculations rather than the updated current snapsot defined above.
                    document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
                    var spanToFormat      = triggerSnapshotSpan.TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive);
                    var formattingService = document?.GetLanguageService <IEditorFormattingService>();

                    if (formattingService != null)
                    {
                        var changes = formattingService.GetFormattingChangesAsync(
                            document, spanToFormat.Span.ToTextSpan(), CancellationToken.None).WaitAndGetResult(CancellationToken.None);
                        document.Project.Solution.Workspace.ApplyTextChanges(document.Id, changes, CancellationToken.None);
                    }
                }
            }

            _recentItemsManager.MakeMostRecentItem(roslynItem.FilterText);

            if (includesCommitCharacter)
            {
                return(new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.SuppressFurtherTypeCharCommandHandlers));
            }

            if (commitCharacter == '\n' && SendEnterThroughToEditor(rules, roslynItem, filterText))
            {
                return(new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.RaiseFurtherReturnKeyAndTabKeyCommandHandlers));
            }

            return(new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.None));
        }
Example #11
0
		public NormalizedSnapshotSpanCollection MapUpToSnapshot(SnapshotSpan span, SpanTrackingMode trackingMode, ITextSnapshot targetSnapshot) {
			if (span.Snapshot == null)
				throw new ArgumentException();
			if (targetSnapshot == null)
				throw new ArgumentNullException(nameof(targetSnapshot));

			if (span.Snapshot.TextBuffer != TopBuffer)
				return NormalizedSnapshotSpanCollection.Empty;
			if (targetSnapshot.TextBuffer != TopBuffer)
				return NormalizedSnapshotSpanCollection.Empty;
			return new NormalizedSnapshotSpanCollection(span.TranslateTo(targetSnapshot, trackingMode));
		}
Example #12
0
            private void AddClassifiedSpansForPreviousTree(
                IEditorClassificationService classificationService, SnapshotSpan span, ITextSnapshot lastSnapshot, Document lastDocument, List <ClassifiedSpan> classifiedSpans)
            {
                // Slightly more complicated case.  They're asking for the classifications for a
                // different snapshot than what we have a parse tree for.  So we first translate the span
                // that they're asking for so that is maps onto the tree that we have spans for.  We then
                // get the classifications from that tree.  We then take the results and translate them
                // back to the snapshot they want.  Finally, as some of the classifications may have
                // changed, we check for some common cases and touch them up manually so that things
                // look right for the user.

                // Note the handling of SpanTrackingModes here: We do EdgeExclusive while mapping back ,
                // and EdgeInclusive mapping forward. What I've convinced myself is that EdgeExclusive
                // is best when mapping back over a deletion, so that we don't end up classifying all of
                // the deleted code.  In most addition/modification cases, there will be overlap with
                // existing spans, and so we'll end up classifying well.  In the worst case, there is a
                // large addition that doesn't exist when we map back, and so we don't have any
                // classifications for it. That's probably okay, because:

                // 1. If it's that large, it's likely that in reality there are multiple classification
                // spans within it.

                // 2.We'll eventually call ClassificationsChanged and re-classify that region anyway.

                // When mapping back forward, we use EdgeInclusive so that in the common typing cases we
                // don't end up with half a token colored differently than the other half.

                // See bugs like http://vstfdevdiv:8080/web/wi.aspx?id=6176 for an example of what can
                // happen when this goes wrong.

                // 1) translate the requested span onto the right span for the snapshot that corresponds
                //    to the syntax tree.
                var translatedSpan = span.TranslateTo(lastSnapshot, SpanTrackingMode.EdgeExclusive);

                if (translatedSpan.IsEmpty)
                {
                    // well, there is no information we can get from previous tree, use lexer to
                    // classify given span. soon we will re-classify the region.
                    AddClassifiedSpansForTokens(classificationService, span, classifiedSpans);
                    return;
                }

                var tempList = ClassificationUtilities.GetOrCreateClassifiedSpanList();

                AddClassifiedSpansForCurrentTree(classificationService, translatedSpan, lastDocument, tempList);

                var currentSnapshot = span.Snapshot;
                var currentText     = currentSnapshot.AsText();

                foreach (var lastClassifiedSpan in tempList)
                {
                    // 2) Translate those classifications forward so that they correspond to the true
                    //    requested snapshot.
                    var lastSnapshotSpan    = lastClassifiedSpan.TextSpan.ToSnapshotSpan(lastSnapshot);
                    var currentSnapshotSpan = lastSnapshotSpan.TranslateTo(currentSnapshot, SpanTrackingMode.EdgeInclusive);

                    var currentClassifiedSpan = new ClassifiedSpan(lastClassifiedSpan.ClassificationType, currentSnapshotSpan.Span.ToTextSpan());

                    // 3) The classifications may be incorrect due to changes in the text.  For example,
                    //    if "clss" becomes "class", then we want to changes the classification from
                    //    'identifier' to 'keyword'.
                    currentClassifiedSpan = classificationService.AdjustStaleClassification(currentText, currentClassifiedSpan);

                    classifiedSpans.Add(currentClassifiedSpan);
                }

                ClassificationUtilities.ReturnClassifiedSpanList(tempList);
            }
        private SnapshotSpan MapTo(SnapshotSpan span, ITextSnapshot snapshot, SpanTrackingMode spanTrackingMode)
        {
            if (span.Snapshot.TextBuffer == snapshot.TextBuffer)
                return span.TranslateTo(snapshot, spanTrackingMode);

            IBufferGraph graph = _bufferGraphFactoryService.CreateBufferGraph(snapshot.TextBuffer);
            IMappingSpan mappingSpan = graph.CreateMappingSpan(span, spanTrackingMode);
            NormalizedSnapshotSpanCollection mapped = mappingSpan.GetSpans(snapshot);
            if (mapped.Count == 1)
                return mapped[0];

            return new SnapshotSpan(mapped[0].Start, mapped[mapped.Count - 1].End);
        }
        public IEnumerable <ITagSpan <TextMarkerTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            if (!settings.XmlMatchTagsEnabled)
            {
                yield break;
            }
            if (spans.Count == 0)
            {
                yield break;
            }
            if (!currentSpan.HasValue)
            {
                yield break;
            }

            SnapshotSpan current = currentSpan.Value;

            if (current.Snapshot != spans[0].Snapshot)
            {
                current = current.TranslateTo(spans[0].Snapshot, SpanTrackingMode.EdgePositive);
            }

            SnapshotSpan currentTag = CompleteTag(current);
            String       text       = currentTag.GetText();

            // avoid processing statements or xml declarations
            if (text.Contains('?'))
            {
                yield break;
            }

            SnapshotSpan?complementTag = null;

            if (text.StartsWith("</"))
            {
                complementTag = FindOpeningTag(current.Snapshot, currentTag.End, current.GetText());
                if (complementTag != null)
                {
                    complementTag = ExtendOpeningTag(complementTag.Value);
                }
            }
            else
            {
                String searchFor = "</" + current.GetText() + ">";
                currentTag    = ExtendOpeningTag(currentTag);
                complementTag = FindClosingTag(current.Snapshot, currentTag.Start, searchFor);
            }

            var defaultTag   = new TextMarkerTag("bracehighlight");
            var alternateTag = new TextMarkerTag("other error");

            if (complementTag.HasValue)
            {
                yield return(new TagSpan <TextMarkerTag>(currentTag, defaultTag));

                yield return(new TagSpan <TextMarkerTag>(complementTag.Value, defaultTag));
            }
            else
            {
                // no matching tag found, or element has no content
                yield return(new TagSpan <TextMarkerTag>(currentTag,
                                                         currentTag.GetText().EndsWith("/>") ? defaultTag : alternateTag));
            }
        }
Example #15
0
 public NormalizedSnapshotSpanCollection MapUpToBuffer(SnapshotSpan span, SpanTrackingMode trackingMode, ITextBuffer targetBuffer)
 {
     if (_buffers.Count == 1 && _buffers[0] == span.Snapshot.TextBuffer) {
         return new NormalizedSnapshotSpanCollection(span.TranslateTo(span.Snapshot.TextBuffer.CurrentSnapshot, trackingMode));
     }
     throw new NotImplementedException();
 }
Example #16
0
 public NormalizedSnapshotSpanCollection MapDownToFirstMatch(SnapshotSpan span, SpanTrackingMode trackingMode, Predicate<ITextSnapshot> match)
 {
     if (_buffers.Count == 1 && _buffers[0] == span.Snapshot.TextBuffer) {
         return new NormalizedSnapshotSpanCollection(span.TranslateTo(span.Snapshot.TextBuffer.CurrentSnapshot, trackingMode));
     }
     throw new NotImplementedException();
 }
            /// <summary>
            /// Translates the symbol to the specified snapshot.
            /// </summary>
            /// <param name="snapshot">The snapshot to which to translate the symbol.</param>
            public void TranslateTo(ITextSnapshot snapshot)
            {
                var oldSpan = new SnapshotSpan(Snapshot, Position, 2);
                var newSpan = oldSpan.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);

                this.Snapshot = snapshot;
                this.Position = newSpan.Start;
            }
Example #18
0
        protected virtual SnapshotSpan CommentSpan(SnapshotSpan span, ITextEdit edit)
        {
            Contract.Requires<ArgumentNullException>(edit != null, "edit");

            span = span.TranslateTo(edit.Snapshot, SpanTrackingMode.EdgeExclusive);

            /*
             * Use line comments if:
             *  UseLineComments is true
             *  AND one of the following is true:
             *
             *  1. there is no selected text
             *  2. on the line where the selection starts, there is only whitespace up to the selection start point
             *     AND on the line where the selection ends, there is only whitespace up to the selection end point,
             *         OR there is only whitespace from the selection end point to the end of the line
             *
             * Use block comments if:
             *  We are not using line comments
             *  AND some text is selected
             *  AND PreferredBlockFormat is not null
             */
            var startContainingLine = span.Start.GetContainingLine();
            var endContainingLine = span.End.GetContainingLine();

            if (UseLineComments
                && (span.IsEmpty ||
                    (string.IsNullOrWhiteSpace(startContainingLine.GetText().Substring(0, span.Start - startContainingLine.Start))
                        && (string.IsNullOrWhiteSpace(endContainingLine.GetText().Substring(0, span.End - endContainingLine.Start))
                            || string.IsNullOrWhiteSpace(endContainingLine.GetText().Substring(span.End - endContainingLine.Start)))
                   )))
            {
                span = CommentLines(span, edit, PreferredLineFormat);
            }
            else if (
                span.Length > 0
                && PreferredBlockFormat != null
                )
            {
                span = CommentBlock(span, edit, PreferredBlockFormat);
            }

            return span;
        }
Example #19
0
		public NormalizedSnapshotSpanCollection MapUpToFirstMatch(SnapshotSpan span, SpanTrackingMode trackingMode, Predicate<ITextSnapshot> match) {
			if (span.Snapshot == null)
				throw new ArgumentException();
			if (match == null)
				throw new ArgumentNullException(nameof(match));

			if (span.Snapshot.TextBuffer != TopBuffer)
				return NormalizedSnapshotSpanCollection.Empty;
			if (!match(TopBuffer.CurrentSnapshot))
				return NormalizedSnapshotSpanCollection.Empty;
			return new NormalizedSnapshotSpanCollection(span.TranslateTo(TopBuffer.CurrentSnapshot, trackingMode));
		}
Example #20
0
        protected virtual SnapshotSpan UncommentSpan(SnapshotSpan span, ITextEdit edit)
        {
            Contract.Requires<ArgumentNullException>(edit != null, "edit");

            span = span.TranslateTo(edit.Snapshot, SpanTrackingMode.EdgeExclusive);
            bool useLineComments = true;
            var startContainingLine = span.Start.GetContainingLine();
            var endContainingLine = span.End.GetContainingLine();

            // special case: empty span
            if (span.IsEmpty)
            {
                if (useLineComments)
                    span = UncommentLines(span, edit, LineFormats);
            }
            else
            {
                SnapshotSpan resultSpan;
                if (TryUncommentBlock(span, edit, BlockFormats, out resultSpan))
                    return resultSpan;

                if (useLineComments)
                {
                    span = UncommentLines(span, edit, LineFormats);
                }
            }

            return span;
        }
Example #21
0
        /// <summary>
        /// Combines one text change with another
        /// </summary>
        public void Combine(TextChange other)
        {
            if (other.IsEmpty)
            {
                return;
            }

            FullParseRequired |= other.FullParseRequired;
            TextChangeType    |= other.TextChangeType;

            if (OldRange == TextRange.EmptyRange || NewRange == TextRange.EmptyRange)
            {
                OldRange        = other.OldRange;
                NewRange        = other.NewRange;
                OldTextProvider = other.OldTextProvider;
                NewTextProvider = other.NewTextProvider;
            }
            else
            {
                ITextSnapshotProvider oldSnapshotProvider      = OldTextProvider as ITextSnapshotProvider;
                ITextSnapshotProvider newSnapshotProvider      = NewTextProvider as ITextSnapshotProvider;
                ITextSnapshotProvider otherOldSnapshotProvider = other.OldTextProvider as ITextSnapshotProvider;
                ITextSnapshotProvider otherNewSnapshotProvider = other.NewTextProvider as ITextSnapshotProvider;
                bool changesAreFromNextSnapshot = false;

                if ((oldSnapshotProvider != null) && (newSnapshotProvider != null) &&
                    (otherOldSnapshotProvider != null) && (otherNewSnapshotProvider != null))
                {
                    ITextSnapshot newSnapshot      = newSnapshotProvider.Snapshot;
                    ITextSnapshot otherOldSnapshot = otherOldSnapshotProvider.Snapshot;
                    if (newSnapshot.Version.ReiteratedVersionNumber == otherOldSnapshot.Version.ReiteratedVersionNumber)
                    {
                        changesAreFromNextSnapshot = true;
                    }
                }

                if (!changesAreFromNextSnapshot)
                {
                    // Assume these changes are from the same snapshot
                    int oldStart = Math.Min(other.OldRange.Start, this.OldRange.Start);
                    int oldEnd   = Math.Max(other.OldRange.End, this.OldRange.End);

                    int newStart = Math.Min(other.NewRange.Start, this.NewRange.Start);
                    int newEnd   = Math.Max(other.NewRange.End, this.NewRange.End);

                    OldRange = TextRange.FromBounds(oldStart, oldEnd);
                    NewRange = TextRange.FromBounds(newStart, newEnd);
                }
                else
                {
                    // the "other" change is from the subsequent snapshot. Merge the changes.
                    ITextSnapshot oldSnapshot      = oldSnapshotProvider.Snapshot;
                    ITextSnapshot newSnapshot      = newSnapshotProvider.Snapshot;
                    ITextSnapshot otherOldSnapshot = otherOldSnapshotProvider.Snapshot;
                    ITextSnapshot otherNewSnapshot = otherNewSnapshotProvider.Snapshot;

                    SnapshotSpan otherOldSpan = other.OldRange.ToSnapshotSpan(otherOldSnapshot);
                    SnapshotSpan oldSpan      = otherOldSpan.TranslateTo(oldSnapshot, SpanTrackingMode.EdgeInclusive);

                    SnapshotSpan newSpan      = NewRange.ToSnapshotSpan(newSnapshot);
                    SnapshotSpan otherNewSpan = newSpan.TranslateTo(otherNewSnapshot, SpanTrackingMode.EdgeInclusive);

                    OldRange        = new TextRange(TextRange.Union(OldRange, oldSpan.ToTextRange()));
                    NewRange        = new TextRange(TextRange.Union(other.NewRange, otherNewSpan.ToTextRange()));
                    NewTextProvider = other.NewTextProvider;
                }
            }

            Version = Math.Max(this.Version, other.Version);
        }