Skip to content

[Omnisharp-LSP] textDocument/documentHighlight support #999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System.IO.Pipes;
using System.Reflection;
using System.Threading.Tasks;
Expand All @@ -8,6 +13,7 @@
using System.Security.AccessControl;
using OmniSharp.Extensions.LanguageServer.Server;
using PowerShellEditorServices.Engine.Services.Handlers;
using Microsoft.PowerShell.EditorServices.TextDocument;

namespace Microsoft.PowerShell.EditorServices.Engine
{
Expand Down Expand Up @@ -56,18 +62,26 @@ public async Task StartAsync()
_configuration.OutNamedPipeName,
out NamedPipeServerStream outNamedPipe);

ILogger logger = options.LoggerFactory.CreateLogger("OptionsStartup");

logger.LogInformation("Waiting for connection");
namedPipe.WaitForConnection();
if (outNamedPipe != null)
{
outNamedPipe.WaitForConnection();
}

logger.LogInformation("Connected");

options.Input = namedPipe;
options.Output = outNamedPipe ?? namedPipe;

options.LoggerFactory = _configuration.LoggerFactory;
options.MinimumLogLevel = _configuration.MinimumLogLevel;
options.Services = _configuration.Services;

logger.LogInformation("Adding handlers");

options
.WithHandler<WorkspaceSymbolsHandler>()
.WithHandler<TextDocumentHandler>()
Expand All @@ -77,7 +91,10 @@ public async Task StartAsync()
.WithHandler<DocumentFormattingHandler>()
.WithHandler<DocumentRangeFormattingHandler>()
.WithHandler<ReferencesHandler>()
.WithHandler<DocumentSymbolHandler>();
.WithHandler<DocumentSymbolHandler>()
.WithHandler<DocumentHighlightHandler>();

logger.LogInformation("Handlers added");
});

_serverStart.SetResult(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Symbols;
Expand Down Expand Up @@ -47,8 +53,6 @@ public SymbolsService(

#endregion



/// <summary>
/// Finds all the symbols in a file.
/// </summary>
Expand Down Expand Up @@ -176,5 +180,33 @@ public List<SymbolReference> FindReferencesOfSymbol(

return symbolReferences;
}

/// <summary>
/// Finds all the occurences of a symbol in the script given a file location
/// </summary>
/// <param name="file">The details and contents of a open script file</param>
/// <param name="symbolLineNumber">The line number of the cursor for the given script</param>
/// <param name="symbolColumnNumber">The coulumn number of the cursor for the given script</param>
/// <returns>FindOccurrencesResult</returns>
public IReadOnlyList<SymbolReference> FindOccurrencesInFile(
ScriptFile file,
int symbolLineNumber,
int symbolColumnNumber)
{
SymbolReference foundSymbol = AstOperations.FindSymbolAtPosition(
file.ScriptAst,
symbolLineNumber,
symbolColumnNumber);

if (foundSymbol == null)
{
return null;
}

return AstOperations.FindReferencesOfSymbol(
file.ScriptAst,
foundSymbol,
needsAliases: false).ToArray();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Symbols;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using PowerShellEditorServices.Engine.Utility;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.PowerShell.EditorServices.TextDocument
{
public class DocumentHighlightHandler : IDocumentHighlightHandler
{
private static readonly DocumentHighlightContainer s_emptyHighlightContainer = new DocumentHighlightContainer();

private readonly ILogger _logger;

private readonly WorkspaceService _workspaceService;

private readonly SymbolsService _symbolsService;

private readonly TextDocumentRegistrationOptions _registrationOptions;

private DocumentHighlightCapability _capability;

public DocumentHighlightHandler(
ILoggerFactory loggerFactory,
WorkspaceService workspaceService,
SymbolsService symbolService)
{
_logger = loggerFactory.CreateLogger<OmniSharp.Extensions.LanguageServer.Protocol.Server.DocumentHighlightHandler>();
_workspaceService = workspaceService;
_symbolsService = symbolService;
_registrationOptions = new TextDocumentRegistrationOptions()
{
DocumentSelector = new DocumentSelector(new DocumentFilter() { Pattern = "**/*.ps*1" } )
};
_logger.LogInformation("highlight handler loaded");
}

public TextDocumentRegistrationOptions GetRegistrationOptions()
{
return _registrationOptions;
}

public Task<DocumentHighlightContainer> Handle(
DocumentHighlightParams request,
CancellationToken cancellationToken)
{
ScriptFile scriptFile = _workspaceService.GetFile(PathUtils.FromUri(request.TextDocument.Uri));

IReadOnlyList<SymbolReference> symbolOccurrences = _symbolsService.FindOccurrencesInFile(
scriptFile,
(int)request.Position.Line,
(int)request.Position.Character);

if (symbolOccurrences == null)
{
return Task.FromResult(s_emptyHighlightContainer);
}

var highlights = new DocumentHighlight[symbolOccurrences.Count];
for (int i = 0; i < symbolOccurrences.Count; i++)
{
highlights[i] = new DocumentHighlight
{
Kind = DocumentHighlightKind.Write, // TODO: Which symbol types are writable?
Range = symbolOccurrences[i].ScriptRegion.ToRange()
};
}

return Task.FromResult(new DocumentHighlightContainer(highlights));
}

public void SetCapability(DocumentHighlightCapability capability)
{
_capability = capability;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,21 @@ internal static ScriptFileMarker FromDiagnosticRecord(PSObject psObject)

if (diagnosticRecord.SuggestedCorrections != null)
{
var suggestedCorrections = diagnosticRecord.SuggestedCorrections as dynamic;
List<ScriptRegion> editRegions = new List<ScriptRegion>();
var editRegions = new List<ScriptRegion>();
string correctionMessage = null;
foreach (var suggestedCorrection in suggestedCorrections)
foreach (dynamic suggestedCorrection in diagnosticRecord.SuggestedCorrections)
{
editRegions.Add(new ScriptRegion
{
File = diagnosticRecord.ScriptPath,
Text = suggestedCorrection.Text,
StartLineNumber = suggestedCorrection.StartLineNumber,
StartColumnNumber = suggestedCorrection.StartColumnNumber,
EndLineNumber = suggestedCorrection.EndLineNumber,
EndColumnNumber = suggestedCorrection.EndColumnNumber
});
editRegions.Add(
new ScriptRegion(
diagnosticRecord.ScriptPath,
suggestedCorrection.Text,
suggestedCorrection.StartLineNumber,
suggestedCorrection.StartColumnNumber,
startOffset: -1,
suggestedCorrection.EndLineNumber,
suggestedCorrection.EndColumnNumber,
endOffset: -1));

correctionMessage = suggestedCorrection.Description;
}

Expand Down
Loading