adde latex lsp and language

This commit is contained in:
liph22
2026-01-10 14:22:02 +01:00
parent b7cfdb00a3
commit d7b808ce59
32 changed files with 994 additions and 455 deletions

View File

@@ -0,0 +1,7 @@
-- Tell Neovim to treat .ltx as regular tex
vim.filetype.add({
extension = {
ltx = "tex",
tex = "tex",
},
})

View File

@@ -13,13 +13,19 @@ vim.opt.rtp:prepend(lazypath)
-- Only enable spell checking for specific filetypes
vim.api.nvim_create_autocmd("FileType", {
pattern = { "markdown", "text", "gitcommit", "tex" },
pattern = { "markdown", "text", "gitcommit", "tex", "plaintext" },
callback = function()
vim.opt_local.spell = true
vim.opt_local.spelllang = "en_us,de"
end,
})
vim.filetype.add({
extension = {
tex = "tex",
},
})
require("vim-options")
require("lazy").setup("plugins")
require("lualine").setup({

View File

@@ -54,6 +54,7 @@
"telescope.nvim": { "branch": "master", "commit": "3333a52ff548ba0a68af6d8da1e54f9cd96e9179" },
"trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" },
"vim-test": { "branch": "master", "commit": "aa619692ff48a3cf3e6bdb893765039488d4e5f3" },
"vimtex": { "branch": "master", "commit": "1b56d5ae6e19cd018f1adaf4868561b087698b9b" },
"vimux": { "branch": "master", "commit": "614f0bb1fb598f97accdcea71d5f7b18d7d62436" },
"which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" },
"yazi.nvim": { "branch": "main", "commit": "30d8c852a0ca52437dad84cf5c92962d565a54a9" }

View File

@@ -25,9 +25,16 @@ return {
graphql = { "prettier" },
handlebars = { "prettier" },
-- Toml
toml = { "tombi" },
-- text
-- Ruby
ruby = { "rubocop" },
-- latex
tex = { "tex-fmt" },
-- Python (black first, then isort for imports)
python = { "black", "isort" },
@@ -52,7 +59,7 @@ return {
prepend_args = { "--tab-width", "2" },
},
beautysh = {
prepend_args = { "--indent-size", "2" }, -- 2 spaces for bash
prepend_args = { "--indent-size", "2" }, -- 2 spaces for bash
},
},
})

View File

