From 0e99a1dcaf3125489c409c9056edca05fdbfcb9c Mon Sep 17 00:00:00 2001
From: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Wed, 5 Apr 2023 22:37:37 -0700
Subject: [PATCH] Add support for the workspace/didChangeConfiguration
 notification

---
 autoload/lsp/capabilities.vim |  2 +-
 autoload/lsp/handlers.vim     |  6 ++++--
 autoload/lsp/lsp.vim          |  5 +++++
 autoload/lsp/lspserver.vim    | 35 +++++++++++++++++++++++++++++++++++
 doc/lsp.txt                   | 21 +++++++++++++++------
 5 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/autoload/lsp/capabilities.vim b/autoload/lsp/capabilities.vim
index ac9b080..5fdb1dd 100644
--- a/autoload/lsp/capabilities.vim
+++ b/autoload/lsp/capabilities.vim
@@ -259,7 +259,7 @@ export def GetClientCaps(): dict<any>
     workspace: {
       workspaceFolders: true,
       applyEdit: true,
-      configuration: false
+      configuration: true
     },
     textDocument: {
       callHierarchy: {
diff --git a/autoload/lsp/handlers.vim b/autoload/lsp/handlers.vim
index c2479e8..a62fbfb 100644
--- a/autoload/lsp/handlers.vim
+++ b/autoload/lsp/handlers.vim
@@ -142,9 +142,11 @@ enddef
 
 # process the workspace/configuration LSP server request
 # Request: "workspace/configuration"
-# Param: none
+# Param: ConfigurationParams
 def ProcessWorkspaceConfiguration(lspserver: dict<any>, request: dict<any>)
-  lspserver.sendResponse(request, {}, {})
+  var items = request.params.items
+  var response = items->map((_, item) => lspserver.workspaceConfigGet(item))
+  lspserver.sendResponse(request, response, {})
 enddef
 
 # process the window/workDoneProgress/create LSP server request
diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim
index 12f4461..f4f6f01 100644
--- a/autoload/lsp/lsp.vim
+++ b/autoload/lsp/lsp.vim
@@ -510,9 +510,14 @@ export def AddServer(serverList: list<dict<any>>)
       server.debug = false
     endif
 
+    if !server->has_key('workspaceConfig')
+      server.workspaceConfig = {}
+    endif
+
     var lspserver: dict<any> = lserver.NewLspServer(server.name, server.path,
 						    args, server.syncInit,
 						    initializationOptions,
+						    server.workspaceConfig,
 						    customNotificationHandlers,
 						    server.debug)
 
diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim
index 2a64da1..01df434 100644
--- a/autoload/lsp/lspserver.vim
+++ b/autoload/lsp/lspserver.vim
@@ -119,6 +119,10 @@ def ServerInitReply(lspserver: dict<any>, initResult: dict<any>): void
 
   # send a "initialized" notification to server
   lspserver.sendInitializedNotif()
+  # send any workspace configuration (optional)
+  if !lspserver.workspaceConfig->empty()
+    lspserver.sendWorkspaceConfig()
+  endif
   lspserver.ready = true
   if exists($'#User#LspServerReady{lspserver.name}')
     exe $'doautocmd <nomodeline> User LspServerReady{lspserver.name}'
@@ -429,6 +433,33 @@ def WaitForResponse(lspserver: dict<any>, req: dict<any>)
   endwhile
 enddef
 
+# Retrieve the Workspace configuration asked by the server.
+# Request: workspace/configuration
+def WorkspaceConfigGet(lspserver: dict<any>, configItem: dict<any>): dict<any>
+  if lspserver.workspaceConfig->empty()
+    return {}
+  endif
+  if !configItem->has_key('section') || configItem.section->empty()
+    return lspserver.workspaceConfig
+  endif
+  var config: dict<any> = lspserver.workspaceConfig
+  for part in configItem.section->split('\.')
+    if !config->has_key(part)
+      return {}
+    endif
+    config = config[part]
+  endfor
+  return config
+enddef
+
+# Send a "workspace/didChangeConfiguration" notification to the language
+# server.
+def SendWorkspaceConfig(lspserver: dict<any>)
+  # Params: DidChangeConfigurationParams
+  var params = {settings: lspserver.workspaceConfig}
+  lspserver.sendNotification('workspace/didChangeConfiguration', params)
+enddef
+
 # Send a file/document opened notification to the language server.
 def TextdocDidOpen(lspserver: dict<any>, bnr: number, ftype: string): void
   # Notification: 'textDocument/didOpen'
@@ -1352,6 +1383,7 @@ enddef
 
 export def NewLspServer(name_arg: string, path_arg: string, args: list<string>,
 			isSync: bool, initializationOptions: any,
+			workspaceConfig: dict<any>,
 			customNotificationHandlers: dict<func>,
 			debug_arg: bool): dict<any>
   var lspserver: dict<any> = {
@@ -1380,6 +1412,7 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list<string>,
     peekSymbolFilePopup: -1,
     callHierarchyType: '',
     selection: {},
+    workspaceConfig: workspaceConfig,
     debug: debug_arg
   }
   lspserver.logfile = $'lsp-{lspserver.name}.log'
@@ -1414,6 +1447,7 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list<string>,
     textdocDidClose: function(TextdocDidClose, [lspserver]),
     textdocDidChange: function(TextdocDidChange, [lspserver]),
     sendInitializedNotif: function(SendInitializedNotif, [lspserver]),
+    sendWorkspaceConfig: function(SendWorkspaceConfig, [lspserver]),
     getCompletion: function(GetCompletion, [lspserver]),
     resolveCompletion: function(ResolveCompletion, [lspserver]),
     gotoDefinition: function(GotoDefinition, [lspserver]),
@@ -1446,6 +1480,7 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list<string>,
     selectionShrink: function(SelectionShrink, [lspserver]),
     foldRange: function(FoldRange, [lspserver]),
     executeCommand: function(ExecuteCommand, [lspserver]),
+    workspaceConfigGet: function(WorkspaceConfigGet, [lspserver]),
     showCapabilities: function(ShowCapabilities, [lspserver])
   })
 
