From: Yegappan Lakshmanan Date: Wed, 26 Oct 2022 15:35:26 +0000 (-0700) Subject: Add a function to use with the 'tagfunc' option to jump to a symbol definition X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=a7cf8ae5ec23256b2a73510916366ae73b5be025;p=vim-lsp.git Add a function to use with the 'tagfunc' option to jump to a symbol definition --- diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index 5d5d6dc..d7b3cd2 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -201,7 +201,7 @@ enddef # display in a balloon var lspDiagPopupID: number = 0 var lspDiagPopupInfo: dict = {} -def g:LspDiagExpr(): string +def g:LspDiagExpr(): any var lspserver: dict = buf.BufLspServerGet(v:beval_bufnr) if lspserver->empty() || !lspserver.running return '' @@ -209,10 +209,8 @@ def g:LspDiagExpr(): string # Display the diagnostic message only if the mouse is over the gutter for # the signs. - if opt.lspOptions.noDiagHoverOnLine - if v:beval_col >= 2 - return '' - endif + if opt.lspOptions.noDiagHoverOnLine && v:beval_col >= 2 + return '' endif var diagInfo: dict = lspserver.getDiagByLine(v:beval_bufnr, @@ -222,7 +220,7 @@ def g:LspDiagExpr(): string return '' endif - return diagInfo.message + return diagInfo.message->split("\n") enddef # Called after leaving insert mode. Used to process diag messages (if any) @@ -924,4 +922,14 @@ export def ShowServerCapabilities() lspserver.showCapabilities() enddef +# Function to use with the 'tagfunc' option. +export def TagFunc(pat: string, flags: string, info: dict): any + var lspserver: dict = CurbufGetServerChecked() + if lspserver->empty() + return v:null + endif + + return lspserver.tagFunc(pat, flags, info) +enddef + # vim: shiftwidth=2 softtabstop=2 diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index b562a2e..f53ab3c 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -1114,6 +1114,35 @@ def ShowCapabilities(lspserver: dict) endfor enddef +# Send a 'textDocument/definition' request to the LSP server to get the +# location where the symbol under the cursor is defined and return a list of +# Dicts in a format accepted by the 'tagfunc' option. +# Returns null if the LSP server doesn't support getting the location of a +# symbol definition or the symbol is not defined. +def TagFunc(lspserver: dict, pat: string, flags: string, info: dict): any + # Check whether LSP server supports getting the location of a definition + if !lspserver.caps->has_key('definitionProvider') + || !lspserver.caps.definitionProvider + return null + endif + + # interface DefinitionParams + # interface TextDocumentPositionParams + var reply = lspserver.rpc('textDocument/definition', GetLspTextDocPosition()) + if reply->empty() || reply.result->empty() + return null + endif + + var taglocations: list> + if reply.result->type() == v:t_list + taglocations = reply.result + else + taglocations = [reply.result] + endif + + return symbol.TagFunc(lspserver, taglocations, pat) +enddef + export def NewLspServer(path: string, args: list, isSync: bool, initializationOptions: dict): dict var lspserver: dict = { path: path, @@ -1164,10 +1193,11 @@ export def NewLspServer(path: string, args: list, isSync: bool, initiali getCompletion: function(GetCompletion, [lspserver]), resolveCompletion: function(ResolveCompletion, [lspserver]), gotoDefinition: function(GotoDefinition, [lspserver]), - switchSourceHeader: function(SwitchSourceHeader, [lspserver]), gotoDeclaration: function(GotoDeclaration, [lspserver]), gotoTypeDef: function(GotoTypeDef, [lspserver]), gotoImplementation: function(GotoImplementation, [lspserver]), + tagFunc: function(TagFunc, [lspserver]), + switchSourceHeader: function(SwitchSourceHeader, [lspserver]), showSignature: function(ShowSignature, [lspserver]), didSaveFile: function(DidSaveFile, [lspserver]), hover: function(ShowHoverInfo, [lspserver]), diff --git a/autoload/lsp/symbol.vim b/autoload/lsp/symbol.vim index ae293dc..9177b00 100644 --- a/autoload/lsp/symbol.vim +++ b/autoload/lsp/symbol.vim @@ -323,4 +323,22 @@ export def GotoSymbol(lspserver: dict, location: dict, peekSymbol: boo redraw! enddef +# Process the LSP server reply message for a 'textDocument/definition' request +# and return a list of Dicts in a format accepted by the 'tagfunc' option. +export def TagFunc(lspserver: dict, + taglocations: list>, + pat: string): list> + var retval: list> + + for tagloc in taglocations + var tagitem = {} + tagitem.name = pat + tagitem.filename = util.LspUriToFile(tagloc.uri) + tagitem.cmd = (tagloc.range.start.line + 1)->string() + retval->add(tagitem) + endfor + + return retval +enddef + # vim: shiftwidth=2 softtabstop=2 diff --git a/doc/lsp.txt b/doc/lsp.txt index 751c77a..78874bc 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -678,7 +678,23 @@ message area instead, you can set the 'showDiagInPopup' option to false. By default this is set to true. ============================================================================== -8. Autocommands *lsp-autocmds* +8. Tag Function + +The |:LspGotoDefinition| command can be used jump to the location where a +symbol is defined. To jump to the symbol definition using the Vim +|tag-commands|, you can set the 'tagfunc' option to the 'lsp#lsp#TagFunc' +function: > + + setlocal tagfunc=lsp#lsp#TagFunc +< +After setting the above option, you can use |Ctrl-]| and other tag related +commands to jump to the symbol definition. + +Note that most of the language servers return only one symbol location even if +the symbol is defined in multiple places in the code. + +============================================================================== +9. Autocommands *lsp-autocmds* *LspAttached* LspAttached A |User| autocommand fired when the LSP client diff --git a/test/unit_tests.vim b/test/unit_tests.vim index 73f103e..5185de4 100644 --- a/test/unit_tests.vim +++ b/test/unit_tests.vim @@ -272,6 +272,7 @@ def Test_LspDiag() assert_equal([5, 2, 'W'], [qfl[1].lnum, qfl[1].col, qfl[1].type]) assert_equal([7, 2, 'W'], [qfl[2].lnum, qfl[2].col, qfl[2].type]) close + g:LspOptionsSet({showDiagInPopup: false}) normal gg var output = execute('LspDiagCurrent')->split("\n") assert_equal('No diagnostic messages found for current line', output[0]) @@ -295,6 +296,7 @@ def Test_LspDiag() WaitForDiags(0) output = execute('LspDiagShow')->split("\n") assert_match('No diagnostic messages found for', output[0]) + g:LspOptionsSet({showDiagInPopup: true}) :%bw! enddef @@ -780,6 +782,38 @@ def Test_LspOutline() :%bw! enddef +# Test for setting the 'tagfunc' +def Test_LspTagFunc() + var lines: list =<< trim END + void aFunc(void) + { + xFunc(); + } + + void bFunc(void) + { + xFunc(); + } + + void xFunc(void) + { + } + END + writefile(lines, 'Xtest.c') + :silent! edit Xtest.c + :sleep 1 + :setlocal tagfunc=lsp#lsp#TagFunc + cursor(3, 4) + :exe "normal \" + assert_equal([11, 1], [line('.'), col('.')]) + cursor(1, 1) + assert_fails('exe "normal \"', 'E433: No tags file') + + :set tagfunc& + :%bw! + delete('Xtest.c') +enddef + def LspRunTests() :set nomore :set debug=beep