feat : UI changes in yazi

This commit is contained in:
Ayush Dumasia 2025-06-09 10:28:15 +05:30
parent 00f537b9fd
commit c422a1d05b
13 changed files with 197 additions and 423 deletions

View file

@ -78,8 +78,8 @@ decoration {
dim_special = 0.2 dim_special = 0.2
rounding = 6 rounding = 6
active_opacity = 1 active_opacity = 0.95
inactive_opacity = 1 inactive_opacity = 0.75
shadow { shadow {
enabled = true enabled = true
range = 3 range = 3

View file

@ -1,5 +1,34 @@
require("git"):setup() require("git"):setup()
local mocha_palette = {
rosewater = "#f5e0dc",
flamingo = "#f2cdcd",
pink = "#f5c2e7",
mauve = "#cba6f7",
red = "#f38ba8",
maroon = "#eba0ac",
peach = "#fab387",
yellow = "#f9e2af",
green = "#a6e3a1",
teal = "#94e2d5",
sky = "#89dceb",
sapphire = "#74c7ec",
blue = "#89b4fa",
lavender = "#b4befe",
text = "#cdd6f4",
subtext1 = "#bac2de",
subtext0 = "#a6adc8",
overlay2 = "#9399b2",
overlay1 = "#7f849c",
overlay0 = "#6c7086",
surface2 = "#585b70",
surface1 = "#45475a",
surface0 = "#313244",
base = "#1e1e2e",
mantle = "#181825",
crust = "#11111b",
}
th.git = th.git or { th.git = th.git or {
-- File status styles -- File status styles
modified = ui.Style():fg("#569CD6"):bold(), -- soft blue modified = ui.Style():fg("#569CD6"):bold(), -- soft blue
@ -8,25 +37,163 @@ th.git = th.git or {
renamed = ui.Style():fg("#DCDCAA"), -- light yellow renamed = ui.Style():fg("#DCDCAA"), -- light yellow
untracked = ui.Style():fg("#C586C0"), -- lavender untracked = ui.Style():fg("#C586C0"), -- lavender
ignored = ui.Style():fg("#858585"), -- gray ignored = ui.Style():fg("#858585"), -- gray
-- Status signs (can use icons if your font supports them) -- Status signs (can use icons if your font supports them)
modified_sign = "", -- or "M" modified_sign = "", -- or "M"
added_sign = "", -- or "A" added_sign = "", -- or "A"
deleted_sign = "", -- or "D" deleted_sign = "", -- or "D"
renamed_sign = "", -- or "R" renamed_sign = "", -- or "R"
untracked_sign = "?", untracked_sign = "?",
ignored_sign = "!", ignored_sign = "!",
-- Optional: line change indicators -- Optional: line change indicators
changes = { changes = {
add = ui.Style():fg("#4EC9B0"), -- teal add = ui.Style():fg("#4EC9B0"), -- teal
delete = ui.Style():fg("#F48771"), -- soft red delete = ui.Style():fg("#F48771"), -- soft red
change = ui.Style():fg("#569CD6"), -- soft blue change = ui.Style():fg("#569CD6"), -- soft blue
}, },
-- Optional: blame styling -- Optional: blame styling
blame = { blame = {
style = ui.Style():fg("#858585"):italic(), style = ui.Style():fg("#858585"):italic(),
format = "  %author%, %age%", format = "  %author%, %age%",
} }
} }
require("yatline"):setup({
-- section_separator = { open = "", close = "" },
-- inverse_separator = { open = "", close = "" },
-- part_separator = { open = "|", close = "|" },
style_a = {
fg = mocha_palette.mantle,
bg_mode = {
normal = mocha_palette.blue,
select = mocha_palette.mauve,
un_set = mocha_palette.red,
},
},
style_b = { bg = mocha_palette.surface0, fg = mocha_palette.text },
style_c = { bg = mocha_palette.base, fg = mocha_palette.text },
permissions_t_fg = mocha_palette.green,
permissions_r_fg = mocha_palette.yellow,
permissions_w_fg = mocha_palette.red,
permissions_x_fg = mocha_palette.sky,
permissions_s_fg = mocha_palette.lavender,
selected = { icon = "󰻭", fg = mocha_palette.yellow },
copied = { icon = "", fg = mocha_palette.green },
cut = { icon = "", fg = mocha_palette.red },
total = { icon = "", fg = mocha_palette.yellow },
succ = { icon = "", fg = mocha_palette.green },
fail = { icon = "", fg = mocha_palette.red },
found = { icon = "", fg = mocha_palette.blue },
processed = { icon = "", fg = mocha_palette.green },
tab_width = 20,
tab_use_inverse = true,
show_background = false,
display_header_line = true,
display_status_line = true,
header_line = {
left = {
section_a = {
{ type = "line", custom = false, name = "tabs", params = { "left" } },
},
section_b = {
{ type = "coloreds", custom = false, name = "githead" },
},
section_c = {},
},
right = {
section_a = {
{ type = "string", custom = false, name = "tab_path" },
},
section_b = {
{ type = "coloreds", custom = false, name = "task_workload" },
},
section_c = {
{ type = "coloreds", custom = false, name = "task_states" },
},
},
},
status_line = {
left = {
section_a = {
{ type = "string", custom = false, name = "tab_mode" },
},
section_b = {
{ type = "string", custom = false, name = "hovered_size" },
},
section_c = {
{ type = "string", custom = false, name = "hovered_name" },
{ type = "coloreds", custom = false, name = "count" },
},
},
right = {
section_a = {
{ type = "string", custom = false, name = "cursor_position" },
},
section_b = {
{ type = "string", custom = false, name = "cursor_percentage" },
},
section_c = {
{ type = "string", custom = false, name = "hovered_file_extension", params = { true } },
{ type = "coloreds", custom = false, name = "permissions" },
},
},
},
})
-- require("yatline-githead"):setup()
require("yatline-githead"):setup({
show_branch = true,
branch_prefix = "",
branch_symbol = "",
branch_borders = "",
commit_symbol = "",
show_behind_ahead = true,
behind_symbol = "",
ahead_symbol = "",
show_stashes = true,
stashes_symbol = "",
show_state = true,
show_state_prefix = true,
state_symbol = "󱅉",
show_staged = true,
staged_symbol = "",
show_unstaged = true,
unstaged_symbol = "",
show_untracked = true,
untracked_symbol = "",
prefix_color = mocha_palette.pink,
branch_color = mocha_palette.pink,
commit_color = mocha_palette.mauve,
stashes_color = mocha_palette.teal,
state_color = mocha_palette.lavender,
staged_color = mocha_palette.green,
unstaged_color = mocha_palette.yellow,
untracked_color = mocha_palette.pink,
ahead_color = mocha_palette.green,
behind_color = mocha_palette.yellow,
})
--- @since 25.2.26
require("full-border"):setup({
type = ui.Border.ROUNDED,
})

View file

@ -1,4 +1,4 @@
[[manager.prepend_keymap]] [[mgr.prepend_keymap]]
on = [ "g", "c" ] on = [ "g", "c" ]
run = "plugin vcs-files" run = "plugin vcs-files"
desc = "Show Git file changes" desc = "Show Git file changes"

View file

@ -8,5 +8,20 @@ use = "yazi-rs/plugins:git"
rev = "864a021" rev = "864a021"
hash = "e0ada736ea676c2bbb3ec705a49526ef" hash = "e0ada736ea676c2bbb3ec705a49526ef"
[[plugin.deps]]
use = "imsi32/yatline"
rev = "4872af0"
hash = "d32742ded0e73146a8ca590fdc4fb404"
[[plugin.deps]]
use = "imsi32/yatline-githead"
rev = "f8f969e"
hash = "4d441b38138ce6492a4e10fa349fd65"
[[plugin.deps]]
use = "yazi-rs/plugins:full-border"
rev = "63f9650"
hash = "3996fc74044bc44144b323686f887e1"
[flavor] [flavor]
deps = [] deps = []

View file

@ -1,21 +0,0 @@
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.

View file

@ -1,78 +0,0 @@
# git.yazi
> [!NOTE]
> 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.
https://github.com/user-attachments/assets/34976be9-a871-4ffe-9d5a-c4cdd0bf4576
## Installation
```sh
ya pack -a yazi-rs/plugins:git
```
## Setup
Add the following to your `~/.config/yazi/init.lua`:
```lua
require("git"):setup()
```
And register it as fetchers in your `~/.config/yazi/yazi.toml`:
```toml
[[plugin.prepend_fetchers]]
id = "git"
name = "*"
run = "git"
[[plugin.prepend_fetchers]]
id = "git"
name = "*/"
run = "git"
```
## Advanced
You can customize the [Style](https://yazi-rs.github.io/docs/plugins/layout#style) of the status sign with:
- `th.git.modified`
- `th.git.added`
- `th.git.untracked`
- `th.git.ignored`
- `th.git.deleted`
- `th.git.updated`
For example:
```lua
-- ~/.config/yazi/init.lua
th.git = th.git or {}
th.git.modified = ui.Style():fg("blue")
th.git.deleted = ui.Style():fg("red"):bold()
```
You can also customize the text of the status sign with:
- `th.git.modified_sign`
- `th.git.added_sign`
- `th.git.untracked_sign`
- `th.git.ignored_sign`
- `th.git.deleted_sign`
- `th.git.updated_sign`
For example:
```lua
-- ~/.config/yazi/init.lua
th.git = th.git or {}
th.git.modified_sign = "M"
th.git.deleted_sign = "D"
```
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

View file

@ -1,228 +0,0 @@
--- @since 25.4.4
local WINDOWS = ya.target_family() == "windows"
-- The code of supported git status,
-- also used to determine which status to show for directories when they contain different statuses
-- see `bubble_up`
local CODES = {
excluded = 100, -- ignored directory
ignored = 6, -- ignored file
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 signs = line:sub(1, 2)
for _, p in ipairs(PATTERNS) do
local path, pattern, code = nil, p[1], p[2]
if signs:find(pattern) then
path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4)
path = WINDOWS and path:gsub("/", "\\") or path
end
if not path then
elseif path:find("[/\\]$") then
-- 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
return code, path
end
end
end
local function root(cwd)
local is_worktree = function(url)
local file, head = io.open(tostring(url)), nil
if file then
head = file:read(8)
file:close()
end
return head == "gitdir: "
end
repeat
local next = cwd:join(".git")
local cha = fs.cha(next)
if cha and (cha.is_dir or is_worktree(next)) then
return tostring(cwd)
end
cwd = cwd.parent
until not cwd
end
local function bubble_up(changed)
local new, empty = {}, Url("")
for path, code in pairs(changed) do
if code ~= CODES.ignored then
local url = Url(path).parent
while url and url ~= empty do
local s = tostring(url)
new[s] = (new[s] or CODES.unknown) > code and new[s] or code
url = url.parent
end
end
end
return new
end
local function propagate_down(excluded, cwd, repo)
local new, rel = {}, cwd:strip_prefix(repo)
for _, path in ipairs(excluded) do
if rel:starts_with(path) then
-- If `cwd` is a subdirectory of an excluded directory, also mark it as `excluded`
new[tostring(cwd)] = CODES.excluded
elseif cwd == repo:join(path).parent then
-- If `path` is a direct subdirectory of `cwd`, mark it as `ignored`
new[path] = CODES.ignored
else
-- Skipping, we only care about `cwd` itself and its direct subdirectories for maximum performance
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 path, code in pairs(changed) do
if code == CODES.unknown then
st.repos[repo][path] = nil
elseif code == CODES.excluded then
-- Mark the directory with a special value `excluded` so that it can be distinguished during UI rendering
st.dirs[path] = CODES.excluded
else
st.repos[repo][path] = code
end
end
ya.render()
end)
local remove = ya.sync(function(st, cwd)
local repo = st.dirs[cwd]
if not repo then
return
end
ya.render()
st.dirs[cwd] = nil
if not st.repos[repo] then
return
end
for _, r in pairs(st.dirs) do
if r == repo then
return
end
end
st.repos[repo] = nil
end)
local function setup(st, opts)
st.dirs = {} -- Mapping between a directory and its corresponding repository
st.repos = {} -- Mapping between a repository and the status of each of its files
opts = opts or {}
opts.order = opts.order or 1500
local t = th.git or {}
local styles = {
[CODES.ignored] = t.ignored and ui.Style(t.ignored) or ui.Style():fg("darkgray"),
[CODES.untracked] = t.untracked and ui.Style(t.untracked) or ui.Style():fg("magenta"),
[CODES.modified] = t.modified and ui.Style(t.modified) or ui.Style():fg("yellow"),
[CODES.added] = t.added and ui.Style(t.added) or ui.Style():fg("green"),
[CODES.deleted] = t.deleted and ui.Style(t.deleted) or ui.Style():fg("red"),
[CODES.updated] = t.updated and ui.Style(t.updated) or ui.Style():fg("yellow"),
}
local signs = {
[CODES.ignored] = t.ignored_sign or "",
[CODES.untracked] = t.untracked_sign or "?",
[CODES.modified] = t.modified_sign or "",
[CODES.added] = t.added_sign or "",
[CODES.deleted] = t.deleted_sign or "",
[CODES.updated] = t.updated_sign or "",
}
Linemode:children_add(function(self)
local url = self._file.url
local repo = st.dirs[tostring(url.base)]
local code
if repo then
code = repo == CODES.excluded and CODES.ignored or st.repos[repo][tostring(url):sub(#repo + 2)]
end
if not code or signs[code] == "" then
return ""
elseif self._file.is_hovered then
return ui.Line { " ", signs[code] }
else
return ui.Line { " ", ui.Span(signs[code]):style(styles[code]) }
end
end, opts.order)
end
local function fetch(_, job)
local cwd = job.files[1].url.base
local repo = root(cwd)
if not repo then
remove(tostring(cwd))
return true
end
local paths = {}
for _, file in ipairs(job.files) do
paths[#paths + 1] = tostring(file.url)
end
-- stylua: ignore
local output, err = Command("git")
:cwd(tostring(cwd))
:args({ "--no-optional-locks", "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames", "--ignored=matching" })
:args(paths)
:stdout(Command.PIPED)
:output()
if not output then
return true, Err("Cannot spawn `git` command, error: %s", err)
end
local changed, excluded = {}, {}
for line in output.stdout:gmatch("[^\r\n]+") do
local code, path = match(line)
if code == CODES.excluded then
excluded[#excluded + 1] = path
else
changed[path] = code
end
end
if job.files[1].cha.is_dir then
ya.dict_merge(changed, bubble_up(changed))
end
ya.dict_merge(changed, propagate_down(excluded, 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
add(tostring(cwd), repo, changed)
return false
end
return { setup = setup, fetch = fetch }

View file

@ -1,21 +0,0 @@
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.

View file

@ -1,29 +0,0 @@
# 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.

View file

@ -1,33 +0,0 @@
--- @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 }

View file

@ -1,4 +1,4 @@
[manager] [mgr]
cwd = { fg = "#94e2d5" } cwd = { fg = "#94e2d5" }
hovered = { fg = "#1e1e2e", bg = "#89b4fa" } hovered = { fg = "#1e1e2e", bg = "#89b4fa" }
@ -747,4 +747,4 @@ exts = [
{ name = "kicad_pro", text = "", fg = "#f5e0dc" }, { name = "kicad_pro", text = "", fg = "#f5e0dc" },
{ name = "liquid", text = "", fg = "#a6e3a1" }, { name = "liquid", text = "", fg = "#a6e3a1" },
{ name = "zip", text = "", fg = "#fab387" }, { name = "zip", text = "", fg = "#fab387" },
] ]

View file

@ -2,8 +2,8 @@
# If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas. # If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas.
"$schema" = "https://yazi-rs.github.io/schemas/yazi.json" "$schema" = "https://yazi-rs.github.io/schemas/yazi.json"
[manager] [mgr]
ratio = [ 2, 4, 3 ] ratio = [ 1, 3, 4 ]
sort_by = "alphabetical" sort_by = "alphabetical"
sort_sensitive = false sort_sensitive = false
sort_reverse = false sort_reverse = false

View file

@ -83,6 +83,7 @@ zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'ls --color $realpath'
# # Shell integrations # # Shell integrations
eval "$(fzf --zsh)" eval "$(fzf --zsh)"
export _ZO_ECHO='0'
eval "$(zoxide init --cmd cd zsh)" eval "$(zoxide init --cmd cd zsh)"
eval $(thefuck --alias) eval $(thefuck --alias)
eval "$(atuin init zsh)" eval "$(atuin init zsh)"
@ -111,13 +112,14 @@ ms(){
alias kls='kubectl get all' alias kls='kubectl get all'
alias jump='nvim $(fzf -m --preview="bat --color=always {}")' alias jump='nvim $(fzf -m --preview="bat --color=always {}")'
alias ls='eza -l -i --header --tree --level=1 --all --sort=Name' alias ls='eza -l --icons --level=0 --tree --sort=Name'
alias search='eval "~/.local/bin/search.sh"' alias search='eval "~/.local/bin/search.sh"'
alias cod='code .' alias cod='code .'
# Tmux # Tmux
alias t='tmux new -s ' alias t='tmux new -s '
alias tt='tmux a -t' alias tt='tmux a -t'
alias fbat="fzf --preview 'bat --style=numbers --color=always --line-range :500 {}'"
alias seek='pacseek' alias seek='pacseek'
alias y='yazi' alias y='yazi'
@ -144,7 +146,7 @@ cpcf() {
} }
mount_gdrive() { mount_gdrive() {
rclone mount gdrive: ~/mnt/gdrive rclone mount gdrive: ~/mnt/gdrive
} }
gh_open() { gh_open() {