diff --git a/doc/lsp.txt b/doc/lsp.txt
index f0c73d7..d837fc1 100644
--- a/doc/lsp.txt
+++ b/doc/lsp.txt
@@ -250,12 +250,15 @@ To add a language server, the following information is needed:
 			or useful for initialization. Those can be provided in
 			this dictionary and if present will be transmitted to
 			the lsp server.
-						*lsp-cfg-debug*
-	debug		(Optional) log the messages printed by this language
-			server in stdout and stderr to a file.  Useful for
-			debugging a language server.  By default the
-			messages are not logged.  See |lsp-debug| for more
-			information.
+						*lsp-cfg-workspaceConfig*
+	workspaceConfig (Optional) a json encodable value that will be sent to
+			the language server after initialization as the
+			"settings" in a "workspace/didChangeConfiguration"
+			notification.  Refer to the language server
+			documentation for the values that will be accepted in
+			this notification.  This configuration is also used to
+			respond to the "workspace/configuration" request
+			message from the language server.
 
 Aditionally the following configurations can be made:
 
@@ -278,6 +281,12 @@ Aditionally the following configurations can be made:
 			call is used to initialize the language server,
 			otherwise the server is initialized asynchronously.
 			By default this is set to "v:false".
+						*lsp-cfg-debug*
+	debug		(Optional) log the messages printed by this language
+			server in stdout and stderr to a file.  Useful for
+			debugging a language server.  By default the
+			messages are not logged.  See |lsp-debug| for more
+			information.
 
 The language servers are added using the LspAddServer() function. This function
 accepts a list of language servers with the above information.
-- 
2.51.0