mirror of
https://github.com/kristoferssolo/telescope-frecency.nvim.git
synced 2025-10-21 20:10:38 +00:00
* refactor: use vim.pesc instead of implementing * feat: add optional func to ignore in registering * test: add tests for ignore_register function * docs: add note for `ignore_register` option * docs: add note for use case of `ignore_patterns`
106 lines
2.7 KiB
Lua
106 lines
2.7 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 scandir = require "plenary.scandir"
|
|
local uv = vim.uv or vim.loop
|
|
|
|
---@class FrecencyFS
|
|
---@field os_homedir string
|
|
---@field private config FrecencyFSConfig
|
|
---@field private ignore_regexes string[]
|
|
local FS = {}
|
|
|
|
---@class FrecencyFSConfig
|
|
---@field scan_depth integer?
|
|
|
|
---@param fs_config? FrecencyFSConfig
|
|
---@return FrecencyFS
|
|
FS.new = function(fs_config)
|
|
local self= setmetatable(
|
|
{ config = vim.tbl_extend("force", { scan_depth = 100 }, fs_config or {}), os_homedir = assert(uv.os_homedir()) },
|
|
{ __index = FS }
|
|
)
|
|
---@param pattern string
|
|
self.ignore_regexes = vim.tbl_map(function(pattern)
|
|
local regex = vim.pesc(pattern):gsub("%%%*", ".*"):gsub("%%%?", ".")
|
|
return "^" .. regex .. "$"
|
|
end, config.ignore_patterns)
|
|
return self
|
|
end
|
|
|
|
---@param path? string
|
|
---@return boolean
|
|
function FS:is_valid_path(path)
|
|
return not not path and Path:new(path):is_file() and not self:is_ignored(path)
|
|
end
|
|
|
|
---@param path string
|
|
---@return function
|
|
function FS:scan_dir(path)
|
|
log.debug { path = path }
|
|
local gitignore = self:make_gitignore(path)
|
|
return coroutine.wrap(function()
|
|
for name, type in
|
|
vim.fs.dir(path, {
|
|
depth = self.config.scan_depth,
|
|
skip = function(dirname)
|
|
if self: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 self:is_ignored(fullpath) and gitignore({ path }, fullpath) then
|
|
coroutine.yield(name)
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
---@param path string
|
|
---@return string
|
|
function FS:relative_from_home(path)
|
|
return Path:new(path):make_relative(self.os_homedir)
|
|
end
|
|
|
|
---@type table<string,string>
|
|
local with_sep = {}
|
|
|
|
---@param path string
|
|
---@param base? string
|
|
---@return boolean
|
|
function FS: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
|
|
|
|
---@private
|
|
---@param path string
|
|
---@return boolean
|
|
function FS:is_ignored(path)
|
|
for _, regex in ipairs(self.ignore_regexes) do
|
|
if path:find(regex) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
---@private
|
|
---@param basepath string
|
|
---@return fun(base_paths: string[], entry: string): boolean
|
|
function FS:make_gitignore(basepath)
|
|
return scandir.__make_gitignore { basepath } or function(_, _)
|
|
return true
|
|
end
|
|
end
|
|
|
|
return FS
|