diff --git a/doc/recipes.md b/doc/recipes.md index 3a78a1f..525ddfc 100644 --- a/doc/recipes.md +++ b/doc/recipes.md @@ -30,47 +30,72 @@ require("oil").setup({ }) ``` -## Hide gitignored files +## Hide gitignored files and show git tracked hidden files ```lua -local git_ignored = setmetatable({}, { - __index = function(self, key) - local proc = vim.system( - { "git", "ls-files", "--ignored", "--exclude-standard", "--others", "--directory" }, - { +-- helper function to parse output +local function parse_output(proc) + local result = proc:wait() + local ret = {} + if result.code == 0 then + for line in vim.gsplit(result.stdout, "\n", { plain = true, trimempty = true }) do + -- Remove trailing slash + line = line:gsub("/$", "") + ret[line] = true + end + end + return ret +end + +-- build git status cache +local function new_git_status() + return setmetatable({}, { + __index = function(self, key) + local ignore_proc = vim.system( + { "git", "ls-files", "--ignored", "--exclude-standard", "--others", "--directory" }, + { + cwd = key, + text = true, + } + ) + local tracked_proc = vim.system({ "git", "ls-tree", "HEAD", "--name-only" }, { cwd = key, text = true, + }) + local ret = { + ignored = parse_output(ignore_proc), + tracked = parse_output(tracked_proc), } - ) - local result = proc:wait() - local ret = {} - if result.code == 0 then - for line in vim.gsplit(result.stdout, "\n", { plain = true, trimempty = true }) do - -- Remove trailing slash - line = line:gsub("/$", "") - table.insert(ret, line) - end - end - rawset(self, key, ret) - return ret - end, -}) + rawset(self, key, ret) + return ret + end, + }) +end +local git_status = new_git_status() + +-- Clear git status cache on refresh +local refresh = require("oil.actions").refresh +local orig_refresh = refresh.callback +refresh.callback = function(...) + git_status = new_git_status() + orig_refresh(...) +end require("oil").setup({ view_options = { is_hidden_file = function(name, _) - -- dotfiles are always considered hidden - if vim.startswith(name, ".") then - return true - end local dir = require("oil").get_current_dir() - -- if no local directory (e.g. for ssh connections), always show - if not dir then - return false + local is_dotfile = vim.startswith(name, ".") and name ~= ".." + -- if no local directory (e.g. for ssh connections), just hide dotfiles + if not dir then return is_dotfile end + -- dotfiles are considered hidden unless tracked + if is_dotfile then + return not git_status[dir].tracked[name] + else + -- Check if file is gitignored + return git_status[dir].ignored[name] end - -- Check if file is gitignored - return vim.list_contains(git_ignored[dir], name) end, }, })