mirror of
https://github.com/hydroxycarbamide/dotfiles.git
synced 2025-05-04 20:09:08 -04:00
Update yazi and its plugins
This commit is contained in:
parent
ab39adc2f3
commit
09065ab756
16 changed files with 1805 additions and 113 deletions
|
@ -152,7 +152,7 @@ keymap = [
|
||||||
{ on = "}", run = "tab_swap 1", desc = "Swap current tab with next tab" },
|
{ on = "}", run = "tab_swap 1", desc = "Swap current tab with next tab" },
|
||||||
|
|
||||||
# Tasks
|
# Tasks
|
||||||
{ on = "w", run = "tasks_show", desc = "Show task manager" },
|
{ on = "w", run = "tasks:show", desc = "Show task manager" },
|
||||||
|
|
||||||
# Help
|
# Help
|
||||||
{ on = "~", run = "help", desc = "Open help" },
|
{ on = "~", run = "help", desc = "Open help" },
|
||||||
|
@ -164,6 +164,15 @@ on = [ "g", "i" ]
|
||||||
run = "plugin lazygit"
|
run = "plugin lazygit"
|
||||||
desc = "run lazygit"
|
desc = "run lazygit"
|
||||||
|
|
||||||
|
[[manager.prepend_keymap]]
|
||||||
|
on = "M"
|
||||||
|
run = "plugin mount"
|
||||||
|
|
||||||
|
[[manager.prepend_keymap]]
|
||||||
|
on = [ "g", "c" ]
|
||||||
|
run = "plugin vcs-files"
|
||||||
|
desc = "Show Git file changes"
|
||||||
|
|
||||||
[tasks]
|
[tasks]
|
||||||
|
|
||||||
keymap = [
|
keymap = [
|
||||||
|
@ -328,7 +337,7 @@ keymap = [
|
||||||
keymap = [
|
keymap = [
|
||||||
{ on = "<C-c>", run = "close", desc = "Cancel completion" },
|
{ on = "<C-c>", run = "close", desc = "Cancel completion" },
|
||||||
{ on = "<Tab>", run = "close --submit", desc = "Submit the completion" },
|
{ on = "<Tab>", run = "close --submit", desc = "Submit the completion" },
|
||||||
{ on = "<Enter>", run = [ "close --submit", "close_input --submit" ], desc = "Submit the completion and input" },
|
{ on = "<Enter>", run = [ "close --submit", "input:close --submit" ], desc = "Submit the completion and input" },
|
||||||
|
|
||||||
{ on = "<A-k>", run = "arrow -1", desc = "Move cursor up" },
|
{ on = "<A-k>", run = "arrow -1", desc = "Move cursor up" },
|
||||||
{ on = "<A-j>", run = "arrow 1", desc = "Move cursor down" },
|
{ on = "<A-j>", run = "arrow 1", desc = "Move cursor down" },
|
||||||
|
|
|
@ -1,17 +1,32 @@
|
||||||
[[plugin.deps]]
|
[[plugin.deps]]
|
||||||
use = "yazi-rs/plugins:git"
|
use = "yazi-rs/plugins:git"
|
||||||
rev = "5186af7"
|
rev = "a1738e8"
|
||||||
hash = "771f18427fb75fb19990ce602bb322f4"
|
hash = "e0ada736ea676c2bbb3ec705a49526ef"
|
||||||
|
|
||||||
[[plugin.deps]]
|
[[plugin.deps]]
|
||||||
use = "yazi-rs/plugins:full-border"
|
use = "yazi-rs/plugins:full-border"
|
||||||
rev = "5186af7"
|
rev = "a1738e8"
|
||||||
hash = "ae9e1d0c6bfd68cdebc98cc684c22b45"
|
hash = "1f3dad061209081a6b04dd6ff2cb06c7"
|
||||||
|
|
||||||
[[plugin.deps]]
|
[[plugin.deps]]
|
||||||
use = "Lil-Dank/lazygit"
|
use = "Lil-Dank/lazygit"
|
||||||
rev = "9f924e3"
|
rev = "7a08a09"
|
||||||
hash = "2b0c33928986f126d5c5a4cac31a6b46"
|
hash = "a1fa2b3e1826c3a34804ea8c548e9f80"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:mime-ext"
|
||||||
|
rev = "a1738e8"
|
||||||
|
hash = "5e24c167e9ae9a203a48f2a438b8c705"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:mount"
|
||||||
|
rev = "a1738e8"
|
||||||
|
hash = "dd97eede8e20e59cd2604e8006e470e2"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:vcs-files"
|
||||||
|
rev = "a1738e8"
|
||||||
|
hash = "36405f8781fcaf33ceab24dffd5cea19"
|
||||||
|
|
||||||
[flavor]
|
[flavor]
|
||||||
deps = []
|
deps = []
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
--- @since 25.2.7
|
--- @since 25.2.26
|
||||||
|
|
||||||
local function setup(_, opts)
|
local function setup(_, opts)
|
||||||
local type = opts and opts.type or ui.Border.ROUNDED
|
local type = opts and opts.type or ui.Border.ROUNDED
|
||||||
|
@ -6,7 +6,7 @@ local function setup(_, opts)
|
||||||
|
|
||||||
Tab.build = function(self, ...)
|
Tab.build = function(self, ...)
|
||||||
local bar = function(c, x, y)
|
local bar = function(c, x, y)
|
||||||
if x <= 0 or x == self._area.w - 1 then
|
if x <= 0 or x == self._area.w - 1 or th.mgr.border_symbol ~= "│" then
|
||||||
return ui.Bar(ui.Bar.TOP)
|
return ui.Bar(ui.Bar.TOP)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ local function setup(_, opts)
|
||||||
c[3]:pad(ui.Pad.y(1)),
|
c[3]:pad(ui.Pad.y(1)),
|
||||||
}
|
}
|
||||||
|
|
||||||
local style = THEME.manager.border_style
|
local style = th.mgr.border_style
|
||||||
self._base = ya.list_merge(self._base or {}, {
|
self._base = ya.list_merge(self._base or {}, {
|
||||||
ui.Border(ui.Border.ALL):area(self._area):type(type):style(style),
|
ui.Border(ui.Border.ALL):area(self._area):type(type):style(style),
|
||||||
ui.Bar(ui.Bar.RIGHT):area(self._chunks[1]):style(style),
|
ui.Bar(ui.Bar.RIGHT):area(self._chunks[1]):style(style),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# git.yazi
|
# git.yazi
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Yazi v25.2.7 or later is required for this plugin to work.
|
> Yazi v25.2.26 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.
|
||||||
|
|
||||||
|
@ -39,38 +39,38 @@ run = "git"
|
||||||
|
|
||||||
You can customize the [Style](https://yazi-rs.github.io/docs/plugins/layout#style) of the status sign with:
|
You can customize the [Style](https://yazi-rs.github.io/docs/plugins/layout#style) of the status sign with:
|
||||||
|
|
||||||
- `THEME.git.modified`
|
- `th.git.modified`
|
||||||
- `THEME.git.added`
|
- `th.git.added`
|
||||||
- `THEME.git.untracked`
|
- `th.git.untracked`
|
||||||
- `THEME.git.ignored`
|
- `th.git.ignored`
|
||||||
- `THEME.git.deleted`
|
- `th.git.deleted`
|
||||||
- `THEME.git.updated`
|
- `th.git.updated`
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- ~/.config/yazi/init.lua
|
-- ~/.config/yazi/init.lua
|
||||||
THEME.git = THEME.git or {}
|
th.git = th.git or {}
|
||||||
THEME.git.modified = ui.Style():fg("blue")
|
th.git.modified = ui.Style():fg("blue")
|
||||||
THEME.git.deleted = ui.Style():fg("red"):bold()
|
th.git.deleted = ui.Style():fg("red"):bold()
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also customize the text of the status sign with:
|
You can also customize the text of the status sign with:
|
||||||
|
|
||||||
- `THEME.git.modified_sign`
|
- `th.git.modified_sign`
|
||||||
- `THEME.git.added_sign`
|
- `th.git.added_sign`
|
||||||
- `THEME.git.untracked_sign`
|
- `th.git.untracked_sign`
|
||||||
- `THEME.git.ignored_sign`
|
- `th.git.ignored_sign`
|
||||||
- `THEME.git.deleted_sign`
|
- `th.git.deleted_sign`
|
||||||
- `THEME.git.updated_sign`
|
- `th.git.updated_sign`
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- ~/.config/yazi/init.lua
|
-- ~/.config/yazi/init.lua
|
||||||
THEME.git = THEME.git or {}
|
th.git = th.git or {}
|
||||||
THEME.git.modified_sign = "M"
|
th.git.modified_sign = "M"
|
||||||
THEME.git.deleted_sign = "D"
|
th.git.deleted_sign = "D"
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
|
@ -1,29 +1,45 @@
|
||||||
--- @since 25.2.7
|
--- @since 25.4.4
|
||||||
|
|
||||||
local WIN = ya.target_family() == "windows"
|
local WINDOWS = ya.target_family() == "windows"
|
||||||
local PATS = {
|
|
||||||
{ "[MT]", 6 }, -- Modified
|
-- The code of supported git status,
|
||||||
{ "[AC]", 5 }, -- Added
|
-- also used to determine which status to show for directories when they contain different statuses
|
||||||
{ "?$", 4 }, -- Untracked
|
-- see `bubble_up`
|
||||||
{ "!$", 3 }, -- Ignored
|
local CODES = {
|
||||||
{ "D", 2 }, -- Deleted
|
excluded = 100, -- ignored directory
|
||||||
{ "U", 1 }, -- Updated
|
ignored = 6, -- ignored file
|
||||||
{ "[AD][AD]", 1 }, -- Updated
|
untracked = 5,
|
||||||
|
modified = 4,
|
||||||
|
added = 3,
|
||||||
|
deleted = 2,
|
||||||
|
updated = 1,
|
||||||
|
unknown = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
local PATTERNS = {
|
||||||
|
{ "!$", CODES.ignored },
|
||||||
|
{ "?$", CODES.untracked },
|
||||||
|
{ "[MT]", CODES.modified },
|
||||||
|
{ "[AC]", CODES.added },
|
||||||
|
{ "D", CODES.deleted },
|
||||||
|
{ "U", CODES.updated },
|
||||||
|
{ "[AD][AD]", CODES.updated },
|
||||||
}
|
}
|
||||||
|
|
||||||
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(PATTERNS) do
|
||||||
local path
|
local path, pattern, code = nil, p[1], p[2]
|
||||||
if signs:find(p[1]) then
|
if signs:find(pattern) then
|
||||||
path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4)
|
path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4)
|
||||||
path = WIN and path:gsub("/", "\\") or path
|
path = WINDOWS and path:gsub("/", "\\") or path
|
||||||
end
|
end
|
||||||
if not path then
|
if not path then
|
||||||
elseif path:find("[/\\]$") then
|
elseif path:find("[/\\]$") then
|
||||||
return p[2] == 3 and 30 or p[2], path:sub(1, -2)
|
-- Mark the ignored directory as `excluded`, so we can process it further within `propagate_down`
|
||||||
|
return code == CODES.ignored and CODES.excluded or code, path:sub(1, -2)
|
||||||
else
|
else
|
||||||
return p[2], path
|
return code, path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -44,34 +60,36 @@ local function root(cwd)
|
||||||
if cha and (cha.is_dir or is_worktree(next)) then
|
if cha and (cha.is_dir or is_worktree(next)) then
|
||||||
return tostring(cwd)
|
return tostring(cwd)
|
||||||
end
|
end
|
||||||
cwd = cwd:parent()
|
cwd = cwd.parent
|
||||||
until not cwd
|
until not cwd
|
||||||
end
|
end
|
||||||
|
|
||||||
local function bubble_up(changed)
|
local function bubble_up(changed)
|
||||||
local new, empty = {}, Url("")
|
local new, empty = {}, Url("")
|
||||||
for k, v in pairs(changed) do
|
for path, code in pairs(changed) do
|
||||||
if v ~= 3 and v ~= 30 then
|
if code ~= CODES.ignored then
|
||||||
local url = Url(k):parent()
|
local url = Url(path).parent
|
||||||
while url and url ~= empty do
|
while url and url ~= empty do
|
||||||
local s = tostring(url)
|
local s = tostring(url)
|
||||||
new[s] = (new[s] or 0) > v and new[s] or v
|
new[s] = (new[s] or CODES.unknown) > code and new[s] or code
|
||||||
url = url:parent()
|
url = url.parent
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return new
|
return new
|
||||||
end
|
end
|
||||||
|
|
||||||
local function propagate_down(ignored, cwd, repo)
|
local function propagate_down(excluded, cwd, repo)
|
||||||
local new, rel = {}, cwd:strip_prefix(repo)
|
local new, rel = {}, cwd:strip_prefix(repo)
|
||||||
for k, v in pairs(ignored) do
|
for _, path in ipairs(excluded) do
|
||||||
if v == 30 then
|
if rel:starts_with(path) then
|
||||||
if rel:starts_with(k) then
|
-- If `cwd` is a subdirectory of an excluded directory, also mark it as `excluded`
|
||||||
new[tostring(repo:join(rel))] = 30
|
new[tostring(cwd)] = CODES.excluded
|
||||||
elseif cwd == repo:join(k):parent() then
|
elseif cwd == repo:join(path).parent then
|
||||||
new[k] = 3
|
-- If `path` is a direct subdirectory of `cwd`, mark it as `ignored`
|
||||||
end
|
new[path] = CODES.ignored
|
||||||
|
else
|
||||||
|
-- Skipping, we only care about `cwd` itself and its direct subdirectories for maximum performance
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return new
|
return new
|
||||||
|
@ -80,84 +98,84 @@ end
|
||||||
local add = ya.sync(function(st, cwd, repo, changed)
|
local add = ya.sync(function(st, cwd, repo, changed)
|
||||||
st.dirs[cwd] = repo
|
st.dirs[cwd] = repo
|
||||||
st.repos[repo] = st.repos[repo] or {}
|
st.repos[repo] = st.repos[repo] or {}
|
||||||
for k, v in pairs(changed) do
|
for path, code in pairs(changed) do
|
||||||
if v == 0 then
|
if code == CODES.unknown then
|
||||||
st.repos[repo][k] = nil
|
st.repos[repo][path] = nil
|
||||||
elseif v == 30 then
|
elseif code == CODES.excluded then
|
||||||
st.dirs[k] = ""
|
-- Mark the directory with a special value `excluded` so that it can be distinguished during UI rendering
|
||||||
|
st.dirs[path] = CODES.excluded
|
||||||
else
|
else
|
||||||
st.repos[repo][k] = v
|
st.repos[repo][path] = code
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ya.render()
|
ya.render()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local remove = ya.sync(function(st, cwd)
|
local remove = ya.sync(function(st, cwd)
|
||||||
local dir = st.dirs[cwd]
|
local repo = st.dirs[cwd]
|
||||||
if not dir then
|
if not repo then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
ya.render()
|
ya.render()
|
||||||
st.dirs[cwd] = nil
|
st.dirs[cwd] = nil
|
||||||
if not st.repos[dir] then
|
if not st.repos[repo] then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, r in pairs(st.dirs) do
|
for _, r in pairs(st.dirs) do
|
||||||
if r == dir then
|
if r == repo then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
st.repos[dir] = nil
|
st.repos[repo] = nil
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local function setup(st, opts)
|
local function setup(st, opts)
|
||||||
st.dirs = {}
|
st.dirs = {} -- Mapping between a directory and its corresponding repository
|
||||||
st.repos = {}
|
st.repos = {} -- Mapping between a repository and the status of each of its files
|
||||||
|
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
opts.order = opts.order or 1500
|
opts.order = opts.order or 1500
|
||||||
|
|
||||||
-- Chosen by ChatGPT fairly, PRs are welcome to adjust them
|
local t = th.git or {}
|
||||||
local t = THEME.git or {}
|
|
||||||
local styles = {
|
local styles = {
|
||||||
[6] = t.modified and ui.Style(t.modified) or ui.Style():fg("#ffa500"),
|
[CODES.ignored] = t.ignored and ui.Style(t.ignored) or ui.Style():fg("darkgray"),
|
||||||
[5] = t.added and ui.Style(t.added) or ui.Style():fg("#32cd32"),
|
[CODES.untracked] = t.untracked and ui.Style(t.untracked) or ui.Style():fg("magenta"),
|
||||||
[4] = t.untracked and ui.Style(t.untracked) or ui.Style():fg("#a9a9a9"),
|
[CODES.modified] = t.modified and ui.Style(t.modified) or ui.Style():fg("yellow"),
|
||||||
[3] = t.ignored and ui.Style(t.ignored) or ui.Style():fg("#696969"),
|
[CODES.added] = t.added and ui.Style(t.added) or ui.Style():fg("green"),
|
||||||
[2] = t.deleted and ui.Style(t.deleted) or ui.Style():fg("#ff4500"),
|
[CODES.deleted] = t.deleted and ui.Style(t.deleted) or ui.Style():fg("red"),
|
||||||
[1] = t.updated and ui.Style(t.updated) or ui.Style():fg("#1e90ff"),
|
[CODES.updated] = t.updated and ui.Style(t.updated) or ui.Style():fg("yellow"),
|
||||||
}
|
}
|
||||||
local signs = {
|
local signs = {
|
||||||
[6] = t.modified_sign and t.modified_sign or "",
|
[CODES.ignored] = t.ignored_sign or "",
|
||||||
[5] = t.added_sign and t.added_sign or "",
|
[CODES.untracked] = t.untracked_sign or "?",
|
||||||
[4] = t.untracked_sign and t.untracked_sign or "",
|
[CODES.modified] = t.modified_sign or "",
|
||||||
[3] = t.ignored_sign and t.ignored_sign or "",
|
[CODES.added] = t.added_sign or "",
|
||||||
[2] = t.deleted_sign and t.deleted_sign or "",
|
[CODES.deleted] = t.deleted_sign or "",
|
||||||
[1] = t.updated_sign and t.updated_sign or "U",
|
[CODES.updated] = t.updated_sign or "",
|
||||||
}
|
}
|
||||||
|
|
||||||
Linemode:children_add(function(self)
|
Linemode:children_add(function(self)
|
||||||
local url = self._file.url
|
local url = self._file.url
|
||||||
local dir = st.dirs[tostring(url:parent())]
|
local repo = st.dirs[tostring(url.base)]
|
||||||
local change
|
local code
|
||||||
if dir then
|
if repo then
|
||||||
change = dir == "" and 3 or st.repos[dir][tostring(url):sub(#dir + 2)]
|
code = repo == CODES.excluded and CODES.ignored or st.repos[repo][tostring(url):sub(#repo + 2)]
|
||||||
end
|
end
|
||||||
|
|
||||||
if not change or signs[change] == "" then
|
if not code or signs[code] == "" then
|
||||||
return ""
|
return ""
|
||||||
elseif self._file:is_hovered() then
|
elseif self._file.is_hovered then
|
||||||
return ui.Line { " ", signs[change] }
|
return ui.Line { " ", signs[code] }
|
||||||
else
|
else
|
||||||
return ui.Line { " ", ui.Span(signs[change]):style(styles[change]) }
|
return ui.Line { " ", ui.Span(signs[code]):style(styles[code]) }
|
||||||
end
|
end
|
||||||
end, opts.order)
|
end, opts.order)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function fetch(_, job)
|
local function fetch(_, job)
|
||||||
local cwd = job.files[1].url:parent()
|
local cwd = job.files[1].url.base
|
||||||
local repo = root(cwd)
|
local repo = root(cwd)
|
||||||
if not repo then
|
if not repo then
|
||||||
remove(tostring(cwd))
|
remove(tostring(cwd))
|
||||||
|
@ -165,8 +183,8 @@ local function fetch(_, job)
|
||||||
end
|
end
|
||||||
|
|
||||||
local paths = {}
|
local paths = {}
|
||||||
for _, f in ipairs(job.files) do
|
for _, file in ipairs(job.files) do
|
||||||
paths[#paths + 1] = tostring(f.url)
|
paths[#paths + 1] = tostring(file.url)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- stylua: ignore
|
-- stylua: ignore
|
||||||
|
@ -180,27 +198,28 @@ local function fetch(_, job)
|
||||||
return true, Err("Cannot spawn `git` command, error: %s", err)
|
return true, Err("Cannot spawn `git` command, error: %s", err)
|
||||||
end
|
end
|
||||||
|
|
||||||
local changed, ignored = {}, {}
|
local changed, excluded = {}, {}
|
||||||
for line in output.stdout:gmatch("[^\r\n]+") do
|
for line in output.stdout:gmatch("[^\r\n]+") do
|
||||||
local sign, path = match(line)
|
local code, path = match(line)
|
||||||
if sign == 30 then
|
if code == CODES.excluded then
|
||||||
ignored[path] = sign
|
excluded[#excluded + 1] = path
|
||||||
else
|
else
|
||||||
changed[path] = sign
|
changed[path] = code
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if job.files[1].cha.is_dir then
|
if job.files[1].cha.is_dir then
|
||||||
ya.dict_merge(changed, bubble_up(changed))
|
ya.dict_merge(changed, bubble_up(changed))
|
||||||
ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo)))
|
end
|
||||||
else
|
ya.dict_merge(changed, propagate_down(excluded, cwd, Url(repo)))
|
||||||
ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo)))
|
|
||||||
|
-- Reset the status of any files that don't appear in the output of `git status` to `unknown`,
|
||||||
|
-- so that cleaning up outdated statuses from `st.repos`
|
||||||
|
for _, path in ipairs(paths) do
|
||||||
|
local s = path:sub(#repo + 2)
|
||||||
|
changed[s] = changed[s] or CODES.unknown
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, p in ipairs(paths) do
|
|
||||||
local s = p:sub(#repo + 2)
|
|
||||||
changed[s] = changed[s] or 0
|
|
||||||
end
|
|
||||||
add(tostring(cwd), repo, changed)
|
add(tostring(cwd), repo, changed)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -4,7 +4,7 @@ return {
|
||||||
if output.stderr ~= "" then
|
if output.stderr ~= "" then
|
||||||
ya.notify({
|
ya.notify({
|
||||||
title = "lazygit",
|
title = "lazygit",
|
||||||
content = "Not in a git directory",
|
content = "Not in a git directory\nError: " .. output.stderr,
|
||||||
level = "warn",
|
level = "warn",
|
||||||
timeout = 5,
|
timeout = 5,
|
||||||
})
|
})
|
||||||
|
|
21
dot_config/yazi/plugins/mime-ext.yazi/readonly_LICENSE
Normal file
21
dot_config/yazi/plugins/mime-ext.yazi/readonly_LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 yazi-rs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
56
dot_config/yazi/plugins/mime-ext.yazi/readonly_README.md
Normal file
56
dot_config/yazi/plugins/mime-ext.yazi/readonly_README.md
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# mime-ext.yazi
|
||||||
|
|
||||||
|
A mime-type provider based on a file extension database, replacing the [builtin `file(1)`](https://github.com/sxyazi/yazi/blob/main/yazi-plugin/preset/plugins/mime.lua) to speed up mime-type retrieval at the expense of accuracy.
|
||||||
|
|
||||||
|
See https://yazi-rs.github.io/docs/tips#make-yazi-even-faster for more information.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ya pack -a yazi-rs/plugins:mime-ext
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add this to your `~/.config/yazi/yazi.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[plugin.prepend_fetchers]]
|
||||||
|
id = "mime"
|
||||||
|
name = "*"
|
||||||
|
run = "mime-ext"
|
||||||
|
prio = "high"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced
|
||||||
|
|
||||||
|
You can also customize it in your `~/.config/yazi/init.lua` with:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("mime-ext"):setup {
|
||||||
|
-- Expand the existing filename database (lowercase), for example:
|
||||||
|
with_files = {
|
||||||
|
makefile = "text/makefile",
|
||||||
|
-- ...
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Expand the existing extension database (lowercase), for example:
|
||||||
|
with_exts = {
|
||||||
|
mk = "text/makefile",
|
||||||
|
-- ...
|
||||||
|
},
|
||||||
|
|
||||||
|
-- If the mime-type is not in both filename and extension databases,
|
||||||
|
-- then fallback to Yazi's preset `mime` plugin, which uses `file(1)`
|
||||||
|
fallback_file1 = false,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- Add more file types (PRs welcome!).
|
||||||
|
- Compress mime-type tables.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.
|
1126
dot_config/yazi/plugins/mime-ext.yazi/readonly_main.lua
Normal file
1126
dot_config/yazi/plugins/mime-ext.yazi/readonly_main.lua
Normal file
File diff suppressed because it is too large
Load diff
21
dot_config/yazi/plugins/mount.yazi/readonly_LICENSE
Normal file
21
dot_config/yazi/plugins/mount.yazi/readonly_LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 yazi-rs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
51
dot_config/yazi/plugins/mount.yazi/readonly_README.md
Normal file
51
dot_config/yazi/plugins/mount.yazi/readonly_README.md
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# mount.yazi
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Yazi v25.2.7 or later is required for this plugin to work.
|
||||||
|
|
||||||
|
A mount manager for Yazi, providing disk mount, unmount, and eject functionality.
|
||||||
|
|
||||||
|
Supported platforms:
|
||||||
|
|
||||||
|
- Linux with [`udisksctl`](https://github.com/storaged-project/udisks) and [`lsblk`](https://github.com/util-linux/util-linux)
|
||||||
|
- macOS with `diskutil`
|
||||||
|
|
||||||
|
https://github.com/user-attachments/assets/c6f780ab-458b-420f-85cf-2fc45fcfe3a2
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ya pack -a yazi-rs/plugins:mount
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add this to your `~/.config/yazi/keymap.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[manager.prepend_keymap]]
|
||||||
|
on = "M"
|
||||||
|
run = "plugin mount"
|
||||||
|
```
|
||||||
|
|
||||||
|
Available keybindings:
|
||||||
|
|
||||||
|
| Key binding | Alternate key | Action |
|
||||||
|
| ------------ | ------------- | --------------------- |
|
||||||
|
| <kbd>q</kbd> | - | Quit the plugin |
|
||||||
|
| <kbd>k</kbd> | <kbd>↑</kbd> | Move up |
|
||||||
|
| <kbd>j</kbd> | <kbd>↓</kbd> | Move down |
|
||||||
|
| <kbd>l</kbd> | <kbd>→</kbd> | Enter the mount point |
|
||||||
|
| <kbd>m</kbd> | - | Mount the partition |
|
||||||
|
| <kbd>u</kbd> | - | Unmount the partition |
|
||||||
|
| <kbd>e</kbd> | - | Eject the disk |
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- Custom keybindings
|
||||||
|
- Windows support (I don't have an Windows machine for testing, PRs welcome!)
|
||||||
|
- Support mount, unmount, and eject the entire disk
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.
|
285
dot_config/yazi/plugins/mount.yazi/readonly_main.lua
Normal file
285
dot_config/yazi/plugins/mount.yazi/readonly_main.lua
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
--- @since 25.2.26
|
||||||
|
|
||||||
|
local toggle_ui = ya.sync(function(self)
|
||||||
|
if self.children then
|
||||||
|
Modal:children_remove(self.children)
|
||||||
|
self.children = nil
|
||||||
|
else
|
||||||
|
self.children = Modal:children_add(self, 10)
|
||||||
|
end
|
||||||
|
ya.render()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local subscribe = ya.sync(function(self)
|
||||||
|
ps.unsub("mount")
|
||||||
|
ps.sub("mount", function() ya.mgr_emit("plugin", { self._id, "refresh" }) end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local update_partitions = ya.sync(function(self, partitions)
|
||||||
|
self.partitions = partitions
|
||||||
|
self.cursor = math.max(0, math.min(self.cursor or 0, #self.partitions - 1))
|
||||||
|
ya.render()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local active_partition = ya.sync(function(self) return self.partitions[self.cursor + 1] end)
|
||||||
|
|
||||||
|
local update_cursor = ya.sync(function(self, cursor)
|
||||||
|
if #self.partitions == 0 then
|
||||||
|
self.cursor = 0
|
||||||
|
else
|
||||||
|
self.cursor = ya.clamp(0, self.cursor + cursor, #self.partitions - 1)
|
||||||
|
end
|
||||||
|
ya.render()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local M = {
|
||||||
|
keys = {
|
||||||
|
{ on = "q", run = "quit" },
|
||||||
|
|
||||||
|
{ on = "k", run = "up" },
|
||||||
|
{ on = "j", run = "down" },
|
||||||
|
{ on = "l", run = { "enter", "quit" } },
|
||||||
|
|
||||||
|
{ on = "<Up>", run = "up" },
|
||||||
|
{ on = "<Down>", run = "down" },
|
||||||
|
{ on = "<Right>", run = { "enter", "quit" } },
|
||||||
|
|
||||||
|
{ on = "m", run = "mount" },
|
||||||
|
{ on = "u", run = "unmount" },
|
||||||
|
{ on = "e", run = "eject" },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function M:new(area)
|
||||||
|
self:layout(area)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:layout(area)
|
||||||
|
local chunks = ui.Layout()
|
||||||
|
:constraints({
|
||||||
|
ui.Constraint.Percentage(10),
|
||||||
|
ui.Constraint.Percentage(80),
|
||||||
|
ui.Constraint.Percentage(10),
|
||||||
|
})
|
||||||
|
:split(area)
|
||||||
|
|
||||||
|
local chunks = ui.Layout()
|
||||||
|
:direction(ui.Layout.HORIZONTAL)
|
||||||
|
:constraints({
|
||||||
|
ui.Constraint.Percentage(10),
|
||||||
|
ui.Constraint.Percentage(80),
|
||||||
|
ui.Constraint.Percentage(10),
|
||||||
|
})
|
||||||
|
:split(chunks[2])
|
||||||
|
|
||||||
|
self._area = chunks[2]
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:entry(job)
|
||||||
|
if job.args[1] == "refresh" then
|
||||||
|
return update_partitions(self.obtain())
|
||||||
|
end
|
||||||
|
|
||||||
|
toggle_ui()
|
||||||
|
update_partitions(self.obtain())
|
||||||
|
subscribe()
|
||||||
|
|
||||||
|
local tx1, rx1 = ya.chan("mpsc")
|
||||||
|
local tx2, rx2 = ya.chan("mpsc")
|
||||||
|
function producer()
|
||||||
|
while true do
|
||||||
|
local cand = self.keys[ya.which { cands = self.keys, silent = true }] or { run = {} }
|
||||||
|
for _, r in ipairs(type(cand.run) == "table" and cand.run or { cand.run }) do
|
||||||
|
tx1:send(r)
|
||||||
|
if r == "quit" then
|
||||||
|
toggle_ui()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function consumer1()
|
||||||
|
repeat
|
||||||
|
local run = rx1:recv()
|
||||||
|
if run == "quit" then
|
||||||
|
tx2:send(run)
|
||||||
|
break
|
||||||
|
elseif run == "up" then
|
||||||
|
update_cursor(-1)
|
||||||
|
elseif run == "down" then
|
||||||
|
update_cursor(1)
|
||||||
|
elseif run == "enter" then
|
||||||
|
local active = active_partition()
|
||||||
|
if active and active.dist then
|
||||||
|
ya.mgr_emit("cd", { active.dist })
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tx2:send(run)
|
||||||
|
end
|
||||||
|
until not run
|
||||||
|
end
|
||||||
|
|
||||||
|
function consumer2()
|
||||||
|
repeat
|
||||||
|
local run = rx2:recv()
|
||||||
|
if run == "quit" then
|
||||||
|
break
|
||||||
|
elseif run == "mount" then
|
||||||
|
self.operate("mount")
|
||||||
|
elseif run == "unmount" then
|
||||||
|
self.operate("unmount")
|
||||||
|
elseif run == "eject" then
|
||||||
|
self.operate("eject")
|
||||||
|
end
|
||||||
|
until not run
|
||||||
|
end
|
||||||
|
|
||||||
|
ya.join(producer, consumer1, consumer2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:reflow() return { self } end
|
||||||
|
|
||||||
|
function M:redraw()
|
||||||
|
local rows = {}
|
||||||
|
for _, p in ipairs(self.partitions or {}) do
|
||||||
|
if not p.sub then
|
||||||
|
rows[#rows + 1] = ui.Row { p.main }
|
||||||
|
elseif p.sub == "" then
|
||||||
|
rows[#rows + 1] = ui.Row { p.main, p.label or "", p.dist or "", p.fstype or "" }
|
||||||
|
else
|
||||||
|
rows[#rows + 1] = ui.Row { " " .. p.sub, p.label or "", p.dist or "", p.fstype or "" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
ui.Clear(self._area),
|
||||||
|
ui.Border(ui.Border.ALL)
|
||||||
|
:area(self._area)
|
||||||
|
:type(ui.Border.ROUNDED)
|
||||||
|
:style(ui.Style():fg("blue"))
|
||||||
|
:title(ui.Line("Mount"):align(ui.Line.CENTER)),
|
||||||
|
ui.Table(rows)
|
||||||
|
:area(self._area:pad(ui.Pad(1, 2, 1, 2)))
|
||||||
|
:header(ui.Row({ "Src", "Label", "Dist", "FSType" }):style(ui.Style():bold()))
|
||||||
|
:row(self.cursor)
|
||||||
|
:row_style(ui.Style():fg("blue"):underline())
|
||||||
|
:widths {
|
||||||
|
ui.Constraint.Length(20),
|
||||||
|
ui.Constraint.Length(20),
|
||||||
|
ui.Constraint.Percentage(70),
|
||||||
|
ui.Constraint.Length(10),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.obtain()
|
||||||
|
local tbl = {}
|
||||||
|
local last
|
||||||
|
for _, p in ipairs(fs.partitions()) do
|
||||||
|
local main, sub = M.split(p.src)
|
||||||
|
if main and last ~= main then
|
||||||
|
if p.src == main then
|
||||||
|
last, p.main, p.sub, tbl[#tbl + 1] = p.src, p.src, "", p
|
||||||
|
else
|
||||||
|
last, tbl[#tbl + 1] = main, { src = main, main = main, sub = "" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if sub then
|
||||||
|
if tbl[#tbl].sub == "" and tbl[#tbl].main == main then
|
||||||
|
tbl[#tbl].sub = nil
|
||||||
|
end
|
||||||
|
p.main, p.sub, tbl[#tbl + 1] = main, sub, p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(M.fillin(tbl), function(a, b)
|
||||||
|
if a.main == b.main then
|
||||||
|
return (a.sub or "") < (b.sub or "")
|
||||||
|
else
|
||||||
|
return a.main > b.main
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.split(src)
|
||||||
|
local pats = {
|
||||||
|
{ "^/dev/sd[a-z]", "%d+$" }, -- /dev/sda1
|
||||||
|
{ "^/dev/nvme%d+n%d+", "p%d+$" }, -- /dev/nvme0n1p1
|
||||||
|
{ "^/dev/mmcblk%d+", "p%d+$" }, -- /dev/mmcblk0p1
|
||||||
|
{ "^/dev/disk%d+", ".+$" }, -- /dev/disk1s1
|
||||||
|
}
|
||||||
|
for _, p in ipairs(pats) do
|
||||||
|
local main = src:match(p[1])
|
||||||
|
if main then
|
||||||
|
return main, src:sub(#main + 1):match(p[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.fillin(tbl)
|
||||||
|
if ya.target_os() ~= "linux" then
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
local sources, indices = {}, {}
|
||||||
|
for i, p in ipairs(tbl) do
|
||||||
|
if p.sub and not p.fstype then
|
||||||
|
sources[#sources + 1], indices[p.src] = p.src, i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #sources == 0 then
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
local output, err = Command("lsblk"):args({ "-p", "-o", "name,fstype", "-J" }):args(sources):output()
|
||||||
|
if err then
|
||||||
|
ya.dbg("Failed to fetch filesystem types for unmounted partitions: " .. err)
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = ya.json_decode(output and output.stdout or "")
|
||||||
|
for _, p in ipairs(t and t.blockdevices or {}) do
|
||||||
|
tbl[indices[p.name]].fstype = p.fstype
|
||||||
|
end
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.operate(type)
|
||||||
|
local active = active_partition()
|
||||||
|
if not active then
|
||||||
|
return
|
||||||
|
elseif not active.sub then
|
||||||
|
return -- TODO: mount/unmount main disk
|
||||||
|
end
|
||||||
|
|
||||||
|
local output, err
|
||||||
|
if ya.target_os() == "macos" then
|
||||||
|
output, err = Command("diskutil"):args({ type, active.src }):output()
|
||||||
|
end
|
||||||
|
if ya.target_os() == "linux" then
|
||||||
|
if type == "eject" then
|
||||||
|
Command("udisksctl"):args({ "unmount", "-b", active.src }):status()
|
||||||
|
output, err = Command("udisksctl"):args({ "power-off", "-b", active.src }):output()
|
||||||
|
else
|
||||||
|
output, err = Command("udisksctl"):args({ type, "-b", active.src }):output()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not output then
|
||||||
|
M.fail("Failed to %s `%s`: %s", type, active.src, err)
|
||||||
|
elseif not output.status.success then
|
||||||
|
M.fail("Failed to %s `%s`: %s", type, active.src, output.stderr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.fail(s, ...) ya.notify { title = "Mount", content = string.format(s, ...), timeout = 10, level = "error" } end
|
||||||
|
|
||||||
|
function M:click() end
|
||||||
|
|
||||||
|
function M:scroll() end
|
||||||
|
|
||||||
|
function M:touch() end
|
||||||
|
|
||||||
|
return M
|
21
dot_config/yazi/plugins/vcs-files.yazi/readonly_LICENSE
Normal file
21
dot_config/yazi/plugins/vcs-files.yazi/readonly_LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 yazi-rs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
29
dot_config/yazi/plugins/vcs-files.yazi/readonly_README.md
Normal file
29
dot_config/yazi/plugins/vcs-files.yazi/readonly_README.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# vcs-files.yazi
|
||||||
|
|
||||||
|
Show Git file changes in Yazi.
|
||||||
|
|
||||||
|
https://github.com/user-attachments/assets/465b801b-3516-4f57-be09-8405da21e34d
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ya pack -a yazi-rs/plugins:vcs-files
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# keymap.toml
|
||||||
|
[[manager.prepend_keymap]]
|
||||||
|
on = [ "g", "c" ]
|
||||||
|
run = "plugin vcs-files"
|
||||||
|
desc = "Show Git file changes"
|
||||||
|
```
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- [ ] Add support for other VCS (e.g. Mercurial, Subversion)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.
|
33
dot_config/yazi/plugins/vcs-files.yazi/readonly_main.lua
Normal file
33
dot_config/yazi/plugins/vcs-files.yazi/readonly_main.lua
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--- @since 25.4.8
|
||||||
|
|
||||||
|
local root = ya.sync(function() return cx.active.current.cwd end)
|
||||||
|
|
||||||
|
local function fail(content) return ya.notify { title = "VCS Files", content = content, timeout = 5, level = "error" } end
|
||||||
|
|
||||||
|
local function entry()
|
||||||
|
local root = root()
|
||||||
|
local output, err = Command("git"):cwd(tostring(root)):args({ "diff", "--name-only", "HEAD" }):output()
|
||||||
|
if err then
|
||||||
|
return fail("Failed to run `git diff`, error: " .. err)
|
||||||
|
elseif not output.status.success then
|
||||||
|
return fail("Failed to run `git diff`, stderr: " .. output.stderr)
|
||||||
|
end
|
||||||
|
|
||||||
|
local id = ya.id("ft")
|
||||||
|
local cwd = root:into_search("Git changes")
|
||||||
|
ya.mgr_emit("cd", { Url(cwd) })
|
||||||
|
ya.mgr_emit("update_files", { op = fs.op("part", { id = id, url = Url(cwd), files = {} }) })
|
||||||
|
|
||||||
|
local files = {}
|
||||||
|
for line in output.stdout:gmatch("[^\r\n]+") do
|
||||||
|
local url = cwd:join(line)
|
||||||
|
local cha = fs.cha(url, true)
|
||||||
|
if cha then
|
||||||
|
files[#files + 1] = File { url = url, cha = cha }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ya.mgr_emit("update_files", { op = fs.op("part", { id = id, url = Url(cwd), files = files }) })
|
||||||
|
ya.mgr_emit("update_files", { op = fs.op("done", { id = id, url = cwd, cha = Cha { kind = 16 } }) })
|
||||||
|
end
|
||||||
|
|
||||||
|
return { entry = entry }
|
|
@ -82,7 +82,7 @@ macro_workers = 25
|
||||||
bizarre_retry = 5
|
bizarre_retry = 5
|
||||||
image_alloc = 536870912 # 512MB
|
image_alloc = 536870912 # 512MB
|
||||||
image_bound = [ 0, 0 ]
|
image_bound = [ 0, 0 ]
|
||||||
suppress_preload = false
|
suppress_preload = true
|
||||||
|
|
||||||
[plugin]
|
[plugin]
|
||||||
|
|
||||||
|
@ -156,6 +156,12 @@ id = "git"
|
||||||
name = "*/"
|
name = "*/"
|
||||||
run = "git"
|
run = "git"
|
||||||
|
|
||||||
|
[[plugin.prepend_fetchers]]
|
||||||
|
id = "mime"
|
||||||
|
name = "*"
|
||||||
|
run = "mime-ext"
|
||||||
|
prio = "high"
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
cursor_blink = false
|
cursor_blink = false
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue