|
7 | 7 | using Microsoft.CodeAnalysis.Completion; |
8 | 8 | using Microsoft.CodeAnalysis.Diagnostics; |
9 | 9 | using Microsoft.CodeAnalysis.Host.Mef; |
| 10 | +using Microsoft.CodeAnalysis.QuickInfo; |
10 | 11 | using Microsoft.CodeAnalysis.Text; |
11 | 12 | using Microsoft.Extensions.Logging; |
12 | 13 | using System.Runtime.CompilerServices; |
@@ -471,6 +472,87 @@ static string addPrefix(string? prefix, string nested) |
471 | 472 | } |
472 | 473 | } |
473 | 474 |
|
| 475 | + /// <returns> |
| 476 | + /// Markdown or <see langword="null"/> if cancelled. |
| 477 | + /// </returns> |
| 478 | + /// <remarks> |
| 479 | + /// For inspiration, see <see href="https://github.com/dotnet/roslyn/blob/ad14335550de1134f0b5a59b6cd040001d0d8c8d/src/LanguageServer/Protocol/Handler/Hover/HoverHandler.cs#L26"/>. |
| 480 | + /// </remarks> |
| 481 | + public async Task<string?> ProvideHoverAsync(string modelUri, string positionJson, CancellationToken cancellationToken) |
| 482 | + { |
| 483 | + if (!TryGetDocument(modelUri, out var document)) |
| 484 | + { |
| 485 | + return ""; |
| 486 | + } |
| 487 | + |
| 488 | + var sw = Stopwatch.StartNew(); |
| 489 | + var position = JsonSerializer.Deserialize(positionJson, BlazorMonacoJsonContext.Default.Position)!; |
| 490 | + try |
| 491 | + { |
| 492 | + var text = await document.GetTextAsync(cancellationToken); |
| 493 | + int caretPosition = text.Lines.GetPosition(position.ToLinePosition()); |
| 494 | + var quickInfoService = document.Project.Services.GetRequiredService<QuickInfoService>(); |
| 495 | + var quickInfo = await quickInfoService.GetQuickInfoAsync(document, caretPosition, cancellationToken); |
| 496 | + if (quickInfo == null) |
| 497 | + { |
| 498 | + return ""; |
| 499 | + } |
| 500 | + |
| 501 | + // Insert line breaks in between sections to ensure we get double spacing between sections. |
| 502 | + var tags = quickInfo.Sections.SelectMany(static s => |
| 503 | + s.TaggedParts.Add(new TaggedText(TextTags.LineBreak, Environment.NewLine))); |
| 504 | + |
| 505 | + var markdown = MonacoConversions.GetMarkdown(tags, document.Project.Language); |
| 506 | + |
| 507 | + logger.LogDebug("Got hover ({Length}) for {Position} in {Time} ms", markdown.Length, position.Stringify(), sw.ElapsedMilliseconds.SeparateThousands()); |
| 508 | + |
| 509 | + return markdown; |
| 510 | + } |
| 511 | + catch (OperationCanceledException) |
| 512 | + { |
| 513 | + logger.LogDebug("Canceled hover for {Position} in {Time} ms", position.Stringify(), sw.ElapsedMilliseconds.SeparateThousands()); |
| 514 | + |
| 515 | + return null; |
| 516 | + } |
| 517 | + } |
| 518 | + |
| 519 | + /// <returns> |
| 520 | + /// JSON-serialized <see cref="SignatureHelp"/>. |
| 521 | + /// We serialize here to avoid serializing twice unnecessarily |
| 522 | + /// (first on Worker to App interface, then on App to Monaco interface). |
| 523 | + /// </returns> |
| 524 | + /// <remarks> |
| 525 | + /// For inspiration, see <see href="https://github.com/dotnet/roslyn/blob/ad14335550de1134f0b5a59b6cd040001d0d8c8d/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs#L25"/>. |
| 526 | + /// </remarks> |
| 527 | + public async Task<string?> ProvideSignatureHelpAsync(string modelUri, string positionJson, string contextJson, CancellationToken cancellationToken) |
| 528 | + { |
| 529 | + if (!TryGetDocument(modelUri, out var document)) |
| 530 | + { |
| 531 | + return "null"; |
| 532 | + } |
| 533 | + |
| 534 | + var sw = Stopwatch.StartNew(); |
| 535 | + var position = JsonSerializer.Deserialize(positionJson, BlazorMonacoJsonContext.Default.Position)!; |
| 536 | + try |
| 537 | + { |
| 538 | + var text = await document.GetTextAsync(cancellationToken); |
| 539 | + int caretPosition = text.Lines.GetPosition(position.ToLinePosition()); |
| 540 | + var context = JsonSerializer.Deserialize(contextJson, BlazorMonacoJsonContext.Default.SignatureHelpContext)!; |
| 541 | + var signatureHelp = await document.GetSignatureHelpAsync(caretPosition, context.ToReason(), context.TriggerCharacter, cancellationToken); |
| 542 | + var signatureHelpJson = JsonSerializer.Serialize(signatureHelp, BlazorMonacoJsonContext.Default.SignatureHelp); |
| 543 | + |
| 544 | + logger.LogDebug("Got signature help ({Length}) for {Position} in {Time} ms", signatureHelpJson.Length, position.Stringify(), sw.ElapsedMilliseconds.SeparateThousands()); |
| 545 | + |
| 546 | + return signatureHelpJson; |
| 547 | + } |
| 548 | + catch (OperationCanceledException) |
| 549 | + { |
| 550 | + logger.LogDebug("Canceled signature help for {Position} in {Time} ms", position.Stringify(), sw.ElapsedMilliseconds.SeparateThousands()); |
| 551 | + |
| 552 | + return null; |
| 553 | + } |
| 554 | + } |
| 555 | + |
474 | 556 | public async void OnCompilationFinished() |
475 | 557 | { |
476 | 558 | try |
|
0 commit comments