Skip to content

Commit

Permalink
perf(files): async find using fs_opendir
Browse files Browse the repository at this point in the history
Switched to fs_opendir, as fs_scandir isn't asynchronous

Also may fix #127
  • Loading branch information
rcarriga committed Oct 10, 2022
1 parent 60bfacd commit 272a22b
Showing 1 changed file with 38 additions and 19 deletions.
57 changes: 38 additions & 19 deletions lua/neotest/lib/file/find.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
local uv = vim.loop
local async = require("neotest.async")
local uv = async.uv
local M = {}
local lib = require("neotest.lib")

local ignored = vim.tbl_add_reverse_lookup({
"node_modules",
})
local async_opendir = async.wrap(function(path, entries, cb)
return vim.loop.fs_opendir(path, cb, entries)
end, 3)

--- Find all files under the given directory.
--- Does not search hidden directories.
Expand All @@ -18,27 +19,45 @@ function M.find(root, opts)
local dirs_to_scan = {}

local paths = {}
local dir, dir_handle = "", uv.fs_scandir(root)
local dir = ""
local max_entries = 1000
local err, dir_handle = async_opendir(root, max_entries)
assert(not err, err)
while dir_handle or #dirs_to_scan > 0 do
if not dir_handle then
dir = table.remove(dirs_to_scan, 1)
dir_handle = uv.fs_scandir(dir)
err, dir_handle = async_opendir(dir, max_entries)
assert(not err, err)
end

local name, path_type = uv.fs_scandir_next(dir_handle)
local rel_path = name and (dir == "" and name or (dir .. sep .. name))
local iter_dir = function()
local pending = {}
return function()
if #pending == 0 then
err, pending = uv.fs_readdir(dir_handle)
assert(not err, err)
if not pending then
uv.fs_closedir(dir_handle)
dir_handle = nil
return nil
end
end
return table.remove(pending)
end
end

if not name then
dir_handle = nil
elseif
path_type == "directory"
and name:sub(1, 1) ~= "."
and not ignored[name]
and (not filter_dir or filter_dir(name, rel_path, root))
then
dirs_to_scan[#dirs_to_scan + 1] = rel_path
elseif path_type == "file" then
paths[#paths + 1] = (root .. sep .. rel_path)
for entry in iter_dir() do
local name, path_type = entry.name, entry.type
local rel_path = name and (dir == "" and name or (dir .. sep .. name))
if
path_type == "directory"
and name:sub(1, 1) ~= "."
and (not filter_dir or filter_dir(name, rel_path, root))
then
dirs_to_scan[#dirs_to_scan + 1] = rel_path
elseif path_type == "file" then
paths[#paths + 1] = (root .. sep .. rel_path)
end
end
end
return paths
Expand Down

0 comments on commit 272a22b

Please sign in to comment.