diff --git a/.dotter/artix-laptop.toml b/.dotter/artix-laptop.toml new file mode 100644 index 00000000..94aaf974 --- /dev/null +++ b/.dotter/artix-laptop.toml @@ -0,0 +1,7 @@ +packages = [ "wayland" ] + +[variables] +dpi = "96" +font_size = "16" +terminal = "ghostty" +browser = "floorp" diff --git a/.dotter/artix-machine.toml b/.dotter/artix-machine.toml new file mode 100644 index 00000000..d4fbc3e3 --- /dev/null +++ b/.dotter/artix-machine.toml @@ -0,0 +1,7 @@ +packages = [ "x11" ] + +[variables] +dpi = "96" +font_size = "10" +terminal = "ghostty" +browser = "floorp" diff --git a/.dotter/global.toml b/.dotter/global.toml index cfd59986..49880136 100644 --- a/.dotter/global.toml +++ b/.dotter/global.toml @@ -32,7 +32,7 @@ depends = [ "base", "awesome_laptop", "picom", "dunst", "rofi" ] "config/x11/xresources" = {target = "~/.config/x11/xresources", type = "template"} [wayland] -depends = [ "base", "hyprland", "dunst" ] +depends = [ "base", "hyprland", "dunst", "rofi" ] [wayland.files] "config/zsh/.zprofile-wayland" = "~/.config/zsh/.zprofile" @@ -48,6 +48,12 @@ depends = [ "shell" ] "config/shell/env" = "~/.zshenv" "config/zsh/" = "~/.config/zsh/" +[fish] +depends = [ "shell" ] + +[fish.files] +"config/fish/" = "~/.config/fish/" + [local.files] "local/bin/" = "~/.local/bin/" "local/share/" = "~/.local/share/" @@ -59,7 +65,7 @@ depends = [ "shell" ] "config/rofi/config.rasi" = {target = "~/.config/rofi/config.rasi", type = "template"} [misc] -depends = [ "torrent", "zathura" ] +depends = [ "torrent", "zathura", "email" ] [misc.files] "config/batrc" = "~/.config/bat/config" @@ -127,8 +133,11 @@ depends = [ "misc", "local", "eww", "lock" ] [spotify.files] "config/spotify-tui.yml" = "~/.config/spotify-tui/config.yml" +[email.files] +"config/neomutt/" = "~/.config/neomutt/" + [terminal] -depends = [ "zsh", "tmux" ] +depends = [ "zsh", "tmux", "fish" ] [terminal.files] "config/alacritty/" = "~/.config/alacritty/" @@ -139,6 +148,7 @@ depends = [ "zsh", "tmux" ] [tmux.files] "config/tmux/" = "~/.config/tmux/" +"config/sesh/" = "~/.config/sesh/" [xplr.files] "config/xplr/" = "~/.config/xplr/" diff --git a/config/awesome/rc-laptop.lua b/config/awesome/rc-laptop.lua index 4d91c926..0bc4fe1a 100644 --- a/config/awesome/rc-laptop.lua +++ b/config/awesome/rc-laptop.lua @@ -68,6 +68,7 @@ beautiful.init(gears.filesystem.get_configuration_dir() .. "mytheme.lua") -- This is used later as the default terminal and editor to run. local terminal = "{{terminal}}" +local browser = "{{browser}}" local editor = os.getenv("EDITOR") or "nvim" local editor_cmd = terminal .. " -e " .. editor @@ -437,7 +438,7 @@ local globalkeys = gears.table.join( -- awful.key({ modkey, "Control" }, "q", awesome.quit, { description = "quit awesome", group = "awesome" }), awful.key({ modkey }, "b", function() - awful.spawn("floorp") + awful.spawn(browser) end, { description = "open browser", group = "launcher" }), awful.key({ modkey }, "n", function() awful.spawn(terminal .. " -e yazi") diff --git a/config/awesome/rc.lua b/config/awesome/rc.lua index cbd65207..2956b99a 100644 --- a/config/awesome/rc.lua +++ b/config/awesome/rc.lua @@ -67,6 +67,7 @@ beautiful.init(gears.filesystem.get_configuration_dir() .. "mytheme.lua") -- This is used later as the default terminal and editor to run. local terminal = "{{terminal}}" +local browser = "{{browser}}" local editor = os.getenv("EDITOR") or "nvim" local editor_cmd = terminal .. " -e " .. editor @@ -107,9 +108,9 @@ local myawesomemenu = { hotkeys_popup.show_help(nil, awful.screen.focused()) end, }, - { "manual", terminal .. " -e man awesome" }, + { "manual", terminal .. " -e man awesome" }, { "edit config", editor_cmd .. " " .. awesome.conffile }, - { "restart", awesome.restart }, + { "restart", awesome.restart }, { "quit", function() @@ -430,7 +431,7 @@ local globalkeys = gears.table.join( -- awful.key({ modkey, "Control" }, "q", awesome.quit, { description = "quit awesome", group = "awesome" }), awful.key({ modkey }, "b", function() - awful.spawn("floorp") + awful.spawn(browser) end, { description = "open browser", group = "launcher" }), awful.key({ modkey }, "n", function() awful.spawn(terminal .. " -e yazi") @@ -485,7 +486,7 @@ local globalkeys = gears.table.join( -- Menubar awful.key({ modkey }, "p", function() -- menubar.show() - awful.spawn("rofi -show drun -show-icons") + awful.spawn("rofi -show combi -show-icons") end, { description = "show the menubar", group = "launcher" }) ) @@ -672,9 +673,9 @@ awful.rules.rules = { rule_any = { class = { "easyeffects" } }, properties = { screen = 1, tag = "9" }, }, - { rule_any = { class = { "kdeconnect.app" } }, properties = { screen = 2, tag = "7" } }, - { rule_any = { class = { "Spotify" } }, properties = { screen = 2, tag = "9" } }, - { rule_any = { class = { "mpv" } }, properties = { fullscreen = true } }, + { rule_any = { class = { "kdeconnect.app" } }, properties = { screen = 2, tag = "7" } }, + { rule_any = { class = { "Spotify" } }, properties = { screen = 2, tag = "9" } }, + { rule_any = { class = { "mpv" } }, properties = { fullscreen = true } }, } --- Signals diff --git a/config/batrc b/config/batrc index c8bfa74e..5576edfa 100644 --- a/config/batrc +++ b/config/batrc @@ -4,7 +4,7 @@ # Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes` # for a list of all available themes ---theme="Rosé Pine" +--theme="base16" # Enable this to use italic text on the terminal. This is not supported on all # terminal emulators (like tmux, by default): diff --git a/config/btop/btop.conf b/config/btop/btop.conf index ec6d3fff..2d125162 100644 --- a/config/btop/btop.conf +++ b/config/btop/btop.conf @@ -1,4 +1,4 @@ -#? Config file for btop v. 1.4.0 +#? Config file for btop v. 1.4.3 #* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes. #* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes" @@ -57,7 +57,7 @@ update_ms = 500 #* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", #* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. -proc_sorting = "memory" +proc_sorting = "cpu direct" #* Reverse sorting order, True or False. proc_reversed = False @@ -72,7 +72,7 @@ proc_colors = True proc_gradient = True #* If process cpu usage should be of the core it's running on or usage of the total available cpu power. -proc_per_core = False +proc_per_core = True #* Show process memory as bytes instead of percent. proc_mem_bytes = True @@ -210,6 +210,9 @@ net_sync = False #* Starts with the Network Interface specified here. net_iface = "" +#* "True" shows bitrates in base 10 (Kbps, Mbps). "False" shows bitrates in binary sizes (Kibps, Mibps, etc.). "Auto" uses base_10_sizes. +base_10_bitrate = "Auto" + #* Show battery stats in top right if battery is present. show_battery = True @@ -226,6 +229,9 @@ log_level = "WARNING" #* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards. nvml_measure_pcie_speeds = True +#* Measure PCIe throughput on AMD cards, may impact performance on certain cards. +rsmi_measure_pcie_speeds = True + #* Horizontally mirror the GPU graph. gpu_mirror_graph = True diff --git a/config/eww/eww.scss b/config/eww/eww.scss index 13bca0b1..deecec4d 100644 --- a/config/eww/eww.scss +++ b/config/eww/eww.scss @@ -146,6 +146,10 @@ clock_time { margin: 0px 10px 0px 10px; } +.module-wifi { + margin: 0 10px; +} + .separ { color: $highlight_med; font-weight: bold; @@ -472,3 +476,11 @@ calendar:indeterminate { min-width: 120px; margin: 0px 0px 20px 0px; } + +.activate-linux { + color: rgba(250, 250, 250, 0.5); + + &.background { + background: none; + } +} diff --git a/config/eww/eww.yuck b/config/eww/eww.yuck index fad49c27..53d8f61a 100644 --- a/config/eww/eww.yuck +++ b/config/eww/eww.yuck @@ -99,12 +99,12 @@ :tooltip "Battery on ${EWW_BATTERY.BAT0.capacity}%" :show_truncated false :wrap false - "${EWW_BATTERY.BAT0.status == "Charging" ? "" : - EWW_BATTERY.BAT0.capacity > 90 ? "" : - EWW_BATTERY.BAT0.capacity > 70 ? "" : - EWW_BATTERY.BAT0.capacity > 40 ? "" : - EWW_BATTERY.BAT0.capacity > 20 ? "" : - ""}" + ;; "${EWW_BATTERY.BAT0.status == "Charging" ? "" : + ;; EWW_BATTERY.BAT0.capacity > 90 ? "" : + ;; EWW_BATTERY.BAT0.capacity > 70 ? "" : + ;; EWW_BATTERY.BAT0.capacity > 40 ? "" : + ;; EWW_BATTERY.BAT0.capacity > 20 ? "" : + ;; ""}" )))) @@ -124,7 +124,7 @@ :tooltip "Using ${memory}% ram" :show_truncated false :wrap false - "")))) + )))) @@ -311,12 +311,12 @@ :class "sys_bat" :thickness 9 (label - :text "${EWW_BATTERY.BAT0.status == "Charging" ? "" : - EWW_BATTERY.BAT0.capacity > 90 ? "" : - EWW_BATTERY.BAT0.capacity > 70 ? "" : - EWW_BATTERY.BAT0.capacity > 40 ? "" : - EWW_BATTERY.BAT0.capacity > 20 ? "" : - ""}" + ;; :text "${EWW_BATTERY.BAT0.status == "Charging" ? "" : + ;; EWW_BATTERY.BAT0.capacity > 90 ? "" : + ;; EWW_BATTERY.BAT0.capacity > 70 ? "" : + ;; EWW_BATTERY.BAT0.capacity > 40 ? "" : + ;; EWW_BATTERY.BAT0.capacity > 20 ? "" : + ;; ""}" :interval "5m" :class "sys_icon_bat ${EWW_BATTERY.BAT0.capacity} syst_icon_bat__${EWW_BATTERY.BAT0.status} ${EWW_BATTERY.BAT0.capacity < 20 ? "sys_icon_bat__low" : ""}" :limit-width 2 @@ -350,7 +350,7 @@ :show_truncated false :wrap false))) (label - :text "" + :text "" :class "sys_sep" :halign "center") (box @@ -363,7 +363,6 @@ :class "sys_mem" :thickness 9 (label - :text "" :class "sys_icon_mem" :limit-width 2 :show_truncated false @@ -566,3 +565,16 @@ (box :class "window" (label :text "${window}"))) +(defwidget activate-linux [] + (box + :orientation "v" + :halign "start" + :valign "start" + (label :xalign 0 :markup "Activate Linux") + (label :xalign 0 :text "Go to Settings to activate Linux"))) + +(defwindow activate-linux + :monitor 0 + :stacking "fg" + :geometry (geometry :x "8px" :y "64px" :width "420px" :anchor "bottom right") + (activate-linux)) diff --git a/config/eww/scripts/wifi b/config/eww/scripts/wifi index cec3f26a..d151c0e3 100644 --- a/config/eww/scripts/wifi +++ b/config/eww/scripts/wifi @@ -3,7 +3,7 @@ status=$(nmcli g | \grep -oE "disconnected") essid=$(nmcli c | \grep wlan0 | awk '{print ($1)}') -if [ $status ] ; then +if [ $status ]; then icon="" text="" col="#575268" @@ -16,8 +16,7 @@ fi if [[ "$1" == "--COL" ]]; then echo $col elif [[ "$1" == "--ESSID" ]]; then - echo $text + echo $text elif [[ "$1" == "--ICON" ]]; then - echo $icon + echo $icon fi - diff --git a/config/fish/completions/fastanime.fish b/config/fish/completions/fastanime.fish new file mode 100644 index 00000000..919add34 --- /dev/null +++ b/config/fish/completions/fastanime.fish @@ -0,0 +1,17 @@ +function _fastanime_completion; + set -l response (env _FASTANIME_COMPLETE=fish_complete COMP_WORDS=(commandline -cp) COMP_CWORD=(commandline -t) fastanime); + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command fastanime --arguments "(_fastanime_completion)"; diff --git a/config/fish/completions/fzf.fish b/config/fish/completions/fzf.fish new file mode 100644 index 00000000..ec8d521c --- /dev/null +++ b/config/fish/completions/fzf.fish @@ -0,0 +1 @@ +fzf --fish | source diff --git a/config/fish/completions/uv.fish b/config/fish/completions/uv.fish new file mode 100644 index 00000000..ac24044c --- /dev/null +++ b/config/fish/completions/uv.fish @@ -0,0 +1 @@ +uv generate-shell-completion fish | source diff --git a/config/fish/completions/uvx.fish b/config/fish/completions/uvx.fish new file mode 100644 index 00000000..1de03d70 --- /dev/null +++ b/config/fish/completions/uvx.fish @@ -0,0 +1 @@ +uvx --generate-shell-completion fish | source diff --git a/config/fish/completions/zoxide.fish b/config/fish/completions/zoxide.fish new file mode 100644 index 00000000..2e9cc179 --- /dev/null +++ b/config/fish/completions/zoxide.fish @@ -0,0 +1 @@ +zoxide init fish | source diff --git a/config/fish/conf.d/aliases.fish b/config/fish/conf.d/aliases.fish new file mode 100644 index 00000000..bde694e5 --- /dev/null +++ b/config/fish/conf.d/aliases.fish @@ -0,0 +1,60 @@ +# Use neovim for vim if present +if type -q nvim + set -g vimdiff "nvim -d" +end + +# Verbosity and settings that you pretty much just always are going to wand +alias bc="bc -ql" +alias cp="cp -vi" +alias df="df -h" +alias mkdir="mkdir -pv" +alias mv="mv -iv" +alias nsxiv="nsxiv -a" +alias rm="rm -vI" +alias wget="wget --hsts-file=$XDG_DATA_HOME/wget-hsts" +alias keychain="keychain --dir $XDG_RUNTIME_DIR/keychain" + +# Colorize commands when possible +alias diff="diff --color=auto" +alias grep="rg --color=auto" +alias ip="ip -color=auto" +alias less="moar" +alias ls="eza -a --icons --group-directories-first" + +# These common commands ate just too long! Abbreviate them +alias battery="acpi" +alias code="vscodium" +alias day="redshift -PO 6500" +alias dv="doasedit" +alias e="$EDITOR" +alias fetch="fastfetch" +alias lf="lfub" +alias lg="lazygit" +alias lock="swaylock" +alias lzd="lazydocker" +alias night="redshift -PO 4500" +alias py="python" +alias sv="rsv" +alias v="$EDITOR" +alias weather="curl wttr.in/" +alias wg-down="wg-quick down wg0" +alias wg-up="wg-quick up wg0" +alias ww="$EDITOR ~/neorg/" +alias yarn="yarn --use-yarnrc $XDG_CONFIG_HOME/yarn/config" +alias yy="yazi" + +# Git aliases +alias gP="git push" +alias ga="git add" +alias gap="git add --patch" +alias gc="git commit" +alias gd="git diff --output-indicator-new=' ' --output-indicator-old=' '" +alias gds="git diff --staged" +alias gl="git log --all --graph --pretty=format:'%C(magenta)%h %C(white) %an %ar%C(auto) %D%n%s%n'" +alias gp="git pull" +alias gs="git status --short" + +# doas alias +for command in mount umount rsv sv pacman updatedb su shutdown poweroff reboot zzz systemctl wg wg-quick + alias $command="doas $command" +end diff --git a/config/fish/conf.d/keybindings.fish b/config/fish/conf.d/keybindings.fish new file mode 100644 index 00000000..574b9979 --- /dev/null +++ b/config/fish/conf.d/keybindings.fish @@ -0,0 +1,2 @@ +# Ctrl+O runs yazicd +bind -M insert \co 'yazicd' diff --git a/config/fish/config.fish b/config/fish/config.fish new file mode 100644 index 00000000..61bf8162 --- /dev/null +++ b/config/fish/config.fish @@ -0,0 +1,57 @@ +# Source startup file +# if test -f "$XDG_CONFIG_HOME/zsh/startup" +# source "$XDG_CONFIG_HOME/zsh/startup" +# end + + +# Starship prompt +starship init fish | source + +# Aliases +if test -f "$XDG_CONFIG_HOME/fish/alias.fish" + source "$XDG_CONFIG_HOME/fish/alias.fish" +end + +# Environment variables +set -x KEYTIMEOUT 1 + +# Functions +function cd + if test (count $argv) -eq 0 + builtin cd ~ + else + builtin cd $argv + end + eza -a --icons --group-directories-first +end + +function lfcd + set tmp (mktemp -uq) + lf -last-dir-path="$tmp" $argv + if test -f "$tmp" + set dir (cat "$tmp") + if test -d "$dir" -a "$dir" != (pwd) + cd "$dir" + end + end +end + +function yazicd + set tmp (mktemp -t "yazi-cwd.XXXXXX") + yazi $argv --cwd-file="$tmp" + set cwd (cat "$tmp") + if test -n "$cwd" -a "$cwd" != "$PWD" + cd "$cwd" + eza -a --icons --group-directories-first + end + rm -f "$tmp" +end + +# Keybindings +fish_vi_key_bindings + + +# Source other files +# if test -f "$HOME/.local/share/../bin/env" +# source "$HOME/.local/share/../bin/env" +# end diff --git a/config/ghostty/config b/config/ghostty/config index 02d7574a..1f9a0407 100644 --- a/config/ghostty/config +++ b/config/ghostty/config @@ -22,6 +22,7 @@ window-decoration = false scrollback-limit = 10000000 mouse-hide-while-typing = true confirm-close-surface = false +mouse-scroll-multiplier = 0.5 # Keybinds keybind = alt+f4=ignore diff --git a/config/git/config b/config/git/config index 7635f8c6..c81d354a 100644 --- a/config/git/config +++ b/config/git/config @@ -10,7 +10,7 @@ whitespace = error preloadindex = true -[url "git@github.com:kristoferssolo"] +[url "git@github.com:kristoferssolo:"] insteadOf = "solo:" [url "git@github.com"] insteadOf = "gh:" diff --git a/config/hypr/hyprland.conf b/config/hypr/hyprland.conf index 5f6279af..30589e44 100644 --- a/config/hypr/hyprland.conf +++ b/config/hypr/hyprland.conf @@ -16,9 +16,10 @@ # See https://wiki.hyprland.org/Configuring/Monitors/ monitor=eDP-1,prefered,0x0,1 -monitor=DP-1,prefered,180x-1440,1 +# monitor=DP-1,prefered,180x-1440,1 # monitor=HDMI-A-1,prefered,480x-1080,1 -monitor=HDMI-A-1,prefered,auto,1 +# monitor=HDMI-A-1,prefered,mirror,eDP-1 +# monitor=DP-1,prefered,mirror,eDP-1 # monitor=DP-1,disabled ################### @@ -30,8 +31,9 @@ monitor=HDMI-A-1,prefered,auto,1 # Set programs that you use $terminal = {{terminal}} $fileManager = $terminal -e yazi -$menu = wofi --show drun -ib -$browser = floorp +# $menu = wofi --show drun -ib +$menu = rofi -show combi -show-icons +$browser = {{browser}} ################# ### AUTOSTART ### @@ -40,11 +42,11 @@ $browser = floorp # Autostart necessary processes (like notifications daemons, status bars, etc.) # Or execute your favorite apps at launch like this: -exec-once=pipewire & pipewire-pulse & wireplumber & eww daemon & eww open bar #& dbus-update-activation-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP DISPLAY XAUTHORITY -# exec-once=eww daemon & eww open bar & dbus-update-activation-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP DISPLAY XAUTHORITY -exec-once=nextcloud & /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & xrdb "$XDG_CONFIG_HOME/x11/xresources" & transmission-daemon & dunst +exec-once=pipewire & pipewire-pulse & wireplumber & eww daemon & eww open bar +exec-once=dbus-update-activation-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP DISPLAY XAUTHORITY +exec-once=nextcloud & /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & xrdb "$XDG_CONFIG_HOME/x11/xresources" & transmission-daemon & dunst & hyprpaper exec-once=[workspace 1 silent] $browser -exec-once=[workspace 8 silent] vesktop & kotatogram-desktop +exec-once=[workspace 8 silent] kotatogram-desktop & flatpak run dev.vencord.Vesktop # exec-once=[workspace 9 silent] spotify-launcher # Source a file (multi-file configs) @@ -72,8 +74,8 @@ env = WM,Hyprland # https://wiki.hyprland.org/Configuring/Variables/#general general { - gaps_in = 5 - gaps_out = 10 + gaps_in = 4 + gaps_out = 8 border_size = 2 @@ -87,13 +89,13 @@ general { # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on allow_tearing = false - layout = master + layout = dwindle } # https://wiki.hyprland.org/Configuring/Variables/#decoration decoration { - rounding = 5 - # rounding_power = 2 + rounding = 4 + rounding_power = 4 # Change transparency of focused and unfocused windows active_opacity = 1.0 @@ -110,7 +112,7 @@ decoration { blur { enabled = true size = 3 - passes = 1 + passes = 3 vibrancy = 0.1696 } @@ -159,6 +161,7 @@ animations { # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below + force_split = 2 preserve_split = true # You probably want this } @@ -170,10 +173,10 @@ master { # https://wiki.hyprland.org/Configuring/Variables/#misc misc { force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers - disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( + disable_hyprland_logo = true # If true disables the random hyprland logo / anime girl background. :( + vfr = true # It will lower the amount of sent frames when nothing is happening on-screen. } - ############# ### INPUT ### ############# @@ -211,6 +214,9 @@ device { sensitivity = -0.5 } +cursor { + hide_on_key_press = true +} ################### ### KEYBINDINGS ### @@ -225,6 +231,9 @@ bind = $mainMod SHIFT, Q, killactive bind = $mainMod, N, exec, $fileManager bind = $mainMod CTRL, SPACE, togglefloating bind = $mainMod, P, exec, $menu +bind = $mainMod, G, exec, rofi -modi games -show games -theme games-smaller +bind = $mainMod, C, exec, rofi -show calc -modi calc -no-show-match -no-sort -calc-command "echo -n '{result}' | wl-copy" +bind = $mainMod, W, exec, networkmanager_dmenu bind = $mainMod SHIFT, P, exec, cliphist list | wofi -S dmenu | cliphist decode | wl-copy bind = $mainMod, F, fullscreen bind = $mainMod, M, bringactivetotop @@ -375,12 +384,12 @@ windowrulev2 = opacity 0.95, class:thunderbird windowrulev2 = workspace 8, class:discord windowrulev2 = opacity 0.95, class:discord windowrulev2 = workspace 8, class:vesktop -windowrulev2 = opacity 0.95, class:vesktop +windowrulev2 = opacity 0.9, class:vesktop windowrulev2 = workspace 8, class:Ripcord windowrulev2 = workspace 8, class:TelegramDesktop windowrulev2 = opacity 0.95, class:TelegramDesktop windowrulev2 = workspace 8, title:Kotatogram -windowrulev2 = opacity 0.95, title:Kotatogram +windowrulev2 = opacity 0.9, initialTitle:Kotatogram windowrulev2 = opacity 0.9, class:teams-for-linux windowrulev2 = workspace 5, class:Ferdium windowrulev2 = opacity 0.9, class:Ferdium @@ -394,7 +403,6 @@ windowrulev2 = opacity 0.9, class:Spotify # chromakey_background = 7,8,17 windowrulev2 = opacity 0.95, class:qbittorrent -windowrulev2 = opacity 0.95, class:lutris windowrulev2 = opacity 0.95, class:pacfinder windowrulev2 = opacity 0.9, class:Bitwarden windowrulev2 = opacity 0.9, class:kdeconnect @@ -403,7 +411,3 @@ windowrulev2 = opacity 0.9, class:kdeconnect windowrulev2 = move 100%-250 100%-250, class:galculator windowrulev2 = size 250 250, class:galculator windowrulev2 = float, class:galculator - -windowrulev2=float,title:^(flameshot) -windowrulev2=move 0 0,title:^(flameshot) -windowrulev2=suppressevent fullscreen,title:^(flameshot) diff --git a/config/hypr/hyprlock.conf b/config/hypr/hyprlock.conf index 06b61a1a..989d19b3 100644 --- a/config/hypr/hyprlock.conf +++ b/config/hypr/hyprlock.conf @@ -1,4 +1,4 @@ -$font = JetBrainsMonoNF +$font = JetBrainsMono NF $base = rgb(191724) $surface = rgb(1f1d2e) diff --git a/config/hypr/hyprpaper.conf b/config/hypr/hyprpaper.conf index 7329a7bd..c5f68097 100644 --- a/config/hypr/hyprpaper.conf +++ b/config/hypr/hyprpaper.conf @@ -1,7 +1,5 @@ -ipc = off +ipc = off # save on baterry splash = true -preload = ~/Pictures/wallpapers/Linux-Dynamic-Wallpapers/Firewatch2/Firewatch2-1.png -preload = ~/Pictures/wallpapers/Linux-Dynamic-Wallpapers/LakesideDeerComplete/LakesideDeer-03.png -preload = ~/Pictures/wallpapers/abstract/GDWP-789-4K-No-Logo.jpg +preload = ~/Pictures/wallpapers/anime/frieren/frieren-beyond-journeys-end-anime-4k-wallpaper.jpg -wallpaper = ,~/Pictures/wallpapers/abstract/GDWP-789-4K-No-Logo.jpg +wallpaper = ,~/Pictures/wallpapers/anime/frieren/frieren-beyond-journeys-end-anime-4k-wallpaper.jpg diff --git a/config/lazygit/config.yml b/config/lazygit/config.yml index e69de29b..237b4ec1 100644 --- a/config/lazygit/config.yml +++ b/config/lazygit/config.yml @@ -0,0 +1,2 @@ +git: + overrideGpg: true diff --git a/config/neomutt/muttrc b/config/neomutt/muttrc new file mode 100644 index 00000000..69592632 --- /dev/null +++ b/config/neomutt/muttrc @@ -0,0 +1,67 @@ +# === Basic Settings === +set realname = "Kristiāns Francis Cagulis" +set from = "kristians.cagulis@gmail.com" +set use_from = yes +set envelope_from = yes # Use 'from' address for envelope +set edit_headers = yes # Let you edit headers when composing + +# === Editor === +set editor = "nano" # Or vim, emacs, etc. + +# === Folder Settings === +# This is where NeoMutt will look for mailboxes. +# For IMAP, it's usually the remote server. +set folder = "imaps://imap.example.com:993" # Your IMAP server and port +set spoolfile = "+INBOX" # Your main inbox +set postponed = "+Drafts" # Where to save drafts (adjust folder name) +set record = "+Sent" # Where to save sent messages (adjust folder name) +set trash = "+Trash" # Where to move deleted messages (adjust folder name) + +# === IMAP Settings === +set imap_user = "kristians.cagulis@gmail.com" +# set imap_pass = "YOUR_APP_PASSWORD" # We'll source this from another file +set imap_check_subscribed = yes +set imap_keepalive = 300 +set mail_check = 60 # Check for new mail every 60 seconds +set imap_passive = no # Some servers need this + +# === SMTP Settings (Sending Mail) === +set smtp_url = "smtps://your_email@example.com@smtp.example.com:465" # SMTP server, port, and username +# set smtp_pass = "YOUR_APP_PASSWORD" # We'll source this from another file + +# === Sorting === +set sort = threads # Sort by threads +set sort_aux = last-date-received # Sort threads by last received date + +# === Header Weeding (Clean up displayed headers) === +ignore * +unignore from: to: cc: date: subject: +hdr_order from: to: cc: date: subject: + +# === Sidebar (Optional but highly recommended) === +set sidebar_visible = yes +set sidebar_width = 25 +set sidebar_format = "%B%?F? [%F]?%* %?N?%N/?%S" # Folder | Unread / Total +# Keybindings for sidebar navigation (Ctrl-B, Ctrl-T, Ctrl-O, Ctrl-C) +bind index,pager \cb sidebar-prev +bind index,pager \ct sidebar-next +bind index,pager \co sidebar-open +bind index,pager \cc sidebar-toggle-visible + +# === Other useful settings === +set confirmappend = no # Don't ask when appending to mbox +set quit = ask-yes # Ask before quitting +set pager_context = 3 # Show 3 lines of context in pager +set menu_scroll = yes # Scroll menus +set tilde = yes # Show tildes for empty lines like in Vim + +# === Source account-specific configurations (like passwords) === +# Make sure the path is correct! +source "~/.config/neomutt/accounts/my_email.conf" + +# === GPG Settings (Optional, for encrypted/signed mail) === +# set crypt_autosign = yes +# set crypt_autoencrypt = yes +# set pgp_sign_as = "0xYOUR_GPG_KEY_ID" +# set pgp_timeout = 3600 # Cache GPG passphrase for 1 hour +# set pgp_good_sign = "~G Good signature from" diff --git a/config/rofi/config.rasi b/config/rofi/config.rasi index 83a3efd1..6da6015e 100644 --- a/config/rofi/config.rasi +++ b/config/rofi/config.rasi @@ -1,7 +1,7 @@ @theme "rose-pine" configuration { - modes: "window,drun,run,ssh,filebrowser"; + modes: "window,drun,run,ssh,filebrowser,games,calc"; font: "JetBrainsMono NF 12"; // location: 0; // yoffset: 0; @@ -34,7 +34,7 @@ configuration { // auto-select: false; // parse-hosts: false; // parse-known-hosts: true; - // combi-modes: "window,run"; + combi-modes: "drun,games"; matching: "fuzzy"; // tokenize: true; // m: "-5"; diff --git a/config/sesh/sesh.toml b/config/sesh/sesh.toml new file mode 100644 index 00000000..80c315ed --- /dev/null +++ b/config/sesh/sesh.toml @@ -0,0 +1,4 @@ +[default_session] +startup_command = "tmux new-window && tmux select-window -t 1 && clear" +preview_command = "eza -a --icons --git --group-directories-first --color=always {}" +blacklist = [ "**/SoloVim/*", "**/solorice/**" ] diff --git a/config/shell/aliasrc b/config/shell/aliasrc index 43f514ad..a44f9c17 100644 --- a/config/shell/aliasrc +++ b/config/shell/aliasrc @@ -34,8 +34,8 @@ alias \ j="joshutoub" \ lf="lfub" \ lg="lazygit" \ - lzd="lazydocker" \ lock="swaylock" \ + lzd="lazydocker" \ night="redshift -PO 4500" \ py="python" \ sv="rsv" \ @@ -45,6 +45,7 @@ alias \ wg-up="wg-quick up wg0" \ ww="$EDITOR ~/neorg/" \ yarn="yarn --use-yarnrc $XDG_CONFIG_HOME/yarn/config" \ + va="source .venv/bin/activate" \ yy="yazi" alias \ diff --git a/config/shell/env b/config/shell/env index dedf4403..b84e97a7 100644 --- a/config/shell/env +++ b/config/shell/env @@ -10,11 +10,14 @@ typeset -U PATH path export PATH="$PATH:${$(find ~/.local/bin -type d -printf %p:)%%:}" export PATH="$PATH:~/.spicetify" export PATH="$PATH:${$(find ~/.cache/.bun/bin -type d -printf %p:)%%:}" +export PATH=$JAVA_HOME/bin:$PATH # Disable files export LESSHISTFILE=- export $(dbus-launch) +export MANPAGER='nvim +Man!' + export LIBSEAT_BACKEND=logind unsetopt PROMPT_SP @@ -87,6 +90,7 @@ export XINITRC="$XDG_CONFIG_HOME/x11/xinitrc" export ZDOTDIR="$XDG_CONFIG_HOME/zsh" # export _JAVA_OPTIONS="-Djava.util.prefs.userRoot=${XDG_CONFIG_HOME}/java - Djavafx.cachedir=${XDG_CACHE_HOME}/openjfx" # export _JAVA_OPTIONS=-Djava.util.prefs.userRoot="$XDG_CONFIG_HOME/java" +export JAVA_HOME="/usr/lib/jvm/java-21-openjdk" # Other program settings export AWT_TOOLKIT="MToolkit wmname LG3D" # May have to install wmname @@ -111,4 +115,3 @@ export _JAVA_AWT_WM_NONREPARENTING=1 # Fix for Java applications in dwm . "$XDG_DATA_HOME/cargo/env" . "$XDG_CACHE_HOME/deno/.deno/env" -. "/home/kristofers/.local/share/cargo/env" diff --git a/config/starship.toml b/config/starship.toml index b574160d..2e2e3a50 100644 --- a/config/starship.toml +++ b/config/starship.toml @@ -1,3 +1,6 @@ +# Get editor completions based on the config schema +"$schema" = 'https://starship.rs/config-schema.json' + # Disable the blank line at the start of the prompt add_newline = false command_timeout = 1000 diff --git a/config/tmux/tmux.conf b/config/tmux/tmux.conf index d7e52a03..2c37ca0d 100644 --- a/config/tmux/tmux.conf +++ b/config/tmux/tmux.conf @@ -43,8 +43,23 @@ bind '"' split-window -v -c "#{pane_current_path}" bind % split-window -h -c "#{pane_current_path}" bind-key -r i run-shell "tmux neww chtsh" -bind-key -r f run-shell "tmux neww ~/.local/bin/tmux-sessionizer" +# bind-key -r f run-shell "tmux neww ~/.local/bin/tmux-sessionizer" +bind-key -r f run-shell "sesh connect \"$( + sesh list --icons | fzf-tmux -p 80%,70% \ + --no-sort --ansi --border-label ' sesh ' --prompt '⚡ ' \ + --header ' ^a all ^t tmux ^g configs ^x zoxide ^d tmux kill ^f find' \ + --bind 'tab:down,btab:up' \ + --bind 'ctrl-a:change-prompt(⚡ )+reload(sesh list --icons)' \ + --bind 'ctrl-t:change-prompt(🪟 )+reload(sesh list -t --icons)' \ + --bind 'ctrl-g:change-prompt(⚙️ )+reload(sesh list -c --icons)' \ + --bind 'ctrl-x:change-prompt(📁 )+reload(sesh list -z --icons)' \ + --bind 'ctrl-f:change-prompt(🔎 )+reload(fd -H -d 2 -t d -E .Trash . ~)' \ + --bind 'ctrl-d:execute(tmux kill-session -t {2..})+change-prompt(⚡ )+reload(sesh list --icons)' \ + --preview-window 'right:55%' \ + --preview 'sesh preview {}' +)\"" +bind-key x kill-pane set -g @plugin "tmux-plugins/tpm" set -g @plugin "tmux-plugins/tmux-sensible" @@ -56,6 +71,7 @@ set -g @plugin "rose-pine/tmux" set -ga update-environment TERM set -ga update-environment TERM_PROGRAM +set -g detach-on-destroy off # don't exit from tmux when closing a session # set vi-mode set-window-option -g mode-keys vi @@ -63,6 +79,7 @@ set-window-option -g mode-keys vi bind-key -T copy-mode-vi v send-keys -X begin-selection bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle bind-key -T copy-mode-vi y send-keys -X copy-selectet-and-cancel +bind -N "last-session (via sesh) " L run-shell "sesh last" # Rose pine diff --git a/config/yazi/keymap.toml b/config/yazi/keymap.toml index 85fb890a..998e1ca1 100644 --- a/config/yazi/keymap.toml +++ b/config/yazi/keymap.toml @@ -2,7 +2,7 @@ # If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas. "$schema" = "https://yazi-rs.github.io/schemas/keymap.json" -[manager] +[mgr] keymap = [ {on = [ "" ], run = "escape", desc = "Exit visual mode, clear selected, or cancel search"}, {on = [ "" ], run = "escape", desc = "Exit visual mode, clear selected, or cancel search"}, diff --git a/config/yazi/package.toml b/config/yazi/package.toml index c8f690f3..684a60a5 100644 --- a/config/yazi/package.toml +++ b/config/yazi/package.toml @@ -10,8 +10,8 @@ hash = "23915860e59348bf4166778bb0e606f7" [[plugin.deps]] use = "hankertrix/augment-command" -rev = "04cda98" -hash = "3ec6486539188b1e1932ac27f3582917" +rev = "ac4a651" +hash = "7b6b0b8c260c9c5e557287bf9b370f7c" [[plugin.deps]] use = "kirasok/torrent-preview" @@ -25,43 +25,43 @@ hash = "5b9dea47776a30946cfbf83232d18fb1" [[plugin.deps]] use = "pirafrank/what-size" -rev = "f1c6b69" -hash = "6e789212eb41d937bab04877ca361099" +rev = "0a4904c" +hash = "fca231a128488a554823374f8f6d5241" [[plugin.deps]] use = "yazi-rs/plugins:git" -rev = "864a021" -hash = "e0ada736ea676c2bbb3ec705a49526ef" +rev = "c0ad8a3" +hash = "bf6f074cd41ee33c3360341d168f9733" [[plugin.deps]] use = "yazi-rs/plugins:chmod" -rev = "864a021" -hash = "2f1053f89d1a301a648ab181d0948e38" +rev = "c0ad8a3" +hash = "d0ad0c1946b46a30c8489735fe8de41c" [[plugin.deps]] use = "yazi-rs/plugins:full-border" -rev = "864a021" -hash = "1f3dad061209081a6b04dd6ff2cb06c7" +rev = "c0ad8a3" +hash = "3996fc74044bc44144b323686f887e1" [[plugin.deps]] use = "yazi-rs/plugins:mount" -rev = "864a021" -hash = "dd97eede8e20e59cd2604e8006e470e2" +rev = "c0ad8a3" +hash = "c0b6cd7dc830b96e77e5c8a71eec7926" [[plugin.deps]] use = "yazi-rs/plugins:smart-filter" -rev = "864a021" -hash = "f0c4b41b5d19a3144958383333eff6e7" +rev = "c0ad8a3" +hash = "4d82cd9e7534d976f000edf9c0f68d8f" [[plugin.deps]] use = "yazi-rs/plugins:diff" -rev = "864a021" -hash = "7a08e303167d5b655c06da6d570f0333" +rev = "c0ad8a3" +hash = "47865a70cade14a0b9b6bc6a54f16bdb" [[plugin.deps]] use = "AnirudhG07/rich-preview" -rev = "fdcf373" -hash = "bd1737dd44b202f412122e6a3b378d4c" +rev = "de28f50" +hash = "b9cd4027db110b4228889be32462f363" [[plugin.deps]] use = "macydnah/office" @@ -70,8 +70,8 @@ hash = "35241f7d85abc5a0d2441020bc597ceb" [[plugin.deps]] use = "boydaihungst/mediainfo" -rev = "9629b1e" -hash = "5204b4e2bd238c40fa66cf0a0191f084" +rev = "c6d0de7" +hash = "7b024fc14b462235068400207cbe7bf0" [[plugin.deps]] use = "iynaix/time-travel" diff --git a/config/yazi/plugins/augment-command.yazi/README.md b/config/yazi/plugins/augment-command.yazi/README.md index 3239382f..566b29cf 100644 --- a/config/yazi/plugins/augment-command.yazi/README.md +++ b/config/yazi/plugins/augment-command.yazi/README.md @@ -21,6 +21,7 @@ plugin. - [Leave (`leave`)](#leave-leave) - [Rename (`rename`)](#rename-rename) - [Remove (`remove`)](#remove-remove) + - [Copy (`copy`)](#copy-copy) - [Create (`create`)](#create-create) - [Shell (`shell`)](#shell-shell) - [Passing arguments to the `shell` command](#passing-arguments-to-the-shell-command) @@ -32,16 +33,20 @@ plugin. - [New commands](#new-commands) - [Parent arrow (`parent_arrow`)](#parent-arrow-parent_arrow) - [Archive (`archive`)](#archive-archive) + - [Emit (`emit`)](#emit-emit) - [Editor (`editor`)](#editor-editor) - [Pager (`pager`)](#pager-pager) - [Usage](#usage) - [Using the `extract` command as an opener](#using-the-extract-command-as-an-opener) + - [Configuring the plugin's prompts](#configuring-the-plugins-prompts) + - [Input prompts](#input-prompts) + - [Confirmation prompts](#confirmation-prompts) - [Full configuration example](#full-configuration-example) -- [Licence](#licence) +- [Licence] ## Requirements -- [Yazi][yazi-link] v25.4.8+ +- [Yazi][yazi-link] v25.5.28+ - [`7z` or `7zz` command][7z-link] - [`file` command][file-command-link] @@ -53,13 +58,13 @@ plugin. ```sh # Add the plugin -ya pack -a hankertrix/augment-command +ya pkg add hankertrix/augment-command # Install plugin -ya pack -i +ya pkg install # Update plugin -ya pack -u +ya pkg upgrade ``` ## Configuration @@ -498,6 +503,29 @@ then it will operate on the selected items. [remove-behaviour-video] +### Copy (`copy`) + +- The `copy` command is augmented as stated in + [this section above][augment-section]. + + Videos: + + - When `must_have_hovered_item` is `true`: + + [copy-must-have-hovered-item-video] + + - When `must_have_hovered_item` is `false`: + + [copy-hovered-item-optional-video] + + - When `prompt` is set to `true`: + + [copy-prompt-video] + + - When `prompt` is set to `false`: + + [copy-behaviour-video] + ### Create (`create`) - You should use Yazi's default `create` command instead @@ -616,7 +644,7 @@ then it will operate on the selected items. # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "i" run = "plugin augment-command -- shell '$PAGER $@' --block --exit-if-dir" desc = "Open the pager" @@ -633,7 +661,7 @@ then it will operate on the selected items. # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "o" run = "plugin augment-command -- shell '$EDITOR $@' --block --exit-if-dir" desc = "Open the editor" @@ -658,7 +686,7 @@ the shell command arguments, so here are a few ways to do it: ```toml # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "i" run = "plugin augment-command -- shell --block 'bat -p --pager less $@'" desc = "Open with bat" @@ -682,7 +710,7 @@ the shell command arguments, so here are a few ways to do it: ```toml # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "" run = 'plugin augment-command -- shell --block -- sh -c "$SHELL"' desc = "Open a shell inside of a shell here" @@ -691,7 +719,7 @@ the shell command arguments, so here are a few ways to do it: ```toml # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "" run = "plugin augment-command -- shell --block -- sh -c 'echo hello'" desc = "Open a shell and say hello inside the opened shell" @@ -706,7 +734,7 @@ the shell command arguments, so here are a few ways to do it: ```toml # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "" run = '''plugin augment-command -- shell --block -- sh -c 'sh -c "$SHELL"'''' desc = "Open a shell inside of a shell inside of a shell here" @@ -715,7 +743,7 @@ the shell command arguments, so here are a few ways to do it: ```toml # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "" run = '''plugin augment-command -- shell --block -- sh -c "$SHELL -c 'echo hello'" @@ -729,7 +757,7 @@ the shell command arguments, so here are a few ways to do it: ```toml # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "" run = '''plugin augment-command -- shell -- @@ -947,14 +975,14 @@ in your `keymap.toml` file. # %AppData%\yazi\config\keymap.toml on Windows # Use K to move up in the parent directory - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "K" run = ["leave", "arrow -1", "enter"] desc = "Move up in the parent directory" # Use J to move down in the parent directory - [[manager.prepend_keymap]] + [[mgr.prepend_keymap]] on = "J" run = ["leave", "arrow 1", "enter"] desc = "Move down in the parent directory" @@ -970,6 +998,16 @@ in your `keymap.toml` file. to an archive, with the plugin prompting for an archive name. The archive file extension given will be used to determine the type of archive to create. +- When the archive name given has no file extension, the `.zip` + file extension will be automatically added by default + to create a `zip` archive. +- When the item group is determined to be the hovered item, + the `archive` command will create a `.zip` archive with the + name of the hovered item if no archive name is given + and the input is confirmed by using the `` key. +- The `archive` command will also prompt for an overwrite confirmation, + if the archive being created already exists, + just like the `create` command. - This command is also augmented as stated in [this section above][augment-section]. @@ -991,6 +1029,8 @@ in your `keymap.toml` file. [archive-behaviour-video] +- `--force` flag to always overwrite the existing archive + without showing the confirmation prompt. - `--encrypt` flag to encrypt the archive with the given password, which applies even when `encrypt_archives` is set to `false`. - `--encrypt-headers` flag to encrypt the archive headers, @@ -1025,10 +1065,55 @@ in your `keymap.toml` file. [archive-remove-archived-files-video] +### Emit (`emit`) + +- The `emit` command allows you to emit any Yazi command + by typing the command into an input prompt. + The syntax of the command is exactly the same as + the commands in the `keymap.toml` file. + For example, if the input is `arrow next`, + then that will be the command that is emitted by the plugin. + + Video: + + [emit-yazi-command-video] + +- `--plugin` flag to emit a plugin command. + This flag essentially just emits Yazi's `plugin` command + with the input passed as the first argument. + For example, if the input is `augment-command -- parent_arrow 1`, + then the full command being emitted by the plugin is + `plugin augment-command -- parent_arrow 1`. + + Video: + + [emit-plugin-command-video] + +- `--augmented` flag to emit an augmented command. + This flag is a shortcut for emitting a command from this plugin. + For example, if the command given is `parent_arrow 1`, + the full command emitted by the plugin is + `plugin augment-command -- parent_arrow 1`. + + Video: + + [emit-augmented-command-video] + +- If `--augmented` flag is passed together with the `--plugin` flag, + the `--augmented` flag will take precedence over the `--plugin` flag, + and the command emitted will be from this plugin + instead of being a `plugin` command. + In any case, you should not be passing + both the `--plugin` and `--augmented` flags. + ### Editor (`editor`) - The `editor` command opens the default editor set by the `$EDITOR` environment variable. +- When the file being edited is owned by the root user on Unix systems, + like Linux and macOS, the `editor` command will automatically call + `sudo -e` to edit the file instead of using the `$EDITOR` + environment variable. - The command is also augmented as stated in [this section above][augment-section]. @@ -1093,7 +1178,7 @@ on Windows, in this format: # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "key" run = "plugin augment-command -- command arguments --flags --options=42" desc = "Description" @@ -1105,7 +1190,7 @@ For example, to use the augmented `enter` command: # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "l" run = "plugin augment-command -- enter" desc = "Enter a directory and skip directories with only a single subdirectory" @@ -1118,22 +1203,22 @@ are also supported, for example: # ~/.config/yazi/keymap.toml on Linux and macOS # %AppData%\yazi\config\keymap.toml on Windows -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "k" run = "plugin augment-command -- arrow -1" desc = "Move cursor up" -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "r" run = "plugin augment-command -- rename --cursor=before_ext" desc = "Rename a file or directory" -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "D" run = "plugin augment-command -- remove --permanently" desc = "Permanently delete the files" -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = ["g", "j"] run = "plugin augment-command -- parent_arrow 1" ``` @@ -1153,6 +1238,166 @@ the `extract` command to a key in your `keymap.toml` file. Look at the [`extract` command section](#extract-extract) for details on how to do so. +### Configuring the plugin's prompts + +If you would like to use the plugin's default prompts, +you can skip this section entirely. Otherwise, read on. + +The plugin's prompts can be configured using the `th` +object for built-in commands like `create`. + +New commands, or new features in existing commands introduced by the plugin, +like `archive` or `quit`, can be configured +using the `th.augment_command` object instead. + +You **must** call the plugin's `setup` function after +configuring the plugin's prompts, otherwise, +the prompts will remain as the default prompts. + +For example: + +```lua +-- Prompt configurations for the plugin +th.create_title = { "Create:", "Create (dir):" } +th.augment_command = th.augment_command or {} +th.augment_command.archive_title = "Archive name:" +th.augment_command.quit_title = "Quit?" + +-- Call the plugin's setup function +require("augment-command"):setup() +``` + +This method of configuration is to be forward compatible +with future versions of Yazi, as mentioned +[here](https://github.com/yazi-rs/plugins/issues/44). + +#### Input prompts + +For `input` prompts, like the prompt for the `archive` command, +there are 3 configuration options: + +- `title` +- `origin` +- `offset` + +These options are documented in [Yazi's documentation][input-configuration]. + +For example, to configure the `create` command, which is built-in: + +```lua +th.create_title = { "Create:", "Create (dir):" } +th.create_origin = "top-center" +th.create_offset = { + x = 0, + y = 2, + w = 50, + h = 3, +} +``` + +This way of configuring the `input` prompt applies to the following: + +- `create` + +Below is an example of configuring the `archive` command, +which is provided by the plugin: + +```lua +th.augment_command = th.augment_command or {} +th.augment_command.archive_title = "Archive name:" +th.augment_command.archive_origin = "top-center" +th.augment_command.archive_offset = { + x = 0, + y = 2, + w = 50, + h = 3, +} +``` + +This way of configuring the `input` prompt applies to the following: + +- `item_group`: The prompt to select an item group. + +- `extract_password`: + The prompt to enter the password when extracting an encrypted archive. + +- `archive`: The prompt for the archive name. + +- `archive_password`: + The prompts to enter the archive password when + creating an encrypted archive. + Note that the title for this prompt, `archive_password_title`, + should be a list of two strings, like this: + + ```lua + th.augment_command = th.augment_command or {} + th.archive_password_title = { + "Archive password:", + "Confirm archive password:", + } + ``` + +#### Confirmation prompts + +For `confirm` prompts, like the prompt for the `quit` command, +there are 4 configuration options: + +- `title` +- `content` +- `origin` +- `offset` + +These options are documented in [Yazi's documentation][confirm-configuration]. + +The configuration for the `confirm` prompt is very +similar to that of the `input` prompt, +just with one more option called `content`. +The `content` option can take either a `string`, or a list of `strings`. + +For example, to configure the `overwrite` part +of the `create` and `archive` commands, which is built-in: + +```lua +th.overwrite_title = "Overwrite file?" +th.overwrite_content = "Will overwrite the following file:" +th.overwrite_origin = "center" +th.overwrite_offset = { + x = 0, + y = 0, + w = 50, + h = 15, +} +``` + +This way of configuring the `confirm` prompt applies to the following: + +- `overwrite`: + The overwrite prompt when creating a file with + the same name as an existing file. + +Below is an example of configuring the `quit` command, +which is provided by the plugin: + +```lua +th.augment_command = th.augment_command or {} +th.augment_command.quit_title = "Quit?" +th.augment_command.quit_content = { + "There are multiple tabs open.", + "Are you sure you want to quit?", +} +th.augment_command.quit_origin = "center" +th.augment_command.quit_offset = { + x = 0, + y = 0, + w = 50, + h = 15, +} +``` + +This way of configuring the `confirm` prompt applies to the following: + +- `quit`: The quit prompt when quitting with multiple tabs open. + ### Full configuration example For a full configuration example, @@ -1181,6 +1426,8 @@ You can view the full licence in the [`LICENSE`][Licence] file. [yazi-yazi-toml]: https://github.com/sxyazi/yazi/blob/main/yazi-config/preset/yazi-default.toml [yazi-shell-variables]: https://yazi-rs.github.io/docs/configuration/keymap/#manager.shell [thunderbird-tip]: https://yazi-rs.github.io/docs/tips#email-selected-files-using-thunderbird +[input-configuration]: https://yazi-rs.github.io/docs/configuration/yazi#input +[confirm-configuration]: https://yazi-rs.github.io/docs/configuration/yazi#confirm [yazi-keymap-toml]: https://github.com/sxyazi/yazi/blob/main/yazi-config/preset/keymap-default.toml [my-keymap-toml]: https://github.com/hankertrix/Dotfiles/blob/main/.config/yazi/keymap.toml [my-yazi-toml]: https://github.com/hankertrix/Dotfiles/blob/main/.config/yazi/yazi.toml @@ -1190,110 +1437,123 @@ You can view the full licence in the [`LICENSE`][Licence] file. -[open-prompt-video]: https://github.com/user-attachments/assets/624da7a1-99cc-428d-acbb-d4ce684f92cb -[open-behaviour-video]: https://github.com/user-attachments/assets/202f1c07-2001-49d7-a9d7-7a4e7b102c41 -[open-auto-extract-archives-video]: https://github.com/user-attachments/assets/dad0572e-15d7-4dfd-bf48-00851af66b6e -[open-recursively-extract-archives-video]: https://github.com/user-attachments/assets/b8e929ce-32cd-4f7e-ad97-ffe94bdacd71 +[open-prompt-video]: https://github.com/user-attachments/assets/a792f9d9-97f3-4fab-95cc-03b33c58dd47 +[open-behaviour-video]: https://github.com/user-attachments/assets/b2e56c10-91cd-4556-9f64-355aa8948832 +[open-auto-extract-archives-video]: https://github.com/user-attachments/assets/a406391a-b31d-4b45-afa1-b982ddd89eaf +[open-recursively-extract-archives-video]: https://github.com/user-attachments/assets/a960f152-4391-4d55-bd0e-0a08efb42729 -[extract-must-have-hovered-item-video]: https://github.com/user-attachments/assets/6b9f347f-34ce-4ca1-8e3a-24dbeb297dc7 -[extract-hovered-item-optional-video]: https://github.com/user-attachments/assets/1596f9f8-e0f5-49e3-964c-6f94b1c24055 -[extract-prompt-video]: https://github.com/user-attachments/assets/568aef53-dc90-420e-ada9-171f56388ee1 -[extract-behaviour-video]: https://github.com/user-attachments/assets/d6ebf5fb-45d3-4ae0-adab-3e89b1ec2f4e -[extract-recursively-extract-archives-video]: https://github.com/user-attachments/assets/d8978671-9149-45b7-9a92-21c1697baa7d -[extract-encrypted-archive-video]: https://github.com/user-attachments/assets/24701662-0c19-4478-b576-75d9284cd695 -[extract-reveal-extracted-item-video]: https://github.com/user-attachments/assets/170bf187-dc2a-4310-aa86-5dc9a864aced -[extract-remove-extracted-archive-video]: https://github.com/user-attachments/assets/9b2e625a-a7f8-4678-8a26-265a7d3b8e0c +[extract-must-have-hovered-item-video]: https://github.com/user-attachments/assets/ed310a81-c482-4eed-9d54-5f50a7cc7637 +[extract-hovered-item-optional-video]: https://github.com/user-attachments/assets/85d5a6bf-ed35-4f9a-b782-faea119da7c5 +[extract-prompt-video]: https://github.com/user-attachments/assets/40f41727-7e55-44d8-816c-e706d09e27b8 +[extract-behaviour-video]: https://github.com/user-attachments/assets/6f4f68d4-d43c-4de6-8d85-7e22c0cc0cc6 +[extract-recursively-extract-archives-video]: https://github.com/user-attachments/assets/d9e7030c-9491-4dfa-a1f4-baf3a45eed64 +[extract-encrypted-archive-video]: https://github.com/user-attachments/assets/48acd16d-f285-4d58-94c3-b402d7784d94 +[extract-reveal-extracted-item-video]: https://github.com/user-attachments/assets/96d7fe43-024a-4b1e-b961-9ab9c708db83 +[extract-remove-extracted-archive-video]: https://github.com/user-attachments/assets/7b700ffc-3ce6-4185-a8b0-8ecfd09c2519 -[smart-enter-video]: https://github.com/user-attachments/assets/be950544-a58f-495a-a7e8-e37e99011070 -[enter-skip-single-subdirectory-video]: https://github.com/user-attachments/assets/1bd30cb0-611a-44f2-9839-968287af4455 +[smart-enter-video]: https://github.com/user-attachments/assets/9fc60a42-8692-4ac8-8250-652958582b98 +[enter-skip-single-subdirectory-video]: https://github.com/user-attachments/assets/8069e828-d2dd-4c69-a0b8-fe13074de715 -[leave-skip-single-subdirectory-video]: https://github.com/user-attachments/assets/735de8f7-6abb-4929-8e3d-bba470fc6063 +[leave-skip-single-subdirectory-video]: https://github.com/user-attachments/assets/01330321-b9f9-4dad-b339-8923509e759c -[rename-must-have-hovered-item-video]: https://github.com/user-attachments/assets/b0f608df-7e8d-4e5f-958f-b3df9d0a92fa -[rename-hovered-item-optional-video]: https://github.com/user-attachments/assets/9613d238-d8e3-4e6f-b073-f847a4f331a1 -[rename-prompt-video]: https://github.com/user-attachments/assets/6ad26e1b-dab1-4e8e-92af-bfcbf6c5232c -[rename-behaviour-video]: https://github.com/user-attachments/assets/fdd70919-f164-4676-9046-6a4b95cd86ed +[rename-must-have-hovered-item-video]: https://github.com/user-attachments/assets/b6ec96f9-c8a2-490c-9003-8c361e83e336 +[rename-hovered-item-optional-video]: https://github.com/user-attachments/assets/8bf0001d-6d39-4c4f-a364-b399e65208e8 +[rename-prompt-video]: https://github.com/user-attachments/assets/a3926488-f127-4d35-b9ab-7943f01abcb3 +[rename-behaviour-video]: https://github.com/user-attachments/assets/e3d65d76-34d5-45a4-918d-0b28e662840a -[remove-must-have-hovered-item-video]: https://github.com/user-attachments/assets/fa0aeb4e-ee6a-4e34-9c6f-4d4bc0afd111 -[remove-hovered-item-optional-video]: https://github.com/user-attachments/assets/f42167dc-df59-451d-b26b-16e75be93fad -[remove-prompt-video]: https://github.com/user-attachments/assets/dd901db3-1ab4-4cb7-bb3f-8aec335c7b94 -[remove-behaviour-video]: https://github.com/user-attachments/assets/d4087826-3480-486d-98ff-708bca548270 +[remove-must-have-hovered-item-video]: https://github.com/user-attachments/assets/3366c9fa-1a4c-4c3c-a37d-70814d23828d +[remove-hovered-item-optional-video]: https://github.com/user-attachments/assets/01a3fc57-cc90-47f5-b744-d3eed00ac237 +[remove-prompt-video]: https://github.com/user-attachments/assets/18940b9f-4f04-4ab3-a6a9-b35ee8084bd8 +[remove-behaviour-video]: https://github.com/user-attachments/assets/e524ecdb-f94b-4e6e-b5b2-967470ac3f87 + + + +[copy-must-have-hovered-item-video]: https://github.com/user-attachments/assets/d4ffa133-16d3-44f7-923d-bdd743fa4a77 +[copy-hovered-item-optional-video]: https://github.com/user-attachments/assets/d2a7f5cd-ab09-45fd-8865-068bb1c269f8 +[copy-prompt-video]: https://github.com/user-attachments/assets/41d372c5-2992-410c-97ae-aca2c6fea4ee +[copy-behaviour-video]: https://github.com/user-attachments/assets/57658664-1a89-46c4-bb4b-3551b0061436 -[create-and-enter-directories-video]: https://github.com/user-attachments/assets/0604e9a3-7c23-4e9c-963a-6e83955fe7ae -[create-and-open-files-video]: https://github.com/user-attachments/assets/2feee5e5-1d56-4150-8f08-101338392950 -[create-and-open-files-and-directories-video]: https://github.com/user-attachments/assets/629a6923-6fa5-4b85-93b7-3b5495c8bbbb -[create-behaviour-video]: https://github.com/user-attachments/assets/55b485ea-e49e-4629-b077-4f2a81031f38 -[create-default-behaviour-video]: https://github.com/user-attachments/assets/acf04af0-107f-4ebb-9ed2-2a03847071a5 +[create-and-enter-directories-video]: https://github.com/user-attachments/assets/b27756db-f6ed-4598-b54f-214b7ccbe208 +[create-and-open-files-video]: https://github.com/user-attachments/assets/b7ff1e6c-4c70-4598-a5f6-a88e1559f5d9 +[create-and-open-files-and-directories-video]: https://github.com/user-attachments/assets/90dc6dd2-c39d-4ed5-a8b1-e17a18f0219f +[create-behaviour-video]: https://github.com/user-attachments/assets/44bdc556-cde7-4ab9-b3c0-05c4f1fa3120 +[create-default-behaviour-video]: https://github.com/user-attachments/assets/4948fd32-27a9-4546-83f9-ad6fa9c6afa8 -[shell-must-have-hovered-item-video]: https://github.com/user-attachments/assets/d9a49cb7-67fd-40fe-8f68-130561de0cca -[shell-hovered-item-optional-video]: https://github.com/user-attachments/assets/f7fdfa7c-d7cc-4157-bb5f-63c37f82ea5b -[shell-prompt-video]: https://github.com/user-attachments/assets/6648ad92-320f-457d-9f3e-b5da6f1c07bc -[shell-behaviour-video]: https://github.com/user-attachments/assets/4727658f-e27c-4fbe-acd7-acfeac54cd17 -[shell-exit-if-directory-video]: https://github.com/user-attachments/assets/ef0e9818-cc81-45fc-9126-6903314ed6b3 +[shell-must-have-hovered-item-video]: https://github.com/user-attachments/assets/b68c51db-ccb7-447b-897e-fd99048c47c0 +[shell-hovered-item-optional-video]: https://github.com/user-attachments/assets/4643b23e-a2df-465f-8f62-3501747038b8 +[shell-prompt-video]: https://github.com/user-attachments/assets/929e6a68-7e3f-4614-8344-c0a482d471ad +[shell-behaviour-video]: https://github.com/user-attachments/assets/3afd995a-225a-4cc1-8189-0241555a6345 +[shell-exit-if-directory-video]: https://github.com/user-attachments/assets/f7cef7a0-027b-462f-8fe0-b107e5844736 -[smart-paste-video]: https://github.com/user-attachments/assets/59800de2-8445-4f68-834b-10a0e394c400 +[smart-paste-video]: https://github.com/user-attachments/assets/946a8211-41a8-43a0-b56e-9c13f5a00f4d -[smart-tab-create-video]: https://github.com/user-attachments/assets/bf48e411-b7ed-4624-abd9-084dcdc25ab5 +[smart-tab-create-video]: https://github.com/user-attachments/assets/4ea25adc-53d0-4086-b8b3-73dcea6d5932 -[smart-tab-switch-video]: https://github.com/user-attachments/assets/5b94ff0f-f77c-4250-96ac-4fea67eebc46 +[smart-tab-switch-video]: https://github.com/user-attachments/assets/9e2190ad-1b4d-425e-90de-1eb41a445584 -[quit-with-confirmation-video]: https://github.com/user-attachments/assets/9e212a32-c7c3-470f-895e-bb1cba03292d +[quit-with-confirmation-video]: https://github.com/user-attachments/assets/d3c71ae0-7024-4f06-9398-457cad0f5c1d -[smooth-arrow-video]: https://github.com/user-attachments/assets/990935f5-ce6e-4536-9ddc-d8a32da69803 -[wraparound-arrow-video]: https://github.com/user-attachments/assets/b8233e26-06b7-436d-bafa-1639ed12aa53 -[smooth-wraparound-arrow-video]: https://github.com/user-attachments/assets/59d3618a-59cd-448d-b552-e3cc796d109e +[smooth-arrow-video]: https://github.com/user-attachments/assets/04683520-6028-4246-b529-eac6d3a936cf +[wraparound-arrow-video]: https://github.com/user-attachments/assets/f2555189-4628-4745-89f4-9ecb4ef070ab +[smooth-wraparound-arrow-video]: https://github.com/user-attachments/assets/5d603738-a527-4e19-80fd-db41ae76e42b -[parent-arrow-video]: https://github.com/user-attachments/assets/c412ed7b-a6ee-44e7-bf68-f9f2e5214a50 -[smooth-parent-arrow-video]: https://github.com/user-attachments/assets/45fdfa5f-86ef-453c-89a8-1c58d6318e93 -[wraparound-parent-arrow-video]: https://github.com/user-attachments/assets/3a429a57-2dc6-47c6-be4e-fab5844bafde -[smooth-wraparound-parent-arrow-video]: https://github.com/user-attachments/assets/7d3d58ea-4b00-4cb2-9aea-950940b1ad1a +[parent-arrow-video]: https://github.com/user-attachments/assets/166a83d6-c7ef-4269-b725-62dde60f078f +[smooth-parent-arrow-video]: https://github.com/user-attachments/assets/02a7090b-3373-43db-95ed-2b3a6fe683d3 +[wraparound-parent-arrow-video]: https://github.com/user-attachments/assets/229e11f8-a5e4-4237-93f3-d6c8875c9e78 +[smooth-wraparound-parent-arrow-video]: https://github.com/user-attachments/assets/7739afe5-e34d-466e-adf2-3e8a8732f04d -[archive-must-have-hovered-item-video]: https://github.com/user-attachments/assets/a8d667c8-a8a5-44ed-9220-aa55345c98ed -[archive-hovered-item-optional-video]: https://github.com/user-attachments/assets/213f82d2-fe70-4c42-8f24-b09c7d7d7dfe -[archive-prompt-video]: https://github.com/user-attachments/assets/20366432-f195-4531-bb08-9b3f0e8f848e -[archive-behaviour-video]: https://github.com/user-attachments/assets/dcbe9909-db40-4f96-8591-c1a104b63381 -[archive-encrypt-files-video]: https://github.com/user-attachments/assets/08b98e01-2cc2-486e-bd4d-bfbe9da792db -[archive-reveal-created-archive-video]: https://github.com/user-attachments/assets/e908afb8-c431-4e6d-8834-c02216461076 -[archive-remove-archived-files-video]: https://github.com/user-attachments/assets/d0495292-6508-4417-b378-033e6acc0c4d +[archive-must-have-hovered-item-video]: https://github.com/user-attachments/assets/6dac06c1-a69c-4b21-86f6-63f6cc693f22 +[archive-hovered-item-optional-video]: https://github.com/user-attachments/assets/b33fbcdf-1e00-49db-aede-99c2c3a26171 +[archive-prompt-video]: https://github.com/user-attachments/assets/ddc0a2e7-9b90-416f-97e3-57af5ad5f355 +[archive-behaviour-video]: https://github.com/user-attachments/assets/437254d2-4746-41e7-9500-13cef60764b7 +[archive-encrypt-files-video]: https://github.com/user-attachments/assets/d4269378-58ce-4b58-a420-13455576c58f +[archive-reveal-created-archive-video]: https://github.com/user-attachments/assets/86f01452-42a4-4a97-9d31-ce6f9bc10407 +[archive-remove-archived-files-video]: https://github.com/user-attachments/assets/012ed8b5-57ae-4cb3-8bf7-4e0af6bdb0d2 + + + +[emit-yazi-command-video]: https://github.com/user-attachments/assets/d2fadf6b-1877-479f-9ac3-734cf227693f +[emit-plugin-command-video]: https://github.com/user-attachments/assets/af28c33a-b915-413a-91b2-fc812c1d4d90 +[emit-augmented-command-video]: https://github.com/user-attachments/assets/08c2d3d6-8ae6-48e2-a045-9c9dc5d81bfd -[editor-must-have-hovered-item-video]: https://github.com/user-attachments/assets/a0e4500d-7bfe-4fb1-9289-8c39c5c6f323 -[editor-hovered-item-optional-video]: https://github.com/user-attachments/assets/96798f1f-2ddc-464a-b6ae-48cc20f88b3c -[editor-prompt-video]: https://github.com/user-attachments/assets/5453cc87-3721-4b80-8cc2-b730ddff5da8 -[editor-behaviour-video]: https://github.com/user-attachments/assets/f479ef38-5b78-43f1-83d4-045bef6f5f20 +[editor-must-have-hovered-item-video]: https://github.com/user-attachments/assets/ca6d4bac-57be-487e-98e7-805b396fb3d3 +[editor-hovered-item-optional-video]: https://github.com/user-attachments/assets/3481a3be-d91c-4903-b7a1-80d3048fcf6b +[editor-prompt-video]: https://github.com/user-attachments/assets/7cdb942f-0ad3-453c-93a5-ab89df5cd644 +[editor-behaviour-video]: https://github.com/user-attachments/assets/e7537e2e-56a0-4681-9820-5b48cd583bc8 -[pager-must-have-hovered-item-video]: https://github.com/user-attachments/assets/7daa8e81-bc83-4ff3-9462-d71293565e67 -[pager-hovered-item-optional-video]: https://github.com/user-attachments/assets/e123fb58-d49e-46b6-bc33-c41eb01cf9aa -[pager-prompt-video]: https://github.com/user-attachments/assets/cfba76a1-116e-4caf-b25a-57d631d115a0 -[pager-behaviour-video]: https://github.com/user-attachments/assets/d036f865-2909-414b-80d9-80e550b6b3dd +[pager-must-have-hovered-item-video]: https://github.com/user-attachments/assets/292f503e-c7b0-45ad-97b3-75325f8bb0e7 +[pager-hovered-item-optional-video]: https://github.com/user-attachments/assets/ca5f1126-4761-4289-a441-4b44c7234e57 +[pager-prompt-video]: https://github.com/user-attachments/assets/45d758e0-f95c-4e2e-92b2-094c2f475c00 +[pager-behaviour-video]: https://github.com/user-attachments/assets/547ebf9c-ab85-4e72-85c0-e130739b9e68 diff --git a/config/yazi/plugins/augment-command.yazi/main.lua b/config/yazi/plugins/augment-command.yazi/main.lua index f6aa24bd..d1a257d6 100644 --- a/config/yazi/plugins/augment-command.yazi/main.lua +++ b/config/yazi/plugins/augment-command.yazi/main.lua @@ -1,4 +1,4 @@ ---- @since 25.4.8 +--- @since 25.5.28 -- Plugin to make some Yazi commands smarter -- Written in Lua 5.4 @@ -15,7 +15,8 @@ -- config: The configuration object ---@alias CommandFunction fun( --- args: Arguments, ---- config: Configuration): nil +--- config: Configuration, +---): nil -- The type of the command table ---@alias CommandTable table @@ -47,6 +48,9 @@ -- The type for the archiver command function ---@alias Archiver.Command fun(): output: CommandOutput|nil, error: Error|nil +-- The type of the function to get the password options +---@alias GetPasswordOptions fun(is_confirm_password: boolean): YaziInputOptions + -- Custom types -- The type of the user configuration table @@ -79,6 +83,7 @@ -- The full configuration for the plugin ---@class (exact) Configuration: UserConfiguration +---@field sudo_edit_supported boolean Whether sudo edit is supported -- The type for the state ---@class (exact) State @@ -95,6 +100,10 @@ ---@field extracted_items_path string|nil The path to the extracted items ---@field archiver_name string|nil The name of the archiver +-- The module table +---@class AugmentCommandPlugin +local M = {} + -- The name of the plugin ---@type string local PLUGIN_NAME = "augment-command" @@ -108,6 +117,7 @@ local Commands = { Leave = "leave", Rename = "rename", Remove = "remove", + Copy = "copy", Create = "create", Shell = "shell", Paste = "paste", @@ -117,6 +127,7 @@ local Commands = { Arrow = "arrow", ParentArrow = "parent_arrow", Archive = "archive", + Emit = "emit", Editor = "editor", Pager = "pager", } @@ -130,6 +141,34 @@ local ItemGroup = { Prompt = "prompt", } +-- Initialise the enum of components for the theme configuration +local ConfigurableComponents = { + + ---@enum BuiltInComponents + BuiltIn = { + Create = "create", + Overwrite = "overwrite", + }, + + ---@enum PluginComponents + Plugin = { + ItemGroup = "item_group", + ExtractPassword = "extract_password", + Quit = "quit", + Archive = "archive", + ArchivePassword = "archive_password", + Emit = "emit", + }, +} + +-- The theme options for the input and confirm prompts +local INPUT_AND_CONFIRM_OPTIONS = { + "title", + "origin", + "offset", + "content", +} + -- The default configuration for the plugin ---@type UserConfiguration local DEFAULT_CONFIG = { @@ -161,7 +200,7 @@ local DEFAULT_CONFIG = { -- The default input options for this plugin local DEFAULT_INPUT_OPTIONS = { - position = { "top-center", x = 0, y = 2, w = 50, h = 3 }, + pos = { "top-center", x = 0, y = 2, w = 50, h = 3 }, } -- The default confirm options for this plugin @@ -249,7 +288,7 @@ local ARCHIVE_FILE_EXTENSIONS_WITH_HEADER_ENCRYPTION = { -- does not implement any functionality ---@type string local BASE_ARCHIVER_ERROR = table.concat({ - "The Extractor class is does not implement any functionality.", + "The Archiver class is does not implement any functionality.", "How did you even manage to get here?", }, "\n") @@ -267,7 +306,7 @@ local BASE_ARCHIVER_ERROR = table.concat({ --- The map of the extract behaviour strings to the command flags ---@field extract_behaviour_map table local Archiver = { - name = "BaseExtractor", + name = "BaseArchiver", command = nil, commands = {}, supports_file_permissions = false, @@ -312,7 +351,7 @@ function Archiver:archive(_) } end --- The 7-Zip extractor +-- The 7-Zip archiver ---@class SevenZip: Archiver ---@field password string The password to the archive local SevenZip = Archiver:subclass({ @@ -328,7 +367,7 @@ local SevenZip = Archiver:subclass({ password = "", }) --- The Tar extractor +-- The Tar archiver ---@class Tar: Archiver local Tar = Archiver:subclass({ name = ArchiverName.Tar, @@ -345,7 +384,7 @@ local Tar = Archiver:subclass({ }, }) --- The default extractor, which is set to 7-Zip +-- The default archiver, which is set to 7-Zip ---@class DefaultArchiver: SevenZip local DefaultArchiver = SevenZip:subclass({}) @@ -687,29 +726,138 @@ local function show_error(error_message, options) ) end --- Function to get the user's input ----@param prompt string The prompt to show to the user ----@param options YaziInputOptions|nil Options for the input ----@return string|nil user_input The user's input ----@return InputEvent event The event for the input function -local function get_user_input(prompt, options) - return ya.input(merge_tables({}, DEFAULT_INPUT_OPTIONS, options or {}, { - title = prompt, - })) +-- Function to throw an error +---@param error_message any The error message as a format string +---@param ... any The items to substitute into the error message given +local function throw_error(error_message, ...) + return error(string.format(error_message, ...)) +end + +-- Function to get the theme from an async function +---@type fun(): Th The theme object +local get_theme = ya.sync(function(state) return state.theme end) + +-- Function to get the component option string +---@param component BuiltInComponents|PluginComponents The component name +---@param option string The option +---@return string component_option The component option string +local function get_component_option_string(component, option) + return string.format("%s_%s", component, option) +end + +-- Function to get the user's configuration for the input or confirm components. +---@param component BuiltInComponents|PluginComponents The name of the component +---@param defaults { +--- prompts: string|string[], -- The default prompts +--- content: string|ui.Line|ui.Text|nil, -- The default contents +--- origin: string|nil, -- The default origin +--- offset: Position|nil, -- The default offset +---} +---@param is_plugin_options boolean|nil Whether the options are plugin specific +---@param is_confirm boolean|nil Whether the component is the confirm component +---@param title_index integer|nil The index to get the title +---@return YaziInputOptions|YaziConfirmOptions options The resolved options +local function get_user_input_or_confirm_options( + component, + defaults, + is_plugin_options, + is_confirm, + title_index +) + -- + + -- Initialise the default prompts + local default_prompts = type(defaults.prompts) == "string" + and { defaults.prompts } + or defaults.prompts + + -- Initialise the title index + title_index = title_index or 1 + + -- Get the theme object + local theme = get_theme() or {} + + -- Initialise the theme configuration + ---@diagnostic disable-next-line: undefined-field + local theme_config = is_plugin_options and (theme.augment_command or {}) + or theme + + -- Get the default options + local default_options = ( + is_confirm and DEFAULT_CONFIRM_OPTIONS or DEFAULT_INPUT_OPTIONS + ).pos + + -- Initialise the list of options + local option_list = {} + + -- Initialise the list of option suffixes + local option_suffixes = merge_tables({}, INPUT_AND_CONFIRM_OPTIONS) + + -- If the component is not the confirm component, remove the last suffix + if not is_confirm then table.remove(option_suffixes) end + + -- Create the list of options + for _, option_suffix in ipairs(option_suffixes) do + table.insert( + option_list, + get_component_option_string(component, option_suffix) + ) + end + + -- Unpack the options + local title_option, origin_option, offset_option, content_option = + table.unpack(option_list) + + -- Get the value of all the options + ---@type string|string[] + local raw_title = theme_config[title_option or ""] or {} + local origin = theme_config[origin_option or ""] + or defaults.origin + or default_options[1] + local offset = theme_config[offset_option or ""] or {} + local content = theme_config[content_option or ""] or defaults.content + + -- Get the title + local title = type(raw_title) == "string" and raw_title + or raw_title[title_index] + or default_prompts[title_index] + + -- Get the position object + local position = { + origin, + x = offset.x or default_options.x, + y = offset.y or default_options.y, + w = offset.w or default_options.w, + h = offset.h or default_options.h, + } + + -- Return the options + return { + title = title, + [is_confirm and "pos" or "position"] = position, + content = content, + } end -- Function to get a password from the user ----@param prompt string The prompt to show to the user ----@param confirmation_prompt string|nil The confirmation prompt ----@param options YaziInputOptions|nil Options for the input +---@param get_password_options GetPasswordOptions Get password options function +---@param want_confirmation boolean|nil Whether to get a confirmation password ---@return string|nil password The password or nil if the user cancelled ---@return InputEvent|nil event The event for the input function -local function get_password(prompt, confirmation_prompt, options) +local function get_password(get_password_options, want_confirmation) -- + -- Merge the obscure option with the password options + local password_options = + merge_tables(get_password_options(false), { obscure = true }) + -- If reconfirmation for the password is not wanted, -- just obtain the user's password and return it - if not confirmation_prompt then return get_user_input(prompt, options) end + if not want_confirmation then return ya.input(password_options) end + + -- Merge the obscure option with the confirm password options + local confirm_password_options = + merge_tables(get_password_options(true), { obscure = true }) -- Otherwise, initialise the password and the event local password = nil @@ -720,7 +868,7 @@ local function get_password(prompt, confirmation_prompt, options) -- -- Get the initial password from the user - local initial_password, initial_event = get_user_input(prompt, options) + local initial_password, initial_event = ya.input(password_options) -- If the initial password is nil, exit the function if initial_password == nil then @@ -729,7 +877,7 @@ local function get_password(prompt, confirmation_prompt, options) -- Get the confirmation password from the user local confirmation_password, confirmation_event = - get_user_input(confirmation_prompt, options) + ya.input(confirm_password_options) -- If the confirmation password is nil, exit the function if confirmation_password == nil then @@ -751,28 +899,68 @@ local function get_password(prompt, confirmation_prompt, options) end -- Otherwise, tell the user their passwords don't match - show_error("Passwords do not match") + show_error("Passwords do not match, please try again") end -- Return the password and event return password, event end --- Function to get the user's confirmation ----@param title string|ui.Line The title of the confirmation prompt ----@param content string|ui.Text The content of the confirmation prompt ----@return boolean confirmation Whether the user has confirmed or not -local function get_user_confirmation(title, content) +-- Function to show an overwrite prompt +---@param file_path_to_overwrite string|Url The file path to overwrite +---@return boolean overwrite Whether the user chooses to overwrite the file +local function show_overwrite_prompt(file_path_to_overwrite) -- - -- Get the user's confirmation - local confirmation = ya.confirm(merge_tables({}, DEFAULT_CONFIRM_OPTIONS, { - title = title, - content = content, - })) + -- Get the user's configuration for the overwrite prompt + local overwrite_confirm_options = get_user_input_or_confirm_options( + ConfigurableComponents.BuiltIn.Overwrite, + { + prompts = "Overwrite file?", + content = ui.Line("Will overwrite the following file:"), + }, + false, + true + ) - -- Return the result of the confirmation - return confirmation + -- Get the type of the overwrite content + local overwrite_content_type = type(overwrite_confirm_options.content) + + -- Initialise the first line of the content + local first_line = nil + + -- If the content section is a string + if + overwrite_content_type == "string" + or overwrite_content_type == "table" + then + -- + + -- Wrap the string in a line and align it to the center. + first_line = ui.Line(overwrite_confirm_options.content) + :align(ui.Line.CENTER) + + -- Otherwise, just set the first line to the content given + else + first_line = overwrite_confirm_options.content + end + + -- Create the content for the overwrite prompt + ---@cast first_line ui.Line|ui.Span + overwrite_confirm_options.content = ui.Text({ + first_line, + ui.Line(string.rep("─", overwrite_confirm_options.pos.w - 2)) + :style(ui.Style(th.confirm.border)) + :align(ui.Line.LEFT), + ui.Line(tostring(file_path_to_overwrite)):align(ui.Line.LEFT), + }):wrap(ui.Text.WRAP_TRIM) + + -- Get the user's confirmation for + -- whether they want to overwrite the item + local user_confirmation = ya.confirm(overwrite_confirm_options) + + -- Return whether the user wants to overwrite the file or not + return user_confirmation end -- Function to merge the given configuration table with the default one @@ -834,38 +1022,122 @@ local function merge_configuration(config) return merged_config end +-- Function to get whether sudo edit is supported +---@return boolean sudo_edit_supported Whether sudo edit is supported +local function get_sudo_edit_supported() + -- + + -- Call the "sudo --help" command and get the handle + -- + -- The "2>&1" redirects the standard error + -- to the file descriptor of the standard output. + -- + -- Since Yazi displays its UI on standard error, + -- we don't want the command to output to the standard error, + -- which will mess up Yazi's UI, so we redirect + -- the standard error output to the standard output. + -- + -- References: + -- https://stackoverflow.com/questions/10508843/what-is-dev-null-21 + -- https://stackoverflow.com/questions/818255/what-does-21-mean + -- https://www.gnu.org/software/bash/manual/html_node/Redirections.html + local handle = io.popen("sudo --help 2>&1") + + -- If the call fails, return false + if not handle then return false end + + -- Otherwise, get the output of the command + local output = handle:read("*a") + + -- Close the handle + handle:close() + + -- If the output contains the edit flag, + -- sudo edit is supported, otherwise, it isn't + local sudo_edit_supported = output:match("%-e, %-%-edit") ~= nil + + -- Return whether sudo edit is supported + return sudo_edit_supported +end + -- Function to initialise the configuration ---@type fun( ---- user_config: Configuration|nil, -- The configuration object +--- user_config: UserConfiguration|nil, -- The configuration object ---): Configuration The initialised configuration object local initialise_config = ya.sync(function(state, user_config) -- -- Merge the default configuration with the user given one, - -- as well as the additional data given, - -- and set it to the state. - state.config = merge_configuration(user_config) + -- as well as the additional data given. + local config = merge_configuration(user_config) + + -- Set the sudo_edit_supported property + ---@cast config Configuration + config.sudo_edit_supported = get_sudo_edit_supported() + + -- Set the configuration to the state + state.config = config -- Return the configuration object for async functions return state.config end) +-- Function to initialise the theme configuration +---@type fun(): Th +local initialise_theme = ya.sync(function(state) + -- + + -- Initialise the theme configuration table + local theme_config = {} + + -- Iterate over all the built-in components + for _, component in pairs(ConfigurableComponents.BuiltIn) do + -- + + -- Iterate over all the options + for _, option in ipairs(INPUT_AND_CONFIRM_OPTIONS) do + -- + + -- Get the component's option + local component_option = + get_component_option_string(component, option) + + -- Get the value for the option + local value = th[component_option] + + -- If the value isn't nil, add it to the theme configuration + if value ~= nil then theme_config[component_option] = value end + end + end + + -- Add the plugin specific theme configuration to the theme configuration + ---@diagnostic disable-next-line: undefined-field + theme_config.augment_command = th.augment_command + + -- Set the theme configuration to the state + state.theme = theme_config + + -- Return the theme object + return state.theme +end) + -- Function to try if a shell command exists ---@param shell_command string The shell command to check ---@param args string[]|nil The arguments to the shell command ---@return boolean shell_command_exists Whether the shell command exists +---@return CommandOutput|nil output The output of the shell command local function async_shell_command_exists(shell_command, args) -- -- Get the output of the shell command with the given arguments local output = Command(shell_command) - :args(args or {}) + :arg(args or {}) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() -- Return true if there's an output and false otherwise - return output ~= nil + return output ~= nil, output end -- Function to emit a command from this plugin @@ -885,7 +1157,7 @@ local function emit_augmented_command(command, args) end -- Emit the augmented command - return ya.mgr_emit("plugin", { + return ya.emit("plugin", { PLUGIN_NAME, string.format("%s %s", command, arguments), }) @@ -915,8 +1187,9 @@ local subscribe_to_augmented_extract_event = ya.sync(function(_) end) -- Function to initialise the plugin ----@param opts Configuration|nil The options given to the plugin +---@param opts UserConfiguration|nil The options given to the plugin ---@return Configuration config The initialised configuration object +---@return Th theme The saved theme object local function initialise_plugin(opts) -- @@ -926,8 +1199,11 @@ local function initialise_plugin(opts) -- Initialise the configuration object local config = initialise_config(opts) + -- Add the theme configuration to the config + local theme = initialise_theme() + -- Return the configuration object - return config + return config, theme end -- Function to standardise the mime type of a file. @@ -974,12 +1250,11 @@ local function is_archive_mime_type(mime_type) -- Standardise the mime type local standardised_mime_type = standardise_mime_type(mime_type) - -- Get the archive extractor for the mime type - local archive_extractor = - ARCHIVE_MIME_TYPE_TO_ARCHIVER_MAP[standardised_mime_type] + -- Get the archiver for the mime type + local archiver = ARCHIVE_MIME_TYPE_TO_ARCHIVER_MAP[standardised_mime_type] - -- Return if an extractor exists for the mime type - return archive_extractor ~= nil + -- Return if an archiver exists for the mime type + return archiver ~= nil end -- Function to check if a given file extension @@ -1013,7 +1288,7 @@ local function get_mime_type(file_path) -- Get the output of the file command local output, _ = Command("file") - :args({ + :arg({ -- Don't prepend file names to the output "-b", @@ -1085,12 +1360,7 @@ end -- Function to get the configuration from an async function ---@type fun(): Configuration The configuration object -local get_config = ya.sync(function(state) - -- - - -- Returns the configuration object - return state.config -end) +local get_config = ya.sync(function(state) return state.config end) -- Function to get the current working directory ---@type fun(): string Returns the current working directory as a string @@ -1206,21 +1476,6 @@ local get_tab_preferences = ya.sync(function(_) return tab_preferences end) --- Function to get if Yazi is loading ----@type fun(): boolean -local yazi_loaded = ya.sync(function(_) - local stage = cx.active.current.stage - local loaded, _ = stage() - return loaded -end) - --- Function to wait until Yazi is loaded ----@return nil -local function wait_until_yazi_is_loaded() - while not yazi_loaded() do - end -end - -- Function to choose which group of items to operate on. -- It returns ItemGroup.Hovered for the hovered item, -- ItemGroup.Selected for the selected items, @@ -1288,17 +1543,27 @@ local function prompt_for_desired_item_group() ---@type ItemGroup|nil local default_item_group = config.default_item_group_for_prompt - -- Get the input options + -- Get the input options, which the (h/s) options local input_options = INPUT_OPTIONS_TABLE[default_item_group] - -- If the default item group is None, then set it to nil + -- If the default item group is none, then set it to nil if default_item_group == ItemGroup.None then default_item_group = nil end - -- Prompt the user for their input - local user_input, event = get_user_input( - "Operate on hovered or selected items? " .. input_options + -- Get the user's input options for the item group prompt + local item_group_input_options = get_user_input_or_confirm_options( + ConfigurableComponents.Plugin.ItemGroup, + { prompts = "Operate on hovered or selected items?" }, + true ) + -- Add the input options to the title + item_group_input_options.title = + string.format("%s %s", item_group_input_options.title, input_options) + + -- Prompt the user for their input + ---@cast item_group_input_options YaziInputOptions + local user_input, event = ya.input(item_group_input_options) + -- If the user input is empty, then exit the function if not user_input then return end @@ -1436,23 +1701,23 @@ local function skip_single_child_directories(initial_directory_path) end -- Emit the change directory command to change to the directory variable - ya.mgr_emit("cd", { directory }) + ya.emit("cd", { directory }) end -- Class implementations --- The function to create a new instance of the extractor +-- The function to create a new instance of the archiver ---@param archive_path string The path to the archive ---@param config Configuration The configuration object ---@param destination_path string|nil The path to extract to ----@return Archiver|nil instance An instance of the extractor if available +---@return Archiver|nil instance An instance of the archiver if available function Archiver:new(archive_path, config, destination_path) -- - -- Initialise whether the extractor is available + -- Initialise whether the archiver is available local available = self.command ~= nil - -- If the extractor has not been initialised + -- If the archiver has not been initialised if not available then -- @@ -1480,7 +1745,7 @@ function Archiver:new(archive_path, config, destination_path) end end - -- If none of the commands for the extractor are available, + -- If none of the commands for the archiver are available, -- then return nil if not available then return nil end @@ -1499,12 +1764,12 @@ function Archiver:new(archive_path, config, destination_path) return instance end --- Function to retry the extractor +-- Function to retry the archiver ---@private ----@param extractor_function Archiver.Command Extractor command to retry +---@param archiver_function Archiver.Command Archiver command to retry ---@param clean_up_wanted boolean|nil Whether to clean up the destination path ----@return Archiver.Result result Result of the extractor function -function SevenZip:retry_extractor(extractor_function, clean_up_wanted) +---@return Archiver.Result result Result of the archiver function +function SevenZip:retry_archiver(archiver_function, clean_up_wanted) -- -- Initialise the number of tries @@ -1518,7 +1783,7 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) local archive_name = archive_url.name -- If the archive name is nil, - -- return the result of the extractor function + -- return the result of the archiver function if not archive_name then return { successful = false, @@ -1545,8 +1810,8 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) for tries = 0, total_number_of_tries do -- - -- Execute the extractor function - local output, error = extractor_function() + -- Execute the archiver function + local output, error = archiver_function() -- If there is no output if not output then @@ -1555,7 +1820,7 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) -- Clean up the extracted files clean_up() - -- Return the result of the extractor function + -- Return the result of the archiver function return { successful = false, error = tostring(error), @@ -1564,7 +1829,7 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) -- If the output status code is 0, -- which means the command was successful, - -- return the result of the extractor function + -- return the result of the archiver function if output.status.code == 0 then return { successful = true, @@ -1590,7 +1855,7 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) then -- - -- Return the extractor function result + -- Return the archiver function result return { successful = false, error = error_message, @@ -1602,7 +1867,7 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) or wrong_password_prompt -- Initialise the width of the input element - local input_width = DEFAULT_INPUT_OPTIONS.position.w + local input_width = DEFAULT_INPUT_OPTIONS.pos.w -- If the length of the password prompt is larger -- than the default input with, set the input width @@ -1611,17 +1876,30 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) input_width = #password_prompt + 1 end - -- Ask the user for the password - local user_input, event = get_password( - password_prompt, - nil, - merge_tables( - true, - {}, - DEFAULT_INPUT_OPTIONS, - { position = { w = input_width } } + -- Function to get the user's input option + -- for the extract password prompt + ---@type GetPasswordOptions + local function get_user_extract_password_options(_) + -- + + -- Get the password input options + local password_input_options = get_user_input_or_confirm_options( + ConfigurableComponents.Plugin.ExtractPassword, + { prompts = password_prompt }, + true ) - ) + + -- Set the width of the component to the input width + ---@cast password_input_options YaziInputOptions + password_input_options.position.w = input_width + + -- Return the password input options + return password_input_options + end + + -- Ask the user for the password + local user_input, event = + get_password(get_user_extract_password_options) -- If the user has confirmed the input, -- and the user input is not nil, @@ -1633,7 +1911,7 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) else -- - -- Return the result of the extractor command + -- Return the result of the archiver command return { successful = false, cancelled = true, @@ -1646,7 +1924,7 @@ function SevenZip:retry_extractor(extractor_function, clean_up_wanted) -- call the clean up function clean_up() - -- Return the result of the extractor command + -- Return the result of the archiver command return { successful = false, error = error_message, @@ -1679,7 +1957,7 @@ function SevenZip:list_items_command() -- Return the result of the command to list the items in the archive return Command(self.command) - :args(arguments) + :arg(arguments) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() @@ -1698,23 +1976,23 @@ function SevenZip:get_items() ---@type string[] local directories = {} - -- Call the function to retry the extractor command + -- Call the function to retry the archiver command -- with the list items in the archive function - local extractor_result = self:retry_extractor( + local archiver_result = self:retry_archiver( function() return self:list_items_command() end ) -- Get the output - local output = extractor_result.output + local output = archiver_result.output -- Get the error - local error = extractor_result.error + local error = archiver_result.error - -- If the extractor command was not successful, + -- If the archiver command was not successful, -- or the output was nil, -- then return nil the error message, -- and nil as the correct password - if not extractor_result.successful or not output then + if not archiver_result.successful or not output then return files, directories, error end @@ -1820,7 +2098,7 @@ function SevenZip:extract_command(extract_files_only, extract_behaviour) -- Return the output of the command return Command(self.command) - :args(arguments) + :arg(arguments) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() @@ -1831,13 +2109,13 @@ end function SevenZip:extract(has_only_one_file) -- - -- Extract the archive with the extractor command - local result = self:retry_extractor( + -- Extract the archive with the extract command + local result = self:retry_archiver( function() return self:extract_command(has_only_one_file) end, true ) - -- Return the extractor result + -- Return the archiver result return result end @@ -1875,7 +2153,7 @@ function SevenZip:archive_command(item_paths, password, encrypt_headers) -- Return the output of the command return Command(self.command) - :args(arguments) + :arg(arguments) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() @@ -1934,7 +2212,7 @@ function Tar:list_items_command() -- Return the result of the command return Command(self.command) - :args(arguments) + :arg(arguments) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() @@ -2039,12 +2317,12 @@ function Tar:extract_command(extract_behaviour) -- -- The error here is ignored because if there -- is an error creating the directory, - -- then the extractor will fail anyway. + -- then the archiver will fail anyway. fs.create("dir_all", Url(self.destination_path)) -- Return the output of the command return Command(self.command) - :args(arguments) + :arg(arguments) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() @@ -2108,7 +2386,7 @@ function Tar:archive_command(item_paths) -- Return the output of the command return Command(self.command) - :args(arguments) + :arg(arguments) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() @@ -2180,13 +2458,13 @@ local function get_archiver(archive_path, command, config, destination_path) local archiver_instance = archiver:new(archive_path, config, destination_path) - -- While the extractor instance failed to be created + -- While the archiver instance failed to be created while not archiver_instance do -- -- If the archiver instance is the default archiver, -- then return an error telling the user to install the - -- default extractor + -- default archiver if archiver.name == DefaultArchiver.name then return archiver_instance, { @@ -2237,7 +2515,7 @@ local function get_archiver(archive_path, command, config, destination_path) show_warning(warning) end - -- Return the extractor instance + -- Return the archiver instance return archiver_instance, { successful = true } end @@ -2249,7 +2527,7 @@ local function move_extracted_items(archive_url, destination_url) -- -- The function to clean up the destination directory - -- and return the extractor result in the event of an error + -- and return the archiver result in the event of an error ---@param error string The error message to return ---@param empty_dir_only boolean|nil Whether to remove the empty dir only ---@return Archiver.Result @@ -2259,7 +2537,7 @@ local function move_extracted_items(archive_url, destination_url) -- Clean up the destination path fs.remove(empty_dir_only and "dir" or "dir_all", destination_url) - -- Return the extractor result + -- Return the archiver result ---@type Archiver.Result return { successful = false, @@ -2377,7 +2655,7 @@ local function move_extracted_items(archive_url, destination_url) -- Clean up the destination directory fs.remove(move_successful and "dir" or "dir_all", destination_url) - -- Return the extractor result with the target path as the + -- Return the archiver result with the target path as the -- path to the extracted items return { successful = move_successful, @@ -2441,14 +2719,14 @@ local function recursively_extract_archive( -- The additional information are: -- - The archive path -- - The destination path - -- - The name of the extractor + -- - The name of the archiver ---@param result Archiver.Result The result to add the paths to ---@return Archiver.Result modified_result The result with the paths added local function add_additional_info(result) return merge_tables({}, result, { archive_path = archive_path, destination_path = destination_path, - extractor_name = archiver.name, + archiver_name = archiver.name, }) end @@ -2579,17 +2857,17 @@ end -- Function to show an archiver error ---@param archiver_result Archiver.Result The result from the archiver ---@return nil -local function show_archiver_error(archiver_result) +local function throw_archiver_error(archiver_result) -- -- The line for the error local error_line = string.format("Error: %s", archiver_result.error) - -- If the extractor name exists + -- If the archiver name exists if archiver_result.archiver_name then -- - -- Add the extractor's name to the error + -- Add the archiver's name to the error error_line = string.format( "%s error: %s", archiver_result.archiver_name, @@ -2617,8 +2895,8 @@ local function show_archiver_error(archiver_result) error_string = error_line end - -- Show the error - show_error(error_string) + -- Throw the error + throw_error(error_string) end -- Function to handle the open command @@ -2638,7 +2916,7 @@ local function handle_open(args, config) -- -- Emit the command and exit the function - return ya.mgr_emit("open", args) + return ya.emit("open", args) end -- If the hovered item is a directory @@ -2670,7 +2948,7 @@ local function handle_open(args, config) -- opening only the hovered item -- as the item group is the hovered item, -- and exit the function - return ya.mgr_emit("open", merge_tables({}, args, { hovered = true })) + return ya.emit("open", merge_tables({}, args, { hovered = true })) end -- Otherwise, the hovered item is an archive @@ -2800,7 +3078,7 @@ local function handle_extract(args, config) -- If the extraction is not successful, notify the user if not extraction_result.successful or not extracted_items_path then - return show_archiver_error(extraction_result) + return throw_archiver_error(extraction_result) end -- Get the url of the archive @@ -2848,12 +3126,12 @@ local function handle_extract(args, config) -- -- Reveal the item and exit the function - return ya.mgr_emit("reveal", { extracted_items_url }) + return ya.emit("reveal", { extracted_items_url }) end -- Otherwise, change the directory to the extracted item. -- Note that extracted_items_url is destroyed here. - ya.mgr_emit("cd", { extracted_items_url }) + ya.emit("cd", { extracted_items_url }) -- If the user wants to skip single subdirectories on enter, -- and the no skip flag is not passed @@ -2890,7 +3168,7 @@ local function handle_enter(args, config) end -- Otherwise, always emit the enter command, - ya.mgr_emit("enter", args) + ya.emit("enter", args) -- If the user doesn't want to skip single subdirectories on enter, -- or one of the arguments passed is no skip, @@ -2913,7 +3191,7 @@ local function handle_leave(args, config) -- -- Always emit the leave command - ya.mgr_emit("leave", args) + ya.emit("leave", args) -- If the user doesn't want to skip single subdirectories on leave, -- or one of the arguments passed is no skip, @@ -2955,7 +3233,7 @@ local function handle_leave(args, config) end -- Emit the change directory command to change to the directory variable - ya.mgr_emit("cd", { directory }) + ya.emit("cd", { directory }) end -- Function to handle a Yazi command @@ -2976,14 +3254,14 @@ local function handle_yazi_command(command, args) -- -- Emit the command to operate on the selected items - ya.mgr_emit(command, args) + ya.emit(command, args) -- If the item group is the hovered item elseif item_group == ItemGroup.Hovered then -- -- Emit the command with the hovered option - ya.mgr_emit(command, merge_tables({}, args, { hovered = true })) + ya.emit(command, merge_tables({}, args, { hovered = true })) end end @@ -3012,7 +3290,7 @@ local function enter_or_open_created_item(item_url, is_directory, args, config) end -- Otherwise, call the function change to the created directory - return ya.mgr_emit("cd", { item_url }) + return ya.emit("cd", { item_url }) end -- Otherwise, the item is a file @@ -3025,14 +3303,8 @@ local function enter_or_open_created_item(item_url, is_directory, args, config) return end - -- Otherwise, call the function to reveal the created file - ya.mgr_emit("reveal", { item_url }) - - -- Wait for Yazi to finish loading - wait_until_yazi_is_loaded() - -- Call the function to open the file - return ya.mgr_emit("open", { hovered = true }) + return ya.emit("open", { hovered = true }) end -- Function to execute the create command @@ -3049,7 +3321,7 @@ local function execute_create(item_url, is_directory, args, config) -- If the parent directory doesn't exist, -- then show an error and exit the function if not parent_directory_url then - return show_error( + return throw_error( "Parent directory of the item to create doesn't exist" ) end @@ -3063,7 +3335,7 @@ local function execute_create(item_url, is_directory, args, config) -- If the function is not successful, -- show the error message and exit the function - if not successful then return show_error(error_message) end + if not successful then return throw_error(error_message) end -- Otherwise, the item to create is a file else @@ -3079,7 +3351,7 @@ local function execute_create(item_url, is_directory, args, config) -- If the function is not successful, -- show the error message and exit the function - if not successful then return show_error(error_message) end + if not successful then return throw_error(error_message) end end -- Otherwise, create the file @@ -3087,9 +3359,15 @@ local function execute_create(item_url, is_directory, args, config) -- If the function is not successful, -- show the error message and exit the function - if not successful then return show_error(error_message) end + if not successful then return throw_error(error_message) end end + -- Wait for a tiny bit for the file to be created + ya.sleep(10e-2) + + -- Reveal the created item + ya.emit("reveal", { tostring(item_url) }) + -- Call the function to enter or open the created item enter_or_open_created_item(item_url, is_directory, args, config) end @@ -3102,9 +3380,18 @@ local function handle_create(args, config) -- Get the directory flag local dir_flag = table_pop(args, "dir", false) + -- Get the user's input options for the create command + local create_input_options = get_user_input_or_confirm_options( + ConfigurableComponents.BuiltIn.Create, + { prompts = { "Create:", "Create (dir):" } }, + false, + false, + dir_flag and 2 or 1 + ) + -- Get the user's input for the item to create - local user_input, event = - get_user_input(dir_flag and "Create (dir):" or "Create:") + ---@cast create_input_options YaziInputOptions + local user_input, event = ya.input(create_input_options) -- If the user input is nil, -- or if the user did not confirm the input, @@ -3149,23 +3436,12 @@ local function handle_create(args, config) if fs.cha(full_url, false) and not table_pop(args, "force", false) then -- - -- Get the user's confirmation for - -- whether they want to overwrite the item - local user_confirmation = get_user_confirmation( - "Overwrite file?", - ui.Text({ - ui.Line("Will overwrite the following file:") - :align(ui.Line.CENTER), - ui.Line(string.rep("─", DEFAULT_CONFIRM_OPTIONS.pos.w - 2)) - :style(ui.Style(th.confirm.border)) - :align(ui.Line.LEFT), - ui.Line(tostring(full_url)):align(ui.Line.LEFT), - }):wrap(ui.Text.WRAP_TRIM) - ) + -- Get whether the user wants to overwrite the file + local should_overwrite = show_overwrite_prompt(full_url) - -- If the user did not confirm the overwrite, + -- If the user does not want to overwrite the file, -- then exit the function - if not user_confirmation then return end + if not should_overwrite then return end end -- Call the function to execute the create command @@ -3357,14 +3633,12 @@ local function handle_shell(args, _) -- If the command isn't a string, -- show an error message and exit the function if command_type ~= "string" then - return show_error( - string.format( - "Shell command given is not a string, " - .. "instead it is a '%s', " - .. "with value '%s'", - command_type, - tostring(command) - ) + return throw_error( + "Shell command given is not a string, " + .. "instead it is a '%s', " + .. "with value '%s'", + command_type, + tostring(command) ) end @@ -3455,7 +3729,7 @@ local function handle_shell(args, _) args = merge_tables({ command }, args) -- Emit the command to operate on the hovered item - ya.mgr_emit("shell", args) + ya.emit("shell", args) end -- Function to handle the paste command @@ -3472,17 +3746,17 @@ local function handle_paste(args, config) -- Just paste the items inside the current directory -- and exit the function - return ya.mgr_emit("paste", args) + return ya.emit("paste", args) end -- Otherwise, enter the directory - ya.mgr_emit("enter", {}) + ya.emit("enter", {}) -- Paste the items inside the directory - ya.mgr_emit("paste", args) + ya.emit("paste", args) -- Leave the directory - ya.mgr_emit("leave", {}) + ya.emit("leave", {}) end -- Function to execute the tab create command @@ -3510,12 +3784,12 @@ local execute_tab_create = ya.sync(function(state, args) -- Emit the command to create a new tab with the arguments -- and exit the function - return ya.mgr_emit("tab_create", args) + return ya.emit("tab_create", args) end -- Otherwise, emit the command to create a new tab -- with the hovered item's url - ya.mgr_emit("tab_create", { hovered_item.url }) + ya.emit("tab_create", { hovered_item.url }) end) -- Function to handle the tab create command @@ -3548,7 +3822,7 @@ local execute_tab_switch = ya.sync(function(state, args) if not (state.config.smart_tab_switch or table_pop(args, "smart", false)) then - return ya.mgr_emit("tab_switch", args) + return ya.emit("tab_switch", args) end -- Get the current tab @@ -3557,28 +3831,25 @@ local execute_tab_switch = ya.sync(function(state, args) -- Get the number of tabs currently open local number_of_open_tabs = #cx.tabs - -- Save the current tab's current working directory - local current_working_directory = tostring(current_tab.cwd) - -- Iterate from the number of current open tabs -- to the given tab number for _ = number_of_open_tabs, tab_index - 1 do -- -- Call the tab create command - ya.mgr_emit("tab_create", { current_working_directory }) + ya.emit("tab_create", { current_tab.cwd }) -- If there is a hovered item if current_tab.hovered then -- -- Reveal the hovered item - ya.mgr_emit("reveal", { tostring(current_tab.hovered.url) }) + ya.emit("reveal", { current_tab.hovered.url }) end end -- Switch to the given tab index - ya.mgr_emit("tab_switch", args) + ya.emit("tab_switch", args) end) -- Function to handle the tab switch command @@ -3601,24 +3872,41 @@ local function handle_quit(args, config) -- If the user doesn't want the confirm on quit functionality, -- or if the number of tabs is 1 or less, -- then emit the quit command - if not (config.confirm_on_quit or args.confirm) or number_of_tabs <= 1 then - return ya.mgr_emit("quit", args) + if + not (config.confirm_on_quit or table_pop(args, "confirm", false)) + or number_of_tabs <= 1 + then + return ya.emit("quit", args) end - -- Otherwise, get the user's confirmation for quitting - local user_confirmation = get_user_confirmation( - "Quit?", - ui.Text({ - "There are multiple tabs open.", - "Are you sure you want to quit?", - }):wrap(ui.Text.WRAP_TRIM) - ) + -- Otherwise, get the user's confirm options + local quit_confirm_options = + get_user_input_or_confirm_options(ConfigurableComponents.Plugin.Quit, { + prompts = "Quit?", + content = ui.Text({ + "There are multiple tabs open.", + "Are you sure you want to quit?", + }):wrap(ui.Text.WRAP_TRIM), + }, true, true) + + -- Get the type of the quit content + local quit_content_type = type(quit_confirm_options.content) + + -- If the type of the quit content is a string or a list of strings + if quit_content_type == "string" or quit_content_type == "table" then + quit_confirm_options.content = ui.Text(quit_confirm_options.content) + :wrap(ui.Text.WRAP_TRIM) + end + + -- Get the user's confirmation for quitting + ---@cast quit_confirm_options YaziConfirmOptions + local user_confirmation = ya.confirm(quit_confirm_options) -- If the user didn't confirm, then exit the function if not user_confirmation then return end -- Otherwise, emit the quit command - ya.mgr_emit("quit", args) + ya.emit("quit", args) end -- Function to handle smooth scrolling @@ -3667,7 +3955,7 @@ local function wraparound_arrow(args) -- immediately emit the arrow command -- and exit the function if type(steps) ~= "number" then - return ya.mgr_emit("arrow", merge_tables({ steps }, args)) + return ya.emit("arrow", merge_tables({ steps }, args)) end -- Initialise the arrow command to use @@ -3689,7 +3977,7 @@ local function wraparound_arrow(args) -- -- Emit the arrow command - ya.mgr_emit("arrow", merge_tables({ arrow_command }, args)) + ya.emit("arrow", merge_tables({ arrow_command }, args)) end end @@ -3709,12 +3997,12 @@ local function handle_arrow(args, config) -- immediately emit the arrow command -- and exit the function if type(steps) ~= "number" then - return ya.mgr_emit("arrow", merge_tables({ steps }, args)) + return ya.emit("arrow", merge_tables({ steps }, args)) end -- Initialise the function to the regular arrow command local function scroll_func(step) - ya.mgr_emit("arrow", merge_tables({ step }, args)) + ya.emit("arrow", merge_tables({ step }, args)) end -- If wraparound file navigation is wanted @@ -3748,7 +4036,7 @@ local function handle_arrow(args, config) end -- Otherwise, emit the regular arrow command - ya.mgr_emit("arrow", args) + ya.emit("arrow", args) end -- Function to get the directory items in the parent directory @@ -3812,14 +4100,12 @@ local execute_parent_arrow = ya.sync(function(state, args) -- then show an error that the offset is not a number -- and exit the function if offset_type ~= "number" then - return show_error( - string.format( - "The given offset is not of the type 'number', " - .. "instead it is a '%s', " - .. "with value '%s'", - offset_type, - tostring(offset) - ) + return throw_error( + "The given offset is not of the type 'number', " + .. "instead it is a '%s', " + .. "with value '%s'", + offset_type, + tostring(offset) ) end @@ -3915,7 +4201,7 @@ local execute_parent_arrow = ya.sync(function(state, args) -- Emit the command to change directory to -- the directory item and exit the function - return ya.mgr_emit("cd", { directory_item.url }) + return ya.emit("cd", { directory_item.url }) end end end) @@ -4039,11 +4325,57 @@ local function handle_archive(args, config) -- If the item paths is nil, exit the function if not item_paths then return end - -- Get the path to the archive - local archive_path = get_user_input("Archive name:") + -- Get the user's archive input options + local archive_input_options = get_user_input_or_confirm_options( + ConfigurableComponents.Plugin.Archive, + { prompts = "Archive name:" }, + true + ) - -- If the archive path isn't given, exit the function - if not archive_path then return end + -- Get the user's input + ---@cast archive_input_options YaziInputOptions + local user_input, event = ya.input(archive_input_options) + + -- If the user did not confirm the input, + -- exit the function + if event ~= 1 then return end + + -- Get the archive path + local archive_path = user_input or "" + + -- If the archive path is empty + if #string_trim(archive_path) < 1 then + -- + + -- If the item group is not the hovered item, + -- exit the function + if item_group ~= ItemGroup.Hovered then return end + + -- Otherwise, get the path of the hovered item + local hovered_item_path = table.unpack(item_paths) + + -- Set the archive name to the hovered item path + -- plus the zip extension + archive_path = hovered_item_path .. ".zip" + end + + -- If the archive path doesn't have a file extension, + -- add the ".zip" file extension + if not Url(archive_path).ext then archive_path = archive_path .. ".zip" end + + -- Get the full url of the archive path + local archive_url = Url(get_current_directory()):join(archive_path) + + -- If the archive already exists and the force flag isn't passed + if fs.cha(archive_url, false) and not table_pop(args, "force", false) then + -- + + -- Get whether the user wants to overwrite the existing file + local should_overwrite = show_overwrite_prompt(archive_url) + + -- If the user doesn't want to overwrite the file, exit the function + if not should_overwrite then return end + end -- Get the archiver local archiver, get_archiver_results = @@ -4051,16 +4383,41 @@ local function handle_archive(args, config) -- If the archiver can't be instantiated, -- show the error and exit the function - if not archiver then return show_archiver_error(get_archiver_results) end + if not archiver then return throw_archiver_error(get_archiver_results) end -- Initialise the password local password = nil - -- If the user wants to encrypt the archive, - -- get the password from the user + -- If the user wants to encrypt the archive if config.encrypt_archives or table_pop(args, "encrypt", false) then - password = - get_password("Archive password:", "Confirm archive password:") + -- + + -- Function to get the user's archive password options + ---@type GetPasswordOptions + local function get_user_archive_password_options(is_confirm_password) + -- + + -- Get the user's archive password options + local archive_password_options = get_user_input_or_confirm_options( + ConfigurableComponents.Plugin.ArchivePassword, + { + prompts = { + "Archive password:", + "Confirm archive password:", + }, + }, + true, + false, + is_confirm_password and 2 or 1 + ) + + -- Return the user's archive password options + ---@cast archive_password_options YaziInputOptions + return archive_password_options + end + + -- Get the user's password + password = get_password(get_user_archive_password_options, true) end -- Get whether to encrypt the headers or not @@ -4080,19 +4437,139 @@ local function handle_archive(args, config) -- If the archiver is not successful, -- show the error and exit the function if not archiver_result.successful then - return show_archiver_error(archiver_result) - end - - -- If the user wants to reveal the created archive, - -- then reveal the created archive - if config.reveal_created_archive or table_pop(args, "reveal", false) then - ya.mgr_emit("reveal", { archive_path }) + return throw_archiver_error(archiver_result) end -- If the user wants to remove archived files, remove them if config.remove_archived_files or table_pop(args, "remove", false) then remove_items(item_paths) end + + -- If the user wants to reveal the created archive + if config.reveal_created_archive or table_pop(args, "reveal", false) then + -- + + -- Wait for a tiny bit for the archive to be created + ya.sleep(10e-2) + + -- Reveal the archive + ya.emit("reveal", { archive_path }) + end +end + +-- Function to handle the emit command +---@type CommandFunction +local function handle_emit(args) + -- + + -- Get the command to emit given by the user + local given_command = table.remove(args, 1) + + -- Get whether the user wants a plugin command + local is_plugin_command = args.plugin + + -- Get whether the user wants an augmented command + local is_augmented_command = args.augmented + + -- Initialise the emit title index + local emit_title_index = nil + + -- Initialise the command function + ---@type fun(command: string, arguments: Arguments): nil + local function command_function(_, _) end + + -- If the user wants an augmented command + if is_augmented_command then + -- + + -- Set the emit title index to 3 + emit_title_index = 3 + + -- Set the command function to emit an augmented command + function command_function(command, arguments) + emit_augmented_command(command, arguments) + end + + -- Otherwise, if the user wants a plugin command + elseif is_plugin_command then + -- + + -- Set the emit title index to 2 + emit_title_index = 2 + + -- Set the command function to emit a plugin command + function command_function(command, arguments) + ya.emit( + "plugin", + { command, convert_arguments_to_string(arguments) } + ) + end + + -- Otherwise, the user wants a regular Yazi command + else + -- + + -- Set the emit title index to 1 + emit_title_index = 1 + + -- Set the command function to emit a Yazi command + function command_function(command, arguments) + ya.emit(command, arguments) + end + end + + -- If the command isn't given + if not given_command then + -- + + -- Get the user's options for the emit input + local emit_input_options = get_user_input_or_confirm_options( + ConfigurableComponents.Plugin.Emit, + { + prompts = { + "Yazi command:", + "Plugin command:", + "Augmented command:", + }, + }, + true, + false, + emit_title_index + ) + + -- If the emit input options is nil, exit the function + if not emit_input_options then return end + + -- Prompt the user for the command + ---@cast emit_input_options YaziInputOptions + given_command = ya.input(emit_input_options) or "" + + -- If the given command is empty, then exit the function + if #string_trim(given_command) < 1 then return end + + -- Emit the command to call the plugin's emit function + -- with the user's command + return emit_augmented_command( + "emit", + + -- The arguments that are being propagated + -- needs to come before the command, + -- otherwise, if the command contains a --, + -- then the wrong command will be emitted by the plugin + string.format( + "%s %s", + convert_arguments_to_string(args), + given_command + ) + ) + end + + -- Remove the plugin and augmented flag from the arguments + table_pop(args, "plugin") + table_pop(args, "augmented") + + -- Call the command function + command_function(given_command, args) end -- Function to handle the editor command @@ -4106,11 +4583,27 @@ local function handle_editor(args, config) -- If the editor not set, exit the function if not editor then return end + -- Initialise the shell command + local shell_command = string.format(editor .. " $@") + + -- Get the cha object of the hovered file + local hovered_item_cha = fs.cha( + Url(get_path_of_hovered_item() or ""), + false + ) or {} + + -- If the user ID of the file is root, + -- and sudo edit is supported, + -- set the shell command to "sudo -e" + if config.sudo_edit_supported and hovered_item_cha.uid == 0 then + shell_command = "sudo -e $@" + end + -- Call the handle shell function - -- with the editor command + -- with the shell command to open the editor handle_shell( merge_tables({ - editor .. " $@", + shell_command, block = true, exit_if_dir = true, }, args), @@ -4158,6 +4651,7 @@ local function run_command_func(command, args, config) [Commands.Leave] = handle_leave, [Commands.Rename] = function(_) handle_yazi_command("rename", args) end, [Commands.Remove] = function(_) handle_yazi_command("remove", args) end, + [Commands.Copy] = function(_) handle_yazi_command("copy", args) end, [Commands.Create] = handle_create, [Commands.Shell] = handle_shell, [Commands.Paste] = handle_paste, @@ -4167,6 +4661,7 @@ local function run_command_func(command, args, config) [Commands.Arrow] = handle_arrow, [Commands.ParentArrow] = handle_parent_arrow, [Commands.Archive] = handle_archive, + [Commands.Emit] = handle_emit, [Commands.Editor] = handle_editor, [Commands.Pager] = handle_pager, } @@ -4185,10 +4680,9 @@ local function run_command_func(command, args, config) end -- The setup function to setup the plugin ----@param _ any ----@param opts Configuration|nil The options given to the plugin +---@param opts UserConfiguration|nil The options given to the plugin ---@return nil -local function setup(_, opts) +function M:setup(opts) -- -- Initialise the plugin @@ -4196,10 +4690,9 @@ local function setup(_, opts) end -- Function to be called to use the plugin ----@param _ any ---@param job { args: Arguments } The job object given by Yazi ---@return nil -local function entry(_, job) +function M:entry(job) -- -- Get the arguments to the plugin @@ -4224,9 +4717,5 @@ local function entry(_, job) run_command_func(command, args, config) end --- Returns the table required for Yazi to run the plugin ----@return { setup: fun(): nil, entry: fun(): nil } -return { - setup = setup, - entry = entry, -} +-- Return the module table +return M diff --git a/config/yazi/plugins/chmod.yazi/README.md b/config/yazi/plugins/chmod.yazi/README.md index e8a66142..b2ad1364 100644 --- a/config/yazi/plugins/chmod.yazi/README.md +++ b/config/yazi/plugins/chmod.yazi/README.md @@ -7,7 +7,7 @@ https://github.com/yazi-rs/plugins/assets/17523360/7aa3abc2-d057-498c-8473-a6282 ## Installation ```sh -ya pack -a yazi-rs/plugins:chmod +ya pkg add yazi-rs/plugins:chmod ``` ## Usage @@ -15,7 +15,7 @@ ya pack -a yazi-rs/plugins:chmod Add this to your `~/.config/yazi/keymap.toml`: ```toml -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = [ "c", "m" ] run = "plugin chmod" desc = "Chmod on selected files" diff --git a/config/yazi/plugins/chmod.yazi/main.lua b/config/yazi/plugins/chmod.yazi/main.lua index ad565c68..589ebd56 100644 --- a/config/yazi/plugins/chmod.yazi/main.lua +++ b/config/yazi/plugins/chmod.yazi/main.lua @@ -1,4 +1,4 @@ ---- @since 25.2.26 +--- @since 25.5.28 local selected_or_hovered = ya.sync(function() local tab, paths = cx.active, {} @@ -13,7 +13,7 @@ end) return { entry = function() - ya.mgr_emit("escape", { visual = true }) + ya.emit("escape", { visual = true }) local urls = selected_or_hovered() if #urls == 0 then @@ -28,7 +28,7 @@ return { return end - local status, err = Command("chmod"):arg(value):args(urls):spawn():wait() + local status, err = Command("chmod"):arg(value):arg(urls):spawn():wait() if not status or not status.success then ya.notify { title = "Chmod", diff --git a/config/yazi/plugins/diff.yazi/README.md b/config/yazi/plugins/diff.yazi/README.md index 54faeb37..1976541e 100644 --- a/config/yazi/plugins/diff.yazi/README.md +++ b/config/yazi/plugins/diff.yazi/README.md @@ -7,7 +7,7 @@ https://github.com/yazi-rs/plugins/assets/17523360/eff5e949-386a-44ea-82f9-4cb4a ## Installation ```sh -ya pack -a yazi-rs/plugins:diff +ya pkg add yazi-rs/plugins:diff ``` ## Usage @@ -15,7 +15,7 @@ ya pack -a yazi-rs/plugins:diff Add this to your `~/.config/yazi/keymap.toml`: ```toml -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "" run = "plugin diff" desc = "Diff the selected with the hovered file" diff --git a/config/yazi/plugins/full-border.yazi/README.md b/config/yazi/plugins/full-border.yazi/README.md index 6e78bd4d..269ca8ec 100644 --- a/config/yazi/plugins/full-border.yazi/README.md +++ b/config/yazi/plugins/full-border.yazi/README.md @@ -7,7 +7,7 @@ Add a full border to Yazi to make it look fancier. ## Installation ```sh -ya pack -a yazi-rs/plugins:full-border +ya pkg add yazi-rs/plugins:full-border ``` ## Usage diff --git a/config/yazi/plugins/full-border.yazi/main.lua b/config/yazi/plugins/full-border.yazi/main.lua index abb1c3eb..a917e1e8 100644 --- a/config/yazi/plugins/full-border.yazi/main.lua +++ b/config/yazi/plugins/full-border.yazi/main.lua @@ -7,10 +7,10 @@ local function setup(_, opts) 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.Bar.TOP) + return ui.Bar(ui.Edge.TOP) end - return ui.Bar(ui.Bar.TOP) + 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) } ) @@ -26,9 +26,9 @@ local function setup(_, opts) local style = th.mgr.border_style self._base = ya.list_merge(self._base or {}, { - 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.LEFT):area(self._chunks[3]):style(style), + 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), diff --git a/config/yazi/plugins/git.yazi/README.md b/config/yazi/plugins/git.yazi/README.md index 4c5b07c7..f1848e99 100644 --- a/config/yazi/plugins/git.yazi/README.md +++ b/config/yazi/plugins/git.yazi/README.md @@ -1,8 +1,5 @@ # 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 @@ -10,7 +7,7 @@ https://github.com/user-attachments/assets/34976be9-a871-4ffe-9d5a-c4cdd0bf4576 ## Installation ```sh -ya pack -a yazi-rs/plugins:git +ya pkg add yazi-rs/plugins:git ``` ## Setup diff --git a/config/yazi/plugins/git.yazi/main.lua b/config/yazi/plugins/git.yazi/main.lua index d8f365a2..fd8b8bf6 100644 --- a/config/yazi/plugins/git.yazi/main.lua +++ b/config/yazi/plugins/git.yazi/main.lua @@ -1,4 +1,4 @@ ---- @since 25.4.4 +--- @since 25.5.28 local WINDOWS = ya.target_family() == "windows" @@ -190,8 +190,8 @@ local function fetch(_, job) -- 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) + :arg({ "--no-optional-locks", "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames", "--ignored=matching" }) + :arg(paths) :stdout(Command.PIPED) :output() if not output then diff --git a/config/yazi/plugins/mediainfo.yazi/README.md b/config/yazi/plugins/mediainfo.yazi/README.md index 71a2b942..9e6078ba 100644 --- a/config/yazi/plugins/mediainfo.yazi/README.md +++ b/config/yazi/plugins/mediainfo.yazi/README.md @@ -10,7 +10,7 @@ This is a Yazi plugin for previewing media files. The preview shows thumbnail using `ffmpeg` if available and media metadata using `mediainfo`. > [!IMPORTANT] -> Minimum version: yazi v25.2.7. +> Minimum version: yazi v25.5.28. ## Preview @@ -48,13 +48,14 @@ Install mediainfo CLI: Install + config this plugin: -> [!IMPORTANT] -> `mediainfo` use video, image, svg, magick built-in plugins behind the scene to render preview image, song cover. +> [!IMPORTANT] > `mediainfo` use video, image, svg, magick built-in plugins behind the scene to render preview image, song cover. > So you can remove those 3 plugins from `preloaders` and `previewers` sections in `yazi.toml`. If you have cache problem, run this cmd, and follow the tips: `yazi --clear-cache` ```bash +ya pkg add boydaihungst/mediainfo +# or ya pack -a boydaihungst/mediainfo ``` diff --git a/config/yazi/plugins/mediainfo.yazi/main.lua b/config/yazi/plugins/mediainfo.yazi/main.lua index 814bfc13..ced08601 100644 --- a/config/yazi/plugins/mediainfo.yazi/main.lua +++ b/config/yazi/plugins/mediainfo.yazi/main.lua @@ -1,4 +1,4 @@ ---- @since 25.2.7 +--- @since 25.5.28 local skip_labels = { ["Complete name"] = true, @@ -56,13 +56,13 @@ function M:peek(job) return end local cache_mediainfo_path = tostring(cache_img_url_no_skip) .. suffix - ya.sleep(math.max(0, (rt and rt.preview or PREVIEW).image_delay / 1000 + start - os.clock())) + ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) local output = read_mediainfo_cached_file(cache_mediainfo_path) local lines = {} local max_lines = math.floor(job.area.h / 2) local last_line = 0 - local is_wrap = rt and rt.preview and rt.preview.wrap == "yes" + local is_wrap = rt.preview.wrap == "yes" if output then local max_width = math.max(1, job.area.w) @@ -82,11 +82,11 @@ function M:peek(job) if not skip_labels[label] then line = ui.Line({ ui.Span(label .. ": "):style(ui.Style():fg("reset"):bold()), - ui.Span(value):style((th and th.spot and th.spot.tbl_col) or ui.Style():fg("blue")), + ui.Span(value):style(th.spot.tbl_col or ui.Style():fg("blue")), }) end elseif str ~= "General" then - line = ui.Line({ ui.Span(str):style((th and th.spot and th.spot.title) or ui.Style():fg("green")) }) + line = ui.Line({ ui.Span(str):style(th.spot.title or ui.Style():fg("green")) }) end if line then @@ -105,7 +105,7 @@ function M:peek(job) local mediainfo_height = math.min(max_lines, last_line) if (job.skip > 0 and #lines == 0) and (not is_video or (is_video and job.skip >= 90)) then - ya.manager_emit("peek", { math.max(0, job.skip - max_lines), only_if = job.file.url, upper_bound = false }) + ya.emit("peek", { math.max(0, job.skip - max_lines), only_if = job.file.url, upper_bound = false }) return end local rendered_img_rect = cache_img_url @@ -121,7 +121,7 @@ function M:peek(job) or nil local image_height = rendered_img_rect and rendered_img_rect.h or 0 - ya.preview_widgets(job, { + ya.preview_widget(job, { ui.Text(lines) :area(ui.Rect({ x = job.area.x, @@ -136,8 +136,7 @@ end function M:seek(job) local h = cx.active.current.hovered if h and h.url == job.file.url then - local step = ya.clamp(-10, job.units, 10) - ya.manager_emit("peek", { + ya.emit("peek", { math.max(0, cx.active.preview.skip + job.units), only_if = job.file.url, }) @@ -165,8 +164,8 @@ function M:preload(job) if cache_img_url_no_skip and (not cache_img_url_no_skip_cha or cache_img_url_no_skip_cha.len <= 0) then -- audio if job.mime and string.find(job.mime, "^audio/") then - local qv = 31 - math.floor((rt and rt.preview or PREVIEW).image_quality * 0.3) - local status, _ = Command("ffmpeg"):args({ + local qv = 31 - math.floor(rt.preview.image_quality * 0.3) + local status, _ = Command("ffmpeg"):arg({ "-v", "quiet", "-threads", @@ -185,10 +184,7 @@ function M:preload(job) "-q:v", qv, "-vf", - string.format( - "scale=-1:'min(%d,ih)':flags=fast_bilinear", - (rt and rt.preview or PREVIEW).max_height / 2 - ), + string.format("scale=-1:'min(%d,ih)':flags=fast_bilinear", rt.preview.max_height / 2), "-f", "image2", "-y", @@ -224,7 +220,7 @@ function M:preload(job) return true end local cmd = "mediainfo" - local output, err = Command(cmd):args({ tostring(job.file.url) }):stdout(Command.PIPED):output() + local output, err = Command(cmd):arg({ tostring(job.file.url) }):stdout(Command.PIPED):output() if err then err_msg = err_msg .. string.format("Failed to start `%s`, Do you have `%s` installed?\n", cmd, cmd) end diff --git a/config/yazi/plugins/mount.yazi/README.md b/config/yazi/plugins/mount.yazi/README.md index 6853be77..ff7f1101 100644 --- a/config/yazi/plugins/mount.yazi/README.md +++ b/config/yazi/plugins/mount.yazi/README.md @@ -1,8 +1,5 @@ # 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: @@ -15,7 +12,7 @@ https://github.com/user-attachments/assets/c6f780ab-458b-420f-85cf-2fc45fcfe3a2 ## Installation ```sh -ya pack -a yazi-rs/plugins:mount +ya pkg add yazi-rs/plugins:mount ``` ## Usage @@ -23,7 +20,7 @@ ya pack -a yazi-rs/plugins:mount Add this to your `~/.config/yazi/keymap.toml`: ```toml -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "M" run = "plugin mount" ``` diff --git a/config/yazi/plugins/mount.yazi/main.lua b/config/yazi/plugins/mount.yazi/main.lua index 962eeefd..87c7313d 100644 --- a/config/yazi/plugins/mount.yazi/main.lua +++ b/config/yazi/plugins/mount.yazi/main.lua @@ -1,4 +1,4 @@ ---- @since 25.2.26 +--- @since 25.5.28 local toggle_ui = ya.sync(function(self) if self.children then @@ -12,7 +12,7 @@ end) local subscribe = ya.sync(function(self) ps.unsub("mount") - ps.sub("mount", function() ya.mgr_emit("plugin", { self._id, "refresh" }) end) + ps.sub("mount", function() ya.emit("plugin", { self._id, "refresh" }) end) end) local update_partitions = ya.sync(function(self, partitions) @@ -113,7 +113,7 @@ function M:entry(job) elseif run == "enter" then local active = active_partition() if active and active.dist then - ya.mgr_emit("cd", { active.dist }) + ya.emit("cd", { active.dist }) end else tx2:send(run) @@ -155,11 +155,11 @@ function M:redraw() return { ui.Clear(self._area), - ui.Border(ui.Border.ALL) + ui.Border(ui.Edge.ALL) :area(self._area) :type(ui.Border.ROUNDED) :style(ui.Style():fg("blue")) - :title(ui.Line("Mount"):align(ui.Line.CENTER)), + :title(ui.Line("Mount"):align(ui.Align.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())) @@ -233,7 +233,7 @@ function M.fillin(tbl) return tbl end - local output, err = Command("lsblk"):args({ "-p", "-o", "name,fstype", "-J" }):args(sources):output() + local output, err = Command("lsblk"):arg({ "-p", "-o", "name,fstype", "-J" }):arg(sources):output() if err then ya.dbg("Failed to fetch filesystem types for unmounted partitions: " .. err) return tbl @@ -256,14 +256,14 @@ function M.operate(type) local output, err if ya.target_os() == "macos" then - output, err = Command("diskutil"):args({ type, active.src }):output() + output, err = Command("diskutil"):arg({ 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() + Command("udisksctl"):arg({ "unmount", "-b", active.src }):status() + output, err = Command("udisksctl"):arg({ "power-off", "-b", active.src }):output() else - output, err = Command("udisksctl"):args({ type, "-b", active.src }):output() + output, err = Command("udisksctl"):arg({ type, "-b", active.src }):output() end end diff --git a/config/yazi/plugins/rich-preview.yazi/README.md b/config/yazi/plugins/rich-preview.yazi/README.md index afacc0b6..938a3aee 100644 --- a/config/yazi/plugins/rich-preview.yazi/README.md +++ b/config/yazi/plugins/rich-preview.yazi/README.md @@ -14,7 +14,7 @@ Preview file types using `rich` command in Yazi. This plugin allows preview for ## Requirements -- [Yazi](https://github.com/sxyazi/yazi) v0.4 or higher. +- [Yazi](https://github.com/sxyazi/yazi) v25.4.8 or higher. - [rich-cli](https://github.com/Textualize/rich) v13.7.1 or higher. ## Installation @@ -22,7 +22,7 @@ Preview file types using `rich` command in Yazi. This plugin allows preview for To install this plugin, simply run- ```bash -ya pack -a AnirudhG07/rich-preview +ya pkg add AnirudhG07/rich-preview ## For linux and MacOS git clone https://github.com/AnirudhG07/rich-preview.yazi.git ~/.config/yazi/plugins/rich-preview.yazi diff --git a/config/yazi/plugins/smart-filter.yazi/README.md b/config/yazi/plugins/smart-filter.yazi/README.md index 8ac4c095..97be2ac4 100644 --- a/config/yazi/plugins/smart-filter.yazi/README.md +++ b/config/yazi/plugins/smart-filter.yazi/README.md @@ -7,7 +7,7 @@ https://github.com/yazi-rs/plugins/assets/17523360/72aaf117-1378-4f7e-93ba-d425a ## Installation ```sh -ya pack -a yazi-rs/plugins:smart-filter +ya pkg add yazi-rs/plugins:smart-filter ``` ## Usage @@ -15,7 +15,7 @@ ya pack -a yazi-rs/plugins:smart-filter Add this to your `~/.config/yazi/keymap.toml`: ```toml -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "F" run = "plugin smart-filter" desc = "Smart filter" diff --git a/config/yazi/plugins/smart-filter.yazi/main.lua b/config/yazi/plugins/smart-filter.yazi/main.lua index a47acffb..4141f954 100644 --- a/config/yazi/plugins/smart-filter.yazi/main.lua +++ b/config/yazi/plugins/smart-filter.yazi/main.lua @@ -1,4 +1,4 @@ ---- @since 25.2.26 +--- @since 25.5.28 local hovered = ya.sync(function() local h = cx.active.current.hovered @@ -28,20 +28,20 @@ local function entry() while true do local value, event = input:recv() if event ~= 1 and event ~= 3 then - ya.mgr_emit("escape", { filter = true }) + ya.emit("escape", { filter = true }) break end - ya.mgr_emit("filter_do", { value, smart = true }) + ya.emit("filter_do", { value, smart = true }) local h = hovered() if h.unique and h.is_dir then - ya.mgr_emit("escape", { filter = true }) - ya.mgr_emit("enter", {}) + ya.emit("escape", { filter = true }) + ya.emit("enter", {}) input = prompt() elseif event == 1 then - ya.mgr_emit("escape", { filter = true }) - ya.mgr_emit(h.is_dir and "enter" or "open", { h.url }) + ya.emit("escape", { filter = true }) + ya.emit(h.is_dir and "enter" or "open", { h.url }) end end end diff --git a/config/yazi/plugins/what-size.yazi/README.md b/config/yazi/plugins/what-size.yazi/README.md index c70b81ca..c94f4425 100644 --- a/config/yazi/plugins/what-size.yazi/README.md +++ b/config/yazi/plugins/what-size.yazi/README.md @@ -9,14 +9,15 @@ what-size supports Yazi on Linux, macOS, and Windows. ### OS - Linux since first commit -- macOS since commit `42c6a0efb7245badb16781da5380be1a1705f3f2` ([link](https://github.com/pirafrank/what-size.yazi/commit/42c6a0efb7245badb16781da5380be1a1705f3f2)) -- Windows since commit `4a56ead2a84c5969791fb17416e0b451ab906c5d` ([link](https://github.com/pirafrank/what-size.yazi/commit/4a56ead2a84c5969791fb17416e0b451ab906c5d)) +- macOS since commit `42c6a0e` ([link](https://github.com/pirafrank/what-size.yazi/commit/42c6a0efb7245badb16781da5380be1a1705f3f2)) +- Windows since commit `4a56ead` ([link](https://github.com/pirafrank/what-size.yazi/commit/4a56ead2a84c5969791fb17416e0b451ab906c5d)) ### Yazi -- yazi `25.x` since commit `fce1778d911621dc57796cdfdf11dcda3c2e28de` ([link](https://github.com/pirafrank/what-size.yazi/commit/fce1778d911621dc57796cdfdf11dcda3c2e28de)). -- yazi `0.4.x` since commit `2780de5aeef1ed16d1973dd6e0cd4d630c900d56` ([link](https://github.com/pirafrank/what-size.yazi/commit/2780de5aeef1ed16d1973dd6e0cd4d630c900d56)). -- yazi `0.3.x` up to commit `f08f7f2d5c94958ac4cb66c51a7c24b4319c6c93` ([link](https://github.com/pirafrank/what-size.yazi/commit/f08f7f2d5c94958ac4cb66c51a7c24b4319c6c93)). +- yazi `25.5.28` and onwards since commit `c5c939b` ([link](https://github.com/pirafrank/what-size.yazi/commit/c5c939bb37ec1d132c942cf5724d4e847acc2977)) +- yazi `25.x`-`25.4.8` since commit `fce1778` ([link](https://github.com/pirafrank/what-size.yazi/commit/fce1778d911621dc57796cdfdf11dcda3c2e28de)) +- yazi `0.4.x` since commit `2780de5` ([link](https://github.com/pirafrank/what-size.yazi/commit/2780de5aeef1ed16d1973dd6e0cd4d630c900d56)) +- yazi `0.3.x` up to commit `f08f7f2` ([link](https://github.com/pirafrank/what-size.yazi/commit/f08f7f2d5c94958ac4cb66c51a7c24b4319c6c93)) ## Requirements diff --git a/config/yazi/plugins/what-size.yazi/main.lua b/config/yazi/plugins/what-size.yazi/main.lua index 80b92c1f..5ec0e2d9 100644 --- a/config/yazi/plugins/what-size.yazi/main.lua +++ b/config/yazi/plugins/what-size.yazi/main.lua @@ -46,7 +46,7 @@ local function get_total_size(items) return total else local arg = ya.target_os() == "macos" and "-scA" or "-scb" - local output, err = Command("du"):arg(arg):args(items):output() + local output, err = Command("du"):arg(arg):arg(items):output() if not output then ya.err("Failed to run du: " .. err) end diff --git a/config/yazi/yazi.toml b/config/yazi/yazi.toml index 370eef44..f011fc2c 100644 --- a/config/yazi/yazi.toml +++ b/config/yazi/yazi.toml @@ -2,7 +2,7 @@ # 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" -[manager] +[mgr] ratio = [ 1, 2, 3 ] sort_by = "alphabetical" sort_sensitive = false diff --git a/config/zsh/.zshrc b/config/zsh/.zshrc index 275c084b..6bef5583 100644 --- a/config/zsh/.zshrc +++ b/config/zsh/.zshrc @@ -77,7 +77,7 @@ function cd { if [ $# -eq 0 ]; then new_directory=${HOME} fi - builtin cd "${new_directory}" && eza -a --icons --group-directories-first + z "${new_directory}" && eza -a --icons --group-directories-first } # Use lf to switch directories and bind it to ctrl-o @@ -87,7 +87,7 @@ lfcd() { lf -last-dir-path="$tmp" "$@" if [ -f "$tmp" ]; then dir="$(cat "$tmp")" - [ -d "$dir" ] && [ "$dir" != "$(pwd)" ] && cd "$dir" || return + [ -d "$dir" ] && [ "$dir" != "$(pwd)" ] && z "$dir" || return fi } @@ -95,16 +95,41 @@ function yazicd() { local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" yazi "$@" --cwd-file="$tmp" if cwd="$(command cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then - builtin cd -- "$cwd" && eza -a --icons --group-directories-first + z -- "$cwd" && eza -a --icons --group-directories-first fi rm -f -- "$tmp" >/dev/null 2>&1 } -tmux-window-name() { + +function tmux-window-name() { ($TMUX_PLUGIN_MANAGER_PATH/tmux-window-name/scripts/rename_session_windows.py &) } -# add-zsh-hook chpwd tmux-window-name +function fzf_sesh_connect_widget() { + local session + session=$( + sesh list --icons | fzf-tmux -p 80%,70% \ + --no-sort --ansi \ + --border-label ' sesh ' \ + --prompt '⚡ ' \ + --header ' ^a all ^t tmux ^g configs ^x zoxide ^d tmux kill ^f find' \ + --bind 'tab:down,btab:up' \ + --bind 'ctrl-a:change-prompt(⚡ )+reload(sesh list --icons)' \ + --bind 'ctrl-t:change-prompt(🪟 )+reload(sesh list -t --icons)' \ + --bind 'ctrl-g:change-prompt(⚙️ )+reload(sesh list -c --icons)' \ + --bind 'ctrl-x:change-prompt(📁 )+reload(sesh list -z --icons)' \ + --bind 'ctrl-f:change-prompt(🔎 )+reload(fd -H -d 2 -t d -E .Trash . ~)' \ + --bind 'ctrl-d:execute(tmux kill-session -t {2..})+change-prompt(⚡ )+reload(sesh list --icons)' \ + --preview-window 'right:55%' \ + --preview 'sesh preview {}' + ) + # if the user picked something, build & run the command + if [[ -n $session ]]; then + BUFFER="sesh connect \"$session\"" + zle accept-line + fi +} +zle -N fzf_sesh_connect_widget # Navigate words with CTRL+ARROW keys bindkey '^H' backward-kill-word # delete previous word with CTRL+BACKSPACE @@ -138,8 +163,8 @@ bindkey -M vicmd '^e' edit-command-line bindkey -M visual '^[[P' vi-delete bindkey -s '^n' '^uv .\n' -bindkey -s '^f' '^utmux neww tmux-sessionizer\n' - +# bindkey -s '^f' '^utmux neww tmux-sessionizer\n' +bindkey '^F' fzf_sesh_connect_widget eval "$(starship init zsh)" eval "$(fzf --zsh)" diff --git a/local/bin/tmux-sessionizer b/local/bin/tmux-sessionizer index b4ab04c9..6157926e 100755 --- a/local/bin/tmux-sessionizer +++ b/local/bin/tmux-sessionizer @@ -1,37 +1,32 @@ #!/bin/bash if [[ $# -eq 1 ]]; then - selected=$1 + selected="$1" else selected=$(project-finder ~/repos/ ~/Nextcloud/ ~/Obsidian/ | sk --height 16) fi -if [[ -z $selected ]]; then +if [[ -z "$selected" ]]; then exit 0 fi selected_name=$(basename "$selected" | tr . _) -tmux_running=$(pgrep tmux) - -if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then - # Create new session with nvim in first window, detached - tmux new-session -ds "$selected_name" -c "$selected" "${EDITOR:-vim} ." - # Create second window as plain terminal - tmux new-window -t "$selected_name:" -c "$selected" - # Select the first window (index 0) - tmux select-window -t "$selected_name:1" - # Attach to the session - tmux attach-session -t "$selected_name" - exit 0 -fi +# Check if the session exists if ! tmux has-session -t="$selected_name" 2>/dev/null; then - # Create new session with nvim in first window, detached - tmux new-session -ds "$selected_name" -c "$selected" "${EDITOR:-vim} ." - # Create second window as plain terminal + # Create a new session, detached, with window 0 in the selected directory + tmux new-session -d -s "$selected_name" -c "$selected" + # Create a second window (index 1) in the same directory tmux new-window -t "$selected_name:" -c "$selected" - # Select the first window (index 0) - tmux select-window -t "$selected_name:1" fi -tmux switch-client -t "$selected_name" +# Always select window 0 +tmux select-window -t "$selected_name:1" + +if [[ -z "$TMUX" ]]; then + # Not inside tmux, attach to the session + tmux attach-session -t "$selected_name" +else + # Inside tmux, switch client to the session + tmux switch-client -t "$selected_name" +fi