if !lspInitializedOnce
LspInitOnce()
endif
- lspserver.startServer()
+ lspserver.startServer(bnr)
endif
buf.BufLspServerSet(bnr, lspserver)
endfor
# Start the server again
- lspserver.startServer()
+ lspserver.startServer(bufnr(''))
AddBuffersToLsp(ftype)
enddef
server.workspaceConfig = {}
endif
+ if !server->has_key('rootSearch') || server.rootSearch->type() != v:t_list
+ server.rootSearch = []
+ endif
+
var lspserver: dict<any> = lserver.NewLspServer(server.name, server.path,
args, server.syncInit,
initializationOptions,
server.workspaceConfig,
+ server.rootSearch,
customNotificationHandlers,
server.debug)
# Start a LSP server
#
-def StartServer(lspserver: dict<any>): number
+def StartServer(lspserver: dict<any>, bnr: number): number
if lspserver.running
util.WarnMsg('LSP server for is already running')
return 0
lspserver.completionLazyDoc = false
lspserver.completionTriggerChars = []
lspserver.signaturePopup = -1
- lspserver.workspaceFolders = [getcwd()]
+ lspserver.workspaceFolders = [bnr->bufname()->fnamemodify(':p:h')]
var job = cmd->job_start(opts)
if job->job_status() == 'fail'
lspserver.job = job
lspserver.running = true
- lspserver.initServer()
+ lspserver.initServer(bnr)
return 0
enddef
# Request: 'initialize'
# Param: InitializeParams
-def InitServer(lspserver: dict<any>)
+def InitServer(lspserver: dict<any>, bnr: number)
# interface 'InitializeParams'
var initparams: dict<any> = {}
initparams.processId = getpid()
name: 'Vim',
version: v:versionlong->string(),
}
- var curdir: string = getcwd()
- initparams.rootPath = curdir
- initparams.rootUri = util.LspFileToUri(curdir)
+
+ # Compute the rootpath (based on the directory of the buffer)
+ var bufDir = bnr->bufname()->fnamemodify(':p:h')
+ var rootPath = ''
+ var rootSearchFiles = lspserver.rootSearchFiles
+ if !rootSearchFiles->empty()
+ rootPath = util.FindNearestRootDir(bufDir, rootSearchFiles)
+ endif
+ if rootPath == ''
+ rootPath = bufDir
+ endif
+ var rootUri = util.LspFileToUri(rootPath)
+ initparams.rootPath = rootPath
+ initparams.rootUri = rootUri
initparams.workspaceFolders = [{
- name: curdir->fnamemodify(':t'),
- uri: util.LspFileToUri(curdir)
+ name: rootPath->fnamemodify(':t'),
+ uri: rootUri
}]
initparams.trace = 'off'
initparams.capabilities = capabilities.GetClientCaps()
export def NewLspServer(name_arg: string, path_arg: string, args: list<string>,
isSync: bool, initializationOptions: any,
workspaceConfig: dict<any>,
+ rootSearchFiles: list<any>,
customNotificationHandlers: dict<func>,
debug_arg: bool): dict<any>
var lspserver: dict<any> = {
nextID: 1,
caps: {},
requests: {},
+ rootSearchFiles: rootSearchFiles,
omniCompletePending: false,
completionTriggerChars: [],
signaturePopup: -1,
return -1
enddef
+# Find the nearest root directory containing a file or directory name from the
+# list of names in 'files' starting with the directory 'startDir'.
+# Based on a similar implementation in the vim-lsp plugin.
+# Searches upwards starting with the directory 'startDir'.
+# If a file name ends with '/' or '\', then it is a directory name, otherwise
+# it is a file name.
+# Returns '' if none of the file and directory names in 'files' can be found
+# in one of the parent directories.
+export def FindNearestRootDir(startDir: string, files: list<any>): string
+ var foundDirs: dict<bool> = {}
+
+ for file in files
+ if file->type() != v:t_string || file == ''
+ continue
+ endif
+ var isDir = file[-1 : ] ==# '/' || file[-1 : ] ==# '\'
+ var relPath: string
+ if isDir
+ relPath = finddir(file, $'{startDir};')
+ else
+ relPath = findfile(file, $'{startDir};')
+ endif
+ if relPath->empty()
+ continue
+ endif
+ var rootDir = relPath->fnamemodify(isDir ? ':p:h:h' : ':p:h')
+ foundDirs[rootDir] = true
+ endfor
+ if foundDirs->empty()
+ return ''
+ endif
+
+ # Sort the directory names by length
+ var sortedList: list<string> = foundDirs->keys()->sort((a, b) => {
+ return b->len() - a->len()
+ })
+
+ # choose the longest matching path (the nearest directory from 'startDir')
+ return sortedList[0]
+enddef
+
# vim: tabstop=8 shiftwidth=2 softtabstop=2
Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
For Vim version 9.0 and above
-Last change: April 2, 2023
+Last change: April 7, 2023
==============================================================================
*lsp-license*
this notification. This configuration is also used to
respond to the "workspace/configuration" request
message from the language server.
+ *lsp-cfg-rootSearch*
+ rootSearch (Optional) a List of file and directory names used to
+ locate the root path or uri of the workspace. The
+ directory names in "rootSearch" must end in "/" or
+ "\". Each file and directory name in "rootSearch" is
+ searched upwards in all the parent directories. If
+ multiple directories are found, then the directory
+ closest to the directory of the current buffer is used
+ as the workspace root. If this parameter is not
+ specified or the files are not found, then the
+ directory of the current buffer is used as the
+ workspace root.
Aditionally the following configurations can be made:
let lspServers = [
\ #{
+ \ name: 'clangd',
\ filetype: ['c', 'cpp'],
\ path: '/usr/local/bin/clangd',
\ args: ['--background-index']