diff --git a/README.md b/README.md index b6d1f82..3b9af47 100644 --- a/README.md +++ b/README.md @@ -324,6 +324,19 @@ you jump to the definition of `StatelessWidget`, the lsp will not try and index files in that directory. If for some reason you would like this behaviour set `analysisExcludedFolders = {}` You cannot/should not edit the files in the sdk directly so diagnostic analysis of these file is pointless. +The analysis server analyses the whole project found via `root_patterns` (or the whole +[pub workspace](https://dart.dev/tools/pub/workspaces)). If you would rather it only analysed the +packages of the files you have open, you can enable `onlyAnalyzeProjectsWithOpenFiles`, at the cost of +the server rebuilding its analysis roots every time a file is opened or closed: + +```lua +lsp = { + init_options = { + onlyAnalyzeProjectsWithOpenFiles = true, + }, +} +``` + #### Project Configuration It is possible to configure how each project is run using neovim's `exrc` functionality (see `:help exrc`). diff --git a/lua/flutter-tools/lsp/init.lua b/lua/flutter-tools/lsp/init.lua index c10df59..38da84a 100644 --- a/lua/flutter-tools/lsp/init.lua +++ b/lua/flutter-tools/lsp/init.lua @@ -100,7 +100,6 @@ local function get_defaults(opts) or opts.flutter_sdk local config = { init_options = { - onlyAnalyzeProjectsWithOpenFiles = true, suggestFromUnimportedLibraries = true, closingLabels = true, outline = true, @@ -175,7 +174,7 @@ function M.get_project_root_dir(buffer_path) local root_path = lsp_utils.is_valid_path(buffer_path) and path.find_root(conf.root_patterns, buffer_path) or nil - if root_path ~= nil then return root_path end + if root_path ~= nil and not path.is_home_or_fs_root(root_path) then return root_path end end local client = lsp_utils.get_dartls_client() return client and client.config.root_dir or nil @@ -285,11 +284,14 @@ function M.attach() -- This callback can run asynchronously, by which point the user may have -- switched to or deleted the buffer we were asked to attach to. if not api.nvim_buf_is_valid(buf) then return end - c.root_dir = M.get_project_root_dir(buffer_path) + local root_dir = M.get_project_root_dir(buffer_path) or fs.dirname(fs.find(conf.root_patterns, { path = buffer_path, upward = true, })[1]) + -- Without a root, dartls analyses only the packages of the open files + -- instead of everything under the home directory or filesystem root. + if root_dir and not path.is_home_or_fs_root(root_dir) then c.root_dir = root_dir end vim.lsp.start(c, { bufnr = buf }) end) end diff --git a/lua/flutter-tools/utils/path.lua b/lua/flutter-tools/utils/path.lua index def5039..5f1ed47 100644 --- a/lua/flutter-tools/utils/path.lua +++ b/lua/flutter-tools/utils/path.lua @@ -200,6 +200,15 @@ function M.pub_cache_dir() return vim.env.HOME and M.join(vim.env.HOME, ".pub-cache") end +---@param dir string +---@return boolean +function M.is_home_or_fs_root(dir) + local real_dir = vim.fs.normalize(uv.fs_realpath(dir) or dir) + if vim.fs.dirname(real_dir) == real_dir then return true end + local home = uv.os_homedir() + return home ~= nil and real_dir == vim.fs.normalize(uv.fs_realpath(home) or home) +end + ---@param dir string ---@return boolean local function is_flutter_sdk_root(dir) diff --git a/tests/path_spec.lua b/tests/path_spec.lua index 811c7a2..1b0764d 100644 --- a/tests/path_spec.lua +++ b/tests/path_spec.lua @@ -156,3 +156,22 @@ describe("path.is_flutter_dependency_path", function() assert.is_false(path.is_flutter_dependency_path("")) end) end) + +describe("path.is_home_or_fs_root", function() + it( + "should reject the home directory", + function() assert.is_true(path.is_home_or_fs_root(vim.uv.os_homedir())) end + ) + + it("should reject the filesystem root", function() + local fs_root = path.is_windows and "C:\\" or "/" + assert.is_true(path.is_home_or_fs_root(fs_root)) + end) + + it("should accept a project directory", function() + local project = vim.fn.tempname() + vim.fn.mkdir(project, "p") + assert.is_false(path.is_home_or_fs_root(project)) + vim.fn.delete(project, "rf") + end) +end)