Common library code for other vc*.nvim projects.

Add code for gitignore support.

+87
+87
lua/vclib/ignore.lua
··· 1 + local M = {} 2 + 3 + local run = require "vclib.run" 4 + 5 + ---@diagnostic disable-next-line: undefined-field 6 + local stat = vim.uv.fs_stat 7 + 8 + -- This is probably way overkill. 9 + local vcs_root_cache = {} 10 + 11 + ---@param path string 12 + ---@return {type: string, root: string}|nil 13 + local function _get_vcs_root(path) 14 + if vcs_root_cache[path] then 15 + return vcs_root_cache[path] 16 + end 17 + if stat(path .. "/.git") then 18 + vcs_root_cache[path] = { 19 + type = "git", 20 + root = path, 21 + } 22 + return vcs_root_cache[path] 23 + end 24 + if stat(path .. "/.jj") then 25 + vcs_root_cache[path] = { 26 + type = "jj", 27 + root = path, 28 + } 29 + return vcs_root_cache[path] 30 + end 31 + -- Could add more, but this is a good start. 32 + if vim.fs.dirname(path) == path then 33 + -- Reached the root directory without finding a VCS directory. 34 + return nil 35 + end 36 + -- Recursively check the parent directory. 37 + return _get_vcs_root(vim.fs.dirname(path)) 38 + end 39 + 40 + local is_ignored_cache = {} 41 + 42 + -- Check if file should be ignored as per gitignore rules. 43 + function M.is_ignored(path) 44 + if is_ignored_cache[path] ~= nil then 45 + return is_ignored_cache[path] 46 + end 47 + 48 + local absolute_path = vim.fs.normalize(vim.fs.abspath(path)) 49 + 50 + local vcs_root = _get_vcs_root(vim.fs.dirname(absolute_path)) 51 + if vcs_root then 52 + local gitdir 53 + if vcs_root.type == "git" then 54 + gitdir = vcs_root.root .. "/.git" 55 + elseif vcs_root.type == "jj" then 56 + -- I should really read `git_target`, but let's keep this simple... 57 + gitdir = vcs_root.root .. "/.jj/repo/store/git" 58 + else 59 + error("Unknown VCS type: " .. vim.inspect(vcs_root.type)) 60 + end 61 + 62 + local out = run 63 + .run_with_timeout({ 64 + "git", 65 + "--git-dir", 66 + gitdir, 67 + "--work-tree", 68 + vcs_root.root, 69 + "check-ignore", 70 + "--no-index", 71 + absolute_path, 72 + }, {}) 73 + :wait() 74 + if out.code == 0 then 75 + is_ignored_cache[path] = true 76 + return true 77 + end 78 + end 79 + 80 + return false 81 + end 82 + 83 + function M.clear_ignored_cache() 84 + is_ignored_cache = {} 85 + end 86 + 87 + return M