Skip to content

Commit 4ae9a07

Browse files
Parse tooltips for members to create markdown view
1 parent d3d5aea commit 4ae9a07

File tree

3 files changed

+536
-16
lines changed

3 files changed

+536
-16
lines changed

src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Linq;
67
using System.Management.Automation;
78
using System.Text;
89
using System.Text.RegularExpressions;
@@ -48,18 +49,20 @@ protected override CompletionRegistrationOptions CreateRegistrationOptions(Compl
4849
{
4950
_completionCapability = capability;
5051
return new CompletionRegistrationOptions()
51-
{
52-
// TODO: What do we do with the arguments?
53-
DocumentSelector = LspUtils.PowerShellDocumentSelector,
54-
ResolveProvider = true,
52+
{
53+
// TODO: What do we do with the arguments?
54+
DocumentSelector = LspUtils.PowerShellDocumentSelector,
55+
ResolveProvider = true,
5556
TriggerCharacters = new[] { ".", "-", ":", "\\", "$", " " },
56-
};
57+
};
5758
}
5859

5960
public bool SupportsSnippets => _completionCapability?.CompletionItem?.SnippetSupport is true;
6061

6162
public bool SupportsCommitCharacters => _completionCapability?.CompletionItem?.CommitCharactersSupport is true;
6263

64+
public bool SupportsMarkdown => _completionCapability?.CompletionItem?.DocumentationFormat?.Contains(MarkupKind.Markdown) is true;
65+
6366
public override async Task<CompletionList> Handle(CompletionParams request, CancellationToken cancellationToken)
6467
{
6568
int cursorLine = request.Position.Line + 1;
@@ -81,6 +84,61 @@ public override async Task<CompletionList> Handle(CompletionParams request, Canc
8184
// Handler for "completionItem/resolve". In VSCode this is fired when a completion item is highlighted in the completion list.
8285
public override async Task<CompletionItem> Handle(CompletionItem request, CancellationToken cancellationToken)
8386
{
87+
if (SupportsMarkdown)
88+
{
89+
if (request.Kind is CompletionItemKind.Method)
90+
{
91+
string documentation = FormatUtils.GetMethodDocumentation(
92+
_logger,
93+
request.Data.ToString(),
94+
out MarkupKind kind);
95+
96+
return request with
97+
{
98+
Documentation = new MarkupContent()
99+
{
100+
Kind = kind,
101+
Value = documentation,
102+
},
103+
};
104+
}
105+
106+
if (request.Kind is CompletionItemKind.Class or CompletionItemKind.TypeParameter or CompletionItemKind.Enum)
107+
{
108+
string documentation = FormatUtils.GetTypeDocumentation(
109+
_logger,
110+
request.Detail,
111+
out MarkupKind kind);
112+
113+
return request with
114+
{
115+
Detail = null,
116+
Documentation = new MarkupContent()
117+
{
118+
Kind = kind,
119+
Value = documentation,
120+
},
121+
};
122+
}
123+
124+
if (request.Kind is CompletionItemKind.EnumMember or CompletionItemKind.Property or CompletionItemKind.Field)
125+
{
126+
string documentation = FormatUtils.GetPropertyDocumentation(
127+
_logger,
128+
request.Data.ToString(),
129+
out MarkupKind kind);
130+
131+
return request with
132+
{
133+
Documentation = new MarkupContent()
134+
{
135+
Kind = kind,
136+
Value = documentation,
137+
},
138+
};
139+
}
140+
}
141+
84142
// We currently only support this request for anything that returns a CommandInfo:
85143
// functions, cmdlets, aliases. No detail means the module hasn't been imported yet and
86144
// IntelliSense shouldn't import the module to get this info.
@@ -242,15 +300,19 @@ internal CompletionItem CreateCompletionItem(
242300
CompletionResultType.Command => item with { Kind = CompletionItemKind.Function },
243301
CompletionResultType.ProviderItem or CompletionResultType.ProviderContainer
244302
=> CreateProviderItemCompletion(item, result, scriptFile, textToBeReplaced),
245-
? item with
246-
{
247-
Kind = CompletionItemKind.Folder,
248-
InsertTextFormat = InsertTextFormat.Snippet,
249-
TextEdit = textEdit with { NewText = snippet }
250-
}
251-
: item with { Kind = CompletionItemKind.Folder },
252-
CompletionResultType.Property => item with { Kind = CompletionItemKind.Property },
253-
CompletionResultType.Method => item with { Kind = CompletionItemKind.Method },
303+
CompletionResultType.Property => item with
304+
{
305+
Kind = CompletionItemKind.Property,
306+
Detail = SupportsMarkdown ? null : detail,
307+
Data = SupportsMarkdown ? detail : null,
308+
CommitCharacters = MaybeAddCommitCharacters("."),
309+
},
310+
CompletionResultType.Method => item with
311+
{
312+
Kind = CompletionItemKind.Method,
313+
Data = item.Detail,
314+
Detail = SupportsMarkdown ? null : item.Detail,
315+
},
254316
CompletionResultType.ParameterName => TryExtractType(detail, out string type)
255317
? item with { Kind = CompletionItemKind.Variable, Detail = type }
256318
// The comparison operators (-eq, -not, -gt, etc) unfortunately come across as
@@ -265,8 +327,10 @@ CompletionResultType.ProviderItem or CompletionResultType.ProviderContainer
265327
CompletionResultType.Type => detail.StartsWith("Class ", StringComparison.CurrentCulture)
266328
// Custom classes come through as types but the PowerShell completion tooltip
267329
// will start with "Class ", so we can more accurately display its icon.
268-
? item with { Kind = CompletionItemKind.Class }
269-
: item with { Kind = CompletionItemKind.TypeParameter },
330+
? item with { Kind = CompletionItemKind.Class, Detail = detail.Substring("Class ".Length) }
331+
: detail.StartsWith("Enum ", StringComparison.CurrentCulture)
332+
? item with { Kind = CompletionItemKind.Enum, Detail = detail.Substring("Enum ".Length) }
333+
: item with { Kind = CompletionItemKind.TypeParameter },
270334
CompletionResultType.Keyword or CompletionResultType.DynamicKeyword =>
271335
item with { Kind = CompletionItemKind.Keyword },
272336
_ => throw new ArgumentOutOfRangeException(nameof(result))

src/PowerShellEditorServices/Utility/Extensions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Collections.Generic;
77
using System.Management.Automation.Language;
8+
using System.Text;
89

910
namespace Microsoft.PowerShell.EditorServices.Utility
1011
{
@@ -144,5 +145,21 @@ public static bool Contains(this IScriptExtent scriptExtent, int line, int colum
144145

145146
return true;
146147
}
148+
149+
/// <summary>
150+
/// Same as <see cref="StringBuilder.AppendLine()" /> but never CRLF. Use this when building
151+
/// formatting for clients that may not render CRLF correctly.
152+
/// </summary>
153+
/// <param name="self"></param>
154+
public static StringBuilder AppendLineLF(this StringBuilder self) => self.Append('\n');
155+
156+
/// <summary>
157+
/// Same as <see cref="StringBuilder.AppendLine(string)" /> but never CRLF. Use this when building
158+
/// formatting for clients that may not render CRLF correctly.
159+
/// </summary>
160+
/// <param name="self"></param>
161+
/// <param name="value"></param>
162+
public static StringBuilder AppendLineLF(this StringBuilder self, string value)
163+
=> self.Append(value).Append('\n');
147164
}
148165
}

0 commit comments

Comments
 (0)