Exemple #1
0
        void SelectionChangedHandler(object sender, EventArgs e)
        {
            if (suppressChangeEvent)
            {
                return;
            }

            var pos = SelectedRow;

            if (pos == null)
            {
                return;
            }

            var nav  = store.GetNavigatorAt(pos);
            var span = nav.GetValue(spanField);

            var roslynSnapshot = lastSourceText.FindCorrespondingEditorTextSnapshot();

            if (roslynSnapshot == null)
            {
                return;
            }
            var editorSpan = new SnapshotSpan(roslynSnapshot, span.Start, span.Length);

            suppressChangeEvent = true;
            try {
                editorTracker.TextView.Selection.Select(editorSpan, false);
            } finally {
                suppressChangeEvent = false;
            }
        }
        /// <summary>
        /// Displays highlights at the given locations.
        /// </summary>
        public void HighlightText(
            SourceText text,
            IDictionary <HighlightType, IEnumerable <TextSpan> > highlights)
        {
            Contract.Requires <ArgumentNullException>(text != null, nameof(text));
            Contract.Requires <ArgumentNullException>(highlights != null, nameof(highlights));

            var snapshot = text.FindCorrespondingEditorTextSnapshot();

            if (snapshot == null)
            {
                return;
            }

            var vsHighlights = new Dictionary <HighlightType, NormalizedSnapshotSpanCollection>();

            foreach (var highlight in highlights)
            {
                var vsSpans = highlight.Value
                              .Select(span => new SnapshotSpan(snapshot, span.Start, span.End - span.Start));
                var vsSpanCollection = new NormalizedSnapshotSpanCollection(vsSpans);
                vsHighlights.Add(highlight.Key, vsSpanCollection);
            }

            this.highlightService.HighlightText(snapshot, vsHighlights);
        }
Exemple #3
0
            public IEnumerable <ActiveStatementTextSpan> GetSpans(SourceText source)
            {
                var document = source.GetOpenDocumentInCurrentContextWithChanges();

                if (document == null)
                {
                    return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                }

                // We might be asked for spans in a different workspace than
                // the one we maintain tracking spans for (for example, a preview).
                if (document.Project.Solution.Workspace != _editSession.BaseSolution.Workspace)
                {
                    return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                }

                ITrackingSpan[] documentTrackingSpans;
                lock (_trackingSpans)
                {
                    if (!_trackingSpans.TryGetValue(document.Id, out documentTrackingSpans) || documentTrackingSpans == null)
                    {
                        return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                    }
                }

                Debug.Assert(documentTrackingSpans.Length > 0);
                var snapshot = source.FindCorrespondingEditorTextSnapshot();

                // The document might have been reopened with a new text buffer
                // and we haven't created tracking spans for the new text buffer yet.
                if (snapshot == null || snapshot.TextBuffer != documentTrackingSpans[0].TextBuffer)
                {
                    return(SpecializedCollections.EmptyEnumerable <ActiveStatementTextSpan>());
                }

                var baseStatements = _editSession.BaseActiveStatements[document.Id];

                Debug.Assert(documentTrackingSpans.Length == baseStatements.Length);

                var result = new ActiveStatementTextSpan[documentTrackingSpans.Length];

                for (int i = 0; i < documentTrackingSpans.Length; i++)
                {
                    Debug.Assert(documentTrackingSpans[i].TextBuffer == snapshot.TextBuffer);

                    result[i] = new ActiveStatementTextSpan(
                        baseStatements[i].Flags,
                        documentTrackingSpans[i].GetSpan(snapshot).Span.ToTextSpan());
                }

                return(result);
            }
