From 0498bd6b36e57bc6fd9f3c53dee0d59721bbd0a1 Mon Sep 17 00:00:00 2001 From: Andreas Louv Date: Tue, 11 Apr 2023 16:40:02 +0200 Subject: [PATCH] Report didOpen, didSave and didClose to all servers for a buffer --- autoload/lsp/buffer.vim | 16 +++++ autoload/lsp/lsp.vim | 137 +++++++++++++++++++++------------------- doc/lsp.txt | 4 +- 3 files changed, 89 insertions(+), 68 deletions(-) diff --git a/autoload/lsp/buffer.vim b/autoload/lsp/buffer.vim index aa41dfd..26897b0 100644 --- a/autoload/lsp/buffer.vim +++ b/autoload/lsp/buffer.vim @@ -45,6 +45,22 @@ export def BufLspServerGet(bnr: number): dict return bufnrToServers[bnr][0] enddef +# Returns the LSP server for the buffer 'bnr' and with ID 'id'. Returns an empty +# dict if the server is not found. +export def BufLspServerGetById(bnr: number, id: number): dict + if !bufnrToServers->has_key(bnr) + return {} + endif + + for lspserver in bufnrToServers[bnr] + if lspserver.id == id + return lspserver + endif + endfor + + return {} +enddef + # Returns the LSP servers for the buffer 'bnr'. Returns an empty list if the # servers are not found. export def BufLspServersGet(bnr: number): list> diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index 8eb97a27..c8db52c 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -43,36 +43,41 @@ def LspInitOnce() lspInitializedOnce = true enddef -# Returns the LSP server for the a specific filetype. Returns an empty dict if -# the server is not found. -def LspGetServer(bnr: number, ftype: string): dict - if ftypeServerMap->has_key(ftype) - var lspservers = ftypeServerMap[ftype] +# Returns the LSP servers for the a specific filetype. Based on how well there +# score, LSP servers with the same score are being returned. +# Returns an empty list if the servers is not found. +def LspGetServers(bnr: number, ftype: string): list> + if !ftypeServerMap->has_key(ftype) + return [] + endif - # The best language server for the current buffer - var bestMatch: dict = {} - var bestScore: number = -1 + var lspservers = ftypeServerMap[ftype] - var bufDir = bnr->bufname()->fnamemodify(':p:h') + # All the langauge servers with the same score are being used + var bestMatches: list> = [] + var bestScore: number = 0 - 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 + var bufDir = bnr->bufname()->fnamemodify(':p:h') - return bestMatch - endif + 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 + bestMatches = [lspserver] + bestScore = score + elseif score == bestScore + bestMatches->add(lspserver) + endif + endfor - return {} + return bestMatches enddef # Add a LSP server for a filetype @@ -295,25 +300,20 @@ def g:LspShowSignature(): string return '' enddef -# buffer change notification listener -def Bufchange_listener(bnr: number, start: number, end: number, added: number, changes: list>) - var lspserver: dict = buf.CurbufGetServer() - if lspserver->empty() || !lspserver.running - return - endif - - lspserver.textdocDidChange(bnr, start, end, added, changes) -enddef - # A buffer is saved. Send the "textDocument/didSave" LSP notification def LspSavedFile() var bnr: number = expand('')->str2nr() - var lspserver: dict = buf.BufLspServerGet(bnr) - if lspserver->empty() || !lspserver.running + var lspservers: list> = buf.BufLspServersGet(bnr)->filter( + (key, lspsrv) => !lspsrv->empty() && lspsrv.running + ) + + if lspservers->empty() return endif - lspserver.didSaveFile(bnr) + for lspserver in lspservers + lspserver.didSaveFile(bnr) + endfor enddef # Return the diagnostic text from the LSP server for the current mouse line to @@ -401,8 +401,8 @@ def AddBufLocalAutocmds(lspserver: dict, bnr: number): void autocmd_add(acmds) enddef -def BufferInit(bnr: number): void - var lspserver: dict = buf.BufLspServerGet(bnr) +def BufferInit(lspserverId: number, bnr: number): void + var lspserver = buf.BufLspServerGetById(bnr, lspserverId) if lspserver->empty() || !lspserver.running return endif @@ -411,7 +411,9 @@ def BufferInit(bnr: number): void lspserver.textdocDidOpen(bnr, ftype) # add a listener to track changes to this buffer - listener_add(Bufchange_listener, bnr) + listener_add((_bnr: number, start: number, end: number, added: number, changes: list>) => { + lspserver.textdocDidChange(bnr, start, end, added, changes) + }, bnr) AddBufLocalAutocmds(lspserver, bnr) @@ -442,39 +444,42 @@ export def AddFile(bnr: number): void if ftype == '' return endif - var lspserver: dict = LspGetServer(bnr, ftype) - if lspserver->empty() + var lspservers: list> = LspGetServers(bnr, ftype) + if lspservers->empty() return endif - if !lspserver.running - if !lspInitializedOnce - LspInitOnce() + for lspserver in lspservers + if !lspserver.running + if !lspInitializedOnce + LspInitOnce() + endif + lspserver.startServer(bnr) endif - lspserver.startServer(bnr) - endif - buf.BufLspServerSet(bnr, lspserver) - - if lspserver.ready - BufferInit(bnr) - else - augroup LSPBufferAutocmds - exe $'autocmd User LspServerReady{lspserver.name} ++once BufferInit({bnr})' - augroup END - endif + buf.BufLspServerSet(bnr, lspserver) + if lspserver.ready + BufferInit(lspserver.id, bnr) + else + augroup LSPBufferAutocmds + exe $'autocmd User LspServerReady{lspserver.name} ++once BufferInit({lspserver.id}, {bnr})' + augroup END + endif + endfor enddef # Notify LSP server to remove a file export def RemoveFile(bnr: number): void - var lspserver: dict = buf.BufLspServerGet(bnr) - if lspserver->empty() - return - endif - if lspserver.running - lspserver.textdocDidClose(bnr) - endif - diag.DiagRemoveFile(lspserver, bnr) - buf.BufLspServerRemove(bnr) + var lspservers: list> = buf.BufLspServersGet(bnr) + for lspserver in lspservers->copy() + if lspserver->empty() + continue + endif + if lspserver.running + lspserver.textdocDidClose(bnr) + endif + diag.DiagRemoveFile(lspserver, bnr) + buf.BufLspServerRemove(bnr, lspserver) + endfor enddef # Stop all the LSP servers diff --git a/doc/lsp.txt b/doc/lsp.txt index 291936e..0ae3e00 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -267,8 +267,8 @@ To add a language server, the following information is needed: 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 + servers that share the longest found workspace root will + be selected as the relevant language servers for a given file. If this parameter is not specified or the files are not -- 2.48.1