Skip to content

Commit dda6258

Browse files
Robert HoltTylerLeonhardt
Robert Holt
authored andcommitted
[Omnisharp-LSP] textDocument/documentHighlight support (PowerShell#999)
* Add handler scaffold * More stuff * Make handler work * Add copyright * Add tests, fix bugs * Fix small issues
1 parent 74f4f2f commit dda6258

File tree

8 files changed

+298
-55
lines changed

8 files changed

+298
-55
lines changed

src/PowerShellEditorServices.Engine/LanguageServer/OmnisharpLanguageServer.cs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
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+
16
using System.IO.Pipes;
27
using System.Reflection;
38
using System.Threading.Tasks;
@@ -8,6 +13,7 @@
813
using System.Security.AccessControl;
914
using OmniSharp.Extensions.LanguageServer.Server;
1015
using PowerShellEditorServices.Engine.Services.Handlers;
16+
using Microsoft.PowerShell.EditorServices.TextDocument;
1117

1218
namespace Microsoft.PowerShell.EditorServices.Engine
1319
{
@@ -56,18 +62,26 @@ public async Task StartAsync()
5662
_configuration.OutNamedPipeName,
5763
out NamedPipeServerStream outNamedPipe);
5864

65+
ILogger logger = options.LoggerFactory.CreateLogger("OptionsStartup");
66+
67+
logger.LogInformation("Waiting for connection");
5968
namedPipe.WaitForConnection();
6069
if (outNamedPipe != null)
6170
{
6271
outNamedPipe.WaitForConnection();
6372
}
6473

74+
logger.LogInformation("Connected");
75+
6576
options.Input = namedPipe;
6677
options.Output = outNamedPipe ?? namedPipe;
6778

6879
options.LoggerFactory = _configuration.LoggerFactory;
6980
options.MinimumLogLevel = _configuration.MinimumLogLevel;
7081
options.Services = _configuration.Services;
82+
83+
logger.LogInformation("Adding handlers");
84+
7185
options
7286
.WithHandler<WorkspaceSymbolsHandler>()
7387
.WithHandler<TextDocumentHandler>()
@@ -77,7 +91,10 @@ public async Task StartAsync()
7791
.WithHandler<DocumentFormattingHandler>()
7892
.WithHandler<DocumentRangeFormattingHandler>()
7993
.WithHandler<ReferencesHandler>()
80-
.WithHandler<DocumentSymbolHandler>();
94+
.WithHandler<DocumentSymbolHandler>()
95+
.WithHandler<DocumentHighlightHandler>();
96+
97+
logger.LogInformation("Handlers added");
8198
});
8299

83100
_serverStart.SetResult(true);

src/PowerShellEditorServices.Engine/Services/Symbols/SymbolsService.cs

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
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+
16
using System;
27
using System.Collections.Generic;
38
using System.Collections.Specialized;
9+
using System.Linq;
410
using System.Runtime.InteropServices;
511
using Microsoft.Extensions.Logging;
612
using Microsoft.PowerShell.EditorServices.Symbols;
@@ -47,8 +53,6 @@ public SymbolsService(
4753

4854
#endregion
4955

50-
51-
5256
/// <summary>
5357
/// Finds all the symbols in a file.
5458
/// </summary>
@@ -176,5 +180,33 @@ public List<SymbolReference> FindReferencesOfSymbol(
176180

177181
return symbolReferences;
178182
}
183+
184+
/// <summary>
185+
/// Finds all the occurences of a symbol in the script given a file location
186+
/// </summary>
187+
/// <param name="file">The details and contents of a open script file</param>
188+
/// <param name="symbolLineNumber">The line number of the cursor for the given script</param>
189+
/// <param name="symbolColumnNumber">The coulumn number of the cursor for the given script</param>
190+
/// <returns>FindOccurrencesResult</returns>
191+
public IReadOnlyList<SymbolReference> FindOccurrencesInFile(
192+
ScriptFile file,
193+
int symbolLineNumber,
194+
int symbolColumnNumber)
195+
{
196+
SymbolReference foundSymbol = AstOperations.FindSymbolAtPosition(
197+
file.ScriptAst,
198+
symbolLineNumber,
199+
symbolColumnNumber);
200+
201+
if (foundSymbol == null)
202+
{
203+
return null;
204+
}
205+
206+
return AstOperations.FindReferencesOfSymbol(
207+
file.ScriptAst,
208+
foundSymbol,
209+
needsAliases: false).ToArray();
210+
}
179211
}
180212
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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 Microsoft.Extensions.Logging;
7+
using Microsoft.PowerShell.EditorServices.Symbols;
8+
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
9+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
10+
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
11+
using PowerShellEditorServices.Engine.Utility;
12+
using System.Collections.Generic;
13+
using System.Threading;
14+
using System.Threading.Tasks;
15+
16+
namespace Microsoft.PowerShell.EditorServices.TextDocument
17+
{
18+
public class DocumentHighlightHandler : IDocumentHighlightHandler
19+
{
20+
private static readonly DocumentHighlightContainer s_emptyHighlightContainer = new DocumentHighlightContainer();
21+
22+
private readonly ILogger _logger;
23+
24+
private readonly WorkspaceService _workspaceService;
25+
26+
private readonly SymbolsService _symbolsService;
27+
28+
private readonly TextDocumentRegistrationOptions _registrationOptions;
29+
30+
private DocumentHighlightCapability _capability;
31+
32+
public DocumentHighlightHandler(
33+
ILoggerFactory loggerFactory,
34+
WorkspaceService workspaceService,
35+
SymbolsService symbolService)
36+
{
37+
_logger = loggerFactory.CreateLogger<OmniSharp.Extensions.LanguageServer.Protocol.Server.DocumentHighlightHandler>();
38+
_workspaceService = workspaceService;
39+
_symbolsService = symbolService;
40+
_registrationOptions = new TextDocumentRegistrationOptions()
41+
{
42+
DocumentSelector = new DocumentSelector(new DocumentFilter() { Pattern = "**/*.ps*1" } )
43+
};
44+
_logger.LogInformation("highlight handler loaded");
45+
}
46+
47+
public TextDocumentRegistrationOptions GetRegistrationOptions()
48+
{
49+
return _registrationOptions;
50+
}
51+
52+
public Task<DocumentHighlightContainer> Handle(
53+
DocumentHighlightParams request,
54+
CancellationToken cancellationToken)
55+
{
56+
ScriptFile scriptFile = _workspaceService.GetFile(PathUtils.FromUri(request.TextDocument.Uri));
57+
58+
IReadOnlyList<SymbolReference> symbolOccurrences = _symbolsService.FindOccurrencesInFile(
59+
scriptFile,
60+
(int)request.Position.Line,
61+
(int)request.Position.Character);
62+
63+
if (symbolOccurrences == null)
64+
{
65+
return Task.FromResult(s_emptyHighlightContainer);
66+
}
67+
68+
var highlights = new DocumentHighlight[symbolOccurrences.Count];
69+
for (int i = 0; i < symbolOccurrences.Count; i++)
70+
{
71+
highlights[i] = new DocumentHighlight
72+
{
73+
Kind = DocumentHighlightKind.Write, // TODO: Which symbol types are writable?
74+
Range = symbolOccurrences[i].ScriptRegion.ToRange()
75+
};
76+
}
77+
78+
return Task.FromResult(new DocumentHighlightContainer(highlights));
79+
}
80+
81+
public void SetCapability(DocumentHighlightCapability capability)
82+
{
83+
_capability = capability;
84+
}
85+
}
86+
}

src/PowerShellEditorServices.Engine/Services/TextDocument/ScriptFileMarker.cs

+13-12
Original file line numberDiff line numberDiff line change
@@ -139,20 +139,21 @@ internal static ScriptFileMarker FromDiagnosticRecord(PSObject psObject)
139139

140140
if (diagnosticRecord.SuggestedCorrections != null)
141141
{
142-
var suggestedCorrections = diagnosticRecord.SuggestedCorrections as dynamic;
143-
List<ScriptRegion> editRegions = new List<ScriptRegion>();
142+
var editRegions = new List<ScriptRegion>();
144143
string correctionMessage = null;
145-
foreach (var suggestedCorrection in suggestedCorrections)
144+
foreach (dynamic suggestedCorrection in diagnosticRecord.SuggestedCorrections)
146145
{
147-
editRegions.Add(new ScriptRegion
148-
{
149-
File = diagnosticRecord.ScriptPath,
150-
Text = suggestedCorrection.Text,
151-
StartLineNumber = suggestedCorrection.StartLineNumber,
152-
StartColumnNumber = suggestedCorrection.StartColumnNumber,
153-
EndLineNumber = suggestedCorrection.EndLineNumber,
154-
EndColumnNumber = suggestedCorrection.EndColumnNumber
155-
});
146+
editRegions.Add(
147+
new ScriptRegion(
148+
diagnosticRecord.ScriptPath,
149+
suggestedCorrection.Text,
150+
suggestedCorrection.StartLineNumber,
151+
suggestedCorrection.StartColumnNumber,
152+
startOffset: -1,
153+
suggestedCorrection.EndLineNumber,
154+
suggestedCorrection.EndColumnNumber,
155+
endOffset: -1));
156+
156157
correctionMessage = suggestedCorrection.Description;
157158
}
158159

0 commit comments

Comments
 (0)