diff --git a/.dotter/global.toml b/.dotter/global.toml
index 307169ad..f8a4688e 100644
--- a/.dotter/global.toml
+++ b/.dotter/global.toml
@@ -66,6 +66,7 @@ depends = [ "torrent", "zathura" ]
"config/fastfetch/" = "~/.config/fastfetch/"
"config/flameshot.ini" = "~/.config/flameshot/flameshot.ini"
"config/gitui/" = "~/.config/gitui/"
+"config/git/" = "~/.config/git/"
"config/mpv/" = "~/.config/mpv/"
"config/lf/" = "~/.config/lf/"
"config/paru.conf" = "~/.config/paru/paru.conf"
@@ -128,6 +129,8 @@ depends = [ "zsh", "tmux" ]
"config/alacritty/" = "~/.config/alacritty/"
"config/alacritty/alacritty.toml" = {target = "~/.config/alacritty/alacritty.toml", type = "template"}
"config/starship.toml" = "~/.config/starship/starship.toml"
+"config/ghostty/" = "~/.config/ghostty/"
+"config/ghostty/config" = {target = "~/.config/ghostty/config", type = "template"}
[tmux.files]
"config/tmux/" = "~/.config/tmux/"
diff --git a/config/HybridBar/scripts/change-active-workspace b/config/HybridBar/scripts/change-active-workspace
old mode 100755
new mode 100644
diff --git a/config/HybridBar/scripts/get-active-workspace b/config/HybridBar/scripts/get-active-workspace
old mode 100755
new mode 100644
diff --git a/config/HybridBar/scripts/get-window-title b/config/HybridBar/scripts/get-window-title
old mode 100755
new mode 100644
diff --git a/config/HybridBar/scripts/get-workspaces b/config/HybridBar/scripts/get-workspaces
old mode 100755
new mode 100644
diff --git a/config/awesome/rc.lua b/config/awesome/rc.lua
index 179f34a6..e748c589 100644
--- a/config/awesome/rc.lua
+++ b/config/awesome/rc.lua
@@ -435,7 +435,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("zen-browser")
end, { description = "open browser", group = "launcher" }),
awful.key({ modkey }, "n", function()
awful.spawn("alacritty -e yazi")
diff --git a/config/btop/btop.conf b/config/btop/btop.conf
index 6a728033..82a46b55 100644
--- a/config/btop/btop.conf
+++ b/config/btop/btop.conf
@@ -202,7 +202,7 @@ net_download = 100
net_upload = 100
#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest.
-net_auto = False
+net_auto = True
#* Sync the auto scaling for download and upload to whichever currently has the highest scale.
net_sync = False
diff --git a/config/dunst/dunstrc.d/50-theme.conf b/config/dunst/dunstrc.d/50-theme.conf
index 08f14c76..d66a95d5 100644
--- a/config/dunst/dunstrc.d/50-theme.conf
+++ b/config/dunst/dunstrc.d/50-theme.conf
@@ -20,21 +20,21 @@
foreground = "#e0def4"
[urgency_low]
- background = "#26273d"
- highlight = "#31748f"
- frame_color = "#31748f"
+ background = "#26233a"
+ highlight = "#9ccfd8"
+ frame_color = "#9ccfd8"
default_icon = "dialog-information"
- format = "%s\n%b"
+ format = "%s\n%b"
[urgency_normal]
- background = "#362e3c"
- highlight = "#f6c177"
- frame_color = "#f6c177"
+ background = "#26233a"
+ highlight = "#ebbcba"
+ frame_color = "#ebbcba"
default_icon = "dialog-warning"
- format = "%s\n%b"
+ format = "%s\n%b"
[urgency_critical]
- background = "#35263d"
+ background = "#26233a"
highlight = "#eb6f92"
frame_color = "#eb6f92"
default_icon = "dialog-error"
diff --git a/config/eww.bak/eww.yuck b/config/eww.bak/eww.yuck
index 55001ef3..8debe384 100644
--- a/config/eww.bak/eww.yuck
+++ b/config/eww.bak/eww.yuck
@@ -224,7 +224,7 @@
:height "10px"
:anchor "top center")
:reserve (struts :side "top" :distance "4%")
-(bar))
+ (bar))
(defwidget bright []
(eventbox :onhover "eww update br_reveal=true" :onhoverlost "eww update br_reveal=false"
diff --git a/config/eww.bak/scripts/change-active-workspace b/config/eww.bak/scripts/change-active-workspace
deleted file mode 100755
index 3a43646e..00000000
--- a/config/eww.bak/scripts/change-active-workspace
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-function clamp {
- min=$1
- max=$2
- val=$3
- python -c "print(max($min, min($val, $max)))"
-}
-
-direction=$1
-current=$2
-if test "$direction" = "down"
-then
- target=$(clamp 1 10 $(($current+1)))
- echo "jumping to $target"
- hyprctl dispatch workspace $target
-elif test "$direction" = "up"
-then
- target=$(clamp 1 10 $(($current-1)))
- echo "jumping to $target"
- hyprctl dispatch workspace $target
-fi
diff --git a/config/eww.bak/scripts/get-active-workspace b/config/eww.bak/scripts/get-active-workspace
deleted file mode 100755
index c80f7f00..00000000
--- a/config/eww.bak/scripts/get-active-workspace
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-hyprctl monitors -j | jq '.[] | select(.focused) | .activeWorkspace.id'
-
-socat -u UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - |
- stdbuf -o0 awk -F '>>|,' -e '/^workspace>>/ {print $2}' -e '/^focusedmon>>/ {print $3}'
diff --git a/config/eww.bak/scripts/get-music b/config/eww.bak/scripts/get-music
deleted file mode 100755
index 2a57d4c6..00000000
--- a/config/eww.bak/scripts/get-music
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-title="$(sp metadata | rg title| cut -d'|' -f2)"
-artist="$(sp metadata | rg artist | cut -d'|' -f2)"
-echo "$artist" - "$title"
diff --git a/config/eww.bak/scripts/get-network b/config/eww.bak/scripts/get-network
deleted file mode 100755
index 8d9ece1a..00000000
--- a/config/eww.bak/scripts/get-network
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-line=$(nmcli connection show | rg wlan0)
-echo $line
-
diff --git a/config/eww.bak/scripts/get-window-title b/config/eww.bak/scripts/get-window-title
deleted file mode 100755
index f246c712..00000000
--- a/config/eww.bak/scripts/get-window-title
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-hyprctl activewindow -j | jq --raw-output .title
-socat -u UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | stdbuf -o0 awk -F '>>|,' '/^activewindow>>/{print $3}'
diff --git a/config/eww.bak/scripts/get-workspaces b/config/eww.bak/scripts/get-workspaces
deleted file mode 100755
index 14911c95..00000000
--- a/config/eww.bak/scripts/get-workspaces
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-
-spaces (){
- WORKSPACE_WINDOWS=$(hyprctl workspaces -j | jq 'map({key: .id | tostring, value: .windows}) | from_entries')
- seq 1 10 | jq --argjson windows "${WORKSPACE_WINDOWS}" --slurp -Mc 'map(tostring) | map({id: ., windows: ($windows[.]//0)})'
-}
-
-spaces
-socat -u UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | while read -r line; do
- spaces
-done
diff --git a/config/eww.bak/scripts/getvol b/config/eww.bak/scripts/getvol
deleted file mode 100755
index 4e4275d8..00000000
--- a/config/eww.bak/scripts/getvol
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-if command -v pamixer &>/dev/null; then
- if [ true == $(pamixer --get-mute) ]; then
- echo 0
- exit
- else
- pamixer --get-volume
- fi
-else
- amixer -D pulse sget Master | awk -F '[^0-9]+' '/Left:/{print $3}'
-fi
diff --git a/config/eww.bak/scripts/github b/config/eww.bak/scripts/github
deleted file mode 100755
index 17682bf0..00000000
--- a/config/eww.bak/scripts/github
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-notifications="$(gh api notifications 2> /dev/null | jq '. | length')"
-[ -z notifications ] && echo "" || echo "$notifications"
diff --git a/config/eww/eww.scss b/config/eww/eww.scss
index 36f18843..ca8fc2e4 100644
--- a/config/eww/eww.scss
+++ b/config/eww/eww.scss
@@ -18,7 +18,7 @@ $bg: rgba(25, 23, 37, 0.7);
* {
all: unset;
font-family: "JetBrainsMono NF";
- font-size: 14;
+ font-size: 20;
}
/** General **/
@@ -128,6 +128,10 @@ clock_time {
&__Charging {
color: $gold;
}
+
+ &__low {
+ color: $love;
+ }
}
.iconbat,
@@ -275,6 +279,10 @@ calendar:indeterminate {
.sys_icon_mem {
font-size: 30;
margin: 30px;
+
+ &__low {
+ color: $love;
+ }
}
.sys_win {
diff --git a/config/eww/eww.yuck b/config/eww/eww.yuck
index 9f2d3d74..ec58833c 100644
--- a/config/eww/eww.yuck
+++ b/config/eww/eww.yuck
@@ -1,5 +1,5 @@
;; Variables
-(defpoll clock_hour :interval "5m" "date +%H")
+(defpoll clock_hour :interval "1m" "date +%H")
(defpoll clock_minute :interval "2s" "date +%M")
(defpoll clock_second :interval "1s" "date +%S")
(defpoll clock_date :interval "10h" "date +%d.%m.%Y")
@@ -7,34 +7,32 @@
(defpoll volume_percent :interval "3s" "amixer -D pulse sget Master | grep 'Left:' | awk -F'[][]' '{ print $2 }' | tr -d '%'")
(defpoll mic_percent :interval "3s" "amixer -D pulse sget Capture | grep 'Left:' | awk -F'[][]' '{ print $2 }' | tr -d '%'")
(defpoll brightness_percent :interval "5s" "brightnessctl -m -d intel_backlight | awk -F, '{print substr($4, 0, length($4)-1)}' | tr -d '%'")
-(defpoll battery :interval "15s" "./scripts/battery --bat")
-(defpoll battery_status :interval "1m" "./scripts/battery --bat-st")
-(defpoll memory :interval "15s" "scripts/memory")
-(defpoll memory_used_mb :interval "2m" "scripts/mem-ad used")
-(defpoll memory_total_mb :interval "2m" "scripts/mem-ad total")
-(defpoll memory_free_mb :interval "2m" "scripts/mem-ad free")
+(defpoll memory :interval "10s" "scripts/memory")
+(defpoll memory_used_mb :interval "1m" "scripts/mem-ad used")
+(defpoll memory_total_mb :interval "1m" "scripts/mem-ad total")
+(defpoll memory_free_mb :interval "1m" "scripts/mem-ad free")
(defvar vol_reveal false)
(defvar br_reveal false)
(defvar music_reveal false)
(defvar wifi_rev false)
(defvar time_rev false)
-(deflisten workspaces :initial "[]" "bash ~/.config/eww/scripts/get-workspaces")
+(deflisten workspaces :initial "[]" "bash ~/.config/eww/scripts/workspace")
(deflisten current_workspace :initial "1" "bash ~/.config/eww/scripts/get-active-workspace")
(deflisten window :initial "..." "bash ~/.config/eww/scripts/get-window-title")
(defvar eww "eww")
-(defpoll COL_WLAN :interval "1m" "~/.config/eww/bar/scripts/wifi --COL")
-(defpoll ESSID_WLAN :interval "1m" "~/.config/eww/bar/scripts/wifi --ESSID")
-(defpoll WLAN_ICON :interval "1m" "~/.config/eww/bar/scripts/wifi --ICON")
+(defpoll COL_WLAN :interval "1m" "~/.config/eww/scripts/wifi --COL")
+(defpoll ESSID_WLAN :interval "1m" "~/.config/eww/scripts/wifi --ESSID")
+(defpoll WLAN_ICON :interval "1m" "~/.config/eww/scripts/wifi --ICON")
-(defpoll song :interval "2s" "~/.config/eww/bar/scripts/music_info --song")
-(defpoll song_artist :interval "2s" "~/.config/eww/bar/scripts/music_info --artist")
-(defpoll current_status :interval "1s" "~/.config/eww/bar/scripts/music_info --time")
-(defpoll song_status :interval "2s" "~/.config/eww/bar/scripts/music_info --status")
-(defpoll cover_art :interval "2s" "~/.config/eww/bar/scripts/music_info --cover")
+(defpoll song :interval "2s" "~/.config/eww/scripts/music_info --song")
+(defpoll song_artist :interval "2s" "~/.config/eww/scripts/music_info --artist")
+(defpoll current_status :interval "1s" "~/.config/eww/scripts/music_info --time")
+(defpoll song_status :interval "2s" "~/.config/eww/scripts/music_info --status")
+(defpoll cover_art :interval "2s" "~/.config/eww/scripts/music_info --cover")
(defpoll calendar_day :interval "20h" "date '+%d'")
(defpoll calendar_year :interval "20h" "date '+%Y'")
@@ -42,16 +40,21 @@
;; widgets
(defwidget wifi []
- (eventbox :onhover "${eww} update wifi_rev=true"
+ (eventbox
+ :onhover "${eww} update wifi_rev=true"
:onhoverlost "${eww} update wifi_rev=false"
- (box :vexpand "false" :hexpand "false" :space-evenly "false"
+ (box
+ :vexpand "false"
+ :hexpand "false"
+ :space-evenly "false"
(button
- :class "module-wif"
+ :class "module-wifi"
:onclick "networkmanager_dmenu"
:wrap "false"
:limit-width 12
:style "color: ${COL_WLAN};" WLAN_ICON)
- (revealer :transition "slideright"
+ (revealer
+ :transition "slideright"
:reveal wifi_rev
:duration "350ms"
(label
@@ -62,7 +65,9 @@
(defwidget workspaces []
- (eventbox :onscroll "bash ~/.config/eww/scripts/change-active-workspace {} ${current_workspace}" :class "workspaces"
+ (eventbox
+ :onscroll "bash ~/.config/eww/scripts/change-active-workspace {} ${current_workspace}"
+ :class "workspaces"
(box :space-evenly true
:halign "start"
:space-evenly true
@@ -74,25 +79,25 @@
(eventbox :onclick "hyprctl dispatch workspace ${workspace.id}"
(box :class "workspace-entry ${workspace.windows > 0 ? "occupied" : "empty"}"
(label :text "${workspace.id}" :class "workspace-entry ${workspace.id == current_workspace ? "current" : ""}" )
- )
- )
- )
- )
- )
- )
+ ))))))
(defwidget bat []
- (box :class "bat_module" :vexpand "false" :hexpand "false"
- (circular-progress :value battery
+ (button
+ :class "bat_module"
+ :vexpand "false"
+ :hexpand "false"
+ :onclick "bash ~/.config/eww/scripts/pop system"
+ (circular-progress
+ :value "${EWW_BATTERY.BAT0.capacity}"
:class "batbar"
:thickness 4
- (button
- :class "iconbat iconbat__${battery_status}"
+ (box
+ :class "iconbat iconbat__${EWW_BATTERY.BAT0.status} ${EWW_BATTERY.BAT0.capacity < 20 ? "iconbat__low" : ""}"
+ :interval "5m"
:limit-width 2
- :tooltip "battery on ${battery}%"
+ :tooltip "Battery on ${EWW_BATTERY.BAT0.capacity}%"
:show_truncated false
- :onclick "$HOME/.config/eww/bar/scripts/pop system"
:wrap false
"${EWW_BATTERY.BAT0.status == "Charging" ? "" :
EWW_BATTERY.BAT0.capacity > 90 ? "" :
@@ -104,15 +109,19 @@
(defwidget mem []
- (box :class "mem_module" :vexpand "false" :hexpand "false"
- (circular-progress :value memory
+ (button
+ :class "mem_module"
+ :vexpand "false"
+ :hexpand "false"
+ :onclick "bash ~/.config/eww/scripts/pop system"
+ (circular-progress
+ :value memory
:class "membar"
:thickness 4
- (button
+ (box
:class "iconmem"
:limit-width 2
- :tooltip "using ${memory}% ram"
- :onclick "$HOME/.config/eww/bar/scripts/pop system"
+ :tooltip "Using ${memory}% ram"
:show_truncated false
:wrap false
""))))
@@ -132,7 +141,7 @@
:reveal time_rev
:duration "350ms"
(button :class "clock_date"
- :onclick "$HOME/.config/eww/bar/scripts/pop calendar" "${clock_date}, ${clock_day}"
+ :onclick "bash ~/.config/eww/scripts/pop calendar" "${clock_date}, ${clock_day}"
)
))))
@@ -144,7 +153,8 @@
(revealer :transition "slideleft"
:reveal vol_reveal
:duration "350ms"
- (scale :class "volbar"
+ (scale
+ :class "volbar"
:value volume_percent
:orientation "h"
:tooltip "${volume_percent}%"
@@ -153,13 +163,24 @@
:onchange "amixer -D pulse sset Master {}%" )))))
(defwidget bright []
- (eventbox :onhover "${eww} update br_reveal=true" :onhoverlost "${eww} update br_reveal=false"
- (box :class "module-2" :space-evenly "false" :orientation "h" :spacing "3"
- (label :text "☼" :class "bright_icon" :tooltip "brightness")
- (revealer :transition "slideleft"
+ (eventbox
+ :onhover "${eww} update br_reveal=true"
+ :onhoverlost "${eww} update br_reveal=false"
+ (box
+ :class "module-2"
+ :space-evenly "false"
+ :orientation "h"
+ :spacing "3"
+ (label
+ :text "☼"
+ :class "bright_icon"
+ :tooltip "brightness")
+ (revealer
+ :transition "slideleft"
:reveal br_reveal
:duration "350ms"
- (scale :class "brightbar"
+ (scale
+ :class "brightbar"
:value brightness_percent
:orientation "h"
:tooltip "${brightness_percent}%"
@@ -171,18 +192,35 @@
;; Music
(defwidget music []
- (eventbox :onhover "${eww} update music_reveal=true"
+ (eventbox
+ :onhover "${eww} update music_reveal=true"
:onhoverlost "${eww} update music_reveal=false"
- (box :class "module-2" :orientation "h" :space-evenly "false" :vexpand "false" :hexpand "false"
- (box :class "song_cover_art" :vexpand "false" :hexpand "false" :style "background-image: url('${cover_art}');")
- (button :class "song" :wrap "true" :onclick "~/.config/eww/bar/scripts/pop music" song)
- (revealer :transition "slideright"
+ (box
+ :class "module-2"
+ :orientation "h"
+ :space-evenly "false"
+ :vexpand "false"
+ :hexpand "false"
+ (box
+ :class "song_cover_art"
+ :vexpand "false"
+ :hexpand "false"
+ :style "background-image: url('${cover_art}');")
+ (button
+ :class "song"
+ :wrap "true"
+ :onclick "~/.config/eww/scripts/pop music" song)
+ (revealer
+ :transition "slideright"
:reveal music_reveal
:duration "350ms"
- (box :vexpand "false" :hexpand "false" :oreintation "h"
- (button :class "song_btn_prev" :onclick "~/.config/eww/bar/scripts/music_info --prev" "")
- (button :class "song_btn_play" :onclick "~/.config/eww/bar/scripts/music_info --toggle" song_status)
- (button :class "song_btn_next" :onclick "~/.config/eww/bar/scripts/music_info --next" ""))))))
+ (box
+ :vexpand "false"
+ :hexpand "false"
+ :oreintation "h"
+ (button :class "song_btn_prev" :onclick "~/.config/eww/scripts/music_info --prev" "")
+ (button :class "song_btn_play" :onclick "~/.config/eww/scripts/music_info --toggle" song_status)
+ (button :class "song_btn_next" :onclick "~/.config/eww/scripts/music_info --next" ""))))))
@@ -203,7 +241,8 @@
(defwidget right []
- (box :orientation "h"
+ (box
+ :orientation "h"
:space-evenly false
:halign "start"
:class "right_modules"
@@ -211,14 +250,16 @@
(defwidget center []
- (box :orientation "h"
+ (box
+ :orientation "h"
:space-evenly false
:halign "center"
:class "center_modules"
(window)))
(defwidget bar_1 []
- (box :class "bar"
+ (box
+ :class "bar"
:orientation "h"
(right)
(center)
@@ -239,61 +280,117 @@
:windowtype "dock"
(bar_1))
+(defwindow bar-1
+ :monitor 1
+ :exclusive true
+ :geometry (geometry
+ :x "0%"
+ :y "0%"
+ :width "100%"
+ :height "10px"
+ :anchor "top center")
+ :reserve (struts :side "top" :distance "4%")
+ :stacking "fg"
+ :windowtype "dock"
+ (bar_1))
+
(defwidget system []
- (box :class "sys_win" :orientation "v" :space-evenly "false" :hexpand "false" :vexpand "false" :spacing 0
- (box :class "sys_bat_box" :orientation "h" :space-evenly "false"
- (circular-progress :value battery
+ (box
+ :class "sys_win"
+ :orientation "v"
+ :space-evenly "false"
+ :hexpand "false"
+ :vexpand "false"
+ :spacing 0
+ (box
+ :class "sys_bat_box"
+ :orientation "h"
+ :space-evenly "false"
+ (circular-progress
+ :value "${EWW_BATTERY.BAT0.capacity}"
:class "sys_bat"
:thickness 9
- (label :text ""
- :class "sys_icon_bat"
+ (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 ? "" :
+ ""}"
+ :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
:show_truncated false
:wrap false))
- (box :orientation "v" :space-evenly "false" :spacing 0 :hexpand "false" :vexpand "false"
- (label :text "battery"
+ (box
+ :orientation "v"
+ :space-evenly "false"
+ :spacing 0
+ :hexpand "false"
+ :vexpand "false"
+ (label
+ :text "Battery"
:halign "start"
:class "sys_text_bat"
:limit-width 9
:show_truncated false
:wrap false)
- (label :text "${battery}%"
+ (label
+ :text "${EWW_BATTERY.BAT0.capacity}%"
:halign "start"
:class "sys_text_bat_sub"
:limit-width 22
:show_truncated false
:wrap false)
- (label :text "${battery_status}"
+ (label
+ :text "${EWW_BATTERY.BAT0.status}"
:halign "start"
:class "sys_text_bat_sub"
:limit-width 22
:show_truncated false
:wrap false)))
- (label :text "" :class "sys_sep" :halign "center")
- (box :class "sys_mem_box" :orientation "h" :space-evenly "false" :halign "start"
- (circular-progress :value memory
+ (label
+ :text ""
+ :class "sys_sep"
+ :halign "center")
+ (box
+ :class "sys_mem_box"
+ :orientation "h"
+ :space-evenly "false"
+ :halign "start"
+ (circular-progress
+ :value memory
:class "sys_mem"
:thickness 9
- (label :text ""
+ (label
+ :text ""
:class "sys_icon_mem"
:limit-width 2
:show_truncated false
:wrap false
:angle 0.0))
- (box :orientation "v" :space-evenly "false" :spacing 0 :hexpand "false" :vexpand "false"
- (label :text "memory"
+ (box
+ :orientation "v"
+ :space-evenly "false"
+ :spacing 0
+ :hexpand "false"
+ :vexpand "false"
+ (label
+ :text "Memory"
:halign "start"
:class "sys_text_mem"
:limit-width 9
:show_truncated false
:wrap false)
- (label :text "${memory_used_mb} | ${memory_total_mb}mb "
+ (label
+ :text "${memory_used_mb}/${memory_total_mb}mb"
:halign "start"
:class "sys_text_mem_sub"
:limit-width 22
:show_truncated false
:wrap false)
- (label :text "${memory_free_mb}mb free"
+ (label
+ :text "${memory_free_mb}mb free"
:halign "start"
:class "sys_text_mem_sub"
:limit-width 22
@@ -301,16 +398,21 @@
:wrap false)))))
(defwidget cal []
- (box :class "cal" :orientation "v"
- (box :class "cal-in"
- (calendar :class "cal"
+ (box
+ :class "cal"
+ :orientation "v"
+ (box
+ :class "cal-in"
+ (calendar
+ :class "cal"
:day calendar_day
:year calendar_year))))
(defwindow calendar
:monitor 0
- :geometry (geometry :x "-20px"
- :y "7%"
+ :geometry (geometry
+ :x "0px"
+ :y "10px"
:anchor "top right"
:width "270px"
:height "60px")
@@ -332,13 +434,35 @@
:tooltip "volume on ${volume_percent}%"
:max 100
:min 0))))
- (label :text "" :class "audio_sep" :halign "center")
- (box :halign "v" :space-evenly "false" :hexpand "false" :vexpand "false"
- (box :class "mic_icon" :orientation "v")
- (box :orientation "v" :halign "center" :vexpand "false" :hexpand "false"
- (label :class "mic_text" :text "mic" :valign "center" :halign "left" )
- (box :class "mic_bar" :halign "center" :vexpand "false" :hexpand "false"
- (scale :value mic_percent
+ (label
+ :text ""
+ :class "audio_sep"
+ :halign "center")
+ (box
+ :halign "v"
+ :space-evenly "false"
+ :hexpand "false"
+ :vexpand "false"
+ (box
+ :class "mic_icon"
+ :orientation "v")
+ (box
+ :orientation "v"
+ :halign "center"
+ :vexpand "false"
+ :hexpand "false"
+ (label
+ :class "mic_text"
+ :text "mic"
+ :valign "center"
+ :halign "left" )
+ (box
+ :class "mic_bar"
+ :halign "center"
+ :vexpand "false"
+ :hexpand "false"
+ (scale
+ :value mic_percent
:space-evenly "false"
:orientation "h"
:tooltip "mic on ${mic_percent}%"
@@ -348,8 +472,9 @@
(defwindow audio_ctl
:monitor 0
- :geometry (geometry :x "-20px"
- :y "7%"
+ :geometry (geometry
+ :x "10px"
+ :y "10px"
:anchor "top right"
:width "280px"
:height "60px")
@@ -359,8 +484,8 @@
(defwindow system
:monitor 0
:geometry (geometry
- :x "-20px"
- :y "5%"
+ :x "10px"
+ :y "10px"
:anchor "top right"
:width "290px"
:height "120px")
@@ -370,26 +495,71 @@
;; Music
(defwidget music_pop []
- (box :class "music_pop" :orientation "h" :space-evenly "false" :vexpand "false" :hexpand "false"
- (box :class "music_cover_art" :vexpand "false" :hexpand "false" :style "background-image: url('${cover_art}');")
- (box :orientation "v" :spacing 20 :space-evenly "false" :vexpand "false" :hexpand "false"
- (label :halign "center" :class "music" :wrap "true" :limit-width 13 :text song)
- (label :halign "center" :class "music_artist" :wrap "true" :limit-width 15 :text song_artist)
- (box :orientation "h" :spacing 15 :halign "center" :space-evenly "false" :vexpand "false" :hexpand "false"
- (button :class "music_btn_prev" :onclick "~/.config/eww/bar/scripts/music_info --prev" "")
- (button :class "music_btn_play" :onclick "~/.config/eww/bar/scripts/music_info --toggle" song_status)
- (button :class "music_btn_next" :onclick "~/.config/eww/bar/scripts/music_info --next" ""))
- (box :class "music_bar" :halign "center" :vexpand "false" :hexpand "false" :space-evenly "false"
- (scale :onscroll "mpc -q seek {}" :min 0 :active "true" :max 100 :value current_status)))))
+ (box
+ :class "music_pop"
+ :orientation "h"
+ :space-evenly "false"
+ :vexpand "false"
+ :hexpand "false"
+ (box
+ :class "music_cover_art"
+ :vexpand "false"
+ :hexpand "false"
+ :style "background-image: url('${cover_art}');")
+ (box
+ :orientation "v"
+ :spacing 20
+ :space-evenly "false"
+ :vexpand "false"
+ :hexpand "false"
+ (label
+ :halign "center"
+ :class "music"
+ :wrap "true"
+ :limit-width 13
+ :text song)
+ (label
+ :halign "center"
+ :class "music_artist"
+ :wrap "true"
+ :limit-width 15
+ :text song_artist)
+ (box
+ :orientation "h"
+ :spacing 15
+ :halign "center"
+ :space-evenly "false"
+ :vexpand "false"
+ :hexpand "false"
+ (button :class "music_btn_prev" :onclick "~/.config/eww/scripts/music_info --prev" "")
+ (button :class "music_btn_play" :onclick "~/.config/eww/scripts/music_info --toggle" song_status)
+ (button :class "music_btn_next" :onclick "~/.config/eww/scripts/music_info --next" ""))
+ (box
+ :class "music_bar"
+ :halign "center"
+ :vexpand "false"
+ :hexpand "false"
+ :space-evenly "false"
+ (scale
+ :onscroll "mpc -q seek {}"
+ :min 0
+ :active "true"
+ :max 100
+ :value current_status)))))
;; music
(defwindow music_win
- ;; :monitor 0
+ :monitor 0
:stacking "fg"
:focusable "false"
:screen 1
- :geometry (geometry :x "0" :y "7%" :width 428 :height 104 :anchor "top center")
+ :geometry (geometry
+ :x "10px"
+ :y "10px"
+ :width 428
+ :height 104
+ :anchor "top center")
(music_pop))
(defwidget window []
diff --git a/config/eww/scripts/battery b/config/eww/scripts/battery
deleted file mode 100755
index 0540a1b1..00000000
--- a/config/eww/scripts/battery
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-
-battery() {
- BAT=`ls /sys/class/power_supply | grep BAT | head -n 1`
- cat /sys/class/power_supply/${BAT}/capacity
-}
-battery_stat() {
- BAT=`ls /sys/class/power_supply | grep BAT | head -n 1`
- cat /sys/class/power_supply/${BAT}/status
-}
-
-if [[ "$1" == "--bat" ]]; then
- battery
-elif [[ "$1" == "--bat-st" ]]; then
- battery_stat
-fi
-
diff --git a/config/eww/scripts/change-active-workspace b/config/eww/scripts/change-active-workspace
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/get-active-workspace b/config/eww/scripts/get-active-workspace
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/get-window-title b/config/eww/scripts/get-window-title
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/get-workspaces b/config/eww/scripts/get-workspaces
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/mem-ad b/config/eww/scripts/mem-ad
old mode 100755
new mode 100644
index 1e4cf89f..aba1cf1b
--- a/config/eww/scripts/mem-ad
+++ b/config/eww/scripts/mem-ad
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/usr/bin/env bash
total="$(free -m | grep Mem: | awk '{ print $2 }')"
used="$(free -m | grep Mem: | awk '{ print $3 }')"
diff --git a/config/eww/scripts/memory b/config/eww/scripts/memory
old mode 100755
new mode 100644
index 217c8344..4cd200f7
--- a/config/eww/scripts/memory
+++ b/config/eww/scripts/memory
@@ -1,3 +1,3 @@
-#!/bin/sh
+#!/usr/bin/env bash
-printf "%.0f\n" $(free -m | grep Mem | awk '{print ($3/$2)*100}')
+awk '/Mem:/ {printf "%.0f\n", ($3/$2)*100}' <(free -m)
diff --git a/config/eww/scripts/music_info b/config/eww/scripts/music_info
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/music_info.bak b/config/eww/scripts/music_info.bak
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/pop b/config/eww/scripts/pop
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/wifi b/config/eww/scripts/wifi
old mode 100755
new mode 100644
diff --git a/config/eww/scripts/workspace b/config/eww/scripts/workspace
old mode 100755
new mode 100644
diff --git a/config/ghostty/config b/config/ghostty/config
new file mode 100644
index 00000000..e3258598
--- /dev/null
+++ b/config/ghostty/config
@@ -0,0 +1,2253 @@
+# The font families to use.
+#
+# You can generate the list of valid values using the CLI:
+#
+# ghostty +list-fonts
+#
+# This configuration can be repeated multiple times to specify preferred
+# fallback fonts when the requested codepoint is not available in the primary
+# font. This is particularly useful for multiple languages, symbolic fonts,
+# etc.
+#
+# Notes on emoji specifically: On macOS, Ghostty by default will always use
+# Apple Color Emoji and on Linux will always use Noto Emoji. You can
+# override this behavior by specifying a font family here that contains
+# emoji glyphs.
+#
+# The specific styles (bold, italic, bold italic) do not need to be
+# explicitly set. If a style is not set, then the regular style (font-family)
+# will be searched for stylistic variants. If a stylistic variant is not
+# found, Ghostty will use the regular style. This prevents falling back to a
+# different font family just to get a style such as bold. This also applies
+# if you explicitly specify a font family for a style. For example, if you
+# set `font-family-bold = FooBar` and "FooBar" cannot be found, Ghostty will
+# use whatever font is set for `font-family` for the bold style.
+#
+# Finally, some styles may be synthesized if they are not supported.
+# For example, if a font does not have an italic style and no alternative
+# italic font is specified, Ghostty will synthesize an italic style by
+# applying a slant to the regular style. If you want to disable these
+# synthesized styles then you can use the `font-style` configurations
+# as documented below.
+#
+# You can disable styles completely by using the `font-style` set of
+# configurations. See the documentation for `font-style` for more information.
+#
+# If you want to overwrite a previous set value rather than append a fallback,
+# specify the value as `""` (empty string) to reset the list and then set the
+# new values. For example:
+#
+# font-family = ""
+# font-family = "My Favorite Font"
+#
+# Setting any of these as CLI arguments will automatically clear the
+# values set in configuration files so you don't need to specify
+# `--font-family=""` before setting a new value. You only need to specify
+# this within config files if you want to clear previously set values in
+# configuration files or on the CLI if you want to clear values set on the
+# CLI.
+#
+# Changing this configuration at runtime will only affect new terminals, i.e.
+# new windows, tabs, etc.
+font-family = "JetBrainsMono NF"
+
+# font-family-bold = "JetBrainsMono NF Bold"
+# font-family-italic = "JetBrainsMono NF Italic"
+# font-family-bold-italic = "JetBrainsMono NF Bold Italic"
+# The named font style to use for each of the requested terminal font styles.
+# This looks up the style based on the font style string advertised by the
+# font itself. For example, "Iosevka Heavy" has a style of "Heavy".
+#
+# You can also use these fields to completely disable a font style. If you set
+# the value of the configuration below to literal `false` then that font style
+# will be disabled. If the running program in the terminal requests a disabled
+# font style, the regular font style will be used instead.
+#
+# These are only valid if its corresponding font-family is also specified. If
+# no font-family is specified, then the font-style is ignored unless you're
+# disabling the font style.
+font-style = default
+
+font-style-bold = default
+font-style-italic = default
+font-style-bold-italic = default
+# Control whether Ghostty should synthesize a style if the requested style is
+# not available in the specified font-family.
+#
+# Ghostty can synthesize bold, italic, and bold italic styles if the font
+# does not have a specific style. For bold, this is done by drawing an
+# outline around the glyph of varying thickness. For italic, this is done by
+# applying a slant to the glyph. For bold italic, both of these are applied.
+#
+# Synthetic styles are not perfect and will generally not look as good
+# as a font that has the style natively. However, they are useful to
+# provide styled text when the font does not have the style.
+#
+# Set this to "false" or "true" to disable or enable synthetic styles
+# completely. You can disable specific styles using "no-bold", "no-italic",
+# and "no-bold-italic". You can disable multiple styles by separating them
+# with a comma. For example, "no-bold,no-italic".
+#
+# Available style keys are: `bold`, `italic`, `bold-italic`.
+#
+# If synthetic styles are disabled, then the regular style will be used
+# instead if the requested style is not available. If the font has the
+# requested style, then the font will be used as-is since the style is
+# not synthetic.
+#
+# Warning: An easy mistake is to disable `bold` or `italic` but not
+# `bold-italic`. Disabling only `bold` or `italic` will NOT disable either
+# in the `bold-italic` style. If you want to disable `bold-italic`, you must
+# explicitly disable it. You cannot partially disable `bold-italic`.
+#
+# By default, synthetic styles are enabled.
+font-synthetic-style = bold,italic,bold-italic
+
+# Apply a font feature. To enable multiple font features you can repeat
+# this multiple times or use a comma-separated list of feature settings.
+#
+# The syntax for feature settings is as follows, where `feat` is a feature:
+#
+# * Enable features with e.g. `feat`, `+feat`, `feat on`, `feat=1`.
+# * Disabled features with e.g. `-feat`, `feat off`, `feat=0`.
+# * Set a feature value with e.g. `feat=2`, `feat = 3`, `feat 4`.
+# * Feature names may be wrapped in quotes, meaning this config should be
+# syntactically compatible with the `font-feature-settings` CSS property.
+#
+# The syntax is fairly loose, but invalid settings will be silently ignored.
+#
+# The font feature will apply to all fonts rendered by Ghostty. A future
+# enhancement will allow targeting specific faces.
+#
+# To disable programming ligatures, use `-calt` since this is the typical
+# feature name for programming ligatures. To look into what font features
+# your font has and what they do, use a font inspection tool such as
+# [fontdrop.info](https://fontdrop.info).
+#
+# To generally disable most ligatures, use `-calt, -liga, -dlig`.
+font-feature = "-calt, -liga, -dlig"
+
+# Font size in points. This value can be a non-integer and the nearest integer
+# pixel size will be selected. If you have a high dpi display where 1pt = 2px
+# then you can get an odd numbered pixel size by specifying a half point.
+#
+# For example, 13.5pt @ 2px/pt = 27px
+#
+# Changing this configuration at runtime will only affect new terminals,
+# i.e. new windows, tabs, etc. Note that you may still not see the change
+# depending on your `window-inherit-font-size` setting. If that setting is
+# true, only the first window will be affected by this change since all
+# subsequent windows will inherit the font size of the previous window.
+#
+# On Linux with GTK, font size is scaled according to both display-wide and
+# text-specific scaling factors, which are often managed by your desktop
+# environment (e.g. the GNOME display scale and large text settings).
+font-size = {{font_size}}
+
+# A repeatable configuration to set one or more font variations values for
+# a variable font. A variable font is a single font, usually with a filename
+# ending in `-VF.ttf` or `-VF.otf` that contains one or more configurable axes
+# for things such as weight, slant, etc. Not all fonts support variations;
+# only fonts that explicitly state they are variable fonts will work.
+#
+# The format of this is `id=value` where `id` is the axis identifier. An axis
+# identifier is always a 4 character string, such as `wght`. To get the list
+# of supported axes, look at your font documentation or use a font inspection
+# tool.
+#
+# Invalid ids and values are usually ignored. For example, if a font only
+# supports weights from 100 to 700, setting `wght=800` will do nothing (it
+# will not be clamped to 700). You must consult your font's documentation to
+# see what values are supported.
+#
+# Common axes are: `wght` (weight), `slnt` (slant), `ital` (italic), `opsz`
+# (optical size), `wdth` (width), `GRAD` (gradient), etc.
+font-variation =
+
+font-variation-bold =
+font-variation-italic =
+font-variation-bold-italic =
+# Force one or a range of Unicode codepoints to map to a specific named font.
+# This is useful if you want to support special symbols or if you want to use
+# specific glyphs that render better for your specific font.
+#
+# The syntax is `codepoint=fontname` where `codepoint` is either a single
+# codepoint or a range. Codepoints must be specified as full Unicode
+# hex values, such as `U+ABCD`. Codepoints ranges are specified as
+# `U+ABCD-U+DEFG`. You can specify multiple ranges for the same font separated
+# by commas, such as `U+ABCD-U+DEFG,U+1234-U+5678=fontname`. The font name is
+# the same value as you would use for `font-family`.
+#
+# This configuration can be repeated multiple times to specify multiple
+# codepoint mappings.
+#
+# Changing this configuration at runtime will only affect new terminals,
+# i.e. new windows, tabs, etc.
+font-codepoint-map =
+
+# Draw fonts with a thicker stroke, if supported.
+# This is currently only supported on macOS.
+font-thicken = false
+
+# Strength of thickening when `font-thicken` is enabled.
+#
+# Valid values are integers between `0` and `255`. `0` does not correspond to
+# *no* thickening, rather it corresponds to the lightest available thickening.
+#
+# Has no effect when `font-thicken` is set to `false`.
+#
+# This is currently only supported on macOS.
+font-thicken-strength = 255
+
+# What color space to use when performing alpha blending.
+#
+# This affects the appearance of text and of any images with transparency.
+# Additionally, custom shaders will receive colors in the configured space.
+#
+# Valid values:
+#
+# * `native` - Perform alpha blending in the native color space for the OS.
+# On macOS this corresponds to Display P3, and on Linux it's sRGB.
+#
+# * `linear` - Perform alpha blending in linear space. This will eliminate
+# the darkening artifacts around the edges of text that are very visible
+# when certain color combinations are used (e.g. red / green), but makes
+# dark text look much thinner than normal and light text much thicker.
+# This is also sometimes known as "gamma correction".
+# (Currently only supported on macOS. Has no effect on Linux.)
+#
+# * `linear-corrected` - Same as `linear`, but with a correction step applied
+# for text that makes it look nearly or completely identical to `native`,
+# but without any of the darkening artifacts.
+alpha-blending = native
+
+# All of the configurations behavior adjust various metrics determined by the
+# font. The values can be integers (1, -1, etc.) or a percentage (20%, -15%,
+# etc.). In each case, the values represent the amount to change the original
+# value.
+#
+# For example, a value of `1` increases the value by 1; it does not set it to
+# literally 1. A value of `20%` increases the value by 20%. And so on.
+#
+# There is little to no validation on these values so the wrong values (e.g.
+# `-100%`) can cause the terminal to be unusable. Use with caution and reason.
+#
+# Some values are clamped to minimum or maximum values. This can make it
+# appear that certain values are ignored. For example, many `*-thickness`
+# adjustments cannot go below 1px.
+#
+# `adjust-cell-height` has some additional behaviors to describe:
+#
+# * The font will be centered vertically in the cell.
+#
+# * The cursor will remain the same size as the font, but may be
+# adjusted separately with `adjust-cursor-height`.
+#
+# * Powerline glyphs will be adjusted along with the cell height so
+# that things like status lines continue to look aligned.
+adjust-cell-width =
+
+adjust-cell-height =
+# Distance in pixels or percentage adjustment from the bottom of the cell to the text baseline.
+# Increase to move baseline UP, decrease to move baseline DOWN.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-font-baseline =
+
+# Distance in pixels or percentage adjustment from the top of the cell to the top of the underline.
+# Increase to move underline DOWN, decrease to move underline UP.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-underline-position =
+
+# Thickness in pixels of the underline.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-underline-thickness =
+
+# Distance in pixels or percentage adjustment from the top of the cell to the top of the strikethrough.
+# Increase to move strikethrough DOWN, decrease to move underline UP.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-strikethrough-position =
+
+# Thickness in pixels or percentage adjustment of the strikethrough.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-strikethrough-thickness =
+
+# Distance in pixels or percentage adjustment from the top of the cell to the top of the overline.
+# Increase to move overline DOWN, decrease to move underline UP.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-overline-position =
+
+# Thickness in pixels or percentage adjustment of the overline.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-overline-thickness =
+
+# Thickness in pixels or percentage adjustment of the bar cursor and outlined rect cursor.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-cursor-thickness =
+
+# Height in pixels or percentage adjustment of the cursor. Currently applies to all cursor types:
+# bar, rect, and outlined rect.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-cursor-height =
+
+# Thickness in pixels or percentage adjustment of box drawing characters.
+# See the notes about adjustments in `adjust-cell-width`.
+adjust-box-thickness =
+
+# The method to use for calculating the cell width of a grapheme cluster.
+# The default value is `unicode` which uses the Unicode standard to determine
+# grapheme width. This results in correct grapheme width but may result in
+# cursor-desync issues with some programs (such as shells) that may use a
+# legacy method such as `wcswidth`.
+#
+# Valid values are:
+#
+# * `legacy` - Use a legacy method to determine grapheme width, such as
+# wcswidth This maximizes compatibility with legacy programs but may result
+# in incorrect grapheme width for certain graphemes such as skin-tone
+# emoji, non-English characters, etc.
+#
+# This is called "legacy" and not something more specific because the
+# behavior is undefined and we want to retain the ability to modify it.
+# For example, we may or may not use libc `wcswidth` now or in the future.
+#
+# * `unicode` - Use the Unicode standard to determine grapheme width.
+#
+# If a running program explicitly enables terminal mode 2027, then `unicode`
+# width will be forced regardless of this configuration. When mode 2027 is
+# reset, this configuration will be used again.
+#
+# This configuration can be changed at runtime but will not affect existing
+# terminals. Only new terminals will use the new configuration.
+grapheme-width-method = unicode
+
+# FreeType load flags to enable. The format of this is a list of flags to
+# enable separated by commas. If you prefix a flag with `no-` then it is
+# disabled. If you omit a flag, its default value is used, so you must
+# explicitly disable flags you don't want. You can also use `true` or `false`
+# to turn all flags on or off.
+#
+# This configuration only applies to Ghostty builds that use FreeType.
+# This is usually the case only for Linux builds. macOS uses CoreText
+# and does not have an equivalent configuration.
+#
+# Available flags:
+#
+# * `hinting` - Enable or disable hinting, enabled by default.
+# * `force-autohint` - Use the freetype auto-hinter rather than the
+# font's native hinter. Enabled by default.
+# * `monochrome` - Instructs renderer to use 1-bit monochrome
+# rendering. This option doesn't impact the hinter.
+# Enabled by default.
+# * `autohint` - Use the freetype auto-hinter. Enabled by default.
+#
+# Example: `hinting`, `no-hinting`, `force-autohint`, `no-force-autohint`
+freetype-load-flags = hinting,force-autohint,monochrome,autohint
+
+# A theme to use. This can be a built-in theme name, a custom theme
+# name, or an absolute path to a custom theme file. Ghostty also supports
+# specifying a different theme to use for light and dark mode. Each
+# option is documented below.
+#
+# If the theme is an absolute pathname, Ghostty will attempt to load that
+# file as a theme. If that file does not exist or is inaccessible, an error
+# will be logged and no other directories will be searched.
+#
+# If the theme is not an absolute pathname, two different directories will be
+# searched for a file name that matches the theme. This is case sensitive on
+# systems with case-sensitive filesystems. It is an error for a theme name to
+# include path separators unless it is an absolute pathname.
+#
+# The first directory is the `themes` subdirectory of your Ghostty
+# configuration directory. This is `$XDG_CONFIG_DIR/ghostty/themes` or
+# `~/.config/ghostty/themes`.
+#
+# The second directory is the `themes` subdirectory of the Ghostty resources
+# directory. Ghostty ships with a multitude of themes that will be installed
+# into this directory. On macOS, this list is in the
+# `Ghostty.app/Contents/Resources/ghostty/themes` directory. On Linux, this
+# list is in the `share/ghostty/themes` directory (wherever you installed the
+# Ghostty "share" directory.
+#
+# To see a list of available themes, run `ghostty +list-themes`.
+#
+# A theme file is simply another Ghostty configuration file. They share
+# the same syntax and same configuration options. A theme can set any valid
+# configuration option so please do not use a theme file from an untrusted
+# source. The built-in themes are audited to only set safe configuration
+# options.
+#
+# Some options cannot be set within theme files. The reason these are not
+# supported should be self-evident. A theme file cannot set `theme` or
+# `config-file`. At the time of writing this, Ghostty will not show any
+# warnings or errors if you set these options in a theme file but they will
+# be silently ignored.
+#
+# Any additional colors specified via background, foreground, palette, etc.
+# will override the colors specified in the theme.
+#
+# To specify a different theme for light and dark mode, use the following
+# syntax: `light:theme-name,dark:theme-name`. For example:
+# `light:rose-pine-dawn,dark:rose-pine`. Whitespace around all values are
+# trimmed and order of light and dark does not matter. Both light and dark
+# must be specified in this form. In this form, the theme used will be
+# based on the current desktop environment theme.
+#
+# There are some known bugs with light/dark mode theming. These will
+# be fixed in a future update:
+#
+# - macOS: titlebar tabs style is not updated when switching themes.
+#
+theme = rose-pine
+
+# Background color for the window.
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+# background = #282c34
+
+# Foreground color for the window.
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+# foreground = #ffffff
+
+# The foreground and background color for selection. If this is not set, then
+# the selection color is just the inverted window background and foreground
+# (note: not to be confused with the cell bg/fg).
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+selection-foreground =
+
+selection-background =
+# Swap the foreground and background colors of cells for selection. This
+# option overrides the `selection-foreground` and `selection-background`
+# options.
+#
+# If you select across cells with differing foregrounds and backgrounds, the
+# selection color will vary across the selection.
+selection-invert-fg-bg = false
+
+# The minimum contrast ratio between the foreground and background colors.
+# The contrast ratio is a value between 1 and 21. A value of 1 allows for no
+# contrast (e.g. black on black). This value is the contrast ratio as defined
+# by the [WCAG 2.0 specification](https://www.w3.org/TR/WCAG20/).
+#
+# If you want to avoid invisible text (same color as background), a value of
+# 1.1 is a good value. If you want to avoid text that is difficult to read, a
+# value of 3 or higher is a good value. The higher the value, the more likely
+# that text will become black or white.
+#
+# This value does not apply to Emoji or images.
+minimum-contrast = 1
+
+# Color palette for the 256 color form that many terminal applications use.
+# The syntax of this configuration is `N=COLOR` where `N` is 0 to 255 (for
+# the 256 colors in the terminal color table) and `COLOR` is a typical RGB
+# color code such as `#AABBCC` or `AABBCC`, or a named X11 color.
+#
+# The palette index can be in decimal, binary, octal, or hexadecimal.
+# Decimal is assumed unless a prefix is used: `0b` for binary, `0o` for octal,
+# and `0x` for hexadecimal.
+#
+# For definitions on the color indices and what they canonically map to,
+# [see this cheat sheet](https://www.ditig.com/256-colors-cheat-sheet).
+
+# The color of the cursor. If this is not set, a default will be chosen.
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+cursor-color =
+
+# Swap the foreground and background colors of the cell under the cursor. This
+# option overrides the `cursor-color` and `cursor-text` options.
+cursor-invert-fg-bg = false
+
+# The opacity level (opposite of transparency) of the cursor. A value of 1
+# is fully opaque and a value of 0 is fully transparent. A value less than 0
+# or greater than 1 will be clamped to the nearest valid value. Note that a
+# sufficiently small value such as 0.3 may be effectively invisible and may
+# make it difficult to find the cursor.
+cursor-opacity = 1
+
+# The style of the cursor. This sets the default style. A running program can
+# still request an explicit cursor style using escape sequences (such as `CSI
+# q`). Shell configurations will often request specific cursor styles.
+#
+# Note that shell integration will automatically set the cursor to a bar at
+# a prompt, regardless of this configuration. You can disable that behavior
+# by specifying `shell-integration-features = no-cursor` or disabling shell
+# integration entirely.
+#
+# Valid values are:
+#
+# * `block`
+# * `bar`
+# * `underline`
+# * `block_hollow`
+#
+cursor-style = bar
+
+# Sets the default blinking state of the cursor. This is just the default
+# state; running programs may override the cursor style using `DECSCUSR` (`CSI
+# q`).
+#
+# If this is not set, the cursor blinks by default. Note that this is not the
+# same as a "true" value, as noted below.
+#
+# If this is not set at all (`null`), then Ghostty will respect DEC Mode 12
+# (AT&T cursor blink) as an alternate approach to turning blinking on/off. If
+# this is set to any value other than null, DEC mode 12 will be ignored but
+# `DECSCUSR` will still be respected.
+#
+# Valid values are:
+#
+# * ` ` (blank)
+# * `true`
+# * `false`
+#
+cursor-style-blink =
+
+# The color of the text under the cursor. If this is not set, a default will
+# be chosen.
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+cursor-text =
+
+# Enables the ability to move the cursor at prompts by using `alt+click` on
+# Linux and `option+click` on macOS.
+#
+# This feature requires shell integration (specifically prompt marking
+# via `OSC 133`) and only works in primary screen mode. Alternate screen
+# applications like vim usually have their own version of this feature but
+# this configuration doesn't control that.
+#
+# It should be noted that this feature works by translating your desired
+# position into a series of synthetic arrow key movements, so some weird
+# behavior around edge cases are to be expected. This is unfortunately how
+# this feature is implemented across terminals because there isn't any other
+# way to implement it.
+cursor-click-to-move = true
+
+# Hide the mouse immediately when typing. The mouse becomes visible again
+# when the mouse is used (button, movement, etc.). Platform-specific behavior
+# may dictate other scenarios where the mouse is shown. For example on macOS,
+# the mouse is shown again when a new window, tab, or split is created.
+mouse-hide-while-typing = false
+
+# Determines whether running programs can detect the shift key pressed with a
+# mouse click. Typically, the shift key is used to extend mouse selection.
+#
+# The default value of `false` means that the shift key is not sent with
+# the mouse protocol and will extend the selection. This value can be
+# conditionally overridden by the running program with the `XTSHIFTESCAPE`
+# sequence.
+#
+# The value `true` means that the shift key is sent with the mouse protocol
+# but the running program can override this behavior with `XTSHIFTESCAPE`.
+#
+# The value `never` is the same as `false` but the running program cannot
+# override this behavior with `XTSHIFTESCAPE`. The value `always` is the
+# same as `true` but the running program cannot override this behavior with
+# `XTSHIFTESCAPE`.
+#
+# If you always want shift to extend mouse selection even if the program
+# requests otherwise, set this to `never`.
+#
+# Valid values are:
+#
+# * `true`
+# * `false`
+# * `always`
+# * `never`
+#
+mouse-shift-capture = false
+
+# Multiplier for scrolling distance with the mouse wheel. Any value less
+# than 0.01 or greater than 10,000 will be clamped to the nearest valid
+# value.
+#
+# A value of "1" (default) scrolls the default amount. A value of "2" scrolls
+# double the default amount. A value of "0.5" scrolls half the default amount.
+# Et cetera.
+mouse-scroll-multiplier = 1
+
+# The opacity level (opposite of transparency) of the background. A value of
+# 1 is fully opaque and a value of 0 is fully transparent. A value less than 0
+# or greater than 1 will be clamped to the nearest valid value.
+#
+# On macOS, background opacity is disabled when the terminal enters native
+# fullscreen. This is because the background becomes gray and it can cause
+# widgets to show through which isn't generally desirable.
+#
+# On macOS, changing this configuration requires restarting Ghostty completely.
+background-opacity = 0.95
+
+# Whether to blur the background when `background-opacity` is less than 1.
+#
+# Valid values are:
+#
+# * a nonnegative integer specifying the *blur intensity*
+# * `false`, equivalent to a blur intensity of 0
+# * `true`, equivalent to the default blur intensity of 20, which is
+# reasonable for a good looking blur. Higher blur intensities may
+# cause strange rendering and performance issues.
+#
+# Supported on macOS and on some Linux desktop environments, including:
+#
+# * KDE Plasma (Wayland and X11)
+#
+# Warning: the exact blur intensity is _ignored_ under KDE Plasma, and setting
+# this setting to either `true` or any positive blur intensity value would
+# achieve the same effect. The reason is that KWin, the window compositor
+# powering Plasma, only has one global blur setting and does not allow
+# applications to specify individual blur settings.
+#
+# To configure KWin's global blur setting, open System Settings and go to
+# "Apps & Windows" > "Window Management" > "Desktop Effects" and select the
+# "Blur" plugin. If disabled, enable it by ticking the checkbox to the left.
+# Then click on the "Configure" button and there will be two sliders that
+# allow you to set background blur and noise intensities for all apps,
+# including Ghostty.
+#
+# All other Linux desktop environments are as of now unsupported. Users may
+# need to set environment-specific settings and/or install third-party plugins
+# in order to support background blur, as there isn't a unified interface for
+# doing so.
+background-blur = true
+
+# The opacity level (opposite of transparency) of an unfocused split.
+# Unfocused splits by default are slightly faded out to make it easier to see
+# which split is focused. To disable this feature, set this value to 1.
+#
+# A value of 1 is fully opaque and a value of 0 is fully transparent. Because
+# "0" is not useful (it makes the window look very weird), the minimum value
+# is 0.15. This value still looks weird but you can at least see what's going
+# on. A value outside of the range 0.15 to 1 will be clamped to the nearest
+# valid value.
+unfocused-split-opacity = 0.7
+
+# The color to dim the unfocused split. Unfocused splits are dimmed by
+# rendering a semi-transparent rectangle over the split. This sets the color of
+# that rectangle and can be used to carefully control the dimming effect.
+#
+# This will default to the background color.
+#
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+unfocused-split-fill =
+
+# The color of the split divider. If this is not set, a default will be chosen.
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+split-divider-color =
+
+# The command to run, usually a shell. If this is not an absolute path, it'll
+# be looked up in the `PATH`. If this is not set, a default will be looked up
+# from your system. The rules for the default lookup are:
+#
+# * `SHELL` environment variable
+#
+# * `passwd` entry (user information)
+#
+# This can contain additional arguments to run the command with. If additional
+# arguments are provided, the command will be executed using `/bin/sh -c`.
+# Ghostty does not do any shell command parsing.
+#
+# This command will be used for all new terminal surfaces, i.e. new windows,
+# tabs, etc. If you want to run a command only for the first terminal surface
+# created when Ghostty starts, use the `initial-command` configuration.
+#
+# Ghostty supports the common `-e` flag for executing a command with
+# arguments. For example, `ghostty -e fish --with --custom --args`.
+# This flag sets the `initial-command` configuration, see that for more
+# information.
+command =
+
+# This is the same as "command", but only applies to the first terminal
+# surface created when Ghostty starts. Subsequent terminal surfaces will use
+# the `command` configuration.
+#
+# After the first terminal surface is created (or closed), there is no
+# way to run this initial command again automatically. As such, setting
+# this at runtime works but will only affect the next terminal surface
+# if it is the first one ever created.
+#
+# If you're using the `ghostty` CLI there is also a shortcut to set this
+# with arguments directly: you can use the `-e` flag. For example: `ghostty -e
+# fish --with --custom --args`. The `-e` flag automatically forces some
+# other behaviors as well:
+#
+# * `gtk-single-instance=false` - This ensures that a new instance is
+# launched and the CLI args are respected.
+#
+# * `quit-after-last-window-closed=true` - This ensures that the Ghostty
+# process will exit when the command exits. Additionally, the
+# `quit-after-last-window-closed-delay` is unset.
+#
+# * `shell-integration=detect` (if not `none`) - This prevents forcibly
+# injecting any configured shell integration into the command's
+# environment. With `-e` its highly unlikely that you're executing a
+# shell and forced shell integration is likely to cause problems
+# (e.g. by wrapping your command in a shell, setting env vars, etc.).
+# This is a safety measure to prevent unexpected behavior. If you want
+# shell integration with a `-e`-executed command, you must either
+# name your binary appropriately or source the shell integration script
+# manually.
+#
+initial-command =
+
+# If true, keep the terminal open after the command exits. Normally, the
+# terminal window closes when the running command (such as a shell) exits.
+# With this true, the terminal window will stay open until any keypress is
+# received.
+#
+# This is primarily useful for scripts or debugging.
+wait-after-command = false
+
+# The number of milliseconds of runtime below which we consider a process exit
+# to be abnormal. This is used to show an error message when the process exits
+# too quickly.
+#
+# On Linux, this must be paired with a non-zero exit code. On macOS, we allow
+# any exit code because of the way shell processes are launched via the login
+# command.
+abnormal-command-exit-runtime = 250
+
+# The size of the scrollback buffer in bytes. This also includes the active
+# screen. No matter what this is set to, enough memory will always be
+# allocated for the visible screen and anything leftover is the limit for
+# the scrollback.
+#
+# When this limit is reached, the oldest lines are removed from the
+# scrollback.
+#
+# Scrollback currently exists completely in memory. This means that the
+# larger this value, the larger potential memory usage. Scrollback is
+# allocated lazily up to this limit, so if you set this to a very large
+# value, it will not immediately consume a lot of memory.
+#
+# This size is per terminal surface, not for the entire application.
+#
+# It is not currently possible to set an unlimited scrollback buffer.
+# This is a future planned feature.
+#
+# This can be changed at runtime but will only affect new terminal surfaces.
+scrollback-limit = 10000000
+
+# Match a regular expression against the terminal text and associate clicking
+# it with an action. This can be used to match URLs, file paths, etc. Actions
+# can be opening using the system opener (e.g. `open` or `xdg-open`) or
+# executing any arbitrary binding action.
+#
+# Links that are configured earlier take precedence over links that are
+# configured later.
+#
+# A default link that matches a URL and opens it in the system opener always
+# exists. This can be disabled using `link-url`.
+#
+# TODO: This can't currently be set!
+
+# Enable URL matching. URLs are matched on hover with control (Linux) or
+# super (macOS) pressed and open using the default system application for
+# the linked URL.
+#
+# The URL matcher is always lowest priority of any configured links (see
+# `link`). If you want to customize URL matching, use `link` and disable this.
+link-url = true
+
+# Whether to start the window in a maximized state. This setting applies
+# to new windows and does not apply to tabs, splits, etc. However, this setting
+# will apply to all new windows, not just the first one.
+maximize = false
+
+# Start new windows in fullscreen. This setting applies to new windows and
+# does not apply to tabs, splits, etc. However, this setting will apply to all
+# new windows, not just the first one.
+#
+# On macOS, this setting does not work if window-decoration is set to
+# "false", because native fullscreen on macOS requires window decorations
+# to be set.
+fullscreen = false
+
+# The title Ghostty will use for the window. This will force the title of the
+# window to be this title at all times and Ghostty will ignore any set title
+# escape sequences programs (such as Neovim) may send.
+#
+# If you want a blank title, set this to one or more spaces by quoting
+# the value. For example, `title = " "`. This effectively hides the title.
+# This is necessary because setting a blank value resets the title to the
+# default value of the running program.
+#
+# This configuration can be reloaded at runtime. If it is set, the title
+# will update for all windows. If it is unset, the next title change escape
+# sequence will be honored but previous changes will not retroactively
+# be set. This latter case may require you to restart programs such as Neovim
+# to get the new title.
+title = "Ghostty"
+
+# The setting that will change the application class value.
+#
+# This controls the class field of the `WM_CLASS` X11 property (when running
+# under X11), and the Wayland application ID (when running under Wayland).
+#
+# Note that changing this value between invocations will create new, separate
+# instances, of Ghostty when running with `gtk-single-instance=true`. See that
+# option for more details.
+#
+# The class name must follow the requirements defined [in the GTK
+# documentation](https://docs.gtk.org/gio/type_func.Application.id_is_valid.html).
+#
+# The default is `com.mitchellh.ghostty`.
+#
+# This only affects GTK builds.
+class = "ghostty"
+
+# This controls the instance name field of the `WM_CLASS` X11 property when
+# running under X11. It has no effect otherwise.
+#
+# The default is `ghostty`.
+#
+# This only affects GTK builds.
+x11-instance-name =
+
+# The directory to change to after starting the command.
+#
+# This setting is secondary to the `window-inherit-working-directory`
+# setting. If a previous Ghostty terminal exists in the same process,
+# `window-inherit-working-directory` will take precedence. Otherwise, this
+# setting will be used. Typically, this setting is used only for the first
+# window.
+#
+# The default is `inherit` except in special scenarios listed next. On macOS,
+# if Ghostty can detect it is launched from launchd (double-clicked) or
+# `open`, then it defaults to `home`. On Linux with GTK, if Ghostty can detect
+# it was launched from a desktop launcher, then it defaults to `home`.
+#
+# The value of this must be an absolute value or one of the special values
+# below:
+#
+# * `home` - The home directory of the executing user.
+#
+# * `inherit` - The working directory of the launching process.
+working-directory =
+
+# Key bindings. The format is `trigger=action`. Duplicate triggers will
+# overwrite previously set values. The list of actions is available in
+# the documentation or using the `ghostty +list-actions` command.
+#
+# Trigger: `+`-separated list of keys and modifiers. Example: `ctrl+a`,
+# `ctrl+shift+b`, `up`.
+#
+# Valid keys are currently only listed in the
+# [Ghostty source code](https://github.com/ghostty-org/ghostty/blob/d6e76858164d52cff460fedc61ddf2e560912d71/src/input/key.zig#L255).
+# This is a documentation limitation and we will improve this in the future.
+# A common gotcha is that numeric keys are written as words: e.g. `one`,
+# `two`, `three`, etc. and not `1`, `2`, `3`. This will also be improved in
+# the future.
+#
+# Valid modifiers are `shift`, `ctrl` (alias: `control`), `alt` (alias: `opt`,
+# `option`), and `super` (alias: `cmd`, `command`). You may use the modifier
+# or the alias. When debugging keybinds, the non-aliased modifier will always
+# be used in output.
+#
+# Note: The fn or "globe" key on keyboards are not supported as a
+# modifier. This is a limitation of the operating systems and GUI toolkits
+# that Ghostty uses.
+#
+# Some additional notes for triggers:
+#
+# * modifiers cannot repeat, `ctrl+ctrl+a` is invalid.
+#
+# * modifiers and keys can be in any order, `shift+a+ctrl` is *weird*,
+# but valid.
+#
+# * only a single key input is allowed, `ctrl+a+b` is invalid.
+#
+# * the key input can be prefixed with `physical:` to specify a
+# physical key mapping rather than a logical one. A physical key
+# mapping responds to the hardware keycode and not the keycode
+# translated by any system keyboard layouts. Example: "ctrl+physical:a"
+#
+# You may also specify multiple triggers separated by `>` to require a
+# sequence of triggers to activate the action. For example,
+# `ctrl+a>n=new_window` will only trigger the `new_window` action if the
+# user presses `ctrl+a` followed separately by `n`. In other software, this
+# is sometimes called a leader key, a key chord, a key table, etc. There
+# is no hardcoded limit on the number of parts in a sequence.
+#
+# Warning: If you define a sequence as a CLI argument to `ghostty`,
+# you probably have to quote the keybind since `>` is a special character
+# in most shells. Example: ghostty --keybind='ctrl+a>n=new_window'
+#
+# A trigger sequence has some special handling:
+#
+# * Ghostty will wait an indefinite amount of time for the next key in
+# the sequence. There is no way to specify a timeout. The only way to
+# force the output of a prefix key is to assign another keybind to
+# specifically output that key (e.g. `ctrl+a>ctrl+a=text:foo`) or
+# press an unbound key which will send both keys to the program.
+#
+# * If a prefix in a sequence is previously bound, the sequence will
+# override the previous binding. For example, if `ctrl+a` is bound to
+# `new_window` and `ctrl+a>n` is bound to `new_tab`, pressing `ctrl+a`
+# will do nothing.
+#
+# * Adding to the above, if a previously bound sequence prefix is
+# used in a new, non-sequence binding, the entire previously bound
+# sequence will be unbound. For example, if you bind `ctrl+a>n` and
+# `ctrl+a>t`, and then bind `ctrl+a` directly, both `ctrl+a>n` and
+# `ctrl+a>t` will become unbound.
+#
+# * Trigger sequences are not allowed for `global:` or `all:`-prefixed
+# triggers. This is a limitation we could remove in the future.
+#
+# Action is the action to take when the trigger is satisfied. It takes the
+# format `action` or `action:param`. The latter form is only valid if the
+# action requires a parameter.
+#
+# * `ignore` - Do nothing, ignore the key input. This can be used to
+# black hole certain inputs to have no effect.
+#
+# * `unbind` - Remove the binding. This makes it so the previous action
+# is removed, and the key will be sent through to the child command
+# if it is printable. Unbind will remove any matching trigger,
+# including `physical:`-prefixed triggers without specifying the
+# prefix.
+#
+# * `csi:text` - Send a CSI sequence. e.g. `csi:A` sends "cursor up".
+#
+# * `esc:text` - Send an escape sequence. e.g. `esc:d` deletes to the
+# end of the word to the right.
+#
+# * `text:text` - Send a string. Uses Zig string literal syntax.
+# e.g. `text:\x15` sends Ctrl-U.
+#
+# * All other actions can be found in the documentation or by using the
+# `ghostty +list-actions` command.
+#
+# Some notes for the action:
+#
+# * The parameter is taken as-is after the `:`. Double quotes or
+# other mechanisms are included and NOT parsed. If you want to
+# send a string value that includes spaces, wrap the entire
+# trigger/action in double quotes. Example: `--keybind="up=csi:A B"`
+#
+# There are some additional special values that can be specified for
+# keybind:
+#
+# * `keybind=clear` will clear all set keybindings. Warning: this
+# removes ALL keybindings up to this point, including the default
+# keybindings.
+#
+# The keybind trigger can be prefixed with some special values to change
+# the behavior of the keybind. These are:
+#
+# * `all:` - Make the keybind apply to all terminal surfaces. By default,
+# keybinds only apply to the focused terminal surface. If this is true,
+# then the keybind will be sent to all terminal surfaces. This only
+# applies to actions that are surface-specific. For actions that
+# are already global (e.g. `quit`), this prefix has no effect.
+#
+# * `global:` - Make the keybind global. By default, keybinds only work
+# within Ghostty and under the right conditions (application focused,
+# sometimes terminal focused, etc.). If you want a keybind to work
+# globally across your system (e.g. even when Ghostty is not focused),
+# specify this prefix. This prefix implies `all:`. Note: this does not
+# work in all environments; see the additional notes below for more
+# information.
+#
+# * `unconsumed:` - Do not consume the input. By default, a keybind
+# will consume the input, meaning that the associated encoding (if
+# any) will not be sent to the running program in the terminal. If
+# you wish to send the encoded value to the program, specify the
+# `unconsumed:` prefix before the entire keybind. For example:
+# `unconsumed:ctrl+a=reload_config`. `global:` and `all:`-prefixed
+# keybinds will always consume the input regardless of this setting.
+# Since they are not associated with a specific terminal surface,
+# they're never encoded.
+#
+# * `performable:` - Only consume the input if the action is able to be
+# performed. For example, the `copy_to_clipboard` action will only
+# consume the input if there is a selection to copy. If there is no
+# selection, Ghostty behaves as if the keybind was not set. This has
+# no effect with `global:` or `all:`-prefixed keybinds. For key
+# sequences, this will reset the sequence if the action is not
+# performable (acting identically to not having a keybind set at
+# all).
+#
+# Performable keybinds will not appear as menu shortcuts in the
+# application menu. This is because the menu shortcuts force the
+# action to be performed regardless of the state of the terminal.
+# Performable keybinds will still work, they just won't appear as
+# a shortcut label in the menu.
+#
+# Keybind triggers are not unique per prefix combination. For example,
+# `ctrl+a` and `global:ctrl+a` are not two separate keybinds. The keybind
+# set later will overwrite the keybind set earlier. In this case, the
+# `global:` keybind will be used.
+#
+# Multiple prefixes can be specified. For example,
+# `global:unconsumed:ctrl+a=reload_config` will make the keybind global
+# and not consume the input to reload the config.
+#
+# Note: `global:` is only supported on macOS. On macOS,
+# this feature requires accessibility permissions to be granted to Ghostty.
+# When a `global:` keybind is specified and Ghostty is launched or reloaded,
+# Ghostty will attempt to request these permissions. If the permissions are
+# not granted, the keybind will not work. On macOS, you can find these
+# permissions in System Preferences -> Privacy & Security -> Accessibility.
+keybind = alt+f4=ignore
+keybind = alt+one=unbind
+keybind = alt+two=unbind
+keybind = alt+three=unbind
+keybind = alt+four=unbind
+keybind = alt+five=unbind
+keybind = alt+six=unbind
+keybind = alt+seven=unbind
+keybind = alt+eight=unbind
+keybind = alt+nine=unbind
+keybind = ctrl+alt+down=ignore
+keybind = ctrl+alt+left=ignore
+keybind = ctrl+alt+right=ignore
+keybind = ctrl+alt+shift+j=write_screen_file:open
+keybind = ctrl+alt+up=ignore
+keybind = ctrl+comma=open_config
+keybind = ctrl+enter=ignore
+keybind = ctrl+equal=increase_font_size:1
+keybind = ctrl+insert=copy_to_clipboard
+keybind = ctrl+minus=decrease_font_size:1
+keybind = ctrl+page_down=ignore
+keybind = ctrl+page_up=ignore
+keybind = ctrl+plus=ignore
+keybind = ctrl+shift+a=select_all
+keybind = ctrl+shift+c=copy_to_clipboard
+keybind = ctrl+shift+comma=reload_config
+keybind = ctrl+shift+e=ignore
+keybind = ctrl+shift+enter=ignore
+keybind = ctrl+shift+i=inspector:toggle
+keybind = ctrl+shift+j=write_screen_file:paste
+keybind = ctrl+shift+left=ignore
+keybind = ctrl+shift+n=ignore
+keybind = ctrl+shift+o=ignore
+keybind = ctrl+shift+page_down=ignore
+keybind = ctrl+shift+page_up=jump_to_prompt:-1
+keybind = ctrl+shift+q=ignore
+keybind = ctrl+shift+right=ignore
+keybind = ctrl+shift+t=ignore
+keybind = ctrl+shift+tab=ignore
+keybind = ctrl+shift+v=paste_from_clipboard
+keybind = ctrl+shift+w=ignore
+keybind = ctrl+tab=ignore
+keybind = ctrl+zero=reset_font_size
+keybind = shift+down=adjust_selection:down
+keybind = shift+end=scroll_to_bottom
+keybind = shift+home=scroll_to_top
+keybind = shift+insert=paste_from_selection
+keybind = shift+left=adjust_selection:left
+keybind = shift+page_down=scroll_page_down
+keybind = shift+page_up=scroll_page_up
+keybind = shift+right=adjust_selection:right
+keybind = shift+up=ignore
+keybind = super+ctrl+left_bracket=ignore
+keybind = super+ctrl+right_bracket=ignore
+keybind = super+ctrl+shift+down=ignore
+keybind = super+ctrl+shift+equal=ignore
+keybind = super+ctrl+shift+left=ignore
+keybind = super+ctrl+shift+right=ignore
+keybind = super+ctrl+shift+up=ignore
+
+# Horizontal window padding. This applies padding between the terminal cells
+# and the left and right window borders. The value is in points, meaning that
+# it will be scaled appropriately for screen DPI.
+#
+# If this value is set too large, the screen will render nothing, because the
+# grid will be completely squished by the padding. It is up to you as the user
+# to pick a reasonable value. If you pick an unreasonable value, a warning
+# will appear in the logs.
+#
+# Changing this configuration at runtime will only affect new terminals, i.e.
+# new windows, tabs, etc.
+#
+# To set a different left and right padding, specify two numerical values
+# separated by a comma. For example, `window-padding-x = 2,4` will set the
+# left padding to 2 and the right padding to 4. If you want to set both
+# paddings to the same value, you can use a single value. For example,
+# `window-padding-x = 2` will set both paddings to 2.
+window-padding-x = 2
+
+# Vertical window padding. This applies padding between the terminal cells and
+# the top and bottom window borders. The value is in points, meaning that it
+# will be scaled appropriately for screen DPI.
+#
+# If this value is set too large, the screen will render nothing, because the
+# grid will be completely squished by the padding. It is up to you as the user
+# to pick a reasonable value. If you pick an unreasonable value, a warning
+# will appear in the logs.
+#
+# Changing this configuration at runtime will only affect new terminals,
+# i.e. new windows, tabs, etc.
+#
+# To set a different top and bottom padding, specify two numerical values
+# separated by a comma. For example, `window-padding-y = 2,4` will set the
+# top padding to 2 and the bottom padding to 4. If you want to set both
+# paddings to the same value, you can use a single value. For example,
+# `window-padding-y = 2` will set both paddings to 2.
+window-padding-y = 2
+
+# The viewport dimensions are usually not perfectly divisible by the cell
+# size. In this case, some extra padding on the end of a column and the bottom
+# of the final row may exist. If this is `true`, then this extra padding
+# is automatically balanced between all four edges to minimize imbalance on
+# one side. If this is `false`, the top left grid cell will always hug the
+# edge with zero padding other than what may be specified with the other
+# `window-padding` options.
+#
+# If other `window-padding` fields are set and this is `true`, this will still
+# apply. The other padding is applied first and may affect how many grid cells
+# actually exist, and this is applied last in order to balance the padding
+# given a certain viewport size and grid cell size.
+window-padding-balance = false
+
+# The color of the padding area of the window. Valid values are:
+#
+# * `background` - The background color specified in `background`.
+# * `extend` - Extend the background color of the nearest grid cell.
+# * `extend-always` - Same as "extend" but always extends without applying
+# any of the heuristics that disable extending noted below.
+#
+# The "extend" value will be disabled in certain scenarios. On primary
+# screen applications (e.g. not something like Neovim), the color will not
+# be extended vertically if any of the following are true:
+#
+# * The nearest row has any cells that have the default background color.
+# The thinking is that in this case, the default background color looks
+# fine as a padding color.
+# * The nearest row is a prompt row (requires shell integration). The
+# thinking here is that prompts often contain powerline glyphs that
+# do not look good extended.
+# * The nearest row contains a perfect fit powerline character. These
+# don't look good extended.
+#
+window-padding-color = background
+
+# Synchronize rendering with the screen refresh rate. If true, this will
+# minimize tearing and align redraws with the screen but may cause input
+# latency. If false, this will maximize redraw frequency but may cause tearing,
+# and under heavy load may use more CPU and power.
+#
+# This defaults to true because out-of-sync rendering on macOS can
+# cause kernel panics (macOS 14.4+) and performance issues for external
+# displays over some hardware such as DisplayLink. If you want to minimize
+# input latency, set this to false with the known aforementioned risks.
+#
+# Changing this value at runtime will only affect new terminals.
+#
+# This setting is only supported currently on macOS.
+window-vsync = true
+
+# If true, new windows and tabs will inherit the working directory of the
+# previously focused window. If no window was previously focused, the default
+# working directory will be used (the `working-directory` option).
+window-inherit-working-directory = true
+
+# If true, new windows and tabs will inherit the font size of the previously
+# focused window. If no window was previously focused, the default font size
+# will be used. If this is false, the default font size specified in the
+# configuration `font-size` will be used.
+window-inherit-font-size = true
+
+# Configure a preference for window decorations. This setting specifies
+# a _preference_; the actual OS, desktop environment, window manager, etc.
+# may override this preference. Ghostty will do its best to respect this
+# preference but it may not always be possible.
+#
+# Valid values:
+#
+# * `none` - All window decorations will be disabled. Titlebar,
+# borders, etc. will not be shown. On macOS, this will also disable
+# tabs (enforced by the system).
+#
+# * `auto` - Automatically decide to use either client-side or server-side
+# decorations based on the detected preferences of the current OS and
+# desktop environment. This option usually makes Ghostty look the most
+# "native" for your desktop.
+#
+# * `client` - Prefer client-side decorations.
+#
+# * `server` - Prefer server-side decorations. This is only relevant
+# on Linux with GTK. This currently only works on Linux with Wayland
+# and the `org_kde_kwin_server_decoration` protocol available (e.g.
+# KDE Plasma, but almost any non-GNOME desktop supports this protocol).
+#
+# If `server` is set but the environment doesn't support server-side
+# decorations, client-side decorations will be used instead.
+#
+# The default value is `auto`.
+#
+# For the sake of backwards compatibility and convenience, this setting also
+# accepts boolean true and false values. If set to `true`, this is equivalent
+# to `auto`. If set to `false`, this is equivalent to `none`.
+# This is convenient for users who live primarily on systems that don't
+# differentiate between client and server-side decorations (e.g. macOS and
+# Windows).
+#
+# The "toggle_window_decorations" keybind action can be used to create
+# a keybinding to toggle this setting at runtime. This will always toggle
+# back to "auto" if the current value is "none" (this is an issue
+# that will be fixed in the future).
+#
+# Changing this configuration in your configuration and reloading will
+# only affect new windows. Existing windows will not be affected.
+#
+# macOS: To hide the titlebar without removing the native window borders
+# or rounded corners, use `macos-titlebar-style = hidden` instead.
+window-decoration = auto
+
+# The font that will be used for the application's window and tab titles.
+#
+# If this setting is left unset, the system default font will be used.
+#
+# Note: any font available on the system may be used, this font is not
+# required to be a fixed-width font.
+window-title-font-family =
+
+# The text that will be displayed in the subtitle of the window. Valid values:
+#
+# * `false` - Disable the subtitle.
+# * `working-directory` - Set the subtitle to the working directory of the
+# surface.
+#
+# This feature is only supported on GTK with Adwaita enabled.
+window-subtitle = false
+
+# The theme to use for the windows. Valid values:
+#
+# * `auto` - Determine the theme based on the configured terminal
+# background color. This has no effect if the "theme" configuration
+# has separate light and dark themes. In that case, the behavior
+# of "auto" is equivalent to "system".
+# * `system` - Use the system theme.
+# * `light` - Use the light theme regardless of system theme.
+# * `dark` - Use the dark theme regardless of system theme.
+# * `ghostty` - Use the background and foreground colors specified in the
+# Ghostty configuration. This is only supported on Linux builds with
+# Adwaita and `gtk-adwaita` enabled.
+#
+# On macOS, if `macos-titlebar-style` is "tabs", the window theme will be
+# automatically set based on the luminosity of the terminal background color.
+# This only applies to terminal windows. This setting will still apply to
+# non-terminal windows within Ghostty.
+#
+# This is currently only supported on macOS and Linux.
+window-theme = auto
+
+# The color space to use when interpreting terminal colors. "Terminal colors"
+# refers to colors specified in your configuration and colors produced by
+# direct-color SGR sequences.
+#
+# Valid values:
+#
+# * `srgb` - Interpret colors in the sRGB color space. This is the default.
+# * `display-p3` - Interpret colors in the Display P3 color space.
+#
+# This setting is currently only supported on macOS.
+window-colorspace = srgb
+
+# The initial window size. This size is in terminal grid cells by default.
+# Both values must be set to take effect. If only one value is set, it is
+# ignored.
+#
+# We don't currently support specifying a size in pixels but a future change
+# can enable that. If this isn't specified, the app runtime will determine
+# some default size.
+#
+# Note that the window manager may put limits on the size or override the
+# size. For example, a tiling window manager may force the window to be a
+# certain size to fit within the grid. There is nothing Ghostty will do about
+# this, but it will make an effort.
+#
+# Sizes larger than the screen size will be clamped to the screen size.
+# This can be used to create a maximized-by-default window size.
+#
+# This will not affect new tabs, splits, or other nested terminal elements.
+# This only affects the initial window size of any new window. Changing this
+# value will not affect the size of the window after it has been created. This
+# is only used for the initial size.
+#
+# BUG: On Linux with GTK, the calculated window size will not properly take
+# into account window decorations. As a result, the grid dimensions will not
+# exactly match this configuration. If window decorations are disabled (see
+# `window-decoration`), then this will work as expected.
+#
+# Windows smaller than 10 wide by 4 high are not allowed.
+window-height = 0
+
+window-width = 0
+# The starting window position. This position is in pixels and is relative
+# to the top-left corner of the primary monitor. Both values must be set to take
+# effect. If only one value is set, it is ignored.
+#
+# Note that the window manager may put limits on the position or override
+# the position. For example, a tiling window manager may force the window
+# to be a certain position to fit within the grid. There is nothing Ghostty
+# will do about this, but it will make an effort.
+#
+# Also note that negative values are also up to the operating system and
+# window manager. Some window managers may not allow windows to be placed
+# off-screen.
+#
+# Invalid positions are runtime-specific, but generally the positions are
+# clamped to the nearest valid position.
+#
+# On macOS, the window position is relative to the top-left corner of
+# the visible screen area. This means that if the menu bar is visible, the
+# window will be placed below the menu bar.
+#
+# Note: this is only supported on macOS and Linux GLFW builds. The GTK
+# runtime does not support setting the window position (this is a limitation
+# of GTK 4.0).
+window-position-x =
+
+window-position-y =
+# Whether to enable saving and restoring window state. Window state includes
+# their position, size, tabs, splits, etc. Some window state requires shell
+# integration, such as preserving working directories. See `shell-integration`
+# for more information.
+#
+# There are three valid values for this configuration:
+#
+# * `default` will use the default system behavior. On macOS, this
+# will only save state if the application is forcibly terminated
+# or if it is configured systemwide via Settings.app.
+#
+# * `never` will never save window state.
+#
+# * `always` will always save window state whenever Ghostty is exited.
+#
+# If you change this value to `never` while Ghostty is not running, the next
+# Ghostty launch will NOT restore the window state.
+#
+# If you change this value to `default` while Ghostty is not running and the
+# previous exit saved state, the next Ghostty launch will still restore the
+# window state. This is because Ghostty cannot know if the previous exit was
+# due to a forced save or not (macOS doesn't provide this information).
+#
+# If you change this value so that window state is saved while Ghostty is not
+# running, the previous window state will not be restored because Ghostty only
+# saves state on exit if this is enabled.
+#
+# The default value is `default`.
+#
+# This is currently only supported on macOS. This has no effect on Linux.
+window-save-state = default
+
+# Resize the window in discrete increments of the focused surface's cell size.
+# If this is disabled, surfaces are resized in pixel increments. Currently
+# only supported on macOS.
+window-step-resize = false
+
+# The position where new tabs are created. Valid values:
+#
+# * `current` - Insert the new tab after the currently focused tab,
+# or at the end if there are no focused tabs.
+#
+# * `end` - Insert the new tab at the end of the tab list.
+window-new-tab-position = current
+
+# Background color for the window titlebar. This only takes effect if
+# window-theme is set to ghostty. Currently only supported in the GTK app
+# runtime.
+#
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+window-titlebar-background =
+
+# Foreground color for the window titlebar. This only takes effect if
+# window-theme is set to ghostty. Currently only supported in the GTK app
+# runtime.
+#
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+window-titlebar-foreground =
+
+# This controls when resize overlays are shown. Resize overlays are a
+# transient popup that shows the size of the terminal while the surfaces are
+# being resized. The possible options are:
+#
+# * `always` - Always show resize overlays.
+# * `never` - Never show resize overlays.
+# * `after-first` - The resize overlay will not appear when the surface
+# is first created, but will show up if the surface is
+# subsequently resized.
+#
+# The default is `after-first`.
+resize-overlay = after-first
+
+# If resize overlays are enabled, this controls the position of the overlay.
+# The possible options are:
+#
+# * `center`
+# * `top-left`
+# * `top-center`
+# * `top-right`
+# * `bottom-left`
+# * `bottom-center`
+# * `bottom-right`
+#
+# The default is `center`.
+resize-overlay-position = center
+
+# If resize overlays are enabled, this controls how long the overlay is
+# visible on the screen before it is hidden. The default is ¾ of a second or
+# 750 ms.
+#
+# The duration is specified as a series of numbers followed by time units.
+# Whitespace is allowed between numbers and units. Each number and unit will
+# be added together to form the total duration.
+#
+# The allowed time units are as follows:
+#
+# * `y` - 365 SI days, or 8760 hours, or 31536000 seconds. No adjustments
+# are made for leap years or leap seconds.
+# * `d` - one SI day, or 86400 seconds.
+# * `h` - one hour, or 3600 seconds.
+# * `m` - one minute, or 60 seconds.
+# * `s` - one second.
+# * `ms` - one millisecond, or 0.001 second.
+# * `us` or `µs` - one microsecond, or 0.000001 second.
+# * `ns` - one nanosecond, or 0.000000001 second.
+#
+# Examples:
+# * `1h30m`
+# * `45s`
+#
+# Units can be repeated and will be added together. This means that
+# `1h1h` is equivalent to `2h`. This is confusing and should be avoided.
+# A future update may disallow this.
+#
+# The maximum value is `584y 49w 23h 34m 33s 709ms 551µs 615ns`. Any
+# value larger than this will be clamped to the maximum value.
+resize-overlay-duration = 750ms
+
+# If true, when there are multiple split panes, the mouse selects the pane
+# that is focused. This only applies to the currently focused window; e.g.
+# mousing over a split in an unfocused window will not focus that split
+# and bring the window to front.
+#
+# Default is false.
+focus-follows-mouse = false
+
+# Whether to allow programs running in the terminal to read/write to the
+# system clipboard (OSC 52, for googling). The default is to allow clipboard
+# reading after prompting the user and allow writing unconditionally.
+#
+# Valid values are:
+#
+# * `ask`
+# * `allow`
+# * `deny`
+#
+clipboard-read = ask
+
+clipboard-write = allow
+# Trims trailing whitespace on data that is copied to the clipboard. This does
+# not affect data sent to the clipboard via `clipboard-write`.
+clipboard-trim-trailing-spaces = true
+
+# Require confirmation before pasting text that appears unsafe. This helps
+# prevent a "copy/paste attack" where a user may accidentally execute unsafe
+# commands by pasting text with newlines.
+clipboard-paste-protection = true
+
+# If true, bracketed pastes will be considered safe. By default, bracketed
+# pastes are considered safe. "Bracketed" pastes are pastes while the running
+# program has bracketed paste mode enabled (a setting set by the running
+# program, not the terminal emulator).
+clipboard-paste-bracketed-safe = true
+
+# Enables or disabled title reporting (CSI 21 t). This escape sequence
+# allows the running program to query the terminal title. This is a common
+# security issue and is disabled by default.
+#
+# Warning: This can expose sensitive information at best and enable
+# arbitrary code execution at worst (with a maliciously crafted title
+# and a minor amount of user interaction).
+title-report = false
+
+# The total amount of bytes that can be used for image data (e.g. the Kitty
+# image protocol) per terminal screen. The maximum value is 4,294,967,295
+# (4GiB). The default is 320MB. If this is set to zero, then all image
+# protocols will be disabled.
+#
+# This value is separate for primary and alternate screens so the effective
+# limit per surface is double.
+image-storage-limit = 320000000
+
+# Whether to automatically copy selected text to the clipboard. `true`
+# will prefer to copy to the selection clipboard, otherwise it will copy to
+# the system clipboard.
+#
+# The value `clipboard` will always copy text to the selection clipboard
+# as well as the system clipboard.
+#
+# Middle-click paste will always use the selection clipboard. Middle-click
+# paste is always enabled even if this is `false`.
+#
+# The default value is true on Linux and macOS.
+copy-on-select = true
+
+# The time in milliseconds between clicks to consider a click a repeat
+# (double, triple, etc.) or an entirely new single click. A value of zero will
+# use a platform-specific default. The default on macOS is determined by the
+# OS settings. On every other platform it is 500ms.
+click-repeat-interval = 0
+
+# Additional configuration files to read. This configuration can be repeated
+# to read multiple configuration files. Configuration files themselves can
+# load more configuration files. Paths are relative to the file containing the
+# `config-file` directive. For command-line arguments, paths are relative to
+# the current working directory.
+#
+# Prepend a ? character to the file path to suppress errors if the file does
+# not exist. If you want to include a file that begins with a literal ?
+# character, surround the file path in double quotes (").
+#
+# Cycles are not allowed. If a cycle is detected, an error will be logged and
+# the configuration file will be ignored.
+#
+# Configuration files are loaded after the configuration they're defined
+# within in the order they're defined. **THIS IS A VERY SUBTLE BUT IMPORTANT
+# POINT.** To put it another way: configuration files do not take effect
+# until after the entire configuration is loaded. For example, in the
+# configuration below:
+#
+# ```
+# config-file = "foo"
+# a = 1
+# ```
+#
+# If "foo" contains `a = 2`, the final value of `a` will be 2, because
+# `foo` is loaded after the configuration file that configures the
+# nested `config-file` value.
+config-file =
+
+# When this is true, the default configuration file paths will be loaded.
+# The default configuration file paths are currently only the XDG
+# config path ($XDG_CONFIG_HOME/ghostty/config).
+#
+# If this is false, the default configuration paths will not be loaded.
+# This is targeted directly at using Ghostty from the CLI in a way
+# that minimizes external effects.
+#
+# This is a CLI-only configuration. Setting this in a configuration file
+# will have no effect. It is not an error, but it will not do anything.
+# This configuration can only be set via CLI arguments.
+config-default-files = true
+
+# Confirms that a surface should be closed before closing it.
+#
+# This defaults to `true`. If set to `false`, surfaces will close without
+# any confirmation. This can also be set to `always`, which will always
+# confirm closing a surface, even if shell integration says a process isn't
+# running.
+confirm-close-surface = false
+
+# Whether or not to quit after the last surface is closed.
+#
+# This defaults to `false` on macOS since that is standard behavior for
+# a macOS application. On Linux, this defaults to `true` since that is
+# generally expected behavior.
+#
+# On Linux, if this is `true`, Ghostty can delay quitting fully until a
+# configurable amount of time has passed after the last window is closed.
+# See the documentation of `quit-after-last-window-closed-delay`.
+quit-after-last-window-closed = true
+
+# Controls how long Ghostty will stay running after the last open surface has
+# been closed. This only has an effect if `quit-after-last-window-closed` is
+# also set to `true`.
+#
+# The minimum value for this configuration is `1s`. Any values lower than
+# this will be clamped to `1s`.
+#
+# The duration is specified as a series of numbers followed by time units.
+# Whitespace is allowed between numbers and units. Each number and unit will
+# be added together to form the total duration.
+#
+# The allowed time units are as follows:
+#
+# * `y` - 365 SI days, or 8760 hours, or 31536000 seconds. No adjustments
+# are made for leap years or leap seconds.
+# * `d` - one SI day, or 86400 seconds.
+# * `h` - one hour, or 3600 seconds.
+# * `m` - one minute, or 60 seconds.
+# * `s` - one second.
+# * `ms` - one millisecond, or 0.001 second.
+# * `us` or `µs` - one microsecond, or 0.000001 second.
+# * `ns` - one nanosecond, or 0.000000001 second.
+#
+# Examples:
+# * `1h30m`
+# * `45s`
+#
+# Units can be repeated and will be added together. This means that
+# `1h1h` is equivalent to `2h`. This is confusing and should be avoided.
+# A future update may disallow this.
+#
+# The maximum value is `584y 49w 23h 34m 33s 709ms 551µs 615ns`. Any
+# value larger than this will be clamped to the maximum value.
+#
+# By default `quit-after-last-window-closed-delay` is unset and
+# Ghostty will quit immediately after the last window is closed if
+# `quit-after-last-window-closed` is `true`.
+#
+# Only implemented on Linux.
+quit-after-last-window-closed-delay =
+
+# This controls whether an initial window is created when Ghostty
+# is run. Note that if `quit-after-last-window-closed` is `true` and
+# `quit-after-last-window-closed-delay` is set, setting `initial-window` to
+# `false` will mean that Ghostty will quit after the configured delay if no
+# window is ever created. Only implemented on Linux and macOS.
+initial-window = true
+
+# The position of the "quick" terminal window. To learn more about the
+# quick terminal, see the documentation for the `toggle_quick_terminal`
+# binding action.
+#
+# Valid values are:
+#
+# * `top` - Terminal appears at the top of the screen.
+# * `bottom` - Terminal appears at the bottom of the screen.
+# * `left` - Terminal appears at the left of the screen.
+# * `right` - Terminal appears at the right of the screen.
+# * `center` - Terminal appears at the center of the screen.
+#
+# Changing this configuration requires restarting Ghostty completely.
+#
+# Note: There is no default keybind for toggling the quick terminal.
+# To enable this feature, bind the `toggle_quick_terminal` action to a key.
+quick-terminal-position = top
+
+# The screen where the quick terminal should show up.
+#
+# Valid values are:
+#
+# * `main` - The screen that the operating system recommends as the main
+# screen. On macOS, this is the screen that is currently receiving
+# keyboard input. This screen is defined by the operating system and
+# not chosen by Ghostty.
+#
+# * `mouse` - The screen that the mouse is currently hovered over.
+#
+# * `macos-menu-bar` - The screen that contains the macOS menu bar as
+# set in the display settings on macOS. This is a bit confusing because
+# every screen on macOS has a menu bar, but this is the screen that
+# contains the primary menu bar.
+#
+# The default value is `main` because this is the recommended screen
+# by the operating system.
+quick-terminal-screen = main
+
+# Duration (in seconds) of the quick terminal enter and exit animation.
+# Set it to 0 to disable animation completely. This can be changed at
+# runtime.
+quick-terminal-animation-duration = 0.2
+
+# Automatically hide the quick terminal when focus shifts to another window.
+# Set it to false for the quick terminal to remain open even when it loses focus.
+quick-terminal-autohide = true
+
+# This configuration option determines the behavior of the quick terminal
+# when switching between macOS spaces. macOS spaces are virtual desktops
+# that can be manually created or are automatically created when an
+# application is in full-screen mode.
+#
+# Valid values are:
+#
+# * `move` - When switching to another space, the quick terminal will
+# also moved to the current space.
+#
+# * `remain` - The quick terminal will stay only in the space where it
+# was originally opened and will not follow when switching to another
+# space.
+#
+# The default value is `move`.
+quick-terminal-space-behavior = move
+
+# Whether to enable shell integration auto-injection or not. Shell integration
+# greatly enhances the terminal experience by enabling a number of features:
+#
+# * Working directory reporting so new tabs, splits inherit the
+# previous terminal's working directory.
+#
+# * Prompt marking that enables the "jump_to_prompt" keybinding.
+#
+# * If you're sitting at a prompt, closing a terminal will not ask
+# for confirmation.
+#
+# * Resizing the window with a complex prompt usually paints much
+# better.
+#
+# Allowable values are:
+#
+# * `none` - Do not do any automatic injection. You can still manually
+# configure your shell to enable the integration.
+#
+# * `detect` - Detect the shell based on the filename.
+#
+# * `bash`, `elvish`, `fish`, `zsh` - Use this specific shell injection scheme.
+#
+# The default value is `detect`.
+shell-integration = detect
+
+# Shell integration features to enable. These require our shell integration
+# to be loaded, either automatically via shell-integration or manually.
+#
+# The format of this is a list of features to enable separated by commas. If
+# you prefix a feature with `no-` then it is disabled. If you omit a feature,
+# its default value is used, so you must explicitly disable features you don't
+# want. You can also use `true` or `false` to turn all features on or off.
+#
+# Available features:
+#
+# * `cursor` - Set the cursor to a blinking bar at the prompt.
+#
+# * `sudo` - Set sudo wrapper to preserve terminfo.
+#
+# * `title` - Set the window title via shell integration.
+#
+# Example: `cursor`, `no-cursor`, `sudo`, `no-sudo`, `title`, `no-title`
+shell-integration-features = cursor,no-sudo,title
+
+# Sets the reporting format for OSC sequences that request color information.
+# Ghostty currently supports OSC 10 (foreground), OSC 11 (background), and
+# OSC 4 (256 color palette) queries, and by default the reported values
+# are scaled-up RGB values, where each component are 16 bits. This is how
+# most terminals report these values. However, some legacy applications may
+# require 8-bit, unscaled, components. We also support turning off reporting
+# altogether. The components are lowercase hex values.
+#
+# Allowable values are:
+#
+# * `none` - OSC 4/10/11 queries receive no reply
+#
+# * `8-bit` - Color components are return unscaled, e.g. `rr/gg/bb`
+#
+# * `16-bit` - Color components are returned scaled, e.g. `rrrr/gggg/bbbb`
+#
+# The default value is `16-bit`.
+osc-color-report-format = 16-bit
+
+# If true, allows the "KAM" mode (ANSI mode 2) to be used within
+# the terminal. KAM disables keyboard input at the request of the
+# application. This is not a common feature and is not recommended
+# to be enabled. This will not be documented further because
+# if you know you need KAM, you know. If you don't know if you
+# need KAM, you don't need it.
+vt-kam-allowed = false
+
+# Custom shaders to run after the default shaders. This is a file path
+# to a GLSL-syntax shader for all platforms.
+#
+# Warning: Invalid shaders can cause Ghostty to become unusable such as by
+# causing the window to be completely black. If this happens, you can
+# unset this configuration to disable the shader.
+#
+# On Linux, this requires OpenGL 4.2. Ghostty typically only requires
+# OpenGL 3.3, but custom shaders push that requirement up to 4.2.
+#
+# The shader API is identical to the Shadertoy API: you specify a `mainImage`
+# function and the available uniforms match Shadertoy. The iChannel0 uniform
+# is a texture containing the rendered terminal screen.
+#
+# If the shader fails to compile, the shader will be ignored. Any errors
+# related to shader compilation will not show up as configuration errors
+# and only show up in the log, since shader compilation happens after
+# configuration loading on the dedicated render thread. For interactive
+# development, use [shadertoy.com](https://shadertoy.com).
+#
+# This can be repeated multiple times to load multiple shaders. The shaders
+# will be run in the order they are specified.
+#
+# Changing this value at runtime and reloading the configuration will only
+# affect new windows, tabs, and splits.
+custom-shader =
+
+# If `true` (default), the focused terminal surface will run an animation
+# loop when custom shaders are used. This uses slightly more CPU (generally
+# less than 10%) but allows the shader to animate. This only runs if there
+# are custom shaders and the terminal is focused.
+#
+# If this is set to `false`, the terminal and custom shader will only render
+# when the terminal is updated. This is more efficient but the shader will
+# not animate.
+#
+# This can also be set to `always`, which will always run the animation
+# loop regardless of whether the terminal is focused or not. The animation
+# loop will still only run when custom shaders are used. Note that this
+# will use more CPU per terminal surface and can become quite expensive
+# depending on the shader and your terminal usage.
+#
+# This value can be changed at runtime and will affect all currently
+# open terminals.
+custom-shader-animation = true
+
+# Control the in-app notifications that Ghostty shows.
+#
+# On Linux (GTK) with Adwaita, in-app notifications show up as toasts. Toasts
+# appear overlaid on top of the terminal window. They are used to show
+# information that is not critical but may be important.
+#
+# Possible notifications are:
+#
+# - `clipboard-copy` (default: true) - Show a notification when text is copied
+# to the clipboard.
+#
+# To specify a notification to enable, specify the name of the notification.
+# To specify a notification to disable, prefix the name with `no-`. For
+# example, to disable `clipboard-copy`, set this configuration to
+# `no-clipboard-copy`. To enable it, set this configuration to `clipboard-copy`.
+#
+# Multiple notifications can be enabled or disabled by separating them
+# with a comma.
+#
+# A value of "false" will disable all notifications. A value of "true" will
+# enable all notifications.
+#
+# This configuration only applies to GTK with Adwaita enabled.
+app-notifications = clipboard-copy
+
+# If anything other than false, fullscreen mode on macOS will not use the
+# native fullscreen, but make the window fullscreen without animations and
+# using a new space. It's faster than the native fullscreen mode since it
+# doesn't use animations.
+#
+# Important: tabs DO NOT WORK in this mode. Non-native fullscreen removes
+# the titlebar and macOS native tabs require the titlebar. If you use tabs,
+# you should not use this mode.
+#
+# If you fullscreen a window with tabs, the currently focused tab will
+# become fullscreen while the others will remain in a separate window in
+# the background. You can switch to that window using normal window-switching
+# keybindings such as command+tilde. When you exit fullscreen, the window
+# will return to the tabbed state it was in before.
+#
+# Allowable values are:
+#
+# * `visible-menu` - Use non-native macOS fullscreen, keep the menu bar visible
+# * `true` - Use non-native macOS fullscreen, hide the menu bar
+# * `false` - Use native macOS fullscreen
+#
+# Changing this option at runtime works, but will only apply to the next
+# time the window is made fullscreen. If a window is already fullscreen,
+# it will retain the previous setting until fullscreen is exited.
+macos-non-native-fullscreen = false
+
+# The style of the macOS titlebar. Available values are: "native",
+# "transparent", "tabs", and "hidden".
+#
+# The "native" style uses the native macOS titlebar with zero customization.
+# The titlebar will match your window theme (see `window-theme`).
+#
+# The "transparent" style is the same as "native" but the titlebar will
+# be transparent and allow your window background color to come through.
+# This makes a more seamless window appearance but looks a little less
+# typical for a macOS application and may not work well with all themes.
+#
+# The "transparent" style will also update in real-time to dynamic
+# changes to the window background color, e.g. via OSC 11. To make this
+# more aesthetically pleasing, this only happens if the terminal is
+# a window, tab, or split that borders the top of the window. This
+# avoids a disjointed appearance where the titlebar color changes
+# but all the topmost terminals don't match.
+#
+# The "tabs" style is a completely custom titlebar that integrates the
+# tab bar into the titlebar. This titlebar always matches the background
+# color of the terminal. There are some limitations to this style:
+# On macOS 13 and below, saved window state will not restore tabs correctly.
+# macOS 14 does not have this issue and any other macOS version has not
+# been tested.
+#
+# The "hidden" style hides the titlebar. Unlike `window-decoration = false`,
+# however, it does not remove the frame from the window or cause it to have
+# squared corners. Changing to or from this option at run-time may affect
+# existing windows in buggy ways.
+#
+# When "hidden", the top titlebar area can no longer be used for dragging
+# the window. To drag the window, you can use option+click on the resizable
+# areas of the frame to drag the window. This is a standard macOS behavior
+# and not something Ghostty enables.
+#
+# The default value is "transparent". This is an opinionated choice
+# but its one I think is the most aesthetically pleasing and works in
+# most cases.
+#
+# Changing this option at runtime only applies to new windows.
+macos-titlebar-style = transparent
+
+# Whether the proxy icon in the macOS titlebar is visible. The proxy icon
+# is the icon that represents the folder of the current working directory.
+# You can see this very clearly in the macOS built-in Terminal.app
+# titlebar.
+#
+# The proxy icon is only visible with the native macOS titlebar style.
+#
+# Valid values are:
+#
+# * `visible` - Show the proxy icon.
+# * `hidden` - Hide the proxy icon.
+#
+# The default value is `visible`.
+#
+# This setting can be changed at runtime and will affect all currently
+# open windows but only after their working directory changes again.
+# Therefore, to make this work after changing the setting, you must
+# usually `cd` to a different directory, open a different file in an
+# editor, etc.
+macos-titlebar-proxy-icon = visible
+
+# macOS doesn't have a distinct "alt" key and instead has the "option"
+# key which behaves slightly differently. On macOS by default, the
+# option key plus a character will sometimes produces a Unicode character.
+# For example, on US standard layouts option-b produces "∫". This may be
+# undesirable if you want to use "option" as an "alt" key for keybindings
+# in terminal programs or shells.
+#
+# This configuration lets you change the behavior so that option is treated
+# as alt.
+#
+# The default behavior (unset) will depend on your active keyboard
+# layout. If your keyboard layout is one of the keyboard layouts listed
+# below, then the default value is "true". Otherwise, the default
+# value is "false". Keyboard layouts with a default value of "true" are:
+#
+# - U.S. Standard
+# - U.S. International
+#
+# Note that if an *Option*-sequence doesn't produce a printable character, it
+# will be treated as *Alt* regardless of this setting. (e.g. `alt+ctrl+a`).
+#
+# Explicit values that can be set:
+#
+# If `true`, the *Option* key will be treated as *Alt*. This makes terminal
+# sequences expecting *Alt* to work properly, but will break Unicode input
+# sequences on macOS if you use them via the *Alt* key.
+#
+# You may set this to `false` to restore the macOS *Alt* key unicode
+# sequences but this will break terminal sequences expecting *Alt* to work.
+#
+# The values `left` or `right` enable this for the left or right *Option*
+# key, respectively.
+#
+# This does not work with GLFW builds.
+macos-option-as-alt =
+
+# Whether to enable the macOS window shadow. The default value is true.
+# With some window managers and window transparency settings, you may
+# find false more visually appealing.
+macos-window-shadow = true
+
+# If true, Ghostty on macOS will automatically enable the "Secure Input"
+# feature when it detects that a password prompt is being displayed.
+#
+# "Secure Input" is a macOS security feature that prevents applications from
+# reading keyboard events. This can always be enabled manually using the
+# `Ghostty > Secure Keyboard Entry` menu item.
+#
+# Note that automatic password prompt detection is based on heuristics
+# and may not always work as expected. Specifically, it does not work
+# over SSH connections, but there may be other cases where it also
+# doesn't work.
+#
+# A reason to disable this feature is if you find that it is interfering
+# with legitimate accessibility software (or software that uses the
+# accessibility APIs), since secure input prevents any application from
+# reading keyboard events.
+macos-auto-secure-input = true
+
+# If true, Ghostty will show a graphical indication when secure input is
+# enabled. This indication is generally recommended to know when secure input
+# is enabled.
+#
+# Normally, secure input is only active when a password prompt is displayed
+# or it is manually (and typically temporarily) enabled. However, if you
+# always have secure input enabled, the indication can be distracting and
+# you may want to disable it.
+macos-secure-input-indication = true
+
+# Customize the macOS app icon.
+#
+# This only affects the icon that appears in the dock, application
+# switcher, etc. This does not affect the icon in Finder because
+# that is controlled by a hardcoded value in the signed application
+# bundle and can't be changed at runtime. For more details on what
+# exactly is affected, see the `NSApplication.icon` Apple documentation;
+# that is the API that is being used to set the icon.
+#
+# Valid values:
+#
+# * `official` - Use the official Ghostty icon.
+# * `custom-style` - Use the official Ghostty icon but with custom
+# styles applied to various layers. The custom styles must be
+# specified using the additional `macos-icon`-prefixed configurations.
+# The `macos-icon-ghost-color` and `macos-icon-screen-color`
+# configurations are required for this style.
+#
+# WARNING: The `custom-style` option is _experimental_. We may change
+# the format of the custom styles in the future. We're still finalizing
+# the exact layers and customization options that will be available.
+#
+# Other caveats:
+#
+# * The icon in the update dialog will always be the official icon.
+# This is because the update dialog is managed through a
+# separate framework and cannot be customized without significant
+# effort.
+#
+macos-icon = official
+
+# The material to use for the frame of the macOS app icon.
+#
+# Valid values:
+#
+# * `aluminum` - A brushed aluminum frame. This is the default.
+# * `beige` - A classic 90's computer beige frame.
+# * `plastic` - A glossy, dark plastic frame.
+# * `chrome` - A shiny chrome frame.
+#
+# This only has an effect when `macos-icon` is set to `custom-style`.
+macos-icon-frame = aluminum
+
+# The color of the ghost in the macOS app icon.
+#
+# Note: This configuration is required when `macos-icon` is set to
+# `custom-style`.
+#
+# This only has an effect when `macos-icon` is set to `custom-style`.
+#
+# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+macos-icon-ghost-color =
+
+# The color of the screen in the macOS app icon.
+#
+# The screen is a gradient so you can specify multiple colors that
+# make up the gradient. Comma-separated colors may be specified as
+# as either hex (`#RRGGBB` or `RRGGBB`) or as named X11 colors.
+#
+# Note: This configuration is required when `macos-icon` is set to
+# `custom-style`.
+#
+# This only has an effect when `macos-icon` is set to `custom-style`.
+macos-icon-screen-color =
+
+# Put every surface (tab, split, window) into a dedicated Linux cgroup.
+#
+# This makes it so that resource management can be done on a per-surface
+# granularity. For example, if a shell program is using too much memory,
+# only that shell will be killed by the oom monitor instead of the entire
+# Ghostty process. Similarly, if a shell program is using too much CPU,
+# only that surface will be CPU-throttled.
+#
+# This will cause startup times to be slower (a hundred milliseconds or so),
+# so the default value is "single-instance." In single-instance mode, only
+# one instance of Ghostty is running (see gtk-single-instance) so the startup
+# time is a one-time cost. Additionally, single instance Ghostty is much
+# more likely to have many windows, tabs, etc. so cgroup isolation is a
+# big benefit.
+#
+# This feature requires systemd. If systemd is unavailable, cgroup
+# initialization will fail. By default, this will not prevent Ghostty
+# from working (see linux-cgroup-hard-fail).
+#
+# Valid values are:
+#
+# * `never` - Never use cgroups.
+# * `always` - Always use cgroups.
+# * `single-instance` - Enable cgroups only for Ghostty instances launched
+# as single-instance applications (see gtk-single-instance).
+#
+linux-cgroup = single-instance
+
+# Memory limit for any individual terminal process (tab, split, window,
+# etc.) in bytes. If this is unset then no memory limit will be set.
+#
+# Note that this sets the "memory.high" configuration for the memory
+# controller, which is a soft limit. You should configure something like
+# systemd-oom to handle killing processes that have too much memory
+# pressure.
+linux-cgroup-memory-limit =
+
+# Number of processes limit for any individual terminal process (tab, split,
+# window, etc.). If this is unset then no limit will be set.
+#
+# Note that this sets the "pids.max" configuration for the process number
+# controller, which is a hard limit.
+linux-cgroup-processes-limit =
+
+# If this is false, then any cgroup initialization (for linux-cgroup)
+# will be allowed to fail and the failure is ignored. This is useful if
+# you view cgroup isolation as a "nice to have" and not a critical resource
+# management feature, because Ghostty startup will not fail if cgroup APIs
+# fail.
+#
+# If this is true, then any cgroup initialization failure will cause
+# Ghostty to exit or new surfaces to not be created.
+#
+# Note: This currently only affects cgroup initialization. Subprocesses
+# must always be able to move themselves into an isolated cgroup.
+linux-cgroup-hard-fail = false
+
+# Enable or disable GTK's OpenGL debugging logs. The default is `true` for
+# debug builds, `false` for all others.
+gtk-opengl-debug = false
+
+# After GTK 4.14.0, we need to force the GSK renderer to OpenGL as the default
+# GSK renderer is broken on some systems. If you would like to override
+# that bekavior, set `gtk-gsk-renderer=default` and either use your system's
+# default GSK renderer, or set the GSK_RENDERER environment variable to your
+# renderer of choice before launching Ghostty. This setting has no effect when
+# using versions of GTK earlier than 4.14.0.
+gtk-gsk-renderer = opengl
+
+# If `true`, the Ghostty GTK application will run in single-instance mode:
+# each new `ghostty` process launched will result in a new window if there is
+# already a running process.
+#
+# If `false`, each new ghostty process will launch a separate application.
+#
+# The default value is `desktop` which will default to `true` if Ghostty
+# detects that it was launched from the `.desktop` file such as an app
+# launcher (like Gnome Shell) or by D-Bus activation. If Ghostty is launched
+# from the command line, it will default to `false`.
+#
+# Note that debug builds of Ghostty have a separate single-instance ID
+# so you can test single instance without conflicting with release builds.
+gtk-single-instance = desktop
+
+# When enabled, the full GTK titlebar is displayed instead of your window
+# manager's simple titlebar. The behavior of this option will vary with your
+# window manager.
+#
+# This option does nothing when `window-decoration` is false or when running
+# under macOS.
+#
+# Changing this value at runtime and reloading the configuration will only
+# affect new windows.
+gtk-titlebar = false
+
+# Determines the side of the screen that the GTK tab bar will stick to.
+# Top, bottom, left, right, and hidden are supported. The default is top.
+#
+# If this option has value `left` or `right` when using Adwaita, it falls
+# back to `top`. `hidden`, meaning that tabs don't exist, is not supported
+# without using Adwaita, falling back to `top`.
+#
+# When `hidden` is set and Adwaita is enabled, a tab button displaying the
+# number of tabs will appear in the title bar. It has the ability to open a
+# tab overview for displaying tabs. Alternatively, you can use the
+# `toggle_tab_overview` action in a keybind if your window doesn't have a
+# title bar, or you can switch tabs with keybinds.
+gtk-tabs-location = top
+
+# If this is `true`, the titlebar will be hidden when the window is maximized,
+# and shown when the titlebar is unmaximized. GTK only.
+gtk-titlebar-hide-when-maximized = false
+
+# Determines the appearance of the top and bottom bars when using the
+# Adwaita tab bar. This requires `gtk-adwaita` to be enabled (it is
+# by default).
+#
+# Valid values are:
+#
+# * `flat` - Top and bottom bars are flat with the terminal window.
+# * `raised` - Top and bottom bars cast a shadow on the terminal area.
+# * `raised-border` - Similar to `raised` but the shadow is replaced with a
+# more subtle border.
+#
+# Changing this value at runtime will only affect new windows.
+adw-toolbar-style = raised
+
+# If `true` (default), then the Ghostty GTK tabs will be "wide." Wide tabs
+# are the new typical Gnome style where tabs fill their available space.
+# If you set this to `false` then tabs will only take up space they need,
+# which is the old style.
+gtk-wide-tabs = true
+
+# If `true` (default), Ghostty will enable Adwaita theme support. This
+# will make `window-theme` work properly and will also allow Ghostty to
+# properly respond to system theme changes, light/dark mode changing, etc.
+# This requires a GTK4 desktop with a GTK4 theme.
+#
+# If you are running GTK3 or have a GTK3 theme, you may have to set this
+# to false to get your theme picked up properly. Having this set to true
+# with GTK3 should not cause any problems, but it may not work exactly as
+# expected.
+#
+# This configuration only has an effect if Ghostty was built with
+# Adwaita support.
+gtk-adwaita = true
+
+# Custom CSS files to be loaded.
+#
+# This configuration can be repeated multiple times to load multiple files.
+# Prepend a ? character to the file path to suppress errors if the file does
+# not exist. If you want to include a file that begins with a literal ?
+# character, surround the file path in double quotes (").
+# The file size limit for a single stylesheet is 5MiB.
+gtk-custom-css =
+
+# If `true` (default), applications running in the terminal can show desktop
+# notifications using certain escape sequences such as OSC 9 or OSC 777.
+desktop-notifications = true
+
+# If `true`, the bold text will use the bright color palette.
+bold-is-bright = true
+
+# This will be used to set the `TERM` environment variable.
+# HACK: We set this with an `xterm` prefix because vim uses that to enable key
+# protocols (specifically this will enable `modifyOtherKeys`), among other
+# features. An option exists in vim to modify this: `:set
+# keyprotocol=ghostty:kitty`, however a bug in the implementation prevents it
+# from working properly. https://github.com/vim/vim/pull/13211 fixes this.
+term = xterm-ghostty
+
+# String to send when we receive `ENQ` (`0x05`) from the command that we are
+# running. Defaults to an empty string if not set.
+enquiry-response =
+
+# Control the auto-update functionality of Ghostty. This is only supported
+# on macOS currently, since Linux builds are distributed via package
+# managers that are not centrally controlled by Ghostty.
+#
+# Checking or downloading an update does not send any information to
+# the project beyond standard network information mandated by the
+# underlying protocols. To put it another way: Ghostty doesn't explicitly
+# add any tracking to the update process. The update process works by
+# downloading information about the latest version and comparing it
+# client-side to the current version.
+#
+# Valid values are:
+#
+# * `off` - Disable auto-updates.
+# * `check` - Check for updates and notify the user if an update is
+# available, but do not automatically download or install the update.
+# * `download` - Check for updates, automatically download the update,
+# notify the user, but do not automatically install the update.
+#
+# If unset, we defer to Sparkle's default behavior, which respects the
+# preference stored in the standard user defaults (`defaults(1)`).
+#
+# Changing this value at runtime works after a small delay.
+auto-update =
+
+# The release channel to use for auto-updates.
+#
+# The default value of this matches the release channel of the currently
+# running Ghostty version. If you download a pre-release version of Ghostty
+# then this will be set to `tip` and you will receive pre-release updates.
+# If you download a stable version of Ghostty then this will be set to
+# `stable` and you will receive stable updates.
+#
+# Valid values are:
+#
+# * `stable` - Stable, tagged releases such as "1.0.0".
+# * `tip` - Pre-release versions generated from each commit to the
+# main branch. This is the version that was in use during private
+# beta testing by thousands of people. It is generally stable but
+# will likely have more bugs than the stable channel.
+#
+# Changing this configuration requires a full restart of
+# Ghostty to take effect.
+#
+# This only works on macOS since only macOS has an auto-update feature.
+auto-update-channel =
+
diff --git a/config/git/config b/config/git/config
new file mode 100644
index 00000000..f6acb8e9
--- /dev/null
+++ b/config/git/config
@@ -0,0 +1,56 @@
+[user]
+ email = dev@kristofers.xyz
+ name = Kristofers Solo
+[init]
+ defaultBranch = main
+[core]
+ editor = nvim
+
+# https://blog.gitbutler.com/how-git-core-devs-configure-git/
+# clearly makes git better
+[column]
+ ui = auto
+[branch]
+ sort = -committerdate
+[tag]
+ sort = version:refname
+[diff]
+ algorithm = histogram
+ colorMoved = plain
+ mnemonicPrefix = true
+ renames = true
+[push]
+ default = simple
+ autoSetupRemote = true
+ followTags = true
+[fetch]
+ prune = true
+ pruneTags = true
+ all = true
+
+# why the hell not?
+
+[help]
+ autocorrect = prompt
+[commit]
+ verbose = true
+[rerere]
+ enabled = true
+ autoupdate = true
+[core]
+ excludesfile = ~/.gitignore
+[rebase]
+ autoSquash = true
+ autoStash = true
+ updateRefs = true
+
+# a matter of taste (uncomment if you dare)
+
+[core]
+ # fsmonitor = true
+ # untrackedCache = true
+[merge]
+ # (just 'diff3' if git version < 2.3)
+ # conflictstyle = zdiff3
+[pull]
+ # rebase = true
diff --git a/config/hypr/hyprland.conf b/config/hypr/hyprland.conf
index 125ecd65..50aaa38f 100644
--- a/config/hypr/hyprland.conf
+++ b/config/hypr/hyprland.conf
@@ -1,4 +1,4 @@
-# This is an example Hyprland config file.
+# This is an example Hyprland config file.hypr
# Refer to the wiki for more information.
# https://wiki.hyprland.org/Configuring/
@@ -15,8 +15,9 @@
################
# See https://wiki.hyprland.org/Configuring/Monitors/
-monitor=eDP-1,prefered,auto,1.5
-monitor=DP-1,prefered,auto,1
+monitor=eDP-1,prefered,0x0,1
+monitor=DP-1,prefered,180x-1440,1
+# monitor=DP-1,disabled
###################
### MY PROGRAMS ###
@@ -30,7 +31,6 @@ $fileManager = $terminal -e yazi
$menu = wofi --show drun -ib
$browser = zen-browser
-
#################
### AUTOSTART ###
#################
@@ -38,8 +38,8 @@ $browser = zen-browser
# 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=nextcloud & /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & xrdb "$XDG_CONFIG_HOME/x11/xresources" & transmission-daemon & dunst & hyprpaper
+exec-once=pipewire & pipewire-pulse & wireplumber & 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 & hyprland-per-window-layout
exec-once=[workspace 1 silent] $browser
exec-once=[workspace 8 silent] vesktop & kotatogram-desktop
exec-once=[workspace 9 silent] spotify-launcher
@@ -55,6 +55,11 @@ source=~/.config/hypr/rose-pine.conf
env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24
+# env = DBUS_SESSION_BUS_ADDRESS,unix:path=/run/user/1000/bus
+env = XDG_CURRENT_DESKTOP,Hyprland
+env = XDG_SESSION_TYPE,wayland
+env = XDG_SESSION_DESKTOP,Hyprland
+env = WM,Hyprland
#####################
@@ -218,11 +223,12 @@ bind = $mainMod SHIFT, Q, killactive
bind = $mainMod, N, exec, $fileManager
bind = $mainMod CTRL, SPACE, togglefloating
bind = $mainMod, P, exec, $menu
+bind = $mainMod SHIFT, P, exec, cliphist list | wofi -S dmenu | cliphist decode | wl-copy
bind = $mainMod, F, fullscreen
bind = $mainMod, M, bringactivetotop
bind = $mainMod, A, pin
bind = $mainMod, B, exec, $browser
-#bind = $mainMod, O, split-changemonitor, +1
+# bind = $mainMod, O, split-changemonitor, +1
# bind = $mainMod, P, pseudo, # dwindle
# bind = $mainMod, J, togglesplit, # dwindle
@@ -254,6 +260,16 @@ bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
+# bind = $mainMod, 1, split-workspace, 1
+# bind = $mainMod, 2, split-workspace, 2
+# bind = $mainMod, 3, split-workspace, 3
+# bind = $mainMod, 4, split-workspace, 4
+# bind = $mainMod, 5, split-workspace, 5
+# bind = $mainMod, 6, split-workspace, 6
+# bind = $mainMod, 7, split-workspace, 7
+# bind = $mainMod, 8, split-workspace, 8
+# bind = $mainMod, 9, split-workspace, 9
+# bind = $mainMod, 0, split-workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspace, 1
@@ -266,6 +282,16 @@ bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
+# bind = $mainMod SHIFT, 1, split-movetoworkspace, 1
+# bind = $mainMod SHIFT, 2, split-movetoworkspace, 2
+# bind = $mainMod SHIFT, 3, split-movetoworkspace, 3
+# bind = $mainMod SHIFT, 4, split-movetoworkspace, 4
+# bind = $mainMod SHIFT, 5, split-movetoworkspace, 5
+# bind = $mainMod SHIFT, 6, split-movetoworkspace, 6
+# bind = $mainMod SHIFT, 7, split-movetoworkspace, 7
+# bind = $mainMod SHIFT, 8, split-movetoworkspace, 8
+# bind = $mainMod SHIFT, 9, split-movetoworkspace, 9
+# bind = $mainMod SHIFT, 0, split-movetoworkspace, 10
# Example special workspace (scratchpad)
# bind = $mainMod, S, togglespecialworkspace, magic
@@ -305,12 +331,13 @@ bindl = , XF86AudioPrev, exec, playerctl previous
bindel = , XF86AudioPlay, exec, playerctl -a play-pause # pause/play everything
bindel = $mainMod, Space, exec, hyprlock
+bindl = , switch:[Lid Switch], exec, hyprlock
# bind = $mainMod CTRL, P, exec, wayshot -f "$(HOME)/Pictures/screenshots/$(date + '%s.png')" -s "$(slurp -f '%x %y %w %y')" --stdout | wl-copy
# bind = $mainMod CTRL, P, exec, wayshot -s "$(slurp -f '%x %y %w %y')" --stdout | wl-copy
# bind = $mainMod, , exec, wayshot -f "$(HOME)/Pictures/screenshots/$(date + '%s.png')"
bind = CTRL, PRINT, exec, hyprshot -m region
-bind = , PRINT, exec, hyprshot -m output
+bind = , PRINT, exec, hyprshot -m output
bind = SHIFT, PRINT, exec, hyprshot -m window
bind = $mainMod ALT, P, exec, hyprpicker -a # colorpicker
@@ -356,9 +383,13 @@ windowrulev2 = opacity 0.9, class:teams-for-linux
windowrulev2 = workspace 5, class:Ferdium
windowrulev2 = opacity 0.9, class:Ferdium
+windowrulev2 = workspace 9, class:com.github.wwmm.easyeffects
windowrulev2 = workspace 9, class:Spotify
windowrulev2 = opacity 0.9, class:Spotify
-windowrulev2 = tile, class:Spotify
+# windowrulev2 = tile, class:Spotify
+# https://github.com/alexhulbert/Hyprchroma
+# windowrulev2 = plugin:chromakey, class:Spotify
+# chromakey_background = 7,8,17
windowrulev2 = opacity 0.95, class:qbittorrent
windowrulev2 = opacity 0.95, class:lutris
@@ -374,4 +405,3 @@ 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 22d0a6aa..06b61a1a 100644
--- a/config/hypr/hyprlock.conf
+++ b/config/hypr/hyprlock.conf
@@ -1,15 +1,25 @@
$font = JetBrainsMonoNF
-$bg = rgb(1a1b26)
-$fg = rgb(c0caf5)
-$border_highlight = rgb(27a1b9)
-$error = rgb(db4b4b)
-$warning = rgb(e0af68)
+$base = rgb(191724)
+$surface = rgb(1f1d2e)
+$overlay = rgb(26233a)
+$muted = rgb(6e6a86)
+$subtle = rgb(908caa)
+$text = rgb(e0def4)
+$love = rgb(eb6f92)
+$gold = rgb(f6c177)
+$rose = rgb(ebbcba)
+$pine = rgb(31748f)
+$foam = rgb(9ccfd8)
+$iris = rgb(c4a7e7)
+$highlight_low = rgb(21202e)
+$highlight_med = rgb(403d52)
+$highlight_high = rgb(524f67)
background {
monitor =
path = screenshot
- color = $bg
+ color = $base
blur_passes = 1
blur_size = 10
@@ -23,7 +33,7 @@ background {
# TIME
label {
monitor =
- text = cmd[update:1000] echo "$(date +"%H:%M:%S")"
+ text = cmd[update:1000] echo "$(date +"%H:%M:%S")"
color = $text
font_size = 90
font_family = $font
@@ -32,10 +42,10 @@ label {
valign = top
}
-# DATE
+# DATE
label {
- monitor =
- text = cmd[update:43200000] echo "$(date +"%d.%m.%Y")"
+ monitor =
+ text = cmd[update:43200000] echo "$(date +"%d.%m.%Y")"
color = $text
font_size = 25
font_family = $font
@@ -46,10 +56,10 @@ label {
image {
- monitor =
+ monitor =
path = ~/.local/share/profile
size = 300
- border_color = $border_highlight
+ border_color = $pine
position = 0, 200
halign = center
@@ -59,21 +69,21 @@ image {
input-field {
monitor =
size = 300, 60
- outline_thickness = 4
+ outline_thickness = 3
dots_size = 0.2
dots_spacing = 0.2
dots_center = true
dots_rounding = -1 # -1 default circle, -2 follow input-field rounding
- outer_color = $border_highlight
- inner_color = $fg
- font_color = $bg
+ outer_color = $pine
+ inner_color = $text
+ font_color = $base
fade_on_empty = true
fade_timeout = 1000 # Milliseconds before fade_on_empty is triggered.
placeholder_text = Input Password... # Text rendered in the input box when it's empty.
hide_input = false
rounding = -1 # -1 means complete rounding (circle/oval)
- check_color = rgb(e0af68)
- fail_color = rgb(db4b4b) # if authentication failed, changes outer_color and fail message color
+ check_color = $gold
+ fail_color = $love # if authentication failed, changes outer_color and fail message color
fail_text = $FAIL ($ATTEMPTS) # can be set to empty
fail_transition = 300 # transition time in ms between normal outer_color and fail_color
capslock_color = -1
diff --git a/config/hypr/hyprpaper.conf b/config/hypr/hyprpaper.conf
index 972e965d..7329a7bd 100644
--- a/config/hypr/hyprpaper.conf
+++ b/config/hypr/hyprpaper.conf
@@ -2,5 +2,6 @@ ipc = off
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
-wallpaper = ,~/Pictures/wallpapers/Linux-Dynamic-Wallpapers/LakesideDeerComplete/LakesideDeer-03.png
+wallpaper = ,~/Pictures/wallpapers/abstract/GDWP-789-4K-No-Logo.jpg
diff --git a/config/lf/cleaner b/config/lf/cleaner
old mode 100755
new mode 100644
diff --git a/config/lf/lfrc b/config/lf/lfrc
old mode 100755
new mode 100644
diff --git a/config/nsxiv/exec/image-info b/config/nsxiv/exec/image-info
old mode 100755
new mode 100644
diff --git a/config/nsxiv/exec/key-handler b/config/nsxiv/exec/key-handler
old mode 100755
new mode 100644
diff --git a/config/nsxiv/exec/nsxiv-url b/config/nsxiv/exec/nsxiv-url
old mode 100755
new mode 100644
diff --git a/config/nsxiv/exec/thumb-info b/config/nsxiv/exec/thumb-info
old mode 100755
new mode 100644
diff --git a/config/nsxiv/exec/win-title b/config/nsxiv/exec/win-title
old mode 100755
new mode 100644
diff --git a/config/shell/env b/config/shell/env
index 7f1d5b2b..f3fb36e9 100644
--- a/config/shell/env
+++ b/config/shell/env
@@ -17,13 +17,12 @@ export LESSHISTFILE=-
export $(dbus-launch)
export LIBSEAT_BACKEND=logind
-# export XDG_RUNTIME_DIR="/run/user/$UID"
unsetopt PROMPT_SP
# Default Apps
-export BROWSER="floorp"
+export BROWSER="zen-browser"
export EDITOR="nvim"
export IMAGE="nsxiv"
export READER="zathura"
@@ -87,8 +86,8 @@ export XAUTHORITY="$XDG_RUNTIME_DIR/Xauthority"
export XCURSOR_PATH="/usr/share/icons:$XDG_DATA_HOME/icons"
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_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"
# Other program settings
export AWT_TOOLKIT="MToolkit wmname LG3D" # May have to install wmname
@@ -112,6 +111,5 @@ export SUDO_ASKPASS="$HOME/.local/bin/dmenupass"
export _JAVA_AWT_WM_NONREPARENTING=1 # Fix for Java applications in dwm
. "$XDG_DATA_HOME/cargo/env"
-. "$XDG_DATA_HOME/rye/env"
. "$XDG_CACHE_HOME/deno/.deno/env"
. "/home/kristofers/.local/share/cargo/env"
diff --git a/config/x11/opt-apps b/config/x11/opt-apps
old mode 100755
new mode 100644
index 64fd4066..199e29bc
--- a/config/x11/opt-apps
+++ b/config/x11/opt-apps
@@ -1,6 +1,6 @@
#!/bin/sh
-autostart="picom nextcloud transmission-daemon zen-browser vesktop syncthing mullvad-vpn spotify-launcher kotatogram-desktop easyeffects"
+autostart="picom nextcloud transmission-daemon zen-browser discord syncthing mullvad-vpn spotify-launcher kotatogram-desktop easyeffects"
for program in $autostart; do
pidof -sx "$program" || "$program" &
diff --git a/config/yazi/keymap.toml b/config/yazi/keymap.toml
index 04dfb064..4d63736f 100644
--- a/config/yazi/keymap.toml
+++ b/config/yazi/keymap.toml
@@ -41,8 +41,8 @@ keymap = [
{on = [ "" ], run = "seek -5", desc = "Seek up 5 units in the preview"},
{on = [ "" ], run = "seek 5", desc = "Seek down 5 units in the preview"},
- {on = [ "g", "g" ], run = "arrow -99999999", desc = "Move cursor to the top"},
- {on = [ "G" ], run = "arrow 99999999", desc = "Move cursor to the bottom"},
+ {on = [ "g", "g" ], run = "arrow top", desc = "Move cursor to the top"},
+ {on = [ "G" ], run = "arrow bot", desc = "Move cursor to the bottom"},
# Selection
{on = [ "" ], run = [ "toggle --state=none", "arrow 1" ], desc = "Toggle the current selection state"},
diff --git a/config/yazi/package.toml b/config/yazi/package.toml
index 117390ef..ab2d724c 100644
--- a/config/yazi/package.toml
+++ b/config/yazi/package.toml
@@ -1,17 +1,17 @@
[[plugin.deps]]
use = "AnirudhG07/nbpreview"
-rev = "1d85745"
+rev = "f8879b3"
hash = "d378328e5d0a1b9fb9f04ab3aade4575"
[[plugin.deps]]
use = "Reledia/glow"
-rev = "5ce76dc"
-hash = "52e5f5c602962e7cbf874da28f52ba45"
+rev = "c76bf4f"
+hash = "a6b78bf9af5390e3a85a6951fbb7b93"
[[plugin.deps]]
use = "Reledia/hexyl"
-rev = "39d3d4e"
-hash = "dd624cbaff94af65f39fd86bc57b340"
+rev = "228a9ef"
+hash = "cdc65cfe4e60e1bf5afe5769d074fa9c"
[[plugin.deps]]
use = "Reledia/miller"
@@ -25,13 +25,13 @@ hash = "a8e15d3c21c02a5af41d46ed04778a02"
[[plugin.deps]]
use = "dedukun/relative-motions"
-rev = "df97039"
-hash = "395940d2b22941e0acb1232579c9d4cf"
+rev = "a1466a9"
+hash = "26d7fd10e163e0624d733c067eba4b61"
[[plugin.deps]]
use = "hankertrix/augment-command"
-rev = "e337feb"
-hash = "feeb35edcf1677c7bafac2bc573670bb"
+rev = "af31941"
+hash = "71c1ef899b40a54fcdf5a41f87daa967"
[[plugin.deps]]
use = "imsi32/yatline"
@@ -40,13 +40,13 @@ hash = "3e51d1fd8a2e481fcfa8eab1251d1c5f"
[[plugin.deps]]
use = "kirasok/torrent-preview"
-rev = "c9e67df"
-hash = "f0d9a684da8e4ab9ccbcd255a97cf42b"
+rev = "4ca5996"
+hash = "6af40ce6b2cd849b5fa32de04a598b06"
[[plugin.deps]]
use = "ndtoan96/ouch"
-rev = "083d564"
-hash = "1e4c0ac1fca31a23412324710193358a"
+rev = "ce6fb75"
+hash = "ed6c185514109d7c5463f609282b220c"
[[plugin.deps]]
use = "pirafrank/what-size"
@@ -55,28 +55,28 @@ hash = "98e5f5af3efd3ba8bc2db0720187cc83"
[[plugin.deps]]
use = "yazi-rs/plugins:chmod"
-rev = "f202fa8"
-hash = "4c7e8fd0266eedee7b619d966bd2d025"
+rev = "5186af7"
+hash = "f28138c2e11e87962b66d583fef724c3"
[[plugin.deps]]
use = "yazi-rs/plugins:full-border"
-rev = "f202fa8"
-hash = "882ed23839778f82dc137248979c8681"
+rev = "5186af7"
+hash = "ae9e1d0c6bfd68cdebc98cc684c22b45"
[[plugin.deps]]
use = "yazi-rs/plugins:git"
-rev = "f202fa8"
-hash = "4d6a07559118975e2dee983d27474d70"
+rev = "5186af7"
+hash = "771f18427fb75fb19990ce602bb322f4"
[[plugin.deps]]
use = "yazi-rs/plugins:hide-preview"
-rev = "f202fa8"
-hash = "5be5885898ca9df783bdec0d402bf4b0"
+rev = "5186af7"
+hash = "1e31898370b752e4faf335b762b3eeaf"
[[plugin.deps]]
use = "yazi-rs/plugins:max-preview"
-rev = "f202fa8"
-hash = "9bc26d10d2f6e2aa93b10905b1b76979"
+rev = "5186af7"
+hash = "a8025f2bb311e869069364fba01abffc"
[flavor]
deps = []
diff --git a/config/yazi/plugins/augment-command.yazi/README.md b/config/yazi/plugins/augment-command.yazi/README.md
index b4170409..a442af87 100644
--- a/config/yazi/plugins/augment-command.yazi/README.md
+++ b/config/yazi/plugins/augment-command.yazi/README.md
@@ -2,7 +2,7 @@
A [Yazi][yazi-link] plugin that enhances Yazi's default commands.
This plugin is inspired by the
-[Yazi tips page](https://yazi-rs.github.io/docs/tips),
+[Yazi tips page][yazi-tips-page],
the [bypass.yazi](https://github.com/Rolv-Apneseth/bypass.yazi) plugin
and the [fast-enter.yazi](https://github.com/ourongxing/fast-enter.yazi)
plugin.
@@ -20,7 +20,7 @@ plugin.
## Requirements
-- [Yazi](https://github.com/sxyazi/yazi) v0.4.2+
+- [Yazi][yazi-link] v25.2.7+
- [`7z` or `7zz` command][7z-link]
- [`file` command][file-command-link]
@@ -51,6 +51,7 @@ ya pack -u
| `smart_paste` | `true` or `false` | `false` | Paste items into a directory without entering it. The behaviour is exactly the same as the [smart paste tip on Yazi's documentation][smart-paste-tip]. Setting this option to `false` will use the default `paste` behaviour. You can also enable this behaviour by passing the `--smart` flag to the `paste` command. |
| `smart_tab_create` | `true` or `false` | `false` | Create tabs in the directory that is being hovered instead of the current directory. The behaviour is exactly the same as the [smart tab tip on Yazi's documentation][smart-tab-tip]. Setting this option to `false` will use the default `tab_create` behaviour, which means you need to pass the `--current` flag to the command. You can also enable this behaviour by passing the `--smart` flag to the `tab_create` command. |
| `smart_tab_switch` | `true` or `false` | `false` | If the tab that is being switched to does not exist yet, setting this option to `true` will create all the tabs in between the current number of open tabs, and the tab that is being switched to. The behaviour is exactly the same as the [smart switch tip on Yazi's documentation][smart-switch-tip]. Setting this option to `false` will use the default `tab_switch` behaviour. You can also enable this behaviour by passing the `--smart` flag to the `tab_switch` command. |
+| `confirm_on_quit` | `true` or `false` | `true` | Setting this option to `true` will cause Yazi to prompt you for a confirmation before quitting when there is more than 1 tab open. Setting this option to `false` will use the default `quit` behaviour, which is to immediately quit Yazi. You can also enable this behaviour by passing the `--confirm` flag to the `quit` command. |
| `open_file_after_creation` | `true` or `false` | `false` | This option determines whether the plugin will open a file after it has been created. Setting this option to `true` will cause the plugin to open the created file. You can also enable this behaviour by passing the `--open` flag to the `create` command. |
| `enter_directory_after_creation` | `true` or `false` | `false` | This option determines whether the plugin will enter a directory after it has been created. Setting this option to `true` will cause the plugin to enter the created directory. You can also enable this behaviour by passing the `--enter` flag to the `create` command. |
| `use_default_create_behaviour` | `true` or `false` | `false` | This option determines whether the plugin will use the behaviour of Yazi's `create` command. Setting this option to `true` will use the behaviour of Yazi's `create` command. You can also enable this behaviour by passing the `--default-behaviour` flag to the `create` command. |
@@ -65,13 +66,12 @@ ya pack -u
If you would like to use the default configuration, which is shown below,
you don't need to add anything to your `~/.config/yazi/init.lua`
-file on Linux and macOS, or your
-`C:\Users\USERNAME\AppData\Roaming\yazi\config\init.lua`
-file on Windows, where `USERNAME` is your Windows username.
+file on Linux and macOS, or your `%AppData%\yazi\config\init.lua`
+file on Windows.
```lua
-- ~/.config/yazi/init.lua for Linux and macOS
--- C:\Users\USERNAME\AppData\Roaming\yazi\config\init.lua for Windows
+-- %AppData%\yazi\config\init.lua for Windows
-- Using the default configuration
require("augment-command"):setup({
@@ -81,6 +81,7 @@ require("augment-command"):setup({
smart_paste = false,
smart_tab_create = false,
smart_tab_switch = false,
+ confirm_on_quit = true,
open_file_after_creation = false,
enter_directory_after_creation = false,
use_default_create_behaviour = false,
@@ -98,15 +99,14 @@ require("augment-command"):setup({
However, if you would like to configure the plugin, you can add
your desired configuration options to your `~/.config/yazi/init.lua` file
on Linux and macOS, or your
-`C:\Users\USERNAME\AppData\Roaming\yazi\config\init.lua`
-file on Windows, where `USERNAME` is your Windows username.
+`%AppData%\yazi\config\init.lua` file on Windows.
You can leave out configuration options that you would
like to be left as default.
An example configuration is shown below:
```lua
-- ~/.config/yazi/init.lua for Linux and macOS
--- C:\Users\USERNAME\AppData\Roaming\yazi\config\init.lua for Windows
+-- %AppData%\yazi\config\init.lua for Windows
-- Custom configuration
require("augment-command"):setup({
@@ -238,8 +238,7 @@ then it will operate on the selected items.
[`extract` openers section][yazi-yazi-toml-extract-openers]
in [Yazi's default `yazi.toml`][yazi-yazi-toml] into your `yazi.toml`,
which is located at `~/.config/yazi/yazi.toml` for Linux and macOS, and
- `C:\Users\USERNAME\AppData\Roaming\yazi\config\yazi.toml`
- file on Windows, where `USERNAME` is your Windows username.
+ `%AppData%\yazi\config\yazi.toml` file on Windows.
Make sure that the `extract` openers are under the `opener` key in your
`yazi.toml`. Then replace `extract` with `augmented-extract`,
and you will be using the plugin's `extract` command instead of
@@ -249,7 +248,7 @@ then it will operate on the selected items.
```toml
# ~/.config/yazi/yazi.toml for Linux and macOS
- # C:\Users\USERNAME\AppData\Roaming\yazi\config\yazi.toml for Windows
+ # %AppData%\yazi\config\yazi.toml for Windows
[opener]
extract = [
@@ -262,7 +261,7 @@ then it will operate on the selected items.
```toml
# ~/.config/yazi/yazi.toml for Linux and macOS
- # C:\Users\USERNAME\AppData\Roaming\yazi\config\yazi.toml for Windows
+ # %AppData%\yazi\config\yazi.toml for Windows
[[opener.extract]]
run = 'ya pub augmented-extract --list "$@"'
@@ -452,16 +451,7 @@ then it will operate on the selected items.
create directories to ensure that the path given exists.
It also supports all the options supported by Yazi's `create` command,
so you can pass them to the command and expect the same behaviour.
- However, due to the
- [`confirm` component](https://github.com/sxyazi/yazi/issues/2082)
- currently not being exposed to plugin developers, it uses Yazi's input
- component to prompt for a confirmation, like in Yazi v0.3.0 and below.
- This is not ideal, but it shouldn't happen that often and
- hopefully wouldn't be too annoying.
- If you are using the latest version of Yazi from the main branch,
- the `confirm` component is now exposed to plugin developers and
- the plugin will use the `confirm` component instead.
- However, the separator in the `confirm` component will be the text colour
+ Do note that the separator in the `confirm` component will be the text colour
instead of your configured border colour for the `confirm` component as
the `list` part of the `confirm` component has not been exposed to plugin
developers, so the separator is made using text.
@@ -536,43 +526,15 @@ then it will operate on the selected items.
- To use this command, the syntax is exactly the same as the default
`shell` command provided by Yazi. You just provide the command you want and
provide any Yazi shell variable, which is documented
- [here](https://yazi-rs.github.io/docs/configuration/keymap/#manager.shell).
+ [here][yazi-shell-variables].
The plugin will automatically replace the shell variable you give
with the file paths for the item group before executing the command.
-- You will also need to escape the quotes when giving the shell command
- if you use the same quotes to quote the given arguments to the plugin.
- For example, if you pass the arguments to the plugin with double quotes,
- i.e. `--args="shell"`, you will have to escape the double quotes with a
- backslash character, like shown below:
- ```toml
- # ~/.config/yazi/keymap.toml on Linux and macOS
- # C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
-
- [[manager.prepend_keymap]]
- on = [ "o" ]
- run = 'plugin augment-command --args="shell \"$EDITOR $@\" --block"'
- desc = "Open the editor"
- ```
-
-- Alternatively, you can use the triple single quote `'''` delimiter
- for the run string and avoid the escaping the shell command altogether,
- like the two examples below:
-
- ```toml
- # ~/.config/yazi/keymap.toml on Linux and macOS
- # C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
-
- [[manager.prepend_keymap]]
- on = [ "o" ]
- run = '''plugin augment-command --args='shell "$EDITOR $@" --block''''
- desc = "Open the editor"
-
- [[manager.prepend_keymap]]
- on = [ "i" ]
- run = '''plugin augment-command --args="shell '$PAGER $@' --block"'''
- desc = "Open the pager"
- ```
+- There is no need to quote the shell variable on Linux and macOS,
+ as it is expanded by the plugin instead of the shell,
+ and the paths are already quoted using the `ya.quote` function
+ before execution, so quoting is entirely unnecessary
+ and may result in unexpected behaviour.
- `--exit-if-dir` flag to stop the shell command given
from executing if the item group consists only of directories.
@@ -586,11 +548,11 @@ then it will operate on the selected items.
```toml
# ~/.config/yazi/keymap.toml on Linux and macOS
- # C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
+ # %AppData%\yazi\config\keymap.toml on Windows
[[manager.prepend_keymap]]
- on = [ "i" ]
- run = '''plugin augment-command --args="shell '$PAGER $@' --block --exit-if-dir"'''
+ on = "i"
+ run = "plugin augment-command -- shell '$PAGER $@' --block --exit-if-dir"
desc = "Open the pager"
```
@@ -601,18 +563,118 @@ then it will operate on the selected items.
```toml
# ~/.config/yazi/keymap.toml on Linux and macOS
- # C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
+ # %AppData%\yazi\config\keymap.toml on Windows
[[manager.prepend_keymap]]
- on = [ "i" ]
- run = '''plugin augment-command --args="shell '$EDITOR $@' --block --exit-if-dir"'''
- desc = "Open the pager"
+ on = "o"
+ run = "plugin augment-command -- shell '$EDITOR $@' --block --exit-if-dir"
+ desc = "Open the editor"
```
Video:
[shell-exit-if-directory-video]
+#### Passing arguments to the `shell` command
+
+Ideally, you will want to avoid using backslashes to escape the shell command
+arguments, so here are a few ways to do it:
+
+1. Shell arguments that don't have special shell variables
+ on Linux and macOS, like `$SHELL`, or don't have special shell characters
+ like `>`, `|` or spaces, need not be quoted with double quotes `"`
+ or single quotes `'` respectively.
+ For example:
+
+ ```toml
+ # ~/.config/yazi/keymap.toml on Linux and macOS
+ # %AppData%\yazi\config\keymap.toml on Windows
+ [[manager.prepend_keymap]]
+ on = "i"
+ run = "plugin augment-command -- shell --block 'bat -p --pager less $@'"
+ desc = "Open with bat"
+ ```
+
+ Even though the `$@` argument above is considered a shell variable in Linux
+ and macOS, the plugin automatically replaces it with the full path
+ of the items in the item group, so it does not need to be quoted with
+ double quotes `"`, as it is expanded by the plugin,
+ and not meant to be expanded by the shell.
+
+2. If the arguments to the `shell` command have special shell variables
+ on Linux and macOS, like `$SHELL`, or special shell characters like
+ `>`, `|`, or spaces, use `--` to denote the end of the flags and options
+ passed to the `shell` command.
+ For example:
+
+ ```toml
+ # ~/.config/yazi/keymap.toml on Linux and macOS
+ # %AppData%\yazi\config\keymap.toml on Windows
+ [[manager.prepend_keymap]]
+ on = ""
+ run = 'plugin augment-command -- shell --block -- sh -c "$SHELL"'
+ desc = "Open a shell inside of a shell here"
+ ```
+
+ ```toml
+ # ~/.config/yazi/keymap.toml on Linux and macOS
+ # %AppData%\yazi\config\keymap.toml on Windows
+ [[manager.prepend_keymap]]
+ on = ""
+ run = "plugin augment-command -- shell --block -- sh -c 'echo hello'"
+ desc = "Open a shell and say hello inside the opened shell"
+ ```
+
+3. If the arguments passed to the `shell` command themselves contain arguments
+ that have special shell variables on Linux and macOS, like `$SHELL`,
+ or special shell characters like `>`, `|`, or spaces,
+ use the triple single quote `'''` delimiter for the `run` string.
+
+ ```toml
+ # ~/.config/yazi/keymap.toml on Linux and macOS
+ # %AppData%\yazi\config\keymap.toml on Windows
+ [[manager.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"
+ ```
+
+ ```toml
+ # ~/.config/yazi/keymap.toml on Linux and macOS
+ # %AppData%\yazi\config\keymap.toml on Windows
+ [[manager.prepend_keymap]]
+ on = ""
+ run = '''plugin augment-command --
+ shell --block -- sh -c "$SHELL -c 'echo hello'"
+ '''
+ desc = "Open a shell inside of a shell and say hello inside the opened shell"
+ ```
+
+ A more legitimate use case for this would be something like
+ [Yazi's tip to email files using Mozilla Thunderbird][thunderbird-tip]:
+
+ ```toml
+ # ~/.config/yazi/keymap.toml on Linux and macOS
+ # %AppData%\yazi\config\keymap.toml on Windows
+ [[manager.prepend_keymap]]
+ on = ""
+ run = '''plugin augment-command --
+ shell --
+ paths=$(for p in $@; do echo "$p"; done | paste -s -d,)
+ thunderbird -compose "attachment='$paths'"
+ '''
+ desc = "Email files using Mozilla Thunderbird"
+ ```
+
+ Once again, the `$@` variable above does not need to be quoted in double
+ quotes `"` as it is expanded by the plugin instead of the shell.
+
+If the above few methods to avoid using backslashes within your shell command
+to escape the quotes are still insufficient for your use case,
+it is probably more appropriate to write a shell script in a separate file
+and execute that instead of writing the shell command inline
+in your `keymap.toml` file.
+
### Paste (`paste`)
- When `smart_paste` is set to `true`,
@@ -699,6 +761,35 @@ then it will operate on the selected items.
[smart-tab-switch-video]
+### Quit (`quit`)
+
+- You should use Yazi's default `quit` command instead of this augmented
+ command if you don't want to have a prompt when quitting Yazi
+ with multiple tabs open.
+ This command has a visual side effect of showing a confirmation prompt
+ for a split second before closing Yazi when quitting Yazi
+ with only 1 tab open, which can be annoying.
+ This confirmation prompt is due to the plugin still running for a bit
+ after the `quit` command is emitted, causing Yazi to prompt you for
+ confirmation as there are tasks still running.
+ However, once the plugin has stopped running, which is a split second
+ after the `quit` command is emitted, Yazi will exit.
+ You can observe this visual effect in the video demonstration below.
+- When `confirm_on_quit` is set to `true`, the plugin will prompt you for
+ confirmation when there is more than 1 tab open. Otherwise, it will
+ immediately quit Yazi, just like the default `quit` command.
+- `--confirm` flag to get the plugin to prompt you for confirmation when
+ quitting with multiple tabs open.
+ This flag will cause the `quit` command to prompt you for confirmation
+ when quitting with multiple tabs open even when `confirm_on_quit` is
+ set to `false`.
+ This allows you to set a specific key to use this behaviour with the
+ `quit` command instead of using it for every `quit` command.
+
+ Video:
+
+ [quit-with-confirmation-video]
+
### Arrow (`arrow`)
- When `wraparound_file_navigation` is set to `true`,
@@ -738,19 +829,19 @@ then it will operate on the selected items.
```toml
# ~/.config/yazi/keymap.toml on Linux and macOS
- # C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
+ # %AppData%\yazi\config\keymap.toml on Windows
# Use K to move up in the parent directory
[[manager.prepend_keymap]]
- on = [ "K" ]
- run = [ "leave", "arrow -1", "enter" ]
+ 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]]
- on = [ "J" ]
- run = [ "leave", "arrow 1", "enter" ]
+ on = "J"
+ run = ["leave", "arrow 1", "enter"]
desc = "Move down in the parent directory"
```
@@ -815,16 +906,16 @@ then it will operate on the selected items.
Add the commands that you would like to use to your `keymap.toml` file,
located at `~/.config/yazi/keymap.toml` on Linux and macOS
-and at `C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml`
+and at `%AppData%\yazi\config\keymap.toml`
on Windows, in this format:
```toml
# ~/.config/yazi/keymap.toml on Linux and macOS
-# C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
+# %AppData%\yazi\config\keymap.toml on Windows
[[manager.prepend_keymap]]
-on = [ "key" ]
-run = "plugin augment-command --args='command arguments --flags --options=42'"
+on = "key"
+run = "plugin augment-command -- command arguments --flags --options=42"
desc = "Description"
```
@@ -832,11 +923,11 @@ For example, to use the augmented `enter` command:
```toml
# ~/.config/yazi/keymap.toml on Linux and macOS
-# C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
+# %AppData%\yazi\config\keymap.toml on Windows
[[manager.prepend_keymap]]
-on = [ "l" ]
-run = "plugin augment-command --args='enter'"
+on = "l"
+run = "plugin augment-command -- enter"
desc = "Enter a directory and skip directories with only a single subdirectory"
```
@@ -845,33 +936,35 @@ are also supported, for example:
```toml
# ~/.config/yazi/keymap.toml on Linux and macOS
-# C:\Users\USERNAME\AppData\Roaming\yazi\config\keymap.toml on Windows
+# %AppData%\yazi\config\keymap.toml on Windows
[[manager.prepend_keymap]]
-on = [ "k" ]
-run = "plugin augment-command --args='arrow -1'"
+on = "k"
+run = "plugin augment-command -- arrow -1"
desc = "Move cursor up"
[[manager.prepend_keymap]]
-on = [ "r" ]
-run = "plugin augment-command --args='rename --cursor=before_ext'"
+on = "r"
+run = "plugin augment-command -- rename --cursor=before_ext"
desc = "Rename a file or directory"
[[manager.prepend_keymap]]
-on = [ "D" ]
-run = "plugin augment-command --args='remove --permanently'"
+on = "D"
+run = "plugin augment-command -- remove --permanently"
desc = "Permanently delete the files"
+
+[[manager.prepend_keymap]]
+on = ["g", "j"]
+run = "plugin augment-command -- parent_arrow 1"
```
For the default descriptions of the commands, you can refer to
[Yazi's default `keymap.toml` file][yazi-keymap-toml].
Essentially, all you need to do to use this plugin
-is to wrap a Yazi command in single quotes,
-like `'enter'`,
-then add `plugin augment-command --args=`
-in front of it, which results in
-`plugin augment-command --args='enter'`.
+is to add `plugin augment-command --`, with a space at the end,
+in front of a Yazi command, such as `enter`,
+which results in `plugin augment-command -- enter'`.
### Using the `extract` command as an opener
@@ -883,7 +976,7 @@ for details on how to do so.
### Full configuration example
For a full configuration example,
-you can take a look at [my `keymap.toml` file][my-keymap-toml]
+you can have a look at [my `keymap.toml` file][my-keymap-toml]
and [my `yazi.toml` file][my-yazi-toml].
## [Licence]
@@ -894,6 +987,7 @@ You can view the full licence in the [`LICENSE`][Licence] file.
[yazi-link]: https://github.com/sxyazi/yazi
+[yazi-tips-page]: https://yazi-rs.github.io/docs/tips
[smart-paste-tip]: https://yazi-rs.github.io/docs/tips#smart-paste
[smart-tab-tip]: https://yazi-rs.github.io/docs/tips#smart-tab
[smart-switch-tip]: https://yazi-rs.github.io/docs/tips#smart-switch
@@ -905,6 +999,8 @@ You can view the full licence in the [`LICENSE`][Licence] file.
[brew-link]: https://brew.sh/
[yazi-yazi-toml-extract-openers]: https://github.com/sxyazi/yazi/blob/main/yazi-config/preset/yazi-default.toml#L51-L54
[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
[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
@@ -979,6 +1075,10 @@ You can view the full licence in the [`LICENSE`][Licence] file.
[smart-tab-switch-video]: https://github.com/user-attachments/assets/1afb540d-47a9-4625-ae59-95d5cd91aa35
+
+
+[quit-with-confirmation-video]: https://github.com/user-attachments/assets/b6206ee4-766b-44ce-b90b-15b015ae71f9
+
[wraparound-arrow-video]: https://github.com/user-attachments/assets/41ea1fb0-a526-4549-95a2-547c3c4b0498
diff --git a/config/yazi/plugins/augment-command.yazi/main.lua b/config/yazi/plugins/augment-command.yazi/main.lua
index 517c7245..5d7e6393 100644
--- a/config/yazi/plugins/augment-command.yazi/main.lua
+++ b/config/yazi/plugins/augment-command.yazi/main.lua
@@ -1,3 +1,5 @@
+--- @since 25.2.7
+
-- Plugin to make some Yazi commands smarter
-- Written in Lua 5.4
@@ -9,29 +11,29 @@
-- The type for the function to handle a command
--
-- Description of the function parameters:
--- args: The arguments to pass to the command
--- config: The configuration object
+-- args: The arguments to pass to the command
+-- config: The configuration object
---@alias CommandFunction fun(
---- args: Arguments,
---- config: Configuration): nil
+--- args: Arguments,
+--- config: Configuration): nil
-- The type of the command table
---@alias CommandTable table
-- The type for the extractor list items command
---@alias ExtractorListItemsCommand fun(
---- self: Extractor,
+--- self: Extractor,
---): output: CommandOutput|nil, error: Error|nil
-- The type for the extractor get items function
---@alias ExtractorGetItems fun(
---- self: Extractor,
+--- self: Extractor,
---): files: string[], directories: string[], error: string|nil
-- The type for the extractor extract function.
---@alias ExtractorExtract fun(
---- self: Extractor,
---- has_only_one_file: boolean|nil,
+--- self: Extractor,
+--- has_only_one_file: boolean|nil,
---): ExtractionResult
-- The type for the extractor function
@@ -48,6 +50,7 @@
---@field smart_paste boolean Whether to use smart paste
---@field smart_tab_create boolean Whether to use smart tab create
---@field smart_tab_switch boolean Whether to use smart tab switch
+---@field confirm_on_quit boolean Whether to show a confirmation when quitting
---@field open_file_after_creation boolean Whether to open after creation
---@field enter_directory_after_creation boolean Whether to enter after creation
---@field use_default_create_behaviour boolean Use Yazi's create behaviour?
@@ -85,68 +88,70 @@ local PLUGIN_NAME = "augment-command"
-- The enum for the supported commands
---@enum SupportedCommands
local Commands = {
- Open = "open",
- Extract = "extract",
- Enter = "enter",
- Leave = "leave",
- Rename = "rename",
- Remove = "remove",
- Create = "create",
- Shell = "shell",
- Paste = "paste",
- TabCreate = "tab_create",
- TabSwitch = "tab_switch",
- Arrow = "arrow",
- ParentArrow = "parent_arrow",
- Editor = "editor",
- Pager = "pager",
+ Open = "open",
+ Extract = "extract",
+ Enter = "enter",
+ Leave = "leave",
+ Rename = "rename",
+ Remove = "remove",
+ Create = "create",
+ Shell = "shell",
+ Paste = "paste",
+ TabCreate = "tab_create",
+ TabSwitch = "tab_switch",
+ Quit = "quit",
+ Arrow = "arrow",
+ ParentArrow = "parent_arrow",
+ Editor = "editor",
+ Pager = "pager",
}
-- The enum for which group of items to operate on
---@enum ItemGroup
local ItemGroup = {
- Hovered = "hovered",
- Selected = "selected",
- None = "none",
- Prompt = "prompt",
+ Hovered = "hovered",
+ Selected = "selected",
+ None = "none",
+ Prompt = "prompt",
}
-- The default configuration for the plugin
---@type UserConfiguration
local DEFAULT_CONFIG = {
- prompt = false,
- default_item_group_for_prompt = ItemGroup.Hovered,
- smart_enter = true,
- smart_paste = false,
- smart_tab_create = false,
- smart_tab_switch = false,
- open_file_after_creation = false,
- enter_directory_after_creation = false,
- use_default_create_behaviour = false,
- enter_archives = true,
- extract_retries = 3,
- recursively_extract_archives = true,
- preserve_file_permissions = false,
- must_have_hovered_item = true,
- skip_single_subdirectory_on_enter = true,
- skip_single_subdirectory_on_leave = true,
- wraparound_file_navigation = false,
+ prompt = false,
+ default_item_group_for_prompt = ItemGroup.Hovered,
+ smart_enter = true,
+ smart_paste = false,
+ smart_tab_create = false,
+ smart_tab_switch = false,
+ confirm_on_quit = true,
+ open_file_after_creation = false,
+ enter_directory_after_creation = false,
+ use_default_create_behaviour = false,
+ enter_archives = true,
+ extract_retries = 3,
+ recursively_extract_archives = true,
+ preserve_file_permissions = false,
+ must_have_hovered_item = true,
+ skip_single_subdirectory_on_enter = true,
+ skip_single_subdirectory_on_leave = true,
+ wraparound_file_navigation = false,
}
-- The default input options for this plugin
local DEFAULT_INPUT_OPTIONS = {
- position = { "top-center", x = 0, y = 2, w = 50, h = 3 },
+ position = { "top-center", x = 0, y = 2, w = 50, h = 3 },
}
-- The default confirm options for this plugin
local DEFAULT_CONFIRM_OPTIONS = {
- pos = { "center", x = 0, y = 0, w = 50, h = 15 },
+ pos = { "center", x = 0, y = 0, w = 50, h = 15 },
}
-- The default notification options for this plugin
local DEFAULT_NOTIFICATION_OPTIONS = {
- title = "Augment Command Plugin",
- timeout = 5,
+ title = "Augment Command Plugin",
+ timeout = 5,
}
-- The tab preference keys.
@@ -155,60 +160,60 @@ local DEFAULT_NOTIFICATION_OPTIONS = {
-- different types for the same thing.
---@type tab.Preference
local TAB_PREFERENCE_KEYS = {
- sort_by = "alphabetical",
- sort_sensitive = false,
- sort_reverse = false,
- sort_dir_first = true,
- sort_translit = false,
- linemode = "none",
- show_hidden = false,
+ sort_by = "alphabetical",
+ sort_sensitive = false,
+ sort_reverse = false,
+ sort_dir_first = true,
+ sort_translit = false,
+ linemode = "none",
+ show_hidden = false,
}
-- The table of input options for the prompt
---@type table
local INPUT_OPTIONS_TABLE = {
- [ItemGroup.Hovered] = "(H/s)",
- [ItemGroup.Selected] = "(h/S)",
- [ItemGroup.None] = "(h/s)",
+ [ItemGroup.Hovered] = "(H/s)",
+ [ItemGroup.Selected] = "(h/S)",
+ [ItemGroup.None] = "(h/s)",
}
-- The extractor names
---@enum ExtractorName
local ExtractorName = {
- SevenZip = "7-Zip",
- Tar = "Tar",
+ SevenZip = "7-Zip",
+ Tar = "Tar",
}
-- The extract behaviour flags
---@enum ExtractBehaviour
local ExtractBehaviour = {
- Overwrite = "overwrite",
- Rename = "rename",
+ Overwrite = "overwrite",
+ Rename = "rename",
}
-- The list of archive file extensions
---@type table
local ARCHIVE_FILE_EXTENSIONS = {
- ["7z"] = true,
- boz = true,
- bz = true,
- bz2 = true,
- bzip2 = true,
- cb7 = true,
- cbr = true,
- cbt = true,
- cbz = true,
- gz = true,
- gzip = true,
- rar = true,
- s7z = true,
- tar = true,
- tbz = true,
- tbz2 = true,
- tgz = true,
- txz = true,
- xz = true,
- zip = true,
+ ["7z"] = true,
+ boz = true,
+ bz = true,
+ bz2 = true,
+ bzip2 = true,
+ cb7 = true,
+ cbr = true,
+ cbt = true,
+ cbz = true,
+ gz = true,
+ gzip = true,
+ rar = true,
+ s7z = true,
+ tar = true,
+ tbz = true,
+ tbz2 = true,
+ tgz = true,
+ txz = true,
+ xz = true,
+ zip = true,
}
-- The error for the base extractor class
@@ -216,8 +221,8 @@ local ARCHIVE_FILE_EXTENSIONS = {
-- does not implement any functionality
---@type string
local BASE_EXTRACTOR_ERROR = table.concat({
- "The Extractor class is does not implement any functionality.",
- "How did you even manage to get here?",
+ "The Extractor class is does not implement any functionality.",
+ "How did you even manage to get here?",
}, "\n")
-- Class definitions
@@ -234,27 +239,27 @@ local BASE_EXTRACTOR_ERROR = table.concat({
--- The map of the extract behaviour strings to the command flags
---@field extract_behaviour_map table
local Extractor = {
- name = "BaseExtractor",
- command = "",
- commands = {},
- supports_file_permissions = false,
- extract_behaviour_map = {},
+ name = "BaseExtractor",
+ command = "",
+ commands = {},
+ supports_file_permissions = false,
+ extract_behaviour_map = {},
}
-- The function to create a subclass of the abstract base extractor
---@param subclass table The subclass to create
---@return Extractor subclass Subclass of the base extractor
function Extractor:subclass(subclass)
- --
+ --
- -- Create a new instance
- local instance = setmetatable(subclass or {}, self)
+ -- Create a new instance
+ local instance = setmetatable(subclass or {}, self)
- -- Set where to find the object's methods or properties
- self.__index = self
+ -- Set where to find the object's methods or properties
+ self.__index = self
- -- Return the instance
- return instance
+ -- Return the instance
+ return instance
end
-- The method to get the archive items
@@ -264,43 +269,43 @@ function Extractor:get_items() return {}, {}, BASE_EXTRACTOR_ERROR end
-- The method to extract the archive
---@type ExtractorExtract
function Extractor:extract(_)
- return {
- successful = false,
- error = BASE_EXTRACTOR_ERROR,
- }
+ return {
+ successful = false,
+ error = BASE_EXTRACTOR_ERROR,
+ }
end
-- The 7-Zip extractor
---@class SevenZip: Extractor
---@field password string The password to the archive
local SevenZip = Extractor:subclass({
- name = ExtractorName.SevenZip,
- commands = { "7z", "7zz" },
+ name = ExtractorName.SevenZip,
+ commands = { "7z", "7zz" },
- -- https://documentation.help/7-Zip/overwrite.htm
- extract_behaviour_map = {
- [ExtractBehaviour.Overwrite] = "-aoa",
- [ExtractBehaviour.Rename] = "-aou",
- },
+ -- https://documentation.help/7-Zip/overwrite.htm
+ extract_behaviour_map = {
+ [ExtractBehaviour.Overwrite] = "-aoa",
+ [ExtractBehaviour.Rename] = "-aou",
+ },
- password = "",
+ password = "",
})
-- The Tar extractor
---@class Tar: Extractor
local Tar = Extractor:subclass({
- name = ExtractorName.Tar,
- commands = { "gtar", "tar" },
- supports_file_permissions = true,
+ name = ExtractorName.Tar,
+ commands = { "gtar", "tar" },
+ supports_file_permissions = true,
- -- https://www.man7.org/linux/man-pages/man1/tar.1.html
- -- https://ss64.com/mac/tar.html
- extract_behaviour_map = {
+ -- https://www.man7.org/linux/man-pages/man1/tar.1.html
+ -- https://ss64.com/mac/tar.html
+ extract_behaviour_map = {
- -- Tar overwrites by default
- [ExtractBehaviour.Overwrite] = "",
- [ExtractBehaviour.Rename] = "-k",
- },
+ -- Tar overwrites by default
+ [ExtractBehaviour.Overwrite] = "",
+ [ExtractBehaviour.Rename] = "-k",
+ },
})
-- The default extractor, which is set to 7-Zip
@@ -310,14 +315,14 @@ local DefaultExtractor = SevenZip:subclass({})
-- The table of archive mime types
---@type table
local ARCHIVE_MIME_TYPE_TO_EXTRACTOR_MAP = {
- ["application/zip"] = DefaultExtractor,
- ["application/gzip"] = DefaultExtractor,
- ["application/tar"] = Tar,
- ["application/bzip"] = DefaultExtractor,
- ["application/bzip2"] = DefaultExtractor,
- ["application/7z-compressed"] = DefaultExtractor,
- ["application/rar"] = DefaultExtractor,
- ["application/xz"] = DefaultExtractor,
+ ["application/zip"] = DefaultExtractor,
+ ["application/gzip"] = DefaultExtractor,
+ ["application/tar"] = Tar,
+ ["application/bzip"] = DefaultExtractor,
+ ["application/bzip2"] = DefaultExtractor,
+ ["application/7z-compressed"] = DefaultExtractor,
+ ["application/rar"] = DefaultExtractor,
+ ["application/xz"] = DefaultExtractor,
}
-- Patterns
@@ -329,14 +334,14 @@ local ARCHIVE_MIME_TYPE_TO_EXTRACTOR_MAP = {
-- characters need to be escaped
---@type string[]
local MIME_TYPE_PREFIXES_TO_REMOVE = {
- "x%-",
- "vnd%.",
+ "x%-",
+ "vnd%.",
}
-- The pattern template to get the mime type without a prefix
---@type string
local get_mime_type_without_prefix_template_pattern =
- "^(%%a-)/%s([%%-%%d%%a]-)$"
+ "^(%%a-)/%s([%%-%%d%%a]-)$"
-- The pattern to get the file extension
---@type string
@@ -346,9 +351,9 @@ local file_extension_pattern = "%.([%a]+)$"
---@type string
local shell_variable_pattern = "[%$%%][%*@0]"
--- The pattern to match the bat command with the pager option passed
+-- The pattern to match the bat command
---@type string
-local bat_command_with_pager_pattern = "%f[%a]bat%f[%A].*%-%-pager%s+"
+local bat_command_pattern = "%f[%a]bat%f[%A]"
-- Utility functions
@@ -365,46 +370,46 @@ local bat_command_with_pager_pattern = "%f[%a]bat%f[%A].*%-%-pager%s+"
---@param ... table[] The tables to merge
---@return table merged_table The merged table
local function merge_tables(...)
- --
+ --
- -- Initialise a new table
- local new_table = {}
+ -- Initialise a new table
+ local new_table = {}
- -- Initialise the index variable
- local index = 1
+ -- Initialise the index variable
+ local index = 1
- -- Iterates over the tables given
- for _, table in ipairs({ ... }) do
- --
+ -- Iterates over the tables given
+ for _, table in ipairs({ ... }) do
+ --
- -- Iterate over all of the keys and values
- for key, value in pairs(table) do
- --
+ -- Iterate over all of the keys and values
+ for key, value in pairs(table) do
+ --
- -- If the key is a number, then add using the index
- -- instead of the key.
- -- This is to allow lists to be merged.
- if type(key) == "number" then
- --
+ -- If the key is a number, then add using the index
+ -- instead of the key.
+ -- This is to allow lists to be merged.
+ if type(key) == "number" then
+ --
- -- Set the value mapped to the index
- new_table[index] = value
+ -- Set the value mapped to the index
+ new_table[index] = value
- -- Increment the index
- index = index + 1
+ -- Increment the index
+ index = index + 1
- -- Otherwise, the key isn't a number
- else
- --
+ -- Otherwise, the key isn't a number
+ else
+ --
- -- Set the key in the new table to the value given
- new_table[key] = value
- end
- end
- end
+ -- Set the key in the new table to the value given
+ new_table[key] = value
+ end
+ end
+ end
- -- Return the new table
- return new_table
+ -- Return the new table
+ return new_table
end
-- Function to split a string into a list
@@ -412,35 +417,35 @@ end
---@param separator string|nil The character to split the string by
---@return string[] splitted_strings The list of strings split by the character
local function string_split(given_string, separator)
- --
+ --
- -- If the separator isn't given, set it to the whitespace character
- separator = separator or "%s"
+ -- If the separator isn't given, set it to the whitespace character
+ separator = separator or "%s"
- -- Initialise the list of splitted strings
- local splitted_strings = {}
+ -- Initialise the list of splitted strings
+ local splitted_strings = {}
- -- Iterate over all of the strings found by pattern
- for string in string.gmatch(given_string, "([^" .. separator .. "]+)") do
- --
+ -- Iterate over all of the strings found by pattern
+ for string in string.gmatch(given_string, "([^" .. separator .. "]+)") do
+ --
- -- Add the string to the list of splitted strings
- table.insert(splitted_strings, string)
- end
+ -- Add the string to the list of splitted strings
+ table.insert(splitted_strings, string)
+ end
- -- Return the list of splitted strings
- return splitted_strings
+ -- Return the list of splitted strings
+ return splitted_strings
end
-- Function to trim a string
---@param string string The string to trim
---@return string trimmed_string The trimmed string
local function string_trim(string)
- --
+ --
- -- Return the string with the whitespace characters
- -- removed from the start and end
- return string:match("^%s*(.-)%s*$")
+ -- Return the string with the whitespace characters
+ -- removed from the start and end
+ return string:match("^%s*(.-)%s*$")
end
-- Function to get a value from a table
@@ -456,17 +461,17 @@ local function table_get(table, key, default) return table[key] or default end
---@param default any The default value to return if the key doesn't exist
---@return any value The value of the key or the default value
local function table_pop(table, key, default)
- --
+ --
- -- Get the value of the key from the table
- local value = table[key]
+ -- Get the value of the key from the table
+ local value = table[key]
- -- Remove the key from the table
- table[key] = nil
+ -- Remove the key from the table
+ table[key] = nil
- -- Return the value if it exist,
- -- otherwise return the default value
- return value or default
+ -- Return the value if it exist,
+ -- otherwise return the default value
+ return value or default
end
-- Function to escape a percentage sign %
@@ -474,93 +479,93 @@ end
---@param replacement_string string The string to escape
---@return string replacement_result The escaped string
local function escape_replacement_string(replacement_string)
- --
+ --
- -- Get the result of the replacement
- local replacement_result = replacement_string:gsub("%%", "%%%%")
+ -- Get the result of the replacement
+ local replacement_result = replacement_string:gsub("%%", "%%%%")
- -- Return the result of the replacement
- return replacement_result
+ -- Return the result of the replacement
+ return replacement_result
end
-- Function to parse the number arguments to the number type
---@param args Arguments The arguments to parse
---@return Arguments parsed_args The parsed arguments
local function parse_number_arguments(args)
- --
+ --
- -- The parsed arguments
- ---@type Arguments
- local parsed_args = {}
+ -- The parsed arguments
+ ---@type Arguments
+ local parsed_args = {}
- -- Iterate over the arguments given
- for arg_name, arg_value in pairs(args) do
- --
+ -- Iterate over the arguments given
+ for arg_name, arg_value in pairs(args) do
+ --
- -- Try to convert the argument to a number
- local number_arg_value = tonumber(arg_value)
+ -- Try to convert the argument to a number
+ local number_arg_value = tonumber(arg_value)
- -- Set the argument to the number argument value
- -- if the argument is a number,
- -- otherwise just set it to the given argument value
- parsed_args[arg_name] = number_arg_value or arg_value
- end
+ -- Set the argument to the number argument value
+ -- if the argument is a number,
+ -- otherwise just set it to the given argument value
+ parsed_args[arg_name] = number_arg_value or arg_value
+ end
- -- Return the parsed arguments
- return parsed_args
+ -- Return the parsed arguments
+ return parsed_args
end
-- Function to convert a table of arguments to a string
---@param args Arguments The arguments to convert
---@return string args_string The string of the arguments
local function convert_arguments_to_string(args)
- --
+ --
- -- The table of string arguments
- ---@type string[]
- local string_arguments = {}
+ -- The table of string arguments
+ ---@type string[]
+ local string_arguments = {}
- -- Iterate all the items in the argument table
- for key, value in pairs(args) do
- --
+ -- Iterate all the items in the argument table
+ for key, value in pairs(args) do
+ --
- -- If the key is a number
- if type(key) == "number" then
- --
+ -- If the key is a number
+ if type(key) == "number" then
+ --
- -- Add the stringified value to the string arguments table
- table.insert(string_arguments, tostring(value))
+ -- Add the stringified value to the string arguments table
+ table.insert(string_arguments, tostring(value))
- -- Otherwise, if the key is a string
- elseif type(key) == "string" then
- --
+ -- Otherwise, if the key is a string
+ elseif type(key) == "string" then
+ --
- -- Replace the underscores and spaces in the key with dashes
- local key_with_dashes = key:gsub("_", "-"):gsub("%s", "-")
+ -- Replace the underscores and spaces in the key with dashes
+ local key_with_dashes = key:gsub("_", "-"):gsub("%s", "-")
- -- If the value is a boolean and the boolean is true,
- -- add the value to the string
- if type(value) == "boolean" and value then
- table.insert(
- string_arguments,
- string.format("--%s", key_with_dashes)
- )
+ -- If the value is a boolean and the boolean is true,
+ -- add the value to the string
+ if type(value) == "boolean" and value then
+ table.insert(
+ string_arguments,
+ string.format("--%s", key_with_dashes)
+ )
- -- Otherwise, just add the key and the value to the string
- else
- table.insert(
- string_arguments,
- string.format("--%s=%s", key_with_dashes, value)
- )
- end
- end
- end
+ -- Otherwise, just add the key and the value to the string
+ else
+ table.insert(
+ string_arguments,
+ string.format("--%s=%s", key_with_dashes, value)
+ )
+ end
+ end
+ end
- -- Combine the string arguments into a single string
- local string_args = table.concat(string_arguments, " ")
+ -- Combine the string arguments into a single string
+ local string_args = table.concat(string_arguments, " ")
- -- Return the string arguments
- return string_args
+ -- Return the string arguments
+ return string_args
end
-- Function to show a warning
@@ -568,10 +573,10 @@ end
---@param options YaziNotificationOptions|nil Options for the notification
---@return nil
local function show_warning(warning_message, options)
- return ya.notify(merge_tables(DEFAULT_NOTIFICATION_OPTIONS, options or {}, {
- content = warning_message,
- level = "warn",
- }))
+ return ya.notify(merge_tables(DEFAULT_NOTIFICATION_OPTIONS, options or {}, {
+ content = warning_message,
+ level = "warn",
+ }))
end
-- Function to show an error
@@ -579,10 +584,10 @@ end
---@param options YaziNotificationOptions|nil Options for the notification
---@return nil
local function show_error(error_message, options)
- return ya.notify(merge_tables(DEFAULT_NOTIFICATION_OPTIONS, options or {}, {
- content = error_message,
- level = "error",
- }))
+ return ya.notify(merge_tables(DEFAULT_NOTIFICATION_OPTIONS, options or {}, {
+ content = error_message,
+ level = "error",
+ }))
end
-- Function to get the user's input
@@ -591,127 +596,101 @@ end
---@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,
- }))
+ return ya.input(merge_tables(DEFAULT_INPUT_OPTIONS, options or {}, {
+ title = prompt,
+ }))
end
-- Function to get the user's confirmation
--- TODO: Remove the `ya.input` version once `ya.confirm` is stable
----@param prompt string The prompt to show to the user
---@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(prompt, title, content)
- --
+local function get_user_confirmation(title, content)
+ --
- -- If the ya.confirm API exists, use it
- if ya.confirm then
- --
+ -- Get the user's confirmation
+ local confirmation = ya.confirm(merge_tables(DEFAULT_CONFIRM_OPTIONS, {
+ title = title,
+ content = content,
+ }))
- -- Get the user's confirmation
- local confirmation = ya.confirm(merge_tables(DEFAULT_CONFIRM_OPTIONS, {
- title = title,
- content = content,
- }))
-
- -- Return the result of the confirmation
- return confirmation
- end
-
- -- TODO: Remove everything after this when `ya.confirm` is stable
-
- -- Get the user's input
- local user_input, event = get_user_input(prompt)
-
- -- If the user has not confirmed the input,
- -- or the user input is nil,
- -- then return false
- if not user_input or event ~= 1 then return false end
-
- -- Lowercase the user's input
- user_input = user_input:lower()
-
- -- If the user input starts with a "y", then return true
- if user_input:find("^y") then return true end
-
- -- Otherwise, return false
- return false
+ -- Return the result of the confirmation
+ return confirmation
end
-- Function to merge the given configuration table with the default one
---@param config UserConfiguration|nil The configuration table to merge
---@return UserConfiguration merged_config The merged configuration table
local function merge_configuration(config)
- --
+ --
- -- If the configuration isn't given, then use the default one
- if config == nil then return DEFAULT_CONFIG end
+ -- If the configuration isn't given, then use the default one
+ if config == nil then return DEFAULT_CONFIG end
- -- Initialise the list of invalid configuration options
- local invalid_configuration_options = {}
+ -- Initialise the list of invalid configuration options
+ local invalid_configuration_options = {}
- -- Initialise the merged configuration
- local merged_config = {}
+ -- Initialise the merged configuration
+ local merged_config = {}
- -- Iterate over the default configuration table
- for key, value in pairs(DEFAULT_CONFIG) do
- --
+ -- Iterate over the default configuration table
+ for key, value in pairs(DEFAULT_CONFIG) do
+ --
- -- Add the default configuration to the merged configuration
- merged_config[key] = value
- end
+ -- Add the default configuration to the merged configuration
+ merged_config[key] = value
+ end
- -- Iterate over the given configuration table
- for key, value in pairs(config) do
- --
+ -- Iterate over the given configuration table
+ for key, value in pairs(config) do
+ --
- -- If the key is not in the merged configuration
- if merged_config[key] == nil then
- --
+ -- If the key is not in the merged configuration
+ if merged_config[key] == nil then
+ --
- -- Add the key to the list of invalid configuration options
- table.insert(invalid_configuration_options, key)
+ -- Add the key to the list of invalid configuration options
+ table.insert(invalid_configuration_options, key)
- -- Continue the loop
- goto continue
- end
+ -- Continue the loop
+ goto continue
+ end
- -- Otherwise, overwrite the value in the merged configuration
- merged_config[key] = value
+ -- Otherwise, overwrite the value in the merged configuration
+ merged_config[key] = value
- -- The label to continue the loop
- ::continue::
- end
+ -- The label to continue the loop
+ ::continue::
+ end
- -- If there are no invalid configuration options,
- -- then return the merged configuration
- if #invalid_configuration_options <= 0 then return merged_config end
+ -- If there are no invalid configuration options,
+ -- then return the merged configuration
+ if #invalid_configuration_options <= 0 then return merged_config end
- -- Otherwise, warn the user of the invalid configuration options
- show_warning(
- "Invalid configuration options: "
- .. table.concat(invalid_configuration_options, ", ")
- )
+ -- Otherwise, warn the user of the invalid configuration options
+ show_warning(
+ "Invalid configuration options: "
+ .. table.concat(invalid_configuration_options, ", ")
+ )
- -- Return the merged configuration
- return merged_config
+ -- Return the merged configuration
+ return merged_config
end
-- Function to initialise the configuration
---@type fun(
---- user_config: Configuration|nil, -- The configuration object
+--- user_config: Configuration|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)
+ -- 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)
- -- Return the configuration object for async functions
- return state.config
+ -- Return the configuration object for async functions
+ return state.config
end)
-- Function to try if a shell command exists
@@ -719,17 +698,17 @@ end)
---@param args string[]|nil The arguments to the shell command
---@return boolean shell_command_exists Whether the shell command exists
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 {})
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :output()
+ -- Get the output of the shell command with the given arguments
+ local output = Command(shell_command)
+ :args(args or {})
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :output()
- -- Return true if there's an output and false otherwise
- return output ~= nil
+ -- Return true if there's an output and false otherwise
+ return output ~= nil
end
-- Function to emit a plugin command
@@ -737,53 +716,49 @@ end
---@param args Arguments The arguments to pass to the plugin command
---@return nil
local function emit_plugin_command(command, args)
- return ya.manager_emit("plugin", {
- PLUGIN_NAME,
- args = string.format(
- "%s %s",
- command,
- convert_arguments_to_string(args)
- ),
- })
+ return ya.manager_emit("plugin", {
+ PLUGIN_NAME,
+ string.format("%s %s", command, convert_arguments_to_string(args)),
+ })
end
-- Function to subscribe to the augmented-extract event
---@type fun(): nil
local subscribe_to_augmented_extract_event = ya.sync(function(_)
- return ps.sub_remote("augmented-extract", function(args)
- --
+ return ps.sub_remote("augmented-extract", function(args)
+ --
- -- If the arguments given isn't a table,
- -- exit the function
- if type(args) ~= "table" then return end
+ -- If the arguments given isn't a table,
+ -- exit the function
+ if type(args) ~= "table" then return end
- -- Iterate over the arguments
- for _, arg in ipairs(args) do
- --
+ -- Iterate over the arguments
+ for _, arg in ipairs(args) do
+ --
- -- Emit the command to call the plugin's extract function
- -- with the given arguments and flags
- emit_plugin_command("extract", {
- archive_path = ya.quote(arg),
- })
- end
- end)
+ -- Emit the command to call the plugin's extract function
+ -- with the given arguments and flags
+ emit_plugin_command("extract", {
+ archive_path = ya.quote(arg),
+ })
+ end
+ end)
end)
-- Function to initialise the plugin
---@param opts Configuration|nil The options given to the plugin
---@return Configuration config The initialised configuration object
local function initialise_plugin(opts)
- --
+ --
- -- Subscribe to the augmented extract event
- subscribe_to_augmented_extract_event()
+ -- Subscribe to the augmented extract event
+ subscribe_to_augmented_extract_event()
- -- Initialise the configuration object
- local config = initialise_config(opts)
+ -- Initialise the configuration object
+ local config = initialise_config(opts)
- -- Return the configuration object
- return config
+ -- Return the configuration object
+ return config
end
-- Function to standardise the mime type of a file.
@@ -792,50 +767,50 @@ end
---@param mime_type string The mime type of the file
---@return string standardised_mime_type The standardised mime type of the file
local function standardise_mime_type(mime_type)
- --
+ --
- -- Trim the whitespace from the mime type
- local trimmed_mime_type = string_trim(mime_type)
+ -- Trim the whitespace from the mime type
+ local trimmed_mime_type = string_trim(mime_type)
- -- Iterate over the mime type prefixes to remove
- for _, prefix in ipairs(MIME_TYPE_PREFIXES_TO_REMOVE) do
- --
+ -- Iterate over the mime type prefixes to remove
+ for _, prefix in ipairs(MIME_TYPE_PREFIXES_TO_REMOVE) do
+ --
- -- Get the pattern to remove the mime type prefix
- local pattern =
- get_mime_type_without_prefix_template_pattern:format(prefix)
+ -- Get the pattern to remove the mime type prefix
+ local pattern =
+ get_mime_type_without_prefix_template_pattern:format(prefix)
- -- Remove the prefix from the mime type
- local mime_type_without_prefix, replacement_count =
- trimmed_mime_type:gsub(pattern, "%1/%2")
+ -- Remove the prefix from the mime type
+ local mime_type_without_prefix, replacement_count =
+ trimmed_mime_type:gsub(pattern, "%1/%2")
- -- If the replacement count is greater than zero,
- -- return the mime type without the prefix
- if replacement_count > 0 then return mime_type_without_prefix end
- end
+ -- If the replacement count is greater than zero,
+ -- return the mime type without the prefix
+ if replacement_count > 0 then return mime_type_without_prefix end
+ end
- -- Return the mime type with whitespace removed
- return trimmed_mime_type
+ -- Return the mime type with whitespace removed
+ return trimmed_mime_type
end
-- Function to check if a given mime type is an archive
---@param mime_type string|nil The mime type of the file
---@return boolean is_archive Whether the mime type is an archive
local function is_archive_mime_type(mime_type)
- --
+ --
- -- If the mime type is nil, return false
- if not mime_type then return false end
+ -- If the mime type is nil, return false
+ if not mime_type then return false end
- -- Standardise the mime type
- local standardised_mime_type = standardise_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_EXTRACTOR_MAP[standardised_mime_type]
+ -- Get the archive extractor for the mime type
+ local archive_extractor =
+ ARCHIVE_MIME_TYPE_TO_EXTRACTOR_MAP[standardised_mime_type]
- -- Return if an extractor exists for the mime type
- return archive_extractor ~= nil
+ -- Return if an extractor exists for the mime type
+ return archive_extractor ~= nil
end
-- Function to check if a given file extension
@@ -843,58 +818,58 @@ end
---@param file_extension string|nil The file extension of the file
---@return boolean is_archive Whether the file extension is an archive
local function is_archive_file_extension(file_extension)
- --
+ --
- -- If the file extension is nil, return false
- if not file_extension then return false end
+ -- If the file extension is nil, return false
+ if not file_extension then return false end
- -- Make the file extension lower case
- file_extension = file_extension:lower()
+ -- Make the file extension lower case
+ file_extension = file_extension:lower()
- -- Trim the whitespace from the file extension
- file_extension = string_trim(file_extension)
+ -- Trim the whitespace from the file extension
+ file_extension = string_trim(file_extension)
- -- Get if the file extension is an archive
- local is_archive = table_get(ARCHIVE_FILE_EXTENSIONS, file_extension, false)
+ -- Get if the file extension is an archive
+ local is_archive = table_get(ARCHIVE_FILE_EXTENSIONS, file_extension, false)
- -- Return if the file extension is an archive file extension
- return is_archive
+ -- Return if the file extension is an archive file extension
+ return is_archive
end
-- Function to get the mime type of a file
---@param file_path string The path to the file
---@return string mime_type The mime type of the file
local function get_mime_type(file_path)
- --
+ --
- -- Get the output of the file command
- local output, _ = Command("file")
- :args({
+ -- Get the output of the file command
+ local output, _ = Command("file")
+ :args({
- -- Don't prepend file names to the output
- "-b",
+ -- Don't prepend file names to the output
+ "-b",
- -- Print the mime type of the file
- "--mime-type",
+ -- Print the mime type of the file
+ "--mime-type",
- -- The file path to get the mime type of
- file_path,
- })
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :output()
+ -- The file path to get the mime type of
+ file_path,
+ })
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :output()
- -- If there is no output, then return an empty string
- if not output then return "" end
+ -- If there is no output, then return an empty string
+ if not output then return "" end
- -- Otherwise, get the mime type from the standard output
- local mime_type = string_trim(output.stdout)
+ -- Otherwise, get the mime type from the standard output
+ local mime_type = string_trim(output.stdout)
- -- Standardise the mime type
- local standardised_mime_type = standardise_mime_type(mime_type)
+ -- Standardise the mime type
+ local standardised_mime_type = standardise_mime_type(mime_type)
- -- Return the standardised mime type
- return standardised_mime_type
+ -- Return the standardised mime type
+ return standardised_mime_type
end
-- Function to get a temporary name.
@@ -902,8 +877,8 @@ end
---@param path string The path to the item to create a temporary name
---@return string temporary_name The temporary name for the item
local function get_temporary_name(path)
- return ".tmp_"
- .. ya.hash(string.format("extract//%s//%.10f", path, ya.time()))
+ return ".tmp_"
+ .. ya.hash(string.format("extract//%s//%.10f", path, ya.time()))
end
-- Function to get a temporary directory url
@@ -912,165 +887,169 @@ end
---@param destination_given boolean|nil Whether the destination was given
---@return Url|nil url The url of the temporary directory
local function get_temporary_directory_url(path, destination_given)
- --
+ --
- -- Get the url of the path given
- ---@type Url
- local path_url = Url(path)
+ -- Get the url of the path given
+ ---@type Url
+ local path_url = Url(path)
- -- Initialise the parent directory to be the path given
- ---@type Url
- local parent_directory_url = path_url
+ -- Initialise the parent directory to be the path given
+ ---@type Url
+ local parent_directory_url = path_url
- -- If the destination is not given
- if not destination_given then
- --
+ -- If the destination is not given
+ if not destination_given then
+ --
- -- Get the parent directory of the given path
- parent_directory_url = Url(path):parent()
+ -- Get the parent directory of the given path
+ parent_directory_url = Url(path):parent()
- -- If the parent directory doesn't exist, return nil
- if not parent_directory_url then return nil end
- end
+ -- If the parent directory doesn't exist, return nil
+ if not parent_directory_url then return nil end
+ end
- -- Create the temporary directory path
- local temporary_directory_url =
- fs.unique_name(parent_directory_url:join(get_temporary_name(path)))
+ -- Create the temporary directory path
+ local temporary_directory_url =
+ fs.unique_name(parent_directory_url:join(get_temporary_name(path)))
- -- Return the temporary directory path
- return temporary_directory_url
+ -- Return the temporary directory path
+ return temporary_directory_url
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
+ -- Returns the configuration object
+ return state.config
end)
-- Function to get the current working directory
---@type fun(): string Returns the current working directory as a string
local get_current_directory = ya.sync(
- function(_) return tostring(cx.active.current.cwd) end
+ function(_) return tostring(cx.active.current.cwd) end
)
-- Function to get the path of the hovered item
---@type fun(
---- quote: boolean|nil, -- Whether to escape the characters in the path
+--- quote: boolean|nil, -- Whether to escape the characters in the path
---): string|nil The path of the hovered item
local get_path_of_hovered_item = ya.sync(function(_, quote)
- --
+ --
- -- Get the hovered item
- local hovered_item = cx.active.current.hovered
+ -- Get the hovered item
+ local hovered_item = cx.active.current.hovered
- -- If there is no hovered item, exit the function
- if not hovered_item then return end
+ -- If there is no hovered item, exit the function
+ if not hovered_item then return end
- -- Convert the url of the hovered item to a string
- local hovered_item_path = tostring(cx.active.current.hovered.url)
+ -- Convert the url of the hovered item to a string
+ local hovered_item_path = tostring(cx.active.current.hovered.url)
- -- If the quote flag is passed,
- -- then quote the path of the hovered item
- if quote then hovered_item_path = ya.quote(hovered_item_path) end
+ -- If the quote flag is passed,
+ -- then quote the path of the hovered item
+ if quote then hovered_item_path = ya.quote(hovered_item_path) end
- -- Return the path of the hovered item
- return hovered_item_path
+ -- Return the path of the hovered item
+ return hovered_item_path
end)
-- Function to get if the hovered item is a directory
---@type fun(): boolean
local hovered_item_is_dir = ya.sync(function(_)
- --
+ --
- -- Get the hovered item
- local hovered_item = cx.active.current.hovered
+ -- Get the hovered item
+ local hovered_item = cx.active.current.hovered
- -- Return if the hovered item exists and is a directory
- return hovered_item and hovered_item.cha.is_dir
+ -- Return if the hovered item exists and is a directory
+ return hovered_item and hovered_item.cha.is_dir
end)
-- Function to get if the hovered item is an archive
---@type fun(): boolean
local hovered_item_is_archive = ya.sync(function(_)
- --
+ --
- -- Get the hovered item
- local hovered_item = cx.active.current.hovered
+ -- Get the hovered item
+ local hovered_item = cx.active.current.hovered
- -- Return if the hovered item exists and is an archive
- return hovered_item and is_archive_mime_type(hovered_item:mime())
+ -- Return if the hovered item exists and is an archive
+ return hovered_item and is_archive_mime_type(hovered_item:mime())
end)
-- Function to get the paths of the selected items
---@type fun(
---- quote: boolean|nil, -- Whether to escape the characters in the path
+--- quote: boolean|nil, -- Whether to escape the characters in the path
---): string[]|nil The list of paths of the selected items
local get_paths_of_selected_items = ya.sync(function(_, quote)
- --
+ --
- -- Get the selected items
- local selected_items = cx.active.selected
+ -- Get the selected items
+ local selected_items = cx.active.selected
- -- If there are no selected items, exit the function
- if #selected_items == 0 then return end
+ -- If there are no selected items, exit the function
+ if #selected_items == 0 then return end
- -- Initialise the list of paths of the selected items
- local paths_of_selected_items = {}
+ -- Initialise the list of paths of the selected items
+ local paths_of_selected_items = {}
- -- Iterate over the selected items
- for _, item in pairs(selected_items) do
- --
+ -- Iterate over the selected items
+ for _, item in pairs(selected_items) do
+ --
- -- Convert the url of the item to a string
- local item_path = tostring(item)
+ -- Convert the url of the item to a string
+ local item_path = tostring(item)
- -- If the quote flag is passed,
- -- then quote the path of the item
- if quote then item_path = ya.quote(item_path) end
+ -- If the quote flag is passed,
+ -- then quote the path of the item
+ if quote then item_path = ya.quote(item_path) end
- -- Add the path of the item to the list of paths
- table.insert(paths_of_selected_items, item_path)
- end
+ -- Add the path of the item to the list of paths
+ table.insert(paths_of_selected_items, item_path)
+ end
- -- Return the list of paths of the selected items
- return paths_of_selected_items
+ -- Return the list of paths of the selected items
+ return paths_of_selected_items
end)
+-- Function to get the number of tabs currently open
+---@type fun(): number
+local get_number_of_tabs = ya.sync(function() return #cx.tabs end)
+
-- Function to get the tab preferences
---@type fun(): tab.Preference
local get_tab_preferences = ya.sync(function(_)
- --
+ --
- -- Create the table to store the tab preferences
- local tab_preferences = {}
+ -- Create the table to store the tab preferences
+ local tab_preferences = {}
- -- Iterate over the tab preference keys
- for key, _ in pairs(TAB_PREFERENCE_KEYS) do
- --
+ -- Iterate over the tab preference keys
+ for key, _ in pairs(TAB_PREFERENCE_KEYS) do
+ --
- -- Set the key in the table to the value
- -- from the state
- tab_preferences[key] = cx.active.pref[key]
- end
+ -- Set the key in the table to the value
+ -- from the state
+ tab_preferences[key] = cx.active.pref[key]
+ end
- -- Return the tab preferences
- return tab_preferences
+ -- Return the tab preferences
+ return tab_preferences
end)
-- Function to get if Yazi is loading
---@type fun(): boolean
local yazi_is_loading = ya.sync(
- function(_) return cx.active.current.stage.is_loading end
+ function(_) return cx.active.current.stage.is_loading end
)
-- Function to wait until Yazi is loaded
---@return nil
local function wait_until_yazi_is_loaded()
- while yazi_is_loading() do
- end
+ while yazi_is_loading() do
+ end
end
-- Function to choose which group of items to operate on.
@@ -1080,120 +1059,120 @@ end
-- to prompt the user.
---@type fun(): ItemGroup|nil The desired item group
local get_item_group_from_state = ya.sync(function(state)
- --
+ --
- -- Get the hovered item
- local hovered_item = cx.active.current.hovered
+ -- Get the hovered item
+ local hovered_item = cx.active.current.hovered
- -- The boolean representing that there are no selected items
- local no_selected_items = #cx.active.selected == 0
+ -- The boolean representing that there are no selected items
+ local no_selected_items = #cx.active.selected == 0
- -- If there is no hovered item
- if not hovered_item then
- --
+ -- If there is no hovered item
+ if not hovered_item then
+ --
- -- If there are no selected items, exit the function
- if no_selected_items then
- return
+ -- If there are no selected items, exit the function
+ if no_selected_items then
+ return
- -- Otherwise, if the configuration is set to have a hovered item,
- -- exit the function
- elseif state.config.must_have_hovered_item then
- return
+ -- Otherwise, if the configuration is set to have a hovered item,
+ -- exit the function
+ elseif state.config.must_have_hovered_item then
+ return
- -- Otherwise, return the enum for the selected items
- else
- return ItemGroup.Selected
- end
+ -- Otherwise, return the enum for the selected items
+ else
+ return ItemGroup.Selected
+ end
- -- Otherwise, there is a hovered item
- -- and if there are no selected items,
- -- return the enum for the hovered item.
- elseif no_selected_items then
- return ItemGroup.Hovered
+ -- Otherwise, there is a hovered item
+ -- and if there are no selected items,
+ -- return the enum for the hovered item.
+ elseif no_selected_items then
+ return ItemGroup.Hovered
- -- Otherwise if there are selected items and the user wants a prompt,
- -- then tells the calling function to prompt them
- elseif state.config.prompt then
- return ItemGroup.Prompt
+ -- Otherwise if there are selected items and the user wants a prompt,
+ -- then tells the calling function to prompt them
+ elseif state.config.prompt then
+ return ItemGroup.Prompt
- -- Otherwise, if the hovered item is selected,
- -- then return the enum for the selected items
- elseif hovered_item:is_selected() then
- return ItemGroup.Selected
+ -- Otherwise, if the hovered item is selected,
+ -- then return the enum for the selected items
+ elseif hovered_item:is_selected() then
+ return ItemGroup.Selected
- -- Otherwise, return the enum for the hovered item
- else
- return ItemGroup.Hovered
- end
+ -- Otherwise, return the enum for the hovered item
+ else
+ return ItemGroup.Hovered
+ end
end)
-- Function to prompt the user for their desired item group
---@return ItemGroup|nil item_group The item group selected by the user
local function prompt_for_desired_item_group()
- --
+ --
- -- Get the configuration
- local config = get_config()
+ -- Get the configuration
+ local config = get_config()
- -- Get the default item group
- ---@type ItemGroup|nil
- local default_item_group = config.default_item_group_for_prompt
+ -- Get the default item group
+ ---@type ItemGroup|nil
+ local default_item_group = config.default_item_group_for_prompt
- -- Get the input options
- local input_options = INPUT_OPTIONS_TABLE[default_item_group]
+ -- Get the input options
+ local input_options = INPUT_OPTIONS_TABLE[default_item_group]
- -- If the default item group is None, then set it to nil
- if default_item_group == ItemGroup.None then default_item_group = nil end
+ -- 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
- )
+ -- Prompt the user for their input
+ local user_input, event = get_user_input(
+ "Operate on hovered or selected items? " .. input_options
+ )
- -- If the user input is empty, then exit the function
- if not user_input then return end
+ -- If the user input is empty, then exit the function
+ if not user_input then return end
- -- Lowercase the user's input
- user_input = user_input:lower()
+ -- Lowercase the user's input
+ user_input = user_input:lower()
- -- If the user did not confirm the input, exit the function
- if event ~= 1 then
- return
+ -- If the user did not confirm the input, exit the function
+ if event ~= 1 then
+ return
- -- Otherwise, if the user's input starts with "h",
- -- return the item group representing the hovered item
- elseif user_input:find("^h") then
- return ItemGroup.Hovered
+ -- Otherwise, if the user's input starts with "h",
+ -- return the item group representing the hovered item
+ elseif user_input:find("^h") then
+ return ItemGroup.Hovered
- -- Otherwise, if the user's input starts with "s",
- -- return the item group representing the selected items
- elseif user_input:find("^s") then
- return ItemGroup.Selected
+ -- Otherwise, if the user's input starts with "s",
+ -- return the item group representing the selected items
+ elseif user_input:find("^s") then
+ return ItemGroup.Selected
- -- Otherwise, return the default item group
- else
- return default_item_group
- end
+ -- Otherwise, return the default item group
+ else
+ return default_item_group
+ end
end
-- Function to get the item group
---@return ItemGroup|nil item_group The desired item group
local function get_item_group()
- --
+ --
- -- Get the item group from the state
- local item_group = get_item_group_from_state()
+ -- Get the item group from the state
+ local item_group = get_item_group_from_state()
- -- If the item group isn't the prompt one,
- -- then return the item group immediately
- if item_group ~= ItemGroup.Prompt then
- return item_group
+ -- If the item group isn't the prompt one,
+ -- then return the item group immediately
+ if item_group ~= ItemGroup.Prompt then
+ return item_group
- -- Otherwise, prompt the user for the desired item group
- else
- return prompt_for_desired_item_group()
- end
+ -- Otherwise, prompt the user for the desired item group
+ else
+ return prompt_for_desired_item_group()
+ end
end
-- Function to get all the items in the given directory
@@ -1202,93 +1181,93 @@ end
---@param directories_only boolean|nil Whether to only get directories
---@return string[] directory_items The list of urls to the directory items
local function get_directory_items(
- directory_path,
- get_hidden_items,
- directories_only
+ directory_path,
+ get_hidden_items,
+ directories_only
)
- --
+ --
- -- Initialise the list of directory items
- ---@type string[]
- local directory_items = {}
+ -- Initialise the list of directory items
+ ---@type string[]
+ local directory_items = {}
- -- Read the contents of the directory
- local directory_contents, _ = fs.read_dir(Url(directory_path), {})
+ -- Read the contents of the directory
+ local directory_contents, _ = fs.read_dir(Url(directory_path), {})
- -- If there are no directory contents,
- -- then return the empty list of directory items
- if not directory_contents then return directory_items end
+ -- If there are no directory contents,
+ -- then return the empty list of directory items
+ if not directory_contents then return directory_items end
- -- Iterate over the directory contents
- for _, item in ipairs(directory_contents) do
- --
+ -- Iterate over the directory contents
+ for _, item in ipairs(directory_contents) do
+ --
- -- If the get hidden items flag is set to false
- -- and the item is a hidden item,
- -- then continue the loop
- if not get_hidden_items and item.cha.is_hidden then goto continue end
+ -- If the get hidden items flag is set to false
+ -- and the item is a hidden item,
+ -- then continue the loop
+ if not get_hidden_items and item.cha.is_hidden then goto continue end
- -- If the directories only flag is passed
- -- and the item is not a directory,
- -- then continue the loop
- if directories_only and not item.cha.is_dir then goto continue end
+ -- If the directories only flag is passed
+ -- and the item is not a directory,
+ -- then continue the loop
+ if directories_only and not item.cha.is_dir then goto continue end
- -- Otherwise, add the item path to the list of directory items
- table.insert(directory_items, tostring(item.url))
+ -- Otherwise, add the item path to the list of directory items
+ table.insert(directory_items, tostring(item.url))
- -- The continue label to continue the loop
- ::continue::
- end
+ -- The continue label to continue the loop
+ ::continue::
+ end
- -- Return the list of directory items
- return directory_items
+ -- Return the list of directory items
+ return directory_items
end
-- Function to skip child directories with only one directory
---@param initial_directory_path string The path of the initial directory
---@return nil
local function skip_single_child_directories(initial_directory_path)
- --
+ --
- -- Initialise the directory variable to the initial directory given
- local directory = initial_directory_path
+ -- Initialise the directory variable to the initial directory given
+ local directory = initial_directory_path
- -- Get the tab preferences
- local tab_preferences = get_tab_preferences()
+ -- Get the tab preferences
+ local tab_preferences = get_tab_preferences()
- -- Start an infinite loop
- while true do
- --
+ -- Start an infinite loop
+ while true do
+ --
- -- Get all the items in the current directory
- local directory_items =
- get_directory_items(directory, tab_preferences.show_hidden)
+ -- Get all the items in the current directory
+ local directory_items =
+ get_directory_items(directory, tab_preferences.show_hidden)
- -- If the number of directory items is not 1,
- -- then break out of the loop.
- if #directory_items ~= 1 then break end
+ -- If the number of directory items is not 1,
+ -- then break out of the loop.
+ if #directory_items ~= 1 then break end
- -- Otherwise, get the directory item
- local directory_item = table.unpack(directory_items)
+ -- Otherwise, get the directory item
+ local directory_item = table.unpack(directory_items)
- -- Get the cha object of the directory item
- -- and don't follow symbolic links
- local directory_item_cha = fs.cha(Url(directory_item), false)
+ -- Get the cha object of the directory item
+ -- and don't follow symbolic links
+ local directory_item_cha = fs.cha(Url(directory_item), false)
- -- If the cha object of the directory item is nil
- -- then break the loop
- if not directory_item_cha then break end
+ -- If the cha object of the directory item is nil
+ -- then break the loop
+ if not directory_item_cha then break end
- -- If the directory item is not a directory,
- -- break the loop
- if not directory_item_cha.is_dir then break end
+ -- If the directory item is not a directory,
+ -- break the loop
+ if not directory_item_cha.is_dir then break end
- -- Otherwise, set the directory to the inner directory
- directory = directory_item
- end
+ -- Otherwise, set the directory to the inner directory
+ directory = directory_item
+ end
- -- Emit the change directory command to change to the directory variable
- ya.manager_emit("cd", { directory })
+ -- Emit the change directory command to change to the directory variable
+ ya.manager_emit("cd", { directory })
end
-- Class implementations
@@ -1299,51 +1278,51 @@ end
---@param config Configuration The configuration object
---@return Extractor|nil instance An instance of the extractor if available
function Extractor:new(archive_path, destination_path, config)
- --
+ --
- -- Initialise whether the extractor is available
- local available = false
+ -- Initialise whether the extractor is available
+ local available = false
- -- Iterate over the commands
- for _, command in ipairs(self.commands) do
- --
+ -- Iterate over the commands
+ for _, command in ipairs(self.commands) do
+ --
- -- Call the shell command exists function
- -- on the command
- local exists = async_shell_command_exists(command)
+ -- Call the shell command exists function
+ -- on the command
+ local exists = async_shell_command_exists(command)
- -- If the command exists
- if exists then
- --
+ -- If the command exists
+ if exists then
+ --
- -- Save the command
- self.command = command
+ -- Save the command
+ self.command = command
- -- Set the available variable to true
- available = true
+ -- Set the available variable to true
+ available = true
- -- Break out of the loop
- break
- end
- end
+ -- Break out of the loop
+ break
+ end
+ end
- -- If none of the commands for the extractor are available,
- -- then return nil
- if not available then return nil end
+ -- If none of the commands for the extractor are available,
+ -- then return nil
+ if not available then return nil end
- -- Otherwise, create a new instance
- local instance = setmetatable({}, self)
+ -- Otherwise, create a new instance
+ local instance = setmetatable({}, self)
- -- Set where to find the object's methods or properties
- self.__index = self
+ -- Set where to find the object's methods or properties
+ self.__index = self
- -- Save the parameters given
- self.archive_path = archive_path
- self.destination_path = destination_path
- self.config = config
+ -- Save the parameters given
+ self.archive_path = archive_path
+ self.destination_path = destination_path
+ self.config = config
- -- Return the instance
- return instance
+ -- Return the instance
+ return instance
end
-- Function to retry the extractor
@@ -1352,264 +1331,264 @@ end
---@param clean_up_wanted boolean|nil Whether to clean up the destination path
---@return ExtractionResult result Result of the extractor function
function SevenZip:retry_extractor(extractor_function, clean_up_wanted)
- --
+ --
- -- Initialise the number of tries
- -- to the number of retries plus 1
- local total_number_of_tries = self.config.extract_retries + 1
+ -- Initialise the number of tries
+ -- to the number of retries plus 1
+ local total_number_of_tries = self.config.extract_retries + 1
- -- Get the url of the archive
- ---@type Url
- local archive_url = Url(self.archive_path)
+ -- Get the url of the archive
+ ---@type Url
+ local archive_url = Url(self.archive_path)
- -- Get the archive name
- local archive_name = archive_url:name()
+ -- Get the archive name
+ local archive_name = archive_url:name()
- -- If the archive name is nil,
- -- return the result of the extractor function
- if not archive_name then
- return {
- successful = false,
- error = string.format("%s does not have a name", self.archive_path),
- }
- end
+ -- If the archive name is nil,
+ -- return the result of the extractor function
+ if not archive_name then
+ return {
+ successful = false,
+ error = string.format("%s does not have a name", self.archive_path),
+ }
+ end
- -- Initialise the initial password prompt
- local initial_password_prompt = string.format("%s password:", archive_name)
+ -- Initialise the initial password prompt
+ local initial_password_prompt = string.format("%s password:", archive_name)
- -- Initialise the wrong password prompt
- local wrong_password_prompt =
- string.format("Wrong password, %s password:", archive_name)
+ -- Initialise the wrong password prompt
+ local wrong_password_prompt =
+ string.format("Wrong password, %s password:", archive_name)
- -- Initialise the clean up function
- local clean_up = clean_up_wanted
- and function() fs.remove("dir_all", Url(self.destination_path)) end
- or function() end
+ -- Initialise the clean up function
+ local clean_up = clean_up_wanted
+ and function() fs.remove("dir_all", Url(self.destination_path)) end
+ or function() end
- -- Initialise the error message
- local error_message = nil
+ -- Initialise the error message
+ local error_message = nil
- -- Iterate over the number of times to try the extraction
- for tries = 0, total_number_of_tries do
- --
+ -- Iterate over the number of times to try the extraction
+ for tries = 0, total_number_of_tries do
+ --
- -- Execute the extractor function
- local output, error = extractor_function()
+ -- Execute the extractor function
+ local output, error = extractor_function()
- -- If there is no output
- if not output then
- --
+ -- If there is no output
+ if not output then
+ --
- -- Clean up the extracted files
- clean_up()
+ -- Clean up the extracted files
+ clean_up()
- -- Return the result of the extractor function
- return {
- successful = false,
- error = tostring(error),
- }
- end
+ -- Return the result of the extractor function
+ return {
+ successful = false,
+ error = tostring(error),
+ }
+ end
- -- If the output status code is 0,
- -- which means the command was successful,
- -- return the result of the extractor function
- if output.status.code == 0 then
- return {
- successful = true,
- output = output.stdout,
- }
- end
+ -- If the output status code is 0,
+ -- which means the command was successful,
+ -- return the result of the extractor function
+ if output.status.code == 0 then
+ return {
+ successful = true,
+ output = output.stdout,
+ }
+ end
- -- Set the error message to the standard error
- error_message = output.stderr
+ -- Set the error message to the standard error
+ error_message = output.stderr
- -- If the command failed for a reason other
- -- than the archive being encrypted,
- -- or if the current try count
- -- is the same as the total number of tries
- if
- not (
- output.status.code == 2
- and error_message:lower():find("wrong password")
- ) or tries == total_number_of_tries
- then
- --
+ -- If the command failed for a reason other
+ -- than the archive being encrypted,
+ -- or if the current try count
+ -- is the same as the total number of tries
+ if
+ not (
+ output.status.code == 2
+ and error_message:lower():find("wrong password")
+ ) or tries == total_number_of_tries
+ then
+ --
- -- Clean up the extracted files
- clean_up()
+ -- Clean up the extracted files
+ clean_up()
- -- Return the extractor function result
- return {
- successful = false,
- error = error_message,
- }
- end
+ -- Return the extractor function result
+ return {
+ successful = false,
+ error = error_message,
+ }
+ end
- -- Otherwise, get the prompt for the password
- local password_prompt = tries == 0 and initial_password_prompt
- or wrong_password_prompt
+ -- Otherwise, get the prompt for the password
+ local password_prompt = tries == 0 and initial_password_prompt
+ or wrong_password_prompt
- -- Initialise the width of the input element
- local input_width = DEFAULT_INPUT_OPTIONS.position.w
+ -- Initialise the width of the input element
+ local input_width = DEFAULT_INPUT_OPTIONS.position.w
- -- If the length of the password prompt is larger
- -- than the default input with, set the input width
- -- to the length of the password prompt + 1
- if #password_prompt > input_width then
- input_width = #password_prompt + 1
- end
+ -- If the length of the password prompt is larger
+ -- than the default input with, set the input width
+ -- to the length of the password prompt + 1
+ if #password_prompt > input_width then
+ input_width = #password_prompt + 1
+ end
- -- Get the new position object
- -- for the new input element
- ---@type Position
- local new_position =
- merge_tables(DEFAULT_INPUT_OPTIONS.position, { w = input_width })
+ -- Get the new position object
+ -- for the new input element
+ ---@type Position
+ local new_position =
+ merge_tables(DEFAULT_INPUT_OPTIONS.position, { w = input_width })
- -- Ask the user for the password
- local user_input, event =
- ---@diagnostic disable-next-line: missing-fields
- get_user_input(password_prompt, { position = new_position })
+ -- Ask the user for the password
+ local user_input, event =
+ ---@diagnostic disable-next-line: missing-fields
+ get_user_input(password_prompt, { position = new_position })
- -- If the user has confirmed the input,
- -- and the user input is not nil,
- -- set the password to the user's input
- if event == 1 and user_input ~= nil then
- self.password = user_input
+ -- If the user has confirmed the input,
+ -- and the user input is not nil,
+ -- set the password to the user's input
+ if event == 1 and user_input ~= nil then
+ self.password = user_input
- -- Otherwise
- else
- --
+ -- Otherwise
+ else
+ --
- -- Call the clean up function
- clean_up()
+ -- Call the clean up function
+ clean_up()
- -- Return the result of the extractor command
- return {
- successful = false,
- cancelled = true,
- error = error_message,
- }
- end
- end
+ -- Return the result of the extractor command
+ return {
+ successful = false,
+ cancelled = true,
+ error = error_message,
+ }
+ end
+ end
- -- If all the tries have been exhausted,
- -- call the clean up function
- clean_up()
+ -- If all the tries have been exhausted,
+ -- call the clean up function
+ clean_up()
- -- Return the result of the extractor command
- return {
- successful = false,
- error = error_message,
- }
+ -- Return the result of the extractor command
+ return {
+ successful = false,
+ error = error_message,
+ }
end
-- Function to list the archive items with the command
---@type ExtractorListItemsCommand
function SevenZip:list_items_command()
- --
+ --
- -- Initialise the arguments for the command
- local arguments = {
+ -- Initialise the arguments for the command
+ local arguments = {
- -- List the items in the archive
- "l",
+ -- List the items in the archive
+ "l",
- -- Use UTF-8 encoding for console input and output
- "-sccUTF-8",
+ -- Use UTF-8 encoding for console input and output
+ "-sccUTF-8",
- -- Pass the password to the command
- "-p" .. self.password,
+ -- Pass the password to the command
+ "-p" .. self.password,
- -- Remove the headers (undocumented switch)
- "-ba",
+ -- Remove the headers (undocumented switch)
+ "-ba",
- -- The archive path
- self.archive_path,
- }
+ -- The archive path
+ self.archive_path,
+ }
- -- Return the result of the command to list the items in the archive
- return Command(self.command)
- :args(arguments)
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :output()
+ -- Return the result of the command to list the items in the archive
+ return Command(self.command)
+ :args(arguments)
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :output()
end
-- Function to get the items in the archive
---@type ExtractorGetItems
function SevenZip:get_items()
- --
+ --
- -- Initialise the list of files in the archive
- ---@type string[]
- local files = {}
+ -- Initialise the list of files in the archive
+ ---@type string[]
+ local files = {}
- -- Initialise the list of directories
- ---@type string[]
- local directories = {}
+ -- Initialise the list of directories
+ ---@type string[]
+ local directories = {}
- -- Call the function to retry the extractor command
- -- with the list items in the archive function
- local extractor_result = self:retry_extractor(
- function() return self:list_items_command() end
- )
+ -- Call the function to retry the extractor command
+ -- with the list items in the archive function
+ local extractor_result = self:retry_extractor(
+ function() return self:list_items_command() end
+ )
- -- Get the output
- local output = extractor_result.output
+ -- Get the output
+ local output = extractor_result.output
- -- Get the error
- local error = extractor_result.error
+ -- Get the error
+ local error = extractor_result.error
- -- If the extractor 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
- return files, directories, error
- end
+ -- If the extractor 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
+ return files, directories, error
+ end
- -- Otherwise, split the output at the newline character
- local output_lines = string_split(output, "\n")
+ -- Otherwise, split the output at the newline character
+ local output_lines = string_split(output, "\n")
- -- The pattern to get the information from an archive item
- ---@type string
- local archive_item_info_pattern = "%s+([%.%a]+)%s+(%d+)%s+(%d+)%s+(.+)$"
+ -- The pattern to get the information from an archive item
+ ---@type string
+ local archive_item_info_pattern = "%s+([%.%a]+)%s+(%d+)%s+(%d+)%s+(.+)$"
- -- Iterate over the lines of the output
- for _, line in ipairs(output_lines) do
- --
+ -- Iterate over the lines of the output
+ for _, line in ipairs(output_lines) do
+ --
- -- Get the information about the archive item from the line.
- -- The information is in the format:
- -- Attributes, Size, Compressed Size, File Path
- local attributes, _, _, file_path =
- line:match(archive_item_info_pattern)
+ -- Get the information about the archive item from the line.
+ -- The information is in the format:
+ -- Attributes, Size, Compressed Size, File Path
+ local attributes, _, _, file_path =
+ line:match(archive_item_info_pattern)
- -- If the file path doesn't exist, then continue the loop
- if not file_path then goto continue end
+ -- If the file path doesn't exist, then continue the loop
+ if not file_path then goto continue end
- -- If the attributes of the item starts with a "D",
- -- which means the item is a directory
- if attributes and attributes:find("^D") then
- --
+ -- If the attributes of the item starts with a "D",
+ -- which means the item is a directory
+ if attributes and attributes:find("^D") then
+ --
- -- Add the directory to the list of directories
- table.insert(directories, file_path)
+ -- Add the directory to the list of directories
+ table.insert(directories, file_path)
- -- Continue the loop
- goto continue
- end
+ -- Continue the loop
+ goto continue
+ end
- -- Otherwise, add the file path to the list of archive items
- table.insert(files, file_path)
+ -- Otherwise, add the file path to the list of archive items
+ table.insert(files, file_path)
- -- The continue label to continue the loop
- ::continue::
- end
+ -- The continue label to continue the loop
+ ::continue::
+ end
- -- Return the list of files, the list of directories,
- -- the error message, and the password
- return files, directories, error
+ -- Return the list of files, the list of directories,
+ -- the error message, and the password
+ return files, directories, error
end
-- Function to extract an archive using the command
@@ -1618,213 +1597,213 @@ end
---@return CommandOutput|nil output The output of the command
---@return Error|nil error The error if any
function SevenZip:extract_command(extract_files_only, extract_behaviour)
- --
+ --
- -- Initialise the extract files only flag to false if it's not given
- extract_files_only = extract_files_only or false
+ -- Initialise the extract files only flag to false if it's not given
+ extract_files_only = extract_files_only or false
- -- Initialise the extract behaviour to rename if it's not given
- extract_behaviour =
- self.extract_behaviour_map[extract_behaviour or ExtractBehaviour.Rename]
+ -- Initialise the extract behaviour to rename if it's not given
+ extract_behaviour =
+ self.extract_behaviour_map[extract_behaviour or ExtractBehaviour.Rename]
- -- Initialise the extraction mode to use.
- -- By default, it extracts the archive with
- -- full paths, which keeps the archive structure.
- local extraction_mode = "x"
+ -- Initialise the extraction mode to use.
+ -- By default, it extracts the archive with
+ -- full paths, which keeps the archive structure.
+ local extraction_mode = "x"
- -- If the extract files only flag is passed
- if extract_files_only then
- --
+ -- If the extract files only flag is passed
+ if extract_files_only then
+ --
- -- Use the regular extract,
- -- without the full paths, which will move
- -- all files in the archive into the current directory
- -- and ignore the archive folder structure.
- extraction_mode = "e"
- end
+ -- Use the regular extract,
+ -- without the full paths, which will move
+ -- all files in the archive into the current directory
+ -- and ignore the archive folder structure.
+ extraction_mode = "e"
+ end
- -- Initialise the arguments for the command
- local arguments = {
+ -- Initialise the arguments for the command
+ local arguments = {
- -- The extraction mode
- extraction_mode,
+ -- The extraction mode
+ extraction_mode,
- -- Assume yes to all prompts
- "-y",
+ -- Assume yes to all prompts
+ "-y",
- -- Use UTF-8 encoding for console input and output
- "-sccUTF-8",
+ -- Use UTF-8 encoding for console input and output
+ "-sccUTF-8",
- -- Configure the extraction behaviour
- extract_behaviour,
+ -- Configure the extraction behaviour
+ extract_behaviour,
- -- Pass the password to the command
- "-p" .. self.password,
+ -- Pass the password to the command
+ "-p" .. self.password,
- -- The archive file to extract
- self.archive_path,
+ -- The archive file to extract
+ self.archive_path,
- -- The destination directory path
- "-o" .. self.destination_path,
- }
+ -- The destination directory path
+ "-o" .. self.destination_path,
+ }
- -- Return the command to extract the archive
- return Command(self.command)
- :args(arguments)
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :output()
+ -- Return the command to extract the archive
+ return Command(self.command)
+ :args(arguments)
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :output()
end
-- Function to extract the archive
---@type ExtractorExtract
function SevenZip:extract(has_only_one_file)
- --
+ --
- -- Extract the archive with the extractor command
- local result = self:retry_extractor(
- function() return self:extract_command(has_only_one_file) end,
- true
- )
+ -- Extract the archive with the extractor command
+ local result = self:retry_extractor(
+ function() return self:extract_command(has_only_one_file) end,
+ true
+ )
- -- Return the extractor result
- return result
+ -- Return the extractor result
+ return result
end
-- Function to list the archive items with the command
---@type ExtractorListItemsCommand
function Tar:list_items_command()
- --
+ --
- -- Initialise the arguments for the command
- local arguments = {
+ -- Initialise the arguments for the command
+ local arguments = {
- -- List the items in the archive
- "-t",
+ -- List the items in the archive
+ "-t",
- -- Pass the file
- "-f",
+ -- Pass the file
+ "-f",
- -- The archive file path
- self.archive_path,
- }
+ -- The archive file path
+ self.archive_path,
+ }
- -- Return the result of the command
- return Command(self.command)
- :args(arguments)
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :output()
+ -- Return the result of the command
+ return Command(self.command)
+ :args(arguments)
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :output()
end
-- Function to get the items in the archive
---@type ExtractorGetItems
function Tar:get_items()
- --
+ --
- -- Call the function to get the list of items in the archive
- local output, error = self:list_items_command()
+ -- Call the function to get the list of items in the archive
+ local output, error = self:list_items_command()
- -- Initialise the list of files
- ---@type string[]
- local files = {}
+ -- Initialise the list of files
+ ---@type string[]
+ local files = {}
- -- Initialise the list of directories
- ---@type string[]
- local directories = {}
+ -- Initialise the list of directories
+ ---@type string[]
+ local directories = {}
- -- If there is no output, return the empty lists and the error
- if not output then return files, directories, tostring(error) end
+ -- If there is no output, return the empty lists and the error
+ if not output then return files, directories, tostring(error) end
- -- Otherwise, split the output into lines and iterate over it
- for _, line in ipairs(string_split(output.stdout, "\n")) do
- --
+ -- Otherwise, split the output into lines and iterate over it
+ for _, line in ipairs(string_split(output.stdout, "\n")) do
+ --
- -- If the line ends with a slash, it's a directory
- if line:sub(-1) == "/" then
- --
+ -- If the line ends with a slash, it's a directory
+ if line:sub(-1) == "/" then
+ --
- -- Add the directory without the trailing slash
- -- to the list of directories
- table.insert(directories, line:sub(1, -2))
+ -- Add the directory without the trailing slash
+ -- to the list of directories
+ table.insert(directories, line:sub(1, -2))
- -- Continue the loop
- goto continue
- end
+ -- Continue the loop
+ goto continue
+ end
- -- Otherwise, the item is a file, so add it to the list of files
- table.insert(files, line)
+ -- Otherwise, the item is a file, so add it to the list of files
+ table.insert(files, line)
- -- The label to continue the loop
- ::continue::
- end
+ -- The label to continue the loop
+ ::continue::
+ end
- -- Return the list of files and directories and the error
- return files, directories, output.stderr
+ -- Return the list of files and directories and the error
+ return files, directories, output.stderr
end
-- Function to extract an archive using the command
---@param extract_behaviour ExtractBehaviour|nil The extract behaviour to use
function Tar:extract_command(extract_behaviour)
- --
+ --
- -- Initialise the extract behaviour to rename if it is not given
- extract_behaviour =
- self.extract_behaviour_map[extract_behaviour or ExtractBehaviour.Rename]
+ -- Initialise the extract behaviour to rename if it is not given
+ extract_behaviour =
+ self.extract_behaviour_map[extract_behaviour or ExtractBehaviour.Rename]
- -- Initialise the arguments for the command
- local arguments = {
+ -- Initialise the arguments for the command
+ local arguments = {
- -- Extract the archive
- "-x",
+ -- Extract the archive
+ "-x",
- -- Verbose
- "-v",
+ -- Verbose
+ "-v",
- -- The extract behaviour flag
- extract_behaviour,
+ -- The extract behaviour flag
+ extract_behaviour,
- -- Specify the destination directory
- "-C",
+ -- Specify the destination directory
+ "-C",
- -- The destination directory path
- self.destination_path,
- }
+ -- The destination directory path
+ self.destination_path,
+ }
- -- If keeping permissions is wanted, add the -p flag
- if self.config.preserve_file_permissions then
- table.insert(arguments, "-p")
- end
+ -- If keeping permissions is wanted, add the -p flag
+ if self.config.preserve_file_permissions then
+ table.insert(arguments, "-p")
+ end
- -- Add the -f flag and the archive path to the arguments
- table.insert(arguments, "-f")
- table.insert(arguments, self.archive_path)
+ -- Add the -f flag and the archive path to the arguments
+ table.insert(arguments, "-f")
+ table.insert(arguments, self.archive_path)
- -- Create the destination path first.
- --
- -- This is required because tar does not
- -- automatically create the directory
- -- pointed to by the -C flag.
- -- Instead, tar just tries to change
- -- the working directory to the directory
- -- pointed to by the -C flag, which can
- -- fail if the directory does not exist.
- --
- -- GNU tar has a --one-top-level=[DIR] option,
- -- which will automatically create the directory
- -- given, but macOS tar does not have this option.
- --
- -- The error here is ignored because if there
- -- is an error creating the directory,
- -- then the extractor will fail anyway.
- fs.create("dir_all", Url(self.destination_path))
+ -- Create the destination path first.
+ --
+ -- This is required because tar does not
+ -- automatically create the directory
+ -- pointed to by the -C flag.
+ -- Instead, tar just tries to change
+ -- the working directory to the directory
+ -- pointed to by the -C flag, which can
+ -- fail if the directory does not exist.
+ --
+ -- GNU tar has a --one-top-level=[DIR] option,
+ -- which will automatically create the directory
+ -- given, but macOS tar does not have this option.
+ --
+ -- The error here is ignored because if there
+ -- is an error creating the directory,
+ -- then the extractor will fail anyway.
+ fs.create("dir_all", Url(self.destination_path))
- -- Return the output of the command
- return Command(self.command)
- :args(arguments)
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :output()
+ -- Return the output of the command
+ return Command(self.command)
+ :args(arguments)
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :output()
end
-- Function to extract the archive.
@@ -1834,35 +1813,35 @@ end
-- extract compressed tarballs.
---@type ExtractorExtract
function Tar:extract(_)
- --
+ --
- -- Call the command to extract the archive
- local output, error = self:extract_command()
+ -- Call the command to extract the archive
+ local output, error = self:extract_command()
- -- If there is no output, return the result
- if not output then
- return {
- successful = false,
- error = tostring(error),
- }
- end
+ -- If there is no output, return the result
+ if not output then
+ return {
+ successful = false,
+ error = tostring(error),
+ }
+ end
- -- Otherwise, if the status code is not 0,
- -- which means the extraction was not successful,
- -- return the result
- if output.status.code ~= 0 then
- return {
- successful = false,
- output = output.stdout,
- error = output.stderr,
- }
- end
+ -- Otherwise, if the status code is not 0,
+ -- which means the extraction was not successful,
+ -- return the result
+ if output.status.code ~= 0 then
+ return {
+ successful = false,
+ output = output.stdout,
+ error = output.stderr,
+ }
+ end
- -- Otherwise, return the successful result
- return {
- successful = true,
- output = output.stdout,
- }
+ -- Otherwise, return the successful result
+ return {
+ successful = true,
+ output = output.stdout,
+ }
end
-- Functions for the commands
@@ -1874,84 +1853,84 @@ end
---@return ExtractionResult result The results of getting the extractor
---@return Extractor|nil extractor The extractor for the file type
local function get_extractor(archive_path, destination_path, config)
- --
+ --
- -- Get the mime type of the archive file
- local mime_type = get_mime_type(archive_path)
+ -- Get the mime type of the archive file
+ local mime_type = get_mime_type(archive_path)
- -- Get the extractor for the mime type
- local extractor = ARCHIVE_MIME_TYPE_TO_EXTRACTOR_MAP[mime_type]
+ -- Get the extractor for the mime type
+ local extractor = ARCHIVE_MIME_TYPE_TO_EXTRACTOR_MAP[mime_type]
- -- If there is no extractor,
- -- return that it is not successful,
- -- but that it has been cancelled
- -- as the mime type is not an archive
- if not extractor then
- return {
- successful = false,
- cancelled = true,
- }
- end
+ -- If there is no extractor,
+ -- return that it is not successful,
+ -- but that it has been cancelled
+ -- as the mime type is not an archive
+ if not extractor then
+ return {
+ successful = false,
+ cancelled = true,
+ }
+ end
- -- Instantiate an instance of the extractor
- local extractor_instance =
- extractor:new(archive_path, destination_path, config)
+ -- Instantiate an instance of the extractor
+ local extractor_instance =
+ extractor:new(archive_path, destination_path, config)
- -- While the extractor instance failed to be created
- while not extractor_instance do
- --
+ -- While the extractor instance failed to be created
+ while not extractor_instance do
+ --
- -- If the extractor instance is the default extractor,
- -- then return an error telling the user to install the
- -- default extractor
- if extractor.name == DefaultExtractor.name then
- return {
- successful = false,
- error = table.concat({
- string.format(
- "%s is not installed,",
- DefaultExtractor.name
- ),
- "please install it before using the 'extract' command",
- }, " "),
- }
- end
+ -- If the extractor instance is the default extractor,
+ -- then return an error telling the user to install the
+ -- default extractor
+ if extractor.name == DefaultExtractor.name then
+ return {
+ successful = false,
+ error = table.concat({
+ string.format(
+ "%s is not installed,",
+ DefaultExtractor.name
+ ),
+ "please install it before using the 'extract' command",
+ }, " "),
+ }
+ end
- -- Try instantiating the default extractor
- extractor_instance =
- DefaultExtractor:new(archive_path, destination_path, config)
- end
+ -- Try instantiating the default extractor
+ extractor_instance =
+ DefaultExtractor:new(archive_path, destination_path, config)
+ end
- -- If the user wants to preserve file permissions,
- -- and the target extractor for the mime type supports
- -- preserving file permissions, but the extractor
- -- instantiated does not, show a warning to the user
- if
- config.preserve_file_permissions
- and extractor.supports_file_permissions
- and not extractor_instance.supports_file_permissions
- then
- --
+ -- If the user wants to preserve file permissions,
+ -- and the target extractor for the mime type supports
+ -- preserving file permissions, but the extractor
+ -- instantiated does not, show a warning to the user
+ if
+ config.preserve_file_permissions
+ and extractor.supports_file_permissions
+ and not extractor_instance.supports_file_permissions
+ then
+ --
- -- The warning to show the user
- local warning = table.concat({
- string.format(
- "%s is not installed, defaulting to %s.",
- extractor.name,
- extractor_instance.name
- ),
- string.format(
- "However, %s does not support preserving file permissions.",
- extractor_instance.name
- ),
- }, "\n")
+ -- The warning to show the user
+ local warning = table.concat({
+ string.format(
+ "%s is not installed, defaulting to %s.",
+ extractor.name,
+ extractor_instance.name
+ ),
+ string.format(
+ "However, %s does not support preserving file permissions.",
+ extractor_instance.name
+ ),
+ }, "\n")
- -- Show the warning to the user
- show_warning(warning)
- end
+ -- Show the warning to the user
+ show_warning(warning)
+ end
- -- Return the extractor instance
- return { successful = true }, extractor_instance
+ -- Return the extractor instance
+ return { successful = true }, extractor_instance
end
-- Function to move the extracted items out of the temporary directory
@@ -1959,144 +1938,144 @@ end
---@param destination_url Url The url of the destination
---@return ExtractionResult result The result of the move
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
- ---@param error string The error message to return
- ---@param empty_dir_only boolean|nil Whether to remove the empty dir only
- ---@return ExtractionResult
- local function fail(error, empty_dir_only)
- --
+ -- The function to clean up the destination directory
+ -- and return the extractor 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 ExtractionResult
+ local function fail(error, empty_dir_only)
+ --
- -- Clean up the destination path
- fs.remove(empty_dir_only and "dir" or "dir_all", destination_url)
+ -- Clean up the destination path
+ fs.remove(empty_dir_only and "dir" or "dir_all", destination_url)
- -- Return the extractor result
- ---@type ExtractionResult
- return {
- successful = false,
- error = error,
- }
- end
+ -- Return the extractor result
+ ---@type ExtractionResult
+ return {
+ successful = false,
+ error = error,
+ }
+ end
- -- Get the extracted items in the destination.
- -- There is a limit of 2 as we just need to
- -- know if the destination contains only
- -- a single item or not.
- local extracted_items = fs.read_dir(destination_url, { limit = 2 })
+ -- Get the extracted items in the destination.
+ -- There is a limit of 2 as we just need to
+ -- know if the destination contains only
+ -- a single item or not.
+ local extracted_items = fs.read_dir(destination_url, { limit = 2 })
- -- If the extracted items doesn't exist,
- -- clean up and return the error
- if not extracted_items then
- return fail(
- string.format(
- "Failed to read the destination directory: %s",
- tostring(destination_url)
- )
- )
- end
+ -- If the extracted items doesn't exist,
+ -- clean up and return the error
+ if not extracted_items then
+ return fail(
+ string.format(
+ "Failed to read the destination directory: %s",
+ tostring(destination_url)
+ )
+ )
+ end
- -- If there are no extracted items,
- -- clean up and return the error
- if #extracted_items == 0 then
- return fail("No files extracted from the archive", true)
- end
+ -- If there are no extracted items,
+ -- clean up and return the error
+ if #extracted_items == 0 then
+ return fail("No files extracted from the archive", true)
+ end
- -- Get the parent directory of the destination
- local parent_directory_url = destination_url:parent()
+ -- Get the parent directory of the destination
+ local parent_directory_url = destination_url:parent()
- -- If the parent directory doesn't exist,
- -- clean up and return the error
- if not parent_directory_url then
- return fail("Destination path has no parent directory")
- end
+ -- If the parent directory doesn't exist,
+ -- clean up and return the error
+ if not parent_directory_url then
+ return fail("Destination path has no parent directory")
+ end
- -- Get the name of the archive without the extension
- local archive_name = archive_url:stem()
+ -- Get the name of the archive without the extension
+ local archive_name = archive_url:stem()
- -- If the name of the archive doesn't exist,
- -- clean up and return the error
- if not archive_name then
- return fail("Archive has no name without its extension")
- end
+ -- If the name of the archive doesn't exist,
+ -- clean up and return the error
+ if not archive_name then
+ return fail("Archive has no name without its extension")
+ end
- -- Get the first extracted item
- local first_extracted_item = table.unpack(extracted_items)
+ -- Get the first extracted item
+ local first_extracted_item = table.unpack(extracted_items)
- -- Initialise the variable to indicate whether the archive has only one item
- local only_one_item = false
+ -- Initialise the variable to indicate whether the archive has only one item
+ local only_one_item = false
- -- Initialise the target directory url to move the extracted items to,
- -- which is the parent directory of the archive
- -- joined with the file name of the archive without the extension
- local target_url = parent_directory_url:join(archive_name)
+ -- Initialise the target directory url to move the extracted items to,
+ -- which is the parent directory of the archive
+ -- joined with the file name of the archive without the extension
+ local target_url = parent_directory_url:join(archive_name)
- -- If there is only one item in the archive
- if #extracted_items == 1 then
- --
+ -- If there is only one item in the archive
+ if #extracted_items == 1 then
+ --
- -- Set the only one item variable to true
- only_one_item = true
+ -- Set the only one item variable to true
+ only_one_item = true
- -- Get the name of the first extracted item
- local first_extracted_item_name = first_extracted_item.url:name()
+ -- Get the name of the first extracted item
+ local first_extracted_item_name = first_extracted_item.url:name()
- -- If the first extracted item has no name,
- -- then clean up and return the error
- if not first_extracted_item_name then
- return fail("The only extracted item has no name")
- end
+ -- If the first extracted item has no name,
+ -- then clean up and return the error
+ if not first_extracted_item_name then
+ return fail("The only extracted item has no name")
+ end
- -- Otherwise, set the target url to the parent directory
- -- of the destination joined with the file name of the extracted item
- target_url = parent_directory_url:join(first_extracted_item_name)
- end
+ -- Otherwise, set the target url to the parent directory
+ -- of the destination joined with the file name of the extracted item
+ target_url = parent_directory_url:join(first_extracted_item_name)
+ end
- -- Get a unique name for the target url
- local unique_target_url = fs.unique_name(target_url)
+ -- Get a unique name for the target url
+ local unique_target_url = fs.unique_name(target_url)
- -- If the unique target url is nil,
- -- clean up and return the error
- if not unique_target_url then
- return fail(
- "Failed to get a unique name to move the extracted items to"
- )
- end
+ -- If the unique target url is nil,
+ -- clean up and return the error
+ if not unique_target_url then
+ return fail(
+ "Failed to get a unique name to move the extracted items to"
+ )
+ end
- -- Set the target path to the string of the target url
- local target_path = tostring(unique_target_url)
+ -- Set the target path to the string of the target url
+ local target_path = tostring(unique_target_url)
- -- Initialise the move successful variable and the error message
- local error_message, move_successful = nil, false
+ -- Initialise the move successful variable and the error message
+ local error_message, move_successful = nil, false
- -- If there is only one item in the archive
- if only_one_item then
- --
+ -- If there is only one item in the archive
+ if only_one_item then
+ --
- -- Move the item to the target path
- move_successful, error_message =
- os.rename(tostring(first_extracted_item.url), target_path)
+ -- Move the item to the target path
+ move_successful, error_message =
+ os.rename(tostring(first_extracted_item.url), target_path)
- -- Otherwise
- else
- --
+ -- Otherwise
+ else
+ --
- -- Rename the destination directory itself to the target path
- move_successful, error_message =
- os.rename(tostring(destination_url), target_path)
- end
+ -- Rename the destination directory itself to the target path
+ move_successful, error_message =
+ os.rename(tostring(destination_url), target_path)
+ end
- -- Clean up the destination directory
- fs.remove(move_successful and "dir" or "dir_all", 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
- -- path to the extracted items
- return {
- successful = move_successful,
- error = error_message,
- extracted_items_path = target_path,
- }
+ -- Return the extractor result with the target path as the
+ -- path to the extracted items
+ return {
+ successful = move_successful,
+ error = error_message,
+ extracted_items_path = target_path,
+ }
end
-- Function to recursively extract archives
@@ -2106,551 +2085,551 @@ end
---@param destination_path string|nil The destination path to extract to
---@return ExtractionResult extraction_result The extraction results
local function recursively_extract_archive(
- archive_path,
- args,
- config,
- destination_path
+ archive_path,
+ args,
+ config,
+ destination_path
)
- --
+ --
- -- Get whether the destination path is given
- local destination_path_given = destination_path ~= nil
+ -- Get whether the destination path is given
+ local destination_path_given = destination_path ~= nil
- -- Initialise the destination path to the archive path if it is not given
- local destination = destination_path or archive_path
+ -- Initialise the destination path to the archive path if it is not given
+ local destination = destination_path or archive_path
- -- Get the temporary directory url
- local temporary_directory_url =
- get_temporary_directory_url(destination, destination_path_given)
+ -- Get the temporary directory url
+ local temporary_directory_url =
+ get_temporary_directory_url(destination, destination_path_given)
- -- If the temporary directory can't be created
- -- then return the result
- if not temporary_directory_url then
- return {
- successful = false,
- error = "Failed to create a temporary directory",
- archive_path = archive_path,
- destination_path = destination_path,
- }
- end
+ -- If the temporary directory can't be created
+ -- then return the result
+ if not temporary_directory_url then
+ return {
+ successful = false,
+ error = "Failed to create a temporary directory",
+ archive_path = archive_path,
+ destination_path = destination_path,
+ }
+ end
- -- Get an extractor for the archive
- local get_extractor_result, extractor =
- get_extractor(archive_path, tostring(temporary_directory_url), config)
+ -- Get an extractor for the archive
+ local get_extractor_result, extractor =
+ get_extractor(archive_path, tostring(temporary_directory_url), config)
- -- If there is no extractor, return the result
- if not extractor then
- return merge_tables(get_extractor_result, {
- archive_path = archive_path,
- destination_path = destination_path,
- })
- end
+ -- If there is no extractor, return the result
+ if not extractor then
+ return merge_tables(get_extractor_result, {
+ archive_path = archive_path,
+ destination_path = destination_path,
+ })
+ end
- -- Function to add additional information to the extraction result
- -- The additional information are:
- -- - The archive path
- -- - The destination path
- -- - The name of the extractor
- ---@param result ExtractionResult The result to add the paths to
- ---@return ExtractionResult 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 = extractor.name,
- })
- end
+ -- Function to add additional information to the extraction result
+ -- The additional information are:
+ -- - The archive path
+ -- - The destination path
+ -- - The name of the extractor
+ ---@param result ExtractionResult The result to add the paths to
+ ---@return ExtractionResult 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 = extractor.name,
+ })
+ end
- -- Get the list of archive files and directories,
- -- the error message and the password
- local archive_files, archive_directories, error = extractor:get_items()
+ -- Get the list of archive files and directories,
+ -- the error message and the password
+ local archive_files, archive_directories, error = extractor:get_items()
- -- If there are no are no archive files and directories
- if #archive_files == 0 and #archive_directories == 0 then
- --
+ -- If there are no are no archive files and directories
+ if #archive_files == 0 and #archive_directories == 0 then
+ --
- -- The extraction result
- ---@type ExtractionResult
- local extraction_result = {
- successful = false,
- error = error or "Archive is empty",
- }
+ -- The extraction result
+ ---@type ExtractionResult
+ local extraction_result = {
+ successful = false,
+ error = error or "Archive is empty",
+ }
- -- Return the extraction result
- return add_additional_info(extraction_result)
- end
+ -- Return the extraction result
+ return add_additional_info(extraction_result)
+ end
- -- Get if the archive has only one file
- local archive_has_only_one_file = #archive_files == 1
- and #archive_directories == 0
+ -- Get if the archive has only one file
+ local archive_has_only_one_file = #archive_files == 1
+ and #archive_directories == 0
- -- Extract the given archive
- local extraction_result = extractor:extract(archive_has_only_one_file)
+ -- Extract the given archive
+ local extraction_result = extractor:extract(archive_has_only_one_file)
- -- If the extraction result is not successful, return it
- if not extraction_result.successful then
- return add_additional_info(extraction_result)
- end
+ -- If the extraction result is not successful, return it
+ if not extraction_result.successful then
+ return add_additional_info(extraction_result)
+ end
- -- Get the result of moving the extracted items
- local move_result =
- move_extracted_items(Url(archive_path), temporary_directory_url)
+ -- Get the result of moving the extracted items
+ local move_result =
+ move_extracted_items(Url(archive_path), temporary_directory_url)
- -- Get the extracted items path
- local extracted_items_path = move_result.extracted_items_path
+ -- Get the extracted items path
+ local extracted_items_path = move_result.extracted_items_path
- -- If moving the extracted items isn't successful,
- -- or if the extracted items path is nil,
- -- or if the user does not want to extract archives recursively,
- -- return the move results
- if
- not move_result.successful
- or not extracted_items_path
- or not config.recursively_extract_archives
- then
- return add_additional_info(move_result)
- end
+ -- If moving the extracted items isn't successful,
+ -- or if the extracted items path is nil,
+ -- or if the user does not want to extract archives recursively,
+ -- return the move results
+ if
+ not move_result.successful
+ or not extracted_items_path
+ or not config.recursively_extract_archives
+ then
+ return add_additional_info(move_result)
+ end
- -- Get the url of the extracted items path
- ---@type Url
- local extracted_items_url = Url(extracted_items_path)
+ -- Get the url of the extracted items path
+ ---@type Url
+ local extracted_items_url = Url(extracted_items_path)
- -- Initialise the base url for the extracted items
- local base_url = extracted_items_url
+ -- Initialise the base url for the extracted items
+ local base_url = extracted_items_url
- -- Get the parent directory of the extracted items path
- local parent_directory_url = extracted_items_url:parent()
+ -- Get the parent directory of the extracted items path
+ local parent_directory_url = extracted_items_url:parent()
- -- If the parent directory doesn't exist
- if not parent_directory_url then
- --
+ -- If the parent directory doesn't exist
+ if not parent_directory_url then
+ --
- -- Modify the move result with a custom error
- ---@type ExtractionResult
- local modified_move_result = merge_tables(move_result, {
- error = "Archive has no parent directory",
- archive_path = archive_path,
- destination_path = destination_path,
- })
+ -- Modify the move result with a custom error
+ ---@type ExtractionResult
+ local modified_move_result = merge_tables(move_result, {
+ error = "Archive has no parent directory",
+ archive_path = archive_path,
+ destination_path = destination_path,
+ })
- -- Return the modified move result
- return modified_move_result
- end
+ -- Return the modified move result
+ return modified_move_result
+ end
- -- If the archive has only one file
- if archive_has_only_one_file then
- --
+ -- If the archive has only one file
+ if archive_has_only_one_file then
+ --
- -- Set the base url to the parent directory of the extracted items path
- base_url = parent_directory_url
- end
+ -- Set the base url to the parent directory of the extracted items path
+ base_url = parent_directory_url
+ end
- -- Iterate over the archive files
- for _, file in ipairs(archive_files) do
- --
+ -- Iterate over the archive files
+ for _, file in ipairs(archive_files) do
+ --
- -- Get the file extension of the file
- local file_extension = file:match(file_extension_pattern)
+ -- Get the file extension of the file
+ local file_extension = file:match(file_extension_pattern)
- -- If the file extension is not found, then skip the file
- if not file_extension then goto continue end
+ -- If the file extension is not found, then skip the file
+ if not file_extension then goto continue end
- -- If the file extension is not an archive file extension, skip the file
- if not is_archive_file_extension(file_extension) then goto continue end
+ -- If the file extension is not an archive file extension, skip the file
+ if not is_archive_file_extension(file_extension) then goto continue end
- -- Otherwise, get the full url to the archive
- local full_archive_url = base_url:join(file)
+ -- Otherwise, get the full url to the archive
+ local full_archive_url = base_url:join(file)
- -- Get the full path to the archive
- local full_archive_path = tostring(full_archive_url)
+ -- Get the full path to the archive
+ local full_archive_path = tostring(full_archive_url)
- -- Recursively extract the archive
- emit_plugin_command(
- "extract",
- merge_tables(args, {
- archive_path = ya.quote(full_archive_path),
- remove = true,
- })
- )
+ -- Recursively extract the archive
+ emit_plugin_command(
+ "extract",
+ merge_tables(args, {
+ archive_path = ya.quote(full_archive_path),
+ remove = true,
+ })
+ )
- -- The label the continue the loop
- ::continue::
- end
+ -- The label the continue the loop
+ ::continue::
+ end
- -- Return the move result
- return add_additional_info(move_result)
+ -- Return the move result
+ return add_additional_info(move_result)
end
-- Function to show an extraction error
---@param extraction_result ExtractionResult The extraction result
---@return nil
local function show_extraction_error(extraction_result)
- --
+ --
- -- The line for the error
- local error_line = string.format("Error: %s", extraction_result.error)
+ -- The line for the error
+ local error_line = string.format("Error: %s", extraction_result.error)
- -- If the extractor name exists
- if extraction_result.extractor_name then
- --
+ -- If the extractor name exists
+ if extraction_result.extractor_name then
+ --
- -- Add the extractor's name to the error
- error_line = string.format(
- "%s error: %s",
- extraction_result.extractor_name,
- extraction_result.error
- )
- end
+ -- Add the extractor's name to the error
+ error_line = string.format(
+ "%s error: %s",
+ extraction_result.extractor_name,
+ extraction_result.error
+ )
+ end
- -- Show the extraction error
- return show_error(table.concat({
- string.format(
- "Failed to extract archive at: %s",
- extraction_result.archive_path
- ),
- string.format("Destination: %s", extraction_result.destination_path),
- error_line,
- }, "\n"))
+ -- Show the extraction error
+ return show_error(table.concat({
+ string.format(
+ "Failed to extract archive at: %s",
+ extraction_result.archive_path
+ ),
+ string.format("Destination: %s", extraction_result.destination_path),
+ error_line,
+ }, "\n"))
end
-- Function to handle the open command
---@type CommandFunction
local function handle_open(args, config)
- --
+ --
- -- Call the function to get the item group
- local item_group = get_item_group()
+ -- Call the function to get the item group
+ local item_group = get_item_group()
- -- If no item group is returned, exit the function
- if not item_group then return end
+ -- If no item group is returned, exit the function
+ if not item_group then return end
- -- If the item group is the selected items,
- -- then execute the command and exit the function
- if item_group == ItemGroup.Selected then
- --
+ -- If the item group is the selected items,
+ -- then execute the command and exit the function
+ if item_group == ItemGroup.Selected then
+ --
- -- Emit the command and exit the function
- return ya.manager_emit("open", args)
- end
+ -- Emit the command and exit the function
+ return ya.manager_emit("open", args)
+ end
- -- If the hovered item is a directory
- if hovered_item_is_dir() then
- --
+ -- If the hovered item is a directory
+ if hovered_item_is_dir() then
+ --
- -- If smart enter is wanted,
- -- calls the function to enter the directory
- -- and exit the function
- if config.smart_enter or table_pop(args, "smart", false) then
- return emit_plugin_command("enter", args)
- end
+ -- If smart enter is wanted,
+ -- calls the function to enter the directory
+ -- and exit the function
+ if config.smart_enter or table_pop(args, "smart", false) then
+ return emit_plugin_command("enter", args)
+ end
- -- Otherwise, just exit the function
- return
- end
+ -- Otherwise, just exit the function
+ return
+ end
- -- Otherwise, if the hovered item is not an archive,
- -- or entering archives isn't wanted,
- -- or the interactive flag is passed
- if
- not hovered_item_is_archive()
- or not config.enter_archives
- or args.interactive
- then
- --
+ -- Otherwise, if the hovered item is not an archive,
+ -- or entering archives isn't wanted,
+ -- or the interactive flag is passed
+ if
+ not hovered_item_is_archive()
+ or not config.enter_archives
+ or args.interactive
+ then
+ --
- -- Simply emit the open command,
- -- opening only the hovered item
- -- as the item group is the hovered item,
- -- and exit the function
- return ya.manager_emit("open", merge_tables(args, { hovered = true }))
- end
+ -- Simply emit the open command,
+ -- opening only the hovered item
+ -- as the item group is the hovered item,
+ -- and exit the function
+ return ya.manager_emit("open", merge_tables(args, { hovered = true }))
+ end
- -- Otherwise, the hovered item is an archive
- -- and entering archives is wanted,
- -- so get the path of the hovered item
- local archive_path = get_path_of_hovered_item()
+ -- Otherwise, the hovered item is an archive
+ -- and entering archives is wanted,
+ -- so get the path of the hovered item
+ local archive_path = get_path_of_hovered_item()
- -- If the archive path somehow doesn't exist, then exit the function
- if not archive_path then return end
+ -- If the archive path somehow doesn't exist, then exit the function
+ if not archive_path then return end
- -- Get the parent directory of the hovered item
- ---@type Url
- local parent_directory_url = Url(archive_path):parent()
+ -- Get the parent directory of the hovered item
+ ---@type Url
+ local parent_directory_url = Url(archive_path):parent()
- -- If the parent directory doesn't exist, then exit the function
- if not parent_directory_url then return end
+ -- If the parent directory doesn't exist, then exit the function
+ if not parent_directory_url then return end
- -- Emit the command to extract the archive
- -- and reveal the extracted items
- emit_plugin_command(
- "extract",
- merge_tables(args, {
- archive_path = ya.quote(archive_path),
- reveal = true,
- parent_dir = ya.quote(tostring(parent_directory_url)),
- })
- )
+ -- Emit the command to extract the archive
+ -- and reveal the extracted items
+ emit_plugin_command(
+ "extract",
+ merge_tables(args, {
+ archive_path = ya.quote(archive_path),
+ reveal = true,
+ parent_dir = ya.quote(tostring(parent_directory_url)),
+ })
+ )
end
-- Function to get the archive paths for the extract command
---@param args Arguments The arguments passed to the plugin
---@return string|string[]|nil archive_paths The archive paths
local function get_archive_paths(args)
- --
+ --
- -- Get the archive path from the arguments given
- local archive_path = table_pop(args, "archive_path")
+ -- Get the archive path from the arguments given
+ local archive_path = table_pop(args, "archive_path")
- -- If the archive path is given, return it immediately
- if archive_path then return archive_path end
+ -- If the archive path is given, return it immediately
+ if archive_path then return archive_path end
- -- Otherwise, get the item group
- local item_group = get_item_group()
+ -- Otherwise, get the item group
+ local item_group = get_item_group()
- -- If there is no item group
- if not item_group then return end
+ -- If there is no item group
+ if not item_group then return end
- -- If the item group is the hovered item
- if item_group == ItemGroup.Hovered then
- --
+ -- If the item group is the hovered item
+ if item_group == ItemGroup.Hovered then
+ --
- -- Get the hovered item path
- local hovered_item_path = get_path_of_hovered_item(true)
+ -- Get the hovered item path
+ local hovered_item_path = get_path_of_hovered_item(true)
- -- If the hovered item path is nil, exit the function
- if not hovered_item_path then return end
+ -- If the hovered item path is nil, exit the function
+ if not hovered_item_path then return end
- -- Otherwise, return the hovered item path
- return hovered_item_path
- end
+ -- Otherwise, return the hovered item path
+ return hovered_item_path
+ end
- -- Otherwise, if the item group is the selected items
- if item_group == ItemGroup.Selected then
- --
+ -- Otherwise, if the item group is the selected items
+ if item_group == ItemGroup.Selected then
+ --
- -- Get the list of selected items
- local selected_items = get_paths_of_selected_items(true)
+ -- Get the list of selected items
+ local selected_items = get_paths_of_selected_items(true)
- -- If there are no selected items, exit the function
- if not selected_items then return end
+ -- If there are no selected items, exit the function
+ if not selected_items then return end
- -- Otherwise, return the list of selected items
- return selected_items
- end
+ -- Otherwise, return the list of selected items
+ return selected_items
+ end
end
-- Function to handle the extract command
---@type CommandFunction
local function handle_extract(args, config)
- --
+ --
- -- Get the archive paths
- local archive_paths = get_archive_paths(args)
+ -- Get the archive paths
+ local archive_paths = get_archive_paths(args)
- -- Get the destination path from the arguments given
- ---@type string
- local destination_path = table_pop(args, "destination_path")
+ -- Get the destination path from the arguments given
+ ---@type string
+ local destination_path = table_pop(args, "destination_path")
- -- If there are no archive paths, exit the function
- if not archive_paths then return end
+ -- If there are no archive paths, exit the function
+ if not archive_paths then return end
- -- If the archive path is a list
- if type(archive_paths) == "table" then
- --
+ -- If the archive path is a list
+ if type(archive_paths) == "table" then
+ --
- -- Iterate over the archive paths
- -- and call the extract command on them
- for _, archive_path in ipairs(archive_paths) do
- emit_plugin_command(
- "extract",
- merge_tables(args, {
- archive_path = ya.quote(archive_path),
- })
- )
- end
+ -- Iterate over the archive paths
+ -- and call the extract command on them
+ for _, archive_path in ipairs(archive_paths) do
+ emit_plugin_command(
+ "extract",
+ merge_tables(args, {
+ archive_path = ya.quote(archive_path),
+ })
+ )
+ end
- -- Exit the function
- return
- end
+ -- Exit the function
+ return
+ end
- -- Otherwise the archive path is a string
- ---@type string
- local archive_path = archive_paths
+ -- Otherwise the archive path is a string
+ ---@type string
+ local archive_path = archive_paths
- -- Call the function to recursively extract the archive
- local extraction_result = recursively_extract_archive(
- archive_path,
- args,
- config,
- destination_path
- )
+ -- Call the function to recursively extract the archive
+ local extraction_result = recursively_extract_archive(
+ archive_path,
+ args,
+ config,
+ destination_path
+ )
- -- If the extraction is cancelled, then just exit the function
- if extraction_result.cancelled then return end
+ -- If the extraction is cancelled, then just exit the function
+ if extraction_result.cancelled then return end
- -- Get the extracted items path
- local extracted_items_path = extraction_result.extracted_items_path
+ -- Get the extracted items path
+ local extracted_items_path = extraction_result.extracted_items_path
- -- If the extraction is not successful, notify the user
- if not extraction_result.successful or not extracted_items_path then
- return show_extraction_error(extraction_result)
- end
+ -- If the extraction is not successful, notify the user
+ if not extraction_result.successful or not extracted_items_path then
+ return show_extraction_error(extraction_result)
+ end
- -- Get the url of the archive
- local archive_url = Url(archive_path)
+ -- Get the url of the archive
+ local archive_url = Url(archive_path)
- -- If the remove flag is passed,
- -- then remove the archive after extraction
- if table_pop(args, "remove", false) then fs.remove("file", archive_url) end
+ -- If the remove flag is passed,
+ -- then remove the archive after extraction
+ if table_pop(args, "remove", false) then fs.remove("file", archive_url) end
- -- If the reveal flag is passed
- if table_pop(args, "reveal", false) then
- --
+ -- If the reveal flag is passed
+ if table_pop(args, "reveal", false) then
+ --
- -- Get the url of the extracted items
- ---@type Url
- local extracted_items_url = Url(extracted_items_path)
+ -- Get the url of the extracted items
+ ---@type Url
+ local extracted_items_url = Url(extracted_items_path)
- -- Get the parent directory of the extracted items
- local parent_directory_url = extracted_items_url:parent()
+ -- Get the parent directory of the extracted items
+ local parent_directory_url = extracted_items_url:parent()
- -- If the parent directory doesn't exist, then exit the function
- if not parent_directory_url then return end
+ -- If the parent directory doesn't exist, then exit the function
+ if not parent_directory_url then return end
- -- Get the given parent directory
- local given_parent_directory = table_pop(args, "parent_dir")
+ -- Get the given parent directory
+ local given_parent_directory = table_pop(args, "parent_dir")
- -- If there is a parent directory given but the parent directory
- -- of the extracted items isn't the same as the given one,
- -- exit the function
- if
- given_parent_directory
- and given_parent_directory ~= tostring(parent_directory_url)
- then
- return
- end
+ -- If there is a parent directory given but the parent directory
+ -- of the extracted items isn't the same as the given one,
+ -- exit the function
+ if
+ given_parent_directory
+ and given_parent_directory ~= tostring(parent_directory_url)
+ then
+ return
+ end
- -- Get the cha of the extracted item
- local extracted_items_cha = fs.cha(extracted_items_url, false)
+ -- Get the cha of the extracted item
+ local extracted_items_cha = fs.cha(extracted_items_url, false)
- -- If the cha of the extracted item doesn't exist,
- -- exit the function
- if not extracted_items_cha then return end
+ -- If the cha of the extracted item doesn't exist,
+ -- exit the function
+ if not extracted_items_cha then return end
- -- If the extracted item is not a directory
- if not extracted_items_cha.is_dir then
- --
+ -- If the extracted item is not a directory
+ if not extracted_items_cha.is_dir then
+ --
- -- Reveal the item and exit the function
- return ya.manager_emit("reveal", { extracted_items_url })
- end
+ -- Reveal the item and exit the function
+ return ya.manager_emit("reveal", { extracted_items_url })
+ end
- -- Otherwise, change the directory to the extracted item.
- -- Note that extracted_items_url is destroyed here.
- ya.manager_emit("cd", { extracted_items_url })
+ -- Otherwise, change the directory to the extracted item.
+ -- Note that extracted_items_url is destroyed here.
+ ya.manager_emit("cd", { extracted_items_url })
- -- If the user wants to skip single subdirectories on enter,
- -- and the no skip flag is not passed
- if
- config.skip_single_subdirectory_on_enter
- and not table_pop(args, "no_skip", false)
- then
- --
+ -- If the user wants to skip single subdirectories on enter,
+ -- and the no skip flag is not passed
+ if
+ config.skip_single_subdirectory_on_enter
+ and not table_pop(args, "no_skip", false)
+ then
+ --
- -- Call the function to skip child directories
- skip_single_child_directories(extracted_items_path)
- end
- end
+ -- Call the function to skip child directories
+ skip_single_child_directories(extracted_items_path)
+ end
+ end
end
-- Function to handle the enter command
---@type CommandFunction
local function handle_enter(args, config)
- --
+ --
- -- If the hovered item is not a directory
- if not hovered_item_is_dir() then
- --
+ -- If the hovered item is not a directory
+ if not hovered_item_is_dir() then
+ --
- -- If smart enter is wanted,
- -- call the function for the open command
- -- and exit the function
- if config.smart_enter or table_pop(args, "smart", false) then
- return emit_plugin_command("open", args)
- end
+ -- If smart enter is wanted,
+ -- call the function for the open command
+ -- and exit the function
+ if config.smart_enter or table_pop(args, "smart", false) then
+ return emit_plugin_command("open", args)
+ end
- -- Otherwise, just exit the function
- return
- end
+ -- Otherwise, just exit the function
+ return
+ end
- -- Otherwise, always emit the enter command,
- ya.manager_emit("enter", args)
+ -- Otherwise, always emit the enter command,
+ ya.manager_emit("enter", args)
- -- If the user doesn't want to skip single subdirectories on enter,
- -- or one of the arguments passed is no skip,
- -- then exit the function
- if
- not config.skip_single_subdirectory_on_enter
- or table_pop(args, "no_skip", false)
- then
- return
- end
+ -- If the user doesn't want to skip single subdirectories on enter,
+ -- or one of the arguments passed is no skip,
+ -- then exit the function
+ if
+ not config.skip_single_subdirectory_on_enter
+ or table_pop(args, "no_skip", false)
+ then
+ return
+ end
- -- Otherwise, call the function to skip child directories
- -- with only a single directory inside
- skip_single_child_directories(get_current_directory())
+ -- Otherwise, call the function to skip child directories
+ -- with only a single directory inside
+ skip_single_child_directories(get_current_directory())
end
-- Function to handle the leave command
---@type CommandFunction
local function handle_leave(args, config)
- --
+ --
- -- Always emit the leave command
- ya.manager_emit("leave", args)
+ -- Always emit the leave command
+ ya.manager_emit("leave", args)
- -- If the user doesn't want to skip single subdirectories on leave,
- -- or one of the arguments passed is no skip,
- -- then exit the function
- if
- not config.skip_single_subdirectory_on_leave
- or table_pop(args, "no_skip", false)
- then
- return
- end
+ -- If the user doesn't want to skip single subdirectories on leave,
+ -- or one of the arguments passed is no skip,
+ -- then exit the function
+ if
+ not config.skip_single_subdirectory_on_leave
+ or table_pop(args, "no_skip", false)
+ then
+ return
+ end
- -- Otherwise, initialise the directory to the current directory
- local directory = get_current_directory()
+ -- Otherwise, initialise the directory to the current directory
+ local directory = get_current_directory()
- -- Get the tab preferences
- local tab_preferences = get_tab_preferences()
+ -- Get the tab preferences
+ local tab_preferences = get_tab_preferences()
- -- Start an infinite loop
- while true do
- --
+ -- Start an infinite loop
+ while true do
+ --
- -- Get all the items in the current directory
- local directory_items =
- get_directory_items(directory, tab_preferences.show_hidden)
+ -- Get all the items in the current directory
+ local directory_items =
+ get_directory_items(directory, tab_preferences.show_hidden)
- -- If the number of directory items is not 1,
- -- then break out of the loop.
- if #directory_items ~= 1 then break end
+ -- If the number of directory items is not 1,
+ -- then break out of the loop.
+ if #directory_items ~= 1 then break end
- -- Get the parent directory of the current directory
- ---@type Url|nil
- local parent_directory = Url(directory):parent()
+ -- Get the parent directory of the current directory
+ ---@type Url|nil
+ local parent_directory = Url(directory):parent()
- -- If the parent directory is nil,
- -- break the loop
- if not parent_directory then break end
+ -- If the parent directory is nil,
+ -- break the loop
+ if not parent_directory then break end
- -- Otherwise, set the new directory to the parent directory
- directory = tostring(parent_directory)
- end
+ -- Otherwise, set the new directory to the parent directory
+ directory = tostring(parent_directory)
+ end
- -- Emit the change directory command to change to the directory variable
- ya.manager_emit("cd", { directory })
+ -- Emit the change directory command to change to the directory variable
+ ya.manager_emit("cd", { directory })
end
-- Function to handle a Yazi command
@@ -2658,28 +2637,28 @@ end
---@param args Arguments The arguments passed to the plugin
---@return nil
local function handle_yazi_command(command, args)
- --
+ --
- -- Call the function to get the item group
- local item_group = get_item_group()
+ -- Call the function to get the item group
+ local item_group = get_item_group()
- -- If no item group is returned, exit the function
- if not item_group then return end
+ -- If no item group is returned, exit the function
+ if not item_group then return end
- -- If the item group is the selected items
- if item_group == ItemGroup.Selected then
- --
+ -- If the item group is the selected items
+ if item_group == ItemGroup.Selected then
+ --
- -- Emit the command to operate on the selected items
- ya.manager_emit(command, args)
+ -- Emit the command to operate on the selected items
+ ya.manager_emit(command, args)
- -- If the item group is the hovered item
- elseif item_group == ItemGroup.Hovered then
- --
+ -- If the item group is the hovered item
+ elseif item_group == ItemGroup.Hovered then
+ --
- -- Emit the command with the hovered option
- ya.manager_emit(command, merge_tables(args, { hovered = true }))
- end
+ -- Emit the command with the hovered option
+ ya.manager_emit(command, merge_tables(args, { hovered = true }))
+ end
end
-- Function to enter or open the created file
@@ -2689,45 +2668,45 @@ end
---@param config Configuration The configuration object
---@return nil
local function enter_or_open_created_item(item_url, is_directory, args, config)
- --
+ --
- -- If the item is a directory
- if is_directory then
- --
+ -- If the item is a directory
+ if is_directory then
+ --
- -- If user does not want to enter the directory
- -- after creating it, exit the function
- if
- not (
- config.enter_directory_after_creation
- or table_pop(args, "enter", false)
- )
- then
- return
- end
+ -- If user does not want to enter the directory
+ -- after creating it, exit the function
+ if
+ not (
+ config.enter_directory_after_creation
+ or table_pop(args, "enter", false)
+ )
+ then
+ return
+ end
- -- Otherwise, call the function change to the created directory
- return ya.manager_emit("cd", { item_url })
- end
+ -- Otherwise, call the function change to the created directory
+ return ya.manager_emit("cd", { item_url })
+ end
- -- Otherwise, the item is a file
+ -- Otherwise, the item is a file
- -- If the user does not want to open the file
- -- after creating it, exit the function
- if
- not (config.open_file_after_creation or table_pop(args, "open", false))
- then
- return
- end
+ -- If the user does not want to open the file
+ -- after creating it, exit the function
+ if
+ not (config.open_file_after_creation or table_pop(args, "open", false))
+ then
+ return
+ end
- -- Otherwise, call the function to reveal the created file
- ya.manager_emit("reveal", { item_url })
+ -- Otherwise, call the function to reveal the created file
+ ya.manager_emit("reveal", { item_url })
- -- Wait for Yazi to finish loading
- wait_until_yazi_is_loaded()
+ -- Wait for Yazi to finish loading
+ wait_until_yazi_is_loaded()
- -- Call the function to open the file
- return ya.manager_emit("open", { hovered = true })
+ -- Call the function to open the file
+ return ya.manager_emit("open", { hovered = true })
end
-- Function to execute the create command
@@ -2736,141 +2715,138 @@ end
---@param config Configuration The configuration object
---@return nil
local function execute_create(item_url, is_directory, args, config)
- --
+ --
- -- Get the parent directory of the file to create
- local parent_directory_url = item_url:parent()
+ -- Get the parent directory of the file to create
+ local parent_directory_url = item_url:parent()
- -- If the parent directory doesn't exist,
- -- then show an error and exit the function
- if not parent_directory_url then
- return show_error(
- "Parent directory of the item to create doesn't exist"
- )
- end
+ -- If the parent directory doesn't exist,
+ -- then show an error and exit the function
+ if not parent_directory_url then
+ return show_error(
+ "Parent directory of the item to create doesn't exist"
+ )
+ end
- -- If the item to create is a directory
- if is_directory then
- --
+ -- If the item to create is a directory
+ if is_directory then
+ --
- -- Call the function to create the directory
- local successful, error_message = fs.create("dir_all", item_url)
+ -- Call the function to create the directory
+ local successful, error_message = fs.create("dir_all", item_url)
- -- If the function is not successful,
- -- show the error message and exit the function
- if not successful then return show_error(tostring(error_message)) end
+ -- If the function is not successful,
+ -- show the error message and exit the function
+ if not successful then return show_error(tostring(error_message)) end
- -- Otherwise, the item to create is a file
- else
- --
+ -- Otherwise, the item to create is a file
+ else
+ --
- -- Otherwise, create the parent directory if it doesn't exist
- if not fs.cha(parent_directory_url, false) then
- --
+ -- Otherwise, create the parent directory if it doesn't exist
+ if not fs.cha(parent_directory_url, false) then
+ --
- -- Call the function to create the parent directory
- local successful, error_message =
- fs.create("dir_all", parent_directory_url)
+ -- Call the function to create the parent directory
+ local successful, error_message =
+ fs.create("dir_all", parent_directory_url)
- -- If the function is not successful,
- -- show the error message and exit the function
- if not successful then
- return show_error(tostring(error_message))
- end
- end
+ -- If the function is not successful,
+ -- show the error message and exit the function
+ if not successful then
+ return show_error(tostring(error_message))
+ end
+ end
- -- Otherwise, create the file
- local successful, error_message = fs.write(item_url, "")
+ -- Otherwise, create the file
+ local successful, error_message = fs.write(item_url, "")
- -- If the function is not successful,
- -- show the error message and exit the function
- if not successful then return show_error(tostring(error_message)) end
- end
+ -- If the function is not successful,
+ -- show the error message and exit the function
+ if not successful then return show_error(tostring(error_message)) end
+ end
- -- Call the function to enter or open the created item
- enter_or_open_created_item(item_url, is_directory, args, config)
+ -- Call the function to enter or open the created item
+ enter_or_open_created_item(item_url, is_directory, args, config)
end
-- Function to handle the create command
---@type CommandFunction
local function handle_create(args, config)
- --
+ --
- -- Get the directory flag
- local dir_flag = table_pop(args, "dir", false)
+ -- Get the directory flag
+ local dir_flag = table_pop(args, "dir", false)
- -- Get the user's input for the item to create
- local user_input, event =
- get_user_input(dir_flag and "Create (dir):" or "Create:")
+ -- Get the user's input for the item to create
+ local user_input, event =
+ get_user_input(dir_flag and "Create (dir):" or "Create:")
- -- If the user input is nil,
- -- or if the user did not confirm the input,
- -- exit the function
- if not user_input or event ~= 1 then return end
+ -- If the user input is nil,
+ -- or if the user did not confirm the input,
+ -- exit the function
+ if not user_input or event ~= 1 then return end
- -- Get the current working directory as a url
- ---@type Url
- local current_working_directory = Url(get_current_directory())
+ -- Get the current working directory as a url
+ ---@type Url
+ local current_working_directory = Url(get_current_directory())
- -- Get whether the url ends with a path delimiter
- local ends_with_path_delimiter = user_input:find("[/\\]$")
+ -- Get whether the url ends with a path delimiter
+ local ends_with_path_delimiter = user_input:find("[/\\]$")
- -- Get the whether the given item is a directory or not based
- -- on the default conditions for a directory
- local is_directory = ends_with_path_delimiter or dir_flag
+ -- Get the whether the given item is a directory or not based
+ -- on the default conditions for a directory
+ local is_directory = ends_with_path_delimiter or dir_flag
- -- Get the url from the user's input
- ---@type Url
- local item_url = Url(user_input)
+ -- Get the url from the user's input
+ ---@type Url
+ local item_url = Url(user_input)
- -- If the user does not want to use the default Yazi create behaviour
- if
- not (
- config.use_default_create_behaviour
- or table_pop(args, "default_behaviour", false)
- )
- then
- --
+ -- If the user does not want to use the default Yazi create behaviour
+ if
+ not (
+ config.use_default_create_behaviour
+ or table_pop(args, "default_behaviour", false)
+ )
+ then
+ --
- -- Get the file extension from the user's input
- local file_extension = user_input:match(file_extension_pattern)
+ -- Get the file extension from the user's input
+ local file_extension = user_input:match(file_extension_pattern)
- -- Set the is directory variable to the is directory condition
- -- or if the file extension exists
- is_directory = is_directory or not file_extension
- end
+ -- Set the is directory variable to the is directory condition
+ -- or if the file extension exists
+ is_directory = is_directory or not file_extension
+ end
- -- Get the full url of the item to create
- local full_url = current_working_directory:join(item_url)
+ -- Get the full url of the item to create
+ local full_url = current_working_directory:join(item_url)
- -- If the path to the item to create already exists,
- -- and the user did not pass the force flag
- if fs.cha(full_url, false) and not table_pop(args, "force", false) then
- --
+ -- If the path to the item to create already exists,
+ -- and the user did not pass the force flag
+ 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(
+ -- 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))
+ :align(ui.Line.LEFT),
+ ui.Line(tostring(full_url)):align(ui.Line.LEFT),
+ }):wrap(ui.Text.WRAP_TRIM)
+ )
- -- TODO: Remove the line below
- "The item already exists, overwrite? (y/N)",
- "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))
- :align(ui.Line.LEFT),
- ui.Line(tostring(full_url)):align(ui.Line.LEFT),
- }):wrap(ui.Text.WRAP_TRIM)
- )
+ -- If the user did not confirm the overwrite,
+ -- then exit the function
+ if not user_confirmation then return end
+ end
- -- If the user did not confirm the overwrite,
- -- then exit the function
- if not user_confirmation then return end
- end
-
- -- Call the function to execute the create command
- return execute_create(full_url, is_directory, args, config)
+ -- Call the function to execute the create command
+ return execute_create(full_url, is_directory, args, config)
end
-- Function to remove the F flag from the less command
@@ -2878,33 +2854,33 @@ end
---@return string command The command with the F flag removed
---@return boolean f_flag_found Whether the F flag was found
local function remove_f_flag_from_less_command(command)
- --
+ --
- -- Initialise the variable to store if the F flag is found
- local f_flag_found = false
+ -- Initialise the variable to store if the F flag is found
+ local f_flag_found = false
- -- Initialise the variable to store the replacement count
- local replacement_count = 0
+ -- Initialise the variable to store the replacement count
+ local replacement_count = 0
- -- Remove the F flag when it is passed at the start
- -- of the flags given to the less command
- command, replacement_count = command:gsub("(%f[%a]less%f[%A].*)%-F", "%1")
+ -- Remove the F flag when it is passed at the start
+ -- of the flags given to the less command
+ command, replacement_count = command:gsub("(%f[%a]less%f[%A].*)%-F", "%1")
- -- If the replacement count is not 0,
- -- set the f_flag_found variable to true
- if replacement_count ~= 0 then f_flag_found = true end
+ -- If the replacement count is not 0,
+ -- set the f_flag_found variable to true
+ if replacement_count ~= 0 then f_flag_found = true end
- -- Remove the F flag when it is passed in the middle
- -- or end of the flags given to the less command command
- command, replacement_count =
- command:gsub("(%f[%a]less%f[%A].*%-)(%a*)F(%a*)", "%1%2%3")
+ -- Remove the F flag when it is passed in the middle
+ -- or end of the flags given to the less command command
+ command, replacement_count =
+ command:gsub("(%f[%a]less%f[%A].*%-)(%a*)F(%a*)", "%1%2%3")
- -- If the replacement count is not 0,
- -- set the f_flag_found variable to true
- if replacement_count ~= 0 then f_flag_found = true end
+ -- If the replacement count is not 0,
+ -- set the f_flag_found variable to true
+ if replacement_count ~= 0 then f_flag_found = true end
- -- Return the command and whether or not the F flag was found
- return command, f_flag_found
+ -- Return the command and whether or not the F flag was found
+ return command, f_flag_found
end
-- Function to fix a command containing less.
@@ -2913,621 +2889,682 @@ end
---@param command string The shell command containing the less command
---@return string command The fixed shell command
local function fix_shell_command_containing_less(command)
- --
+ --
- -- Remove the F flag from the given command
- local fixed_command = remove_f_flag_from_less_command(command)
+ -- Remove the F flag from the given command
+ local fixed_command = remove_f_flag_from_less_command(command)
- -- Get the LESS environment variable
- local less_environment_variable = os.getenv("LESS")
+ -- Get the LESS environment variable
+ local less_environment_variable = os.getenv("LESS")
- -- If the LESS environment variable is not set,
- -- then return the given command with the F flag removed
- if not less_environment_variable then return fixed_command end
+ -- If the LESS environment variable is not set,
+ -- then return the given command with the F flag removed
+ if not less_environment_variable then return fixed_command end
- -- Otherwise, remove the F flag from the LESS environment variable
- -- and check if the F flag was found
- local less_command_with_modified_env_variables, f_flag_found =
- remove_f_flag_from_less_command("less " .. less_environment_variable)
+ -- Otherwise, remove the F flag from the LESS environment variable
+ -- and check if the F flag was found
+ local less_command_with_modified_env_variables, f_flag_found =
+ remove_f_flag_from_less_command("less " .. less_environment_variable)
- -- If the F flag isn't found,
- -- then return the given command with the F flag removed
- if not f_flag_found then return fixed_command end
+ -- If the F flag isn't found,
+ -- then return the given command with the F flag removed
+ if not f_flag_found then return fixed_command end
- -- Add the less environment variable flags to the less command
- fixed_command = fixed_command:gsub(
- "%f[%a]less%f[%A]",
- escape_replacement_string(less_command_with_modified_env_variables)
- )
+ -- Add the less environment variable flags to the less command
+ fixed_command = fixed_command:gsub(
+ "%f[%a]less%f[%A]",
+ escape_replacement_string(less_command_with_modified_env_variables)
+ )
- -- Unset the LESS environment variable before calling the command
- fixed_command = "unset LESS; " .. fixed_command
+ -- Unset the LESS environment variable before calling the command
+ fixed_command = "unset LESS; " .. fixed_command
- -- Return the fixed command
- return fixed_command
+ -- Return the fixed command
+ return fixed_command
end
-- Function to fix the bat default pager command
---@param command string The command containing the bat default pager command
---@return string command The fixed bat command
-local function fix_bat_default_pager_shell_command(command)
- --
+local function fix_shell_command_containing_bat(command)
+ --
- -- Initialise the default pager command for bat without the F flag
- local bat_default_pager_command_without_f_flag = "less -RX"
+ -- The pattern to match the pager argument for the bat command
+ local bat_pager_pattern = "(%-%-pager)%s+(%S+)"
- -- Get the modified command and the replacement count
- -- when replacing the less command when it is quoted
- local modified_command, replacement_count = command:gsub(
- "("
- .. bat_command_with_pager_pattern
- .. "['\"]+%s*"
- .. ")"
- .. "less"
- .. "(%s*['\"]+)",
- "%1" .. bat_default_pager_command_without_f_flag .. "%2"
- )
+ -- Get the pager argument for the bat command
+ local _, pager_argument = command:match(bat_pager_pattern)
- -- If the replacement count is not 0,
- -- then return the modified command
- if replacement_count ~= 0 then return modified_command end
+ -- If there is a pager argument
+ --
+ -- We don't need to do much if the pager argument already exists,
+ -- as we can rely on the function that fixes the less command to
+ -- remove the -F flag that is executed after this function is called.
+ --
+ -- There's only work to be done if the pager argument isn't quoted,
+ -- as we need to quote it so the function that fixes the less command
+ -- can execute cleanly without causing shell syntax errors.
+ --
+ -- The reason why we don't quote the less command in the function
+ -- to fix the less command is to not deal with using backslashes
+ -- to escape the quotes, which can get really messy and really confusing,
+ -- so we just naively replace the less command with the fixed version
+ -- without caring about whether the less command is passed as an
+ -- argument, or is called as a shell command.
+ if pager_argument then
+ --
- -- Otherwise, get the modified command and the replacement count
- -- when replacing the less command when it is unquoted
- modified_command, replacement_count = command:gsub(
- "(" .. bat_command_with_pager_pattern .. ")" .. "less",
- '%1"' .. bat_default_pager_command_without_f_flag .. '"'
- )
+ -- If the pager argument is quoted, return the command immediately
+ if pager_argument:find("['\"].+['\"]") then
+ return command
+ end
- -- If the replacement count is not 0,
- -- then return the modified command
- if replacement_count ~= 0 then return modified_command end
+ -- Otherwise, quote the pager argument with single quotes
+ --
+ -- It should be fine to quote with single quotes
+ -- as the user passing the argument probably isn't
+ -- using a shell variable, as they would have quoted
+ -- the shell variable in double quotes instead of
+ -- omitting the quotes.
+ pager_argument = string.format("'%s'", pager_argument)
- -- Otherwise, return the given command
- return command
+ -- Replace the pager argument with the quoted version
+ local modified_command =
+ command:gsub(bat_pager_pattern, "%1 " .. pager_argument)
+
+ -- Return the modified command
+ return modified_command
+ end
+
+ -- If there is no pager argument,
+ -- initialise the default pager command for bat without the F flag
+ local bat_default_pager_command_without_f_flag = "less -RX"
+
+ -- Replace the bat command with the command to use the
+ -- bat default pager command without the F flag
+ local modified_command = command:gsub(
+ bat_command_pattern,
+ string.format(
+ "bat --pager '%s'",
+ bat_default_pager_command_without_f_flag
+ ),
+ 1
+ )
+
+ -- Return the modified command
+ return modified_command
end
-- Function to fix the shell commands given to work properly with Yazi
---@param command string A shell command
---@return string command The fixed shell command
local function fix_shell_command(command)
- --
+ --
- -- If the given command includes the less command
- if command:find("%f[%a]less%f[%A]") ~= nil then
- --
+ -- If the given command contains the bat command
+ if command:find(bat_command_pattern) ~= nil then
+ --
- -- Fix the command containing less
- command = fix_shell_command_containing_less(command)
- end
+ -- Calls the command to fix the bat command
+ command = fix_shell_command_containing_bat(command)
+ end
- -- If the given command contains the bat command with the pager
- -- option passed
- if command:find(bat_command_with_pager_pattern) ~= nil then
- --
+ -- If the given command includes the less command
+ if command:find("%f[%a]less%f[%A]") ~= nil then
+ --
- -- Calls the command to fix the bat command with the default pager
- command = fix_bat_default_pager_shell_command(command)
- end
+ -- Fix the command containing less
+ command = fix_shell_command_containing_less(command)
+ end
- -- Return the modified command
- return command
+ -- Return the modified command
+ return command
end
-- Function to handle a shell command
---@type CommandFunction
local function handle_shell(args, _)
- --
+ --
- -- Get the first item of the arguments given
- -- and set it to the command variable
- local command = table.remove(args, 1)
+ -- Get the first item of the arguments given
+ -- and set it to the command variable
+ local command = table.remove(args, 1)
- -- Get the type of the command variable
- local command_type = type(command)
+ -- Get the type of the command variable
+ local command_type = type(command)
- -- 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)
- )
- )
- end
+ -- 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)
+ )
+ )
+ end
- -- Fix the given command
- command = fix_shell_command(command)
+ -- Fix the given command
+ command = fix_shell_command(command)
- -- Call the function to get the item group
- local item_group = get_item_group()
+ -- Call the function to get the item group
+ local item_group = get_item_group()
- -- If no item group is returned, exit the function
- if not item_group then return end
+ -- If no item group is returned, exit the function
+ if not item_group then return end
- -- Get whether the exit if directory flag is passed
- local exit_if_dir = table_pop(args, "exit_if_dir", false)
+ -- Get whether the exit if directory flag is passed
+ local exit_if_dir = table_pop(args, "exit_if_dir", false)
- -- If the item group is the selected items
- if item_group == ItemGroup.Selected then
- --
+ -- If the item group is the selected items
+ if item_group == ItemGroup.Selected then
+ --
- -- Get the paths of the selected items
- local selected_items = get_paths_of_selected_items(true)
+ -- Get the paths of the selected items
+ local selected_items = get_paths_of_selected_items(true)
- -- If there are no selected items, exit the function
- if not selected_items then return end
+ -- If there are no selected items, exit the function
+ if not selected_items then return end
- -- If the exit if directory flag is passed
- if exit_if_dir then
- --
+ -- If the exit if directory flag is passed
+ if exit_if_dir then
+ --
- -- Initialise the number of files
- local number_of_files = 0
+ -- Initialise the number of files
+ local number_of_files = 0
- -- Iterate over all of the selected items
- for _, item in pairs(selected_items) do
- --
+ -- Iterate over all of the selected items
+ for _, item in pairs(selected_items) do
+ --
- -- Get the cha object of the item
- local item_cha = fs.cha(Url(item), false)
+ -- Get the cha object of the item
+ local item_cha = fs.cha(Url(item), false)
- -- If the item isn't a directory
- if not (item_cha or {}).is_dir then
- --
+ -- If the item isn't a directory
+ if not (item_cha or {}).is_dir then
+ --
- -- Increment the number of files
- number_of_files = number_of_files + 1
- end
- end
+ -- Increment the number of files
+ number_of_files = number_of_files + 1
+ end
+ end
- -- If the number of files is 0, then exit the function
- if number_of_files == 0 then return end
- end
+ -- If the number of files is 0, then exit the function
+ if number_of_files == 0 then return end
+ end
- -- Replace the shell variable in the command
- -- with the quoted paths of the selected items
- command = command:gsub(
- shell_variable_pattern,
- escape_replacement_string(table.concat(selected_items, " "))
- )
+ -- Replace the shell variable in the command
+ -- with the quoted paths of the selected items
+ command = command:gsub(
+ shell_variable_pattern,
+ escape_replacement_string(table.concat(selected_items, " "))
+ )
- -- If the item group is the hovered item
- elseif item_group == ItemGroup.Hovered then
- --
+ -- If the item group is the hovered item
+ elseif item_group == ItemGroup.Hovered then
+ --
- -- Get the hovered item path
- local hovered_item_path = get_path_of_hovered_item(true)
+ -- Get the hovered item path
+ local hovered_item_path = get_path_of_hovered_item(true)
- -- If the hovered item path is nil, exit the function
- if not hovered_item_path then return end
+ -- If the hovered item path is nil, exit the function
+ if not hovered_item_path then return end
- -- If the exit if directory flag is passed,
- -- and the hovered item is a directory,
- -- then exit the function
- if exit_if_dir and hovered_item_is_dir() then return end
+ -- If the exit if directory flag is passed,
+ -- and the hovered item is a directory,
+ -- then exit the function
+ if exit_if_dir and hovered_item_is_dir() then return end
- -- Replace the shell variable in the command
- -- with the quoted path of the hovered item
- command = command:gsub(
- shell_variable_pattern,
- escape_replacement_string(hovered_item_path)
- )
+ -- Replace the shell variable in the command
+ -- with the quoted path of the hovered item
+ command = command:gsub(
+ shell_variable_pattern,
+ escape_replacement_string(hovered_item_path)
+ )
- -- Otherwise, exit the function
- else
- return
- end
+ -- Otherwise, exit the function
+ else
+ return
+ end
- -- Merge the command back into the arguments given
- args = merge_tables({ command }, args)
+ -- Merge the command back into the arguments given
+ args = merge_tables({ command }, args)
- -- Emit the command to operate on the hovered item
- ya.manager_emit("shell", args)
+ -- Emit the command to operate on the hovered item
+ ya.manager_emit("shell", args)
end
-- Function to handle the paste command
---@type CommandFunction
local function handle_paste(args, config)
- --
+ --
- -- If the hovered item is not a directory or smart paste is not wanted
- if
- not hovered_item_is_dir()
- or not (config.smart_paste or table_pop(args, "smart", false))
- then
- --
+ -- If the hovered item is not a directory or smart paste is not wanted
+ if
+ not hovered_item_is_dir()
+ or not (config.smart_paste or table_pop(args, "smart", false))
+ then
+ --
- -- Just paste the items inside the current directory
- -- and exit the function
- return ya.manager_emit("paste", args)
- end
+ -- Just paste the items inside the current directory
+ -- and exit the function
+ return ya.manager_emit("paste", args)
+ end
- -- Otherwise, enter the directory
- ya.manager_emit("enter", {})
+ -- Otherwise, enter the directory
+ ya.manager_emit("enter", {})
- -- Paste the items inside the directory
- ya.manager_emit("paste", args)
+ -- Paste the items inside the directory
+ ya.manager_emit("paste", args)
- -- Leave the directory
- ya.manager_emit("leave", {})
+ -- Leave the directory
+ ya.manager_emit("leave", {})
end
-- Function to execute the tab create command
---@type fun(
---- args: Arguments, -- The arguments passed to the plugin
+--- args: Arguments, -- The arguments passed to the plugin
---): nil
local execute_tab_create = ya.sync(function(state, args)
- --
+ --
- -- Get the hovered item
- local hovered_item = cx.active.current.hovered
+ -- Get the hovered item
+ local hovered_item = cx.active.current.hovered
- -- If the hovered item is nil,
- -- or if the hovered item is not a directory,
- -- or if the user doesn't want to smartly
- -- create a tab in the hovered directory
- if
- not hovered_item
- or not hovered_item.cha.is_dir
- or not (
- state.config.smart_tab_create
- or table_pop(args, "smart", false)
- )
- then
- --
+ -- If the hovered item is nil,
+ -- or if the hovered item is not a directory,
+ -- or if the user doesn't want to smartly
+ -- create a tab in the hovered directory
+ if
+ not hovered_item
+ or not hovered_item.cha.is_dir
+ or not (
+ state.config.smart_tab_create or table_pop(args, "smart", false)
+ )
+ then
+ --
- -- Emit the command to create a new tab with the arguments
- -- and exit the function
- return ya.manager_emit("tab_create", args)
- end
+ -- Emit the command to create a new tab with the arguments
+ -- and exit the function
+ return ya.manager_emit("tab_create", args)
+ end
- -- Otherwise, emit the command to create a new tab
- -- with the hovered item's url
- ya.manager_emit("tab_create", { hovered_item.url })
+ -- Otherwise, emit the command to create a new tab
+ -- with the hovered item's url
+ ya.manager_emit("tab_create", { hovered_item.url })
end)
-- Function to handle the tab create command
---@type CommandFunction
local function handle_tab_create(args)
- --
+ --
- -- Call the function to execute the tab create command
- execute_tab_create(args)
+ -- Call the function to execute the tab create command
+ execute_tab_create(args)
end
-- Function to execute the tab switch command
---@type fun(
---- args: Arguments, -- The arguments passed to the plugin
+--- args: Arguments, -- The arguments passed to the plugin
---): nil
local execute_tab_switch = ya.sync(function(state, args)
- --
+ --
- -- Get the tab index
- local tab_index = args[1]
+ -- Get the tab index
+ local tab_index = args[1]
- -- If no tab index is given, exit the function
- if not tab_index then return end
+ -- If no tab index is given, exit the function
+ if not tab_index then return end
- -- If the user doesn't want to create tabs
- -- when switching to a new tab,
- -- or the tab index is not given,
- -- then just call the tab switch command
- -- and exit the function
- if
- not (state.config.smart_tab_switch or table_pop(args, "smart", false))
- then
- return ya.manager_emit("tab_switch", args)
- end
+ -- If the user doesn't want to create tabs
+ -- when switching to a new tab,
+ -- or the tab index is not given,
+ -- then just call the tab switch command
+ -- and exit the function
+ if
+ not (state.config.smart_tab_switch or table_pop(args, "smart", false))
+ then
+ return ya.manager_emit("tab_switch", args)
+ end
- -- Get the current tab
- local current_tab = cx.active.current
+ -- Get the current tab
+ local current_tab = cx.active.current
- -- Get the number of tabs currently open
- local number_of_open_tabs = #cx.tabs
+ -- Get the number of tabs currently open
+ local number_of_open_tabs = #cx.tabs
- -- Iterate from the number of current open tabs
- -- to the given tab number
- for _ = number_of_open_tabs, tab_index do
- --
+ -- Iterate from the number of current open tabs
+ -- to the given tab number
+ for _ = number_of_open_tabs, tab_index do
+ --
- -- Call the tab create command
- ya.manager_emit("tab_create", { current_tab.cwd })
+ -- Call the tab create command
+ ya.manager_emit("tab_create", { current_tab.cwd })
- -- If there is a hovered item
- if current_tab.hovered then
- --
+ -- If there is a hovered item
+ if current_tab.hovered then
+ --
- -- Reveal the hovered item
- ya.manager_emit("reveal", { current_tab.hovered.url })
- end
- end
+ -- Reveal the hovered item
+ ya.manager_emit("reveal", { current_tab.hovered.url })
+ end
+ end
- -- Switch to the given tab index
- ya.manager_emit("tab_switch", args)
+ -- Switch to the given tab index
+ ya.manager_emit("tab_switch", args)
end)
-- Function to handle the tab switch command
---@type CommandFunction
local function handle_tab_switch(args)
- --
+ --
- -- Call the function to execute the tab switch command
- execute_tab_switch(args)
+ -- Call the function to execute the tab switch command
+ execute_tab_switch(args)
+end
+
+-- Function to execute the quit command
+---@type CommandFunction
+local function handle_quit(args, config)
+ --
+
+ -- Get the number of tabs
+ local number_of_tabs = get_number_of_tabs()
+
+ -- 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.manager_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)
+ )
+
+ -- If the user didn't confirm, then exit the function
+ if not user_confirmation then return end
+
+ -- Otherwise, emit the quit command
+ ya.manager_emit("quit", args)
end
-- Function to do the wraparound for the arrow command
---@type fun(
---- args: Arguments, -- The arguments passed to the plugin
+--- args: Arguments, -- The arguments passed to the plugin
---): nil
local wraparound_arrow = ya.sync(function(_, args)
- --
+ --
- -- Get the current tab
- local current_tab = cx.active.current
+ -- Get the current tab
+ local current_tab = cx.active.current
- -- Get the step from the arguments given
- local step = table.remove(args, 1)
+ -- Get the step from the arguments given
+ local step = table.remove(args, 1)
- -- Get the number of files in the current tab
- local number_of_files = #current_tab.files
+ -- Get the number of files in the current tab
+ local number_of_files = #current_tab.files
- -- If there are no files in the current tab, exit the function
- if number_of_files == 0 then return end
+ -- If there are no files in the current tab, exit the function
+ if number_of_files == 0 then return end
- -- Get the new cursor index,
- -- which is the current cursor position plus the step given
- -- to the arrow function, modulus the number of files in
- -- the current tab
- local new_cursor_index = (current_tab.cursor + step) % number_of_files
+ -- Get the new cursor index,
+ -- which is the current cursor position plus the step given
+ -- to the arrow function, modulus the number of files in
+ -- the current tab
+ local new_cursor_index = (current_tab.cursor + step) % number_of_files
- -- Emit the arrow function with the new cursor index minus
- -- the current cursor index to determine how to move the cursor
- ya.manager_emit(
- "arrow",
- merge_tables(args, { new_cursor_index - current_tab.cursor })
- )
+ -- Emit the arrow function with the new cursor index minus
+ -- the current cursor index to determine how to move the cursor
+ ya.manager_emit(
+ "arrow",
+ merge_tables(args, { new_cursor_index - current_tab.cursor })
+ )
end)
-- Function to handle the arrow command
---@type CommandFunction
local function handle_arrow(args, config)
- --
+ --
- -- If wraparound file navigation isn't wanted,
- -- then execute the arrow command
- if not config.wraparound_file_navigation then
- ya.manager_emit("arrow", args)
+ -- If wraparound file navigation isn't wanted,
+ -- then execute the arrow command
+ if not config.wraparound_file_navigation then
+ ya.manager_emit("arrow", args)
- -- Otherwise, call the wraparound arrow function
- else
- wraparound_arrow(args)
- end
+ -- Otherwise, call the wraparound arrow function
+ else
+ wraparound_arrow(args)
+ end
end
-- Function to get the directory items in the parent directory
---@type fun(
---- directories_only: boolean, -- Whether to only get directories
+--- directories_only: boolean, -- Whether to only get directories
---): string[] directory_items The list of paths to the directory items
local get_parent_directory_items = ya.sync(function(_, directories_only)
- --
+ --
- -- Initialise the list of directory items
- local directory_items = {}
+ -- Initialise the list of directory items
+ local directory_items = {}
- -- Get the parent directory
- local parent_directory = cx.active.parent
+ -- Get the parent directory
+ local parent_directory = cx.active.parent
- -- If the parent directory doesn't exist,
- -- return the empty list of directory items
- if not parent_directory then return directory_items end
+ -- If the parent directory doesn't exist,
+ -- return the empty list of directory items
+ if not parent_directory then return directory_items end
- -- Otherwise, iterate over the items in the parent directory
- for _, item in ipairs(parent_directory.files) do
- --
+ -- Otherwise, iterate over the items in the parent directory
+ for _, item in ipairs(parent_directory.files) do
+ --
- -- If the directories only flag is passed,
- -- and the item is not a directory,
- -- then skip the item
- if directories_only and not item.cha.is_dir then goto continue end
+ -- If the directories only flag is passed,
+ -- and the item is not a directory,
+ -- then skip the item
+ if directories_only and not item.cha.is_dir then goto continue end
- -- Otherwise, add the item to the list of directory items
- table.insert(directory_items, item)
+ -- Otherwise, add the item to the list of directory items
+ table.insert(directory_items, item)
- -- The continue label to skip the item
- ::continue::
- end
+ -- The continue label to skip the item
+ ::continue::
+ end
- -- Return the list of directory items
- return directory_items
+ -- Return the list of directory items
+ return directory_items
end)
-- Function to execute the parent arrow command
---@type fun(
---- args: Arguments, -- The arguments passed to the plugin
+--- args: Arguments, -- The arguments passed to the plugin
---): nil
local execute_parent_arrow = ya.sync(function(state, args)
- --
+ --
- -- Gets the parent directory
- local parent_directory = cx.active.parent
+ -- Gets the parent directory
+ local parent_directory = cx.active.parent
- -- If the parent directory doesn't exist,
- -- then exit the function
- if not parent_directory then return end
+ -- If the parent directory doesn't exist,
+ -- then exit the function
+ if not parent_directory then return end
- -- Get the offset from the arguments given
- local offset = table.remove(args, 1)
+ -- Get the offset from the arguments given
+ local offset = table.remove(args, 1)
- -- Get the type of the offset
- local offset_type = type(offset)
+ -- Get the type of the offset
+ local offset_type = type(offset)
- -- If the offset is not a number,
- -- 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)
- )
- )
- end
+ -- If the offset is not a number,
+ -- 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)
+ )
+ )
+ end
- -- Get the number of items in the parent directory
- local number_of_items = #parent_directory.files
+ -- Get the number of items in the parent directory
+ local number_of_items = #parent_directory.files
- -- Initialise the new cursor index
- -- to the current cursor index
- local new_cursor_index = parent_directory.cursor
+ -- Initialise the new cursor index
+ -- to the current cursor index
+ local new_cursor_index = parent_directory.cursor
- -- Get whether the user wants to sort directories first
- local sort_directories_first = cx.active.pref.sort_dir_first
+ -- Get whether the user wants to sort directories first
+ local sort_directories_first = cx.active.pref.sort_dir_first
- -- If wraparound file navigation is wanted
- if state.config.wraparound_file_navigation then
- --
+ -- If wraparound file navigation is wanted
+ if state.config.wraparound_file_navigation then
+ --
- -- If the user sorts their directories first
- if sort_directories_first then
- --
+ -- If the user sorts their directories first
+ if sort_directories_first then
+ --
- -- Get the directories in the parent directory
- local directories = get_parent_directory_items(true)
+ -- Get the directories in the parent directory
+ local directories = get_parent_directory_items(true)
- -- Get the number of directories in the parent directory
- local number_of_directories = #directories
+ -- Get the number of directories in the parent directory
+ local number_of_directories = #directories
- -- If the number of directories is 0, then exit the function
- if number_of_directories == 0 then return end
+ -- If the number of directories is 0, then exit the function
+ if number_of_directories == 0 then return end
- -- Get the new cursor index by adding the offset,
- -- and modding the whole thing by the number of directories
- new_cursor_index = (parent_directory.cursor + offset)
- % number_of_directories
+ -- Get the new cursor index by adding the offset,
+ -- and modding the whole thing by the number of directories
+ new_cursor_index = (parent_directory.cursor + offset)
+ % number_of_directories
- -- Otherwise, if the user doesn't sort their directories first
- else
- --
+ -- Otherwise, if the user doesn't sort their directories first
+ else
+ --
- -- Get the new cursor index by adding the offset,
- -- and modding the whole thing by the number of
- -- items in the parent directory
- new_cursor_index = (parent_directory.cursor + offset)
- % number_of_items
- end
+ -- Get the new cursor index by adding the offset,
+ -- and modding the whole thing by the number of
+ -- items in the parent directory
+ new_cursor_index = (parent_directory.cursor + offset)
+ % number_of_items
+ end
- -- Otherwise, get the new cursor index normally
- -- by adding the offset to the cursor index
- else
- new_cursor_index = parent_directory.cursor + offset
- end
+ -- Otherwise, get the new cursor index normally
+ -- by adding the offset to the cursor index
+ else
+ new_cursor_index = parent_directory.cursor + offset
+ end
- -- Increment the cursor index by 1.
- -- The cursor index needs to be increased by 1
- -- as the cursor index is 0-based, while Lua
- -- tables are 1-based.
- new_cursor_index = new_cursor_index + 1
+ -- Increment the cursor index by 1.
+ -- The cursor index needs to be increased by 1
+ -- as the cursor index is 0-based, while Lua
+ -- tables are 1-based.
+ new_cursor_index = new_cursor_index + 1
- -- Get the starting index of the loop
- local start_index = new_cursor_index
+ -- Get the starting index of the loop
+ local start_index = new_cursor_index
- -- Get the ending index of the loop.
- --
- -- If the offset given is negative, set the end index to 1,
- -- as the loop will iterate backwards.
- -- Otherwise, if the step given is positive,
- -- set the end index to the number of items in the
- -- parent directory.
- local end_index = offset < 0 and 1 or number_of_items
+ -- Get the ending index of the loop.
+ --
+ -- If the offset given is negative, set the end index to 1,
+ -- as the loop will iterate backwards.
+ -- Otherwise, if the step given is positive,
+ -- set the end index to the number of items in the
+ -- parent directory.
+ local end_index = offset < 0 and 1 or number_of_items
- -- Get the step for the loop.
- --
- -- If the offset given is negative, set the step to -1,
- -- as the loop will iterate backwards.
- -- Otherwise, if the step given is positive, set
- -- the step to 1 to iterate forwards.
- local step = offset < 0 and -1 or 1
+ -- Get the step for the loop.
+ --
+ -- If the offset given is negative, set the step to -1,
+ -- as the loop will iterate backwards.
+ -- Otherwise, if the step given is positive, set
+ -- the step to 1 to iterate forwards.
+ local step = offset < 0 and -1 or 1
- -- Iterate over the parent directory items
- for i = start_index, end_index, step do
- --
+ -- Iterate over the parent directory items
+ for i = start_index, end_index, step do
+ --
- -- Get the directory item
- local directory_item = parent_directory.files[i]
+ -- Get the directory item
+ local directory_item = parent_directory.files[i]
- -- If the directory item exists and is a directory
- if directory_item and directory_item.cha.is_dir then
- --
+ -- If the directory item exists and is a directory
+ if directory_item and directory_item.cha.is_dir then
+ --
- -- Emit the command to change directory to
- -- the directory item and exit the function
- return ya.manager_emit("cd", { directory_item.url })
- end
- end
+ -- Emit the command to change directory to
+ -- the directory item and exit the function
+ return ya.manager_emit("cd", { directory_item.url })
+ end
+ end
end)
-- Function to handle the parent arrow command
---@type CommandFunction
local function handle_parent_arrow(args)
- --
+ --
- -- Call the function to execute the parent arrow command
- -- with the arguments given
- execute_parent_arrow(args)
+ -- Call the function to execute the parent arrow command
+ -- with the arguments given
+ execute_parent_arrow(args)
end
-- Function to handle the editor command
---@type CommandFunction
local function handle_editor(args, config)
- --
+ --
- -- Get the editor environment variable
- local editor = os.getenv("EDITOR")
+ -- Get the editor environment variable
+ local editor = os.getenv("EDITOR")
- -- If the editor not set, exit the function
- if not editor then return end
+ -- If the editor not set, exit the function
+ if not editor then return end
- -- Call the handle shell function
- -- with the editor command
- handle_shell(
- merge_tables({
- editor .. " $@",
- block = true,
- exit_if_dir = true,
- }, args),
- config
- )
+ -- Call the handle shell function
+ -- with the editor command
+ handle_shell(
+ merge_tables({
+ editor .. " $@",
+ block = true,
+ exit_if_dir = true,
+ }, args),
+ config
+ )
end
-- Function to handle the pager command
---@type CommandFunction
local function handle_pager(args, config)
- --
+ --
- -- Get the pager environment variable
- local pager = os.getenv("PAGER")
+ -- Get the pager environment variable
+ local pager = os.getenv("PAGER")
- -- If the pager is not set, exit the function
- if not pager then return end
+ -- If the pager is not set, exit the function
+ if not pager then return end
- -- Call the handle shell function
- -- with the pager command
- handle_shell(
- merge_tables({
- pager .. " $@",
- block = true,
- exit_if_dir = true,
- }, args),
- config
- )
+ -- Call the handle shell function
+ -- with the pager command
+ handle_shell(
+ merge_tables({
+ pager .. " $@",
+ block = true,
+ exit_if_dir = true,
+ }, args),
+ config
+ )
end
-- Function to run the commands given
@@ -3536,39 +3573,40 @@ end
---@param config Configuration The configuration object
---@return nil
local function run_command_func(command, args, config)
- --
+ --
- -- The command table
- ---@type CommandTable
- local command_table = {
- [Commands.Open] = handle_open,
- [Commands.Extract] = handle_extract,
- [Commands.Enter] = handle_enter,
- [Commands.Leave] = handle_leave,
- [Commands.Rename] = function(_) handle_yazi_command("rename", args) end,
- [Commands.Remove] = function(_) handle_yazi_command("remove", args) end,
- [Commands.Create] = handle_create,
- [Commands.Shell] = handle_shell,
- [Commands.Paste] = handle_paste,
- [Commands.TabCreate] = handle_tab_create,
- [Commands.TabSwitch] = handle_tab_switch,
- [Commands.Arrow] = handle_arrow,
- [Commands.ParentArrow] = handle_parent_arrow,
- [Commands.Editor] = handle_editor,
- [Commands.Pager] = handle_pager,
- }
+ -- The command table
+ ---@type CommandTable
+ local command_table = {
+ [Commands.Open] = handle_open,
+ [Commands.Extract] = handle_extract,
+ [Commands.Enter] = handle_enter,
+ [Commands.Leave] = handle_leave,
+ [Commands.Rename] = function(_) handle_yazi_command("rename", args) end,
+ [Commands.Remove] = function(_) handle_yazi_command("remove", args) end,
+ [Commands.Create] = handle_create,
+ [Commands.Shell] = handle_shell,
+ [Commands.Paste] = handle_paste,
+ [Commands.TabCreate] = handle_tab_create,
+ [Commands.TabSwitch] = handle_tab_switch,
+ [Commands.Quit] = handle_quit,
+ [Commands.Arrow] = handle_arrow,
+ [Commands.ParentArrow] = handle_parent_arrow,
+ [Commands.Editor] = handle_editor,
+ [Commands.Pager] = handle_pager,
+ }
- -- Get the function for the command
- ---@type CommandFunction|nil
- local command_func = command_table[command]
+ -- Get the function for the command
+ ---@type CommandFunction|nil
+ local command_func = command_table[command]
- -- If the function isn't found, notify the user and exit the function
- if not command_func then
- return show_error("Unknown command: " .. command)
- end
+ -- If the function isn't found, notify the user and exit the function
+ if not command_func then
+ return show_error("Unknown command: " .. command)
+ end
- -- Otherwise, call the function for the command
- command_func(args, config)
+ -- Otherwise, call the function for the command
+ command_func(args, config)
end
-- The setup function to setup the plugin
@@ -3576,10 +3614,10 @@ end
---@param opts Configuration|nil The options given to the plugin
---@return nil
local function setup(_, opts)
- --
+ --
- -- Initialise the plugin
- initialise_plugin(opts)
+ -- Initialise the plugin
+ initialise_plugin(opts)
end
-- Function to be called to use the plugin
@@ -3587,33 +3625,33 @@ end
---@param job { args: Arguments } The job object given by Yazi
---@return nil
local function entry(_, job)
- --
+ --
- -- Get the arguments to the plugin
- ---@type Arguments
- local args = parse_number_arguments(job.args)
+ -- Get the arguments to the plugin
+ ---@type Arguments
+ local args = parse_number_arguments(job.args)
- -- Get the command passed to the plugin
- local command = table.remove(args, 1)
+ -- Get the command passed to the plugin
+ local command = table.remove(args, 1)
- -- If the command isn't given, exit the function
- if not command then return end
+ -- If the command isn't given, exit the function
+ if not command then return end
- -- Get the configuration object
- local config = get_config()
+ -- Get the configuration object
+ local config = get_config()
- -- If the configuration hasn't been initialised yet,
- -- then initialise the plugin with the default configuration,
- -- as it hasn't been initialised either
- if not config then config = initialise_plugin() end
+ -- If the configuration hasn't been initialised yet,
+ -- then initialise the plugin with the default configuration,
+ -- as it hasn't been initialised either
+ if not config then config = initialise_plugin() end
- -- Call the function to handle the commands
- run_command_func(command, args, config)
+ -- Call the function to handle the commands
+ 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,
+ setup = setup,
+ entry = entry,
}
diff --git a/config/yazi/plugins/chmod.yazi/main.lua b/config/yazi/plugins/chmod.yazi/main.lua
index 183c31e2..d3a5a672 100644
--- a/config/yazi/plugins/chmod.yazi/main.lua
+++ b/config/yazi/plugins/chmod.yazi/main.lua
@@ -1,3 +1,5 @@
+--- @since 25.2.7
+
local selected_or_hovered = ya.sync(function()
local tab, paths = cx.active, {}
for _, u in pairs(tab.selected) do
diff --git a/config/yazi/plugins/full-border.yazi/main.lua b/config/yazi/plugins/full-border.yazi/main.lua
index 0de33b1d..058371ad 100644
--- a/config/yazi/plugins/full-border.yazi/main.lua
+++ b/config/yazi/plugins/full-border.yazi/main.lua
@@ -1,3 +1,5 @@
+--- @since 25.2.7
+
local function setup(_, opts)
local type = opts and opts.type or ui.Border.ROUNDED
local old_build = Tab.build
diff --git a/config/yazi/plugins/git.yazi/README.md b/config/yazi/plugins/git.yazi/README.md
index f17d7b39..10542306 100644
--- a/config/yazi/plugins/git.yazi/README.md
+++ b/config/yazi/plugins/git.yazi/README.md
@@ -1,7 +1,7 @@
# git.yazi
> [!NOTE]
-> Yazi v0.4.1 or later is required for this plugin to work.
+> Yazi v25.2.7 or later is required for this plugin to work.
Show the status of Git file changes as linemode in the file list.
diff --git a/config/yazi/plugins/git.yazi/main.lua b/config/yazi/plugins/git.yazi/main.lua
index d629d7d6..edd54fc0 100644
--- a/config/yazi/plugins/git.yazi/main.lua
+++ b/config/yazi/plugins/git.yazi/main.lua
@@ -1,3 +1,5 @@
+--- @since 25.2.7
+
local WIN = ya.target_family() == "windows"
local PATS = {
{ "[MT]", 6 }, -- Modified
@@ -159,9 +161,6 @@ local function fetch(_, job)
local repo = root(cwd)
if not repo then
remove(tostring(cwd))
- if not ya.__250127 then -- TODO: remove this
- return 1
- end
return true
end
@@ -178,10 +177,6 @@ local function fetch(_, job)
:stdout(Command.PIPED)
:output()
if not output then
- if not ya.__250127 then -- TODO: remove this
- ya.err("Cannot spawn git command, error: " .. err)
- return 0
- end
return true, Err("Cannot spawn `git` command, error: %s", err)
end
@@ -208,9 +203,6 @@ local function fetch(_, job)
end
add(tostring(cwd), repo, changed)
- if not ya.__250127 then -- TODO: remove this
- return 3
- end
return false
end
diff --git a/config/yazi/plugins/glow.yazi/README.md b/config/yazi/plugins/glow.yazi/README.md
index c67f7cc7..ba66ae77 100644
--- a/config/yazi/plugins/glow.yazi/README.md
+++ b/config/yazi/plugins/glow.yazi/README.md
@@ -19,7 +19,7 @@ Make sure you have [glow](https://github.com/charmbracelet/glow) installed, and
## Feature
-+ You can modify line wrap in `init.lua`, the current value is 55.
++ You can modify line wrap in `main.lua`, the current value is 55.
+ You can press `ctrl+e` to scroll up and `ctrl+y` to scroll down the readme file in preview panel in yazi: (add this to `keymap.toml`)
```toml
prepend_keymap = [
diff --git a/config/yazi/plugins/glow.yazi/main.lua b/config/yazi/plugins/glow.yazi/main.lua
index cc813e9d..09080154 100644
--- a/config/yazi/plugins/glow.yazi/main.lua
+++ b/config/yazi/plugins/glow.yazi/main.lua
@@ -1,7 +1,7 @@
local M = {}
function M:peek(job)
- -- Set a fixed width of 55 characters for the preview
+ -- Set a fixed width of 50 characters for the preview
local preview_width = 55
local child = Command("glow")
@@ -55,20 +55,8 @@ function M:seek(job)
if not h or h.url ~= job.file.url then
return
end
-
- local scroll_amount = 1
- local scroll_offset = job.units
-
- if job.key == "ctrl-e" then
- scroll_offset = scroll_amount
- elseif job.key == "ctrl-y" then
- scroll_offset = -scroll_amount
- else
- scroll_offset = job.units
- end
-
ya.manager_emit('peek', {
- math.max(0, cx.active.preview.skip + scroll_offset),
+ math.max(0, cx.active.preview.skip + job.units),
only_if = job.file.url,
})
end
diff --git a/config/yazi/plugins/hexyl.yazi/main.lua b/config/yazi/plugins/hexyl.yazi/main.lua
index 6fe0990e..3b6a51cf 100644
--- a/config/yazi/plugins/hexyl.yazi/main.lua
+++ b/config/yazi/plugins/hexyl.yazi/main.lua
@@ -1,57 +1,76 @@
local M = {}
function M:peek(job)
- local child
- local l = self.file.cha.len
- if l == 0 then
- child = Command("hexyl")
- :args({
- tostring(job.file.url),
- })
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :spawn()
- else
- child = Command("hexyl")
- :args({
- "--border",
- "none",
- "--terminal-width",
- tostring(job.area.w),
- tostring(job.file.url),
- })
- :stdout(Command.PIPED)
- :stderr(Command.PIPED)
- :spawn()
- end
+ local child
+ local l = job.file.cha.len
+ if l == 0 then
+ child = Command("hexyl")
+ :args({
+ tostring(job.file.url),
+ })
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :spawn()
+ else
+ child = Command("hexyl")
+ :args({
+ "--border", "none",
+ "--terminal-width", tostring(job.area.w),
+ tostring(job.file.url),
+ })
+ :stdout(Command.PIPED)
+ :stderr(Command.PIPED)
+ :spawn()
+ end
- local limit = job.area.h
- local i, lines = 0, ""
- repeat
- local next, event = child:read_line()
- if event == 1 then
- ya.err(tostring(event))
- elseif event ~= 0 then
- break
- end
+ if not child then
+ return require("code").peek(job)
+ end
- i = i + 1
- if i > job.skip then
- lines = lines .. next
- end
- until i >= job.skip + limit
+ local limit = job.area.h
+ local i, lines = 0, ""
+ repeat
+ local line, event = child:read_line()
+ if event == 1 then
+ ya.err(tostring(event))
+ break
+ elseif event ~= 0 then
+ break
+ end
- child:start_kill()
- if job.skip > 0 and i < job.skip + limit then
- ya.manager_emit("peek", { math.max(0, i - limit), only_if = job.file.url, upper_bound = true })
- else
- lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
- ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) })
- end
+ i = i + 1
+ if i > job.skip then
+ lines = lines .. line
+ end
+ until i >= job.skip + limit
+
+ child:start_kill()
+ if job.skip > 0 and i < job.skip + limit then
+ ya.manager_emit("peek", {
+ math.max(0, i - limit),
+ only_if = job.file.url,
+ upper_bound = true,
+ })
+ else
+ lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
+ ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) })
+ end
end
-function M:seek(units)
- require("code").seek(job, units)
+function M:seek(job)
+ -- Get the currently hovered file from your UI context.
+ local h = cx.active.current.hovered
+ if not h or h.url ~= job.file.url then
+ return
+ end
+
+ local scroll_offset = job.units
+
+ -- Emit a new peek event with the updated skip value.
+ ya.manager_emit("peek", {
+ math.max(0, cx.active.preview.skip + scroll_offset),
+ only_if = job.file.url,
+ })
end
return M
diff --git a/config/yazi/plugins/hide-preview.yazi/README.md b/config/yazi/plugins/hide-preview.yazi/README.md
index f307e667..f6ecb7a0 100644
--- a/config/yazi/plugins/hide-preview.yazi/README.md
+++ b/config/yazi/plugins/hide-preview.yazi/README.md
@@ -1,5 +1,8 @@
# hide-preview.yazi
+> [!WARNING]
+> This plugin has been deprecated. Please use the new [toggle-pane.yazi](../toggle-pane.yazi) instead.
+
Switch the preview pane between hidden and shown.
https://github.com/yazi-rs/plugins/assets/17523360/c4f0b5c4-ff9f-4be8-ba73-4d8e7902e383
diff --git a/config/yazi/plugins/hide-preview.yazi/main.lua b/config/yazi/plugins/hide-preview.yazi/main.lua
index fcf4094f..7b9a2bd6 100644
--- a/config/yazi/plugins/hide-preview.yazi/main.lua
+++ b/config/yazi/plugins/hide-preview.yazi/main.lua
@@ -1,6 +1,14 @@
+--- @since 25.2.7
--- @sync entry
local function entry(st)
+ ya.notify {
+ title = "Deprecated plugin",
+ content = "The `hide-preview` plugin is deprecated, please use the new `toggle-pane` plugin instead: https://github.com/yazi-rs/plugins/tree/main/toggle-pane.yazi",
+ timeout = 10,
+ level = "warn",
+ }
+
if st.old then
Tab.layout, st.old = st.old, nil
else
diff --git a/config/yazi/plugins/max-preview.yazi/README.md b/config/yazi/plugins/max-preview.yazi/README.md
index 73b90585..4de80df0 100644
--- a/config/yazi/plugins/max-preview.yazi/README.md
+++ b/config/yazi/plugins/max-preview.yazi/README.md
@@ -1,5 +1,8 @@
# max-preview.yazi
+> [!WARNING]
+> This plugin has been deprecated. Please use the new [toggle-pane.yazi](../toggle-pane.yazi) instead.
+
Maximize or restore the preview pane.
https://github.com/yazi-rs/plugins/assets/17523360/8976308e-ebfe-4e9e-babe-153eb1f87d61
diff --git a/config/yazi/plugins/max-preview.yazi/main.lua b/config/yazi/plugins/max-preview.yazi/main.lua
index 64edfed6..025ffe4d 100644
--- a/config/yazi/plugins/max-preview.yazi/main.lua
+++ b/config/yazi/plugins/max-preview.yazi/main.lua
@@ -1,6 +1,14 @@
+--- @since 25.2.7
--- @sync entry
local function entry(st)
+ ya.notify {
+ title = "Deprecated plugin",
+ content = "The `max-preview` plugin is deprecated, please use the new `toggle-pane` plugin instead: https://github.com/yazi-rs/plugins/tree/main/toggle-pane.yazi",
+ timeout = 10,
+ level = "warn",
+ }
+
if st.old then
Tab.layout, st.old = st.old, nil
else
diff --git a/config/yazi/plugins/ouch.yazi/README.md b/config/yazi/plugins/ouch.yazi/README.md
index 570b52b0..fd2ee089 100644
--- a/config/yazi/plugins/ouch.yazi/README.md
+++ b/config/yazi/plugins/ouch.yazi/README.md
@@ -10,7 +10,7 @@
## Installation
-If you use latest Yazi from main branch
+If you use Yazi from latest main branch
```bash
# Linux/macOS
git clone https://github.com/ndtoan96/ouch.yazi.git ~/.config/yazi/plugins/ouch.yazi
@@ -22,16 +22,16 @@ git clone https://github.com/ndtoan96/ouch.yazi.git %AppData%\yazi\config\plugin
git clone https://github.com/ndtoan96/ouch.yazi.git "$($env:APPDATA)\yazi\config\plugins\ouch.yazi"
```
-If you use Yazi <= 0.3.3
+If you use Yazi < 0.4.3
```bash
# Linux/macOS
-git clone --branch v0.2.1 --single-branch https://github.com/ndtoan96/ouch.yazi.git ~/.config/yazi/plugins/ouch.yazi
+git clone --branch v0.4.0 --single-branch https://github.com/ndtoan96/ouch.yazi.git ~/.config/yazi/plugins/ouch.yazi
# Windows with cmd
-git clone --branch v0.2.1 --single-branch https://github.com/ndtoan96/ouch.yazi.git %AppData%\yazi\config\plugins\ouch.yazi
+git clone --branch v0.4.0 --single-branch https://github.com/ndtoan96/ouch.yazi.git %AppData%\yazi\config\plugins\ouch.yazi
# Windows with powershell
-git clone --branch v0.2.1 --single-branch https://github.com/ndtoan96/ouch.yazi.git "$($env:APPDATA)\yazi\config\plugins\ouch.yazi"
+git clone --branch v0.4.0 --single-branch https://github.com/ndtoan96/ouch.yazi.git "$($env:APPDATA)\yazi\config\plugins\ouch.yazi"
```
Make sure you have [ouch](https://github.com/ouch-org/ouch) installed and in your `PATH`.
diff --git a/config/yazi/plugins/relative-motions.yazi/README.md b/config/yazi/plugins/relative-motions.yazi/README.md
index b39c8a2a..35a2386b 100644
--- a/config/yazi/plugins/relative-motions.yazi/README.md
+++ b/config/yazi/plugins/relative-motions.yazi/README.md
@@ -6,26 +6,14 @@ https://github.com/dedukun/relative-motions.yazi/assets/25795432/04fb186a-5efe-4
## Requirements
-- [Yazi](https://github.com/sxyazi/yazi) v0.3.0+
+- [Yazi](https://github.com/sxyazi/yazi) v25.2.7+
## Installation
-If you use the latest Yazi from main branch
-
```sh
ya pack -a dedukun/relative-motions
```
-If you are using <= v0.3.3
-
-```sh
-# Linux/macOS
-git clone --branch 0.3.3 https://github.com/dedukun/relative-motions.yazi.git ~/.config/yazi/plugins/relative-motions.yazi
-
-# Windows
-git clone --branch 0.3.3 https://github.com/dedukun/relative-motions.yazi.git %AppData%\yazi\config\plugins\relative-motions.yazi
-```
-
## Configuration
If you want to use the numbers directly to start a motion add this to your `keymap.toml`:
@@ -35,47 +23,47 @@ If you want to use the numbers directly to start a motion add this to your `keym
```toml
[[manager.prepend_keymap]]
on = [ "1" ]
-run = "plugin relative-motions --args=1"
+run = "plugin relative-motions 1"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "2" ]
-run = "plugin relative-motions --args=2"
+run = "plugin relative-motions 2"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "3" ]
-run = "plugin relative-motions --args=3"
+run = "plugin relative-motions 3"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "4" ]
-run = "plugin relative-motions --args=4"
+run = "plugin relative-motions 4"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "5" ]
-run = "plugin relative-motions --args=5"
+run = "plugin relative-motions 5"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "6" ]
-run = "plugin relative-motions --args=6"
+run = "plugin relative-motions 6"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "7" ]
-run = "plugin relative-motions --args=7"
+run = "plugin relative-motions 7"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "8" ]
-run = "plugin relative-motions --args=8"
+run = "plugin relative-motions 8"
desc = "Move in relative steps"
[[manager.prepend_keymap]]
on = [ "9" ]
-run = "plugin relative-motions --args=9"
+run = "plugin relative-motions 9"
desc = "Move in relative steps"
```
@@ -94,18 +82,19 @@ desc = "Trigger a new relative motion"
Additionally there are a couple of initial configurations that can be given to the plugin's `setup` function:
-| Configuration | Values | Default | Description |
-| -------------- | ----------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
-| `show_numbers` | `relative`, `absolute`, `relative_absolute` or `none` | `none` | Shows relative or absolute numbers before the file icon |
-| `show_motion` | `true` or `false` | `false` | Shows current motion in Status bar |
-| `only_motions` | `true` or `false` | `false` | If true, only the motion movements will be enabled, i.e., the commands for delete, cut, yank and visual selection will be disabled |
+| Configuration | Values | Default | Description |
+| -------------- | ----------------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| `show_numbers` | `relative`, `absolute`, `relative_absolute` or `none` | `none` | Shows relative or absolute numbers before the file icon |
+| `show_motion` | `true` or `false` | `false` | Shows current motion in Status bar |
+| `only_motions` | `true` or `false` | `false` | If true, only the motion movements will be enabled, i.e., the commands for delete, cut, yank and visual selection will be disabled |
+| `enter_mode` | `cache`, `first` or `cache_or_first` | `cache_or_first` | The method to enter folders |
If you want, for example, to enable relative numbers as well as to show the motion in the status bar,
add the following to Yazi's `init.lua`, i.e. `~/.config/yazi/init.lua`:
```lua
-- ~/.config/yazi/init.lua
-require("relative-motions"):setup({ show_numbers="relative", show_motion = true })
+require("relative-motions"):setup({ show_numbers="relative", show_motion = true, enter_mode ="first" })
```
> [!NOTE]
@@ -119,13 +108,15 @@ require("relative-motions"):setup({ show_numbers="relative", show_motion = true
This plugin adds the some basic vim motions like `3k`, `12j`, `10gg`, etc.
The following table show all the available motions:
-| Command | Description |
-| -------------- | ------------------- |
-| `j`/`` | Move `n` lines down |
-| `k`/`` | Move `n` lines up |
-| `gj`/`g` | Go `n` lines down |
-| `gk`/`g` | Go `n` lines up |
-| `gg` | Go to line |
+| Command | Description |
+| -------------- | --------------------- |
+| `j`/`` | Move `n` lines down |
+| `k`/`` | Move `n` lines up |
+| `h`/`` | Move `n` folders back |
+| `l`/`` | Enter `n` folders |
+| `gj`/`g` | Go `n` lines down |
+| `gk`/`g` | Go `n` lines up |
+| `gg` | Go to line |
Furthermore, the following operations were also added:
diff --git a/config/yazi/plugins/relative-motions.yazi/main.lua b/config/yazi/plugins/relative-motions.yazi/main.lua
index be938098..a2764595 100644
--- a/config/yazi/plugins/relative-motions.yazi/main.lua
+++ b/config/yazi/plugins/relative-motions.yazi/main.lua
@@ -1,3 +1,4 @@
+--- @since 25.2.7
-- stylua: ignore
local MOTIONS_AND_OP_KEYS = {
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
@@ -8,7 +9,7 @@ local MOTIONS_AND_OP_KEYS = {
{ on = "t" }, { on = "L" }, { on = "H" }, { on = "w" },
{ on = "W" }, { on = "<" }, { on = ">" }, { on = "~" },
-- movement
- { on = "g" }, { on = "j" }, { on = "k" }, { on = "" }, { on = "" }
+ { on = "g" }, { on = "j" }, { on = "k" }, { on = "h" }, { on = "l" }, { on = "" }, { on = "" }, { on = "" }, { on = "" }
}
-- stylua: ignore
@@ -16,7 +17,7 @@ local MOTION_KEYS = {
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
{ on = "5" }, { on = "6" }, { on = "7" }, { on = "8" }, { on = "9" },
-- movement
- { on = "g" }, { on = "j" }, { on = "k" }
+ { on = "g" }, { on = "j" }, { on = "k" }, { on = "h" }, { on = "l" }, { on = "" }, { on = "" }, { on = "" }, { on = "" }
}
-- stylua: ignore
@@ -30,6 +31,10 @@ local SHOW_NUMBERS_ABSOLUTE = 0
local SHOW_NUMBERS_RELATIVE = 1
local SHOW_NUMBERS_RELATIVE_ABSOLUTE = 2
+local ENTER_MODE_FIRST = 0
+local ENTER_MODE_CACHE = 1
+local ENTER_MODE_CACHE_OR_FIRST = 2
+
-----------------------------------------------
----------------- R E N D E R -----------------
-----------------------------------------------
@@ -149,6 +154,10 @@ local function normal_direction(dir)
return "j"
elseif dir == "" then
return "k"
+ elseif dir == "" then
+ return "h"
+ elseif dir == "" then
+ return "l"
end
return dir
end
@@ -205,6 +214,29 @@ end
local get_active_tab = ya.sync(function(_) return cx.tabs.idx end)
+local get_cache_or_first_dir = ya.sync(function(state)
+ if state._enter_mode == ENTER_MODE_CACHE then
+ return nil
+ elseif state._enter_mode == ENTER_MODE_CACHE_OR_FIRST then
+ local hovered_file = cx.active.current.hovered
+
+ if hovered_file ~= nil and hovered_file.cha.is_dir then
+ return cx.active.current.cursor
+ end
+ end
+
+ local files = cx.active.current.files
+ local index = 1
+
+ for i = 1, #files do
+ if files[i].cha.is_dir then
+ index = i
+ break
+ end
+ end
+
+ return index - 1
+end)
-----------------------------------------------
---------- E N T R Y / S E T U P ----------
-----------------------------------------------
@@ -231,7 +263,7 @@ return {
if cmd == "g" then
if direction == "g" then
- ya.manager_emit("arrow", { -99999999 })
+ ya.manager_emit("arrow", { "top" })
ya.manager_emit("arrow", { lines - 1 })
render_clear()
return
@@ -254,6 +286,19 @@ return {
ya.manager_emit("arrow", { lines })
elseif cmd == "k" then
ya.manager_emit("arrow", { -lines })
+ elseif cmd == "h" then
+ for _ = 1, lines do
+ ya.manager_emit("leave", {})
+ end
+ elseif cmd == "l" then
+ for _ = 1, lines do
+ ya.manager_emit("enter", {})
+ local file_idx = get_cache_or_first_dir()
+ if file_idx then
+ ya.manager_emit("arrow", { "top" })
+ ya.manager_emit("arrow", { file_idx })
+ end
+ end
elseif is_tab_command(cmd) then
if cmd == "t" then
for _ = 1, lines do
@@ -315,6 +360,16 @@ return {
render_motion_setup()
end
+ if args["enter_mode"] == "cache" then
+ state._enter_mode = ENTER_MODE_CACHE
+ elseif args["enter_mode"] == "first" then
+ state._enter_mode = ENTER_MODE_FIRST
+ elseif args["enter_mode"] == "cache_or_first" then
+ state._enter_mode = ENTER_MODE_CACHE_OR_FIRST
+ else
+ state._enter_mode = ENTER_MODE_CACHE_OR_FIRST
+ end
+
if args["show_numbers"] == "absolute" then
render_numbers(SHOW_NUMBERS_ABSOLUTE)
elseif args["show_numbers"] == "relative" then
diff --git a/config/yazi/plugins/torrent-preview.yazi/README.md b/config/yazi/plugins/torrent-preview.yazi/README.md
index aa5ed0f8..8381ee09 100644
--- a/config/yazi/plugins/torrent-preview.yazi/README.md
+++ b/config/yazi/plugins/torrent-preview.yazi/README.md
@@ -1,6 +1,6 @@
# torrent-preview.yazi
-[Yazi](https://github.com/sxyazi/yazi) plugin to preview `application/x-bittorrent` files
+[Yazi](https://github.com/sxyazi/yazi) plugin to preview `application/bittorrent` files

@@ -13,6 +13,14 @@
### Linux/MacOS
+Using the [Yazi Package Manager](https://yazi-rs.github.io/docs/cli/#package-manager):
+
+```sh
+ya pack -a kirasok/torrent-preview
+```
+
+Or manually:
+
```sh
git clone https://github.com/kirasok/torrent-preview.yazi.git ~/.config/yazi/plugins/torrent-preview.yazi
```
@@ -23,6 +31,10 @@ Add this to your `yazi.toml`:
```toml
[[plugin.prepend_previewers]]
-mime = "application/x-bittorrent"
+mime = "application/bittorrent"
run = "torrent-preview"
```
+
+> [!NOTE]
+> Yazi after `v0.4` removes `x-` prefix from subtype, so even if `file -i` outputs `application/x-bittorrent`, you should use `application/bittorrent` ([relevant issue](https://github.com/kirasok/torrent-preview.yazi/issues/2))
+
diff --git a/config/yazi/yazi.toml b/config/yazi/yazi.toml
index 4894591c..bfeff9ba 100644
--- a/config/yazi/yazi.toml
+++ b/config/yazi/yazi.toml
@@ -93,7 +93,7 @@ previewers = [
{mime = "application/json", run = "code"},
# Image
{mime = "image/vnd.djvu", run = "noop"},
- {mime = "image/*", run = "image"},
+ # {mime = "image/*", run = "image"},
# Video
# {mime = "video/*", run = "video"},
# PDF
diff --git a/dotter b/dotter
old mode 100755
new mode 100644
diff --git a/dotter.arm b/dotter.arm
old mode 100755
new mode 100644
diff --git a/dotter.exe b/dotter.exe
old mode 100755
new mode 100644
diff --git a/local/bin/tmux-sessionizer b/local/bin/tmux-sessionizer
index f98be204..53cfc552 100755
--- a/local/bin/tmux-sessionizer
+++ b/local/bin/tmux-sessionizer
@@ -3,7 +3,7 @@
if [[ $# -eq 1 ]]; then
selected=$1
else
- selected=$(fd --min-depth 1 --max-depth 1 --type d . ~/repos/Rust/ ~/repos/examples/ ~/repos/ ~/neorg/Work/ ~/Nextcloud/repos/ ~/Nextcloud/Documents/LaTeX/ ~/Nextcloud/Documents/Typst/ ~/Nextcloud/repos/university/** ~/Nextcloud/repos/university/**/**/ ~/repos/yoda-bot/ ~/repos/Codnity/ ~/repos/Codnity/emisela/ ~/repos/Codnity/dio/ ~/repos/Codnity/zaao/ ~/repos/Codnity/talentflow/ | sk --height 16)
+ selected=$(fd --min-depth 1 --max-depth 1 --type d . ~/repos/Rust/ ~/repos/examples/ ~/repos/ ~/neorg/Work/ ~/Nextcloud/repos/ ~/Nextcloud/Documents/LaTeX/ ~/Nextcloud/Documents/Typst/ ~/Nextcloud/repos/university/** ~/Nextcloud/repos/university/**/**/ ~/repos/yoda-bot/ ~/repos/Codnity/ ~/repos/Codnity/emisela/ ~/repos/Codnity/dio/ ~/repos/Codnity/zaao/ ~/repos/Codnity/talentflow/ ~/Obsidian | sk --height 16)
fi
if [[ -z $selected ]]; then