diff --git a/CHANGELOG.md b/CHANGELOG.md index 758efb2b..673e57ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Config: Add a new `config.server.root_dir` option to override the root + directory detection logic + ## [4.23.5] - 2024-05-24 ### Fixed diff --git a/doc/rustaceanvim.txt b/doc/rustaceanvim.txt index 9da43f53..6e6234c3 100644 --- a/doc/rustaceanvim.txt +++ b/doc/rustaceanvim.txt @@ -234,12 +234,13 @@ RustcOpts *RustcOpts* RustaceanLspClientOpts *RustaceanLspClientOpts* Fields: ~ - {auto_attach?} (boolean|fun(bufnr:integer):boolean) Whether to automatically attach the LSP client. Defaults to `true` if the `rust-analyzer` executable is found. - {cmd?} (string[]|fun():string[]) Command and arguments for starting rust-analyzer - {settings?} (table|fun(project_root:string|nil,default_settings:table):table) Setting passed to rust-analyzer. Defaults to a function that looks for a `rust-analyzer.json` file or returns an empty table. See https://rust-analyzer.github.io/manual.html#configuration. - {standalone?} (boolean) Standalone file support (enabled by default). Disabling it may improve rust-analyzer's startup time. - {logfile?} (string) The path to the rust-analyzer log file. - {load_vscode_settings?} (boolean) Whether to search (upward from the buffer) for rust-analyzer settings in .vscode/settings json. If found, loaded settings will override configured options. Default: false + {auto_attach?} (boolean|fun(bufnr:integer):boolean) Whether to automatically attach the LSP client. Defaults to `true` if the `rust-analyzer` executable is found. + {cmd?} (string[]|fun():string[]) Command and arguments for starting rust-analyzer + {root_dir?} (string|fun(filename:string,default:fun(filename:string):string|nil):string|nil) The directory to use for the attached LSP. Can be a function, which may return nil if no server should attach. The second argument contains the default implementation, which can be used for fallback behavior. + {settings?} (table|fun(project_root:string|nil,default_settings:table):table) Setting passed to rust-analyzer. Defaults to a function that looks for a `rust-analyzer.json` file or returns an empty table. See https://rust-analyzer.github.io/manual.html#configuration. + {standalone?} (boolean) Standalone file support (enabled by default). Disabling it may improve rust-analyzer's startup time. + {logfile?} (string) The path to the rust-analyzer log file. + {load_vscode_settings?} (boolean) Whether to search (upward from the buffer) for rust-analyzer settings in .vscode/settings json. If found, loaded settings will override configured options. Default: false RustaceanDapOpts *RustaceanDapOpts* diff --git a/lua/rustaceanvim/cargo.lua b/lua/rustaceanvim/cargo.lua index f8ef7130..f12d130d 100644 --- a/lua/rustaceanvim/cargo.lua +++ b/lua/rustaceanvim/cargo.lua @@ -27,13 +27,29 @@ local function get_mb_active_client_root(file_name) end end +---Attempts to find the root for an existing active client. If no existing +---client root is found, returns the result of evaluating `config.root_dir`. +---@param config RustaceanLspClientConfig ---@param file_name string ---@return string | nil root_dir -function cargo.get_root_dir(file_name) +function cargo.get_config_root_dir(config, file_name) local reuse_active = get_mb_active_client_root(file_name) if reuse_active then return reuse_active end + + local config_root_dir = config.root_dir + if type(config_root_dir) == 'function' then + return config_root_dir(file_name, cargo.get_root_dir) + else + return config_root_dir + end +end + +---The default implementation used for `vim.g.rustaceanvim.server.root_dir` +---@param file_name string +---@return string | nil root_dir +function cargo.get_root_dir(file_name) local path = file_name:find('%.rs$') and vim.fs.dirname(file_name) or file_name if not path then return nil diff --git a/lua/rustaceanvim/config/check.lua b/lua/rustaceanvim/config/check.lua index 41910d83..cd5aa025 100644 --- a/lua/rustaceanvim/config/check.lua +++ b/lua/rustaceanvim/config/check.lua @@ -89,6 +89,7 @@ function M.validate(cfg) cmd = { server.cmd, { 'function', 'table' } }, standalone = { server.standalone, 'boolean' }, settings = { server.settings, { 'function', 'table' }, true }, + root_dir = { server.root_dir, { 'function', 'string' } }, }) if not ok then return false, err diff --git a/lua/rustaceanvim/config/init.lua b/lua/rustaceanvim/config/init.lua index 124a404a..5b2fe2c7 100644 --- a/lua/rustaceanvim/config/init.lua +++ b/lua/rustaceanvim/config/init.lua @@ -110,6 +110,7 @@ vim.g.rustaceanvim = vim.g.rustaceanvim ---@class RustaceanLspClientOpts ---@field auto_attach? boolean | fun(bufnr: integer):boolean Whether to automatically attach the LSP client. Defaults to `true` if the `rust-analyzer` executable is found. ---@field cmd? string[] | fun():string[] Command and arguments for starting rust-analyzer +---@field root_dir? string | fun(filename: string, default: fun(filename: string):string|nil):string|nil The directory to use for the attached LSP. Can be a function, which may return nil if no server should attach. The second argument contains the default implementation, which can be used for fallback behavior. ---@field settings? table | fun(project_root:string|nil, default_settings: table):table Setting passed to rust-analyzer. Defaults to a function that looks for a `rust-analyzer.json` file or returns an empty table. See https://rust-analyzer.github.io/manual.html#configuration. ---@field standalone? boolean Standalone file support (enabled by default). Disabling it may improve rust-analyzer's startup time. ---@field logfile? string The path to the rust-analyzer log file. diff --git a/lua/rustaceanvim/config/internal.lua b/lua/rustaceanvim/config/internal.lua index 6f9cf45a..8f68710d 100644 --- a/lua/rustaceanvim/config/internal.lua +++ b/lua/rustaceanvim/config/internal.lua @@ -1,4 +1,5 @@ local types = require('rustaceanvim.types.internal') +local cargo = require('rustaceanvim.cargo') local compat = require('rustaceanvim.compat') local config = require('rustaceanvim.config') local executors = require('rustaceanvim.executors') @@ -275,6 +276,10 @@ local RustaceanDefaultConfig = { cmd = function() return { 'rust-analyzer', '--log-file', RustaceanConfig.server.logfile } end, + + ---@type string | fun(filename: string, default: fun(filename: string):string|nil):string|nil + root_dir = cargo.get_root_dir, + --- standalone file support --- setting it to false may improve startup time ---@type boolean diff --git a/lua/rustaceanvim/lsp.lua b/lua/rustaceanvim/lsp.lua index 1efa5daa..00c73b91 100644 --- a/lua/rustaceanvim/lsp.lua +++ b/lua/rustaceanvim/lsp.lua @@ -95,7 +95,7 @@ M.start = function(bufnr) local client_config = config.server ---@type LspStartConfig local lsp_start_config = vim.tbl_deep_extend('force', {}, client_config) - local root_dir = cargo.get_root_dir(bufname) + local root_dir = cargo.get_config_root_dir(client_config, bufname) if not root_dir then --- No project root found. Start in detached/standalone mode. root_dir = vim.fs.dirname(bufname) diff --git a/lua/rustaceanvim/neotest/init.lua b/lua/rustaceanvim/neotest/init.lua index 9eb7cbae..7921cd3c 100644 --- a/lua/rustaceanvim/neotest/init.lua +++ b/lua/rustaceanvim/neotest/init.lua @@ -27,12 +27,13 @@ ---@diagnostic disable: duplicate-set-field +local cargo = require('rustaceanvim.cargo') +local compat = require('rustaceanvim.compat') +local config = require('rustaceanvim.config.internal') local lib = require('neotest.lib') local nio = require('nio') -local trans = require('rustaceanvim.neotest.trans') -local cargo = require('rustaceanvim.cargo') local overrides = require('rustaceanvim.overrides') -local compat = require('rustaceanvim.compat') +local trans = require('rustaceanvim.neotest.trans') ---@package ---@type neotest.Adapter @@ -42,7 +43,7 @@ local NeotestAdapter = { name = 'rustaceanvim' } ---@param file_name string ---@return string | nil NeotestAdapter.root = function(file_name) - return cargo.get_root_dir(file_name) + return cargo.get_config_root_dir(config.server, file_name) end ---@package