diff --git a/CHANGELOG.md b/CHANGELOG.md index fc31a9e1b4..44388994e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ All changes to the project will be documented in this file. ## [1.35.4] - Not yet released +* Added LSP handler for the `workspace/symbol` request. (PR: [#1799](https://github.com/OmniSharp/omnisharp-roslyn/pull/1799)) ## [1.35.3] - 2020-06-11 * Added LSP handler for `textDocument/codeAction` request. (PR: [#1795](https://github.com/OmniSharp/omnisharp-roslyn/pull/1795)) diff --git a/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpDocumentSymbolHandler.cs b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpDocumentSymbolHandler.cs index 73af1e33fb..fc7412aa01 100644 --- a/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpDocumentSymbolHandler.cs +++ b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpDocumentSymbolHandler.cs @@ -24,26 +24,6 @@ public static IEnumerable Enumerate(RequestHandlers handlers) private readonly Mef.IRequestHandler _codeStructureHandler; - private static readonly IDictionary Kinds = new Dictionary - { - { OmniSharp.Models.V2.SymbolKinds.Class, SymbolKind.Class }, - { OmniSharp.Models.V2.SymbolKinds.Delegate, SymbolKind.Class }, - { OmniSharp.Models.V2.SymbolKinds.Enum, SymbolKind.Enum }, - { OmniSharp.Models.V2.SymbolKinds.Interface, SymbolKind.Interface }, - { OmniSharp.Models.V2.SymbolKinds.Struct, SymbolKind.Struct }, - { OmniSharp.Models.V2.SymbolKinds.Constant, SymbolKind.Constant }, - { OmniSharp.Models.V2.SymbolKinds.Destructor, SymbolKind.Method }, - { OmniSharp.Models.V2.SymbolKinds.EnumMember, SymbolKind.EnumMember }, - { OmniSharp.Models.V2.SymbolKinds.Event, SymbolKind.Event }, - { OmniSharp.Models.V2.SymbolKinds.Field, SymbolKind.Field }, - { OmniSharp.Models.V2.SymbolKinds.Indexer, SymbolKind.Property }, - { OmniSharp.Models.V2.SymbolKinds.Method, SymbolKind.Method }, - { OmniSharp.Models.V2.SymbolKinds.Operator, SymbolKind.Operator }, - { OmniSharp.Models.V2.SymbolKinds.Property, SymbolKind.Property }, - { OmniSharp.Models.V2.SymbolKinds.Namespace, SymbolKind.Namespace }, - { OmniSharp.Models.V2.SymbolKinds.Unknown, SymbolKind.Class }, - }; - public OmniSharpDocumentSymbolHandler(Mef.IRequestHandler codeStructureHandler, DocumentSelector documentSelector) : base(new TextDocumentRegistrationOptions() { @@ -76,7 +56,7 @@ private static DocumentSymbol ToDocumentSymbol(CodeElement node) return new DocumentSymbol { Name = node.Name, - Kind = Kinds.ContainsKey(node.Kind) ? Kinds[node.Kind] : SymbolKind.Class, + Kind = Helpers.ToSymbolKind(node.Kind), Range = Helpers.ToRange(node.Ranges[OmniSharp.Models.V2.SymbolRangeNames.Full]), SelectionRange = Helpers.ToRange(node.Ranges[OmniSharp.Models.V2.SymbolRangeNames.Name]), Children = new Container(node.Children?.Select(ToDocumentSymbol) ?? Enumerable.Empty()) diff --git a/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpWorkspaceSymbolsHandler.cs b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpWorkspaceSymbolsHandler.cs new file mode 100644 index 0000000000..891de2fc18 --- /dev/null +++ b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpWorkspaceSymbolsHandler.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using OmniSharp.Extensions.JsonRpc; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using OmniSharp.Extensions.LanguageServer.Protocol.Server; +using OmniSharp.Mef; +using OmniSharp.Models; +using OmniSharp.Models.FindSymbols; + +namespace OmniSharp.LanguageServerProtocol.Handlers +{ + internal sealed class OmniSharpWorkspaceSymbolsHandler : WorkspaceSymbolsHandler + { + private readonly IRequestHandler _FindSymbolsHandler; + + public static IEnumerable Enumerate(RequestHandlers handlers) + { + foreach (var (selector, findSymbolsHandler) in handlers + .OfType>()) + { + // + // TODO: remove the conditional when we upgrade to v0.16.0 of Omnisharp.Extensions.LSP + // + // we have no WorkspaceSymbolRegistrationOptions/DocumentSelector until version 0.16.0 of Omnisharp.Extensions.LSP + // thus we artificially limit the handler to C# language for now + // (as Cake version of would get selected otherwise) + // + if (selector.Any(f => f.Pattern == "**/*.cs")) + { + yield return new OmniSharpWorkspaceSymbolsHandler(findSymbolsHandler, selector); + } + } + } + + public OmniSharpWorkspaceSymbolsHandler( + IRequestHandler findSymbolsHandler, + DocumentSelector selector) + { + _FindSymbolsHandler = findSymbolsHandler; + } + + public async override Task + Handle(WorkspaceSymbolParams request, CancellationToken cancellationToken) + { + var omnisharpRequest = new FindSymbolsRequest { + Filter = request.Query, + MaxItemsToReturn = 100, + }; + + var omnisharpResponse = await _FindSymbolsHandler.Handle(omnisharpRequest); + + var symbols = omnisharpResponse.QuickFixes?.Cast().Select( + x => new SymbolInformation { + Name = x.Text, + Kind = Helpers.ToSymbolKind(x.Kind), + Location = new OmniSharp.Extensions.LanguageServer.Protocol.Models.Location { + Uri = Helpers.ToUri(x.FileName), + Range = Helpers.ToRange((x.Column, x.Line), (x.EndColumn, x.EndLine)) + } + }) + .ToArray(); + + return symbols ?? Array.Empty(); + } + } +} diff --git a/src/OmniSharp.LanguageServerProtocol/Helpers.cs b/src/OmniSharp.LanguageServerProtocol/Helpers.cs index 67b5118300..ce25f5ecd5 100644 --- a/src/OmniSharp.LanguageServerProtocol/Helpers.cs +++ b/src/OmniSharp.LanguageServerProtocol/Helpers.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text.RegularExpressions; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Models; @@ -143,5 +144,30 @@ public static string EscapeMarkdown(string markdown) return null; return Regex.Replace(markdown, @"([\\`\*_\{\}\[\]\(\)#+\-\.!])", @"\$1"); } + + private static readonly IDictionary Kinds = new Dictionary + { + { OmniSharp.Models.V2.SymbolKinds.Class, SymbolKind.Class }, + { OmniSharp.Models.V2.SymbolKinds.Delegate, SymbolKind.Class }, + { OmniSharp.Models.V2.SymbolKinds.Enum, SymbolKind.Enum }, + { OmniSharp.Models.V2.SymbolKinds.Interface, SymbolKind.Interface }, + { OmniSharp.Models.V2.SymbolKinds.Struct, SymbolKind.Struct }, + { OmniSharp.Models.V2.SymbolKinds.Constant, SymbolKind.Constant }, + { OmniSharp.Models.V2.SymbolKinds.Destructor, SymbolKind.Method }, + { OmniSharp.Models.V2.SymbolKinds.EnumMember, SymbolKind.EnumMember }, + { OmniSharp.Models.V2.SymbolKinds.Event, SymbolKind.Event }, + { OmniSharp.Models.V2.SymbolKinds.Field, SymbolKind.Field }, + { OmniSharp.Models.V2.SymbolKinds.Indexer, SymbolKind.Property }, + { OmniSharp.Models.V2.SymbolKinds.Method, SymbolKind.Method }, + { OmniSharp.Models.V2.SymbolKinds.Operator, SymbolKind.Operator }, + { OmniSharp.Models.V2.SymbolKinds.Property, SymbolKind.Property }, + { OmniSharp.Models.V2.SymbolKinds.Namespace, SymbolKind.Namespace }, + { OmniSharp.Models.V2.SymbolKinds.Unknown, SymbolKind.Class }, + }; + + public static SymbolKind ToSymbolKind(string omnisharpKind) + { + return Kinds.TryGetValue(omnisharpKind.ToLowerInvariant(), out var symbolKind) ? symbolKind : SymbolKind.Class; + } } } diff --git a/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs b/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs index 368867c1d0..2a9e1622cf 100644 --- a/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs +++ b/src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs @@ -163,6 +163,7 @@ private Task Initialize(Extensions.LanguageServer.Server.ILanguageServer server, .Concat(OmniSharpCompletionHandler.Enumerate(_handlers)) .Concat(OmniSharpSignatureHelpHandler.Enumerate(_handlers)) .Concat(OmniSharpRenameHandler.Enumerate(_handlers)) + .Concat(OmniSharpWorkspaceSymbolsHandler.Enumerate(_handlers)) .Concat(OmniSharpDocumentSymbolHandler.Enumerate(_handlers)) .Concat(OmniSharpReferencesHandler.Enumerate(_handlers)) .Concat(OmniSharpCodeLensHandler.Enumerate(_handlers))