telescope-frecency.nvim/lua/frecency/fs.lua
JINNOUCHI Yasushi 58c0089414
fix!: register realpath for consistency (#240)
Now it uses realpath for registering and validating DB. This means, if you have entries that has filenames differing only for case, it can deal with them as they exist.

Before this, it has miscalculated scores for such cases. For example, in case you have `/path/to/foo.lua` and `/path/to/Foo.lua`, it registers entries for each file. Now it detects accurate filename for the specified one, and removes it in validation.

* test: separate logic for utils

* fix!: register realpath for consistency

* refactor: convert fs module from class

* refactor: move db initialization phase to start()

* fix: run database:start() truly asynchronously

* fix: call each functions with async wrapping

* refactor: add types for args in command

* fix: run register() synchronously

Because vim.api.nvim_* cannot be used in asynchronous functions.

* docs: add note for calling setup() twice

* fix: run non-fast logic on next tick
2024-08-15 17:40:03 +09:00

101 lines
2.3 KiB
Lua

local config = require "frecency.config"
local os_util = require "frecency.os_util"
local log = require "frecency.log"
local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]]
local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]]
local scandir = require "plenary.scandir"
local uv = vim.uv or vim.loop
local M = {
os_homedir = assert(uv.os_homedir()),
}
-- TODO: make this configurable
local SCAN_DEPTH = 100
---@param path string
---@return boolean
function M.is_ignored(path)
for _, regex in ipairs(config.ignore_regexes()) do
if path:find(regex) then
return true
end
end
return false
end
---@async
---@param path? string
---@return boolean
function M.is_valid_path(path)
if not path then
return false
end
local err, st = async.uv.fs_stat(path)
return not err and st.type == "file" and not M.is_ignored(path)
end
---@param path string
---@return function
function M.scan_dir(path)
log.debug { path = path }
local gitignore = M.make_gitignore(path)
return coroutine.wrap(function()
for name, type in
vim.fs.dir(path, {
depth = SCAN_DEPTH,
skip = function(dirname)
if M.is_ignored(os_util.join_path(path, dirname)) then
return false
end
end,
})
do
local fullpath = os_util.join_path(path, name)
if type == "file" and not M.is_ignored(fullpath) and gitignore({ path }, fullpath) then
coroutine.yield(name)
end
end
end)
end
---@param path string
---@return string
function M.relative_from_home(path)
return Path:new(path):make_relative(M.os_homedir)
end
---@type table<string,string>
local with_sep = {}
---@param path string
---@param base? string
---@return boolean
function M.starts_with(path, base)
if not base then
return true
end
if not with_sep[base] then
with_sep[base] = base .. (base:sub(#base) == Path.path.sep and "" or Path.path.sep)
end
return path:find(with_sep[base], 1, true) == 1
end
---@async
---@param path string
---@return boolean
function M.exists(path)
return not (async.uv.fs_stat(path))
end
---@private
---@param basepath string
---@return fun(base_paths: string[], entry: string): boolean
function M.make_gitignore(basepath)
return scandir.__make_gitignore { basepath } or function(_, _)
return true
end
end
return M