]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Make the code ready for adding support for "features"
authorAndreas Louv <andreas@louv.dk>
Wed, 12 Apr 2023 09:00:10 +0000 (11:00 +0200)
committerAndreas Louv <andreas@louv.dk>
Thu, 13 Apr 2023 21:58:31 +0000 (23:58 +0200)
README.md
autoload/lsp/buffer.vim
autoload/lsp/lsp.vim
autoload/lsp/lspserver.vim
doc/lsp.txt

index 2abe07e54e9bda221d02fe2475f2a5340f02f553..54bdfeefd2a1a08fe33227f396f99a44679125b4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -131,6 +131,7 @@ path|complete path to the LSP server executable (without any arguments).
 args|a list of command-line arguments passed to the LSP server. Each argument is a separate List item.
 initializationOptions|User provided initialization options. May be of any type. For example the *intelephense* PHP language server accept several options here with the License Key among others. 
 customNotificationHandlers|A dictionary of notifications and functions that can be specified to add support for custom language server notifications.
+features|A dictionary of booleans that can be specified to toggle what things a given LSP is providing (folding, goto definition, etc) This is useful when running multiple servers in one buffer.
 
 The LSP servers are added using the LspAddServer() function. This function accepts a list of LSP servers with the above information.
 
index bdb69aac3c394cc7e61c23430fd97ea65c2c9acc..fbe0ec3e464e0c9f8f1312cebb081d8ebc14a2e2 100644 (file)
@@ -30,9 +30,9 @@ export def BufLspServerRemove(bnr: number, lspserver: dict<any>)
   endif
 enddef
 
-# Returns the LSP server for the buffer 'bnr'. Returns an empty dict if the
-# server is not found.
-export def BufLspServerGet(bnr: number): dict<any>
+# Returns the LSP server for the buffer 'bnr' and optionally 'domain'.
+# Returns an empty dict if the server is not found.
+export def BufLspServerGet(bnr: number, domain: string = null_string): dict<any>
   if !bufnrToServers->has_key(bnr)
     return {}
   endif
@@ -41,8 +41,44 @@ export def BufLspServerGet(bnr: number): dict<any>
     return {}
   endif
 
-  # TODO implement logic to compute which server to return
-  return bufnrToServers[bnr][0]
+  if domain == null_string
+    return bufnrToServers[bnr][0]
+  endif
+
+  var SupportedCheckFns = {
+  }
+
+  if !SupportedCheckFns->has_key(domain)
+    # If this happns it is a programming error, and should be fixed in the source code
+    :throw $'Error: ''{domain}'' is not a valid domain'
+    return {}
+  endif
+
+  var SupportedCheckFn = SupportedCheckFns[domain]
+
+  var possibleLSPs: list<dict<any>> = []
+
+  for lspserver in bufnrToServers[bnr]
+    if !SupportedCheckFn(lspserver)
+      continue
+    endif
+
+    possibleLSPs->add(lspserver)
+  endfor
+
+  if possibleLSPs->len() == 0
+    return {}
+  endif
+
+  # LSP server is configured to be a provider for 'domain'
+  for lspserver in possibleLSPs
+    if lspserver.features->has_key(domain) && lspserver.features[domain]
+      return lspserver
+    endif
+  endfor
+
+  # Return the first LSP server that supports 'domain'
+  return possibleLSPs[0]
 enddef
 
 # Returns the LSP server for the buffer 'bnr' and with ID 'id'. Returns an empty
@@ -71,10 +107,10 @@ export def BufLspServersGet(bnr: number): list<dict<any>>
   return bufnrToServers[bnr]
 enddef
 
-# Returns the LSP server for the current buffer. Returns an empty dict if the
-# server is not found.
-export def CurbufGetServer(): dict<any>
-  return BufLspServerGet(bufnr())
+# Returns the LSP server for the current buffer with the optionally 'domain'.
+# Returns an empty dict if the server is not found.
+export def CurbufGetServer(domain: string = null_string): dict<any>
+  return BufLspServerGet(bufnr(), domain)
 enddef
 
 # Returns the LSP servers for the current buffer. Returns an empty list if the
@@ -89,15 +125,16 @@ export def BufHasLspServer(bnr: number): bool
   return !lspserver->empty()
 enddef
 
-# Returns the LSP server for the current buffer if it is running and is ready.
+# Returns the LSP server for the current buffer with the optinally 'domain' if
+# it is running and is ready.
 # Returns an empty dict if the server is not found or is not ready.
