public async Task HandleAsync(RequestHoverText command, KernelInvocationContext context) { using var _ = new GCPressure(1024 * 1024); var document = _workspace.UpdateWorkingDocument(command.Code); var text = await document.GetTextAsync(); var cursorPosition = text.Lines.GetPosition(command.LinePosition); var service = QuickInfoService.GetService(document); var info = await service.GetQuickInfoAsync(document, cursorPosition); if (info == null) { return; } var scriptSpanStart = text.Lines.GetLinePosition(0); var linePosSpan = text.Lines.GetLinePositionSpan(info.Span); var correctedLinePosSpan = linePosSpan.SubtractLineOffset(scriptSpanStart); context.Publish( new HoverTextProduced( command, new[] { new FormattedValue("text/markdown", info.ToMarkdownString()) }, correctedLinePosSpan)); }
QuickInfoState(QuickInfoService quickInfoService, Document document, SourceText sourceText, ITextSnapshot snapshot) { QuickInfoService = quickInfoService; Document = document; SourceText = sourceText; Snapshot = snapshot; }
public async Task HandleAsync(RequestHoverText command, KernelInvocationContext context) { if (!command.DocumentIdentifier.TryDecodeDocumentFromDataUri(out var documentContents)) { return; } var(document, offset) = GetDocumentWithOffsetFromCode(documentContents); var text = await document.GetTextAsync(); var cursorPosition = text.Lines.GetPosition(new LinePosition(command.Position.Line, command.Position.Character)); var absolutePosition = cursorPosition + offset; var service = QuickInfoService.GetService(document); var info = await service.GetQuickInfoAsync(document, absolutePosition); if (info == null) { return; } var scriptSpanStart = text.Lines.GetLinePosition(offset); var linePosSpan = text.Lines.GetLinePositionSpan(info.Span); var correctedLinePosSpan = linePosSpan.SubtractLineOffset(scriptSpanStart); context.PublishHoverMarkdownResponse(command, info.ToMarkdownString(), correctedLinePosSpan); }
public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> quickInfoContent, out ITrackingSpan applicableToSpan) { if (_state == QuickInfoState.Disable) { applicableToSpan = default; return; } if (_state == QuickInfoState.Override) { quickInfoContent.Clear(); } var triggerPoint = session.GetTriggerPoint(_textBuffer.CurrentSnapshot); if (!triggerPoint.HasValue) { applicableToSpan = default; return; } var quickInfo = QuickInfoService.GetQuickInfoAsync(_textBuffer, triggerPoint.Value, CancellationToken.None).Result; if (quickInfo is null || quickInfo.Descriptions.Length == 0) { applicableToSpan = default; return; } var trackingSpan = triggerPoint.Value.Snapshot.CreateTrackingSpan(quickInfo.GetSpan(), SpanTrackingMode.EdgeInclusive); var items = new List <UIElement>(); foreach (var item in quickInfo.Descriptions) { var textBlock = ToTextBlock(item); if (item.Kind == SymbolDescriptionKind.Main) { var panel = new WrapPanel(); var uiElements = TryGetImageElement(quickInfo.Image, out var image) ? image.Enumerate().Concat(textBlock.Enumerate()) : textBlock.Enumerate(); Populate(panel, uiElements); items.Insert(0, panel); } else { items.Add(textBlock); } } var container = new StackPanel(); Populate(container, items); quickInfoContent.Add(container); applicableToSpan = trackingSpan; }
public async Task <IntellisenseQuickInfoItem> GetQuickInfoItemAsync(IAsyncQuickInfoSession session, CancellationToken cancellationToken) { var triggerPoint = session.GetTriggerPoint(_subjectBuffer.CurrentSnapshot); if (!triggerPoint.HasValue) { return(null); } var snapshot = triggerPoint.Value.Snapshot; var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(null); } var service = QuickInfoService.GetService(document); if (service == null) { return(null); } try { using (Logger.LogBlock(FunctionId.Get_QuickInfo_Async, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); var options = _globalOptions.GetSymbolDescriptionOptions(document.Project.Language); var item = await service.GetQuickInfoAsync(document, triggerPoint.Value, options, cancellationToken).ConfigureAwait(false); if (item != null) { var textVersion = snapshot.Version; var trackingSpan = textVersion.CreateTrackingSpan(item.Span.ToSpan(), SpanTrackingMode.EdgeInclusive); var classificationOptions = _globalOptions.GetClassificationOptions(document.Project.Language); return(await IntellisenseQuickInfoBuilder.BuildItemAsync( trackingSpan, item, document, classificationOptions, _threadingContext, _operationExecutor, _asyncListener, _streamingPresenter, cancellationToken).ConfigureAwait(false)); } return(null); } } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken, ErrorSeverity.Critical)) { throw ExceptionUtilities.Unreachable; } }
public async Task <IntellisenseQuickInfoItem> GetQuickInfoItemAsync(IAsyncQuickInfoSession session, CancellationToken cancellationToken) { var triggerPoint = session.GetTriggerPoint(_subjectBuffer.CurrentSnapshot); if (!triggerPoint.HasValue) { return(null); } var snapshot = triggerPoint.Value.Snapshot; var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(null); } var service = QuickInfoService.GetService(document); if (service == null) { return(null); } try { using (Internal.Log.Logger.LogBlock(FunctionId.Get_QuickInfo_Async, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); var item = await service.GetQuickInfoAsync(document, triggerPoint.Value, cancellationToken).ConfigureAwait(false); if (item != null) { var textVersion = snapshot.Version; var trackingSpan = textVersion.CreateTrackingSpan(item.Span.ToSpan(), SpanTrackingMode.EdgeInclusive); return(await IntellisenseQuickInfoBuilder.BuildItemAsync(trackingSpan, item, snapshot, document, _streamingPresenter, cancellationToken).ConfigureAwait(false)); } return(null); } } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public async Task <MsQuickInfoItem> GetQuickInfoItemAsync(IAsyncQuickInfoSession session, CancellationToken cancellationToken) { // NOTE: returned null would be ignored by VS if (_state == QuickInfoState.Disable) { return(null); } var triggerPoint = session.GetTriggerPoint(_textBuffer.CurrentSnapshot); if (!triggerPoint.HasValue) { return(null); } var quickInfo = await QuickInfoService.GetQuickInfoAsync(_textBuffer, triggerPoint.Value, cancellationToken); if (quickInfo is null || quickInfo.Descriptions.Length == 0) { return(null); } var trackingSpan = triggerPoint.Value.Snapshot.CreateTrackingSpan(quickInfo.GetSpan(), SpanTrackingMode.EdgeInclusive); var items = new List <object>(); foreach (var item in quickInfo.Descriptions) { if (item.Kind == SymbolDescriptionKind.Main) { var containerItem = TryGetImageElement(quickInfo.Image, out var image) ? new ContainerElement(ContainerElementStyle.Wrapped, image, ToClassifiedTextElement(item)) : new ContainerElement(ContainerElementStyle.Wrapped, ToClassifiedTextElement(item)); items.Insert(0, containerItem); } else { items.Add(ToClassifiedTextElement(item)); } } // NOTE: wrap element into a specified type to determine that the content element was created by CoCo or not return(_state == QuickInfoState.Override ? new MsQuickInfoItem(trackingSpan, new QuickInfoWrapper(new ContainerElement(ContainerElementStyle.Stacked, items))) : new MsQuickInfoItem(trackingSpan, new ContainerElement(ContainerElementStyle.Stacked, items))); }
public RoslynSession( SourceText sourceText, ProjectInfo projectInfo, MefHostServices hostServices, ImmutableArray <DiagnosticAnalyzer> analyzers, ImmutableDictionary <string, ImmutableArray <CodeFixProvider> > codeFixProviders, ImmutableArray <ISignatureHelpProviderWrapper> signatureHelpProviders ) { _workspace = new CustomWorkspace(hostServices); _sourceText = sourceText; _document = CreateProjectAndOpenNewDocument(_workspace, projectInfo, sourceText); QuickInfoService = QuickInfoService.GetService(_document); _completionService = CompletionService.GetService(_document); Analyzers = analyzers; SignatureHelpProviders = signatureHelpProviders; CodeFixProviders = codeFixProviders; }
public async Task <string> GetQuickInfo(Document document, CompletionItem completion) { var infoService = QuickInfoService.GetService(document); string text = (await document.GetTextAsync()).ToString(); string completedText = text.Substring(0, completion.Span.Start) + completion.DisplayText + (completion.Span.End == text.Length ? "" : text.Substring(completion.Span.End)); var newDoc = document.WithText(SourceText.From(completedText)); var info = await infoService.GetQuickInfoAsync(newDoc, completedText.Length - 1); if (info == null || info.Sections.Length == 0) { return(null); } return(string.Join( Environment.NewLine, info.Sections.Select(section => section.Text) )); }
public async Task HandleAsync(RequestHoverText command, KernelInvocationContext context) { var document = _workspace.ForkDocument(command.Code); var text = await document.GetTextAsync(); var cursorPosition = text.Lines.GetPosition(command.Position); var service = QuickInfoService.GetService(document); var info = await service.GetQuickInfoAsync(document, cursorPosition); if (info == null) { return; } var scriptSpanStart = text.Lines.GetLinePosition(0); var linePosSpan = text.Lines.GetLinePositionSpan(info.Span); var correctedLinePosSpan = linePosSpan.SubtractLineOffset(scriptSpanStart); context.PublishHoverTextMarkdownResponse(command, info.ToMarkdownString(), correctedLinePosSpan); }
public static QuickInfoState?Create(ITextSnapshot snapshot) { if (snapshot == null) { throw new ArgumentNullException(nameof(snapshot)); } var sourceText = snapshot.AsText(); var document = sourceText.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(null); } var quickInfoService = QuickInfoService.GetService(document); if (quickInfoService == null) { return(null); } return(new QuickInfoState(quickInfoService, document, sourceText, snapshot)); }
public async Task <QuickInfoResponse> Handle(QuickInfoRequest request) { var document = _workspace.GetDocument(request.FileName); var response = new QuickInfoResponse(); if (document is null) { return(response); } var quickInfoService = QuickInfoService.GetService(document); if (quickInfoService is null) { _logger?.LogWarning($"QuickInfo service was null for {document.FilePath}"); return(response); } var sourceText = await document.GetTextAsync(); var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); var quickInfo = await quickInfoService.GetQuickInfoAsync(document, position); if (quickInfo is null) { _logger?.LogTrace($"No QuickInfo found for {document.FilePath}:{request.Line},{request.Column}"); return(response); } var finalTextBuilder = new StringBuilder(); var sectionTextBuilder = new StringBuilder(); var description = quickInfo.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.Description); if (description is object) { appendSectionAsCsharp(description, finalTextBuilder, _formattingOptions, includeSpaceAtStart: false); } var summary = quickInfo.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.DocumentationComments); if (summary is object) { buildSectionAsMarkdown(summary, sectionTextBuilder, _formattingOptions, out _); appendBuiltSection(finalTextBuilder, sectionTextBuilder, _formattingOptions); } foreach (var section in quickInfo.Sections) { switch (section.Kind) { case QuickInfoSectionKinds.Description: case QuickInfoSectionKinds.DocumentationComments: continue; case QuickInfoSectionKinds.TypeParameters: appendSectionAsCsharp(section, finalTextBuilder, _formattingOptions); break; case QuickInfoSectionKinds.AnonymousTypes: // The first line is "Anonymous Types:" buildSectionAsMarkdown(section, sectionTextBuilder, _formattingOptions, out int lastIndex, untilLineBreak: true); appendBuiltSection(finalTextBuilder, sectionTextBuilder, _formattingOptions); // Then we want all anonymous types to be C# highlighted appendSectionAsCsharp(section, finalTextBuilder, _formattingOptions, lastIndex + 1); break; case NullabilityAnalysis: // Italicize the nullable analysis for emphasis. buildSectionAsMarkdown(section, sectionTextBuilder, _formattingOptions, out _); appendBuiltSection(finalTextBuilder, sectionTextBuilder, _formattingOptions, italicize: true); break; default: buildSectionAsMarkdown(section, sectionTextBuilder, _formattingOptions, out _); appendBuiltSection(finalTextBuilder, sectionTextBuilder, _formattingOptions); break; } } response.Markdown = finalTextBuilder.ToString().Trim(); return(response);
public async Task <Section> GetTextAt(int pos16) { //using var p1 = perf.local(); if (!CodeInfo.GetContextAndDocument(out var cd, pos16)) { return(null); } //don't include <remarks>. Sometimes it takes too much space. Badly formatted if eg contains markdown. var opt1 = QuickInfoOptions.Default with { ShowRemarksInQuickInfo = false, IncludeNavigationHintsInQuickInfo = false }; var opt2 = new Microsoft.CodeAnalysis.LanguageServices.SymbolDescriptionOptions(opt1, Microsoft.CodeAnalysis.Classification.ClassificationOptions.Default); var service = QuickInfoService.GetService(cd.document); var r = await Task.Run(async() => await service.GetQuickInfoAsync(cd.document, pos16, opt2, default)); //p1.Next(); if (r == null) { return(null); } //this oveload is internal, but: // - The public overload does not have an options parameter. Used to set options for workspace, but it stopped working. // - Roslyn in Debug config asserts "don't use this function". //print.it(r.Span, r.RelatedSpans); //print.it(r.Tags); var a = r.Sections; if (a.Length == 0) { return(null); //when cursor is on }. //SHOULDDO: display block start code, like in VS. } //don't show some useless quickinfos, eg for literals if (r.Tags.Length == 2 && a.Length == 2 && a[1].Kind == QuickInfoSectionKinds.DocumentationComments) { //print.it(r.Tags[0], a[1].Kind, a[1].Text); var s = a[1].Text; if (s.Starts("Represents ")) { switch (r.Tags[0]) { case "Class": if (s == "Represents text as a sequence of UTF-16 code units.") { return(null); } break; case "Structure": if (s.RxIsMatch(@"^Represents a (\d+-bit u?n?signed integer|[\w+-]+ floating-point number)\.$")) { return(null); } break; } } } var x = new CiText(); //bool hasDocComm = false; //QuickInfoSection descr = null; for (int i = 0; i < a.Length; i++) { var se = a[i]; //print.it(se.Kind, se.Text); //if (se.Kind == QuickInfoSectionKinds.RemarksDocumentationComments) continue; x.StartParagraph(); //if (se.Kind == QuickInfoSectionKinds.RemarksDocumentationComments) { // x.Append("More info in Remarks (click and press F1)."); //no, because the DB does not contain Au and .NET remarks; would show this info only for others (local, XML files). //} else { if (i == 0) //image { CiUtil.TagsToKindAndAccess(r.Tags, out var kind, out var access); if (kind != CiItemKind.None) { if (access != default) { x.Image(access); } x.Image(kind); x.Append(" "); } } var tp = se.TaggedParts; if (tp[0].Tag == TextTags.LineBreak) //remove/replace some line breaks in returns and exceptions { int lessNewlines = se.Kind switch { QuickInfoSectionKinds.ReturnsDocumentationComments => 1, QuickInfoSectionKinds.Exception => 2, _ => 0 }; var k = new List <TaggedText>(tp.Length - 1); for (int j = 1; j < tp.Length; j++) { var v = tp[j]; if (lessNewlines > 0 && j > 1) { if (v.Tag == TextTags.LineBreak) { if (j == 2) { continue; //remove line break after "Returns:" etc } if (lessNewlines == 2) //in list of exceptions replace "\n " with ", " { if (++j == tp.Length || tp[j].Tag != TextTags.Space) { j--; continue; } v = new(TextTags.Text, ", "); } } } k.Add(v); } x.AppendTaggedParts(k, false); } else { x.AppendTaggedParts(tp); } //} x.EndParagraph(); } return(x.Result); } }
public async Task <QuickInfoResponse> Handle(QuickInfoRequest request, Document document) { var response = new QuickInfoResponse(); if (document is null) { return(response); } var quickInfoService = QuickInfoService.GetService(document); if (quickInfoService is null) { _logger?.LogWarning($"QuickInfo service was null for {document.FilePath}"); return(response); } var sourceText = await document.GetTextAsync(); var position = sourceText.GetTextPosition(request); var quickInfo = await quickInfoService.GetQuickInfoAsync(document, position); if (quickInfo is null) { _logger?.LogTrace($"No QuickInfo found for {document.FilePath}:{request.Line},{request.Column}"); return(response); } var finalTextBuilder = new StringBuilder(); bool lastSectionHadLineBreak = true; var description = quickInfo.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.Description); if (description is object) { appendSection(description, MarkdownFormat.AllTextAsCSharp); } var summary = quickInfo.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.DocumentationComments); if (summary is object) { appendSection(summary, MarkdownFormat.Default); } foreach (var section in quickInfo.Sections) { switch (section.Kind) { case QuickInfoSectionKinds.Description: case QuickInfoSectionKinds.DocumentationComments: continue; case QuickInfoSectionKinds.TypeParameters: appendSection(section, MarkdownFormat.AllTextAsCSharp); break; case QuickInfoSectionKinds.AnonymousTypes: // The first line is "Anonymous Types:" // Then we want all anonymous types to be C# highlighted appendSection(section, MarkdownFormat.FirstLineDefaultRestCSharp); break; case NullabilityAnalysis: // Italicize the nullable analysis for emphasis. appendSection(section, MarkdownFormat.Italicize); break; default: appendSection(section, MarkdownFormat.Default); break; } } response.Markdown = finalTextBuilder.ToString().Trim(); return(response); void appendSection(QuickInfoSection section, MarkdownFormat format) { if (!lastSectionHadLineBreak && !section.TaggedParts.StartsWithNewline()) { finalTextBuilder.Append(_formattingOptions.NewLine); finalTextBuilder.Append(_formattingOptions.NewLine); } MarkdownHelpers.TaggedTextToMarkdown(section.TaggedParts, finalTextBuilder, _formattingOptions, format, out lastSectionHadLineBreak); } }