Ejemplo n.º 1
0
        /// <summary>
        /// Makes an LSP document symbol request and returns the response and the text snapshot used at
        /// the time the LSP client sends the request to the server.
        /// </summary>
        public static async Task <(JToken response, ITextSnapshot snapshot)?> DocumentSymbolsRequestAsync(
            ITextBuffer textBuffer,
            ILanguageServiceBroker2 languageServiceBroker,
            string textViewFilePath,
            CancellationToken cancellationToken)
        {
            ITextSnapshot?requestSnapshot = null;

            JToken ParameterFunction(ITextSnapshot snapshot)
            {
                requestSnapshot = snapshot;
                return(JToken.FromObject(new RoslynDocumentSymbolParams()
                {
                    UseHierarchicalSymbols = true,
                    TextDocument = new TextDocumentIdentifier()
                    {
                        Uri = new Uri(textViewFilePath)
                    }
                }));
            }

            var response = (await languageServiceBroker.RequestAsync(
                                textBuffer: textBuffer,
                                method: Methods.TextDocumentDocumentSymbolName,
                                capabilitiesFilter: _ => true,
                                languageServerName: WellKnownLspServerKinds.AlwaysActiveVSLspServer.ToUserVisibleString(),
                                parameterFactory: ParameterFunction,
                                cancellationToken: cancellationToken).ConfigureAwait(false))?.Response;

            Contract.ThrowIfNull(requestSnapshot);
            return(response is null ? null : (response, requestSnapshot));
        }
Ejemplo n.º 2
0
        public ITextBuffer GetTextBuffer()
        {
            var workspace = (TestWorkspace?)_languageServiceProvider?.WorkspaceServices.Workspace;

            if (_textBuffer == null)
            {
                Contract.ThrowIfNull(_languageServiceProvider, $"To get a text buffer for a {nameof(TestHostDocument)}, it must have been parented in a project.");
                var contentType = _languageServiceProvider.GetRequiredService <IContentTypeLanguageService>().GetDefaultContentType();

                _textBuffer          = workspace !.GetOrCreateBufferForPath(FilePath, contentType, _languageServiceProvider.Language, _initialText);
                _initialTextSnapshot = _textBuffer.CurrentSnapshot;
            }

            if (workspace != null)
            {
                // Open (or reopen) any files that were closed in this call. We do this for all linked copies at once.
                foreach (var linkedId in workspace.CurrentSolution.GetDocumentIdsWithFilePath(FilePath).Concat(this.Id))
                {
                    var testDocument = workspace.GetTestDocument(linkedId);

                    if (testDocument != null)
                    {
                        if (!workspace.IsDocumentOpen(linkedId))
                        {
                            // If there is a linked file, we'll start the non-linked one as being the primary context, which some tests depend on.
                            workspace.OnDocumentOpened(linkedId, _textBuffer.AsTextContainer(), isCurrentContext: !testDocument.IsLinkFile);
                        }
                    }
                    ;
                }
            }

            return(_textBuffer);
        }
            private static bool TryGetSnapshot(Document document, [NotNullWhen(true)] out ITextSnapshot?snapshot)
            {
                if (!document.TryGetText(out var source))
                {
                    snapshot = null;
                    return(false);
                }

                snapshot = source.FindCorrespondingEditorTextSnapshot();
                return(snapshot != null);
            }