-export def CurbufGetServerChecked(): dict<any>
+export def CurbufGetServerChecked(domain: string = null_string): dict<any>
   var fname: string = @%
   if fname == ''
     return {}
   endif
 
-  var lspserver: dict<any> = CurbufGetServer()
+  var lspserver: dict<any> = CurbufGetServer(domain)
   if lspserver->empty()
     util.ErrMsg($'Error: Language server for "{&filetype}" file type is not found')
     return {}
index 88e0b086038627ecf674a7754ca5cc6304b12cba..27674f983857e08e010ce41e0241cb0db4205555 100644 (file)
@@ -598,6 +598,11 @@ export def AddServer(serverList: list<dict<any>>)
       customNotificationHandlers = server.customNotificationHandlers
     endif
 
+    var features: dict<bool> = {}
+    if server->has_key('features')
+      features = server.features
+    endif
+
     if server.omnicompl->type() != v:t_bool
       util.ErrMsg($'Error: Setting of omnicompl {server.omnicompl} is not a Boolean')
       return
@@ -632,7 +637,7 @@ export def AddServer(serverList: list<dict<any>>)
                                                    server.workspaceConfig,
                                                    server.rootSearch,
                                                    customNotificationHandlers,
-                                                   server.debug)
+                                                   features, server.debug)
 
     var ftypes = server.filetype
     if ftypes->type() == v:t_string
index 74e0914762e07694d849d38140afb2353fba828a..bbc852ff952fc64b552b2742d8fb911ba69fa83f 100644 (file)
@@ -1476,7 +1476,7 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list<string>,
                        workspaceConfig: dict<any>,
                        rootSearchFiles: list<any>,
                        customNotificationHandlers: dict<func>,
-                       debug_arg: bool): dict<any>
+                       features: dict<bool>, debug_arg: bool): dict<any>
   var lspserver: dict<any> = {
     id: GetUniqueServerId(),
     name: name_arg,
@@ -1485,6 +1485,7 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list<string>,
     syncInit: isSync,
     initializationOptions: initializationOptions,
     customNotificationHandlers: customNotificationHandlers,
+    features: features,
     running: false,
     ready: false,
     job: v:none,
index 20f4e7edd6e9c02f5ed38239d2ff723108955d98..73adf21050236b5195f9272e20117a0c4c36acda 100644 (file)
@@ -299,6 +299,11 @@ Aditionally the following configurations can be made:
                        }
                }])
 <
+                                       *lsp-cfg-features*
+       features
+                       (Optional) toggle which features should be enabled for a
+                       given langauge server. See |lsp-multiple-servers| for
+                       more information.
                                                *lsp-cfg-omnicompl*
        omnicompl       (Optional) a boolean value that enables (true)
                        or disables (false) omni-completion for this file
@@ -1320,4 +1325,45 @@ In the completion popup, will show something like this: >
                | createIfNotExists     method() |
                | ...                            |
 <
+==============================================================================
+16. Multiple Language Servers for a buffer     *lsp-multiple-servers*
+
+It's possible to run multiple language servers for a given buffer.
+
+By default the language server defined first will be used for as much as it
+supports, then the next and so on. With the exception that diagnostics from all
+running language servers will be joined together. This means that you can define
+a language server that only supports a subset of features at first and then
+define the general purpose language server after it: >
+
+               vim9script
+               g:LspAddServer([
+                       # This language server reports that it only supports
+                       # textDocument/documentFormatting, so it will be used
+                       # for :LspFormat but nothing else.
+                       {
+                               filetype: ['html'],
+                               path: 'html-pretty-lsp',
+                               args: ['--stdio']
+                       },
+                       # This language server also supports
+                       # textDocument/documentFormatting, but since it's been
+                       # defined later, the one above will be used instead.
+                       # However this server also supports
+                       # textDocument/definition, textDocument/declaration,
+                       # etc, so it will be used for :LspGotoDefinition,
+                       # :LspGotoDeclaration, etc
+                       {
+                               filetype: ['html'],
+                               path: 'html-language-server',
+                               args: ['--stdio']
+                       }
+               ])
+<
+By proving the configuration |lsp-cfg-features| it's possible specify which
+servers should be used for a given method.  The following flags are supported
+>
+#{
+}
+<
 vim:tw=78:ts=8:noet:ft=help:norl: