enddef
# Go to a definition using "textDocument/definition" LSP request
-export def GotoDefinition(peek: bool)
+export def GotoDefinition(peek: bool, cmdmods: string)
var lspserver: dict<any> = CurbufGetServerChecked()
if lspserver->empty()
return
endif
- lspserver.gotoDefinition(peek)
+ lspserver.gotoDefinition(peek, cmdmods)
enddef
-# Switch source header using "textDocument/switchSourceHeader" LSP request
-# (Clangd specifc extension)
-export def SwitchSourceHeader()
+# Go to a declaration using "textDocument/declaration" LSP request
+export def GotoDeclaration(peek: bool, cmdmods: string)
var lspserver: dict<any> = CurbufGetServerChecked()
if lspserver->empty()
return
endif
- lspserver.switchSourceHeader()
+ lspserver.gotoDeclaration(peek, cmdmods)
enddef
-# Go to a declaration using "textDocument/declaration" LSP request
-export def GotoDeclaration(peek: bool)
+# Go to a type definition using "textDocument/typeDefinition" LSP request
+export def GotoTypedef(peek: bool, cmdmods: string)
var lspserver: dict<any> = CurbufGetServerChecked()
if lspserver->empty()
return
endif
- lspserver.gotoDeclaration(peek)
+ lspserver.gotoTypeDef(peek, cmdmods)
enddef
-# Go to a type definition using "textDocument/typeDefinition" LSP request
-export def GotoTypedef(peek: bool)
+# Go to a implementation using "textDocument/implementation" LSP request
+export def GotoImplementation(peek: bool, cmdmods: string)
var lspserver: dict<any> = CurbufGetServerChecked()
if lspserver->empty()
return
endif
- lspserver.gotoTypeDef(peek)
+ lspserver.gotoImplementation(peek, cmdmods)
enddef
-# Go to a implementation using "textDocument/implementation" LSP request
-export def GotoImplementation(peek: bool)
+# Switch source header using "textDocument/switchSourceHeader" LSP request
+# (Clangd specifc extension)
+export def SwitchSourceHeader()
var lspserver: dict<any> = CurbufGetServerChecked()
if lspserver->empty()
return
endif
- lspserver.gotoImplementation(peek)
+ lspserver.switchSourceHeader()
enddef
# Show the signature using "textDocument/signatureHelp" LSP method
# window but don't jump to the symbol location.
#
# Result: Location | Location[] | LocationLink[] | null
-def GotoSymbolLoc(lspserver: dict<any>, msg: string, peekSymbol: bool)
+def GotoSymbolLoc(lspserver: dict<any>, msg: string, peekSymbol: bool,
+ cmdmods: string)
var reply = lspserver.rpc(msg, GetLspTextDocPosition())
if reply->empty() || reply.result->empty()
var emsg: string
return
endif
- if !peekSymbol
- util.PushCursorToTagStack()
- endif
-
var location: dict<any>
if reply.result->type() == v:t_list
location = reply.result[0]
location = reply.result
endif
- symbol.GotoSymbol(lspserver, location, peekSymbol)
+ symbol.GotoSymbol(lspserver, location, peekSymbol, cmdmods)
enddef
# Request: "textDocument/definition"
# Param: DefinitionParams
-def GotoDefinition(lspserver: dict<any>, peek: bool)
+def GotoDefinition(lspserver: dict<any>, peek: bool, cmdmods: string)
# Check whether LSP server supports jumping to a definition
if !lspserver.caps->get('definitionProvider', false)
util.ErrMsg("Error: Jumping to a symbol definition is not supported")
# interface DefinitionParams
# interface TextDocumentPositionParams
- GotoSymbolLoc(lspserver, 'textDocument/definition', peek)
+ GotoSymbolLoc(lspserver, 'textDocument/definition', peek, cmdmods)
enddef
# Request: "textDocument/declaration"
# Param: DeclarationParams
-def GotoDeclaration(lspserver: dict<any>, peek: bool): void
+def GotoDeclaration(lspserver: dict<any>, peek: bool, cmdmods: string)
# Check whether LSP server supports jumping to a declaration
if !lspserver.caps->get('declarationProvider', false)
util.ErrMsg("Error: Jumping to a symbol declaration is not supported")
# interface DeclarationParams
# interface TextDocumentPositionParams
- GotoSymbolLoc(lspserver, 'textDocument/declaration', peek)
+ GotoSymbolLoc(lspserver, 'textDocument/declaration', peek, cmdmods)
enddef
# Request: "textDocument/typeDefinition"
# Param: TypeDefinitionParams
-def GotoTypeDef(lspserver: dict<any>, peek: bool): void
+def GotoTypeDef(lspserver: dict<any>, peek: bool, cmdmods: string)
# Check whether LSP server supports jumping to a type definition
if !lspserver.caps->get('typeDefinitionProvider', false)
util.ErrMsg("Error: Jumping to a symbol type definition is not supported")
# interface TypeDefinitionParams
# interface TextDocumentPositionParams
- GotoSymbolLoc(lspserver, 'textDocument/typeDefinition', peek)
+ GotoSymbolLoc(lspserver, 'textDocument/typeDefinition', peek, cmdmods)
enddef
# Request: "textDocument/implementation"
# Param: ImplementationParams
-def GotoImplementation(lspserver: dict<any>, peek: bool): void
+def GotoImplementation(lspserver: dict<any>, peek: bool, cmdmods: string)
# Check whether LSP server supports jumping to a implementation
if !lspserver.caps->get('implementationProvider', false)
util.ErrMsg("Error: Jumping to a symbol implementation is not supported")
# interface ImplementationParams
# interface TextDocumentPositionParams
- GotoSymbolLoc(lspserver, 'textDocument/implementation', peek)
+ GotoSymbolLoc(lspserver, 'textDocument/implementation', peek, cmdmods)
enddef
# Request: "textDocument/switchSourceHeader"
endif
enddef
-# Jump to the definition, declaration or implementation of a symbol.
-# Also, used to peek at the definition, declaration or implementation of a
-# symbol.
-export def GotoSymbol(lspserver: dict<any>, location: dict<any>, peekSymbol: bool)
- var fname = util.LspUriToFile(location.uri)
- if peekSymbol
- # open the definition/declaration in the preview window and highlight the
- # matching symbol
+# Display the symbol in file 'fname' at 'location' in a popup window.
+def PeekSymbolLocation(lspserver: dict<any>, fname: string,
+ location: dict<any>)
+ var bnum = fname->bufadd()
+ if bnum == 0
+ # Failed to create or find a buffer
+ return
+ endif
+ silent! bnum->bufload()
- var bnum = bufadd(fname)
- if bnum == 0
- # Failed to create or find a buffer
- return
- endif
+ if lspserver.peekSymbolPopup->winbufnr() != -1
+ # If the symbol popup window is already present, close it.
+ lspserver.peekSymbolPopup->popup_close()
+ endif
+ var ptitle = $"{fnamemodify(fname, ':t')} ({fnamemodify(fname, ':h')})"
+ lspserver.peekSymbolPopup = popup_atcursor(bnum, {moved: 'any',
+ title: ptitle,
+ minwidth: 10,
+ maxwidth: 60,
+ minheight: 10,
+ maxheight: 10,
+ mapping: false,
+ wrap: false})
+
+ # Highlight the symbol name and center the line in the popup
+ var pwid = lspserver.peekSymbolPopup
+ var pwbuf = winbufnr(pwid)
+ var pos: list<number> = []
+ var start_col: number
+ var end_col: number
+ start_col = util.GetLineByteFromPos(pwbuf, location.range.start) + 1
+ end_col = util.GetLineByteFromPos(pwbuf, location.range.end) + 1
+ pos->add(location.range.start.line + 1)
+ pos->extend([start_col, end_col - start_col])
+ matchaddpos('Search', [pos], 10, 101, {window: pwid})
+ var cmds =<< trim eval END
+ cursor({location.range.start.line + 1}, 1)
+ normal! z.
+ END
+ win_execute(pwid, cmds, 'silent!')
+enddef
- if lspserver.peekSymbolPopup->winbufnr() != -1
- # If the symbol popup window is already present, close it.
- lspserver.peekSymbolPopup->popup_close()
- endif
- var ptitle = $"{fnamemodify(fname, ':t')} ({fnamemodify(fname, ':h')})"
- lspserver.peekSymbolPopup = popup_atcursor(bnum, {moved: 'any',
- title: ptitle,
- minwidth: 10,
- maxwidth: 60,
- minheight: 10,
- maxheight: 10,
- mapping: false,
- wrap: false})
-
- # Highlight the symbol name and center the line in the popup
- var pwid = lspserver.peekSymbolPopup
- var pwbuf = winbufnr(pwid)
- var pos: list<number> = []
- var start_col: number
- var end_col: number
- start_col = util.GetLineByteFromPos(pwbuf, location.range.start) + 1
- end_col = util.GetLineByteFromPos(pwbuf, location.range.end) + 1
- pos->add(location.range.start.line + 1)
- pos->extend([start_col, end_col - start_col])
- matchaddpos('Search', [pos], 10, 101, {window: pwid})
- var cmds =<< trim eval END
- cursor({location.range.start.line + 1}, 1)
- normal! z.
- END
- win_execute(pwid, cmds, 'silent!')
- else
- # jump to the file and line containing the symbol
+# Jump to the symbol in file 'fname' at 'location'. The user specified
+# window command modifiers (e.g. topleft) are in 'cmdmods'.
+def JumpToSymbolLocation(lspserver: dict<any>, fname: string,
+ location: dict<any>, cmdmods: string)
+ # jump to the file and line containing the symbol
+ if cmdmods == ''
var bnr: number = fname->bufnr()
if bnr != bufnr()
var wid = fname->bufwinid()
if wid != -1
- wid->win_gotoid()
+ wid->win_gotoid()
else
- if bnr != -1
- # Reuse an existing buffer. If the current buffer has unsaved changes
- # and 'hidden' is not set or if the current buffer is a special
- # buffer, then open the buffer in a new window.
- if (&modified && !&hidden) || &buftype != ''
- exe $'sbuffer {bnr}'
- else
- exe $'buf {bnr}'
- endif
- else
- if (&modified && !&hidden) || &buftype != ''
- # if the current buffer has unsaved changes and 'hidden' is not set,
- # or if the current buffer is a special buffer, then open the file
- # in a new window
- exe $'split {fname}'
- else
- exe $'edit {fname}'
- endif
- endif
+ if bnr != -1
+ # Reuse an existing buffer. If the current buffer has unsaved changes
+ # and 'hidden' is not set or if the current buffer is a special
+ # buffer, then open the buffer in a new window.
+ if (&modified && !&hidden) || &buftype != ''
+ exe $'sbuffer {bnr}'
+ else
+ exe $'buf {bnr}'
+ endif
+ else
+ if (&modified && !&hidden) || &buftype != ''
+ # if the current buffer has unsaved changes and 'hidden' is not set,
+ # or if the current buffer is a special buffer, then open the file
+ # in a new window
+ exe $'split {fname}'
+ else
+ exe $'edit {fname}'
+ endif
+ endif
endif
endif
- # Set the previous cursor location mark. Instead of using setpos(), m' is
- # used so that the current location is added to the jump list.
- normal m'
- setcursorcharpos(location.range.start.line + 1,
+ else
+ exe $'{cmdmods} split {fname}'
+ endif
+ # Set the previous cursor location mark. Instead of using setpos(), m' is
+ # used so that the current location is added to the jump list.
+ normal m'
+ setcursorcharpos(location.range.start.line + 1,
location.range.start.character + 1)
+enddef
+
+# Jump to the definition, declaration or implementation of a symbol.
+# Also, used to peek at the definition, declaration or implementation of a
+# symbol.
+export def GotoSymbol(lspserver: dict<any>, location: dict<any>,
+ peekSymbol: bool, cmdmods: string)
+ var fname = util.LspUriToFile(location.uri)
+ if peekSymbol
+ PeekSymbolLocation(lspserver, fname, location)
+ else
+ # Save the current cursor location in the tag stack.
+ util.PushCursorToTagStack()
+ JumpToSymbolLocation(lspserver, fname, location, cmdmods)
endif
enddef
can be used to go back up the tag stack. Also the
|``| mark is set to the position before the jump.
+ This command supports |:command-modifiers|. You can
+ use the modifiers to specify whether a new window or
+ a new tab page is used and where the window is opened.
+ Example(s): >
+ # Open a horizontally split window
+ :topleft LspGotoDefinition
+ # Open a vertically split window
+ :vert LspGotoDefinition
+ # Open a new tab page
+ :tab LspGotoDefinition
+<
You may want to map a key to invoke this command: >
nnoremap <buffer> gd <Cmd>LspGotoDefinition<CR>
+ nnoremap <buffer> <C-W>gd <Cmd>topleft LspGotoDefinition<CR>
<
*:LspGotoDeclaration*
:LspGotoDeclaration Jumps to the declaration of the symbol under the
command! -nargs=0 -bar LspServerRestart lsp.RestartServer()
command! -nargs=1 -complete=customlist,LspServerTraceComplete -bar LspServerTrace lsp.ServerTraceSet(<q-args>)
command! -nargs=1 -complete=customlist,LspServerDebugComplete -bar LspServerDebug lsp.ServerDebug(<q-args>)
-command! -nargs=0 -bar LspGotoDefinition lsp.GotoDefinition(v:false)
-command! -nargs=0 -bar LspGotoDeclaration lsp.GotoDeclaration(v:false)
-command! -nargs=0 -bar LspGotoTypeDef lsp.GotoTypedef(v:false)
-command! -nargs=0 -bar LspGotoImpl lsp.GotoImplementation(v:false)
-command! -nargs=0 -bar LspPeekDefinition lsp.GotoDefinition(v:true)
-command! -nargs=0 -bar LspPeekDeclaration lsp.GotoDeclaration(v:true)
-command! -nargs=0 -bar LspPeekTypeDef lsp.GotoTypedef(v:true)
-command! -nargs=0 -bar LspPeekImpl lsp.GotoImplementation(v:true)
+command! -nargs=0 -bar LspGotoDefinition lsp.GotoDefinition(v:false, <q-mods>)
+command! -nargs=0 -bar LspGotoDeclaration lsp.GotoDeclaration(v:false, <q-mods>)
+command! -nargs=0 -bar LspGotoTypeDef lsp.GotoTypedef(v:false, <q-mods>)
+command! -nargs=0 -bar LspGotoImpl lsp.GotoImplementation(v:false, <q-mods>)
+command! -nargs=0 -bar LspPeekDefinition lsp.GotoDefinition(v:true, <q-mods>)
+command! -nargs=0 -bar LspPeekDeclaration lsp.GotoDeclaration(v:true, <q-mods>)
+command! -nargs=0 -bar LspPeekTypeDef lsp.GotoTypedef(v:true, <q-mods>)
+command! -nargs=0 -bar LspPeekImpl lsp.GotoImplementation(v:true, <q-mods>)
command! -nargs=0 -bar LspShowSignature call LspShowSignature()
command! -nargs=0 -bar LspDiagShow lsp.ShowDiagnostics()
command! -nargs=0 -bar LspDiagCurrent lsp.LspShowCurrentDiag()
END
setline(1, lines)
:sleep 1
+
cursor(24, 6)
:LspGotoDeclaration
assert_equal([6, 19], [line('.'), col('.')])
exe "normal! \<C-t>"
assert_equal([24, 6], [line('.'), col('.')])
+ assert_equal(1, winnr('$'))
+
:LspGotoDefinition
assert_equal([9, 12], [line('.'), col('.')])
exe "normal! \<C-t>"
assert_equal([24, 6], [line('.'), col('.')])
- # FIXME: The following test is failing in Github CI
- # :LspGotoImpl
- # assert_equal([15, 11], [line('.'), col('.')])
- # exe "normal! \<C-t>"
- # assert_equal([24, 6], [line('.'), col('.')])
+ assert_equal(1, winnr('$'))
+
+ # Command modifiers
+ :topleft LspGotoDefinition
+ assert_equal([9, 12], [line('.'), col('.')])
+ assert_equal([1, 2], [winnr(), winnr('$')])
+ close
+ exe "normal! \<C-t>"
+ assert_equal([24, 6], [line('.'), col('.')])
+
+ :tab LspGotoDefinition
+ assert_equal([9, 12], [line('.'), col('.')])
+ assert_equal([2, 2, 1], [tabpagenr(), tabpagenr('$'), winnr('$')])
+ tabclose
+ exe "normal! \<C-t>"
+ assert_equal([24, 6], [line('.'), col('.')])
+
+ # FIXME: :LspGotoTypeDef and :LspGotoImpl are supported only with clang-14.
+ # This clangd version is not available in Github CI.
# Error cases
# FIXME: The following tests are failing in Github CI. Comment out for now.
# tag stack should not be changed
assert_fails("normal! \<C-t>", 'E555:')
+ # FIXME: :LspPeekTypeDef and :LspPeekImpl are supported only with clang-14.
+ # This clangd version is not available in Github CI.
+
:%bw!
# empty file