@@ -17,16 +17,49 @@ return {
"neovim/nvim-lspconfig",
lazy = false,
dependencies = {
"SmiteshP/nvim-navic", -- Add this dependency
"SmiteshP/nvim-navic",
},
config = function()
local capabilities = require('cmp_nvim_lsp').default_capabilities()
local capabilities = require("cmp_nvim_lsp").default_capabilities()
local navic = require("nvim-navic")
-- Define server configurations
local servers = {
ts_ls = {},
tombi = {},
solargraph = {},
textlsp = {
filetypes = { "ltx", "txt" },
},
-- Add texlab for LaTeX
texlab = {
settings = {
texlab = {
build = {
executable = "latexmk",
args = { "-pdf", "-interaction=nonstopmode", "-synctex=1", "%f" },
onSave = true,
},
forwardSearch = {
executable = "zathura", -- Change to your PDF viewer if different
args = { "--synctex-forward", "%l:1:%f", "%p" },
},
chktex = {
onOpenAndSave = true,
onEdit = false,
},
},
},
},
-- Optional: Add ltex for grammar/spell checking (can be resource-heavy)
ltex = {
settings = {
ltex = {
language = "en-US", -- or "de-DE", "de-CH", etc.
enabled = { "latex", "tex", "bib" },
},
},
},
html = {},
lua_ls = {
settings = {
@@ -44,7 +77,6 @@ return {
},
},
pyright = {},
bashls = {
filetypes = { "sh", "bash", "zsh" },
settings = {
@@ -59,14 +91,12 @@ return {
-- Setup each server with the new API
for server, config in pairs(servers) do
config.capabilities = capabilities
-- Add navic on_attach for breadcrumbs
config.on_attach = function(client, bufnr)
if client.server_capabilities.documentSymbolProvider then
navic.attach(client, bufnr)
end
end
vim.lsp.config[server] = config
vim.lsp.enable(server)
end

View File

@@ -11,6 +11,9 @@ return {
"black",
"isort",
"beautysh",
"tombi",
"tex-fmt",
"texlab",
-- Linters (add these)
"ruff", -- Python (fast!)

View File

@@ -65,7 +65,7 @@ return {
vim.keymap.set("n", "<leader>fS", builtin.lsp_workspace_symbols, {})
-- Diagnostics
vim.keymap.set("n", "<leader>fd", builtin.diagnostics, {})
vim.keymap.set("n", "<leader>fD", builtin.diagnostics, {})
-- Resume last picker
vim.keymap.set("n", "<leader>f.", builtin.resume, {})

View File

@@ -17,18 +17,18 @@ return {
-- Other languages you use
"lua",
"vim",
"latex",
},
-- Auto install missing parsers
auto_install = true,
-- Enable syntax highlighting
highlight = {
enable = true,
-- Optional: disable markdown highlighting if render-markdown handles it
-- disable = { 'markdown' },
},
-- -- Enable syntax highlighting
-- highlight = {
-- enable = true,
-- -- Optional: disable markdown highlighting if render-markdown handles it
-- disable = { "latex", "tex" }, -- Disable for LaTeX
-- },
-- Enable indentation
indent = {
enable = true,

View File

@@ -0,0 +1,86 @@
return {
"lervag/vimtex",
ft = "tex",
config = function()
-- PDF viewer
vim.g.vimtex_view_method = "zathura"
-- Compiler settings
vim.g.vimtex_compiler_latexmk = {
continuous = 1,
callback = 1,
options = {
"-pdf",
"-shell-escape",
"-verbose",
"-file-line-error",
"-synctex=1",
"-interaction=nonstopmode",
},
}
-- Concealment (makes LaTeX prettier to read)
vim.g.vimtex_syntax_conceal = {
accents = 1,
math_symbols = 1,
math_fracs = 1,
math_super_sub = 1,
}
vim.g.vimtex_toc_config = {
name = "TOC",
layers = { "content", "todo", "include" },
split_width = 25,
todo_sorted = 0,
show_help = 1,
show_numbers = 1,
}
-- Don't open quickfix window automatically
vim.g.vimtex_quickfix_mode = 0
-- kenable folding
vim.g.vimtex_fold_enabled = 1
-- What to fold (customize as needed)
vim.g.vimtex_fold_types = {
envs = {
enabled = 1,
whitelist = {}, -- Empty = all environments
blacklist = {},
},
sections = {
enabled = 1,
sections = {
"%(add)?part",
"%(chapter|%(sub)*section|%(sub)?paragraph)",
"appendix",
},
},
items = {
enabled = 0, -- Don't fold individual list items
},
}
-- Disable some features for better performance (optional)
vim.g.vimtex_indent_enabled = 1
vim.g.vimtex_syntax_enabled = 1
vim.g.vimtex_syntax_conceal = {
accents = 1,
ligatures = 1,
cites = 1,
fancy = 1,
spacing = 1,
greek = 1,
math_bounds = 1,
math_delimiters = 1,
math_fracs = 1,
math_super_sub = 1,
math_symbols = 1,
sections = 0,
styles = 1,
}
vim.opt.conceallevel = 2
end,
}

View File

@@ -15,3 +15,7 @@ vim.keymap.set("n", "<c-l>", ":wincmd l<CR>")
vim.keymap.set("n", "<leader>h", ":nohlsearch<CR>")
vim.wo.number = true
-- In your keybindings file
vim.keymap.set("n", "<leader>lc", ":!pdflatex %<CR>", { desc = "Compile LaTeX" })
vim.keymap.set("n", "<leader>lv", ":!zathura %:r.pdf &<CR>", { desc = "View PDF" })

View File

@@ -1,7 +0,0 @@
hydroxide serve &
kanata --cfg ~/.config/kanata/config.kbd &
sudo mount -a &
syncthing &

3
scripts/scripts/latex.sh Executable file
View File

@@ -0,0 +1,3 @@
pdflatex "$1" && zathura "${1%.tex}.pdf" &

View File

@@ -1,89 +0,0 @@
#!/bin/bash
# Configuration variables - change this for your setup
gluetun_container_name="gluetun"
qbittorrent_container_name="qbittorrent"
gluetun_origin="http://100.120.152.94:8888"
qb_origin="http://100.120.152.94:8099"
####################################################################
# Arrays for URLs
declare -A gluetun_urls=(
["pub_ip"]="$gluetun_origin/v1/publicip/ip"
["portforwarded"]="$gluetun_origin/v1/openvpn/portforwarded"
)
declare -A qbittorrent_urls=(
#used for getting and setting listen_port
["prefs"]="$qb_origin/api/v2/app/preferences"
["setPrefs"]="$qb_origin/api/v2/app/setPreferences"
)
# Function to check if a Docker container is running
is_container_running() {
local container_name="$1"
docker inspect -f '{{.State.Running}}' "$container_name" 2>/dev/null
# echo "Container $container_name status: $status"
}
get_vpn_external_ip() {
local url="$1"
curl -s "$url" | -r .'public_ip'
}
# Function to send a GET request and extract the port from the response
get_port_from_url() {
local url="$1"
local port_key
# Try 'port' key first
port_key=$(curl -s "$url" | jq -r '.port')
if [ "$port_key" == "null" ]; then
# If 'port' key is null, try 'listen_port' key
port_key=$(curl -s "$url" | jq -r '.listen_port')
fi
echo "$port_key"
}
# Function to send a POST request with JSON data
send_post_request() {
local url="$1"
local port="$2"
curl -s -X POST -d json={\"listen_port\":$port} "$url"
}
# Outputs container names
echo "Gluetun container name: $gluetun_container_name - Gluetun Origin URL: $gluetun_origin"
echo "qBittorrent container name: $qbittorrent_container_name - qBittorrent Origin URL: $qb_origin"
# Check if both containers are running
if [[ $(is_container_running "$gluetun_container_name") == $(is_container_running "$qbittorrent_container_name") ]]; then
echo "Both Gluetun and qBittorrent containers are running. Continuing."
external_ip=$(get_vpn_external_ip "${gluetun_urls["pub_ip"]}")
if [ -z "$external_ip" ]; then
echo "External IP is empty. Exiting script due to potential VPN or internet connection issue."
exit 1
else
echo "External IP is $external_ip therefore VPN is up"
fi
gluetun_port=$(get_port_from_url "${gluetun_urls["portforwarded"]}")
qbittorrent_port=$(get_port_from_url "${qbittorrent_urls["prefs"]}")
echo "Gluetun forwarded port is $gluetun_port"
echo "qBittorrent listen port is $qbittorrent_port"
if [ "$gluetun_port" -eq "$qbittorrent_port" ]; then
echo "qBittorrent listen port is already set to $qbittorrent_port. No need to change. Exiting script."
else
echo "Updating qBittorrent listen port to Gluetun forwarded port $gluetun_port."
send_post_request "${qbittorrent_urls["setPrefs"]}" "$gluetun_port"
qbittorrent_port=$(get_port_from_url "${qbittorrent_urls["prefs"]}")
echo "qBittorrent listen port updated to $qbittorrent_port. Exiting script."
fi
else
echo "Either Gluetun or qBittorrent container is not running. Exiting script."
fi

View File

@@ -1,9 +1,22 @@
require("mime-ext"):setup({
-- with_files = {
-- tex = "text/makefile",
-- },
with_exts = {
tex = "text/makefile",
},
})
require("full-border"):setup({
-- Available values: ui.Border.PLAIN, ui.Border.ROUNDED
type = ui.Border.ROUNDED,
})
-- git-yazi plugin
-- th.git = th.git or {}
-- th.git.modified = ui.Style():fg("blue")
-- th.git.deleted = ui.Style():fg("red"):bold()
require("git"):setup()
-- whoosh plugin
-- You can configure your bookmarks using simplified syntax
-- local bookmarks = {

View File

@@ -1,287 +1,154 @@
[mgr]
prepend_keymap = [
{ on = "F", run = "plugin smart-filter", desc = "Smart filter" },
# rsync plugin
{on = [ "R" ], run = "plugin rsync", desc = "Copy files using rsync"},
{ on = ["R"], run = "plugin rsync", desc = "Copy files using rsync" },
# yafg plugin
{ on = [ "F", "G" ], run = "plugin yafg"},
{ on = ["F", "G"], run = "plugin yafg" },
# lazygit plugin
{on = [ "g", "i" ], run = "plugin lazygit", desc = "run lazygit"},
{ on = ["g", "i"], run = "plugin lazygit", desc = "run lazygit" },
# mount plugin
{ on = "M", run = "plugin mount"},
{ on = "M", run = "plugin mount" },
# smart-enter plugin
{ on = "l", run = "plugin smart-enter", desc = "Enter the child directory, or open the file"},
{ on = "l", run = "plugin smart-enter", desc = "Enter the child directory, or open the file" },
# jump-to-char plugin
{ on = "f", run = "plugin jump-to-char", desc = "Jump to char" },
# whoosh plugin
{ on = "[", run = "plugin whoosh jump_by_key", desc = "Jump bookmark by key"},
{ on = "[", run = "plugin whoosh jump_by_key", desc = "Jump bookmark by key" },
# Direct fuzzy search access
{ on = "}", run = "plugin whoosh jump_by_fzf", desc = "Direct fuzzy search for bookmarks"},
{ on = "}", run = "plugin whoosh jump_by_fzf", desc = "Direct fuzzy search for bookmarks" },
# Basic bookmark operations
{ on = [ "]", "a" ], run = "plugin whoosh save", desc = "Add bookmark (hovered file/directory)"},
{ on = [ "]", "A" ], run = "plugin whoosh save_cwd", desc = "Add bookmark (current directory)"},
{ on = ["]", "a"], run = "plugin whoosh save", desc = "Add bookmark (hovered file/directory)" },
{ on = ["]", "A"], run = "plugin whoosh save_cwd", desc = "Add bookmark (current directory)" },
## Temporary bookmarks
{ on = [ "]", "t" ], run = "plugin whoosh save_temp", desc = "Add temporary bookmark (hovered file/directory)"},
{ on = [ "]", "T" ], run = "plugin whoosh save_cwd_temp", desc = "Add temporary bookmark (current directory)"},
{ on = ["]", "t"], run = "plugin whoosh save_temp", desc = "Add temporary bookmark (hovered file/directory)" },
{ on = ["]", "T"], run = "plugin whoosh save_cwd_temp", desc = "Add temporary bookmark (current directory)" },
## Jump to bookmarks
{ on = "<A-k>", run = "plugin whoosh jump_key_k", desc = "Jump directly to bookmark with key k"},
{ on = [ "]", "f" ], run = "plugin whoosh jump_by_fzf", desc = "Jump bookmark by fzf"},
{ on = "<A-k>", run = "plugin whoosh jump_key_k", desc = "Jump directly to bookmark with key k" },
{ on = ["]", "f"], run = "plugin whoosh jump_by_fzf", desc = "Jump bookmark by fzf" },
## Delete bookmarks
{ on = [ "]", "d" ], run = "plugin whoosh delete_by_key", desc = "Delete bookmark by key"},
{ on = [ "]", "D" ], run = "plugin whoosh delete_by_fzf", desc = "Delete bookmarks by fzf (use TAB to select multiple)"},
{ on = [ "]", "C" ], run = "plugin whoosh delete_all", desc = "Delete all user bookmarks"},
{ on = ["]", "d"], run = "plugin whoosh delete_by_key", desc = "Delete bookmark by key" },
{ on = ["]", "D"], run = "plugin whoosh delete_by_fzf", desc = "Delete bookmarks by fzf (use TAB to select multiple)" },
{ on = ["]", "C"], run = "plugin whoosh delete_all", desc = "Delete all user bookmarks" },
## Rename Bookmarks
{ on = [ "]", "r" ], run = "plugin whoosh rename_by_key", desc = "Rename bookmark by key"},
{ on = [ "]", "R" ], run = "plugin whoosh rename_by_fzf", desc = "Rename bookmark by fzf"},
{ on = ["]", "r"], run = "plugin whoosh rename_by_key", desc = "Rename bookmark by key" },
{ on = ["]", "R"], run = "plugin whoosh rename_by_fzf", desc = "Rename bookmark by fzf" },
# Navigation
{ on = ["<Esc>"], run = "escape", desc = "Exit visual mode, clear selected, or cancel search" },
{ on = ["q"], run = "quit", desc = "Exit the process" },
{ on = ["<C-q>"], run = "close", desc = "Close the current tab, or quit if it is last tab" },
{ on = ["<Esc>"], run = "escape", desc = "Exit visual mode, clear selected, or cancel search" },
{ on = ["q"], run = "quit", desc = "Exit the process" },
{ on = ["<C-q>"], run = "close", desc = "Close the current tab, or quit if it is last tab" },
# projects plugin
{on = [ "P", "p" ], run = "plugin projects 'load SomeProject'", desc = "Load the 'SomeProject' project"},
{on = [ "P", "s" ], run = "plugin projects save", desc = "Save current project"},
{on = [ "P", "l" ], run = "plugin projects load", desc = "Load project"},
{on = [ "P", "P" ], run = "plugin projects load_last", desc = "Load last project"},
{on = [ "P", "d" ], run = "plugin projects delete", desc = "Delete project"},
{on = [ "P", "D" ], run = "plugin projects delete_all", desc = "Delete all projects"},
{on = [ "P", "m" ], run = "plugin projects 'merge current'", desc = "Merge current tab to other projects"},
{on = [ "P", "M" ], run = "plugin projects 'merge all'", desc = "Merge current project to other projects"},
{ on = ["P", "p"], run = "plugin projects 'load SomeProject'", desc = "Load the 'SomeProject' project" },
{ on = ["P", "s"], run = "plugin projects save", desc = "Save current project" },
{ on = ["P", "l"], run = "plugin projects load", desc = "Load project" },
{ on = ["P", "P"], run = "plugin projects load_last", desc = "Load last project" },
{ on = ["P", "d"], run = "plugin projects delete", desc = "Delete project" },
{ on = ["P", "D"], run = "plugin projects delete_all", desc = "Delete all projects" },
{ on = ["P", "m"], run = "plugin projects 'merge current'", desc = "Merge current tab to other projects" },
{ on = ["P", "M"], run = "plugin projects 'merge all'", desc = "Merge current project to other projects" },
# fazif plugin
{on = [ "b", "d" ], run = "plugin fazif faziffd", desc = "Find files/directories with fd and fzf"},
{on = [ "b", "D" ], run = "plugin fazif faziffdr", desc = "Find files/directories with fd and fzf"},
{on = [ "b", "r" ], run = "plugin fazif fazifrg", desc = "Find content in files with ripgrep and fzf"},
{on = [ "b", "R" ], run = "plugin fazif fazifrga", desc = "Find content in documents with ripgrep-all and fzf"},
# Tagging plugin
#─────────────────────────── TOGGLE TAG(S) ────────────────────────────
# Toggle a tag (press any tag key)
# A tag hint window will show up.
# Simply press any tag key to toggle that tag for selected or hovered files/folders.
{ on = [ "t", "t", "k" ], run = "plugin simple-tag -- toggle-tag", desc = "Toggle a tag (press any key)" },
# Fast Toggle tag(s) with fixed keys=!1q. key=!1q tag=!1q or tags=!1q also work
# NOTE: For key=" (Quotation mark), then use key=\" (Backslash + Quotation mark) instead.
{ on = [ "`" ], run = "plugin simple-tag -- toggle-tag --keys=!1q", desc = "Toggle tag(s) with fixed tag key(s) = (! and 1 and q)" },
# { on = [ "`" ], run = "plugin simple-tag -- toggle-tag --keys=*", desc = "Toggle tag with fixed tag key = *" },
# { on = [ "`" ], run = "plugin simple-tag -- toggle-tag --key=*", desc = "Toggle tag with fixed tag key = *" },
# Toggle tag(s) with value from input box.
# A tag hint window and an input box will show up.
# Simply input tag key(s) to toggle that tags for selected or hovered files/folders.
# Do not input any delimiter.
{ on = [ "t", "t", "i" ], run = "plugin simple-tag -- toggle-tag --input", desc = "Toggle tag(s) with value from (input box)" },
#─────────────────────────── ADD TAG(S) ───────────────────────────────
# Add a tag (press any tag key)
# A tag hint window will show up.
# Simply press any new tag key to add to selected or hovered files/folders.
{ on = [ "t", "a", "k" ], run = "plugin simple-tag -- add-tag", desc = "Add a tag (press any key)" },
# Fast Add tag(s) with fixed keys=!1q. key=!1q tag=!1q or tags=!1q also work
{ on = [ "t", "a", "f" ], run = "plugin simple-tag -- add-tag --keys=!1q", desc = "Add tag(s) with fixed tag keys = (! and 1 and q)" },
# { on = [ "t", "a", "f" ], run = "plugin simple-tag -- add-tag --keys=*", desc = "Add tag with fixed tag key = *" },
# { on = [ "t", "a", "f" ], run = "plugin simple-tag -- add-tag --key=*", desc = "Add tag with fixed tag key = *" },
# Add tag(s) with value from input box.
# A tag hint window and an input box will show up.
# Simply input new tag key(s) to add to selected or hovered files/folders.
# Do not input any delimiter.
{ on = [ "t", "a", "i" ], run = "plugin simple-tag -- add-tag --input", desc = "Add tag(s) with value from (input box)" },
#─────────────────────────── REMOVE/DELETE TAG(S) ───────────────────────────
# Remove a tag (press any tag key)
# A tag hint window will show up.
# Simply press any tag key to be removed from selected or hovered files/folders.
{ on = [ "t", "d", "k" ], run = "plugin simple-tag -- remove-tag", desc = "Remove a tag (press any key)" },
# Fast Remove tag(s) with fixed keys=!1q. key=!1q tag=!1q or tags=!1q also work
{ on = [ "t", "d", "f" ], run = "plugin simple-tag -- remove-tag --keys=!1q", desc = "Remove tag(s) with fixed tag keys = (! and 1 and q)" },
# { on = [ "t", "d", "f" ], run = "plugin simple-tag -- remove-tag --keys=*", desc = "Remove tag with fixed tag key = *" },
# { on = [ "t", "d", "f" ], run = "plugin simple-tag -- remove-tag --key=*", desc = "Remove tag with fixed tag key = *" },
# Remove tag(s) with value from input box.
# A tag hint window and an input box will show up.
# Simply input tag key(s) to be removed from selected or hovered files/folders.
# Do not input any delimiter.
{ on = [ "t", "d", "i" ], run = "plugin simple-tag -- remove-tag --input", desc = "Remove tag(s) with value from (input box)" },
#─────────────────────────── REPLACE ALL OLD TAG(S) WITH NEW TAG(S) ───────────────────────────
# Replace a tag (press any tag key)
# A tag hint window will show up.
# Simply press any new tag key for selected or hovered files/folders.
{ on = [ "t", "r", "k" ], run = "plugin simple-tag -- replace-tag", desc = "Replace with a new tag (press any key)" },
# Fast Replace tag(s) with fixed keys=!1q. key=!1q tag=!1q or tags=!1q also work
{ on = [ "t", "r", "f" ], run = "plugin simple-tag -- replace-tag --keys=!1q", desc = "Replace tag(s) with fixed tag keys = (! and 1 and q)" },
# { on = [ "t", "r", "f" ], run = "plugin simple-tag -- replace-tag --keys=*", desc = "Replace tag(s) with fixed tag key = *" },
# { on = [ "t", "r", "f" ], run = "plugin simple-tag -- replace-tag --key=*", desc = "Replace tag(s) with fixed tag key = *" },
# Replace tag(s) with value from input box.
# A tag hint window and an input box will show up.
# Simply input new tag key(s) for selected or hovered files/folders.
# Do not input any delimiter.
{ on = [ "t", "r", "i" ], run = "plugin simple-tag -- replace-tag --input", desc = "Replace tag(s) with value from (input box)" },
#─────────────────────────── EDIT TAG(S) ───────────────────────────
# Edit a tag for hovered or selected files/folders
# An input box with current tagged keys and a tag hint window will show up for each hovered or selected files/folders.
# Simply edit tag key(s) for selected or hovered files/folders.
# If you cancel any input box, all changes will be discarded.
{ on = [ "t", "e" ], run = "plugin simple-tag -- edit-tag ", desc = "Edit tag(s) (input box)" },
# ───────────────────────────── CLEAR TAG(S) ─────────────────────────────
# Clear all tags from selected or hovered files/folders
{ on = [ "t", "c" ], run = "plugin simple-tag -- clear", desc = "Clear all tags from selected or hovered files" },
# ───────────────────────────── CHANGE UI ─────────────────────────────
# Switch tag indicator between icon > tag key > hidden.
# Useful when u don't remember the tag key
{ on = [ "t", "u", "s" ], run = "plugin simple-tag -- toggle-ui", desc = "Toggle tag indicator (icon > tag key > hidden)" },
# Fixed tag indicator mode = hidden (Available modes: hidden|icon|text)
{ on = [ "t", "u", "h" ], run = "plugin simple-tag -- toggle-ui --mode=hidden", desc = "Hide all tags indicator" },
# ─────────────────────── FILTER FILES/FOLDERS BY TAGS: ───────────────────────
# Available filter modes:
# and → Filter files which contain all of selected tags (Default if mode isn't specified).
# or → Filter files which contain at least one of selected tags.
# NOTE: Not available in vfs mode (Remote Virtual Filesystem)
# Filter files/folders by tags
# Filter files/folders by a tag (press any tag key)
# A tag hint window will show up.
# Simply press any new tag key to filter files/folders containing that tag in current directory.
{ on = [ "t", "f" ], run = "plugin simple-tag -- filter", desc = "Filter files/folders by a tag (press any key)" },
# Fast Filter files/folders with fixed keys=!1q. key=!1q tag=!1q or tags=!1q also work
# { on = [ "t", "f" ], run = "plugin simple-tag -- filter --key=!", desc = "Filter files/folders by a fixed tag = !" },
# { on = [ "t", "f" ], run = "plugin simple-tag -- filter --keys=!1q", desc = "Filter files/folders by multiple fixed tag(s) (! and 1 and q)" },
# Filter files/folders by tag(s) with value from input box.
# An input box and a tag hint window will show up.
# Simply input tag key(s) to filter files/folders of current directory.
# Do not input any delimiter.
# For example: Input value or --keys=!1q -> filter any files/folders contain all of these tags (! and 1 and q) in current directory.
{ on = [ "t", "F" ], run = "plugin simple-tag -- filter --input", desc = "Filter files/folders by tag(s) (input box)" },
# Filter files/folders by tag(s) with --mode=or.
# --mode=or -> Input value or --keys = !1q -> filter any files/folders contain at least one of these tags (! or 1 or q)
{ on = [ "t", "F" ], run = "plugin simple-tag -- filter --input --mode=or", desc = "Filter files/folders by contain tags (input box)" },
# { on = [ "t", "F" ], run = "plugin simple-tag -- filter --keys=!1q --mode=or", desc = "Filter files/folders by multiple fixed tag(s) (! or 1 or q)" },
# ─────────────────────── VISUAL SELECT FILES/FOLDERS BY TAGS: ───────────────────────
# Available selection actions:
# replace → Replaces the current selection list with files/folders that have the selected tag.
# unite → Combines the currently selected files/folders with those that have the selected tag.
# intersect → Keeps only the files/folders that are present in both the current selection and the tagged items.
# subtract → Deselects files/folders that have the selected tag from the current selection.
# exclude → Combines the currently selected files/folders with the tagged items, then deselects any overlapping items between the current selection and the tagged items.
# undo → Undos or redoes the last selection action.
# which_key will popup to choose selection mode
# And a tag hint window will show up.
# Simply select a selection mode then press any tag key to select files/folders
{ on = [ "t", "s", "t" ], run = "plugin simple-tag -- toggle-select", desc = "Select a selection action then select a tag key (toggle-select)" },
# fixed tag(s). --keys=!1q or --key=!1q or --tag=!1q or --tags=!1q. They are the same.
{ on = [ "t", "s", "t" ], run = "plugin simple-tag -- toggle-select --keys=!1q", desc = "" },
# Run action on files/folders by a tag.
# A tag hint window will show up.
# Simply press any tag key to do the following action:
{ on = [ "t", "s", "r" ], run = "plugin simple-tag -- replace-select", desc = "replace-select" },
{ on = [ "t", "s", "u" ], run = "plugin simple-tag -- unite-select", desc = "unite-select" },
{ on = [ "t", "s", "i" ], run = "plugin simple-tag -- intersect-select", desc = "intersect-select" },
{ on = [ "t", "s", "s" ], run = "plugin simple-tag -- subtract-select", desc = "subtract-select" },
{ on = [ "t", "s", "e" ], run = "plugin simple-tag -- exclude-select", desc = "exclude-select" },
# Run action on files/folders by fixed tag(s). --keys=!1q or --key=!1q or --tag=!1q or --tags=!1q. They are the same.
{ on = [ "t", "s", "e" ], run = "plugin simple-tag -- replace-select --keys=!1q", desc = "Replaces the current selection list with files/folders that have (! and 1 and q) tag(s)" },
# Run action on files/folders by tag(s) with value from input box.
# A tag hint window will show up.
# Simply input tag key(s) to do the following action:
{ on = [ "t", "s", "R" ], run = "plugin simple-tag -- replace-select --input", desc = "replace-select --input" },
{ on = [ "t", "s", "U" ], run = "plugin simple-tag -- unite-select --input", desc = "unite-select --input" },
{ on = [ "t", "s", "I" ], run = "plugin simple-tag -- intersect-select --input", desc = "intersect-select --input" },
{ on = [ "t", "s", "S" ], run = "plugin simple-tag -- subtract-select --input", desc = "subtract-select --input" },
{ on = [ "t", "s", "E" ], run = "plugin simple-tag -- exclude-select --input", desc = "exclude-select --input" },
# it also support --mode=or when using with --input or --keys=!1q or --key=!1q or --tag=!1q or --tags=!1q
{ on = [ "t", "s", "R" ], run = "plugin simple-tag -- replace-select --input --mode=or", desc = "replace-select --input --mode=or" },
{ on = [ "t", "s", "R" ], run = "plugin simple-tag -- replace-select --keys=!1q --mode=or", desc = "replace-select --keys=!1q --mode=or" },
# Undo/Redo selection (only works after using 5 modes above)
{ on = [ "t", "s", "u" ], run = "plugin simple-tag -- undo-select", desc = "Undos/Redos the last selection action" },
{ on = ["b", "d"], run = "plugin fazif faziffd", desc = "Find files/directories with fd and fzf" },
{ on = ["b", "D"], run = "plugin fazif faziffdr", desc = "Find files/directories with fd and fzf" },
{ on = ["b", "r"], run = "plugin fazif fazifrg", desc = "Find content in files with ripgrep and fzf" },
{ on = ["b", "R"], run = "plugin fazif fazifrga", desc = "Find content in documents with ripgrep-all and fzf" },
# Tagging plugin
# ─────────────────────────── TOGGLE TAG(S) ────────────────────────────
{ on = ["t", "t", "k"], run = "plugin simple-tag -- toggle-tag", desc = "Toggle a tag (press any key)" },
{ on = ["'"], run = "plugin simple-tag -- toggle-tag --keys=!", desc = "Toggle tag(s) with fixed tag key(s) = (! and 1 and q)" },
{ on = ["-"], run = "plugin simple-tag -- toggle-tag --keys=1", desc = "Toggle tag(s) with fixed tag key(s) = (! and 1 and q)" },
{ on = ["t", "t", "i"], run = "plugin simple-tag -- toggle-tag --input", desc = "Toggle tag(s) with value from (input box)" },
# ─────────────────────────── ADD TAG(S) ───────────────────────────────
{ on = ["t", "a", "k"], run = "plugin simple-tag -- add-tag", desc = "Add a tag (press any key)" },
# { on = [ "t", "a", "f" ], run = "plugin simple-tag -- add-tag --keys=!1q", desc = "Add tag(s) with fixed tag keys = (! and 1 and q)" },
{ on = ["t", "a", "i"], run = "plugin simple-tag -- add-tag --input", desc = "Add tag(s) with value from (input box)" },
# ─────────────────────────── REMOVE/DELETE TAG(S) ───────────────────────────
{ on = ["t", "d", "k"], run = "plugin simple-tag -- remove-tag", desc = "Remove a tag (press any key)" },
{ on = ["t", "d", "f"], run = "plugin simple-tag -- remove-tag --keys=!1q", desc = "Remove tag(s) with fixed tag keys = (! and 1 and q)" },
{ on = ["t", "d", "i"], run = "plugin simple-tag -- remove-tag --input", desc = "Remove tag(s) with value from (input box)" },
# ─────────────────────────── REPLACE ALL OLD TAG(S) WITH NEW TAG(S) ───────────────────────────
{ on = ["t", "r", "k"], run = "plugin simple-tag -- replace-tag", desc = "Replace with a new tag (press any key)" },
{ on = ["t", "r", "f"], run = "plugin simple-tag -- replace-tag --keys=!1q", desc = "Replace tag(s) with fixed tag keys = (! and 1 and q)" },
{ on = ["t", "r", "i"], run = "plugin simple-tag -- replace-tag --input", desc = "Replace tag(s) with value from (input box)" },
# ─────────────────────────── EDIT TAG(S) ───────────────────────────
{ on = ["t", "e"], run = "plugin simple-tag -- edit-tag ", desc = "Edit tag(s) (input box)" },
# ───────────────────────────── CLEAR TAG(S) ─────────────────────────────
{ on = ["t", "c"], run = "plugin simple-tag -- clear", desc = "Clear all tags from selected or hovered files" },
# ───────────────────────────── CHANGE UI ─────────────────────────────
{ on = ["t", "u", "s"], run = "plugin simple-tag -- toggle-ui", desc = "Toggle tag indicator (icon > tag key > hidden)" },
{ on = ["t", "u", "h"], run = "plugin simple-tag -- toggle-ui --mode=hidden", desc = "Hide all tags indicator" },
# ─────────────────────── FILTER FILES/FOLDERS BY TAGS: ───────────────────────
{ on = ["t", "f"], run = "plugin simple-tag -- filter", desc = "Filter files/folders by a tag (press any key)" },
{ on = ["t", "F"], run = "plugin simple-tag -- filter --input", desc = "Filter files/folders by tag(s) (input box)" },
{ on = ["t", "F"], run = "plugin simple-tag -- filter --input --mode=or", desc = "Filter files/folders by contain tags (input box)" },
# ─────────────────────── VISUAL SELECT FILES/FOLDERS BY TAGS: ───────────────────────
# Available selection actions:
# replace → Replaces the current selection list with files/folders that have the selected tag.
# unite → Combines the currently selected files/folders with those that have the selected tag.
# intersect → Keeps only the files/folders that are present in both the current selection and the tagged items.
# subtract → Deselects files/folders that have the selected tag from the current selection.
# exclude → Combines the currently selected files/folders with the tagged items, then deselects any overlapping items between the current selection and the tagged items.
# undo → Undos or redoes the last selection action.
{ on = ["t", "s", "t"], run = "plugin simple-tag -- toggle-select", desc = "Select a selection action then select a tag key (toggle-select)" },
{ on = ["t", "s", "t"], run = "plugin simple-tag -- toggle-select --keys=!1q", desc = "" },
{ on = ["t", "s", "r"], run = "plugin simple-tag -- replace-select", desc = "replace-select" },
{ on = ["t", "s", "u"], run = "plugin simple-tag -- unite-select", desc = "unite-select" },
{ on = ["t", "s", "i"], run = "plugin simple-tag -- intersect-select", desc = "intersect-select" },
{ on = ["t", "s", "s"], run = "plugin simple-tag -- subtract-select", desc = "subtract-select" },
{ on = ["t", "s", "e"], run = "plugin simple-tag -- exclude-select", desc = "exclude-select" },
{ on = ["t", "s", "e"], run = "plugin simple-tag -- replace-select --keys=!1q", desc = "Replaces the current selection list with files/folders that have (! and 1 and q) tag(s)" },
{ on = ["t", "s", "R"], run = "plugin simple-tag -- replace-select --input", desc = "replace-select --input" },
{ on = ["t", "s", "U"], run = "plugin simple-tag -- unite-select --input", desc = "unite-select --input" },
{ on = ["t", "s", "I"], run = "plugin simple-tag -- intersect-select --input", desc = "intersect-select --input" },
{ on = ["t", "s", "S"], run = "plugin simple-tag -- subtract-select --input", desc = "subtract-select --input" },
{ on = ["t", "s", "E"], run = "plugin simple-tag -- exclude-select --input", desc = "exclude-select --input" },
{ on = ["t", "s", "R"], run = "plugin simple-tag -- replace-select --input --mode=or", desc = "replace-select --input --mode=or" },
{ on = ["t", "s", "R"], run = "plugin simple-tag -- replace-select --keys=!1q --mode=or", desc = "replace-select --keys=!1q --mode=or" },
# Undo/Redo selection (only works after using 5 modes above)
{ on = ["t", "s", "u"], run = "plugin simple-tag -- undo-select", desc = "Undos/Redos the last selection action" },
# Directory navigation
{ on = ["k"], run = "arrow -1", desc = "Move cursor up" },
{ on = ["j"], run = "arrow 1", desc = "Move cursor down" },
{ on = ["h"], run = "leave", desc = "Go back to parent directory" },
{ on = ["l"], run = "enter", desc = "Enter directory" },
{ on = ["j"], run = "arrow 1", desc = "Move cursor down" },
{ on = ["h"], run = "leave", desc = "Go back to parent directory" },
{ on = ["l"], run = "enter", desc = "Enter directory" },
# File operations
{ on = ["<Enter>"], run = "open", desc = "Open selected files" },
{ on = ["y"], run = "yank", desc = "Yank selected files (copy)" },
{ on = ["x"], run = "yank --cut", desc = "Yank selected files (cut)" },
{ on = ["p"], run = "paste", desc = "Paste yanked files" },
{ on = ["d"], run = "remove", desc = "Trash selected files" },
{ on = ["D"], run = "remove --permanently", desc = "Permanently delete selected files" },
{ on = ["a"], run = "create", desc = "Create a file or directory" },
{ on = ["r"], run = "rename --cursor=before_ext", desc = "Rename selected file" },
{ on = ["<Enter>"], run = "open", desc = "Open selected files" },
{ on = ["y"], run = "yank", desc = "Yank selected files (copy)" },
{ on = ["x"], run = "yank --cut", desc = "Yank selected files (cut)" },
{ on = ["p"], run = "paste", desc = "Paste yanked files" },
{ on = ["d"], run = "remove", desc = "Trash selected files" },
{ on = ["D"], run = "remove --permanently", desc = "Permanently delete selected files" },
{ on = ["a"], run = "create", desc = "Create a file or directory" },
{ on = ["r"], run = "rename --cursor=before_ext", desc = "Rename selected file" },
# Selection
{ on = ["e"], run = ["select --state=none", "arrow 1"], desc = "Toggle selection" },
{ on = ["v"], run = "visual_mode", desc = "Enter visual mode" },
{ on = ["V"], run = "visual_mode --unset", desc = "Enter visual mode (unset)" },
{ on = ["v"], run = "visual_mode", desc = "Enter visual mode" },
{ on = ["V"], run = "visual_mode --unset", desc = "Enter visual mode (unset)" },
# Search
{ on = ["/"], run = "find --smart", desc = "Find file" },
{ on = ["n"], run = "find_arrow", desc = "Go to next found" },
{ on = ["n"], run = "find_arrow", desc = "Go to next found" },
{ on = ["N"], run = "find_arrow --previous", desc = "Go to previous found" },
# Tabs
{ on = ["T"], run = "tab_create --current", desc = "Create new tab" },
{ on = ["1"], run = "tab_switch 0", desc = "Switch to tab 1" },
{ on = ["2"], run = "tab_switch 1", desc = "Switch to tab 2" },
{ on = ["3"], run = "tab_switch 2", desc = "Switch to tab 3" },
# Preview
{ on = ["z"], run = "plugin --sync hide-preview", desc = "Toggle preview" },
# Other
{ on = ["g", "h"], run = "cd ~", desc = "Go to home directory" },
{ on = ["g", "h"], run = "cd ~", desc = "Go to home directory" },
{ on = ["g", "c"], run = "cd ~/.config", desc = "Go to config directory" },
{ on = ["g", "d"], run = "cd ~/Downloads", desc = "Go to downloads" },
{ on = ["~"], run = "help", desc = "Open help" },
{ on = ["~"], run = "help", desc = "Open help" },
]
[tasks]
prepend_keymap = [
{ on = ["<Esc>"], run = "close", desc = "Close task manager" },
{ on = ["k"], run = "arrow -1", desc = "Move cursor up" },
{ on = ["j"], run = "arrow 1", desc = "Move cursor down" },
{ on = ["k"], run = "arrow -1", desc = "Move cursor up" },
{ on = ["j"], run = "arrow 1", desc = "Move cursor down" },
]
[select]
prepend_keymap = [
{ on = ["<Esc>"], run = "close", desc = "Cancel selection" },
{ on = ["<Enter>"], run = "close --submit", desc = "Submit selection" },
@@ -290,14 +157,12 @@ prepend_keymap = [
]
[input]
prepend_keymap = [
{ on = ["<Esc>"], run = "close", desc = "Cancel input" },
{ on = ["<Enter>"], run = "close --submit", desc = "Submit input" },
]
[completion]
prepend_keymap = [
{ on = ["<Tab>"], run = "close --submit", desc = "Submit completion" },
{ on = ["k"], run = "arrow -1", desc = "Move cursor up" },
@@ -305,10 +170,9 @@ prepend_keymap = [
]
[help]
prepend_keymap = [
{ on = ["<Esc>"], run = "escape", desc = "Clear filter or exit help" },
{ on = ["q"], run = "close", desc = "Exit help" },
{ on = ["k"], run = "arrow -1", desc = "Move cursor up" },
{ on = ["j"], run = "arrow 1", desc = "Move cursor down" },
{ on = ["q"], run = "close", desc = "Exit help" },
{ on = ["k"], run = "arrow -1", desc = "Move cursor up" },
{ on = ["j"], run = "arrow 1", desc = "Move cursor down" },
]

View File

@@ -83,6 +83,16 @@ use = "llanosrocas/yaziline"
rev = "6266926"
hash = "9917ab5cb9bdbab7ca7f2501f84f0f11"
[[plugin.deps]]
use = "boydaihungst/file-extra-metadata"
rev = "4fbb106"
hash = "8765a20c837f4be5718f89ab1cf33b4"
[[plugin.deps]]
use = "yazi-rs/plugins:full-border"
rev = "68f7d48"
hash = "3996fc74044bc44144b323686f887e1"
[[flavor.deps]]
use = "yazi-rs/flavors:catppuccin-mocha"
rev = "4a1802a"

View File

@@ -0,0 +1,19 @@
Copyright (c) 2024 boydaihungst
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

@@ -0,0 +1,110 @@
# file-extra-metadata
<!--toc:start-->
- [file-extra-metadata](#file-extra-metadata)
- [Preview](#preview)
- [Before:](#before)
- [After:](#after)
- [Requirements](#requirements)
- [Installation](#installation)
- [For developer](#for-developer)
<!--toc:end-->
This is a Yazi plugin that replaces the default file previewer and spotter with extra information.
> [!IMPORTANT]
> Minimum version: yazi v25.5.28
## Preview
### Before:
- Previewer
![Before preview](statics/2024-11-17-12-06-24.png)
- Spotter
![Before spot](statics/2025-12-29-before_spotter.png)
### After:
- Previewer
![After previewer](statics/2024-11-21-05-27-48.png)
- Spotter
![After spotter](statics/2025-12-29-after_spotter.png)
## Requirements
- [yazi >= 25.5.28](https://github.com/sxyazi/yazi)
- Tested on Linux. For MacOS, Windows: some fields will shows empty values.
## Installation
Install the plugin:
```sh
ya pkg add boydaihungst/file-extra-metadata
```
Create `~/.config/yazi/yazi.toml` and add:
For yazi < v25.12.29 (29/12/2025) replace `url` with `name`
```toml
[plugin]
append_previewers = [
{ url = "*", run = "file-extra-metadata" },
]
# Setup keybind for spotter: https://github.com/sxyazi/yazi/pull/1802
append_spotters = [
{ url = "*", run = "file-extra-metadata" },
]
```
or
```toml
[plugin]
previewers = [
# ... the rest
# disable default file plugin { name = "*", run = "file" },
{ url = "*", run = "file-extra-metadata" },
]
# Setup keybind for spotter: https://github.com/sxyazi/yazi/pull/1802
spotters = [
# ... the rest
# Fallback
# { name = "*", run = "file" },
{ url = "*", run = "file-extra-metadata" },
]
```
### Custom theme
Read more: https://github.com/sxyazi/yazi/pull/2391
Edit or add `yazi/theme.toml`:
```toml
[spot]
border = { fg = "#4fa6ed" }
title = { fg = "#4fa6ed" }
# Table.
tbl_cell = { fg = "#4fa6ed", reversed = true }
tbl_col = { fg = "#4fa6ed" }
```
## For developer
If you want to combine this with other spotter/previewer:
```lua
require("file-extra-metadata"):render_table(job, { show_plugins_section = true })
```

View File

@@ -0,0 +1,371 @@
--- @since 25.5.28
local M = {}
local STATE_KEY = {
ALTER_DF_COMMAND = "ALTER_DF_COMMAND",
}
local set_state = ya.sync(function(state, key, value)
state[key] = value
end)
local get_state = ya.sync(function(state, key)
return state[key]
end)
local function permission(file)
local h = file
if not h then
return ""
end
local perm = h.cha:perm()
if not perm then
return ""
end
local spans = ""
for i = 1, #perm do
local c = perm:sub(i, i)
spans = spans .. c
end
return spans
end
local function link_count(file)
local h = file
if h == nil or ya.target_family() ~= "unix" then
return ""
end
return h.cha.nlink
end
local function owner_group(file)
local h = file
if h == nil or ya.target_family() ~= "unix" then
return ""
end
return (ya.user_name(h.cha.uid) or tostring(h.cha.uid)) .. "/" .. (ya.group_name(h.cha.gid) or tostring(h.cha.gid))
end
local file_size_and_folder_childs = function(file)
local h = file
if not h then
return ""
end
return h.cha.len and ya.readable_size(h.cha.len) or ""
end
--- get file timestamp
---@param file any
---@param type "mtime" | "atime" | "btime"
---@return any
local function fileTimestamp(file, type)
local h = file
if not h then
return ""
end
local time = math.floor(h.cha[type] or 0)
if time == 0 then
return ""
else
return os.date("%Y-%m-%d %H:%M", time)
end
end
-- Function to split a string by spaces (considering multiple spaces as one delimiter)
local function split_by_whitespace(input)
local result = {}
for word in string.gmatch(input, "%S+") do
table.insert(result, word)
end
return result
end
local function get_filesystem_extra(file)
local result = {
filesystem = "",
device = "",
type = "",
used_space = "",
avail_space = "",
total_space = "",
used_space_percent = "",
avail_space_percent = "",
error = nil,
is_virtual = false,
}
local h = file
local file_url = h.url
local is_virtual = file_url.scheme and file_url.scheme.is_virtual
file_url = is_virtual and (file.path or Url(file_url.scheme.cache .. tostring(file_url.path)))
or (file_url.path or file_url.url)
if not h or ya.target_family() ~= "unix" then
return result
end
local output, child
local alter_df_command = get_state(STATE_KEY.ALTER_DF_COMMAND)
if not alter_df_command then
child, _ = Command("df"):arg({ "-P", "-T", "-h", tostring(file_url) }):stdout(Command.PIPED):spawn()
if child then
-- Ignore header
local _, event = child:read_line()
if event == 0 then
output, _ = child:read_line()
end
child:start_kill()
end
end
-- Fallback for macOS/BSD if -T failed (empty output or error)
if not output or output == "" then
if not alter_df_command then
set_state(STATE_KEY.ALTER_DF_COMMAND, true)
end
child, _ = Command("df"):arg({ "-P", "-h", tostring(file_url) }):stdout(Command.PIPED):spawn()
if child then
local _, event = child:read_line() -- skip header
if event == 0 then
output, _ = child:read_line()
end
child:start_kill()
end
end
if output and output ~= "" then
-- Splitting the data
local parts = split_by_whitespace(output)
-- Display the result
if #parts >= 7 then
result.filesystem = is_virtual and (parts[7] .. " (vfs)") or parts[7]
result.device = is_virtual and (parts[1] .. " (vfs)") or parts[1]
result.total_space = parts[3]
result.used_space = parts[4]
result.avail_space = parts[5]
result.used_space_percent = parts[6]
result.avail_space_percent = 100 - tonumber((string.match(parts[6], "%d+") or "0"))
result.type = is_virtual and (parts[2] .. " (vfs)") or parts[2]
else
result.filesystem = is_virtual and (parts[6] .. " (vfs)") or parts[6]
-- result.device (Type) is missing in df output, fetch from mount
result.total_space = parts[2]
result.used_space = parts[3]
result.avail_space = parts[4]
result.used_space_percent = parts[5]
result.avail_space_percent = 100 - tonumber((string.match(parts[5], "%d+") or "0"))
result.device = is_virtual and (parts[1] .. " (vfs)") or parts[1]
local mount_child = Command("mount"):stdout(Command.PIPED):spawn()
if mount_child then
while true do
local line, event = mount_child:read_line()
if not line or event ~= 0 then
break
end
-- Check if line starts with filesystem (e.g. /dev/disk1s1 on ...)
local s, e = line:find(parts[1] .. " on ", 1, true)
if s == 1 then
local fstype = line:match("%(([^,]+)")
if fstype then
result.type = is_virtual and (fstype .. " (vfs)") or fstype
end
break
end
end
end
end
result.is_virtual = is_virtual
else
result.error = "df error: check install"
end
return result
end
local function attributes(file)
local h = file
local file_url = h.url
if h.cha.is_link then
file_url = Url(h.link_to)
end
local is_virtual = file_url.scheme and file_url.scheme.is_virtual
file_url = is_virtual and (file.path or Url(file_url.scheme.cache .. tostring(file_url.path))) or file_url
if not h or ya.target_family() ~= "unix" then
return ""
end
local output, _ = Command("lsattr"):arg({ "-d", tostring(file_url) }):stdout(Command.PIPED):output()
if output then
-- Splitting the data
local parts = split_by_whitespace(output.stdout)
-- Display the result
for i, part in ipairs(parts) do
if i == 1 then
return part
end
end
return ""
else
return "lsattr error: check install"
end
end
---shorten string
---@param _s string string
---@param _t string tail
---@param _w number max characters
---@return string
local shorten = function(_s, _t, _w)
local s = _s or utf8.len(_s)
local t = _t or ""
local ellipsis = "" .. t
local w = _w < utf8.len(ellipsis) and utf8.len(ellipsis) or _w
local n_ellipsis = utf8.len(ellipsis) or 0
if utf8.len(s) > w then
return s:sub(1, (utf8.offset(s, w - n_ellipsis + 1) or 2) - 1) .. ellipsis
end
return s
end
function M:render_table(job, opts)
local styles = {
header = th.spot.title or ui.Style():fg("green"),
row_label = ui.Style():fg("reset"),
row_value = th.spot.tbl_col or ui.Style():fg("blue"),
}
local filesystem_extra = get_filesystem_extra(job.file)
local prefix = " "
local rows = {}
local label_max_length = 15
local file_name_extension = job.file.cha.is_dir and "" or ("." .. (job.file.url.ext or ""))
local row = function(key, value)
local h = type(value) == "table" and #value or 1
rows[#rows + 1] = ui.Row({ ui.Line(key):style(styles.row_label), ui.Text(value):style(styles.row_value) })
:height(h)
end
local file_name = shorten(
job.file.name,
file_name_extension,
math.floor(job.area.w - label_max_length - utf8.len(file_name_extension))
)
local location = shorten(
tostring((job.file.url.path or job.file.url).parent),
"",
math.floor(job.area.w - label_max_length - utf8.len(prefix))
)
local filesystem_error = filesystem_extra.error
and shorten(filesystem_extra.error, "", math.floor(job.area.w - label_max_length - utf8.len(prefix)))
or nil
local filesystem =
shorten(filesystem_extra.filesystem, "", math.floor(job.area.w - label_max_length - utf8.len(prefix)))
rows[#rows + 1] = ui.Row({ "Metadata", "" }):style(styles.header)
row(prefix .. "File:", file_name)
row(prefix .. "Mimetype:", job.mime)
row(prefix .. "Location:", location)
if job.file.cache then
row(prefix .. "Cached:", tostring(job.file.path or job.file.cache))
end
row(prefix .. "Mode:", permission(job.file))
row(prefix .. "Attributes:", attributes(job.file))
row(prefix .. "Links:", tostring(link_count(job.file)))
if job.file.cha.is_link then
row(prefix .. "Linked:", tostring(job.file.cha.is_link and job.file.link_to))
end
row(prefix .. "Owner:", owner_group(job.file))
row(prefix .. "Size:", file_size_and_folder_childs(job.file))
row(prefix .. "Created:", fileTimestamp(job.file, "btime"))
row(prefix .. "Modified:", fileTimestamp(job.file, "mtime"))
row(prefix .. "Accessed:", fileTimestamp(job.file, "atime"))
row(prefix .. "Filesystem:", filesystem_error or filesystem)
row(prefix .. "Device:", filesystem_error or filesystem_extra.device)
row(prefix .. "Type:", filesystem_error or filesystem_extra.type)
row(
prefix .. "Free space:",
filesystem_error
or (
(
filesystem_extra.avail_space
and filesystem_extra.total_space
and filesystem_extra.avail_space_percent
)
and (filesystem_extra.avail_space .. " / " .. filesystem_extra.total_space .. " (" .. filesystem_extra.avail_space_percent .. "%)")
or ""
)
)
if opts and opts.show_plugins_section then
-- TODO: Remove this after the next release
local is_yazi_nightly, _ = pcall(require, "mime.dir")
local spotter = rt.plugin.spotter(is_yazi_nightly and job.file or job.file.url, job.mime)
local previewer = rt.plugin.previewer(is_yazi_nightly and job.file or job.file.url, job.mime)
local fetchers = rt.plugin.fetchers(job.file, job.mime)
local preloaders = rt.plugin.preloaders(is_yazi_nightly and job.file or job.file.url, job.mime)
for i, v in ipairs(fetchers) do
fetchers[i] = v.cmd
end
for i, v in ipairs(preloaders) do
preloaders[i] = v.cmd
end
rows[#rows + 1] = ui.Row({ { "", "Plugins" }, "" }):height(2):style(styles.header)
row(prefix .. "Spotter:", spotter and spotter.cmd or "(none)")
row(prefix .. "Previewer:", previewer and previewer.cmd or "(none)")
row(prefix .. "Fetchers:", #fetchers ~= 0 and fetchers or "(none)")
row(prefix .. "Preloaders:", #preloaders ~= 0 and preloaders or "(none)")
end
return ui.Table(rows):area(job.area):row(1):col(1):col_style(styles.row_value):widths({
ui.Constraint.Length(label_max_length),
ui.Constraint.Fill(1),
})
end
function M:peek(job)
local start, cache = os.clock(), ya.file_cache(job)
if not cache or not self:preload(job) then
return 1
end
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
ya.preview_widget(job, { self:render_table(job) })
end
function M:seek(job)
local h = cx.active.current.hovered
if h and h.url == job.file.url then
local step = math.floor(job.units * job.area.h / 10)
ya.emit("peek", {
tostring(math.max(0, cx.active.preview.skip + step)),
only_if = tostring(job.file.url),
})
end
end
function M:preload(job)
local cache = ya.file_cache(job)
if not cache or fs.cha(cache) then
return true
end
return true
end
function M:spot(job)
job.area = ui.Pos({ "center", w = 80, h = 25 })
ya.spot_table(
job,
self:render_table(job, { show_plugins_section = true })
:cell_style(th.spot.tbl_cell or ui.Style():fg("blue"):reverse())
)
end
return M

View 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.

View File

@@ -0,0 +1,32 @@
# full-border.yazi
Add a full border to Yazi to make it look fancier.
![full-border](https://github.com/yazi-rs/plugins/assets/17523360/ef81b560-2465-4d36-abf2-5d21dcb7b987)
## Installation
```sh
ya pkg add yazi-rs/plugins:full-border
```
## Usage
Add this to your `init.lua` to enable the plugin:
```lua
require("full-border"):setup()
```
Or you can customize the border type:
```lua
require("full-border"):setup {
-- Available values: ui.Border.PLAIN, ui.Border.ROUNDED
type = ui.Border.ROUNDED,
}
```
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

View File

@@ -0,0 +1,43 @@
--- @since 25.2.26
local function setup(_, opts)
local type = opts and opts.type or ui.Border.ROUNDED
local old_build = Tab.build
Tab.build = function(self, ...)
local bar = function(c, x, y)
if x <= 0 or x == self._area.w - 1 or th.mgr.border_symbol ~= "" then
return ui.Bar(ui.Edge.TOP)
end
return ui.Bar(ui.Edge.TOP)
:area(
ui.Rect { x = x, y = math.max(0, y), w = ya.clamp(0, self._area.w - x, 1), h = math.min(1, self._area.h) }
)
:symbol(c)
end
local c = self._chunks
self._chunks = {
c[1]:pad(ui.Pad.y(1)),
c[2]:pad(ui.Pad(1, c[3].w > 0 and 0 or 1, 1, c[1].w > 0 and 0 or 1)),
c[3]:pad(ui.Pad.y(1)),
}
local style = th.mgr.border_style
self._base = ya.list_merge(self._base or {}, {
ui.Border(ui.Edge.ALL):area(self._area):type(type):style(style),
ui.Bar(ui.Edge.RIGHT):area(self._chunks[1]):style(style),
ui.Bar(ui.Edge.LEFT):area(self._chunks[3]):style(style),
bar("", c[1].right - 1, c[1].y),
bar("", c[1].right - 1, c[1].bottom - 1),
bar("", c[2].right, c[2].y),
bar("", c[2].right, c[2].bottom - 1),
})
old_build(self, ...)
end
end
return { setup = setup }

View File

@@ -1,35 +1,45 @@
[mgr]
ratio = [2, 3, 5]
sort_by = "natural"
# it also support --mode=or when using with --input or --keys=!1q or --key=!1q or --tag=!1q or --tags=!1q
ratio = [2, 3, 5]
sort_by = "natural"
sort_sensitive = false
sort_reverse = false
sort_reverse = false
sort_dir_first = true
linemode = "none"
show_hidden = true
show_symlink = true
scrolloff = 5
linemode = "none"
show_hidden = true
show_symlink = true
scrolloff = 5
[preview]
tab_size = 2
max_width = 600
max_height = 900
cache_dir = ""
image_delay = 30
image_filter = "triangle"
tab_size = 2
max_width = 600
max_height = 900
cache_dir = ""
image_delay = 30
image_filter = "triangle"
image_quality = 75
[opener]
# edit = [
# { run = '$EDITOR "$@"', block = true, for = "unix" },
# ]
open = [
{ run = 'xdg-open "$1"', desc = "Open", orphan = true },
]
edit = [
{ run = 'nvim "$@"', block = true, desc = "nvim", for = "unix" },
]
open = [
{ run = 'xdg-open "$1"', desc = "Open", for = "linux" },
]
reveal = [
{ run = 'xdg-open "$(dirname "$1")"', desc = "Reveal", for = "linux" },
]
play = [
{ run = 'mpv --force-window "$@"', orphan = true, for = "unix" },
{ run = 'mpv --force-window "$@"', orphan = true, for = "unix" },
]
pdf = [
{ run = 'zathura "$@"', orphan = true, for = "linux" },
]
text = [
{ run = 'nvim "$@"', block = true, for = "linux" },
]
[open]
@@ -37,15 +47,14 @@ rules = [
# Empty files
{ mime = "inode/empty", use = "edit" },
# { mime = "inode/x-empty", use = "edit" },
# Text files - use nvim
{ mime = "text/*", use = "edit" },
# Text files - use edit (which uses $EDITOR/nvim)
{ mime = "text/*", use = "edit" }, # Changed from "text" to "edit"
# { mime = "text/x-tex", use = "edit" }, # Changed from "text" to "edit"
{ mime = "application/json", use = "edit" },
{ mime = "application/x-sh", use = "edit" },
{ mime = "application/x-shellscript", use = "edit" },
{ mime = "application/javascript", use = "edit" },
# Fallback by extension for files without detectable MIME
# Fallback by extension
{ name = "*.sh", use = "edit" },
{ name = "*.json", use = "edit" },
{ name = "*.md", use = "edit" },
@@ -55,48 +64,45 @@ rules = [
{ name = "*.toml", use = "edit" },
{ name = "*.yaml", use = "edit" },
{ name = "*.yml", use = "edit" },
{ name = "*.tex", use = "edit" }, # Uncommented!
{ name = "*.text", use = "edit" },
# Media files
{ mime = "image/*", use = "open" },
{ mime = "video/*", use = "play" },
{ mime = "audio/*", use = "play" },
{ mime = "application/pdf", use = "open" },
{ mime = "application/pdf", use = "pdf" },
# Fallback
{ mime = "*", use = "open" },
]
[tasks]
micro_workers = 10
macro_workers = 25
bizarre_retry = 5
micro_workers = 10
macro_workers = 25
bizarre_retry = 5
suppress_preload = false
[plugin]
prepend_fetchers = [
{ id = "mime", url = "*", run = "mime-ext", prio = "high"},
{ id = "mime", url = "*", run = "mime-ext", prio = "high" },
# git plugin
{ id = "git", name = "*", run = "git" },
{ id = "git", name = "*/", run = "git" },
{ id = "git", url = "*", run = "git" },
{ id = "git", url = "*/", run = "git" },
# mime plugin
{ id = "simple-tag", url = "*", run = "simple-tag" },
{ id = "simple-tag", url = "*/", run = "simple-tag" },
]
preloaders = [
# Image
{ mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" },
{ mime = "image/*", run = "image" },
# Video
#{ mime = "video/*", run = "video" },
# PDF
{ mime = "application/pdf", run = "pdf" },
# Font
{ mime = "font/*", run = "font" },
{ mime = "application/ms-opentype", run = "font" },
# Image
{ mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" },
{ mime = "image/*", run = "image" },
# Video
# { mime = "video/*", run = "video" },
# PDF
{ mime = "application/pdf", run = "pdf" },
# Font
{ mime = "font/*", run = "font" },
{ mime = "application/ms-opentype", run = "font" },
]
prepend_preloaders = [
# Replace magick, image, video with mediainfo
{ mime = "{audio,video,image}/*", run = "mediainfo" },
@@ -104,39 +110,42 @@ prepend_preloaders = [
# Adobe Illustrator, Adobe Photoshop is image/adobe.photoshop, already handled above
{ mime = "application/postscript", run = "mediainfo" },
]
previewers = [
{ name = "*/", run = "folder", sync = true },
# Code
{ mime = "text/*", run = "code" },
{ mime = "*/{xml,javascript,wine-extension-ini}", run = "code" },
# JSON
{ mime = "application/{json,ndjson}", run = "json" },
# Image
{ mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" },
{ mime = "image/*", run = "image" },
# # Video
#{ mime = "video/*", run = "video" },
# PDF
{ mime = "application/pdf", run = "pdf" },
spotters = [
# extra-metadata plugin
{ url = "*", run = "file-extra-metadata" },
]
previewers = [
{ name = "*/", run = "folder", sync = true },
# Code
{ mime = "text/*", run = "code" },
{ mime = "*/{xml,javascript,wine-extension-ini}", run = "code" },
# JSON
{ mime = "application/{json,ndjson}", run = "json" },
# Image
{ mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" },
{ mime = "image/*", run = "image" },
# # Video
# { mime = "video/*", run = "video" },
# PDF
{ mime = "application/pdf", run = "pdf" },
# extra-metadata plugin
{ url = "*", run = "file-extra-metadata" },
]
prepend_previewers = [
# mediainfo MUST come before the catch-all piper rule
{ mime = "{audio,video,image}/*", run = "mediainfo"},
{ mime = "{audio,video,image}/*", run = "mediainfo" },
{ mime = "application/subrip", run = "mediainfo" },
{ mime = "application/postscript", run = "mediainfo" },
# ouch plugin for archives
{ mime = "application/{*zip,tar,bzip2,7z*,rar,xz,zstd,java-archive}", run = "ouch"},
{ mime = "application/{*zip,tar,bzip2,7z*,rar,xz,zstd,java-archive}", run = "ouch" },
# piper for directories
{ url = "*/", run = 'piper -- eza -TL=3 --color=always --icons=always --group-directories-first --no-quotes "$1"'},
{ url = "*/", run = 'piper -- eza -TL=3 --color=always --icons=always --group-directories-first --no-quotes "$1"' },
# piper markdown (commented out as you had it)
# rich preview plugin
{ url = "*.csv", run = "rich-preview"}, # for csv files
{ url = "*.md", run = "rich-preview" }, # for markdown (.md) files
{ url = "*.rst", run = "rich-preview"}, # for restructured text (.rst) files
{ url = "*.ipynb", run = "rich-preview"}, # for jupyter notebooks (.ipynb)
{ url = "*.json", run = "rich-preview"}, # for json (.json) files
# { url = "*.lang_type", run = "rich-preview"} # for particular language files eg. .py, .go., .lua, etc.
{ url = "*.csv", run = "rich-preview" }, # for csv files
{ url = "*.md", run = "rich-preview" }, # for markdown (.md) files
{ url = "*.rst", run = "rich-preview" }, # for restructured text (.rst) files
{ url = "*.ipynb", run = "rich-preview" }, # for jupyter notebooks (.ipynb)
{ url = "*.json", run = "rich-preview" }, # for json (.json) files
# { url = "*.lang_type", run = "rich-preview"} # for particular language files eg. .py, .go., .lua, etc.
]

View File

@@ -5,6 +5,7 @@ alias f='fuck'
alias a='aerc'
# Scripts
alias la='/home/liph/scripts/latex.sh'
alias ar='/mnt/tank/scripts/aria.sh'
alias sp='/mnt/tank/scripts/split.sh'
alias nt='/mnt/tank/scripts/nothumb.sh'
@@ -126,11 +127,6 @@ alias aryt="yt-dlp --external-downloader aria2c --external-downloader-args '-x 8
alias aria='aria2c -x 8' # add URL in '' for 8 segmented download
alias yd='yt-dlp' # copy link from videodownload helper and add the URL in ''
# ffmpeg
alias ffcmp='ffmpeg -i video.mp4 -q:a 0 -map a audio.mp3' # convert on mp4 into mp3
alias ffcbmp='for file in *.mp4; do
ffmpeg -i "$file" -q:a 0 -map a "${file%.mp4}.mp3"
done' # batch rename all mp4 into mp3 add -af "volume=1.5" to increase audio volume by 1.5
alias photodetect='gphoto2 --auto-detect'
alias photoget='gphoto2 --get-all-files'

View File

@@ -25,11 +25,11 @@ source <(fzf --zsh)
# env aur helper
if command -v paru &> /dev/null; then
export AUR_HELPER="paru"
export AUR_HELPER="paru"
elif command -v yay &> /dev/null; then
export AUR_HELPER="yay"
export AUR_HELPER="yay"
else
export AUR_HELPER="pacman" # Fallback to pacman
export AUR_HELPER="pacman" # Fallback to pacman
fi
#export AUR_HELPER="paru"
@@ -99,21 +99,21 @@ _fzf_comprun() {
}
function y() {
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd
yazi "$@" --cwd-file="$tmp"
if cwd="$(command cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
builtin cd -- "$cwd"
fi
rm -f -- "$tmp"
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd
yazi "$@" --cwd-file="$tmp"
if cwd="$(command cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
builtin cd -- "$cwd"
fi
rm -f -- "$tmp"
}
# Load a few important annexes, without Turbo
# (this is currently required for annexes)
zinit light-mode for \
zdharma-continuum/zinit-annex-as-monitor \
zdharma-continuum/zinit-annex-bin-gem-node \
zdharma-continuum/zinit-annex-patch-dl \
zdharma-continuum/zinit-annex-rust
zdharma-continuum/zinit-annex-as-monitor \
zdharma-continuum/zinit-annex-bin-gem-node \
zdharma-continuum/zinit-annex-patch-dl \
zdharma-continuum/zinit-annex-rust
### End of Zinit's installer chunk