From: Yegappan Lakshmanan Date: Fri, 7 Apr 2023 21:40:08 +0000 (-0700) Subject: Support for detecting the workspace root directory X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=ca7f26773bf4348d956e16d3d9dba82ca87c180c;p=vim-lsp.git Support for detecting the workspace root directory --- diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index f4f6f01..020c07a 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -371,7 +371,7 @@ export def AddFile(bnr: number): void if !lspInitializedOnce LspInitOnce() endif - lspserver.startServer() + lspserver.startServer(bnr) endif buf.BufLspServerSet(bnr, lspserver) @@ -438,7 +438,7 @@ export def RestartServer() endfor # Start the server again - lspserver.startServer() + lspserver.startServer(bufnr('')) AddBuffersToLsp(ftype) enddef @@ -514,10 +514,15 @@ export def AddServer(serverList: list>) server.workspaceConfig = {} endif + if !server->has_key('rootSearch') || server.rootSearch->type() != v:t_list + server.rootSearch = [] + endif + var lspserver: dict = lserver.NewLspServer(server.name, server.path, args, server.syncInit, initializationOptions, server.workspaceConfig, + server.rootSearch, customNotificationHandlers, server.debug) diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index 01df434..dbaacea 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -46,7 +46,7 @@ enddef # Start a LSP server # -def StartServer(lspserver: dict): number +def StartServer(lspserver: dict, bnr: number): number if lspserver.running util.WarnMsg('LSP server for is already running') return 0 @@ -71,7 +71,7 @@ def StartServer(lspserver: dict): number 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' @@ -85,7 +85,7 @@ def StartServer(lspserver: dict): number lspserver.job = job lspserver.running = true - lspserver.initServer() + lspserver.initServer(bnr) return 0 enddef @@ -143,7 +143,7 @@ enddef # Request: 'initialize' # Param: InitializeParams -def InitServer(lspserver: dict) +def InitServer(lspserver: dict, bnr: number) # interface 'InitializeParams' var initparams: dict = {} initparams.processId = getpid() @@ -151,12 +151,23 @@ def InitServer(lspserver: dict) 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() @@ -1384,6 +1395,7 @@ enddef export def NewLspServer(name_arg: string, path_arg: string, args: list, isSync: bool, initializationOptions: any, workspaceConfig: dict, + rootSearchFiles: list, customNotificationHandlers: dict, debug_arg: bool): dict var lspserver: dict = { @@ -1400,6 +1412,7 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list, nextID: 1, caps: {}, requests: {}, + rootSearchFiles: rootSearchFiles, omniCompletePending: false, completionTriggerChars: [], signaturePopup: -1, diff --git a/autoload/lsp/util.vim b/autoload/lsp/util.vim index a51718b..cb1798e 100644 --- a/autoload/lsp/util.vim +++ b/autoload/lsp/util.vim @@ -226,4 +226,45 @@ export def Indexof(list: list, CallbackFn: func(number, any): bool): number 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): string + var foundDirs: dict = {} + + 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 = 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 diff --git a/doc/lsp.txt b/doc/lsp.txt index d837fc1..1aa9086 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -2,7 +2,7 @@ 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* @@ -259,6 +259,18 @@ To add a language server, the following information is needed: 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: @@ -297,6 +309,7 @@ server and to set the language server options. For example: > let lspServers = [ \ #{ + \ name: 'clangd', \ filetype: ['c', 'cpp'], \ path: '/usr/local/bin/clangd', \ args: ['--background-index']