.github/workflows/unitests.yml | 2 +- autoload/lsp/handlers.vim | 60 ----------------------------------------------------- autoload/lsp/lsp.vim | 27 ++------------------------- autoload/lsp/lspserver.vim | 87 +++++++++++++++++++++++++++++++++-------------------- test/unit_tests.vim | 34 +++++++++++++++++++++++++++++++++- diff --git a/.github/workflows/unitests.yml b/.github/workflows/unitests.yml index 1009b0a2a11f0b6e99ac0d689d886dfedc8ac5d6..eea4ac27859d55477faa48a4239e4bc21819cda3 100644 --- a/.github/workflows/unitests.yml +++ b/.github/workflows/unitests.yml @@ -7,7 +7,7 @@ runs-on: ubuntu-latest steps: - name: Install packages run: | - sudo apt update && sudo apt install -y clangd-12 + sudo apt update && sudo apt install -y clangd-14 - name: Setup Vim uses: rhysd/action-setup-vim@v1 id: vim diff --git a/autoload/lsp/handlers.vim b/autoload/lsp/handlers.vim index 5f808a5aa0183ebccc763c10d0f6ea3d6731f66f..bdb2a5be55305a954a0e5ab957d44258d1d5aa7d 100644 --- a/autoload/lsp/handlers.vim +++ b/autoload/lsp/handlers.vim @@ -55,11 +55,6 @@ lspserver.getDocSymbols(@%) endif enddef -# Process a 'shutdown' reply from the LSP server. -def ProcessShutdownReply(lspserver: dict, req: dict, reply: dict): void - return -enddef - # process the 'textDocument/signatureHelp' reply from the LSP server # Result: SignatureHelp | null def ProcessSignaturehelpReply(lspserver: dict, req: dict, reply: dict): void @@ -505,63 +500,11 @@ lspserver.workspaceSymbolPopup->popup_settext( symbols->copy()->mapnew('v:val.name')) enddef -# process the 'textDocument/prepareCallHierarchy' reply from the LSP server -# Result: CallHierarchyItem[] | null -def ProcessPrepareCallHierarchy(lspserver: dict, req: dict, reply: dict) - if reply.result->empty() - if lspserver.callHierarchyType == 'incoming' - util.WarnMsg('No incoming calls') - else - util.WarnMsg('No outgoing calls') - endif - return - endif - - var choice: number = 1 - if reply.result->len() > 1 - var items: list = ['Select a Call Hierarchy Item:'] - for i in range(reply.result->len()) - items->add(printf("%d. %s", i + 1, reply.result[i].name)) - endfor - choice = inputlist(items) - if choice < 1 || choice > items->len() - return - endif - endif - - if lspserver.callHierarchyType == 'incoming' - g:LspGetIncomingCalls(reply.result[choice - 1]) - else - g:LspGetOutgoingCalls(reply.result[choice - 1]) - endif -enddef - -# process the 'callHierarchy/incomingCalls' reply from the LSP server -# Result: CallHierarchyIncomingCall[] | null -def ProcessIncomingCalls(lspserver: dict, req: dict, reply: dict) - if reply.result->empty() - return - endif - - callhier.IncomingCalls(reply.result) -enddef - -# process the 'callHierarchy/outgoingCalls' reply from the LSP server -# Result: CallHierarchyOutgoingCall[] | null -def ProcessOutgoingCalls(lspserver: dict, req: dict, reply: dict) - if reply.result->empty() - return - endif - - callhier.OutgoingCalls(reply.result) -enddef - # Process various reply messages from the LSP server export def ProcessReply(lspserver: dict, req: dict, reply: dict): void var lsp_reply_handlers: dict = { 'initialize': ProcessInitializeReply, - 'shutdown': ProcessShutdownReply, 'textDocument/signatureHelp': ProcessSignaturehelpReply, 'textDocument/completion': ProcessCompletionReply, 'textDocument/hover': ProcessHoverReply, @@ -571,9 +514,6 @@ 'textDocument/codeAction': ProcessCodeActionReply, 'textDocument/foldingRange': ProcessFoldingRangeReply, 'workspace/executeCommand': ProcessWorkspaceExecuteReply, 'workspace/symbol': ProcessWorkspaceSymbolReply, - 'textDocument/prepareCallHierarchy': ProcessPrepareCallHierarchy, - 'callHierarchy/incomingCalls': ProcessIncomingCalls, - 'callHierarchy/outgoingCalls': ProcessOutgoingCalls } if lsp_reply_handlers->has_key(req.method) diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index d1e1c0d7329871a77368d5439ffa0eb80302b9a9..199a915711160574143f72e8846936937c4928fd 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -701,30 +701,9 @@ if lspserver->empty() return endif - lspserver.callHierarchyType = 'incoming' - var fname: string = @% - lspserver.prepareCallHierarchy(fname) -enddef - -def g:LspGetIncomingCalls(item: dict) - var lspserver: dict = CurbufGetServerChecked() - if lspserver->empty() - return - endif - - lspserver.incomingCalls(item) + lspserver.incomingCalls(@%) enddef -def g:LspGetOutgoingCalls(item: dict) - var lspserver: dict = CurbufGetServerChecked() - if lspserver->empty() - return - endif - - lspserver.outgoingCalls(item) -enddef - - # Display all the symbols used by the current symbol. # Uses LSP "callHierarchy/outgoingCalls" request export def OutgoingCalls() @@ -733,9 +712,7 @@ if lspserver->empty() return endif - lspserver.callHierarchyType = 'outgoing' - var fname: string = @% - lspserver.prepareCallHierarchy(fname) + lspserver.outgoingCalls(@%) enddef # Rename a symbol diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index 8d9dc8e61f8b4ba3256768f018a683829ff8f9f0..82a9e7f056b3d9f876fd4cc9d3f0c49a8710d05e 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -10,6 +10,7 @@ import './diag.vim' import './selection.vim' import './symbol.vim' import './textedit.vim' +import './callhierarchy.vim' as callhier # LSP server standard output handler def Output_cb(lspserver: dict, chan: channel, msg: any): void @@ -769,26 +770,34 @@ save_cursor->setpos('.') enddef # Request: "textDocument/prepareCallHierarchy" -# Param: CallHierarchyPrepareParams -def PrepareCallHierarchy(lspserver: dict, fname: string) - # Check whether LSP server supports call hierarchy - if !lspserver.caps->has_key('callHierarchyProvider') - || !lspserver.caps.callHierarchyProvider - util.ErrMsg("Error: LSP server does not support call hierarchy") - return +def PrepareCallHierarchy(lspserver: dict): dict + # interface CallHierarchyPrepareParams + # interface TextDocumentPositionParams + var param: dict + param = GetLspTextDocPosition() + var reply = lspserver.rpc('textDocument/prepareCallHierarchy', param) + if reply->empty() || reply.result->empty() + return {} endif - var req = lspserver.createRequest('textDocument/prepareCallHierarchy') + # Result: CallHierarchyItem[] | null + var choice: number = 1 + if reply.result->len() > 1 + var items: list = ['Select a Call Hierarchy Item:'] + for i in range(reply.result->len()) + items->add(printf("%d. %s", i + 1, reply.result[i].name)) + endfor + choice = inputlist(items) + if choice < 1 || choice > items->len() + return {} + endif + endif - # interface CallHierarchyPrepareParams - # interface TextDocumentPositionParams - req.params->extend(GetLspTextDocPosition()) - lspserver.sendMessage(req) + return reply.result[choice - 1] enddef # Request: "callHierarchy/incomingCalls" -# Param: CallHierarchyItem -def IncomingCalls(lspserver: dict, hierItem: dict) +def IncomingCalls(lspserver: dict, fname: string) # Check whether LSP server supports call hierarchy if !lspserver.caps->has_key('callHierarchyProvider') || !lspserver.caps.callHierarchyProvider @@ -796,21 +805,27 @@ util.ErrMsg("Error: LSP server does not support call hierarchy") return endif - var req = lspserver.createRequest('callHierarchy/incomingCalls') + var reply = PrepareCallHierarchy(lspserver) + if reply->empty() + util.WarnMsg('No incoming calls') + return + endif - # interface CallHierarchyIncomingCallsParams - # interface CallHierarchyItem - req.params->extend({item: hierItem}) - lspserver.sendMessage(req) - if exists('g:LSPTest') && g:LSPTest - # When running LSP tests, make this a synchronous call - lspserver.waitForResponse(req) + # Request: "callHierarchy/incomingCalls" + # Param: CallHierarchyIncomingCallsParams + var param = {} + param.item = reply + reply = lspserver.rpc('callHierarchy/incomingCalls', param) + if reply->empty() || reply.result->empty() + util.WarnMsg('No incoming calls') + return endif + + callhier.IncomingCalls(reply.result) enddef # Request: "callHierarchy/outgoingCalls" -# Param: CallHierarchyItem -def OutgoingCalls(lspserver: dict, hierItem: dict) +def OutgoingCalls(lspserver: dict, fname: string) # Check whether LSP server supports call hierarchy if !lspserver.caps->has_key('callHierarchyProvider') || !lspserver.caps.callHierarchyProvider @@ -818,16 +833,23 @@ util.ErrMsg("Error: LSP server does not support call hierarchy") return endif - var req = lspserver.createRequest('callHierarchy/outgoingCalls') + var reply = PrepareCallHierarchy(lspserver) + if reply->empty() + util.WarnMsg('No outgoing calls') + return + endif - # interface CallHierarchyOutgoingCallsParams - # interface CallHierarchyItem - req.params->extend({item: hierItem}) - lspserver.sendMessage(req) - if exists('g:LSPTest') && g:LSPTest - # When running LSP tests, make this a synchronous call - lspserver.waitForResponse(req) + # Request: "callHierarchy/outgoingCalls" + # Param: CallHierarchyOutgoingCallsParams + var param = {} + param.item = reply + reply = lspserver.rpc('callHierarchy/outgoingCalls', param) + if reply->empty() || reply.result->empty() + util.WarnMsg('No outgoing calls') + return endif + + callhier.OutgoingCalls(reply.result) enddef # Request: "textDocument/rename" @@ -1120,7 +1142,6 @@ showReferences: function(ShowReferences, [lspserver]), docHighlight: function(DocHighlight, [lspserver]), getDocSymbols: function(GetDocSymbols, [lspserver]), textDocFormat: function(TextDocFormat, [lspserver]), - prepareCallHierarchy: function(PrepareCallHierarchy, [lspserver]), incomingCalls: function(IncomingCalls, [lspserver]), outgoingCalls: function(OutgoingCalls, [lspserver]), renameSymbol: function(RenameSymbol, [lspserver]), diff --git a/test/unit_tests.vim b/test/unit_tests.vim index cf5fb7735ec0383885ab2b3b336b178360a6c5e4..5489dfc71e054433e2059ee79d6079fe58d78db8 100644 --- a/test/unit_tests.vim +++ b/test/unit_tests.vim @@ -21,7 +21,7 @@ source ../plugin/lsp.vim var lspServers = [{ filetype: ['c', 'cpp'], - path: '/usr/bin/clangd-12', + path: '/usr/bin/clangd-14', args: ['--background-index', '--clang-tidy'] }] call LspAddServer(lspServers) @@ -669,6 +669,38 @@ expected = {id: 0, col: 15, end: 1, type: 'signature', length: 5, start: 1} expected.type_bufnr = bnr assert_equal([expected], prop_list(1, {bufnr: bnr})) popup_close(p[0]) + :%bw! +enddef + +# Test for :LspIncomingCalls +def Test_LspIncomingCalls() + silent! edit Xtest.c + sleep 200m + var lines: list =<< trim END + void xFunc(void) + { + } + + void aFunc(void) + { + xFunc(); + } + + void bFunc(void) + { + xFunc(); + } + END + setline(1, lines) + :sleep 1 + cursor(1, 6) + :LspIncomingCalls + assert_equal(2, winnr('$')) + var l = getloclist(0) + assert_equal([7, 3], [l[0].lnum, l[0].col]) + assert_equal('aFunc: xFunc();', l[0].text) + assert_equal([12, 3], [l[1].lnum, l[1].col]) + assert_equal('bFunc: xFunc();', l[1].text) :%bw! enddef