feat: add a new git_ignored theme option to allow customizing the color of ignored files, closes #19

This commit is contained in:
sxyazi
2024-09-04 12:48:50 +08:00
parent d9bfa0b987
commit c2c354e13d
2 changed files with 87 additions and 59 deletions

View File

@@ -1,19 +1,11 @@
local PATS = { local PATS = {
{ "[MT]", "M" }, -- Modified { "[MT]", 6 }, -- Modified
{ "[AC]", "A" }, -- Added { "[AC]", 5 }, -- Added
{ "?$", "?" }, -- Untracked { "?$", 4 }, -- Untracked
{ "D", "D" }, -- Deleted { "!$", 3 }, -- Ignored
{ "U", "U" }, -- Updated { "D", 2 }, -- Deleted
{ "[AD][AD]", "U" }, -- Updated { "U", 1 }, -- Updated
} { "[AD][AD]", 1 }, -- Updated
local WEIGHTS = {
["M"] = 6,
["A"] = 5,
["?"] = 4,
["D"] = 3,
["U"] = 2,
[""] = 1,
} }
local function match(line) local function match(line)
@@ -32,60 +24,101 @@ local function root(cwd)
repeat repeat
local cha = fs.cha(cwd:join(".git")) local cha = fs.cha(cwd:join(".git"))
if cha and cha.is_dir then if cha and cha.is_dir then
return string.format("%s%s", cwd, ya.target_family() == "windows" and "\\" or "/") return tostring(cwd)
end end
cwd = cwd:parent() cwd = cwd:parent()
until not cwd until not cwd
end end
local save = ya.sync(function(st, states) local add = ya.sync(function(st, cwd, repo, changes)
st.states = st.states or {} st.repos[cwd] = repo
for k, v in pairs(states) do st.changes[repo] = st.changes[repo] or {}
st.states[k] = v ~= "" and v or nil for k, v in pairs(changes) do
st.changes[repo][k] = v ~= 0 and v or nil
end end
ya.render() ya.render()
end) end)
local remove = ya.sync(function(st, cwd)
local repo = st.repos[cwd]
if not repo then
return
end
ya.render()
st.repos[cwd] = nil
if not st.changes[repo] then
return
end
for _, r in pairs(st.repos) do
if r == repo then
return
end
end
st.changes[repo] = nil
end)
local function setup(st, opts) local function setup(st, opts)
st.states = {} st.repos = {}
st.changes = {}
opts = opts or {} opts = opts or {}
opts.order = opts.order or 500 opts.order = opts.order or 500
-- Chosen by ChatGPT fairly, PRs are welcome to adjust them
local styles = { local styles = {
["M"] = THEME.git_modified and ui.Style(THEME.git_modified) or ui.Style():fg("blue"), [6] = THEME.git_modified and ui.Style(THEME.git_modified) or ui.Style():fg("#ffa500"),
["A"] = THEME.git_added and ui.Style(THEME.git_added) or ui.Style():fg("green"), [5] = THEME.git_added and ui.Style(THEME.git_added) or ui.Style():fg("#32cd32"),
["?"] = THEME.git_untracked and ui.Style(THEME.git_untracked) or ui.Style():fg("yellow"), [4] = THEME.git_untracked and ui.Style(THEME.git_untracked) or ui.Style():fg("#a9a9a9"),
["D"] = THEME.git_deleted and ui.Style(THEME.git_deleted) or ui.Style():fg("red"), [3] = THEME.git_ignored and ui.Style(THEME.git_ignored) or ui.Style():fg("#696969"),
["U"] = THEME.git_updated and ui.Style(THEME.git_updated) or ui.Style():fg("blue"), [2] = THEME.git_deleted and ui.Style(THEME.git_deleted) or ui.Style():fg("#ff4500"),
[1] = THEME.git_updated and ui.Style(THEME.git_updated) or ui.Style():fg("#1e90ff"),
} }
-- TODO: Use nerd-font icons as default matching Yazi's default behavior
local icons = { local icons = {
["M"] = THEME.git_modified and THEME.git_modified.icon or "M", [6] = THEME.git_modified and THEME.git_modified.icon or "*",
["A"] = THEME.git_added and THEME.git_added.icon or "A", [5] = THEME.git_added and THEME.git_added.icon or "+",
["?"] = THEME.git_untracked and THEME.git_untracked.icon or "?", [4] = THEME.git_untracked and THEME.git_untracked.icon or "?",
["D"] = THEME.git_deleted and THEME.git_deleted.icon or "D", [3] = THEME.git_ignored and THEME.git_ignored.icon or "",
["U"] = THEME.git_updated and THEME.git_updated.icon or "U", [2] = THEME.git_deleted and THEME.git_deleted.icon or "-",
[1] = THEME.git_updated and THEME.git_updated.icon or "U",
} }
Linemode:children_add(function(self) Linemode:children_add(function(self)
local s = st.states[tostring(self._file.url)] local url = self._file.url
if s and icons[s] ~= "" then local repo = st.repos[tostring(url:parent())]
return ui.Line { ui.Span(" "), ui.Span(icons[s]):style(styles[s]) } if not repo then
return ui.Line("")
end
local change = st.changes[repo][tostring(url):sub(#repo + 2)]
if not change or icons[change] == "" then
return ui.Line("")
elseif self._file:is_hovered() then
return ui.Line { ui.Span(" "), ui.Span(icons[change]) }
else else
return ui.Line {} return ui.Line { ui.Span(" "), ui.Span(icons[change]):style(styles[change]) }
end end
end, opts.order) end, opts.order)
end end
local function fetch(self) local function fetch(self)
local paths = {} local cwd = self.files[1].url:parent()
for _, file in ipairs(self.files) do local repo = root(cwd)
paths[#paths + 1] = tostring(file.url) if not repo then
remove(tostring(cwd))
return 1
end
local paths = {}
for _, f in ipairs(self.files) do
paths[#paths + 1] = tostring(f.url)
end end
local cwd = self.files[1].url:parent()
local output, err = Command("git") local output, err = Command("git")
:cwd(tostring(cwd)) :cwd(tostring(cwd))
:args({ "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames" }) :args({ "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames", "--ignored=matching" })
:args(paths) :args(paths)
:stdout(Command.PIPED) :stdout(Command.PIPED)
:output() :output()
@@ -94,42 +127,37 @@ local function fetch(self)
return 0 return 0
end end
local prefix = root(cwd) local changes = {}
if not prefix then
return 1
end
local states = {}
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 not sign then
elseif path:find("[/\\]$") then elseif path:find("[/\\]$") then
states[prefix .. path:sub(1, -2)] = sign changes[path:sub(1, -2)] = sign
else else
states[prefix .. path] = sign changes[path] = sign
end end
end end
prefix = Url(prefix)
if self.files[1].cha.is_dir then if self.files[1].cha.is_dir then
local parents = {} local parents, empty_url = {}, Url("")
for k, v in pairs(states) do for k, v in pairs(changes) do
local url = Url(k):parent() local url = Url(k):parent()
while url and url ~= prefix do while url and url ~= empty_url do
local s = tostring(url) local s = tostring(url)
parents[s] = (WEIGHTS[parents[s]] or 0) > WEIGHTS[v] and parents[s] or v parents[s] = (parents[s] or 0) > v and parents[s] or v
url = url:parent() url = url:parent()
end end
end end
for k, v in pairs(parents) do for k, v in pairs(parents) do
states[k] = v changes[k] = v
end end
end end
for _, p in ipairs(paths) do for _, f in ipairs(self.files) do
states[p] = states[p] or "" local name = f.url:name()
changes[name] = changes[name] or 0
end end
save(states) add(tostring(cwd), repo, changes)
return 3 return 3
end end

View File

@@ -25,9 +25,9 @@ local function setup(st, opts)
local spans = {} local spans = {}
for _, tag in ipairs(st.tags[url] or {}) do for _, tag in ipairs(st.tags[url] or {}) do
if self._file:is_hovered() then if self._file:is_hovered() then
spans[#spans + 1] = ui.Span(""):bg(st.colors[tag] or "reset") spans[#spans + 1] = ui.Span(""):bg(st.colors[tag] or "reset")
else else
spans[#spans + 1] = ui.Span(""):fg(st.colors[tag] or "reset") spans[#spans + 1] = ui.Span(""):fg(st.colors[tag] or "reset")
end end
end end
return ui.Line(spans) return ui.Line(spans)