From: Andreas Louv Date: Mon, 13 Mar 2023 23:15:07 +0000 (+0100) Subject: Scan for the closest identifier under the cursor when resolving cursor location X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=c24ec6f3ac0826e5a8cc04e41bac61e26dd75894;p=vim-lsp.git Scan for the closest identifier under the cursor when resolving cursor location This works somewhat like "CTRL-]" and "CTRL-R_CTRL-W". --- diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index f0397c8..28d9813 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -789,22 +789,39 @@ def TextdocDidChange(lspserver: dict, bnr: number, start: number, enddef # Return the current cursor position as a LSP position. +# find_ident will search for a identifier in front of the cursor, just like +# CTRL-] and c_CTRL-R_CTRL-W does. +# # LSP line and column numbers start from zero, whereas Vim line and column # numbers start from one. The LSP column number is the character index in the # line and not the byte index in the line. -def GetLspPosition(): dict +def GetLspPosition(find_ident: bool): dict var lnum: number = line('.') - 1 var col: number = charcol('.') - 1 + var line = getline('.') + + if find_ident + # 1. skip to start of identifier + while line[col] != '' && line[col] !~ '\k' + col = col + 1 + endwhile + + # 2. back up to start of identifier + while col > 0 && line[col - 1] =~ '\k' + col = col - 1 + endwhile + endif + return {line: lnum, character: col} enddef # Return the current file name and current cursor position as a LSP # TextDocumentPositionParams structure -def GetLspTextDocPosition(): dict> +def GetLspTextDocPosition(find_ident: bool): dict> # interface TextDocumentIdentifier # interface Position return {textDocument: {uri: util.LspFileToUri(@%)}, - position: GetLspPosition()} + position: GetLspPosition(find_ident)} enddef # Get a list of completion items. @@ -824,7 +841,7 @@ def GetCompletion(lspserver: dict, triggerKind_arg: number, triggerChar: st # interface CompletionParams # interface TextDocumentPositionParams - var params = GetLspTextDocPosition() + var params = GetLspTextDocPosition(false) # interface CompletionContext params.context = {triggerKind: triggerKind_arg, triggerCharacter: triggerChar} @@ -866,7 +883,7 @@ enddef # Result: Location | Location[] | LocationLink[] | null def GotoSymbolLoc(lspserver: dict, msg: string, peekSymbol: bool, cmdmods: string) - var reply = lspserver.rpc(msg, GetLspTextDocPosition()) + var reply = lspserver.rpc(msg, GetLspTextDocPosition(true)) if reply->empty() || reply.result->empty() var emsg: string if msg ==# 'textDocument/declaration' @@ -984,7 +1001,7 @@ def ShowSignature(lspserver: dict): void # interface SignatureHelpParams # interface TextDocumentPositionParams - var params = GetLspTextDocPosition() + var params = GetLspTextDocPosition(false) lspserver.rpc_a('textDocument/signatureHelp', params, signature.SignatureHelp) enddef @@ -1017,7 +1034,7 @@ def ShowHoverInfo(lspserver: dict): void # interface HoverParams # interface TextDocumentPositionParams - var params = GetLspTextDocPosition() + var params = GetLspTextDocPosition(false) lspserver.rpc_a('textDocument/hover', params, hover.HoverReply) enddef @@ -1033,7 +1050,7 @@ def ShowReferences(lspserver: dict, peek: bool): void # interface ReferenceParams # interface TextDocumentPositionParams var param: dict - param = GetLspTextDocPosition() + param = GetLspTextDocPosition(true) param.context = {includeDeclaration: true} var reply = lspserver.rpc('textDocument/references', param) @@ -1090,7 +1107,7 @@ def DocHighlight(lspserver: dict): void # interface DocumentHighlightParams # interface TextDocumentPositionParams - var params = GetLspTextDocPosition() + var params = GetLspTextDocPosition(false) lspserver.rpc_a('textDocument/documentHighlight', params, function('DocHighlightReply', [bufnr()])) enddef @@ -1176,7 +1193,7 @@ def PrepareCallHierarchy(lspserver: dict): dict # interface CallHierarchyPrepareParams # interface TextDocumentPositionParams var param: dict - param = GetLspTextDocPosition() + param = GetLspTextDocPosition(false) var reply = lspserver.rpc('textDocument/prepareCallHierarchy', param) if reply->empty() || reply.result->empty() return {} @@ -1287,7 +1304,7 @@ def TypeHiearchy(lspserver: dict, direction: number) # interface TypeHierarchy # interface TextDocumentPositionParams var param: dict - param = GetLspTextDocPosition() + param = GetLspTextDocPosition(false) # 0: children, 1: parent, 2: both param.direction = direction param.resolve = 5 @@ -1312,7 +1329,7 @@ def RenameSymbol(lspserver: dict, newName: string) # interface RenameParams # interface TextDocumentPositionParams var param: dict = {} - param = GetLspTextDocPosition() + param = GetLspTextDocPosition(true) param.newName = newName var reply = lspserver.rpc('textDocument/rename', param) @@ -1453,7 +1470,7 @@ def SelectionRange(lspserver: dict, fname: string) var param = {} param.textDocument = {} param.textDocument.uri = util.LspFileToUri(fname) - param.positions = [GetLspPosition()] + param.positions = [GetLspPosition(false)] var reply = lspserver.rpc('textDocument/selectionRange', param) if reply->empty() || reply.result->empty() @@ -1578,7 +1595,7 @@ def TagFunc(lspserver: dict, pat: string, flags: string, info: dict): # interface DefinitionParams # interface TextDocumentPositionParams - var reply = lspserver.rpc('textDocument/definition', GetLspTextDocPosition()) + var reply = lspserver.rpc('textDocument/definition', GetLspTextDocPosition(false)) if reply->empty() || reply.result->empty() return null endif diff --git a/test/unit_tests.vim b/test/unit_tests.vim index cbdf008..d3d0d45 100644 --- a/test/unit_tests.vim +++ b/test/unit_tests.vim @@ -979,6 +979,47 @@ def Test_LspCustomNotificationHandlers() :%bw! enddef +def Test_ScanFindIdent() + :silent! edit Xtest.c + sleep 200m + var lines: list =<< trim END + int count; + int fn(int a) + { + int hello; + hello = a; + return count + 1; + } + END + setline(1, lines) + :redraw! + + # LspGotoDefinition et al + cursor(5, 10) + assert_equal([], + execute('LspGotoDefinition')->split("\n")) + assert_equal([2, 12], [line('.'), col('.')]) + + cursor(6, 10) + assert_equal([], + execute('LspGotoDefinition')->split("\n")) + assert_equal([1, 5], [line('.'), col('.')]) + + # LspShowReferences + cursor(6, 10) + assert_equal([], + execute('LspShowReferences')->split("\n")) + + # LspRename + cursor(6, 10) + assert_equal([], + execute('LspRename counter')->split("\n")) + assert_equal('int counter;', getline(1)) + assert_equal(' return counter + 1;', getline(6)) + + bw! +enddef + # Start the C language server. Returns true on success and false on failure. def StartLangServer(): bool # Edit a dummy C file to start the LSP server