From 65fc04d03fb802a1ca32cf7b971c0758c5b2ead8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3n=C3=A1n=20Carrigan?= Date: Sat, 10 Sep 2022 23:43:09 +0100 Subject: [PATCH] feat(client): control concurrent discovery See #13 --- doc/neotest.txt | 4 ++-- lua/neotest/client/init.lua | 43 +++++++++++++------------------------ lua/neotest/config/init.lua | 29 ++++++++++++++++++++----- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/doc/neotest.txt b/doc/neotest.txt index 2a968b7c..9ef95f81 100644 --- a/doc/neotest.txt +++ b/doc/neotest.txt @@ -59,7 +59,7 @@ Default values: enabled = true }, discovery = { - concurrent = true, + concurrent = 0, enabled = true }, floating = { @@ -187,7 +187,7 @@ Class~ {neotest.Config.discovery} Fields~ {enabled} `(boolean)` -{concurrent} `(boolean)` Parse files concurrently. Disable if experiencing performance issues. +{concurrent} `(integer)` Number of workers to parse files concurrently. 0 automatically assigns number based on CPU. Set to 1 if experiencing lag. Class~ {neotest.Config.running} diff --git a/lua/neotest/client/init.lua b/lua/neotest/client/init.lua index 6e7ed3bf..3dff1778 100644 --- a/lua/neotest/client/init.lua +++ b/lua/neotest/client/init.lua @@ -244,47 +244,34 @@ function NeotestClient:_update_positions(path, args) end end local files = lib.func_util.filter_list(adapter.is_test_file, lib.files.find(path)) - return lib.files.parse_dir_from_files(path, files) + local positions = lib.files.parse_dir_from_files(path, files) + self._state:update_positions(adapter_id, positions) + self:_parse_files(adapter_id, path, files) else - return adapter.discover_positions(path) + local positions = adapter.discover_positions(path) + if positions then + self._state:update_positions(adapter_id, positions) + end end end) if not success or not positions then logger.error("Couldn't find positions in path", path, positions) return end - self._state:update_positions(adapter_id, positions) - - if positions:data().type == "dir" then - self:_parse_dir_files(path, adapter_id) - end end -function NeotestClient:_parse_dir_files(path, adapter_id) - local tree = assert(self._state:positions(adapter_id, path)) - local parse_funcs = {} - for _, node in tree:iter_nodes() do - local pos = node:data() - if pos.type == "file" and #node:children() == 0 then - table.insert(parse_funcs, function() - self:_update_positions(pos.id, { adapter = adapter_id }) - end) +function NeotestClient:_parse_files(adapter_id, root, paths) + local function worker() + while #paths > 0 do + self:_update_positions(table.remove(paths), { adapter = adapter_id }) end end - if #parse_funcs == 0 then - return - end - - local root = tree:data().path - - if config.projects[root].discovery.concurrent then - async.util.join(parse_funcs) - else - for _, func in ipairs(parse_funcs) do - func() - end + local workers = {} + for _ = 1, config.projects[root].discovery.concurrent do + table.insert(workers, worker) end + async.util.join(workers) end ---@private diff --git a/lua/neotest/config/init.lua b/lua/neotest/config/init.lua index 272906e2..c4e7d77a 100644 --- a/lua/neotest/config/init.lua +++ b/lua/neotest/config/init.lua @@ -19,7 +19,7 @@ local function define_highlights() hi default NeotestMarked ctermfg=Brown guifg=#F79000 gui=bold hi default NeotestTarget ctermfg=Red guifg=#F70067 hi default link NeotestUnknown Normal -]]) +]] ) end local augroup = vim.api.nvim_create_augroup("NeotestColorSchemeRefresh", {}) @@ -45,7 +45,7 @@ define_highlights() ---@class neotest.Config.discovery ---@field enabled boolean ----@field concurrent boolean Parse files concurrently. Disable if experiencing performance issues. +---@field concurrent integer Number of workers to parse files concurrently. 0 automatically assigns number based on CPU. Set to 1 if experiencing lag. ---@class neotest.Config.running ---@field concurrent boolean Run tests concurrently when an adapter provides multiple commands to run @@ -101,7 +101,7 @@ local default_config = { adapters = {}, discovery = { enabled = true, - concurrent = true, + concurrent = 0, }, running = { concurrent = true, @@ -202,18 +202,35 @@ local user_config = default_config ---@type neotest.Config local NeotestConfigModule = {} +local convert_concurrent = function(val) + if val == 0 or val == true then + return #vim.loop.cpu_info() + 4 + end + if val == false then + return 1 + end + assert(type(val) == "number", "concurrent must be a boolean or a number") + return val +end + ---@param config neotest.Config ---@private function NeotestConfigModule.setup(config) user_config = vim.tbl_deep_extend("force", default_config, config) + --- Avoid mutating default for docgen + user_config.discovery = vim.tbl_deep_extend( + "force", + user_config.discovery, + { concurrent = convert_concurrent(user_config.discovery.concurrent) } + ) user_config.projects = setmetatable({}, { - __index = function(_, key) + __index = function() return user_config end, }) for project_root, project_config in pairs(config.projects or {}) do - NeotestConfigModule.setup_project(project_root, config) + NeotestConfigModule.setup_project(project_root, project_config) end end @@ -225,6 +242,8 @@ function NeotestConfigModule.setup_project(project_root, config) discovery = user_config.discovery, running = user_config.running, }) + user_config.projects[path].discovery.concurrent = + convert_concurrent(user_config.projects[path].discovery.concurrent) end function NeotestConfigModule._format_default()