From 36c7ed2b678f352c9938da3188ad3f689cd1a7bb Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sun, 26 Jan 2025 22:26:53 +0100 Subject: add language server configuration to its object table --- init.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'init.lua') diff --git a/init.lua b/init.lua index a47ad22..865d35a 100644 --- a/init.lua +++ b/init.lua @@ -1280,7 +1280,10 @@ local function find_root_uri(ls, file_path) end local function ls_start(ls, init_options) - ls.fd = vis:communicate(ls.name, 'exec ' .. ls.cmd) + ls.fd = vis:communicate(ls.name, 'exec ' .. ls.conf.cmd) + + -- detect the workspace root + ls.rootUri = vis.win.file and find_root_uri(ls, vis.win.file.path) -- register the response handler vis.events.subscribe(vis.events.PROCESS_RESPONSE, function(name, event, code, msg) @@ -1310,7 +1313,7 @@ local function ls_start(ls, init_options) local params = { processId = vis_pid, clientInfo = {name = lspc.name, version = lspc.version}, - rootUri = (vis.win.file and find_root_uri(ls, vis.win.file.path)) or lspc.json.null, + rootUri = ls.rootUri or lspc.json.null, capabilities = lspc.client_capabilites, } @@ -1324,10 +1327,8 @@ end function LanguageServer.new(ls_conf) local ls = { name = ls_conf.name, - cmd = ls_conf.cmd, - settings = ls_conf.settings, - roots = ls_conf.roots, - formatting_options = ls_conf.formatting_options, + conf = ls_conf, + initialized = false, id = 0, inflight = {}, @@ -1635,7 +1636,7 @@ vis:command_register('lspc-format', function(argv, _, win) local params = { textDocument = {uri = path_to_uri(win.file.path)}, - options = ls.formatting_options, + options = ls.conf.formatting_options, } if params.options == nil then params.options = { -- cgit v1.2.3 From 4c3bce82fad31b67d0d8fe00c17a0ea66c4ad9d1 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Mon, 27 Jan 2025 09:40:44 +0100 Subject: implement more sophisticated settings --- init.lua | 65 +++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 19 deletions(-) (limited to 'init.lua') diff --git a/init.lua b/init.lua index 865d35a..b433b12 100644 --- a/init.lua +++ b/init.lua @@ -34,6 +34,9 @@ local parser = dofile(source_path .. 'parser.lua') -- initialise the util module local util = dofile(source_path .. 'util.lua').init(lspc) +-- initialise the settings module +local settings = dofile(source_path .. 'settings.lua').init(lspc) + -- load a suitable json module lspc.json = dofile(source_path .. 'json.lua') @@ -85,7 +88,9 @@ end -- map of known language servers per syntax lspc.ls_map = dofile(source_path .. 'supported-servers.lua') --- return the name of the language server for this syntax +--- Return the name of the language server for this syntax +-- @param syntax the syntax the language server should support +-- @return the name of the languauge server configured for syntax local function get_ls_name_for_syntax(syntax) local ls_def = lspc.ls_map[syntax] if not ls_def then @@ -951,15 +956,24 @@ local function lspc_handle_initialize_response(ls, result) -- According to nvim-lspconfig sendig the lsp server settings shortly after -- initialization is an undocumented convention. -- See https://github.com/neovim/nvim-lspconfig/blob/ed88435764d8b00442e66d39ec3d9c360e560783/CONTRIBUTING.md - if ls.settings then - ls:send_notification('workspace/didChangeConfiguration', { - settings = ls.settings, - }) - end + lspc:log('Loading settings for ' .. ls.name) + ls:send_default_settings() vis.events.emit(lspc.events.LS_INITIALIZED, ls) end +--- Send didChangeConfiguration notification with the default settings +function LanguageServer:send_default_settings() + -- Use the rootUri or the open file's path as scope for the initial settings + local scope = self.rootUri or vis.win.file and vis.win.file.path + local effective_ls_settings = settings.effective_settings(self, nil, scope) + if effective_ls_settings then + self:send_notification('workspace/didChangeConfiguration', { + settings = effective_ls_settings, + }) + end +end + --- Dispatch method response from the server -- @param method_response the response send from the server -- @param req the request causing this response @@ -1027,20 +1041,15 @@ function LanguageServer:handle_method_response(method_response, req) self.inflight[method_response.id] = nil end +--- Handle a workspace/configuration request from a server +-- @param params the parameters send with the request +-- @param response the response we are about to send local function lspc_handle_workspace_configuration_call(ls, params, response) local results = {} for _, item in ipairs(params.items) do - -- de-flatten the section and map it to our settings if one is present. - if item.section then - local t = ls.settings - for k in item.section:gmatch('[^.]+') do - if not t then - break - end - t = t[k] - end - table.insert(results, t or lspc.json.null) - end + local scope = item.scopeUri and uri_to_path(item.scopeUri) + local effective_settings = settings.effective_settings(ls, item.section, scope) + table.insert(results, effective_settings) end response.result = results end @@ -1161,8 +1170,11 @@ function LanguageServer:recv_data(data) end end --- check if a language server is running and initialized -local function lspc_get_usable_ls(win, explicit_syntax) +--- Return a running language server +-- @param win the window for which the language server might be running +-- @param explicit_syntax the syntax if different from win.syntax +-- @return a running language server or nil and an error message +function lspc.get_running_ls(win, explicit_syntax) local ls local syntax = explicit_syntax or (win and win.syntax) -- try to use the first language server managing the current file @@ -1187,6 +1199,21 @@ local function lspc_get_usable_ls(win, explicit_syntax) end end + return ls +end + +--- Return a running and initialized language server +-- @param win the window for which the language server might be running +-- @param explicit_syntax the syntax if different from win.syntax +-- @return a running and initialized language server or nil and an error message +local function lspc_get_usable_ls(win, explicit_syntax) + local ls, err = lspc.get_running_ls(win, explicit_syntax) + + if err then + return nil, err + end + + assert(ls) if not ls.initialized then return nil, 'Language server ' .. ls.name .. ' not initialized yet. Please try again' end -- cgit v1.2.3 From 22dee48bad475064616dabf8122c2d7bc1444f72 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Wed, 13 Aug 2025 14:03:26 +0200 Subject: settings: do not send empty settings arrays to the server LSP requires that the result array of a workspace/configure call must include null if the client can not provide any configuration. --- init.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'init.lua') diff --git a/init.lua b/init.lua index b433b12..9a40bf9 100644 --- a/init.lua +++ b/init.lua @@ -967,7 +967,7 @@ function LanguageServer:send_default_settings() -- Use the rootUri or the open file's path as scope for the initial settings local scope = self.rootUri or vis.win.file and vis.win.file.path local effective_ls_settings = settings.effective_settings(self, nil, scope) - if effective_ls_settings then + if next(effective_ls_settings) then self:send_notification('workspace/didChangeConfiguration', { settings = effective_ls_settings, }) @@ -1049,7 +1049,12 @@ local function lspc_handle_workspace_configuration_call(ls, params, response) for _, item in ipairs(params.items) do local scope = item.scopeUri and uri_to_path(item.scopeUri) local effective_settings = settings.effective_settings(ls, item.section, scope) - table.insert(results, effective_settings) + -- If we can not provide any settings LSP requires that null is present in the result array. + if next(effective_settings) then + table.insert(results, effective_settings) + else + table.insert(results, nil) + end end response.result = results end -- cgit v1.2.3