Exemple #4
0
            private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e)
            {
                // Do some quick checks to avoid doing any further work for diagnostics  we don't
                // care about.
                var ourDocument = _subjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext();

                if (ourDocument == null ||
                    ourDocument.Project.Solution.Workspace != e.Workspace ||
                    ourDocument.Id != e.DocumentId)
                {
                    return;
                }

                // Make sure we can find an editor snapshot for these errors.  Otherwise we won't
                // be able to make ITagSpans for them.  If we can't, just bail out.  This happens
                // when the solution crawler is very far behind.  However, it will have a more
                // up to date document within it that it will eventually process.  Until then
                // we just keep around the stale tags we have.
                //
                // Note: if the Solution or Document is null here, then that means the document
                // was removed.  In that case, we do want to proceed so that we'll produce 0
                // tags and we'll update the editor appropriately.
                SourceText    sourceText     = null;
                ITextSnapshot editorSnapshot = null;

                if (e.Solution != null)
                {
                    var diagnosticDocument = e.Solution.GetDocument(e.DocumentId);
                    if (diagnosticDocument != null)
                    {
                        if (!diagnosticDocument.TryGetText(out sourceText))
                        {
                            return;
                        }

                        editorSnapshot = sourceText.FindCorrespondingEditorTextSnapshot();
                        if (editorSnapshot == null)
                        {
                            return;
                        }
                    }
                }

                if (this.IsForeground())
                {
                    OnDiagnosticsUpdatedOnForeground(sender, e, sourceText, editorSnapshot);
                }
                else
                {
                    RegisterNotification(() => OnDiagnosticsUpdatedOnForeground(sender, e, sourceText, editorSnapshot));
                }
            }
Exemple #5
0
        private ImmutableArray <CompletionItem> GetItems(SourceText text, Document document, int position, CompletionTrigger triggerInfo, CancellationToken cancellationToken)
        {
            var line     = text.Lines.GetLineFromPosition(position);
            var lineText = text.ToString(TextSpan.FromBounds(line.Start, position));
            var match    = s_directiveRegex.Match(lineText);

            if (!match.Success)
            {
                return(ImmutableArray <CompletionItem> .Empty);
            }

            var quotedPathGroup = match.Groups[1];
            var quotedPath      = quotedPathGroup.Value;
            var endsWithQuote   = PathCompletionUtilities.EndsWithQuote(quotedPath);

            if (endsWithQuote && (position >= line.Start + match.Length))
            {
                return(ImmutableArray <CompletionItem> .Empty);
            }

            var buffer   = text.Container.GetTextBuffer();
            var snapshot = text.FindCorrespondingEditorTextSnapshot();

            if (snapshot == null)
            {
                return(ImmutableArray <CompletionItem> .Empty);
            }

            var fileSystem = CurrentWorkingDirectoryDiscoveryService.GetService(snapshot);

            // TODO: https://github.com/dotnet/roslyn/issues/5263
            // Avoid dependency on a specific resolver.
            // The search paths should be provided by specialized workspaces:
            // - InteractiveWorkspace for interactive window
            // - ScriptWorkspace for loose .csx files (we don't have such workspace today)
            var searchPaths = (document.Project.CompilationOptions.SourceReferenceResolver as SourceFileResolver)?.SearchPaths ?? ImmutableArray <string> .Empty;

            var helper = new FileSystemCompletionHelper(
                this,
                GetTextChangeSpan(text, position, quotedPathGroup),
                fileSystem,
                Glyph.OpenFolder,
                Glyph.CSharpFile,
                searchPaths: searchPaths,
                allowableExtensions: new[] { ".csx" },
                itemRules: s_rules);

            var pathThroughLastSlash = this.GetPathThroughLastSlash(text, position, quotedPathGroup);

            return(helper.GetItems(pathThroughLastSlash, documentPath: null));
        }
Exemple #6
0
        private ImmutableArray <CompletionItem> GetItems(SourceText text, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var line     = text.Lines.GetLineFromPosition(position);
            var lineText = text.ToString(TextSpan.FromBounds(line.Start, position));
            var match    = s_directiveRegex.Match(lineText);

            if (!match.Success)
            {
                return(ImmutableArray <CompletionItem> .Empty);
            }

            var quotedPathGroup = match.Groups[1];
            var quotedPath      = quotedPathGroup.Value;
            var endsWithQuote   = PathCompletionUtilities.EndsWithQuote(quotedPath);

            if (endsWithQuote && (position >= line.Start + match.Length))
            {
                return(ImmutableArray <CompletionItem> .Empty);
            }

            var buffer   = text.Container.GetTextBuffer();
            var snapshot = text.FindCorrespondingEditorTextSnapshot();

            if (snapshot == null)
            {
                return(ImmutableArray <CompletionItem> .Empty);
            }

            var fileSystem = CurrentWorkingDirectoryDiscoveryService.GetService(snapshot);

            var searchPaths = ImmutableArray.Create(fileSystem.CurrentDirectory);

            var helper = new FileSystemCompletionHelper(
                this,
                GetTextChangeSpan(text, position, quotedPathGroup),
                fileSystem,
                Glyph.OpenFolder,
                Glyph.CSharpFile,
                searchPaths: searchPaths,
                allowableExtensions: new[] { ".csx" },
                itemRules: ItemRules.Instance);

            var pathThroughLastSlash = this.GetPathThroughLastSlash(text, position, quotedPathGroup);

            return(helper.GetItems(pathThroughLastSlash, documentPath: null));
        }
        /// <summary>
        /// Selects a text span in a document.
        /// </summary>
        public void SelectText(SourceText text, TextSpan selectedSpan)
        {
            Contract.Requires <ArgumentNullException>(text != null, nameof(text));

            var snapshot    = text.FindCorrespondingEditorTextSnapshot();
            var document    = snapshot.GetOpenDocumentInCurrentContextWithChanges();
            var windowFrame = this.OpenDocumentGetFrame(document);

            var textView = VsShellUtilities.GetTextView(windowFrame);
            var lineSpan = text.Lines.GetLinePositionSpan(selectedSpan);

            textView.SetSelection(
                lineSpan.Start.Line,
                lineSpan.Start.Character,
                lineSpan.End.Line,
                lineSpan.End.Character);
        }
