From 9e0be0285a98465cad6591799b4905e0f5421600 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Tue, 10 Dec 2024 08:11:14 +0200 Subject: [PATCH] Update 2024-12-10 --- .dotter/global.toml | 27 +- config/batrc | 2 +- config/btop/btop.conf | 2 +- config/shell/aliasrc | 1 - config/tmThemes/Rosé Pine Dawn.tmTheme | 299 ++++++ config/tmThemes/Rosé Pine Moon.tmTheme | 299 ++++++ config/tmThemes/Rosé Pine.tmTheme | 299 ++++++ config/tmux/tmux.conf | 5 +- config/yazi/keymap.toml | 2 +- config/yazi/package.toml | 32 +- .../plugins/augment-command.yazi/README.md | 157 ++- .../plugins/augment-command.yazi/init.lua | 905 ++++++++++++------ config/yazi/plugins/exifaudio.yazi/init.lua | 54 +- config/yazi/plugins/glow.yazi/init.lua | 53 +- config/yazi/plugins/hexyl.yazi/init.lua | 29 +- config/yazi/plugins/nbpreview.yazi/init.lua | 25 +- config/yazi/plugins/ouch.yazi/init.lua | 28 +- .../plugins/relative-motions.yazi/init.lua | 15 +- config/yazi/plugins/yatline.yazi/init.lua | 25 +- config/yazi/yazi.toml | 2 +- local/bin/typst-port | 32 + 21 files changed, 1778 insertions(+), 515 deletions(-) create mode 100644 config/tmThemes/Rosé Pine Dawn.tmTheme create mode 100644 config/tmThemes/Rosé Pine Moon.tmTheme create mode 100644 config/tmThemes/Rosé Pine.tmTheme create mode 100644 local/bin/typst-port diff --git a/.dotter/global.toml b/.dotter/global.toml index 738141a3..433129d0 100644 --- a/.dotter/global.toml +++ b/.dotter/global.toml @@ -1,7 +1,7 @@ [helpers] [default] -depends = [ ] +depends = [] [default.files] LICENSE = "" @@ -13,38 +13,38 @@ LICENSE = "" default_target_type = "symbolic" [base] -depends = [ "default", "zsh", "spotify", "terminal", "local", "misc" ] +depends = ["default", "zsh", "spotify", "terminal", "local", "misc"] [x11] -depends = [ "base", "awesome", "picom", "dunst" ] +depends = ["base", "awesome", "picom", "dunst"] [x11.files] "config/zsh/.zprofile-x11" = "~/.config/zsh/.zprofile" "config/x11/" = "~/.config/x11/" -"config/x11/xresources" = {target = "~/.config/x11/xresources", type = "template"} +"config/x11/xresources" = { target = "~/.config/x11/xresources", type = "template" } [x11-laptop] -depends = [ "base", "awesome_laptop", "picom", "dunst" ] +depends = ["base", "awesome_laptop", "picom", "dunst"] [x11-laptop.files] "config/zsh/.zprofile-x11" = "~/.config/zsh/.zprofile" "config/x11/" = "~/.config/x11/" -"config/x11/xresources" = {target = "~/.config/x11/xresources", type = "template"} +"config/x11/xresources" = { target = "~/.config/x11/xresources", type = "template" } [wayland] -depends = [ "base", "hyprland", "dunst" ] +depends = ["base", "hyprland", "dunst"] [wayland.files] "config/zsh/.zprofile-wayland" = "~/.config/zsh/.zprofile" -"config/x11/xresources" = {target = "~/.config/x11/xresources", type = "template"} +"config/x11/xresources" = { target = "~/.config/x11/xresources", type = "template" } [shell.files] "config/shell/" = "~/.config/shell/" [zsh] -depends = [ "shell" ] +depends = ["shell"] [zsh.files] "config/shell/env" = "~/.zshenv" @@ -55,10 +55,11 @@ depends = [ "shell" ] "local/share/" = "~/.local/share/" [misc] -depends = [ "torrent", "zathura" ] +depends = ["torrent", "zathura"] [misc.files] "config/batrc" = "~/.config/bat/config" +"config/tmThemes/" = "~/.config/silicon/themes/" "config/btop/" = "~/.config/btop/" "config/htoprc" = "~/.config/htop/htoprc" "config/fastfetch/" = "~/.config/fastfetch/" @@ -92,7 +93,7 @@ depends = [ "torrent", "zathura" ] "config/dunst/" = "~/.config/dunst/" [hyprland] -depends = [ "dunst", "misc", "local", "eww", "lock" ] +depends = ["dunst", "misc", "local", "eww", "lock"] [hyprland.files] "config/hypr/" = "~/.config/hypr/" @@ -120,11 +121,11 @@ depends = [ "dunst", "misc", "local", "eww", "lock" ] "config/spotify-tui.yml" = "~/.config/spotify-tui/config.yml" [terminal] -depends = [ "zsh", "tmux", "yazi" ] +depends = ["zsh", "tmux", "yazi"] [terminal.files] "config/alacritty/" = "~/.config/alacritty/" -"config/alacritty/alacritty.toml" = {target = "~/.config/alacritty/alacritty.toml", type = "template"} +"config/alacritty/alacritty.toml" = { target = "~/.config/alacritty/alacritty.toml", type = "template" } "config/starship.toml" = "~/.config/starship/starship.toml" [tmux.files] diff --git a/config/batrc b/config/batrc index db74b122..c8bfa74e 100644 --- a/config/batrc +++ b/config/batrc @@ -4,7 +4,7 @@ # Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes` # for a list of all available themes ---theme="base16-256" +--theme="Rosé Pine" # Enable this to use italic text on the terminal. This is not supported on all # terminal emulators (like tmux, by default): diff --git a/config/btop/btop.conf b/config/btop/btop.conf index 6a728033..185efa15 100644 --- a/config/btop/btop.conf +++ b/config/btop/btop.conf @@ -57,7 +57,7 @@ update_ms = 500 #* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", #* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. -proc_sorting = "cpu direct" +proc_sorting = "memory" #* Reverse sorting order, True or False. proc_reversed = False diff --git a/config/shell/aliasrc b/config/shell/aliasrc index e4f60c54..17ea8e11 100644 --- a/config/shell/aliasrc +++ b/config/shell/aliasrc @@ -46,7 +46,6 @@ alias \ night="redshift -PO 4500" \ py="python" \ sv="rsv" \ - typst-port="ss -tunlp | rg tinymist" \ v="$EDITOR" \ weather="curl wttr.in/" \ wg-down="wg-quick down wg0" \ diff --git a/config/tmThemes/Rosé Pine Dawn.tmTheme b/config/tmThemes/Rosé Pine Dawn.tmTheme new file mode 100644 index 00000000..6c94c8c1 --- /dev/null +++ b/config/tmThemes/Rosé Pine Dawn.tmTheme @@ -0,0 +1,299 @@ + + + + + name + Rosé Pine Dawn + settings + + + settings + + background + #faf4ed + caret + #cecacd + foreground + #575279 + invisibles + #fffaf3 + lineHighlight + #f4ede8 + selection + #dfdad9 + + + + name + Comment + scope + comment + settings + + foreground + #797593 + + + + name + String + scope + string + settings + + foreground + #ea9d34 + + + + name + Number + scope + constant.numeric + settings + + foreground + #907aa9 + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #907aa9 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #907aa9 + + + + name + Variable + scope + variable + settings + + fontStyle + + foreground + #d7827e + + + + name + Keyword + scope + keyword + settings + + foreground + #b4637a + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #b4637a + + + + name + Storage type + scope + storage.type + settings + + fontStyle + italic + foreground + #56949f + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + bold + foreground + #286983 + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #286983 + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + foreground + #286983 + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + italic + foreground + #ea9d34 + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + foreground + #b4637a + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #286983 + + + + name + Library function + scope + support.function + settings + + fontStyle + + foreground + #56949f + + + + name + Library constant + scope + support.constant + settings + + fontStyle + + foreground + #56949f + + + + name + Library class/type + scope + support.type, support.class + settings + + fontStyle + italic + foreground + #56949f + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + + + + + name + Invalid + scope + invalid + settings + + background + #b4637a + fontStyle + + foreground + #575279 + + + + name + Invalid deprecated + scope + invalid.deprecated + settings + + background + #907aa9 + foreground + #575279 + + + + uuid + dac29768-bcff-4df3-936c-88c7540d550d + colorSpaceName + sRGB + semanticClass + theme.light.rosé_pine-dawn + author + oplik0 + comment + soho vibes - modified from the sublime text theme by ThatOneCalculator + + diff --git a/config/tmThemes/Rosé Pine Moon.tmTheme b/config/tmThemes/Rosé Pine Moon.tmTheme new file mode 100644 index 00000000..d96a7e1a --- /dev/null +++ b/config/tmThemes/Rosé Pine Moon.tmTheme @@ -0,0 +1,299 @@ + + + + + name + Rosé Pine Moon + settings + + + settings + + background + #232136 + caret + #56526e + foreground + #e0def4 + invisibles + #2a273f + lineHighlight + #2a283e + selection + #6e6a86 + + + + name + Comment + scope + comment + settings + + foreground + #908caa + + + + name + String + scope + string + settings + + foreground + #f6c177 + + + + name + Number + scope + constant.numeric + settings + + foreground + #c4a7e7 + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #c4a7e7 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #c4a7e7 + + + + name + Variable + scope + variable + settings + + fontStyle + + foreground + #ea9a97 + + + + name + Keyword + scope + keyword + settings + + foreground + #eb6f92 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #eb6f92 + + + + name + Storage type + scope + storage.type + settings + + fontStyle + italic + foreground + #9ccfd8 + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + bold + foreground + #3e8fb0 + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #3e8fb0 + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + foreground + #3e8fb0 + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + italic + foreground + #f6c177 + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + foreground + #eb6f92 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #3e8fb0 + + + + name + Library function + scope + support.function + settings + + fontStyle + + foreground + #9ccfd8 + + + + name + Library constant + scope + support.constant + settings + + fontStyle + + foreground + #9ccfd8 + + + + name + Library class/type + scope + support.type, support.class + settings + + fontStyle + italic + foreground + #9ccfd8 + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + + + + + name + Invalid + scope + invalid + settings + + background + #eb6f92 + fontStyle + + foreground + #e0def4 + + + + name + Invalid deprecated + scope + invalid.deprecated + settings + + background + #c4a7e7 + foreground + #e0def4 + + + + uuid + a65f621e-b84b-48fb-afec-e5c085e8debf + colorSpaceName + sRGB + semanticClass + theme.dark.rosé_pine-moon + author + oplik0 + comment + soho vibes - modified from the sublime text theme by ThatOneCalculator + + diff --git a/config/tmThemes/Rosé Pine.tmTheme b/config/tmThemes/Rosé Pine.tmTheme new file mode 100644 index 00000000..7dea0f15 --- /dev/null +++ b/config/tmThemes/Rosé Pine.tmTheme @@ -0,0 +1,299 @@ + + + + + name + Rosé Pine + settings + + + settings + + background + #191724 + caret + #524f67 + foreground + #e0def4 + invisibles + #1f1d2e + lineHighlight + #21202e + selection + #403d52 + + + + name + Comment + scope + comment + settings + + foreground + #908caa + + + + name + String + scope + string + settings + + foreground + #f6c177 + + + + name + Number + scope + constant.numeric + settings + + foreground + #c4a7e7 + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #c4a7e7 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #c4a7e7 + + + + name + Variable + scope + variable + settings + + fontStyle + + foreground + #ebbcba + + + + name + Keyword + scope + keyword + settings + + foreground + #eb6f92 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #eb6f92 + + + + name + Storage type + scope + storage.type + settings + + fontStyle + italic + foreground + #9ccfd8 + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + bold + foreground + #31748f + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #31748f + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + foreground + #31748f + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + italic + foreground + #f6c177 + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + foreground + #eb6f92 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #31748f + + + + name + Library function + scope + support.function + settings + + fontStyle + + foreground + #9ccfd8 + + + + name + Library constant + scope + support.constant + settings + + fontStyle + + foreground + #9ccfd8 + + + + name + Library class/type + scope + support.type, support.class + settings + + fontStyle + italic + foreground + #9ccfd8 + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + + + + + name + Invalid + scope + invalid + settings + + background + #eb6f92 + fontStyle + + foreground + #e0def4 + + + + name + Invalid deprecated + scope + invalid.deprecated + settings + + background + #c4a7e7 + foreground + #e0def4 + + + + uuid + c3af112c-80e3-45fe-8890-43ca225fda21 + colorSpaceName + sRGB + semanticClass + theme.dark.rosé_pine + author + oplik0 + comment + soho vibes - modified from the sublime text theme by ThatOneCalculator + + diff --git a/config/tmux/tmux.conf b/config/tmux/tmux.conf index 248d5ff5..3c671315 100644 --- a/config/tmux/tmux.conf +++ b/config/tmux/tmux.conf @@ -8,6 +8,9 @@ set-option -g status-position top set-option -sg escape-time 0 set-option -g focus-events on +set -g allow-passthrough on +set -g visual-activity off + set -g mouse on # Disable setatus bar @@ -49,8 +52,6 @@ set -g @plugin "tmux-plugins/tmux-yank" set -g @plugin "tmux-plugins/tmux-resurrect" set -g @plugin "rose-pine/tmux" -set -g allow-passthrough on - set -ga update-environment TERM set -ga update-environment TERM_PROGRAM diff --git a/config/yazi/keymap.toml b/config/yazi/keymap.toml index 5e18ac6b..04dfb064 100644 --- a/config/yazi/keymap.toml +++ b/config/yazi/keymap.toml @@ -170,7 +170,7 @@ prepend_keymap = [ {on = [ "m", "a" ], run = ''' shell 'ripdrag -atk "$@"' --confirm ''', desc = "Drag and drop all"}, {on = [ "m", "i" ], run = ''' shell 'ripdrag -tk "$@"' --confirm ''', desc = "Drag and drop individual"}, # vidir - {on = [ "B" ], run = ''' shell 'vidir "$@"' --confirm ''', desc = "Bulk rename"}, + {on = "B", run = 'vidir "$1"', desc = "Bulk rename"}, # Max Preview {on = "T", run = "plugin --sync max-preview", desc = "Maximize or restore preview"}, # Hide Preview diff --git a/config/yazi/package.toml b/config/yazi/package.toml index 912a8b7c..b0d5fe46 100644 --- a/config/yazi/package.toml +++ b/config/yazi/package.toml @@ -1,21 +1,21 @@ [plugin] deps = [ - {use = "AnirudhG07/nbpreview", rev = "2d24602"}, - {use = "Reledia/glow", rev = "388e847"}, - {use = "Reledia/hexyl", rev = "ccc0a4a"}, - {use = "Reledia/miller", rev = "40e0265"}, - {use = "Sonico98/exifaudio", rev = "855ff05"}, - {use = "dedukun/relative-motions", rev = "44c4c1c"}, - {use = "hankertrix/augment-command", rev = "fe145ac"}, - {use = "imsi32/yatline", rev = "e255f5c"}, - {use = "kirasok/torrent-preview", rev = "76970b6"}, - {use = "ndtoan96/ouch", rev = "db14883"}, - {use = "pirafrank/what-size", rev = "f08f7f2"}, - {use = "yazi-rs/plugins:chmod", rev = "d85bfd6"}, - {use = "yazi-rs/plugins:full-border", rev = "d85bfd6"}, - {use = "yazi-rs/plugins:git", rev = "d85bfd6"}, - {use = "yazi-rs/plugins:hide-preview", rev = "d85bfd6"}, - {use = "yazi-rs/plugins:max-preview", rev = "d85bfd6"}, + {use = "AnirudhG07/nbpreview", rev = "1d85745" }, + {use = "Reledia/glow", rev = "c2ed51e" }, + {use = "Reledia/hexyl", rev = "39d3d4e" }, + {use = "Reledia/miller", rev = "40e0265" }, + {use = "Sonico98/exifaudio", rev = "d794614" }, + {use = "dedukun/relative-motions", rev = "df97039" }, + {use = "hankertrix/augment-command", rev = "4d64860" }, + {use = "imsi32/yatline", rev = "1b4a9a1" }, + {use = "kirasok/torrent-preview", rev = "76970b6" }, + {use = "ndtoan96/ouch", rev = "b869886" }, + {use = "pirafrank/what-size", rev = "f08f7f2" }, + {use = "yazi-rs/plugins:chmod", rev = "ec97f88" }, + {use = "yazi-rs/plugins:full-border", rev = "ec97f88" }, + {use = "yazi-rs/plugins:git", rev = "ec97f88" }, + {use = "yazi-rs/plugins:hide-preview", rev = "ec97f88" }, + {use = "yazi-rs/plugins:max-preview", rev = "ec97f88" }, ] [flavor] diff --git a/config/yazi/plugins/augment-command.yazi/README.md b/config/yazi/plugins/augment-command.yazi/README.md index dd920baf..b1402ca2 100644 --- a/config/yazi/plugins/augment-command.yazi/README.md +++ b/config/yazi/plugins/augment-command.yazi/README.md @@ -5,7 +5,8 @@ plugin that enhances Yazi's default commands. This plugin is inspired by the [Yazi tips page](https://yazi-rs.github.io/docs/tips), the [bypass.yazi](https://github.com/Rolv-Apneseth/bypass.yazi) plugin -and the [fast-enter.yazi](https://github.com/ourongxing/fast-enter.yazi) plugin. +and the [fast-enter.yazi](https://github.com/ourongxing/fast-enter.yazi) +plugin. ## Table of Contents @@ -44,15 +45,18 @@ ya pack -u | `prompt` | `true` or `false` | `false` | Create a prompt to choose between hovered and selected items when both exist. If this option is disabled, selected items will only be operated on when the hovered item is selected, otherwise the hovered item will be the default item that is operated on. | | `default_item_group_for_prompt` | `hovered`, `selected` or `none` | `hovered` | The default item group to operate on when the prompt is submitted without any value. This only takes effect if `prompt` is set to `true`, otherwise this option doesn't do anything. `hovered` means the hovered item is operated on, `selected` means the selected items are operated on, and `none` just cancels the operation. | | `smart_enter` | `true` or `false` | `true` | Use one command to open files or enter a directory. With this option set, the `enter` and `open` commands will both call the `enter` command when a directory is hovered and call the `open` command when a regular file is hovered. | -| `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](https://yazi-rs.github.io/docs/tips#smart-paste). Setting this option to `false` will use the default `paste` behaviour. You can also enable smart pasting by passing the `--smart` flag to the paste command. | +| `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](https://yazi-rs.github.io/docs/tips#smart-paste). 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](https://yazi-rs.github.io/docs/tips#smart-tab). 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 [this tip](https://github.com/sxyazi/yazi/issues/918#issuecomment-2058157773). 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. | | `enter_archives` | `true` or `false` | `true` | Automatically extract and enter archive files. This option requires the [7z or 7zz command](https://github.com/p7zip-project/p7zip) to be present. | | `extract_retries` | An integer, like `1`, `3`, `10`, etc. | `3` | This option determines how many times the plugin will retry opening an encrypted or password-protected archive when a wrong password is given. This value plus 1 is the total number of times the plugin will try opening an encrypted or password-protected archive. | +| `extract_archives_recursively` | `true` or `false` | `true` | This option determines whether the plugin will extract all archives inside an archive file recursively. If this option is set to `false`, archive files inside an archive will not be extracted, and you will have to manually extract them yourself. | | `must_have_hovered_item` | `true` or `false` | `true` | This option stops the plugin from executing any commands when there is no hovered item. | | `skip_single_subdirectory_on_enter` | `true` or `false` | `true` | Skip directories when there is only one subdirectory and no other files when entering directories. This behaviour can be turned off by passing the `--no-skip` flag to the `enter` or `open` commands. | | `skip_single_subdirectory_on_leave` | `true` or `false` | `true` | Skip directories when there is only one subdirectory and no other files when leaving directories. This behaviour can be turned off by passing the `--no-skip` flag to the `leave` command. | | `ignore_hidden_items` | `true` or `false` | `false` | Ignore hidden items when determining whether a directory only has one subdirectory and no other items. Setting this option to `false` will mean that hidden items in a directory will stop the plugin from skipping the single subdirectory. | -| `wraparound_file_navigation` | `true` or `false` | `false` | Wrap around from the bottom to the top or from the top to the bottom when using the `arrow` or `parent-arrow` command to navigate. | -| `sort_directories_first` | `true` or `false` | `true` | This option tells the plugin if you have sorted directories first in your [`yazi.toml` file](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first), located at `~/.config/yazi/yazi.toml` on Linux and macOS or `C:\Users\USERNAME\AppData\Roaming\yazi\config\yazi.toml` on Windows, where `USERNAME` is your Windows username. If you have set [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) to `true` in your [`yazi.toml` file](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first), set this option to `true` as well. If you have set [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) to `false` instead, set this option to `false` as well. This option only affects the `parent-arrow` command with `wraparound_file_navigation` set to `true`. If the [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) setting doesn't match the plugin's `sort_directories_first` setting, i.e. Yazi's `sort_dir_first` is `true` but the plugin's `sort_directories_first` is `false`, or Yazi's `sort_dir_first` is `false` but the plugin's `sort_directories_first` is `true`, the wraparound functionality of the `parent-arrow` command will not work properly and may act erratically. The default value of `sort_directories_first` follows Yazi's [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) default value, which is `true`. | +| `wraparound_file_navigation` | `true` or `false` | `false` | Wrap around from the bottom to the top or from the top to the bottom when using the `arrow` or `parent_arrow` command to navigate. | +| `sort_directories_first` | `true` or `false` | `true` | This option tells the plugin if you have sorted directories first in your [`yazi.toml` file](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first), located at `~/.config/yazi/yazi.toml` on Linux and macOS or `C:\Users\USERNAME\AppData\Roaming\yazi\config\yazi.toml` on Windows, where `USERNAME` is your Windows username. If you have set [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) to `true` in your [`yazi.toml` file](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first), set this option to `true` as well. If you have set [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) to `false` instead, set this option to `false` as well. This option only affects the `parent_arrow` command with `wraparound_file_navigation` set to `true`. If the [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) setting doesn't match the plugin's `sort_directories_first` setting, i.e. Yazi's `sort_dir_first` is `true` but the plugin's `sort_directories_first` is `false`, or Yazi's `sort_dir_first` is `false` but the plugin's `sort_directories_first` is `true`, the wraparound functionality of the `parent_arrow` command will not work properly and may act erratically. The default value of `sort_directories_first` follows Yazi's [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) default value, which is `true`. | 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` @@ -70,8 +74,11 @@ require("augment-command"):setup({ default_item_group_for_prompt = "hovered", smart_enter = true, smart_paste = false, + smart_tab_create = false, + smart_tab_switch = false, enter_archives = true, extract_retries = 3, + extract_archives_recursively = true, must_have_hovered_item = true, skip_single_subdirectory_on_enter = true, skip_single_subdirectory_on_leave = true, @@ -83,9 +90,11 @@ 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` +on Linux and macOS, or your +`C:\Users\USERNAME\AppData\Roaming\yazi\config\init.lua` file on Windows, where `USERNAME` is your Windows username. -You can leave out configuration options that you would like to be left as default. +You can leave out configuration options that you would +like to be left as default. An example configuration is shown below: ```lua @@ -135,17 +144,16 @@ then it will operate on the selected items. - Automatically extracts and enters archive files, with support for skipping directories that contain only one subdirectory in the extracted archive. - This can be disabled by setting `enter_archives` to `false` in the configuration. + This can be disabled by setting `enter_archives` to `false` + in the configuration. This feature requires the [`7z` or `7zz` command](https://github.com/p7zip-project/p7zip) to be present to extract the archives. -- If the archive file contains only a single file, - the command will automatically extract it to the - current directory instead of creating a folder - for the contents of the archive. - If this extracted file is also an archive file, - the command will automatically - extract its contents before deleting it. +- If the extracted archive file contains other archive + files in it, those archives will be automatically + extracted, keeping the directory structure + of the archive if the archive doesn't + only contain a single archive file. This feature requires the [`file` command](https://www.darwinsys.com/file/) to detect the mime type of the extracted file, @@ -154,6 +162,9 @@ then it will operate on the selected items. compressed tarballs much easier, as there's no need to press a key twice to decompress and extract the compressed tarballs. + You can disable this feature by setting + `extract_archives_recursively` to `false` + in the configuration. ### Enter (`enter`) @@ -192,23 +203,6 @@ then it will operate on the selected items. - The `remove` command is augmented as stated in [this section above](#what-about-the-commands-are-augmented). -### Paste (`paste`) - -- When `smart_paste` is set to `true`, - the `paste` command will paste items - into a hovered directory without entering it. - If the hovered item is not a directory, - the command pastes in the current directory instead. - Otherwise, when `smart_paste` is set to `false`, - the `paste` command will behave like the default - `paste` command. -- `--smart` flag to enable pasting in a hovered directory - without entering the directory. - This flag will cause the `paste` command to paste items - into a hovered directory even when `smart_paste` is set to `false`. - This allows you to set a key to use smart paste - instead of using smart paste for every paste command. - ### Shell (`shell`) - This command runs the shell command given with the augment stated in @@ -257,7 +251,7 @@ then it will operate on the selected items. desc = "Open the pager" ``` -- `--exit-if-directory` flag to stop the shell command given +- `--exit-if-dir` flag to stop the shell command given from executing if the item group consists only of directories. For example, if the item group is the hovered item, then the shell command will not be executed if the hovered item @@ -273,10 +267,84 @@ then it will operate on the selected items. [[manager.prepend_keymap]] on = [ "i" ] - run = '''plugin augment-command --args="shell '$PAGER $@' --block --confirm --exit-if-directory"''' + run = '''plugin augment-command --args="shell '$PAGER $@' --block --confirm --exit-if-dir"''' desc = "Open the pager" ``` +### Paste (`paste`) + +- When `smart_paste` is set to `true`, + the `paste` command will paste items + into the hovered directory without entering it. + If the hovered item is not a directory, + the command pastes in the current directory instead. + Otherwise, when `smart_paste` is set to `false`, + the `paste` command will behave like the default + `paste` command. +- `--smart` flag to enable pasting in the hovered directory + without entering the directory. + This flag will cause the `paste` command to paste items + into the hovered directory even when `smart_paste` is set to `false`. + This allows you to set a key to use this behaviour + with the `paste` command instead of using it for + every `paste` command. + +### Tab create (`tab_create`) + +- When `smart_tab_create` is set to `true`, + the `tab_create` command will create a tab + in the hovered directory instead of the + current directory like the default key binds. + If the hovered item is not a directory, + then the command just creates a new tab in + the current directory instead. + Otherwise, when `smart_tab_create` is set to + `false`, the `tab_create` command will behave + like the default key bind to create a tab, + which is `tab_create --current`. +- `--smart` flag to enable creating a tab + in the hovered directory. + This flag will cause the `tab_create` command + to create a tab in the hovered directory even + when `smart_tab_create` is set to `false`. + This allows you to set a specific key to use this + behaviour with the `tab_create` command instead + of using it for every `tab_create` command. + +### Tab switch (`tab_switch`) + +- When `smart_tab_switch` is set to `true`, + the `tab_switch` command will ensure that + the tab that is being switched to exist. + It does this by automatically creating + all the tabs required for the desired + tab to exist. + For example, if you are switching to + tab 5 (`tab_switch 4`), and you only have + two tabs currently open (tabs 1 and 2), + the plugin will create tabs 3, 4 and 5 + and then switch to tab 5. + The tabs are created using the current + directory. The `smart_tab_create` + configuration option does not affect + the behaviour of this command. + Otherwise, when `smart_tab_switch` is + set to `false`, the `tab_switch` command + will behave like the default `tab_switch` + command, and simply switch to the tab + if it exists, and do nothing if it doesn't + exist. +- `--smart` flag to automatically create + the required tabs for the desired tab + to exist. + This flag will cause the `tab_switch` + command to automatically create the + required tabs even when `smart_tab_switch` + is set to `false`. + This allows you to set a specific key to use this + behaviour with the `tab_switch` command instead + of using it for every `tab_switch` command. + ### Arrow (`arrow`) - When `wraparound_file_navigation` is set to `true`, @@ -286,7 +354,7 @@ then it will operate on the selected items. ## New commands -### Parent-arrow (`parent-arrow`) +### Parent arrow (`parent_arrow`) - This command behaves like the `arrow` command, but in the parent directory. @@ -304,8 +372,8 @@ then it will operate on the selected items. i.e. if you have set the [`sort_dir_first`](https://yazi-rs.github.io/docs/configuration/yazi#manager.sort_dir_first) to `true` in your `~/.config/yazi/yazi.toml` file on Linux and macOS, - or your `C:\Users\USERNAME\AppData\Roaming\yazi\config\yazi.toml` on Windows, - like so: + or your `C:\Users\USERNAME\AppData\Roaming\yazi\config\yazi.toml` + on Windows, like so: ```toml # ~/.config/yazi/yazi.toml on Linux and macOS @@ -385,13 +453,15 @@ then it will operate on the selected items. ### Editor (`editor`) -- The `editor` command opens the default editor set by the `$EDITOR` environment variable. +- The `editor` command opens the default editor set by the + `$EDITOR` environment variable. - The command is also augmented as stated in [this section above](#what-about-the-commands-are-augmented). ### Pager (`pager`) -- The `pager` command opens the default pager set by the `$PAGER` environment variable. +- The `pager` command opens the default pager set by the + `$PAGER` environment variable. - The command is also augmented as stated in [this section above](#what-about-the-commands-are-augmented). - The `pager` command will also skip opening directories, as the pager @@ -400,7 +470,7 @@ then it will operate on the selected items. is a directory, or if **all** the selected items are directories. This makes the pager command less annoying as it will not try to open a directory and then immediately fail with an error, - causing a flash and Yazi to send a notification. + causing a flash and causing Yazi to send a notification. ## Usage @@ -431,7 +501,8 @@ run = "plugin augment-command --args='enter'" desc = "Enter a directory and skip directories with only a single subdirectory" ``` -All the default arguments, flags and options provided by Yazi are also supported, for example: +All the default arguments, flags and options provided by Yazi +are also supported, for example: ```toml # ~/.config/yazi/keymap.toml on Linux and macOS @@ -470,7 +541,7 @@ For a full configuration example, you can take a look at [my `keymap.toml` file](https://github.com/hankertrix/Dotfiles/blob/master/.config/yazi/keymap.toml). -## Licence +## [Licence](LICENSE) -This plugin is licenced under the GNU AGPL v3 licence. -You can view the full licence in the `LICENSE` file. +This plugin is licenced under the [GNU AGPL v3 licence](LICENSE). +You can view the full licence in the [`LICENSE`](LICENSE) file. diff --git a/config/yazi/plugins/augment-command.yazi/init.lua b/config/yazi/plugins/augment-command.yazi/init.lua index b4e41629..87961029 100644 --- a/config/yazi/plugins/augment-command.yazi/init.lua +++ b/config/yazi/plugins/augment-command.yazi/init.lua @@ -1,14 +1,27 @@ -- Plugin to make some Yazi commands smarter -- Written in Lua 5.4 +-- Type aliases + -- The type for the arguments ---@alias Arguments table +-- The type for the extractor command +---@alias ExtractorFunction fun( +--- password: string|nil, +--- configuration: Configuration): CommandOutput|nil, integer + +-- Custom types + +-- The type for the state +---@class (exact) State +---@field config Configuration + -- The type for the Command output ---@class (exact) CommandOutput ---@field stdout string ---@field stderr string ----@field status table { success: boolean, code: number } +---@field status { success: boolean, code: number } --- The type for the Url object ---@class (exact) Url @@ -18,13 +31,20 @@ ---@field is_archive boolean ---@field is_absolute boolean ---@field has_root boolean ----@field name function(): string|nil ----@field stem function(): string|nil ----@field join function(url: Url|string): Url ----@field parent function(): Url|nil ----@field starts_with function(url: Url|string): boolean ----@field ends_with function(url: Url|string): boolean ----@field strip_prefix function(url: Url|string): boolean +---@field name fun(): string|nil +---@field stem fun(): string|nil +---@field join fun(url: Url|string): Url +---@field parent fun(): Url|nil +---@field starts_with fun(url: Url|string): boolean +---@field ends_with fun(url: Url|string): boolean +---@field strip_prefix fun(url: Url|string): boolean + +-- The type for the extraction results +---@class (exact) ExtractionResult +---@field archive_path string +---@field successful boolean +---@field extracted_items_path string|nil +---@field error_message string|nil -- The enum for which group of items to operate on ---@enum ItemGroup @@ -43,10 +63,12 @@ local Commands = { Leave = "leave", Rename = "rename", Remove = "remove", - Paste = "paste", Shell = "shell", + Paste = "paste", + TabCreate = "tab_create", + TabSwitch = "tab_switch", Arrow = "arrow", - ParentArrow = "parent-arrow", + ParentArrow = "parent_arrow", Editor = "editor", Pager = "pager", } @@ -67,8 +89,11 @@ local ExtractBehaviour = { ---@field default_item_group_for_prompt ItemGroup ---@field smart_enter boolean ---@field smart_paste boolean +---@field smart_tab_create boolean +---@field smart_tab_switch boolean ---@field enter_archives boolean ---@field extract_retries number +---@field extract_archives_recursively boolean ---@field must_have_hovered_item boolean ---@field skip_single_subdirectory_on_enter boolean ---@field skip_single_subdirectory_on_leave boolean @@ -81,8 +106,11 @@ local DEFAULT_CONFIG = { default_item_group_for_prompt = ItemGroup.Hovered, smart_enter = true, smart_paste = false, + smart_tab_create = false, + smart_tab_switch = false, enter_archives = true, extract_retries = 3, + extract_archives_recursively = true, must_have_hovered_item = true, skip_single_subdirectory_on_enter = true, skip_single_subdirectory_on_leave = true, @@ -127,22 +155,60 @@ local ARCHIVE_MIME_TYPES = { "application/bzip", "application/bzip2", "application/7z-compressed", + "application/rar-compressed", "application/rar", "application/xz", + + -- Bug in file(1) that classifies + -- some zip archives as a data stream, + -- hopefully this can be removed in the future. + -- + -- Link to bug report: + -- https://bugs.astron.com/view.php?id=571 + "application/octet-stream", +} + +-- The list of archive file extensions +---@type string[] +local ARCHIVE_FILE_EXTENSIONS = { + "zip", + "tar", + "boz", + "bz", + "bz2", + "7z", + "rar", + "xz", +} + +-- The list of mime type prefixes to remove +-- +-- The prefixes are used in a lua pattern +-- to match on the mime type, so special +-- characters need to be escaped +---@type string[] +local MIME_TYPE_PREFIXES_TO_REMOVE = { + "x%-", + "vnd%.", } -- The pattern to get the double dash from the front of the argument ---@type string local double_dash_pattern = "^%-%-" --- The pattern to get the mime type without the "x-" prefix +-- The pattern template to get the mime type without a prefix ---@type string -local get_mime_type_without_x_prefix_pattern = "^(%a-)/x%-([%-%d%a]-)$" +local get_mime_type_without_prefix_template_pattern = + "^(%%a-)/%s([%%-%%d%%a]-)$" -- 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 file extension +---@type string +local file_extension_pattern = "%.([%a]+)$" + -- The pattern to get the shell variables in a command ---@type string local shell_variable_pattern = "[%$%%][%*@0]" @@ -161,8 +227,8 @@ local bat_command_with_pager_pattern = "%f[%a]bat%f[%A].*%-%-pager%s+" -- with the items in the first table being added first, -- and the items in the second table being added second, -- and so on. ----@param ... table[] ----@return table +---@param ... table[] The tables to merge +---@return table merged_table The merged table local function merge_tables(...) -- @@ -207,9 +273,9 @@ local function merge_tables(...) end -- Function to check if a list contains a given value ----@param list any[] ----@param value any ----@return boolean +---@param list any[] The list to check +---@param value any The value to check for +---@return boolean value_is_in_list Whether the value is in the list local function list_contains(list, value) -- @@ -227,9 +293,9 @@ local function list_contains(list, value) end -- Function to split a string into a list ----@param given_string string ----@param separator string ----@return string[] +---@param given_string string The string to split +---@param separator string 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) -- @@ -252,8 +318,8 @@ local function string_split(given_string, separator) end -- The function to trim a string ----@param string string ----@return string +---@param string string The string to trim +---@return string trimmed_string The trimmed string local function string_trim(string) -- @@ -264,8 +330,8 @@ end -- Function to parse the arguments given. -- This function takes the arguments passed to the entry function ----@param args string[] ----@return Arguments +---@param args string[] The list of string arguments given by Yazi +---@return Arguments parsed_args The list of arguments with the correct types local function parse_args(args) -- @@ -404,27 +470,26 @@ local function merge_configuration(config) end -- Function to initialise the configuration ----@param state any ----@param user_config Configuration|nil ----@param additional_data any ----@return Configuration +---@param state State The state object +---@param user_config Configuration|nil The configuration object +---@param additional_data table Additional data +---@return Configuration config The initialised configuration object local initialise_config = ya.sync(function(state, user_config, additional_data) -- -- 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_tables( - merge_configuration(user_config), additional_data - ) + state.config = + merge_tables(merge_configuration(user_config), additional_data) -- Return the configuration object for async functions return state.config end) -- The function to try if a shell command exists ----@param shell_command string ----@return boolean +---@param shell_command string The shell command to check +---@return boolean Whether the shell command exists local function shell_command_exists(shell_command) -- @@ -471,8 +536,8 @@ local function shell_command_exists(shell_command) end -- The function to initialise the plugin ----@param opts Configuration|nil ----@return Configuration +---@param opts Configuration|nil The options given to the plugin +---@return Configuration config The initialised configuration object local function initialise_plugin(opts) -- @@ -496,6 +561,38 @@ local function initialise_plugin(opts) return config end +-- Function to standardise the mime type of a file. +-- This function will follow what Yazi does to standardise +-- mime types returned by the file command. +---@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) + + -- 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) + + -- 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 + + -- 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 @@ -505,22 +602,42 @@ local function is_archive_mime_type(mime_type) -- If the mime type is nil, return false if not mime_type then return false end - -- Trim the whitespace from the mime type - mime_type = string_trim(mime_type) - - -- Remove the "x-" prefix from the mime type - mime_type = mime_type:gsub(get_mime_type_without_x_prefix_pattern, "%1/%2") + -- Standardise the mime type + local standardised_mime_type = standardise_mime_type(mime_type) -- Get if the mime type is an archive - local is_archive = list_contains(ARCHIVE_MIME_TYPES, mime_type) + local is_archive = list_contains(ARCHIVE_MIME_TYPES, standardised_mime_type) -- Return if the mime type is an archive return is_archive end +-- Function to check if a given file extension +-- is an archive file extension +---@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 + + -- Make the file extension lower case + file_extension = file_extension:lower() + + -- Trim the whitespace from the file extension + file_extension = string_trim(file_extension) + + -- Get if the file extension is an archive + local is_archive = list_contains(ARCHIVE_FILE_EXTENSIONS, file_extension) + + -- Return if the file extension is an archive file extension + return is_archive +end + -- Function to get the configuration from an async function ----@param state any ----@return Configuration +---@param state State The state object +---@return Configuration config The configuration object local get_config = ya.sync(function(state) -- @@ -530,15 +647,15 @@ end) -- Function to get the current working directory ---@param _ any ----@return string -local get_current_directory = ya.sync(function(_) - return tostring(cx.active.current.cwd) -end) +---@return string current_working_directory The current working directory +local get_current_directory = ya.sync( + function(_) return tostring(cx.active.current.cwd) end +) -- Function to get the path of the hovered item ---@param _ any ----@param quote boolean ----@return string|nil +---@param quote boolean Whether to shell escape the characters in the path +---@return string|nil hovered_item_path The path of the hovered item local get_path_of_hovered_item = ya.sync(function(_, quote) -- @@ -561,7 +678,7 @@ end) -- Function to get if the hovered item is a directory ---@param _ any ----@return boolean +---@return boolean is_directory Whether the hovered item is a directory local hovered_item_is_dir = ya.sync(function(_) -- @@ -574,7 +691,7 @@ end) -- Function to get if the hovered item is an archive ---@param _ any ----@return boolean +---@return boolean is_archive Whether the hovered item is an archive local hovered_item_is_archive = ya.sync(function(_) -- @@ -587,8 +704,8 @@ end) -- Function to get the paths of the selected items ---@param _ any ----@param quote boolean ----@return string[]|nil +---@param quote boolean Whether to shell escape the characters in the path +---@return string[]|nil paths The list of paths of the selected items local get_paths_of_selected_items = ya.sync(function(_, quote) -- @@ -625,8 +742,8 @@ end) -- ItemGroup.Selected for the selected items, -- and ItemGroup.Prompt to tell the calling function -- to prompt the user. ----@param state any ----@return ItemGroup|nil +---@param state State The state object +---@return ItemGroup|nil item_group The desired item group local get_item_group_from_state = ya.sync(function(state) -- @@ -677,7 +794,7 @@ local get_item_group_from_state = ya.sync(function(state) end) -- Function to prompt the user for their desired item group ----@return ItemGroup|nil +---@return ItemGroup|nil item_group The item group selected by the user local function prompt_for_desired_item_group() -- @@ -722,7 +839,7 @@ local function prompt_for_desired_item_group() end -- Function to get the item group ----@return ItemGroup|nil +---@return ItemGroup|nil item_group The desired item group local function get_item_group() -- @@ -741,10 +858,10 @@ local function get_item_group() end -- The function to get all the items in the given directory ----@param directory string ----@param ignore_hidden_items boolean ----@param directories_only boolean|nil ----@return string[] +---@param directory string The path to the directory +---@param ignore_hidden_items boolean Whether to ignore hidden items +---@param directories_only boolean|nil Whether to only get directories +---@return string[] directory_items The list of paths to the directory items local function get_directory_items( directory, ignore_hidden_items, @@ -788,9 +905,9 @@ local function get_directory_items( end -- Function to skip child directories with only one directory ----@param args Arguments ----@param config Configuration ----@param initial_directory string +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@param initial_directory string The path of the initial directory ---@return nil local function skip_single_child_directories(args, config, initial_directory) -- @@ -837,8 +954,8 @@ local function skip_single_child_directories(args, config, initial_directory) end -- The function to check if an archive is password protected ----@param command_error_string string ----@return boolean +---@param command_error_string string The error string from the extractor +---@return boolean is_encrypted Whether the archive is password protected local function archive_is_encrypted(command_error_string) -- @@ -853,16 +970,10 @@ end -- The function to handle retrying the extractor command -- --- The extractor command is a function that takes --- two arguments, first being the password to the archive, --- and the second being the configuration object. --- It returns the output and the err --- from the Command:output() function. --- -- The initial password is the password given to the extractor command -- and the test encryption is to test the archive password without -- actually executing the given extractor command. ----@param extractor_command function A function that extracts the archive +---@param extractor_function ExtractorFunction The function to run the extractor ---@param config Configuration The configuration object ---@param initial_password string|nil The initial password to try ---@param archive_path string|nil The path to the archive file @@ -871,7 +982,7 @@ end ---@return string|nil stdout The standard output of the extractor command ---@return string|nil correct_password The correct password to the archive local function retry_extractor( - extractor_command, + extractor_function, config, initial_password, archive_path @@ -893,12 +1004,20 @@ local function retry_extractor( -- to the number of retries plus 1 local total_number_of_tries = config.extract_retries + 1 + -- Initialise the initial password prompt + local initial_password_prompt = + "Archive is encrypted, please enter the password:" + + -- Initialise the wrong password prompt + local wrong_password_prompt = + "Wrong password, please enter another password:" + -- Iterate over the number of times to try the extraction for tries = 0, total_number_of_tries do -- -- Execute the extractor command - local output, err = extractor_command(password, config) + local output, err = extractor_function(password, config) -- If there is no output -- then return false, the error code as a string, @@ -947,20 +1066,10 @@ local function retry_extractor( return false, error_message, output.stdout, nil end - -- Initialise the prompt for the password - local password_prompt = "Wrong password, please enter another password:" - - -- If this is the first time opening the archive, - -- which means the number of tries is 0, - -- then ask the user for the password - -- instead of giving the wrong password message. - if tries == 0 then - password_prompt = "Archive is encrypted, please enter the password:" - end - -- Ask the user for the password local user_input, event = ya.input(merge_tables(DEFAULT_INPUT_OPTIONS, { - title = password_prompt, + title = tries == 0 and initial_password_prompt + or wrong_password_prompt, })) -- If the user has confirmed the input, @@ -985,12 +1094,12 @@ local function retry_extractor( end -- The command to list the items in an archive ----@param archive_path string ----@param config Configuration ----@param password string|nil ----@param remove_headers boolean|nil ----@param show_details boolean|nil ----@return CommandOutput, integer +---@param archive_path string The path to the archive +---@param config Configuration The configuration object +---@param password string|nil The password to the archive +---@param remove_headers boolean|nil Whether to remove the headers +---@param show_details boolean|nil Whether to show the details +---@return CommandOutput|nil, integer local function list_archive_items_command( archive_path, config, @@ -1050,10 +1159,11 @@ end -- file has more than one file in it. ---@param archive_path string The path to the archive file ---@param config Configuration The configuration object ----@return boolean|nil has_one_file Whether the archive file has one file in it +---@return table files The list of files in the archive +---@return table directories The list of directories in the archive ---@return string|nil error_message The error message for an incorrect password ---@return string|nil correct_password The correct password to the archive -local function archive_only_has_one_file(archive_path, config) +local function get_archive_items(archive_path, config) -- -- The function to list the items in the archive @@ -1083,7 +1193,9 @@ local function archive_only_has_one_file(archive_path, config) -- or the output was nil, -- then return nil the error message, -- and nil as the correct password - if not successful or not output then return nil, error_message, nil end + if not successful or not output then + return files, directories, error_message, nil + end -- Otherwise, split the output at the newline character local output_lines = string_split(output, "\n") @@ -1118,52 +1230,38 @@ local function archive_only_has_one_file(archive_path, config) -- The continue label to continue the loop ::continue:: - - -- If there is more than 1 file in the archive - -- then break out of the loop - if #files > 1 then break end end - -- If there are no files in the archive, - -- return nil, an error saying that there's - -- no files in the archive, and the password - if #files == 0 then return nil, "No files in the archive!", password end - - -- If there is only one file in the archive and no directories, - -- then return true, the error message, and the password - if #files == 1 and #directories == 0 then - return true, error_message, password - end - - -- Otherwise, return false, the error message and the password - return false, error_message, password + -- Return the list of files, the list of directories, + -- the error message, and the password + return files, directories, error_message, password end -- Function to get a temporary name. -- The code is taken from Yazi's source code. ----@param file_path string ----@return string -local function get_temporary_name(file_path) +---@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.md5(string.format("extract//%s//%.10f", file_path, ya.time())) + .. ya.md5(string.format("extract//%s//%.10f", path, ya.time())) end -- Function to get a temporary directory url -- for the given file path ----@param file_path string ----@return Url|nil -local function get_temporary_directory_url(file_path) +---@param path string The path to the item to create a temporary directory +---@return Url|nil url The url of the temporary directory +local function get_temporary_directory_url(path) -- -- Get the parent directory of the file path - local parent_directory = Url(file_path):parent() + local parent_directory = Url(path):parent() -- If the parent directory doesn't exist, then return nil if not parent_directory then return nil end -- Otherwise, create the temporary directory path local temporary_directory_url = - fs.unique_name(parent_directory:join(get_temporary_name(file_path))) + fs.unique_name(parent_directory:join(get_temporary_name(path))) -- Return the temporary directory path return temporary_directory_url @@ -1176,7 +1274,7 @@ end ---@param password string|nil The password to the archive ---@param extract_files_only boolean|nil Extract the files only or not ---@param extract_behaviour ExtractBehaviour|nil The extraction behaviour ----@return CommandOutput, integer +---@return CommandOutput|nil, integer local function extract_command( archive_path, destination_directory_path, @@ -1243,8 +1341,8 @@ local function extract_command( end -- The function to get the mime type of a file ----@param file_path string ----@return string +---@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) -- @@ -1276,8 +1374,8 @@ local function get_mime_type(file_path) end -- The function to check if a file is an archive ----@param file_path string ----@return boolean +---@param file_path string The path to the file +---@return boolean is_archive Whether the file is an archive local function is_archive_file(file_path) -- @@ -1296,10 +1394,10 @@ end -- The function to clean up the temporary directory -- after extracting an archive. ----@param temporary_directory_url Url ----@param removal_mode "dir" | "dir_all" | "dir_clean" ----@param ... any ----@return ... any +---@param temporary_directory_url Url The url of the temporary directory +---@param removal_mode "dir" | "dir_all" | "dir_clean" The removal mode +---@param ... any Return values +---@return ... Returns the given return values local function clean_up_temporary_directory( temporary_directory_url, removal_mode, @@ -1315,9 +1413,9 @@ local function clean_up_temporary_directory( end -- The function to move extracted items out of the temporary directory ----@param archive_url Url ----@param temporary_directory_url Url ----@return boolean move_successful A boolean if the move was successful +---@param archive_url Url The url of the archive +---@param temporary_directory_url Url The url of the temporary directory +---@return boolean move_successful Whether the move was successful ---@return string|nil error_message An error message for unsuccessful extracts ---@return string|nil extracted_items_path The path of the extracted item local function move_extracted_items_to_archive_parent_directory( @@ -1422,7 +1520,7 @@ local function move_extracted_items_to_archive_parent_directory( temporary_directory_url, "dir_all", move_successful, - "Failed to get a unique name for to move the extracted items to", + "Failed to get a unique name to move the extracted items to", extracted_items_path ) end @@ -1463,47 +1561,28 @@ local function move_extracted_items_to_archive_parent_directory( end --- The function to extract an archive. ---- This function returns 2 values: ---- 1. A boolean to indicate if the extraction of the archive was successful ---- 2. An error message if the extraction was unsuccessful ---- 3. The file path indicating the directory to change to, which can be nil ----@param archive_path string ----@param config Configuration ----@return boolean successful A boolean indicating extraction success ----@return string|nil error_message An error message if extraction failed ----@return string|nil extracted_items_path The path of the extracted items -local function extract_archive(archive_path, config) +---@param archive_path string The path to the archive +---@param config Configuration The configuration object +---@param has_only_one_file boolean Whether the archive has only one file +---@param initial_password string|nil The initial password to try +---@return ExtractionResult extraction_result The result of the extraction +local function extract_archive( + archive_path, + config, + has_only_one_file, + initial_password +) -- - -- Initialise the extract files only flag to false - local extract_files_only = false - -- Initialise the successful variable to false local successful = false -- Initialise the error message to nil local error_message = nil - -- Get the list of archive items, the error message and the password - local has_only_one_file, archive_error, correct_password = - archive_only_has_one_file(archive_path, config) - -- Initialise the extracted items path to nil local extracted_items_path = nil - -- If there are no files in the archive, - -- then return the successful variable, - -- the error message, and the extracted items path - if has_only_one_file == nil then - return successful, archive_error, extracted_items_path - end - - -- Otherwise, the archive only has one file, - -- then set the files only flag to true - if has_only_one_file then - extract_files_only = true - end - -- Get the url of the temporary directory local temporary_directory_url = get_temporary_directory_url(archive_path) @@ -1512,9 +1591,13 @@ local function extract_archive(archive_path, config) -- saying a path for the temporary directory -- cannot be determined, and the extracted items path if not temporary_directory_url then - return successful, - "Failed to determine a path for the temporary directory", - extracted_items_path + return { + archive_path = archive_path, + successful = successful, + extracted_items_path = extracted_items_path, + error_message = "Failed to determine a path " + .. "for the temporary directory", + } end -- Get the url of the archive @@ -1529,7 +1612,12 @@ local function extract_archive(archive_path, config) -- that the archive file name is somehow empty, -- and the extracted items path if not archive_name then - return successful, "Archive file name is empty", extracted_items_path + return { + archive_path = archive_path, + successful = successful, + extracted_items_path = extracted_items_path, + error_message = "Archive file name is empty", + } end -- Create the extractor command @@ -1539,7 +1627,7 @@ local function extract_archive(archive_path, config) tostring(temporary_directory_url), configuration, password, - extract_files_only, + has_only_one_file, ExtractBehaviour.Overwrite ) end @@ -1548,15 +1636,24 @@ local function extract_archive(archive_path, config) successful, error_message, _, _ = retry_extractor( extractor_command, config, - correct_password, + initial_password, archive_path ) -- If the extraction was not successful, - -- then return whether the extraction was successful, - -- the error message and the extracted items path if not successful then - return successful, error_message, extracted_items_path + -- + + -- Clean up the temporary directory + clean_up_temporary_directory(temporary_directory_url, "dir_all") + + -- Return the extraction results + return { + archive_path = archive_path, + successful = successful, + extracted_items_path = extracted_items_path, + error_message = error_message, + } end -- Otherwise, move the extracted items @@ -1567,45 +1664,154 @@ local function extract_archive(archive_path, config) temporary_directory_url ) - -- If the extract files only flag is false, - -- then return whether the extraction was successful, - -- the error message and the extracted items path - if not extract_files_only or not extracted_items_path then - return successful, error_message, extracted_items_path - end - - -- If the item is not an archive - -- then return whether the extraction was successful, - -- the error message and the extract directory - if not is_archive_file(extracted_items_path) then - return successful, error_message, extracted_items_path - end - - -- Save the extracted archive path - local extracted_archive_path = extracted_items_path - - -- Extract the archive item - successful, error_message, extracted_items_path = - extract_archive(extracted_archive_path, config) - - -- If the extraction was not successful, - -- then return whether the extraction was successful, - -- the error message and the extracted items path - if not successful then - return successful, error_message, extracted_items_path - end - - -- Remove the archive after extracting it successfully - fs.remove("file", Url(extracted_archive_path)) + -- Create the extraction result + ---@type ExtractionResult + local extraction_result = { + archive_path = archive_path, + successful = successful, + extracted_items_path = extracted_items_path, + error_message = error_message, + } -- Return the result of the extraction - return successful, error_message, extracted_items_path + return extraction_result +end + +-- The function to recursively extract archives +---@param archive_path string The path to the archive +---@param config Configuration The configuration object +---@return ExtractionResult[] extraction_results The list of extraction results +---@return string|nil extracted_items_path The path to the extracted items +local function recursively_extract_archives(archive_path, config) + -- + + -- Initialise the table of extraction results + ---@type ExtractionResult[] + local list_of_extraction_results = {} + + -- Get the list of archive files and directories, + -- the error message and the password + local archive_files, archive_directories, err, password = + get_archive_items(archive_path, config) + + -- If there are no are no archive files and directories + if #archive_files == 0 and #archive_directories == 0 then + -- + + -- Add that the archive is empty if there is no error message + table.insert(list_of_extraction_results, { + archive_path = archive_path, + successful = false, + error_message = err or "Archive is empty", + }) + + -- Return the list of extraction results + return list_of_extraction_results + end + + -- 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_results = extract_archive( + archive_path, + config, + archive_has_only_one_file, + password + ) + + -- Add the extraction results to the list of extraction results + table.insert(list_of_extraction_results, extraction_results) + + -- Get the extracted items path + local extracted_items_path = extraction_results.extracted_items_path + + -- If the extraction of the archive isn't successful, + -- or if the extracted items path is nil, + -- or if the user does not want to extract archives recursively, + -- return the list of extraction results + if + not extraction_results.successful + or not extracted_items_path + or not config.extract_archives_recursively + then + return list_of_extraction_results, extracted_items_path + end + + -- Get the url of the extracted items path + local extracted_items_url = Url(extracted_items_path) + + -- 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() + + -- If the parent directory doesn't exist, + -- then return the list of extraction results + if not parent_directory_url then return list_of_extraction_results end + + -- 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 + + -- 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) + + -- 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 + + -- 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) + + -- If the file is not an archive, skip the file + if not is_archive_file(full_archive_path) then goto continue end + + -- Otherwise, recursively extract the archive + local archive_extraction_results, extracted_archive_path = + recursively_extract_archives(full_archive_path, config) + + -- Merge the results with the existing list of extraction results + list_of_extraction_results = + merge_tables(list_of_extraction_results, archive_extraction_results) + + -- If the archive has only one file, + -- update the extracted items path + -- to the extracted archive path + if archive_has_only_one_file then + extracted_items_path = extracted_archive_path + end + + -- Remove the archive file after extracting it + fs.remove("file", full_archive_url) + + -- The label the continue the loop + ::continue:: + end + + -- Return the list of extraction results and the extracted items path + return list_of_extraction_results, extracted_items_path end -- Function to handle the open command ----@param args Arguments ----@param config Configuration ----@param command_table CommandTable +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@param command_table CommandTable The command table ---@return nil local function handle_open(args, config, command_table) -- @@ -1638,11 +1844,10 @@ local function handle_open(args, config, command_table) -- and exit the function if config.smart_enter then return enter_command(args, config, command_table) + end -- Otherwise, just exit the function - else - return - end + return end -- Otherwise, if the hovered item is not an archive, @@ -1671,19 +1876,23 @@ local function handle_open(args, config, command_table) if not archive_path then return end -- Run the function to extract the archive - local extract_successful, err, extracted_items_path = - extract_archive(archive_path, config) + local extraction_results, extracted_items_path = + recursively_extract_archives(archive_path, config) - -- If the extraction of the archive isn't successful, - -- notify the user and exit the function - if not extract_successful then - return ya.notify(merge_tables(DEFAULT_NOTIFICATION_OPTIONS, { - content = "Failed to extract archive at: " - .. archive_path - .. "\nError: " - .. err, - level = "error", - })) + -- Iterate over the extraction results + for _, extraction_result in ipairs(extraction_results) do + -- + + -- If the extraction is not successful, notify the user + if not extraction_result.successful then + ya.notify(merge_tables(DEFAULT_NOTIFICATION_OPTIONS, { + content = "Failed to extract archive at: " + .. extraction_result.archive_path + .. "\nError: " + .. extraction_result.error_message, + level = "error", + })) + end end -- If the extracted items path is nil, @@ -1710,9 +1919,9 @@ local function handle_open(args, config, command_table) end -- Function to handle the enter command ----@param args Arguments ----@param config Configuration ----@param command_table CommandTable +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@param command_table CommandTable The command table ---@return nil local function handle_enter(args, config, command_table) -- @@ -1729,11 +1938,10 @@ local function handle_enter(args, config, command_table) -- and exit the function if config.smart_enter then return open_command(args, config, command_table) + end -- Otherwise, just exit the function - else - return - end + return end -- Otherwise, always emit the enter command, @@ -1745,8 +1953,8 @@ local function handle_enter(args, config, command_table) end -- Function to handle the leave command ----@param args Arguments ----@param config Configuration +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object ---@return nil local function handle_leave(args, config) -- @@ -1793,7 +2001,7 @@ end -- Function to handle a Yazi command ---@param command string A Yazi command ----@param args Arguments +---@param args Arguments The arguments passed to the plugin ---@return nil local function handle_yazi_command(command, args) -- @@ -1817,43 +2025,11 @@ local function handle_yazi_command(command, args) -- Emit the command with the hovered option ya.manager_emit(command, merge_tables(args, { hovered = true })) - - -- Otherwise, exit the function - else - return end end --- Function to handle the paste command ----@param args Arguments ----@param config Configuration ----@return nil -local function handle_paste(args, config) - -- - - -- If the hovered item is a directory and smart paste is wanted - if hovered_item_is_dir() and (config.smart_paste or args.smart) then - -- - - -- Enter the directory - ya.manager_emit("enter", {}) - - -- Paste the items inside the directory - ya.manager_emit("paste", args) - - -- Leave the directory - ya.manager_emit("leave", {}) - - -- Exit the function - return - end - - -- Otherwise, just paste the items inside the current directory - ya.manager_emit("paste", args) -end - -- Function to remove the F flag from the less command ----@param command string +---@param command string The shell command containing the less command ---@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) @@ -1889,7 +2065,7 @@ end -- Function to fix a command containing less. -- All this function does is remove -- the F flag from a command containing less. ----@param command string +---@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) -- @@ -1927,7 +2103,7 @@ local function fix_shell_command_containing_less(command) end -- Function to fix the bat default pager command ----@param command string +---@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) -- @@ -1939,11 +2115,11 @@ local function fix_bat_default_pager_shell_command(command) -- when replacing the less command when it is quoted local modified_command, replacement_count = command:gsub( "(" - .. bat_command_with_pager_pattern - .. "['\"]+%s*" - .. ")" - .. "less" - .. "(%s*['\"]+)", + .. bat_command_with_pager_pattern + .. "['\"]+%s*" + .. ")" + .. "less" + .. "(%s*['\"]+)", "%1" .. bat_default_pager_command_without_f_flag .. "%2" ) @@ -1994,11 +2170,11 @@ local function fix_shell_command(command) end -- Function to handle a shell command ----@param args Arguments ----@param _ nil ----@param exit_if_directory boolean|nil +---@param args Arguments The arguments passed to the plugin +---@param _ any +---@param exit_if_dir boolean|nil Whether to exit when all are directories ---@return nil -local function handle_shell(args, _, _, exit_if_directory) +local function handle_shell(args, _, _, exit_if_dir) -- -- Get the first item of the arguments given @@ -2020,11 +2196,11 @@ local function handle_shell(args, _, _, exit_if_directory) -- If the exit if directory flag is not given, -- and the arguments contain the -- exit if directory flag - if not exit_if_directory and args.exit_if_directory then + if not exit_if_dir and args.exit_if_dir then -- -- Set the exit if directory flag to true - exit_if_directory = true + exit_if_dir = true end -- If the item group is the selected items @@ -2032,7 +2208,7 @@ local function handle_shell(args, _, _, exit_if_directory) -- -- If the exit if directory flag is passed - if exit_if_directory then + if exit_if_dir then -- -- Initialise the number of files @@ -2072,7 +2248,7 @@ local function handle_shell(args, _, _, exit_if_directory) -- If the exit if directory flag is passed, -- and the hovered item is a directory, -- then exit the function - if exit_if_directory and hovered_item_is_dir() then return end + 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 @@ -2091,9 +2267,123 @@ local function handle_shell(args, _, _, exit_if_directory) ya.manager_emit("shell", args) end +-- Function to handle the paste command +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@return nil +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 args.smart) then + -- + + -- 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", {}) + + -- Paste the items inside the directory + ya.manager_emit("paste", args) + + -- Leave the directory + ya.manager_emit("leave", {}) +end + +-- The function to execute the tab create command +---@param state State The state object +---@param args Arguments The arguments passed to the plugin +---@return nil +local execute_tab_create = ya.sync(function(state, args) + -- + + -- Get the hovered item + local hovered_item = cx.active.current.hovered + + -- Get if the hovered item is a directory + local hovered_item_is_directory = hovered_item and hovered_item.cha.is_dir + + -- If the hovered item is a directory, + -- and the user wants to create a tab + -- in the hovered directory + if + hovered_item_is_directory + and (state.config.smart_tab_create or args.smart) + then + -- + + -- Set the arguments to the url of the hovered item + args = { hovered_item.url } + end + + -- Emit the command to create a new tab with the arguments + ya.manager_emit("tab_create", args) +end) + +-- Function to handle the tab create command +---@param args Arguments The arguments passed to the plugin +---@return nil +local function handle_tab_create(args) + -- + + -- Call the function to execute the tab create command + execute_tab_create(args) +end + +-- Function to execute the tab switch command +---@param state State The state object +---@param args Arguments The arguments passed to the plugin +---@return nil +local execute_tab_switch = ya.sync(function(state, args) + -- + + -- 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 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 args.smart) then + return ya.manager_emit("tab_switch", args) + end + + -- 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 + -- + + -- Call the tab create command + ya.manager_emit("tab_create", { current = true }) + end + + -- Switch to the given tab index + ya.manager_emit("tab_switch", args) +end) + +-- Function to handle the tab switch command +---@param args Arguments The arguments passed to the plugin +---@return nil +local function handle_tab_switch(args, config) + -- + + -- Call the function to execute the tab switch command + execute_tab_switch(args) +end + -- Function to do the wraparound for the arrow command ---@param _ any ----@param args Arguments +---@param args Arguments The arguments passed to the plugin ---@return nil local wraparound_arrow = ya.sync(function(_, args) -- @@ -2125,8 +2415,8 @@ local wraparound_arrow = ya.sync(function(_, args) end) -- Function to handle the arrow command ----@param args Arguments ----@param config Configuration +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object ---@return nil local function handle_arrow(args, config) -- @@ -2144,8 +2434,8 @@ end -- Function to get the directory items in the parent directory ---@param _ any ----@param directories_only boolean ----@return string[] +---@param directories_only boolean Whether to only get directories +---@return string[] directory_items The list of paths to the directory items local get_parent_directory_items = ya.sync(function(_, directories_only) -- @@ -2180,10 +2470,10 @@ local get_parent_directory_items = ya.sync(function(_, directories_only) end) -- Function to execute the parent arrow command ----@param state any ----@param args Arguments +---@param state State The state object +---@param args Arguments The arguments passed to the plugin ---@return nil -local execute_parent_arrow_command = ya.sync(function(state, args) +local execute_parent_arrow = ya.sync(function(state, args) -- -- Gets the parent directory @@ -2290,19 +2580,19 @@ local execute_parent_arrow_command = ya.sync(function(state, args) end) -- Function to handle the parent arrow command ----@param args Arguments +---@param args Arguments The arguments passed to the plugin ---@return nil local function handle_parent_arrow(args) -- -- Call the function to execute the parent arrow command -- with the arguments given - execute_parent_arrow_command(args) + execute_parent_arrow(args) end -- Function to handle the editor command ----@param args Arguments ----@param config Configuration +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object ---@return nil local function handle_editor(args, config) -- @@ -2332,9 +2622,9 @@ local function handle_editor(args, config) end -- Function to handle the pager command ----@param args Arguments ----@param config Configuration ----@param command_table CommandTable +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@param command_table CommandTable The command table ---@return nil local function handle_pager(args, config, command_table) -- @@ -2368,9 +2658,9 @@ local function handle_pager(args, config, command_table) end -- Function to run the commands given ----@param command string ----@param args Arguments ----@param config Configuration +---@param command string The command passed to the plugin +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object ---@return nil local function run_command_func(command, args, config) -- @@ -2381,14 +2671,12 @@ local function run_command_func(command, args, config) [Commands.Open] = handle_open, [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.Paste] = handle_paste, + [Commands.Rename] = function(_) handle_yazi_command("rename", args) end, + [Commands.Remove] = function(_) handle_yazi_command("remove", args) end, [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, @@ -2407,6 +2695,7 @@ local function run_command_func(command, args, config) end -- Parse the arguments and set it to the args variable + ---@type Arguments args = parse_args(args) -- Otherwise, call the function for the command @@ -2415,7 +2704,7 @@ end -- The setup function to setup the plugin ---@param _ any ----@param opts Configuration|nil +---@param opts Configuration|nil The options given to the plugin ---@return nil local function setup(_, opts) -- @@ -2426,7 +2715,7 @@ end -- The function to be called to use the plugin ---@param _ any ----@param args string[] +---@param args string[] The list of string arguments given by Yazi ---@return nil local function entry(_, args) -- @@ -2450,7 +2739,7 @@ local function entry(_, args) end -- Returns the table required for Yazi to run the plugin ----@return table { setup: function, entry: function } +---@return { setup: fun(): nil, entry: fun(): nil } return { setup = setup, entry = entry, diff --git a/config/yazi/plugins/exifaudio.yazi/init.lua b/config/yazi/plugins/exifaudio.yazi/init.lua index b1ecfaa9..4e6980bd 100644 --- a/config/yazi/plugins/exifaudio.yazi/init.lua +++ b/config/yazi/plugins/exifaudio.yazi/init.lua @@ -40,8 +40,8 @@ function Mediainfo(...) return child end -function M:peek() - local cache = ya.file_cache(self) +function M:peek(job) + local cache = ya.file_cache(job) if not cache then return end @@ -50,26 +50,26 @@ function M:peek() local cache_dir = GetPath(tostring(cache)) -- Try mediainfo, otherwise use exiftool - local status, child = pcall(Mediainfo, self.file.url, cache_dir) + local status, child = pcall(Mediainfo, job.file.url, cache_dir) if not status or child == nil then - status, child = pcall(Exiftool, self.file.url) + status, child = pcall(Exiftool, job.file.url) if not status or child == nil then local error = ui.Line { ui.Span("Make sure exiftool is installed and in your PATH") } -- TODO)) Remove legacy method when v0.4 gets released local function display_error_legacy() - local p = ui.Paragraph(self.area, { error }):wrap(ui.Paragraph.WRAP) - ya.preview_widgets(self, { p }) + local p = ui.Paragraph(job.area, { error }):wrap(ui.Paragraph.WRAP) + ya.preview_widgets(job, { p }) end local function display_error() - local p = ui.Text(error):area(self.area):wrap(ui.Text.WRAP) - ya.preview_widgets(self, { p }) + local p = ui.Text(error):area(job.area):wrap(ui.Text.WRAP) + ya.preview_widgets(job, { p }) end if pcall(display_error) then else pcall(display_error_legacy) end return end end - local limit = self.area.h + local limit = job.area.h local i, metadata = 0, {} repeat local next, event = child:read_line() @@ -80,7 +80,7 @@ function M:peek() end i = i + 1 - if i > self.skip then + if i > job.skip then local m_title, m_tag = Prettify(next) if m_title ~= "" and m_tag ~= "" then local ti = ui.Span(m_title):bold() @@ -89,30 +89,30 @@ function M:peek() table.insert(metadata, ui.Line{}) end end - until i >= self.skip + limit + until i >= job.skip + limit -- TODO)) Remove legacy method when v0.4 gets released local function display_metadata_legacy() - local p = ui.Paragraph(self.area, metadata):wrap(ui.Paragraph.WRAP) - ya.preview_widgets(self, { p }) + local p = ui.Paragraph(job.area, metadata):wrap(ui.Paragraph.WRAP) + ya.preview_widgets(job, { p }) end local function display_metadata() - local p = ui.Text(metadata):area(self.area):wrap(ui.Text.WRAP) - ya.preview_widgets(self, { p }) + local p = ui.Text(metadata):area(job.area):wrap(ui.Text.WRAP) + ya.preview_widgets(job, { p }) end if pcall(display_metadata) then else pcall(display_metadata_legacy) end - local cover_width = self.area.w / 2 - 5 - local cover_height = (self.area.h / 4) + 3 + local cover_width = job.area.w / 2 - 5 + local cover_height = (job.area.h / 4) + 3 local bottom_right = ui.Rect { - x = self.area.right - cover_width, - y = self.area.bottom - cover_height, + x = job.area.right - cover_width, + y = job.area.bottom - cover_height, w = cover_width, h = cover_height, } - if self:preload() == 1 then + if self:preload(job) == 1 then ya.image_show(cache, bottom_right) end end @@ -172,18 +172,18 @@ function Prettify(metadata) end -function M:seek(units) +function M:seek(job) local h = cx.active.current.hovered - if h and h.url == self.file.url then + if h and h.url == job.file.url then ya.manager_emit("peek", { - tostring(math.max(0, cx.active.preview.skip + units)), - only_if = tostring(self.file.url), + tostring(math.max(0, cx.active.preview.skip + job.units)), + only_if = tostring(job.file.url), }) end end -function M:preload() - local cache = ya.file_cache(self) +function M:preload(job) + local cache = ya.file_cache(job) if not cache or fs.cha(cache) then return 1 end @@ -216,7 +216,7 @@ Channels: %Channel(s)%"\ fs.write(Url(cache_dir.."mediainfo.txt"), mediainfo_template) local output = Command("exiftool") - :args({ "-b", "-CoverArt", "-Picture", tostring(self.file.url) }) + :args({ "-b", "-CoverArt", "-Picture", tostring(job.file.url) }) :stdout(Command.PIPED) :stderr(Command.PIPED) :output() diff --git a/config/yazi/plugins/glow.yazi/init.lua b/config/yazi/plugins/glow.yazi/init.lua index bb383042..c19e48b6 100644 --- a/config/yazi/plugins/glow.yazi/init.lua +++ b/config/yazi/plugins/glow.yazi/init.lua @@ -2,20 +2,20 @@ local M = {} function M:peek() local child = Command("glow") - :args({ - "--style", - "dark", - "--width", - tostring(self.area.w), - tostring(self.file.url), - }) - :env("CLICOLOR_FORCE", "1") - :stdout(Command.PIPED) - :stderr(Command.PIPED) - :spawn() + :args({ + "--style", + "dark", + "--width", + tostring(self.area.w), + tostring(self.file.url), + }) + :env("CLICOLOR_FORCE", "1") + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() if not child then - return self:fallback_to_builtin() + return require("code").peek(self) end local limit = self.area.h @@ -23,7 +23,7 @@ function M:peek() repeat local next, event = child:read_line() if event == 1 then - return self:fallback_to_builtin() + return require("code").peek(self) elseif event ~= 0 then break end @@ -36,36 +36,15 @@ function M:peek() child:start_kill() if self.skip > 0 and i < self.skip + limit then - ya.manager_emit( - "peek", - { tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" } - ) + ya.manager_emit("peek", { math.max(0, i - limit), only_if = self.file.url, upper_bound = true }) else lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size)) - ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) }) + ya.preview_widgets(self, { ui.Text.parse(lines):area(self.area) }) end end function M:seek(units) - local h = cx.active.current.hovered - if h and h.url == self.file.url then - local step = math.floor(units * self.area.h / 10) - ya.manager_emit("peek", { - tostring(math.max(0, cx.active.preview.skip + step)), - only_if = tostring(self.file.url), - }) - end -end - -function M:fallback_to_builtin() - local err, bound = ya.preview_code(self) - if bound then - ya.manager_emit("peek", { bound, only_if = self.file.url, upper_bound = true }) - elseif err and not err:find("cancelled", 1, true) then - ya.preview_widgets(self, { - ui.Paragraph(self.area, { ui.Line(err):reverse() }), - }) - end + require("code").seek(self, units) end return M diff --git a/config/yazi/plugins/hexyl.yazi/init.lua b/config/yazi/plugins/hexyl.yazi/init.lua index 91f05f2c..6fe0990e 100644 --- a/config/yazi/plugins/hexyl.yazi/init.lua +++ b/config/yazi/plugins/hexyl.yazi/init.lua @@ -1,12 +1,12 @@ local M = {} -function M:peek() +function M:peek(job) local child local l = self.file.cha.len if l == 0 then child = Command("hexyl") :args({ - tostring(self.file.url), + tostring(job.file.url), }) :stdout(Command.PIPED) :stderr(Command.PIPED) @@ -17,15 +17,15 @@ function M:peek() "--border", "none", "--terminal-width", - tostring(self.area.w), - tostring(self.file.url), + tostring(job.area.w), + tostring(job.file.url), }) :stdout(Command.PIPED) :stderr(Command.PIPED) :spawn() end - local limit = self.area.h + local limit = job.area.h local i, lines = 0, "" repeat local next, event = child:read_line() @@ -36,29 +36,22 @@ function M:peek() end i = i + 1 - if i > self.skip then + if i > job.skip then lines = lines .. next end - until i >= self.skip + limit + until i >= job.skip + limit child:start_kill() - if self.skip > 0 and i < self.skip + limit then - ya.manager_emit("peek", { math.max(0, i - limit), only_if = self.file.url, upper_bound = true }) + 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(self, { ui.Text.parse(lines):area(self.area) }) + ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) }) end end function M:seek(units) - local h = cx.active.current.hovered - if h and h.url == self.file.url then - local step = math.floor(units * self.area.h / 10) - ya.manager_emit("peek", { - tostring(math.max(0, cx.active.preview.skip + step)), - only_if = tostring(self.file.url), - }) - end + require("code").seek(job, units) end return M diff --git a/config/yazi/plugins/nbpreview.yazi/init.lua b/config/yazi/plugins/nbpreview.yazi/init.lua index baca4677..2a41cc35 100644 --- a/config/yazi/plugins/nbpreview.yazi/init.lua +++ b/config/yazi/plugins/nbpreview.yazi/init.lua @@ -1,6 +1,6 @@ local M = {} -function M:peek() +function M:peek(job) local child = Command("nbpreview") :args({ -- DO NOT CHANGE -- @@ -17,43 +17,42 @@ function M:peek() -- SPECIAL CUSTOMIZATIONS -- "--color-system=standard", "--theme=ansi_dark", - tostring(self.file.url), + tostring(job.file.url), }) :stdout(Command.PIPED) :stderr(Command.PIPED) :spawn() - if not child then - return require("code").peek(self) + return require("code"):peek(job) end - local limit = self.area.h + local limit = job.area.h local i, lines = 0, "" repeat local next, event = child:read_line() if event == 1 then - return require("code").peek(self) + return require("code"):peek(job) elseif event ~= 0 then break end i = i + 1 - if i > self.skip then + if i > job.skip then lines = lines .. next end - until i >= self.skip + limit + until i >= job.skip + limit child:start_kill() - if self.skip > 0 and i < self.skip + limit then - ya.manager_emit("peek", { math.max(0, i - limit), only_if = self.file.url, upper_bound = true }) + 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(self, { ui.Text.parse(lines):area(self.area) }) + ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) }) end end -function M:seek(units) - require("code").seek(self, units) +function M:seek(job) + require("code"):seek(job) end return M diff --git a/config/yazi/plugins/ouch.yazi/init.lua b/config/yazi/plugins/ouch.yazi/init.lua index 46997b58..6e5c9a60 100644 --- a/config/yazi/plugins/ouch.yazi/init.lua +++ b/config/yazi/plugins/ouch.yazi/init.lua @@ -1,13 +1,13 @@ local M = {} -function M:peek() +function M:peek(job) local child = Command("ouch") - :args({ "l", "-t", "-y", tostring(self.file.url) }) + :args({ "l", "-t", "-y", tostring(job.file.url) }) :stdout(Command.PIPED) :stderr(Command.PIPED) :spawn() - local limit = self.area.h - local file_name = string.match(tostring(self.file.url), ".*[/\\](.*)") + local limit = job.area.h + local file_name = string.match(tostring(job.file.url), ".*[/\\](.*)") local lines = string.format("📁 \x1b[2m%s\x1b[0m\n", file_name) local num_lines = 1 local num_skip = 0 @@ -20,7 +20,7 @@ function M:peek() end if line:find('Archive', 1, true) ~= 1 and line:find('[INFO]', 1, true) ~= 1 then - if num_skip >= self.skip then + if num_skip >= job.skip then lines = lines .. line num_lines = num_lines + 1 else @@ -30,23 +30,23 @@ function M:peek() until num_lines >= limit child:start_kill() - if self.skip > 0 and num_lines < limit then + if job.skip > 0 and num_lines < limit then ya.manager_emit( "peek", - { tostring(math.max(0, self.skip - (limit - num_lines))), only_if = tostring(self.file.url), upper_bound = "" } + { tostring(math.max(0, job.skip - (limit - num_lines))), only_if = tostring(job.file.url), upper_bound = "" } ) else - ya.preview_widgets(self, { ui.Text(lines):area(self.area) }) + ya.preview_widgets(job, { ui.Text(lines):area(job.area) }) end end -function M:seek(units) +function M:seek(job) local h = cx.active.current.hovered - if h and h.url == self.file.url then - local step = math.floor(units * self.area.h / 10) + if h and h.url == job.file.url then + local step = math.floor(job.units * job.area.h / 10) ya.manager_emit("peek", { math.max(0, cx.active.preview.skip + step), - only_if = tostring(self.file.url), + only_if = tostring(job.file.url), }) end end @@ -110,8 +110,8 @@ local function invoke_compress_command(paths, name) end end -function M:entry(args) - local default_fmt = args[1] +function M:entry(job) + local default_fmt = job.args[1] ya.manager_emit("escape", { visual = true }) diff --git a/config/yazi/plugins/relative-motions.yazi/init.lua b/config/yazi/plugins/relative-motions.yazi/init.lua index ef14623e..be938098 100644 --- a/config/yazi/plugins/relative-motions.yazi/init.lua +++ b/config/yazi/plugins/relative-motions.yazi/init.lua @@ -51,7 +51,7 @@ local render_motion_setup = ya.sync(function(_) end -- TODO: check why it doesn't work line this - -- Status:children_add(Status.motion, 100, Status.RIGHT) + -- Status:children_add(function() return ui.Span("") end, 1000, Status.RIGHT) end) local render_motion = ya.sync(function(_, motion_num, motion_cmd) @@ -66,15 +66,15 @@ local render_motion = ya.sync(function(_, motion_num, motion_cmd) local motion_span if not motion_cmd then - motion_span = ui.Span(string.format(" %3d ", motion_num)):style(style) + motion_span = ui.Span(string.format(" %3d ", motion_num)) else - motion_span = ui.Span(string.format(" %3d%s ", motion_num, motion_cmd)):style(style) + motion_span = ui.Span(string.format(" %3d%s ", motion_num, motion_cmd)) end return ui.Line { - ui.Span(THEME.status.separator_open):fg(style.bg), - motion_span, - ui.Span(THEME.status.separator_close):fg(style.bg), + ui.Span(THEME.status.separator_open):fg(style.main.bg), + motion_span:style(style.main), + ui.Span(THEME.status.separator_close):fg(style.main.bg), ui.Span(" "), } end @@ -210,9 +210,10 @@ local get_active_tab = ya.sync(function(_) return cx.tabs.idx end) ----------------------------------------------- return { - entry = function(_, args) + entry = function(_, job) local initial_value + local args = job.args -- this is checking if the argument is a valid number if #args > 0 then initial_value = tostring(tonumber(args[1])) diff --git a/config/yazi/plugins/yatline.yazi/init.lua b/config/yazi/plugins/yatline.yazi/init.lua index 2aadc8f2..100ff0b3 100644 --- a/config/yazi/plugins/yatline.yazi/init.lua +++ b/config/yazi/plugins/yatline.yazi/init.lua @@ -228,7 +228,7 @@ end function Yatline.string.get:hovered_size() local hovered = cx.active.current.hovered if hovered then - return ya.readable_size(hovered:size() or hovered.cha.length) + return ya.readable_size(hovered:size() or hovered.cha.len) else return "" end @@ -522,7 +522,7 @@ function Yatline.coloreds.get:permissions() local hovered = cx.active.current.hovered if hovered then - local perm = hovered.cha:permissions() + local perm = hovered.cha:perm() if perm then local coloreds = {} @@ -826,9 +826,9 @@ end local function config_paragraph(area, line) local line_array = { line } or {} if show_background then - return ui.Paragraph(area, line_array):style(style_c) + return ui.Text(line_array):area(area):style(style_c) else - return ui.Paragraph(area, line_array) + return ui.Text(line_array):area(area) end end @@ -976,7 +976,7 @@ return { return { config_paragraph(self._area) } end - local gauge = ui.Gauge(self._area) + local gauge = ui.Gauge():area(self._area) if progress.fail == 0 then gauge = gauge:gauge_style(THEME.status.progress_normal) else @@ -998,13 +998,13 @@ return { if display_header_line then if show_line(header_line) then - Header.render = function(self) + Header.redraw = function(self) local left_line = config_line(header_line.left, Side.LEFT) local right_line = config_line(header_line.right, Side.RIGHT) return { config_paragraph(self._area, left_line), - ui.Paragraph(self._area, { right_line }):align(ui.Paragraph.RIGHT) + ui.Text(right_line):area(self._area):align(ui.Text.RIGHT) } end @@ -1012,19 +1012,20 @@ return { Header.children_remove = function() return {} end end else - Header.render = function() return {} end + Header.redraw = function() return {} end end if display_status_line then if show_line(status_line) then - Status.render = function(self) + Status.redraw = function(self) local left_line = config_line(status_line.left, Side.LEFT) local right_line = config_line(status_line.right, Side.RIGHT) + local right_width = right_line:width() return { config_paragraph(self._area, left_line), - ui.Paragraph(self._area, { right_line }):align(ui.Paragraph.RIGHT), - table.unpack(Progress:render(self._area, right_line:width())), + ui.Text(right_line):area(self._area):align(ui.Text.RIGHT), + table.unpack(Progress:new(self._area, right_width):redraw()), } end @@ -1032,7 +1033,7 @@ return { Status.children_remove = function() return {} end end else - Status.render = function() return {} end + Status.redraw = function() return {} end end Root.layout = function(self) diff --git a/config/yazi/yazi.toml b/config/yazi/yazi.toml index 5719bb64..a156c0a8 100644 --- a/config/yazi/yazi.toml +++ b/config/yazi/yazi.toml @@ -26,7 +26,7 @@ ueberzug_offset = [ 0, 0, 0, 0 ] [opener] edit = [ - {run = '${EDITOR:=vi} "$@"', desc = "$EDITOR", block = true, for = "unix"}, + {run = '${EDITOR:=vim} "$@"', desc = "$EDITOR", block = true, for = "unix"}, {run = 'code "%*"', orphan = true, desc = "code", for = "windows"}, {run = 'code -w "%*"', block = true, desc = "code (block)", for = "windows"}, ] diff --git a/local/bin/typst-port b/local/bin/typst-port new file mode 100644 index 00000000..d2a0f748 --- /dev/null +++ b/local/bin/typst-port @@ -0,0 +1,32 @@ +#!/usr/bin/bash + +copy_to_clipboard() { + if [[ "$XDG_SESSION_TYPE" == "wayland" ]]; then + # Wayland + wl-copy + else + # X11 + xclip -selection clipboard + fi +} + +get_tinymist_ports() { + local line_num=${1:-0} # Default to 0 if no argument provided + + # Get all lines and store in array + mapfile -t lines < <(ss -tunlp | grep tinymist | awk '{ + split($5, addr, ":") + print addr[1] ":" addr[2] + }') + + # Check if requested line exists + if [ "$line_num" -lt 0 ] || [ "$line_num" -ge "${#lines[@]}" ]; then + echo "Error: Line $line_num does not exist" + exit 1 + fi + + # Output the requested line + echo "${lines[$line_num]}" | tee >(copy_to_clipboard) +} + +get_tinymist_ports "$1"