autoload/lsp/lsp.vim | 67 ++++++++++++++++++++++++++++++++++++++++------------- doc/lsp.txt | 17 ++++++++++++----- diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index 7b85dec54e30ccdb2d8c885433c6d8a6bbac9db2..a1ff94007b99634f0f8350ed79da89aeeffa9a15 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -26,7 +26,7 @@ # LSP server information var lspServers: list> = [] # filetype to LSP server map -var ftypeServerMap: dict> = {} +var ftypeServerMap: dict>> = {} var lspInitializedOnce = false @@ -45,13 +45,41 @@ enddef # Returns the LSP server for the a specific filetype. Returns an empty dict if # the server is not found. -def LspGetServer(ftype: string): dict - return ftypeServerMap->get(ftype, {}) +def LspGetServer(bnr: number, ftype: string): dict + if ftypeServerMap->has_key(ftype) + var lspservers = ftypeServerMap[ftype] + + # The best language server for the current buffer + var bestMatch: dict = {} + var bestScore: number = -1 + + var bufDir = bnr->bufname()->fnamemodify(':p:h') + + for lspserver in lspservers + var score: number = 0 + if !lspserver.rootSearchFiles->empty() + # The score is calculated by how deep the workspace root dir is, the + # deeper the better. + var path = util.FindNearestRootDir(bufDir, lspserver.rootSearchFiles) + score = path->strcharlen() + endif + if score > bestScore + bestMatch = lspserver + bestScore = score + endif + endfor + + return bestMatch + endif + + return {} enddef # Add a LSP server for a filetype def LspAddServer(ftype: string, lspsrv: dict) - ftypeServerMap->extend({[ftype]: lspsrv}) + var lspsrvlst = ftypeServerMap->has_key(ftype) ? ftypeServerMap[ftype] : [] + lspsrvlst->add(lspsrv) + ftypeServerMap[ftype] = lspsrvlst enddef # Enable/disable the logging of the language server protocol messages @@ -85,11 +113,14 @@ var lines = [] # Add filetype to server mapping information lines->add('Filetype Information') lines->add('====================') - for [ftype, lspserver] in ftypeServerMap->items() - lines->add($"Filetype: '{ftype}'") - lines->add($"Server Path: '{lspserver.path}'") - lines->add($"Status: {lspserver.running ? 'Running' : 'Not running'}") - lines->add('') + for [ftype, lspservers] in ftypeServerMap->items() + for lspserver in lspservers + lines->add($"Filetype: '{ftype}'") + lines->add($"Server Name: '{lspserver.name}'") + lines->add($"Server Path: '{lspserver.path}'") + lines->add($"Status: {lspserver.running ? 'Running' : 'Not running'}") + lines->add('') + endfor endfor # Add buffer to server mapping information @@ -143,12 +174,16 @@ # Get LSP server running status for filetype 'ftype' # Return true if running, or false if not found or not running export def ServerRunning(ftype: string): bool - for [ft, lspserver] in ftypeServerMap->items() - if ftype ==# ft - return lspserver.running - endif - endfor - return v:false + if ftypeServerMap->has_key(ftype) + var lspservers = ftypeServerMap[ftype] + for lspserver in lspservers + if lspserver.running + return true + endif + endfor + endif + + return false enddef # Go to a definition using "textDocument/definition" LSP request @@ -363,7 +398,7 @@ var ftype: string = bnr->getbufvar('&filetype') if ftype == '' return endif - var lspserver: dict = LspGetServer(ftype) + var lspserver: dict = LspGetServer(bnr, ftype) if lspserver->empty() return endif diff --git a/doc/lsp.txt b/doc/lsp.txt index 56e58022a6d80ce627e20b83912b81664d09207a..acd4cac959bb57463b1d825e0addcd376b3ed106 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -269,11 +269,18 @@ "\". 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 current - working directory is used as the workspace root for - decendent files, for any other files the parent - directory of the file is used. + as the workspace root. + + This option is also used to decide which server to run + when multiple servers are defined for a filetype. The + server with the longest found workspace root will be + selected as the relevant language server for a given + file. + + If this parameter is not specified or the files are not + found, then the current working directory is used as the + workspace root for decendent files, for any other files + the parent directory of the file is used. Aditionally the following configurations can be made: