From 329599da5b7b6de30a77d323c1e842aadbe06e89 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Fri, 7 Apr 2023 22:55:31 -0700 Subject: [PATCH] Add the preliminary support for code lens --- README.md | 1 + autoload/lsp/capabilities.vim | 12 ++++++++++++ autoload/lsp/codeaction.vim | 8 ++++++-- autoload/lsp/codelens.vim | 32 ++++++++++++++++++++++++++++++++ autoload/lsp/lsp.vim | 11 +++++++++++ autoload/lsp/lspserver.vim | 35 +++++++++++++++++++++++++++++++++++ doc/lsp.txt | 7 +++++++ plugin/lsp.vim | 5 +++-- 8 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 autoload/lsp/codelens.vim diff --git a/README.md b/README.md index ebb1726..73d382e 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ The following commands are provided to use the LSP features. Command|Description -------|----------- :LspCodeAction|Apply the code action supplied by the language server to the diagnostic in the current line. +:LspCodeLens|Display a list of code lens commands and apply a selected code lens command to the current file. :LspDiagCurrent|Display the diagnostic message for the current line. :LspDiagFirst|Jump to the first diagnostic message for the current buffer. :LspDiagHere|Jump to the next diagnostic message in the current line. diff --git a/autoload/lsp/capabilities.vim b/autoload/lsp/capabilities.vim index 5fdb1dd..9aefc53 100644 --- a/autoload/lsp/capabilities.vim +++ b/autoload/lsp/capabilities.vim @@ -170,6 +170,18 @@ export def ProcessServerCaps(lspserver: dict, caps: dict) lspserver.isCodeActionProvider = false endif + # codeLensProvider + if lspserver.caps->has_key('codeLensProvider') + lspserver.isCodeLensProvider = true + if lspserver.caps.codeLensProvider->has_key('resolveProvider') + lspserver.isCodeLensResolveProvider = true + else + lspserver.isCodeLensResolveProvider = false + endif + else + lspserver.isCodeLensProvider = false + endif + # workspaceSymbolProvider if lspserver.caps->has_key('workspaceSymbolProvider') if lspserver.caps.workspaceSymbolProvider->type() == v:t_bool diff --git a/autoload/lsp/codeaction.vim b/autoload/lsp/codeaction.vim index 0855767..81a146f 100644 --- a/autoload/lsp/codeaction.vim +++ b/autoload/lsp/codeaction.vim @@ -12,10 +12,14 @@ export def RegisterCmdHandler(cmd: string, Handler: func) CommandHandlers[cmd] = Handler enddef -def DoCommand(lspserver: dict, cmd: dict) +export def DoCommand(lspserver: dict, cmd: dict) if cmd->has_key('command') && CommandHandlers->has_key(cmd.command) var CmdHandler: func = CommandHandlers[cmd.command] - call CmdHandler(cmd) + try + call CmdHandler(cmd) + catch + util.ErrMsg($'Error: "{cmd.command}" handler raised exception {v:exception}') + endtry else lspserver.executeCommand(cmd) endif diff --git a/autoload/lsp/codelens.vim b/autoload/lsp/codelens.vim new file mode 100644 index 0000000..2571665 --- /dev/null +++ b/autoload/lsp/codelens.vim @@ -0,0 +1,32 @@ +vim9script + +import './codeaction.vim' + +# Functions related to handling LSP code lens + +export def ProcessCodeLens(lspserver: dict, codeLensItems: list>) + var text: list = [] + for i in codeLensItems->len()->range() + var item = codeLensItems[i] + if !item->has_key('command') + # resolve the code lens + item = lspserver.resolveCodeLens(item) + if item->empty() + continue + endif + codeLensItems[i] = item + endif + text->add(printf("%d. %s\t| L%s:%s", i + 1, item.command.title, + item.range.start.line + 1, + getline(item.range.start.line + 1))) + endfor + + var choice = inputlist(['Code Lens:'] + text) + if choice < 1 || choice > codeLensItems->len() + return + endif + + codeaction.DoCommand(lspserver, codeLensItems[choice - 1].command) +enddef + +# vim: tabstop=8 shiftwidth=2 softtabstop=2 diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index 020c07a..7b85dec 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -795,6 +795,17 @@ export def CodeAction(line1: number, line2: number, query: string) lspserver.codeAction(fname, line1, line2, query) enddef +# Code lens +# Uses LSP "textDocument/codeLens" request +export def CodeLens() + var lspserver: dict = buf.CurbufGetServerChecked() + if lspserver->empty() + return + endif + + lspserver.codeLens(@%) +enddef + # Perform a workspace wide symbol lookup # Uses LSP "workspace/symbol" request export def SymbolSearch(queryArg: string) diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index dbaacea..8f8ba89 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -20,6 +20,7 @@ import './completion.vim' import './hover.vim' import './signature.vim' import './codeaction.vim' +import './codelens.vim' import './callhierarchy.vim' as callhier import './typehierarchy.vim' as typehier import './inlayhints.vim' @@ -1165,6 +1166,38 @@ def CodeAction(lspserver: dict, fname_arg: string, line1: number, codeaction.ApplyCodeAction(lspserver, reply.result, query) enddef +# Request: "textDocument/codeLens" +# Param: CodeLensParams +def CodeLens(lspserver: dict, fname: string) + # Check whether LSP server supports code lens operation + if !lspserver.isCodeLensProvider + util.ErrMsg('Error: LSP server does not support code lens operation') + return + endif + + var params = {textDocument: {uri: util.LspFileToUri(fname)}} + var reply = lspserver.rpc('textDocument/codeLens', params) + if reply->empty() || reply.result->empty() + util.WarnMsg($'Error: No code lens actions found for the current file') + return + endif + + codelens.ProcessCodeLens(lspserver, reply.result) +enddef + +# Request: "codeLens/resolve" +# Param: CodeLens +def ResolveCodeLens(lspserver: dict, codeLens: dict): dict + if !lspserver.isCodeLensResolveProvider + return {} + endif + var reply = lspserver.rpc('codeLens/resolve', codeLens) + if reply->empty() + return {} + endif + return reply.result +enddef + # List project-wide symbols matching query string # Request: "workspace/symbol" # Param: WorkspaceSymbolParams @@ -1485,6 +1518,8 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list, typeHierarchy: function(TypeHiearchy, [lspserver]), renameSymbol: function(RenameSymbol, [lspserver]), codeAction: function(CodeAction, [lspserver]), + codeLens: function(CodeLens, [lspserver]), + resolveCodeLens: function(ResolveCodeLens, [lspserver]), workspaceQuery: function(WorkspaceQuerySymbols, [lspserver]), addWorkspaceFolder: function(AddWorkspaceFolder, [lspserver]), removeWorkspaceFolder: function(RemoveWorkspaceFolder, [lspserver]), diff --git a/doc/lsp.txt b/doc/lsp.txt index 1aa9086..8f40636 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -70,6 +70,8 @@ The following commands are provided: :LspCodeAction Apply the code action supplied by the language server to the diagnostic in the current line. +:LspCodeLens Display all the code lens commands available for the + current file and apply the selected command. :LspDiagCurrent Display the diagnostic message for the current line. :LspDiagFirst Jump to the first diagnostic message for the current buffer. @@ -477,6 +479,11 @@ can map these commands to keys and make it easier to invoke them. When [query] is not given you will be prompted to select one of the actions supplied by the language server. + *:LspCodeLens* +:LspCodeLens Display a list of code lens commands available for the + current buffer and apply the selected code lens + command. + *:LspDiagCurrent* :LspDiagCurrent Displays the diagnostic message (if any) for the current line. If the option 'showDiagInPopup' is set diff --git a/plugin/lsp.vim b/plugin/lsp.vim index 043f75c..46ab79d 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -78,6 +78,7 @@ augroup END # LSP commands command! -nargs=? -bar -range LspCodeAction lsp.CodeAction(, , ) +command! -nargs=0 -bar LspCodeLens lsp.CodeLens() command! -nargs=0 -bar -bang LspDiagCurrent lsp.LspShowCurrentDiag(false) command! -nargs=0 -bar LspDiagFirst lsp.JumpToDiag('first') command! -nargs=0 -bar LspDiagHighlightDisable lsp.DiagHighlightDisable() @@ -115,10 +116,10 @@ command! -nargs=0 -bar LspShowServerCapabilities lsp.ShowServerCapabilities() command! -nargs=0 -bar LspShowServer lsp.ShowServer() command! -nargs=0 -bar LspShowAllServers lsp.ShowAllServers() command! -nargs=0 -bar LspShowSignature call LspShowSignature() -# Clangd specifc extension to switch from one C/C++ source file to a -# corresponding header file command! -nargs=0 -bar LspSubTypeHierarchy lsp.TypeHierarchy(0) command! -nargs=0 -bar LspSuperTypeHierarchy lsp.TypeHierarchy(1) +# Clangd specifc extension to switch from one C/C++ source file to a +# corresponding header file command! -nargs=0 -bar LspSwitchSourceHeader lsp.SwitchSourceHeader() command! -nargs=? -bar LspSymbolSearch lsp.SymbolSearch() command! -nargs=1 -bar -complete=dir LspWorkspaceAddFolder lsp.AddWorkspaceFolder() -- 2.48.1