Exemple #8
0
            private bool TryGetOldSnapshot(Document document, out SourceText text, out ITextSnapshot oldSnapshot)
            {
                if (!document.TryGetText(out text))
                {
                    oldSnapshot = null;
                    return(false);
                }

                oldSnapshot = text.FindCorrespondingEditorTextSnapshot();
                if (oldSnapshot == null)
                {
                    return(false);
                }

                // two should be same
                Contract.ThrowIfFalse(text.Length == oldSnapshot.Length);
                return(true);
            }
            public bool TryGetSpan(ActiveStatementId id, SourceText source, out TextSpan span)
            {
                lock (_trackingSpans)
                {
                    if (_trackingSpans.TryGetValue(id.DocumentId, out var documentSpans) && documentSpans != null)
                    {
                        var trackingSpan = documentSpans[id.Ordinal];
                        var snapshot     = source.FindCorrespondingEditorTextSnapshot();

                        if (snapshot != null && snapshot.TextBuffer == trackingSpan.TextBuffer)
                        {
                            span = trackingSpan.GetSpan(snapshot).Span.ToTextSpan();
                            return(true);
                        }
                    }
                }

                span = default;
                return(false);
            }
        internal static string GetBaseDirectory(SourceText text, Document document)
        {
            string result;

            if (document.Project.IsSubmission)
            {
                var buffer   = text.Container.GetTextBuffer();
                var snapshot = text.FindCorrespondingEditorTextSnapshot();
                if (snapshot == null)
                {
                    return(null);
                }

                result = CurrentWorkingDirectoryDiscoveryService.GetService(snapshot).WorkingDirectory;
            }
            else
            {
                result = PathUtilities.GetDirectoryName(document.FilePath);
            }

            return(PathUtilities.IsAbsolute(result) ? result : null);
        }
Exemple #11
0
            public void UpdateActiveStatementSpans(SourceText source, IEnumerable <KeyValuePair <ActiveStatementId, TextSpan> > spans)
            {
                bool leafUpdated = false;
                bool updated     = false;

                ITrackingSpan[] documentSpans;
                lock (_trackingSpans)
                {
                    foreach (var span in spans)
                    {
                        ActiveStatementId id = span.Key;
                        if (_trackingSpans.TryGetValue(id.DocumentId, out documentSpans) && documentSpans != null)
                        {
                            var snapshot = source.FindCorrespondingEditorTextSnapshot();

                            // Avoid updating spans if the buffer has changed.
                            // Buffer change is handled by DocumentOpened event.
                            if (snapshot != null && snapshot.TextBuffer == documentSpans[id.Ordinal].TextBuffer)
                            {
                                documentSpans[id.Ordinal] = snapshot.CreateTrackingSpan(span.Value.ToSpan(), SpanTrackingMode.EdgeExclusive);

                                if (!leafUpdated)
                                {
                                    var baseStatements = _editSession.BaseActiveStatements[id.DocumentId];
                                    leafUpdated = (baseStatements[id.Ordinal].Flags & ActiveStatementFlags.LeafFrame) != 0;
                                }

                                updated = true;
                            }
                        }
                    }
                }

                if (updated)
                {
                    _service.OnTrackingSpansChanged(leafUpdated);
                }
            }
