diff --git a/doc/VectorCode.txt b/doc/VectorCode.txt index 54dc416e..a152bddc 100644 --- a/doc/VectorCode.txt +++ b/doc/VectorCode.txt @@ -1,4 +1,4 @@ -*VectorCode.txt* For Last change: 2025 March 27 +*VectorCode.txt* For Last change: 2025 March 28 ============================================================================== Table of Contents *VectorCode-table-of-contents* @@ -324,7 +324,13 @@ interface: 1. The `default` backend which works exactly like the original implementation used in previous versions; 2. The `lsp` based backend, which make use of the experimental `vectorcode-server` -implemented in version 0.4.0. +implemented in version 0.4.0. If you want to customise the LSP executable or +any options supported by `vim.lsp.ClientConfig`, you can do so by using +`vim.lsp.config()` or +nvim-lspconfig . The LSP will +attempt to read configurations from these 2 sources before it starts. (If +`vim.lsp.config.vectorcode_server` is not `nil`, this will be used and +nvim-lspconfig will be ignored.) ------------------------------------------------------------------------------- Features default lsp diff --git a/docs/neovim.md b/docs/neovim.md index 679fc8e6..40922d50 100644 --- a/docs/neovim.md +++ b/docs/neovim.md @@ -293,7 +293,13 @@ interface: 1. The `default` backend which works exactly like the original implementation used in previous versions; 2. The `lsp` based backend, which make use of the experimental `vectorcode-server` - implemented in version 0.4.0. + implemented in version 0.4.0. If you want to customise the LSP executable or + any options supported by `vim.lsp.ClientConfig`, you can do so by using + `vim.lsp.config()` or + [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig). The LSP will + attempt to read configurations from these 2 sources before it starts. (If + `vim.lsp.config.vectorcode_server` is not `nil`, this will be used and + nvim-lspconfig will be ignored.) | Features | `default` | `lsp` | diff --git a/lua/vectorcode/cacher/lsp.lua b/lua/vectorcode/cacher/lsp.lua index 9c0e4106..059bcd61 100644 --- a/lua/vectorcode/cacher/lsp.lua +++ b/lua/vectorcode/cacher/lsp.lua @@ -35,66 +35,8 @@ end ---@return boolean local function is_lsp_running() - local clients = vim.lsp.get_clients({ name = "vectorcode_server" }) - if #clients == 0 then - return false - end - client_id = clients[1].id - return true -end - ----@param project_root string? ----@param ok_to_fail boolean? ----@return boolean -local function start_server(project_root, ok_to_fail) - if is_lsp_running() then - return true - end - - if ok_to_fail == nil then - ok_to_fail = true - end - local cmd = { "vectorcode-server" } - if - type(project_root) == "string" - and vim.list_contains({ "directory" }, vim.uv.fs_stat(project_root).type) - then - vim.list_extend(cmd, { "--project_root", project_root }) - else - local try_root = vim.fs.root(".", ".vectorcode") or vim.fs.root(".", ".git") - if try_root ~= nil then - vim.list_extend(cmd, { "--project_root", try_root }) - else - vim.schedule(function() - vim.notify( - "Failed to start vectorcode-server due to failing to resolve the project root.", - vim.log.levels.ERROR, - notify_opts - ) - end) - return false - end - end - local id, err = vim.lsp.start_client({ - name = "vectorcode_server", - cmd = cmd, - }) - - if err ~= nil and (vc_config.get_user_config().notify or not ok_to_fail) then - vim.schedule(function() - vim.notify( - ("Failed to start vectorcode-server due to the following error:\n%s"):format( - err - ), - vim.log.levels.ERROR, - notify_opts - ) - end) - return false - else - client_id = id - return true - end + client_id = job_runner.init() + return client_id ~= nil end ---@type table @@ -223,13 +165,7 @@ M.register_buffer = vc_config.check_cli_wrap( opts = vim.tbl_deep_extend("force", vc_config.get_user_config().async_opts, opts or {}) - if - not start_server(opts.project_root or vim.api.nvim_buf_get_name(bufnr), false) - then - -- failed to start the server - return false - end - assert(client_id ~= nil) + assert(is_lsp_running()) if CACHE[bufnr] ~= nil then -- update the options and/or query_cb diff --git a/lua/vectorcode/config.lua b/lua/vectorcode/config.lua index 7f21cdf1..8cb60916 100644 --- a/lua/vectorcode/config.lua +++ b/lua/vectorcode/config.lua @@ -18,6 +18,23 @@ local config = { on_setup = { update = false, lsp = false }, } +---@return vim.lsp.ClientConfig +local lsp_configs = function() + local cfg = + { cmd = { "vectorcode-server" }, root_markers = { ".vectorcode", ".git" } } + if vim.lsp.config ~= nil and vim.lsp.config.vectorcode_server ~= nil then + -- nvim >= 0.11.0 + cfg = vim.tbl_deep_extend("force", cfg, vim.lsp.config.vectorcode_server) + else + -- nvim < 0.11.0 + local ok, lspconfig = pcall(require, "lspconfig.configs") + if ok and lspconfig.vectorcode_server ~= nil then + cfg = lspconfig.vectorcode_server.config_def.default_config + end + end + return cfg +end + local setup_config = vim.deepcopy(config, true) local notify_opts = { title = "VectorCode" } @@ -55,11 +72,12 @@ local startup_handler = check_cli_wrap(function(configs) end) end if configs.on_setup.lsp then - local lsp_module = require("vectorcode.jobrunner.lsp") - if type(lsp_module) == "table" then - -- this will trigger the private `get_client` function in the runner and hence start the LSP - lsp_module.is_job_running(0) + local ok, runner = pcall(require, "vectorcode.jobrunner.lsp") + if not ok or not type(runner) == "table" or runner == nil then + vim.notify("Failed to start vectorcode-server.", vim.log.levels.WARN, notify_opts) + return end + runner.init() end end) @@ -135,4 +153,6 @@ return { has_cli = has_cli, check_cli_wrap = check_cli_wrap, + + lsp_configs = lsp_configs, } diff --git a/lua/vectorcode/jobrunner/init.lua b/lua/vectorcode/jobrunner/init.lua index f2a9245c..f13a436e 100644 --- a/lua/vectorcode/jobrunner/init.lua +++ b/lua/vectorcode/jobrunner/init.lua @@ -7,6 +7,7 @@ local utils = require("vectorcode.utils") ---@field run fun(args: string[], timeout_ms: integer?, bufnr: integer):(result:table, error:table) ---@field is_job_running fun(job_handle: integer):boolean ---@field stop_job fun(job_handle: integer) +---@field init function? return { --- Automatically find project_root from buffer path if it's not already specified. diff --git a/lua/vectorcode/jobrunner/lsp.lua b/lua/vectorcode/jobrunner/lsp.lua index 3b073663..0c526039 100644 --- a/lua/vectorcode/jobrunner/lsp.lua +++ b/lua/vectorcode/jobrunner/lsp.lua @@ -14,55 +14,33 @@ local CLIENT = nil local vc_config = require("vectorcode.config") local notify_opts = vc_config.notify_opts +--- Returns the Client ID if applicable, or `nil` if the language server fails to start ---@param ok_to_fail boolean -local function get_client(ok_to_fail) +---@return integer? +function jobrunner.init(ok_to_fail) ok_to_fail = ok_to_fail or true - if #vim.lsp.get_clients({ name = "vectorcode_server" }) > 0 then - CLIENT = vim.lsp.get_clients({ name = "vectorcode_server" })[1] + local client_id = vim.lsp.start(vc_config.lsp_configs(), {}) + if client_id ~= nil then + -- server started + CLIENT = vim.lsp.get_client_by_id(client_id) --[[@as vim.lsp.Client]] else - local cmd = { "vectorcode-server" } - - local try_root = vim.fs.root(".", ".vectorcode") or vim.fs.root(".", ".git") - if try_root ~= nil then - vim.list_extend(cmd, { "--project_root", try_root }) - else + -- failed to start server + if vc_config.get_user_config().notify or not ok_to_fail then vim.schedule(function() vim.notify( - "Failed to start vectorcode-server due to failing to resolve the project root.", + "Failed to start vectorcode-server due some error.", vim.log.levels.ERROR, notify_opts ) end) - return false - end - local id, err = vim.lsp.start_client({ - name = "vectorcode_server", - cmd = cmd, - }) - - if err ~= nil and (vc_config.get_user_config().notify or not ok_to_fail) then - vim.schedule(function() - vim.notify( - ("Failed to start vectorcode-server due to the following error:\n%s"):format( - err - ), - vim.log.levels.ERROR, - notify_opts - ) - end) - return false - elseif id ~= nil then - local cli = vim.lsp.get_client_by_id(id) - if cli ~= nil then - CLIENT = cli - return true - end end + return nil end + return client_id end function jobrunner.run(args, timeout_ms, bufnr) - get_client(false) + jobrunner.init(false) assert(CLIENT ~= nil) assert(bufnr ~= nil) if timeout_ms == nil or timeout_ms < 0 then @@ -85,7 +63,7 @@ function jobrunner.run(args, timeout_ms, bufnr) end function jobrunner.run_async(args, callback, bufnr) - get_client(false) + jobrunner.init(false) assert(CLIENT ~= nil) assert(bufnr ~= nil) @@ -106,7 +84,7 @@ function jobrunner.run_async(args, callback, bufnr) end end args = require("vectorcode.jobrunner").find_root(args, bufnr) - local _, id = CLIENT.request( + local _, id = CLIENT:request( vim.lsp.protocol.Methods.workspace_executeCommand, { command = "vectorcode", arguments = args }, function(err, result, _, _) @@ -124,7 +102,7 @@ function jobrunner.run_async(args, callback, bufnr) end function jobrunner.is_job_running(job_handler) - get_client(true) + jobrunner.init(true) if CLIENT ~= nil then local request_data = CLIENT.requests[job_handler] return request_data ~= nil and request_data.type == "pending" @@ -133,9 +111,9 @@ function jobrunner.is_job_running(job_handler) end function jobrunner.stop_job(job_handler) - get_client(true) + jobrunner.init(true) if CLIENT ~= nil then - CLIENT.cancel_request(job_handler) + CLIENT:cancel_request(job_handler) end end