feat: better handling of ignored files

This commit is contained in:
sxyazi
2024-09-04 23:07:55 +08:00
parent 63beb7528b
commit 0345e859fb
2 changed files with 74 additions and 41 deletions

View File

@@ -1,5 +1,8 @@
# git.yazi # git.yazi
> [!NOTE]
> Yazi v0.3.2 or later is required for this plugin to work.
Show the status of Git file changes as linemode in the file list. Show the status of Git file changes as linemode in the file list.
https://github.com/user-attachments/assets/34976be9-a871-4ffe-9d5a-c4cdd0bf4576 https://github.com/user-attachments/assets/34976be9-a871-4ffe-9d5a-c4cdd0bf4576

View File

@@ -11,11 +11,15 @@ local PATS = {
local function match(line) local function match(line)
local signs = line:sub(1, 2) local signs = line:sub(1, 2)
for _, p in ipairs(PATS) do for _, p in ipairs(PATS) do
if not signs:find(p[1]) then local path
elseif line:sub(4, 4) == '"' then if signs:find(p[1]) then
return p[2], line:sub(5, -2) path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4)
end
if not path then
elseif path:find("[/\\]$") then
return p[2] == 3 and 30 or p[2], path:sub(1, -2)
else else
return p[2], line:sub(4) return p[2], path
end end
end end
end end
@@ -30,38 +34,73 @@ local function root(cwd)
until not cwd until not cwd
end end
local add = ya.sync(function(st, cwd, repo, changes) local function bubble_up(changed)
st.repos[cwd] = repo local new, empty = {}, Url("")
st.changes[repo] = st.changes[repo] or {} for k, v in pairs(changed) do
for k, v in pairs(changes) do if v ~= 3 and v ~= 30 then
st.changes[repo][k] = v ~= 0 and v or nil local url = Url(k):parent()
while url and url ~= empty do
local s = tostring(url)
new[s] = (new[s] or 0) > v and new[s] or v
url = url:parent()
end
end
end
return new
end
local function propagate_down(ignored, cwd, repo)
local new, rel = {}, cwd:strip_prefix(repo)
for k, v in pairs(ignored) do
if v == 30 then
if rel:starts_with(k) then
new[tostring(repo:join(rel))] = 30
elseif cwd == repo:join(k):parent() then
new[k] = 3
end
end
end
return new
end
local add = ya.sync(function(st, cwd, repo, changed)
st.dirs[cwd] = repo
st.repos[repo] = st.repos[repo] or {}
for k, v in pairs(changed) do
if v == 0 then
st.repos[repo][k] = nil
elseif v == 30 then
st.dirs[k] = ""
else
st.repos[repo][k] = v
end
end end
ya.render() ya.render()
end) end)
local remove = ya.sync(function(st, cwd) local remove = ya.sync(function(st, cwd)
local repo = st.repos[cwd] local dir = st.dirs[cwd]
if not repo then if not dir then
return return
end end
ya.render() ya.render()
st.repos[cwd] = nil st.dirs[cwd] = nil
if not st.changes[repo] then if not st.repos[dir] then
return return
end end
for _, r in pairs(st.repos) do for _, r in pairs(st.dirs) do
if r == repo then if r == dir then
return return
end end
end end
st.changes[repo] = nil st.repos[dir] = nil
end) end)
local function setup(st, opts) local function setup(st, opts)
st.dirs = {}
st.repos = {} st.repos = {}
st.changes = {}
opts = opts or {} opts = opts or {}
opts.order = opts.order or 500 opts.order = opts.order or 500
@@ -80,19 +119,19 @@ local function setup(st, opts)
[6] = THEME.git_modified and THEME.git_modified.icon or "*", [6] = THEME.git_modified and THEME.git_modified.icon or "*",
[5] = THEME.git_added and THEME.git_added.icon or "+", [5] = THEME.git_added and THEME.git_added.icon or "+",
[4] = THEME.git_untracked and THEME.git_untracked.icon or "?", [4] = THEME.git_untracked and THEME.git_untracked.icon or "?",
[3] = THEME.git_ignored and THEME.git_ignored.icon or "", [3] = THEME.git_ignored and THEME.git_ignored.icon or "!",
[2] = THEME.git_deleted and THEME.git_deleted.icon or "-", [2] = THEME.git_deleted and THEME.git_deleted.icon or "-",
[1] = THEME.git_updated and THEME.git_updated.icon or "U", [1] = THEME.git_updated and THEME.git_updated.icon or "U",
} }
Linemode:children_add(function(self) Linemode:children_add(function(self)
local url = self._file.url local url = self._file.url
local repo = st.repos[tostring(url:parent())] local dir = st.dirs[tostring(url:parent())]
if not repo then local change
return ui.Line("") if dir then
change = dir == "" and 3 or st.repos[dir][tostring(url):sub(#dir + 2)]
end end
local change = st.changes[repo][tostring(url):sub(#repo + 2)]
if not change or icons[change] == "" then if not change or icons[change] == "" then
return ui.Line("") return ui.Line("")
elseif self._file:is_hovered() then elseif self._file:is_hovered() then
@@ -127,37 +166,28 @@ local function fetch(self)
return 0 return 0
end end
local changes = {} local changed, ignored = {}, {}
for line in output.stdout:gmatch("[^\r\n]+") do for line in output.stdout:gmatch("[^\r\n]+") do
local sign, path = match(line) local sign, path = match(line)
if not sign then if sign == 30 then
elseif path:find("[/\\]$") then ignored[path] = sign
changes[path:sub(1, -2)] = sign
else else
changes[path] = sign changed[path] = sign
end end
end end
if self.files[1].cha.is_dir then if self.files[1].cha.is_dir then
local parents, empty_url = {}, Url("") ya.dict_merge(changed, bubble_up(changed))
for k, v in pairs(changes) do ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo)))
local url = Url(k):parent() else
while url and url ~= empty_url do ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo)))
local s = tostring(url)
parents[s] = (parents[s] or 0) > v and parents[s] or v
url = url:parent()
end
end
for k, v in pairs(parents) do
changes[k] = v
end
end end
for _, p in ipairs(paths) do for _, p in ipairs(paths) do
local s = p:sub(#repo + 2) local s = p:sub(#repo + 2)
changes[s] = changes[s] or 0 changed[s] = changed[s] or 0
end end
add(tostring(cwd), repo, changes) add(tostring(cwd), repo, changed)
return 3 return 3
end end