From 5a344fb59af9e40ebdab189410834fbd2408d6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Saulius=20Menkevic=CC=8Cius?= Date: Thu, 14 May 2020 08:24:32 +0300 Subject: [PATCH 1/2] LSP: wire up handler for codeAction --- .../Handlers/OmniSharpCodeActionHandler.cs | 101 ++++++++++++++++++ .../Helpers.cs | 17 +++ .../LanguageServerHost.cs | 1 + 3 files changed, 119 insertions(+) create mode 100644 src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpCodeActionHandler.cs diff --git a/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpCodeActionHandler.cs b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpCodeActionHandler.cs new file mode 100644 index 0000000000..ff04622646 --- /dev/null +++ b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpCodeActionHandler.cs @@ -0,0 +1,101 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using OmniSharp.Extensions.JsonRpc; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Models; +using OmniSharp.Models.V2.CodeActions; + +namespace OmniSharp.LanguageServerProtocol.Handlers +{ + internal sealed class OmniSharpCodeActionHandler: CodeActionHandler + { + public static IEnumerable Enumerate(RequestHandlers handlers) + { + foreach (var (selector, getActionsHandler, runActionHandler) in handlers + .OfType, + Mef.IRequestHandler>()) + { + yield return new OmniSharpCodeActionHandler(getActionsHandler, runActionHandler, selector); + } + } + + private readonly Mef.IRequestHandler _getActionsHandler; + private readonly Mef.IRequestHandler _runActionHandler; + + public OmniSharpCodeActionHandler( + Mef.IRequestHandler getActionsHandler, + Mef.IRequestHandler runActionHandler, + DocumentSelector documentSelector) + : base(new CodeActionRegistrationOptions() + { + DocumentSelector = documentSelector, + CodeActionKinds = new Container( + CodeActionKind.SourceOrganizeImports, + CodeActionKind.Refactor, + CodeActionKind.RefactorExtract), + }) + { + _getActionsHandler = getActionsHandler; + _runActionHandler = runActionHandler; + } + + public async override Task Handle(CodeActionParams request, CancellationToken cancellationToken) + { + var omnisharpRequest = new GetCodeActionsRequest { + FileName = Helpers.FromUri(request.TextDocument.Uri), + Column = (int)request.Range.Start.Character, + Line = (int)request.Range.Start.Line, + Selection = Helpers.FromRange(request.Range), + }; + + var omnisharpResponse = await _getActionsHandler.Handle(omnisharpRequest); + + var codeActions = new List(); + + foreach (var ca in omnisharpResponse.CodeActions) + { + var omnisharpCaRequest = new RunCodeActionRequest { + Identifier = ca.Identifier, + FileName = Helpers.FromUri(request.TextDocument.Uri), + Column = Convert.ToInt32(request.Range.Start.Character), + Line = Convert.ToInt32(request.Range.Start.Line), + Selection = Helpers.FromRange(request.Range), + ApplyTextChanges = false, + WantsTextChanges = true, + }; + + var omnisharpCaResponse = await _runActionHandler.Handle(omnisharpCaRequest); + + var changes = omnisharpCaResponse.Changes.ToDictionary( + x => Helpers.ToUri(x.FileName), + x => ((ModifiedFileResponse)x).Changes.Select(edit => new TextEdit + { + NewText = edit.NewText, + Range = Helpers.ToRange((edit.StartColumn, edit.StartLine), (edit.EndColumn, edit.EndLine)) + })); + + CodeActionKind kind; + if (ca.Identifier.StartsWith("using ")) { kind = CodeActionKind.SourceOrganizeImports; } + else if (ca.Identifier.StartsWith("Inline ")) { kind = CodeActionKind.RefactorInline; } + else if (ca.Identifier.StartsWith("Extract ")) { kind = CodeActionKind.RefactorExtract; } + else if (ca.Identifier.StartsWith("Change ")) { kind = CodeActionKind.QuickFix; } + else { kind = CodeActionKind.Refactor; } + + codeActions.Add( + new CodeAction { + Title = ca.Name, + Kind = kind, + Diagnostics = new Container(), + Edit = new WorkspaceEdit { Changes = changes, } + }); + } + + return new CommandOrCodeActionContainer( + codeActions.Select(ca => new CommandOrCodeAction(ca))); + } + } +} diff --git a/src/OmniSharp.LanguageServerProtocol/Helpers.cs b/src/OmniSharp.LanguageServerProtocol/Helpers.cs index 1180e12683..67b5118300 100644 --- a/src/OmniSharp.LanguageServerProtocol/Helpers.cs +++ b/src/OmniSharp.LanguageServerProtocol/Helpers.cs @@ -40,6 +40,23 @@ public static Range ToRange(this QuickFix location) }; } + public static OmniSharp.Models.V2.Range FromRange(Range range) + { + return new OmniSharp.Models.V2.Range + { + Start = new OmniSharp.Models.V2.Point + { + Column = Convert.ToInt32(range.Start.Character), + Line = Convert.ToInt32(range.Start.Line), + }, + End = new OmniSharp.Models.V2.Point + { + Column = Convert.ToInt32(range.End.Character), + Line = Convert.ToInt32(range.End.Line), + }, + }; + } + public static DiagnosticSeverity ToDiagnosticSeverity(string logLevel) { // We stringify this value and pass to clients diff --git a/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs b/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs index 58d8b3e70c..536b83758d 100644 --- a/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs +++ b/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs @@ -166,6 +166,7 @@ private Task Initialize(Extensions.LanguageServer.Server.ILanguageServer server, .Concat(OmniSharpDocumentSymbolHandler.Enumerate(_handlers)) .Concat(OmniSharpReferencesHandler.Enumerate(_handlers)) .Concat(OmniSharpCodeLensHandler.Enumerate(_handlers)) + .Concat(OmniSharpCodeActionHandler.Enumerate(_handlers)) .Concat(OmniSharpDocumentFormattingHandler.Enumerate(_handlers)) .Concat(OmniSharpDocumentFormatRangeHandler.Enumerate(_handlers)) .Concat(OmniSharpDocumentOnTypeFormatHandler.Enumerate(_handlers))) From ce4e5d88d180282c2e0eeff47064f565a9c4cd87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Saulius=20Menkevic=CC=8Cius?= Date: Thu, 14 May 2020 08:48:01 +0300 Subject: [PATCH 2/2] Update changelog for the recent changes related to LSP support. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b28ef23c6..d9e5a0f29b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All changes to the project will be documented in this file. ## [1.35.2] - not yet released +* Added LSP handler for `textDocument/codeAction` request. (PR: [#1795](https://github.com/OmniSharp/omnisharp-roslyn/pull/1795)) +* Updated LSP libraries to 0.14.2 which fixes problems with document synchronisation. (PR: [#1791](https://github.com/OmniSharp/omnisharp-roslyn/pull/1791)) * Added support for `WarningsAsErrors` in csproj files (PR: [#1779](https://github.com/OmniSharp/omnisharp-roslyn/pull/1779)) * Added support for `WarningsNotAsErrors` in csproj files ([#1681](https://github.com/OmniSharp/omnisharp-roslyn/issues/1681), PR: [#1784](https://github.com/OmniSharp/omnisharp-roslyn/pull/1784))