Skip to content

Commit 43128e6

Browse files
codelens support (PowerShell#1001)
* codelens support * address rob's feedback
1 parent dda6258 commit 43128e6

13 files changed

+734
-29
lines changed

src/PowerShellEditorServices.Engine/LanguageServer/OmnisharpLanguageServer.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,10 @@ public async Task StartAsync()
9292
.WithHandler<DocumentRangeFormattingHandler>()
9393
.WithHandler<ReferencesHandler>()
9494
.WithHandler<DocumentSymbolHandler>()
95-
.WithHandler<DocumentHighlightHandler>();
95+
.WithHandler<DocumentHighlightHandler>()
96+
.WithHandler<CodeLensHandlers>();
9697

97-
logger.LogInformation("Handlers added");
98+
logger.LogInformation("Handlers added");
9899
});
99100

100101
_serverStart.SetResult(true);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.PowerShell.EditorServices.CodeLenses
7+
{
8+
/// <summary>
9+
/// Represents data expected back in an LSP CodeLens response.
10+
/// </summary>
11+
internal class CodeLensData
12+
{
13+
public string Uri { get; set; }
14+
15+
public string ProviderId { get; set; }
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
9+
10+
namespace Microsoft.PowerShell.EditorServices.CodeLenses
11+
{
12+
/// <summary>
13+
/// Specifies the contract for a Code Lens provider.
14+
/// </summary>
15+
public interface ICodeLensProvider
16+
{
17+
/// <summary>
18+
/// Specifies a unique identifier for the feature provider, typically a
19+
/// fully-qualified name like "Microsoft.PowerShell.EditorServices.MyProvider"
20+
/// </summary>
21+
string ProviderId { get; }
22+
23+
/// <summary>
24+
/// Provides a collection of CodeLenses for the given
25+
/// document.
26+
/// </summary>
27+
/// <param name="scriptFile">
28+
/// The document for which CodeLenses should be provided.
29+
/// </param>
30+
/// <returns>An array of CodeLenses.</returns>
31+
CodeLens[] ProvideCodeLenses(ScriptFile scriptFile);
32+
33+
/// <summary>
34+
/// Resolves a CodeLens that was created without a Command.
35+
/// </summary>
36+
/// <param name="codeLens">
37+
/// The CodeLens to resolve.
38+
/// </param>
39+
/// <param name="scriptFile">
40+
/// A CancellationToken which can be used to cancel the
41+
/// request.
42+
/// </param>
43+
/// <returns>
44+
/// A Task which returns the resolved CodeLens when completed.
45+
/// </returns>
46+
CodeLens ResolveCodeLens(
47+
CodeLens codeLens,
48+
ScriptFile scriptFile);
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Collections.Generic;
7+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
8+
9+
namespace Microsoft.PowerShell.EditorServices.CodeLenses
10+
{
11+
/// <summary>
12+
/// Specifies the contract for an implementation of
13+
/// the ICodeLenses component.
14+
/// </summary>
15+
public interface ICodeLenses
16+
{
17+
/// <summary>
18+
/// Gets the collection of ICodeLensProvider implementations
19+
/// that are registered with this component.
20+
/// </summary>
21+
List<ICodeLensProvider> Providers { get; }
22+
23+
/// <summary>
24+
/// Provides a collection of CodeLenses for the given
25+
/// document.
26+
/// </summary>
27+
/// <param name="scriptFile">
28+
/// The document for which CodeLenses should be provided.
29+
/// </param>
30+
/// <returns>An array of CodeLenses.</returns>
31+
CodeLens[] ProvideCodeLenses(ScriptFile scriptFile);
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Management.Automation.Language;
7+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
8+
9+
namespace Microsoft.PowerShell.EditorServices
10+
{
11+
internal static class IScriptExtentExtensions
12+
{
13+
public static Range ToRange(this IScriptExtent scriptExtent)
14+
{
15+
return new Range
16+
{
17+
Start = new Position
18+
{
19+
Line = scriptExtent.StartLineNumber - 1,
20+
Character = scriptExtent.StartColumnNumber - 1
21+
},
22+
End = new Position
23+
{
24+
Line = scriptExtent.EndLineNumber - 1,
25+
Character = scriptExtent.EndColumnNumber - 1
26+
}
27+
};
28+
}
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Collections.Generic;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Microsoft.PowerShell.EditorServices.Symbols;
10+
using Newtonsoft.Json.Linq;
11+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
12+
13+
namespace Microsoft.PowerShell.EditorServices.CodeLenses
14+
{
15+
internal class PesterCodeLensProvider : ICodeLensProvider
16+
{
17+
18+
/// <summary>
19+
/// The symbol provider to get symbols from to build code lenses with.
20+
/// </summary>
21+
private readonly IDocumentSymbolProvider _symbolProvider;
22+
23+
/// <summary>
24+
/// Specifies a unique identifier for the feature provider, typically a
25+
/// fully-qualified name like "Microsoft.PowerShell.EditorServices.MyProvider"
26+
/// </summary>
27+
public string ProviderId => nameof(PesterCodeLensProvider);
28+
29+
/// <summary>
30+
/// Create a new Pester CodeLens provider for a given editor session.
31+
/// </summary>
32+
public PesterCodeLensProvider()
33+
{
34+
_symbolProvider = new PesterDocumentSymbolProvider();
35+
}
36+
37+
/// <summary>
38+
/// Get the Pester CodeLenses for a given Pester symbol.
39+
/// </summary>
40+
/// <param name="pesterSymbol">The Pester symbol to get CodeLenses for.</param>
41+
/// <param name="scriptFile">The script file the Pester symbol comes from.</param>
42+
/// <returns>All CodeLenses for the given Pester symbol.</returns>
43+
private CodeLens[] GetPesterLens(PesterSymbolReference pesterSymbol, ScriptFile scriptFile)
44+
{
45+
46+
var codeLensResults = new CodeLens[]
47+
{
48+
new CodeLens()
49+
{
50+
Range = pesterSymbol.ScriptRegion.ToRange(),
51+
Data = JToken.FromObject(new {
52+
Uri = scriptFile.DocumentUri,
53+
ProviderId = nameof(PesterCodeLensProvider)
54+
}),
55+
Command = new Command()
56+
{
57+
Name = "PowerShell.RunPesterTests",
58+
Title = "Run tests",
59+
Arguments = JArray.FromObject(new object[] {
60+
scriptFile.DocumentUri,
61+
false /* No debug */,
62+
pesterSymbol.TestName,
63+
pesterSymbol.ScriptRegion?.StartLineNumber })
64+
}
65+
},
66+
67+
new CodeLens()
68+
{
69+
Range = pesterSymbol.ScriptRegion.ToRange(),
70+
Data = JToken.FromObject(new {
71+
Uri = scriptFile.DocumentUri,
72+
ProviderId = nameof(PesterCodeLensProvider)
73+
}),
74+
Command = new Command()
75+
{
76+
Name = "PowerShell.RunPesterTests",
77+
Title = "Debug tests",
78+
Arguments = JArray.FromObject(new object[] {
79+
scriptFile.DocumentUri,
80+
true /* No debug */,
81+
pesterSymbol.TestName,
82+
pesterSymbol.ScriptRegion?.StartLineNumber })
83+
}
84+
}
85+
};
86+
87+
return codeLensResults;
88+
}
89+
90+
/// <summary>
91+
/// Get all Pester CodeLenses for a given script file.
92+
/// </summary>
93+
/// <param name="scriptFile">The script file to get Pester CodeLenses for.</param>
94+
/// <returns>All Pester CodeLenses for the given script file.</returns>
95+
public CodeLens[] ProvideCodeLenses(ScriptFile scriptFile)
96+
{
97+
var lenses = new List<CodeLens>();
98+
foreach (SymbolReference symbol in _symbolProvider.ProvideDocumentSymbols(scriptFile))
99+
{
100+
if (symbol is PesterSymbolReference pesterSymbol)
101+
{
102+
if (pesterSymbol.Command != PesterCommandType.Describe)
103+
{
104+
continue;
105+
}
106+
107+
lenses.AddRange(GetPesterLens(pesterSymbol, scriptFile));
108+
}
109+
}
110+
111+
return lenses.ToArray();
112+
}
113+
114+
/// <summary>
115+
/// Resolve the CodeLens provision asynchronously -- just wraps the CodeLens argument in a task.
116+
/// </summary>
117+
/// <param name="codeLens">The code lens to resolve.</param>
118+
/// <param name="scriptFile">The script file.</param>
119+
/// <returns>The given CodeLens, wrapped in a task.</returns>
120+
public CodeLens ResolveCodeLens(CodeLens codeLens, ScriptFile scriptFile)
121+
{
122+
// This provider has no specific behavior for
123+
// resolving CodeLenses.
124+
return codeLens;
125+
}
126+
}
127+
}

0 commit comments

Comments
 (0)