Ejemplo n.º 4
0
        public IEnumerable <ITagSpan <IntraTextAdornmentTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            if (spans.Count == 0)
            {
                return(Array.Empty <ITagSpan <IntraTextAdornmentTag> >());
            }

            var snapshot = spans[0].Snapshot;

            if (_cache.Count == 0 || snapshot != _cacheSnapshot)
            {
                // Calculate UI elements
                _cache.Clear();
                _cacheSnapshot = snapshot;

                var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
                var classify = document?.Project.Solution.Options.GetOption(InlineHintsOptions.ColorHints, document?.Project.Language) ?? false;

                // Calling into the InlineParameterNameHintsDataTaggerProvider which only responds with the current
                // active view and disregards and requests for tags not in that view
                var fullSpan = new SnapshotSpan(snapshot, 0, snapshot.Length);
                var tags     = _tagAggregator.GetTags(new NormalizedSnapshotSpanCollection(fullSpan));
                foreach (var tag in tags)
                {
                    // Gets the associated span from the snapshot span and creates the IntraTextAdornmentTag from the data
                    // tags. Only dealing with the dataTagSpans if the count is 1 because we do not see a multi-buffer case
                    // occuring
                    var dataTagSpans = tag.Span.GetSpans(snapshot);
                    if (dataTagSpans.Count == 1)
                    {
                        var dataTagSpan        = dataTagSpans[0];
                        var parameterHintUITag = InlineHintsTag.Create(
                            tag.Tag.Hint, Format, _textView, dataTagSpan, _taggerProvider, _formatMap, classify);

                        _cache.Add(new TagSpan <IntraTextAdornmentTag>(dataTagSpan, parameterHintUITag));
                    }
                }
            }

            var selectedSpans = new List <ITagSpan <IntraTextAdornmentTag> >();

            foreach (var tagSpan in _cache)
            {
                if (spans.IntersectsWith(tagSpan.Span))
                {
                    selectedSpans.Add(tagSpan);
                }
            }

            return(selectedSpans);
        }
Ejemplo n.º 5
0
        public IEnumerable <ITagSpan <IntraTextAdornmentTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            if (spans.Count == 0)
            {
                return(Array.Empty <ITagSpan <IntraTextAdornmentTag> >());
            }

            var snapshot = spans[0].Snapshot;

            if (_cache.Count == 0 || snapshot != _cacheSnapshot)
            {
                // Calculate UI elements
                _cache.Clear();
                _cacheSnapshot = snapshot;

                // Calling into the InlineParameterNameHintsDataTaggerProvider which only responds with the current
                // active view and disregards and requests for tags not in that view
                var fullSpan = new SnapshotSpan(snapshot, 0, snapshot.Length);
                var dataTags = _tagAggregator.GetTags(new NormalizedSnapshotSpanCollection(fullSpan));
                foreach (var dataTag in dataTags)
                {
                    // Gets the associated span from the snapshot span and creates the IntraTextAdornmentTag from the data
                    // tags. Only dealing with the dataTagSpans if the count is 1 because we do not see a multi-buffer case
                    // occuring
                    var dataTagSpans = dataTag.Span.GetSpans(snapshot);
                    var textTag      = dataTag.Tag;
                    if (dataTagSpans.Count == 1)
                    {
                        var dataTagSpan = dataTagSpans[0];
                        var parameterHintSnapshotSpan = new SnapshotSpan(dataTagSpan.Start, 0);
                        var parameterHintUITag        = InlineParameterNameHintsTag.Create(textTag.ParameterName,
                                                                                           Format, _textView, dataTagSpan, textTag.ParameterSymbolKey, _inlineParameterNameHintsTaggerProvider);

                        _cache.Add(new TagSpan <IntraTextAdornmentTag>(parameterHintSnapshotSpan, parameterHintUITag));
                    }
                }
            }

            var selectedSpans = new List <ITagSpan <IntraTextAdornmentTag> >();

            foreach (var tagSpan in _cache)
            {
                if (spans.IntersectsWith(tagSpan.Span))
                {
                    selectedSpans.Add(tagSpan);
                }
            }

            return(selectedSpans);
        }
Ejemplo n.º 6
0
        internal TestHostDocument(
            ExportProvider exportProvider,
            HostLanguageServices?languageServiceProvider,
            string code,
            string name,
            string filePath,
            int?cursorPosition,
            IDictionary <string, ImmutableArray <TextSpan> > spans,
            SourceCodeKind sourceCodeKind  = SourceCodeKind.Regular,
            IReadOnlyList <string>?folders = null,
            bool isLinkFile = false,
            IDocumentServiceProvider?documentServiceProvider = null,
            ImmutableArray <string> roles = default,
            ITextBuffer?textBuffer        = null,
            bool isSourceGenerated        = false
            )
        {
            Contract.ThrowIfNull(filePath);

            _exportProvider          = exportProvider;
            _languageServiceProvider = languageServiceProvider;
            _initialText             = code;
            Name                     = name;
            FilePath                 = filePath;
            _folders                 = folders;
            this.CursorPosition      = cursorPosition;
            SourceCodeKind           = sourceCodeKind;
            this.IsLinkFile          = isLinkFile;
            IsSourceGenerated        = isSourceGenerated;
            _documentServiceProvider = documentServiceProvider;
            _roles                   = roles.IsDefault ? s_defaultRoles : roles;

            if (spans.ContainsKey(string.Empty))
            {
                this.SelectedSpans = spans[string.Empty];
            }

            foreach (var namedSpanList in spans.Where(s => s.Key != string.Empty))
            {
                this.AnnotatedSpans.Add(namedSpanList);
            }

            Loader = new TestDocumentLoader(this, _initialText);

            if (textBuffer != null)
            {
                _textBuffer          = textBuffer;
                _initialTextSnapshot = textBuffer.CurrentSnapshot;
            }
        }