Exemple #12
0
 private static ITextSnapshot GetRoslynSnapshot(SourceText sourceText)
 => sourceText.FindCorrespondingEditorTextSnapshot();
            /// <summary>
            /// We do all mutation work on the UI thread.  That ensures that all mutation
            /// is processed serially *and* it means we can safely examine things like
            /// subject buffers and open documents without any threat of race conditions.
            /// Note that we do not do any expensive work here.  We just store (or remove)
            /// the data we were given in appropriate buckets.
            ///
            /// For example, we create a TaggerProvider per unique DiagnosticUpdatedArgs.Id
            /// we get.  So if we see a new id we simply create a tagger for it and pass it
            /// these args to store.  Otherwise we pass these args to the existing tagger.
            ///
            /// Similarly, clearing out data is just a matter of us clearing our reference
            /// to the data.
            /// </summary>
            private void OnDiagnosticsUpdatedOnForeground(DiagnosticsUpdatedArgs e)
            {
                this.AssertIsForeground();

                if (_disposed)
                {
                    return;
                }

                // Do some quick checks to avoid doing any further work for diagnostics  we don't
                // care about.
                var ourDocument   = _subjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext();
                var ourDocumentId = ourDocument?.Id;

                if (ourDocumentId != _currentDocumentId)
                {
                    // Our buffer has started tracking some other document entirely.
                    // We have to clear out all of the diagnostics we have currently stored.
                    RemoveAllCachedDiagnostics();
                }

                _currentDocumentId = ourDocumentId;

                // Now see if the document we're tracking corresponds to the diagnostics
                // we're hearing about.  If not, just ignore them.
                if (ourDocument == null ||
                    ourDocument.Project.Solution.Workspace != e.Workspace ||
                    ourDocument.Id != e.DocumentId)
                {
                    return;
                }

                // We're hearing about diagnostics for our document.  We may be hearing
                // about new diagnostics coming, or existing diagnostics being cleared
                // out.

                // First see if this is a document/project removal.  If so, clear out any state we
                // have associated with any analyzers we have for that document/project.
                ProcessRemovedDiagnostics(e);

                // Make sure we can find an editor snapshot for these errors.  Otherwise we won't
                // be able to make ITagSpans for them.  If we can't, just bail out.  This happens
                // when the solution crawler is very far behind.  However, it will have a more
                // up to date document within it that it will eventually process.  Until then
                // we just keep around the stale tags we have.
                //
                // Note: if the Solution or Document is null here, then that means the document
                // was removed.  In that case, we do want to proceed so that we'll produce 0
                // tags and we'll update the editor appropriately.
                SourceText    sourceText     = null;
                ITextSnapshot editorSnapshot = null;

                if (e.Solution != null)
                {
                    var diagnosticDocument = e.Solution.GetDocument(e.DocumentId);
                    if (diagnosticDocument != null)
                    {
                        if (!diagnosticDocument.TryGetText(out sourceText))
                        {
                            return;
                        }

                        editorSnapshot = sourceText.FindCorrespondingEditorTextSnapshot();
                        if (editorSnapshot == null)
                        {
                            return;
                        }

                        // Make sure the editor we've got associated with these diagnostics is the
                        // same one we're a tagger for.  It is possible for us to hear about diagnostics
                        // for the *same* Document that are not from the *same* buffer.  For example,
                        // say we have the following chain of events:
                        //
                        //      Document is opened.
                        //      Diagnostics start analyzing.
                        //      Document is closed.
                        //      Document is opened.
                        //      Diagnostics finish and report for document.
                        //
                        // We'll hear about diagnostics for the original Document/Buffer that was
                        // opened.  But we'll be trying to apply them to this current Document/Buffer.
                        // That won't work since these will be different buffers (and thus, we won't
                        // be able to map the diagnostic spans appropriately).
                        //
                        // Note: returning here is safe.  Because the file is closed/opened, The
                        // Diagnostics Service will reanalyze it.  It will then report the new results
                        // which we will hear about and use.
                        if (editorSnapshot.TextBuffer != _subjectBuffer)
                        {
                            return;
                        }
                    }
                }

                OnDiagnosticsUpdatedOnForeground(e, sourceText, editorSnapshot);
            }