# Perform a workspace wide symbol lookup
# Uses LSP "workspace/symbol" request
-export def SymbolSearch(queryArg: string)
+export def SymbolSearch(queryArg: string, cmdmods: string)
var lspserver: dict<any> = buf.CurbufGetServerChecked()
if lspserver->empty()
return
endif
:redraw!
- lspserver.workspaceQuery(query)
+ lspserver.workspaceQuery(query, true, cmdmods)
enddef
# Display the list of workspace folders
# List project-wide symbols matching query string
# Request: "workspace/symbol"
# Param: WorkspaceSymbolParams
-def WorkspaceQuerySymbols(lspserver: dict<any>, query: string)
+def WorkspaceQuerySymbols(lspserver: dict<any>, query: string, firstCall: bool, cmdmods: string = '')
# Check whether the LSP server supports listing workspace symbols
if !lspserver.isWorkspaceSymbolProvider
util.ErrMsg('LSP server does not support listing workspace symbols')
return
endif
- symbol.WorkspaceSymbolPopup(lspserver, query, reply.result)
+ var symInfo: list<dict<any>> = reply.result
+
+ symInfo->map((_, sym) => {
+ if sym->has_key('location')
+ lspserver.decodeLocation(sym.location)
+ endif
+ return sym
+ })
+
+ if firstCall && symInfo->len() == 1
+ # If there is only one symbol, then jump to the symbol location
+ var symLoc: dict<any> = symInfo[0]->get('location', {})
+ if !symLoc->empty()
+ symbol.GotoSymbol(lspserver, symLoc, false, cmdmods)
+ endif
+ else
+ symbol.WorkspaceSymbolPopup(lspserver, query, symInfo, cmdmods)
+ endif
enddef
# Add a workspace folder to the language server.
# Update the popup with the new list of symbol names
popupID->popup_settext('')
if query != ''
- lspserver.workspaceQuery(query)
+ lspserver.workspaceQuery(query, false)
else
[]->setwinvar(popupID, 'LspSymbolTable')
endif
enddef
# Jump to the location of a symbol selected in the popup menu
-def JumpToWorkspaceSymbol(popupID: number, result: number): void
+def JumpToWorkspaceSymbol(cmdmods: string, popupID: number, result: number): void
# clear the message displayed at the command-line
:echo ''
# if the selected file is already present in a window, then jump to it
var fname: string = symTbl[result - 1].file
- var bufnum = fname->bufnr()
- var winList: list<number> = bufnum->win_findbuf()
- if winList->empty()
- # Not present in any window
- if &modified || &buftype != ''
- # the current buffer is modified or is not a normal buffer, then open
- # the file in a new window
- exe $'split {symTbl[result - 1].file}'
+ var bnr = fname->bufnr()
+ if cmdmods->empty()
+ var winList: list<number> = bnr->win_findbuf()
+ if winList->empty()
+ # Not present in any window
+ if &modified || &buftype != ''
+ # the current buffer is modified or is not a normal buffer, then
+ # open the file in a new window
+ exe $'split {symTbl[result - 1].file}'
+ else
+ exe $'confirm edit {symTbl[result - 1].file}'
+ endif
else
- exe $'confirm edit {symTbl[result - 1].file}'
- endif
- else
- if bufnr() != bufnum
- var winID = fname->bufwinid()
- if winID == -1
- # not present in the current tab page
- winID = winList[0]
+ # If the target buffer is opened in the curent window, then don't
+ # change the window.
+ if bufnr() != bnr
+ # If the target buffer is opened in a window in the current tab
+ # page, then use it.
+ var winID = fname->bufwinid()
+ if winID == -1
+ # not present in the current tab page. Use the first window.
+ winID = winList[0]
+ endif
+ winID->win_gotoid()
endif
- winID->win_gotoid()
endif
+ else
+ exe $'{cmdmods} split {symTbl[result - 1].file}'
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(symTbl[result - 1].pos.line + 1,
- util.GetCharIdxWithoutCompChar(bufnum,
+ util.GetCharIdxWithoutCompChar(bnr,
symTbl[result - 1].pos) + 1)
catch
# ignore exceptions
enddef
# display a list of symbols from the workspace
-def ShowSymbolMenu(lspserver: dict<any>, query: string)
+def ShowSymbolMenu(lspserver: dict<any>, query: string, cmdmods: string)
# Create the popup menu
var lnum = &lines - &cmdheight - 2 - 10
var popupAttr = {
fixed: 1,
close: 'button',
filter: function(FilterSymbols, [lspserver]),
- callback: JumpToWorkspaceSymbol
+ callback: function('JumpToWorkspaceSymbol', [cmdmods])
}
lspserver.workspaceSymbolPopup = popup_menu([], popupAttr)
lspserver.workspaceSymbolQuery = query
# process the 'workspace/symbol' reply from the LSP server
# Result: SymbolInformation[] | null
export def WorkspaceSymbolPopup(lspserver: dict<any>, query: string,
- symInfo: list<dict<any>>)
+ symInfo: list<dict<any>>, cmdmods: string)
var symbols: list<dict<any>> = []
var symbolType: string
var fileName: string
- var r: dict<dict<number>>
var symName: string
# Create a symbol popup menu if it is not present
if lspserver.workspaceSymbolPopup->winbufnr() == -1
- ShowSymbolMenu(lspserver, query)
+ ShowSymbolMenu(lspserver, query, cmdmods)
endif
for symbol in symInfo
# interface SymbolInformation
fileName = util.LspUriToFile(symbol.location.uri)
- r = symbol.location.range
- lspserver.decodeRange(fileName->bufnr(), r)
symName = symbol.name
if symbol->has_key('containerName') && symbol.containerName != ''
symbols->add({name: symName,
file: fileName,
- pos: r.start})
+ pos: symbol.location.range.start})
endfor
symbols->setwinvar(lspserver.workspaceSymbolPopup, 'LspSymbolTable')
lspserver.workspaceSymbolPopup->popup_settext(
var fname = LspUriToFile(uri)
# jump to the file and line containing the symbol
+ var bnr: number = fname->bufnr()
if cmdmods->empty()
- var bnr: number = fname->bufnr()
if bnr == bufnr()
# Set the previous cursor location mark. Instead of using setpos(), m' is
# used so that the current location is added to the jump list.
endif
endif
else
- exe $'{cmdmods} split {fname}'
+ if bnr == -1
+ exe $'{cmdmods} split {fname}'
+ else
+ # Use "sbuffer" so that the 'switchbuf' option settings are used.
+ exe $'{cmdmods} sbuffer {bnr}'
+ endif
endif
setcursorcharpos(range.start.line + 1,
GetCharIdxWithoutCompChar(bufnr(), range.start) + 1)
:LspSymbolSearch <sym> Perform a workspace wide search for the symbol <sym>.
If <sym> is not supplied, then you will be prompted to
enter the symbol name (the keyword under the cursor is
- used as the default). A popup window is opened with
- the list of matching symbols. You can enter a few
- characters to narrow down the list of matches. The
+ used as the default). If there is only one matching
+ symbol, then the cursor will be positioned at the
+ symbol location. Otherwise a popup window is opened
+ with the list of matching symbols. You can enter a
+ few characters to narrow down the list of matches. The
displayed symbol name can be erased by pressing
<Backspace> or <C-U> and a new symbol search pattern
can be entered. You can close the popup menu by
You can enter a new search pattern to do a workspace
wide symbol search.
+ This command accepts |:command-modifiers| which can be
+ used to jump to a symbol in a horizontally or
+ vertically split window or a new tab page: >
+
+ :topleft LspSymbolSearch foo
+ :vert LspSymbolSearch bar
+ :tab LspSymbolSearch baz
+<
*:LspWorkspaceAddFolder*
:LspWorkspaceAddFolder {folder}
Add a folder to the workspace
# 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(<q-args>)
+command! -nargs=? -bar LspSymbolSearch lsp.SymbolSearch(<q-args>, <q-mods>)
command! -nargs=1 -bar -complete=dir LspWorkspaceAddFolder lsp.AddWorkspaceFolder(<q-args>)
command! -nargs=0 -bar LspWorkspaceListFolders lsp.ListWorkspaceFolders()
command! -nargs=1 -bar -complete=dir LspWorkspaceRemoveFolder lsp.RemoveWorkspaceFolder(<q-args>)
g:WaitForServerFileLoad(0)
cursor(1, 1)
- feedkeys(":LspSymbolSearch Func1\<CR>\<CR>", "xt")
+ feedkeys(":LspSymbolSearch Func1\<CR>", "xt")
assert_equal([5, 18], [line('.'), col('.')])
cursor(1, 1)
- feedkeys(":LspSymbolSearch Func2\<CR>\<CR>", "xt")
+ feedkeys(":LspSymbolSearch Func2\<CR>", "xt")
assert_equal([9, 14], [line('.'), col('.')])
cursor(1, 1)
- feedkeys(":LspSymbolSearch Func3\<CR>\<CR>", "xt")
+ feedkeys(":LspSymbolSearch Func3\<CR>", "xt")
assert_equal([13, 22], [line('.'), col('.')])
:%bw!
g:WaitForServerFileLoad(0)
cursor(1, 1)
- feedkeys(":LspSymbolSearch lsptest_funcB\<CR>\<CR>", "xt")
+ feedkeys(":LspSymbolSearch lsptest_funcB\<CR>", "xt")
assert_equal([5, 6], [line('.'), col('.')])
cursor(1, 1)
assert_equal([9, 6], [line('.'), col('.')])
cursor(1, 1)
- feedkeys(":LspSymbolSearch lsptest_funcA\<CR>\<BS>B\<CR>", "xt")
+ feedkeys(":LspSymbolSearch lsptest_func\<CR>A\<BS>B\<CR>", "xt")
assert_equal([5, 6], [line('.'), col('.')])
var output = execute(':LspSymbolSearch lsptest_nonexist')->split("\n")