Ejemplo n.º 7
0
        private async void View_LayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
            await delaySemaphorSlim.WaitAsync();

            ITextSnapshot snapshot = e.NewSnapshot;

            this.lastSnapshot = snapshot;

            delaySemaphorSlim.Release();

            await Task.Delay(1000);

            await delaySemaphorSlim.WaitAsync();

            try
            {
                if (this.lastSnapshot != snapshot ||
                    this.viewAccessor?.ActiveView == null ||
                    this.viewAccessor.ActiveView != this.lastView)
                {
                    return;
                }

                string     text = snapshot.GetText();
                SyntaxTree tree = CSharpSyntaxTree.ParseText(text);

                await this.operationSemaphorSlim.WaitAsync();

                try
                {
                    this.localContext = new LocalContext(tree);
                }
                finally
                {
                    this.operationSemaphorSlim.Release();
                }
            }
            finally
            {
                if (delaySemaphorSlim.CurrentCount == 0)
                {
                    this.lastSnapshot = null;
                }

                delaySemaphorSlim.Release();
            }
        }
Ejemplo n.º 8
0
        public ITextBuffer2 GetTextBuffer()
        {
            var workspace = (TestWorkspace?)_languageServiceProvider?.WorkspaceServices.Workspace;

            if (_textBuffer == null)
            {
                Contract.ThrowIfNull(_languageServiceProvider, $"To get a text buffer for a {nameof(TestHostDocument)}, it must have been parented in a project.");
                var contentType = _languageServiceProvider.GetRequiredService <IContentTypeLanguageService>().GetDefaultContentType();

                _textBuffer          = workspace !.GetOrCreateBufferForPath(FilePath, contentType, _languageServiceProvider.Language, _initialText);
                _initialTextSnapshot = _textBuffer.CurrentSnapshot;
            }

            if (workspace != null)
            {
                // Open (or reopen) any files that were closed in this call. We do this for all linked copies at once.
                foreach (var linkedId in workspace.CurrentSolution.GetDocumentIdsWithFilePath(FilePath).Concat(this.Id))
                {
                    if (workspace.IsDocumentOpen(linkedId))
                    {
                        continue;
                    }

                    if (workspace.GetTestDocument(linkedId) is { } testDocument)
                    {
                        if (testDocument.IsSourceGenerated)
                        {
                            var threadingContext = workspace.GetService <IThreadingContext>();
                            var document         = threadingContext.JoinableTaskFactory.Run(() => workspace.CurrentSolution.GetSourceGeneratedDocumentAsync(testDocument.Id, CancellationToken.None).AsTask());
                            Contract.ThrowIfNull(document);

                            workspace.OnSourceGeneratedDocumentOpened(_textBuffer.AsTextContainer(), document);
                        }
                        else
                        {
                            // If there is a linked file, we'll start the non-linked one as being the primary context, which some tests depend on.
                            workspace.OnDocumentOpened(linkedId, _textBuffer.AsTextContainer(), isCurrentContext: !testDocument.IsLinkFile);
                        }
                    }
                    else if (workspace.GetTestAdditionalDocument(linkedId) is { } testAdditionalDocument)
                    {
                        workspace.OnAdditionalDocumentOpened(linkedId, _textBuffer.AsTextContainer());
                    }
Ejemplo n.º 9
0
            private void OnLayoutChanged(object?sender, TextViewLayoutChangedEventArgs e)
            {
                _foregroundObject.AssertIsForeground();
                // The formatted span refers to the span of the textview's buffer that is visible.
                // If it changes, then we want to reclassify.  Note: the span might not change if
                // text were overwritten.  However, in the case of text-edits, we'll hear about
                // through other means as we have an EventSource for that purpose.  This event
                // source is for knowing if the user moves the view around.  This handles direct
                // moves using the caret/scrollbar, as well as moves that happen because someone
                // jumped directly to a location using goto-def.  It also handles view changes
                // caused by the user collapsing an outlining region.

                var lastSpan               = _span;
                var lastViewTextSnapshot   = _viewTextSnapshot;
                var lastViewVisualSnapshot = _viewVisualSnapshot;

                _span               = _textView.TextViewLines.FormattedSpan.Span;
                _viewTextSnapshot   = _textView.TextSnapshot;
                _viewVisualSnapshot = _textView.VisualSnapshot;

                if (_span != lastSpan)
                {
                    // The span changed.  This could have happened for a few different reasons.
                    // If none of the view's text snapshots changed, then it was because of scrolling.

                    if (
                        _viewTextSnapshot == lastViewTextSnapshot &&
                        _viewVisualSnapshot == lastViewVisualSnapshot
                        )
                    {
                        // We scrolled.
                        RaiseChanged(_scrollChangeDelay);
                    }
                    else
                    {
                        // text changed in some way.
                        RaiseChanged(_textChangeDelay);
                    }
                }
            }
Ejemplo n.º 10
0
        private void UpdateContextAndJump(Action <LocalContextState> jumpAction)
        {
            this.operationSemaphorSlim.Wait();

            try
            {
                IWpfTextView?view = this.viewAccessor?.ActiveView;

                if (view == null && this.lastView != null)
                {
                    this.lastView.LayoutChanged -= this.View_LayoutChanged;
                    this.lastView     = null;
                    this.lastSnapshot = null;
                }

                if (view != null && this.lastActiveView != view)
                {
                    if (this.adornment != null)
                    {
                        this.adornment.Remove();
                    }

                    this.adornment      = new TextHighlightAdornment(view);
                    this.lastActiveView = view;

                    string     text = view.TextSnapshot.GetText();
                    SyntaxTree tree = CSharpSyntaxTree.ParseText(text);
                    this.localContext = new LocalContext(tree);

                    view.LayoutChanged += View_LayoutChanged;
                    this.lastView       = view;
                }

                if (this.adornment != null && view != null)
                {
                    _ = this.localContext ?? throw new NullReferenceException(
                                  "The local context should be initialized first.");

                    this.adornment.Remove();

                    SnapshotPoint    caret        = view.Caret.Position.BufferPosition;
                    IWpfTextViewLine textViewLine = view.GetTextViewLineContainingBufferPosition(caret);
                    int line      = caret.GetContainingLine().LineNumber;
                    int startChar = textViewLine.Start.Difference(caret);

                    Debug.WriteLine(
                        "The state before cursor update:\t" +
                        $"{this.localContext.State.GetType().Name}");

                    this.localContext.TransitionTo(line, startChar);

                    Debug.WriteLine(
                        "The state after cursor update:\t" +
                        $"{this.localContext.State.GetType().Name}");

                    jumpAction(this.localContext.State);

                    LocalContextState state = this.localContext.State;

                    Debug.WriteLine(
                        "The state after jump:\t\t\t" +
                        $"{this.localContext.State.GetType().Name}");

                    if (state.IsJumpTargetSet)
                    {
                        this.adornment.EndorseTextBounds(
                            state.JumpTargetStartLine,
                            state.JumpTargetEndLine,
                            state.JumpTargetStartChar,
                            state.JumpTargetEndChar);

                        ITextSnapshotLine jumpTargetLine = view.TextSnapshot
                                                           .GetLineFromLineNumber(state.JumpTargetStartLine);
                        SnapshotPoint jumpPoint = jumpTargetLine.Start.Add(state.JumpTargetStartChar);

                        view.Caret.MoveTo(new SnapshotPoint(view.TextSnapshot, jumpPoint));

                        if (!view.TextViewLines.ContainsBufferPosition(jumpPoint))
                        {
                            var span = new SnapshotSpan(
                                view.TextSnapshot,
                                Span.FromBounds(jumpTargetLine.Start, jumpTargetLine.End));

                            view.ViewScroller.EnsureSpanVisible(
                                span,
                                EnsureSpanVisibleOptions.AlwaysCenter);
                        }

                        view.Caret.EnsureVisible();
                    }
                }
            }
            finally
            {
                this.operationSemaphorSlim.Release();
            }
        }