Compare commits

..

6 Commits
master ... trb

  1. 11
      .bashrc
  2. 22
      .config/fsel/config.toml
  3. 51
      .config/i3/config
  4. 2
      .config/i3/py3status.conf
  5. 2
      .config/i3/scripts/autoapp
  6. 34
      .config/nvim/lazy-lock.json
  7. 3
      .config/nvim/lua/config/options.lua
  8. 10
      .config/nvim/lua/plugins/conform.lua
  9. 7
      .config/nvim/lua/plugins/image.lua
  10. 5
      .config/ratflow/profiles/chodak_pc/config.d/20-keys-apps-core
  11. 606
      .config/sway/config
  12. 11
      .config/sway/scripts/always-float
  13. 28
      .config/sway/scripts/autoapp
  14. 36
      .config/sway/scripts/backlight
  15. 101
      .config/sway/scripts/gammastep-adjust
  16. 44
      .config/sway/scripts/output-profile
  17. 37
      .config/sway/scripts/screenshot
  18. 46
      .config/sway/scripts/swayexit
  19. 48
      .config/sway/scripts/translate-wl
  20. 68
      .config/sway/scripts/volctl
  21. 95
      .config/waybar/config.jsonc
  22. 169
      .config/waybar/disk.py
  23. 151
      .config/waybar/network.py
  24. 97
      .config/waybar/network.sh
  25. 53
      .config/waybar/style.css
  26. 30
      .config/waybar/top.sh
  27. 5
      .config/waybar/watch.sh
  28. 21
      .config/yazi/flavors/everforest-medium.yazi/LICENSE
  29. 21
      .config/yazi/flavors/everforest-medium.yazi/LICENSE-tmtheme
  30. 45
      .config/yazi/flavors/everforest-medium.yazi/README.md
  31. 179
      .config/yazi/flavors/everforest-medium.yazi/flavor.toml
  32. BIN
      .config/yazi/flavors/everforest-medium.yazi/preview.png
  33. 3186
      .config/yazi/flavors/everforest-medium.yazi/tmtheme.xml
  34. 21
      .config/yazi/flavors/gruvbox-material.yazi/LICENSE
  35. 201
      .config/yazi/flavors/gruvbox-material.yazi/LICENSE-tmtheme
  36. 42
      .config/yazi/flavors/gruvbox-material.yazi/README.md
  37. 214
      .config/yazi/flavors/gruvbox-material.yazi/flavor.toml
  38. BIN
      .config/yazi/flavors/gruvbox-material.yazi/preview.png
  39. 1376
      .config/yazi/flavors/gruvbox-material.yazi/tmtheme.xml
  40. 11
      .config/yazi/init.lua
  41. 56
      .config/yazi/keymap.toml
  42. 69
      .config/yazi/package.toml
  43. 21
      .config/yazi/plugins/chmod.yazi/LICENSE
  44. 28
      .config/yazi/plugins/chmod.yazi/README.md
  45. 47
      .config/yazi/plugins/chmod.yazi/main.lua
  46. 21
      .config/yazi/plugins/diff.yazi/LICENSE
  47. 28
      .config/yazi/plugins/diff.yazi/README.md
  48. 41
      .config/yazi/plugins/diff.yazi/main.lua
  49. 21
      .config/yazi/plugins/full-border.yazi/LICENSE
  50. 32
      .config/yazi/plugins/full-border.yazi/README.md
  51. 44
      .config/yazi/plugins/full-border.yazi/main.lua
  52. 21
      .config/yazi/plugins/git.yazi/LICENSE
  53. 86
      .config/yazi/plugins/git.yazi/README.md
  54. 259
      .config/yazi/plugins/git.yazi/main.lua
  55. 12
      .config/yazi/plugins/git.yazi/types.lua
  56. 21
      .config/yazi/plugins/gvfs.yazi/LICENSE
  57. 324
      .config/yazi/plugins/gvfs.yazi/README.md
  58. 23
      .config/yazi/plugins/gvfs.yazi/assets/automount.sh
  59. 9
      .config/yazi/plugins/gvfs.yazi/assets/gnome-keyring-daemon.service
  60. 2530
      .config/yazi/plugins/gvfs.yazi/main.lua
  61. 21
      .config/yazi/plugins/jump-to-char.yazi/LICENSE
  62. 28
      .config/yazi/plugins/jump-to-char.yazi/README.md
  63. 32
      .config/yazi/plugins/jump-to-char.yazi/main.lua
  64. 21
      .config/yazi/plugins/mount.yazi/LICENSE
  65. 50
      .config/yazi/plugins/mount.yazi/README.md
  66. 71
      .config/yazi/plugins/mount.yazi/cross.lua
  67. 272
      .config/yazi/plugins/mount.yazi/main.lua
  68. 54
      .config/yazi/plugins/mount.yazi/sudo.lua
  69. 19
      .config/yazi/plugins/open-with-cmd.yazi/LICENSE
  70. 25
      .config/yazi/plugins/open-with-cmd.yazi/README.md
  71. 19
      .config/yazi/plugins/open-with-cmd.yazi/main.lua
  72. 21
      .config/yazi/plugins/piper.yazi/LICENSE
  73. 102
      .config/yazi/plugins/piper.yazi/README.md
  74. 71
      .config/yazi/plugins/piper.yazi/main.lua
  75. 19
      .config/yazi/plugins/relative-motions.yazi/LICENSE
  76. 145
      .config/yazi/plugins/relative-motions.yazi/README.md
  77. 406
      .config/yazi/plugins/relative-motions.yazi/main.lua
  78. 21
      .config/yazi/plugins/smart-enter.yazi/LICENSE
  79. 40
      .config/yazi/plugins/smart-enter.yazi/README.md
  80. 11
      .config/yazi/plugins/smart-enter.yazi/main.lua
  81. 21
      .config/yazi/plugins/zoom.yazi/LICENSE
  82. 55
      .config/yazi/plugins/zoom.yazi/README.md
  83. 119
      .config/yazi/plugins/zoom.yazi/main.lua
  84. 3
      .config/yazi/theme.toml
  85. 37
      .config/yazi/yazi.toml
  86. 25
      .dotfiles.d/init/arch/init-cargo-tools.sh
  87. 16
      .dotfiles.d/init/arch/init-nvim.sh
  88. 23
      .dotfiles.d/init/arch/init-shell.sh
  89. 0
      .dotfiles.d/init/init-nvim.sh
  90. 5
      .dotfiles.d/init/init-shell.sh
  91. 28
      .dotfiles.d/init/ubuntu/init-cargo-tools.sh
  92. 447
      .local/bin/btswitch
  93. 26
      .local/bin/cat-md
  94. 6
      .local/share/applications/mimeinfo.cache
  95. 8
      .local/share/applications/nvim.desktop
  96. 8
      .local/share/applications/yazi.desktop
  97. 5
      .tmux.conf
  98. 6
      .tmux.d/tmux-gruvbox/gruvbox-tpm.tmux
  99. 98
      .tmux.d/tmux-gruvbox/src/gruvbox-main.sh
  100. 19
      .tmux.d/tmux-gruvbox/src/helper_methods.sh
  101. Some files were not shown because too many files have changed in this diff Show More

11
.bashrc

@ -157,14 +157,3 @@ alias bat=batcat
[ -f ~/.fzf.bash ] && source ~/.fzf.bash
[ -f "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env"
. "$HOME/.cargo/env"
# Sway / Wayland environment
export XDG_CURRENT_DESKTOP=sway
export XDG_SESSION_TYPE=wayland
export QT_QPA_PLATFORM=wayland
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
export GDK_BACKEND=wayland
export MOZ_ENABLE_WAYLAND=1
export SDL_VIDEODRIVER=wayland
export _JAVA_AWT_WM_NONREPARENTING=1

22
.config/fsel/config.toml

@ -1,22 +0,0 @@
# Root level - UI/Color options go here
highlight_color = "LightBlue"
main_border_color = "White"
pin_color = "Orange"
terminal_launcher = "kitty -e" # or "tty" for TTY mode (-t/--tty)
# App launcher specific options
[app_launcher]
filter_desktop = true
filter_actions = false
list_executables_in_path = true
ranking_mode = "frecency"
pinned_order = "ranking"
# Dmenu mode overrides
[dmenu]
delimiter = " "
show_line_numbers = true
# Clipboard mode overrides
[cclip]
image_preview = true

51
.config/i3/config

@ -17,6 +17,8 @@ set $mod Mod4
# helper scripts location
set $scriptsDir ~/.config/i3/scripts/
set $scriptsDir /home/chodylal/.config/i3/scripts/
#################################################################
# /profiles/current/config.d/10-workspaces:
@ -86,9 +88,8 @@ bindsym $mod+Control+Right move workspace to output right
#------------------------------------------------
# monitors - use "xrandr --listmonitors" to obtain your output names
set $leftOutput eDP
set $rightOutput HDMI-A-0
set $leftOutput HDMI-1
set $rightOutput eDP-1
# setup monitors
exec --no-startup-id xrandr --output $rightOutput --primary
exec --no-startup-id xrandr --output $leftOutput --left-of $rightOutput
@ -139,24 +140,16 @@ exec_always --no-startup-id sleep 2 && xrandr --output $leftOutput --left-of $ri
# start a terminal
#bindsym $mod+Return exec i3-sensible-terminal
#bindsym $mod+Return exec terminator -p ratflow-terminator
bindsym $mod+Return exec kitty
bindsym $mod+Return exec /home/chodylal/.local/kitty.app/bin/kitty
# start dmenu (a program launcher)
#bindsym $mod+d exec dmenu_run
#bindsym Mod1+F2 exec dmenu_run
#let's replace dmenu by custom launcher:
# bindsym $mod+d exec ulauncher
bindsym $mod+d exec ulauncher
bindsym Mod1+F2 exec dmenu_run
bindsym $mod+d exec --no-startup-id alacritty --title launcher -e bash -l -c "fsel -r --detach"
# bindsym $mod+d exec --no-startup-id alacritty --title launcher -e top
for_window [title="^launcher$"] floating enable, resize set width 600 height 530, border none
for_window [title="^launcher$"] move position center
# run app assigned to current workspace
bindsym $mod+Shift+a exec $scriptsDir/autoapp
#################################################################
@ -182,10 +175,10 @@ floating_modifier $mod
bindsym $mod+Shift+q kill
# change focus
bindsym $mod+j focus left
bindsym $mod+k focus down
bindsym $mod+l focus up
bindsym $mod+semicolon focus right
# bindsym $mod+j focus left
# bindsym $mod+k focus down
# bindsym $mod+l focus up
# bindsym $mod+semicolon focus right
# alternatively, you can use the cursor keys:
bindsym $mod+Left focus left
@ -194,10 +187,10 @@ bindsym $mod+Up focus up
bindsym $mod+Right focus right
# move focused window
bindsym $mod+Shift+j move left
bindsym $mod+Shift+k move down
bindsym $mod+Shift+l move up
bindsym $mod+Shift+semicolon move right
# bindsym $mod+Shift+j move left
# bindsym $mod+Shift+k move down
# bindsym $mod+Shift+l move up
# bindsym $mod+Shift+semicolon move right
# alternatively, you can use the cursor keys:
bindsym $mod+Shift+Left move left
@ -347,14 +340,17 @@ bindsym Shift+$mod+p exec /home/chodak/.screenlayout/edp.sh
#------------------------------------------------
# regenerate and reload i3 configuration file
bindsym $mod+Shift+c exec rfreload
# bindsym $mod+Shift+c exec rfreload
# suspend
bindsym $mod+Escape exec systemctl suspend
bindsym $mod+Escape exec i3lock -c 000000 && systemctl suspend
# lock
bindsym $mod+Shift+l exec i3lock -c 000000
# regenerate i3 configuration file and restart i3 (preserves your layout/session, can be used to upgrade i3)
bindsym $mod+Shift+r exec rfreload --restart
# bindsym $mod+Shift+r exec rfreload --restart
bindsym $mod+Shift+r exec i3-msg reload
# exit i3 (logs you out of your X session)
bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'"
@ -456,7 +452,7 @@ bar {
#Use tray_output primary/none/<output name> to define where the tray should be (multiple tray_output can be used)
#Remember to set any of your displays to primary (i.e. using xrandr)
#tray_output primary
tray_output $rightOutput
colors {
separator $clFocusedActiveText
#background $clUnfocusedBackground
@ -534,6 +530,11 @@ for_window [class="gsimplecal"] floating enable
for_window [class="Osmo"] floating enable
for_window [class="Skype"] floating enable
for_window [class="Yad"] floating enable
for_window [class="SMiKO" instance="^SMiKO$"] floating enable
for_window [class="SMiKO" instance="SMiKO"] floating enable
#################################################################
# /profiles/current/config.d/90-exec:

2
.config/i3/py3status.conf

@ -37,7 +37,7 @@ networkmanager {
external_script top {
cache_timeout = 10
script_path = "/usr/share/ratflow/scripts/top"
script_path = "/home/chodylal/.config/i3/scripts/top"
}
netdata {

2
.config/i3/scripts/autoapp

@ -2,7 +2,7 @@
import subprocess, json, os
mapFile = open(os.environ['HOME'] + '/.config/ratflow/profiles/current/autoapp.conf', 'r');
mapFile = open(os.environ['HOME'] + '/.config/i3/autoapp.conf', 'r');
map = json.loads(mapFile.read());

34
.config/nvim/lazy-lock.json

@ -1,39 +1,41 @@
{
"LazyVim": { "branch": "main", "commit": "c10948c50b18fae7f256433afdef09e432410480" },
"avante.nvim": { "branch": "main", "commit": "d9c33ebe1e7205f416796b5b383d6894abe47495" },
"LazyVim": { "branch": "main", "commit": "83d90f339defdb109a6ede333865a66ffc7ef6aa" },
"avante.nvim": { "branch": "main", "commit": "0e40cb0c0f13b87be8a2276a844428d60c466d78" },
"blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" },
"bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
"catppuccin": { "branch": "main", "commit": "49a926655a2f5579e9c276470fc300baaa49e524" },
"catppuccin": { "branch": "main", "commit": "8edd468af4d63212b84d69b2ddb5ffc9023ef5eb" },
"clangd_extensions.nvim": { "branch": "main", "commit": "78c2ecd659d54972be17aa6ba2deac3c53223b80" },
"conform.nvim": { "branch": "master", "commit": "619363c30309d29ffa631e67c8183f2a72caa373" },
"diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" },
"dotenv.nvim": { "branch": "main", "commit": "7d516e9293c6e3ac21830fb10a4e8674c02747c6" },
"dressing.nvim": { "branch": "master", "commit": "2d7c2db2507fa3c4956142ee607431ddb2828639" },
"flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" },
"friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" },
"gitsigns.nvim": { "branch": "main", "commit": "2038c666bd9d8a0b7349a0b6ee00dc83104b9ecf" },
"grug-far.nvim": { "branch": "main", "commit": "c995bbacf8229dc096ec1c3d60f8531059c86c1b" },
"hybrid-theme": { "branch": "main", "commit": "6ae348938376f345e02eea4e6c27c0874b05f33a" },
"gitsigns.nvim": { "branch": "main", "commit": "dd3f588bacbeb041be6facf1742e42097f62165d" },
"grug-far.nvim": { "branch": "main", "commit": "5506c2f59dc9ab2ed6c233585412b24d31d51521" },
"hybrid-theme": { "branch": "main", "commit": "b131110fbe63481d7d263c71982206a70a04d236" },
"image.nvim": { "branch": "master", "commit": "44e07129cd0ea0c60afa7a1991d35b5765b51a6b" },
"indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" },
"just-runner.nvim": { "branch": "main", "commit": "f29d405aa828900df242600720a2b0e57261489f" },
"lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" },
"lazydev.nvim": { "branch": "main", "commit": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d" },
"lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" },
"mason-lspconfig.nvim": { "branch": "main", "commit": "21c5b3ebeaa0412e28096bb0701434c51c1fbf76" },
"mason.nvim": { "branch": "main", "commit": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d" },
"mini.ai": { "branch": "main", "commit": "d73c36349aa7b0bab5f77ad71701a1d42211a1df" },
"mini.files": { "branch": "main", "commit": "a5689dae6b732955e33eec225b798d6815063179" },
"mini.icons": { "branch": "main", "commit": "e56797f90192d81f1fda02e662fc3e8e3d775027" },
"mini.pairs": { "branch": "main", "commit": "4a014143fcb4e9df26198ccb3ecff3b9e77a048c" },
"lualine.nvim": { "branch": "master", "commit": "131a558e13f9f28b15cd235557150ccb23f89286" },
"mason-lspconfig.nvim": { "branch": "main", "commit": "7b01e2974a47d489bb92f47a41e4c0088ea8f86e" },
"mason.nvim": { "branch": "main", "commit": "bb639d4bf385a4d89f478b83af4d770be05ab7eb" },
"mini.ai": { "branch": "main", "commit": "4ce4c35e411ea329a15d4b15e9c89c2a3089e437" },
"mini.files": { "branch": "main", "commit": "423d6b5afb7a94e658950d470957f830d43dd41e" },
"mini.icons": { "branch": "main", "commit": "520995f1d75da0e4cc901ee95080b1ff2bc46b94" },
"mini.pairs": { "branch": "main", "commit": "30cf2f01c4aaa2033db67376b9924fa2442c05d6" },
"noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" },
"nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" },
"nvim-lint": { "branch": "master", "commit": "01c9842c089069ab497430159312b2c8868a4590" },
"nvim-lspconfig": { "branch": "master", "commit": "bfcc0171a43f22afa61d927ffe9fcb6cb85dc99e" },
"nvim-lint": { "branch": "master", "commit": "d48f3a76189d03b2239f6df1b2f7e3fa8353743b" },
"nvim-lspconfig": { "branch": "master", "commit": "9573948c38bfabeec353ae7dd7d3ffec4c506a6b" },
"nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" },
"nvim-treesitter-textobjects": { "branch": "main", "commit": "851e865342e5a4cb1ae23d31caf6e991e1c99f1e" },
"nvim-ts-autotag": { "branch": "main", "commit": "88c1453db4ba7dd24131086fe51fdf74e587d275" },
"persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" },
"plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" },
"render-markdown.nvim": { "branch": "main", "commit": "f422cb5c6855f150e2ddcfaf44e7157b98b34f6a" },
"render-markdown.nvim": { "branch": "main", "commit": "5adf0895310c1904e5abfaad40a2baad7fe44a07" },
"snacks.nvim": { "branch": "main", "commit": "882c996cf28183f4d63640de0b4c02ec886d01f2" },
"todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" },
"tokyonight.nvim": { "branch": "main", "commit": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6" },

3
.config/nvim/lua/config/options.lua

@ -35,4 +35,5 @@ vim.opt.listchars = {
-- eol = "↲", -- Symbol for end of line (optional)
}
-- Do not hide syntax makers (**, ``` etc)
-- vim.opt.conceallevel = 0

10
.config/nvim/lua/plugins/conform.lua

@ -1,10 +0,0 @@
return {
"stevearc/conform.nvim",
opts = {
formatters = {
shfmt = {
args = { "-i", "2", "-ci", "-bn", "-sr" },
},
},
},
}

7
.config/nvim/lua/plugins/image.lua

@ -0,0 +1,7 @@
return {
"3rd/image.nvim",
build = false, -- so that it doesn't build the rock https://github.com/3rd/image.nvim/issues/91#issuecomment-2453430239
opts = {
processor = "magick_cli",
},
}

5
.config/ratflow/profiles/chodak_pc/config.d/20-keys-apps-core

@ -14,12 +14,9 @@ bindsym $mod+Return exec kitty
#bindsym Mod1+F2 exec dmenu_run
#let's replace dmenu by custom launcher:
# bindsym $mod+d exec ulauncher
bindsym $mod+d exec ulauncher
bindsym Mod1+F2 exec ulauncher
bindsym $mod+d exec kitty --title launcher -o cursor_trail=0 -e fsel -r --detach
for_window [title="^launcher$"] floating enable, resize set width 500 height 430, border none
# run app assigned to current workspace
bindsym $mod+Shift+a exec $scriptsDir/autoapp

606
.config/sway/config

@ -1,606 +0,0 @@
#----------------------------------------------------------------
# Sway Config — Arch + Wayland
#
# Migrated from i3/X11 config. All X11-specific tools have been
# replaced with Wayland-native equivalents (see migration notes
# throughout this file).
#
# Install script: arch-init.sh
#----------------------------------------------------------------
#################################################################
# Variables
#################################################################
# Mod key: Mod4 = Super/Windows key, Mod1 = Alt
set $mod Mod4
# Helper scripts directory (Wayland replacements for ratflow scripts)
set $scriptsDir ~/.config/sway/scripts
# Config directory
set $configDir ~/.config/sway
#################################################################
# Workspaces
#################################################################
set $workspace1 1: >_
set $workspace2 2: dev
set $workspace3 3: www
set $workspace4 4: files
set $workspace5 5: e-mail
set $workspace6 6: IM
set $workspace7 7: video
set $workspace8 8: workspace
set $workspace9 9: workspace
set $workspace10 10: Music
set $workspace11 V: VM
# Switch to workspace
bindsym $mod+1 workspace $workspace1
bindsym $mod+2 workspace $workspace2
bindsym $mod+3 workspace $workspace3
bindsym $mod+4 workspace $workspace4
bindsym $mod+5 workspace $workspace5
bindsym $mod+6 workspace $workspace6
bindsym $mod+7 workspace $workspace7
bindsym $mod+8 workspace $workspace8
bindsym $mod+9 workspace $workspace9
bindsym $mod+0 workspace $workspace10
# Move focused container to workspace
bindsym $mod+Shift+1 move container to workspace $workspace1
bindsym $mod+Shift+2 move container to workspace $workspace2
bindsym $mod+Shift+3 move container to workspace $workspace3
bindsym $mod+Shift+4 move container to workspace $workspace4
bindsym $mod+Shift+5 move container to workspace $workspace5
bindsym $mod+Shift+6 move container to workspace $workspace6
bindsym $mod+Shift+7 move container to workspace $workspace7
bindsym $mod+Shift+8 move container to workspace $workspace8
bindsym $mod+Shift+9 move container to workspace $workspace9
bindsym $mod+Shift+0 move container to workspace $workspace10
# Next/prev workspace
bindsym $mod+x workspace next
bindsym $mod+Shift+x move container to workspace next
bindsym $mod+z workspace prev
bindsym $mod+Shift+z move container to workspace prev
# Moving workspace across monitors
# MIGRATION: xrandr replaced by swaymsg output commands
bindsym $mod+Control+Left move workspace to output left
bindsym $mod+Control+Right move workspace to output right
#################################################################
# Output / Monitor Management
# MIGRATION: xrandr → swaymsg output / kanshi for auto profiles
#################################################################
# Define your outputs — run `swaymsg -t get_outputs` to get names
set $leftOutput eDP-1
set $rightOutput HDMI-A-1
# Default monitor setup
# sway handles output layout natively, no xrandr needed
output $rightOutput pos 1920 0
output $leftOutput pos 0 0
# Mode for toggling outputs (replaces i3 "outputs" mode)
mode "outputs" {
# $mod+Shift+1: turn off left monitor; $mod+1: turn it on
bindsym $mod+Shift+1 output $leftOutput disable; mode "default"
bindsym $mod+1 output $leftOutput enable; mode "default"
# $mod+Shift+2: turn off right monitor; $mod+2: turn it on
bindsym $mod+Shift+2 output $rightOutput disable; mode "default"
bindsym $mod+2 output $rightOutput enable; mode "default"
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+m mode "outputs"
#################################################################
# Wallpaper
# MIGRATION: feh → swaybg (Wayland-native wallpaper setter)
# Omarchy also uses swaybg for this purpose.
#################################################################
set $wallpaper1 /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png
set $wallpaper2 /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png
# swaybg is a native Wayland wallpaper setter
output $leftOutput bg $wallpaper1 fill
output $rightOutput bg $wallpaper2 fill
#################################################################
# Input Device Configuration
# MIGRATION: synclient → sway input {} blocks
# X11 touchpad/synaptics config replaced by libinput via sway.
#################################################################
input "type:touchpad" {
tap enabled
click_method button_areas
scroll_method two_finger
dwt enabled
# natural_scroll enabled # uncomment if you prefer macOS-style scrolling
}
input "type:keyboard" {
xkb_layout pl
# xkb_variant ...
# xkb_options caps:escape # uncomment to remap Caps Lock to Escape
}
#################################################################
# Application Launchers
# MIGRATION: ulauncher works on Wayland but is GTK-based.
# Alternatives: wofi (native), rofi-wayland, tofi.
# dmenu_run replaced by wofi (or keep as dmenu_path | wofi -d).
# Omarchy uses Walker — a modern Wayland-native launcher.
#################################################################
# Terminal
bindsym $mod+Return exec kitty
# App launcher: wofi (lightweight, Wayland-native)
# Alternatives: rofi -show drun (rofi-wayland package), tofi
bindsym $mod+d exec fuzzel
bindsym Mod1+F2 exec wofi --show run
# Clipboard manager — show history (Ctrl+Alt+H)
# bindsym Control+Mod1+h exec copyq toggle
bindsym Control+Mod1+h exec cliphist list | fuzzel --width 80 --dmenu | cliphist decode | wl-copy
# Run app assigned to current workspace
bindsym $mod+Shift+a exec $scriptsDir/autoapp
#################################################################
# Window Navigation
# MIGRATION: i3-msg workspace back_and_forth → same in sway
#################################################################
bindsym $mod+Tab workspace back_and_forth
#################################################################
# Window Management
# MIGRATION: nearly identical to i3 — sway is i3-compatible
#################################################################
# Use Mouse+$mod to drag floating windows
floating_modifier $mod
# Kill focused window
bindsym $mod+Shift+q kill
# Change focus (vim keys)
bindsym $mod+j focus left
bindsym $mod+k focus down
bindsym $mod+l focus up
bindsym $mod+semicolon focus right
# Change focus (arrow keys)
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
# Move focused window (vim keys)
bindsym $mod+Shift+j move left
bindsym $mod+Shift+k move down
bindsym $mod+Shift+l move up
bindsym $mod+Shift+semicolon move right
# Move focused window (arrow keys)
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
# Split orientation
bindsym $mod+h split h
bindsym $mod+v split v
# Fullscreen
bindsym $mod+f fullscreen
# Layout modes
bindsym $mod+s layout stacking
bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split
# Toggle tiling / floating
bindsym $mod+Shift+space floating toggle
bindsym $mod+button2 floating toggle
# Focus tiling/floating toggle
bindsym $mod+space focus mode_toggle
# Focus parent container
bindsym $mod+a focus parent
# Always-float toggle (custom script)
bindsym $mod+Shift+f exec $scriptsDir/always-float
#################################################################
# Resize Mode
#################################################################
mode "resize" {
bindsym j resize shrink width 10 px or 10 ppt
bindsym k resize grow height 10 px or 10 ppt
bindsym l resize shrink height 10 px or 10 ppt
bindsym semicolon resize grow width 10 px or 10 ppt
bindsym Left resize shrink width 10 px or 10 ppt
bindsym Down resize grow height 10 px or 10 ppt
bindsym Up resize shrink height 10 px or 10 ppt
bindsym Right resize grow width 10 px or 10 ppt
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+r mode "resize"
#################################################################
# Screenshots
# MIGRATION: screengrab (X11) → grim + slurp (Wayland-native)
# grim = screen capture (replaces scrot/import/screengrab)
# slurp = region selector (Wayland-native)
# wl-copy copies to Wayland clipboard
# Omarchy also uses grim + slurp (+ satty for annotation).
#################################################################
# Screenshots — capture once, save to file + copy to clipboard
bindsym Print exec $scriptsDir/screenshot full
bindsym Shift+Print exec $scriptsDir/screenshot area
bindsym Control+Print exec $scriptsDir/screenshot window
#################################################################
# Calendar
# MIGRATION: osmo/gsimplecal (X11) → keep osmo if desired,
# or use waybar clock module + rofi/wofi calendar script.
# Omarchy uses waybar clock module only (no standalone calendar app).
#################################################################
bindsym $mod+c exec osmo -c
# Alternative: wofi-based calendar popup
# bindsym $mod+c exec $scriptsDir/calendar-popup
#################################################################
# Screen Color Temperature
# MIGRATION: redshift (X11) → gammastep (Wayland fork of redshift)
# or wlsunset (lighter alternative).
# Omarchy uses hyprsunset (Hyprland-specific), but for sway
# gammastep is the standard choice.
# $scriptsDir/gammastep-adjust replaces redshift-adjust.
#################################################################
bindsym $mod+Control+KP_Next exec $scriptsDir/gammastep-adjust "-500"
bindsym $mod+Control+KP_Prior exec $scriptsDir/gammastep-adjust "+500"
bindsym $mod+Control+l exec gammastep -x
#################################################################
# Translation of Selected Text
# MIGRATION: trans-xsel (X11 xsel) → translate-shell + wl-clipboard
# Uses wl-paste / wl-copy instead of xsel/xclip.
#################################################################
bindsym $mod+t exec bash -c "$scriptsDir/translate-wl en:pl &"
bindsym $mod+Shift+t exec bash -c "$scriptsDir/translate-wl pl:en &"
#################################################################
# Multimedia Keys & Audio
# MIGRATION: PulseAudio volctl → PipeWire + wpctl (or pamixer)
# Arch + Wayland standard is PipeWire with WirePlumber.
# Volume OSD: SwayOSD (Omarchy approach) or swayosd-server.
# The $scriptsDir/volctl wrapper uses wpctl/pamixer underneath.
#################################################################
# Volume controls (primary sink)
bindsym XF86AudioRaiseVolume exec --no-startup-id $scriptsDir/volctl up
bindsym XF86AudioLowerVolume exec --no-startup-id $scriptsDir/volctl down
bindsym XF86AudioMute exec --no-startup-id $scriptsDir/volctl toggle
# Volume controls (secondary sink, e.g. HDMI)
bindsym Shift+XF86AudioRaiseVolume exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl up
bindsym Shift+XF86AudioLowerVolume exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl down
bindsym Shift+XF86AudioMute exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl toggle
# Screen brightness
# MIGRATION: xbacklight / ratflow-backlight → brightnessctl
bindsym XF86MonBrightnessUp exec --no-startup-id $scriptsDir/backlight up
bindsym XF86MonBrightnessDown exec --no-startup-id $scriptsDir/backlight down
# Media player controls
# MIGRATION: clementine-specific → playerctl (agnostic MPRIS controller)
# playerctl works with any MPRIS2-compatible player (Spotify, mpv, etc.)
bindsym XF86AudioPlay exec playerctl play-pause
bindsym XF86AudioPause exec playerctl pause
bindsym XF86AudioNext exec playerctl next
bindsym XF86AudioPrev exec playerctl previous
#################################################################
# Projector / Screen Layout
# MIGRATION: xrandr shell scripts → swaymsg output commands
# kanshi can auto-switch profiles on hotplug.
#################################################################
bindsym $mod+p exec $scriptsDir/output-profile projector
bindsym $mod+Shift+p exec $scriptsDir/output-profile edp-only
#################################################################
# Session / Power Management
# MIGRATION: i3-nagbar → swaynag, i3exit → loginctl-based script
# swayidle handles DPMS/idle (replaces xset dpms).
# swaylock replaces i3lock.
# Omarchy uses hyprlock+hypridle, sway equivalents are swaylock+swayidle.
#################################################################
# Reload sway config
bindsym $mod+Shift+c exec swaymsg reload
# Suspend
bindsym $mod+Escape exec systemctl suspend
# Restart sway
bindsym $mod+Shift+r exec swaymsg reload
# Exit sway
bindsym $mod+Shift+e exec swaynag -t warning -m 'Exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
# Session management mode (replaces i3exit)
set $exitScript $scriptsDir/swayexit
mode "session_management" {
bindsym l exec --no-startup-id $exitScript lock, mode "default"
bindsym e exec --no-startup-id $exitScript logout, mode "default"
bindsym s exec --no-startup-id $exitScript suspend, mode "default"
bindsym h exec --no-startup-id $exitScript hibernate, mode "default"
bindsym r exec --no-startup-id $exitScript reboot, mode "default"
bindsym Shift+s exec --no-startup-id $exitScript shutdown, mode "default"
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+Pause mode "session_management"
#################################################################
# New Workspace
# MIGRATION: yad → zenity (or rofi/wofi)
# yad has some Wayland issues; zenity is GTK and works.
# Alternatively, use wofi for a pure Wayland input dialog.
#################################################################
bindsym $mod+n exec name=$(wofi --dmenu --prompt "Workspace name") && swaymsg workspace "$name"
#################################################################
# Theme / Appearance
# MIGRATION: No i3 client colors — sway has the same syntax.
# compton → not needed (sway has built-in compositor with
# basic effects). For blur/shadows, use swayfx (fork of sway).
# Omarchy uses Hyprland which has built-in blur/animation;
# for sway, swayfx adds these features.
#################################################################
# Font
set $fontName "Source Sans 3 Semi-Bold"
set $fontSize 10
set $barFontSize 9
font pango: $fontName $fontSize
# Window colors
# border background text indicator
client.focused #252525 #252525 #D9D9D9 #101010
client.focused_inactive #101010 #101010 #606060 #101010
client.unfocused #101010 #000000 #606060 #101010
client.urgent #F05000 #F05000 #F0F0F0 #101010
# Default border style
default_border pixel 2
default_floating_border normal 2
# Gaps (optional — sway supports gaps natively, unlike stock i3)
# gaps inner 5
# gaps outer 2
# Window opacity (requires swayfx for per-window opacity, or use
# sway's built-in opacity for all windows)
# for_window [app_id="kitty"] opacity 0.95
#################################################################
# Bar — Waybar
# MIGRATION: i3bar + py3status → waybar
# waybar is the standard bar for wlroots-based compositors.
# Omarchy uses waybar with extensive modules.
# Config files: ~/.config/waybar/config.jsonc + style.css
#################################################################
bar {
swaybar_command waybar
}
#################################################################
# Window Assignments
# MIGRATION: class= → app_id= for native Wayland apps.
# XWayland apps still use class=. Use `swaymsg -t get_tree`
# to find the correct app_id for native Wayland apps.
# Note: some apps may need both rules.
#################################################################
# Development
assign [app_id="qtcreator"] $workspace2
assign [class="Qtcreator"] $workspace2
assign [app_id="eclipse"] $workspace2
assign [class="Eclipse"] $workspace2
# Browser
assign [app_id="firefox"] $workspace3
assign [class="Firefox"] $workspace3
assign [app_id="chromium"] $workspace3
assign [class="Chromium-browser"] $workspace3
assign [class="Chrome"] $workspace3
# File managers
assign [app_id="pcmanfm-qt"] $workspace4
assign [class="Pcmanfm"] $workspace4
assign [app_id="dolphin"] $workspace4
assign [class="Dolphin"] $workspace4
assign [app_id="nautilus"] $workspace4
assign [class="Nautilus"] $workspace4
assign [app_id="thunar"] $workspace4
assign [class="Thunar"] $workspace4
# E-mail
assign [app_id="thunderbird"] $workspace5
assign [class="Thunderbird"] $workspace5
# IM
assign [app_id="telegram-desktop"] $workspace6
assign [class="Telegram"] $workspace6
assign [class="Skype"] $workspace6
# Video
assign [app_id="kodi"] $workspace7
assign [class="Kodi"] $workspace7
# Music
assign [app_id="spotify"] $workspace10
assign [class="Spotify"] $workspace10
assign [class="Clementine"] $workspace10
# VM
assign [class="VirtualBox"] $workspace11
assign [app_id="virt-manager"] $workspace11
#################################################################
# Floating Windows
#################################################################
for_window [app_id="screengrab"] floating enable
for_window [app_id="osmo"] floating enable
for_window [app_id="gsimplecal"] floating enable
for_window [class="Osmo"] floating enable
for_window [class="Skype"] floating enable
for_window [app_id="yad"] floating enable
for_window [class="Yad"] floating enable
for_window [app_id="wofi"] floating enable
for_window [app_id="swaync"] floating enable
#################################################################
# Idle Management
# MIGRATION: xset dpms → swayidle
# Locks screen after timeout, turns off display.
# Omarchy uses hypridle; sway equivalent is swayidle.
#################################################################
set $lockCommand swaylock -f -c 000000
exec swayidle -w \
timeout 600 '$lockCommand' \
timeout 900 'swaymsg "output * dpms off"' \
resume 'swaymsg "output * dpms on"' \
before-sleep '$lockCommand'
#################################################################
# Autostart
# MIGRATION NOTES:
# dunst → mako (Wayland-native notifier, used by Omarchy)
# or swaync (Sway Notification Center, more feature-rich)
# compton → NOT NEEDED (sway has built-in compositor)
# For blur/rounded corners, use swayfx
# synclient → sway input {} block (see above)
# redshift → gammastep or wlsunset
# nm-applet → nm-applet still works on Wayland, or use
# waybar network module + impala TUI (Omarchy approach)
# parcellite → cliphist + wl-clipboard (Wayland clipboard manager)
# cliphist stores history, wl-copy/wl-paste for access
# xset dpms → swayidle (see above)
#################################################################
# Notification daemon — mako (Omarchy uses mako)
exec --no-startup-id mako
# Alternative: swaync (Sway Notification Center) — more feature-rich
# exec --no-startup-id swaync
# Screen color temperature
exec --no-startup-id gammastep -l 52.43:15.15 -m wayland
# Network manager applet (still works on Wayland)
exec --no-startup-id nm-applet --indicator
# Clipboard manager
# Use Ctrl+Alt+H to toggle the clipboard history window
# exec --no-startup-id wl-paste --watch --type image cliphist store
exec --no-startup-id wl-paste --type text --watch cliphist store
exec --no-startup-id wl-paste --type image --watch cliphist store
# Bluetooth manager (waybar module can handle this, or use blueman-applet)
# exec --no-startup-id blueman-applet
# Polkit authentication agent (needed for GUI apps that need root)
exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1
# Background services for XDG desktop portals (screen sharing, file picker)
exec --no-startup-id dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway
#################################################################
# Key repeat rate
#################################################################
# input "type:keyboard" {
# xkb_layout pl
# # xkb_variant "programmer"
# xkb_options "grp:alt_shift_toggle, compose:ralt"
# repeat_delay 300
# repeat_rate 40
# }
# input type:keyboard { xkb_layout pl xkb_options grp:win_space_toggle }
# input type:keyboard {
# xkb_layout pl
# xkb_options level3:ralt_switch
# }
# input type:keyboard {
# xkb_layout pl
# xkb_options grp:alt_shift_toggle
# }
input type:keyboard {
xkb_layout pl,us
# lv3:ralt_switch keeps Right Alt working for Polish chars
# grp:alt_shift_toggle allows Alt+Shift to switch layouts
xkb_options lv3:ralt_switch,grp:alt_shift_toggle
}

11
.config/sway/scripts/always-float

@ -1,11 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# always-float — Toggle floating on the currently focused window
#
# Adapted from the ratflow always-float script.
# Uses swaymsg instead of i3-msg.
#
# Dependencies: sway
#----------------------------------------------------------------
swaymsg floating toggle

28
.config/sway/scripts/autoapp

@ -1,28 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# autoapp — Launch the application assigned to current workspace
#
# Adapted from the ratflow autoapp script.
# Reads workspace assignments and launches the matching app.
# Uses swaymsg instead of i3-msg.
#
# Dependencies: sway, jq
#----------------------------------------------------------------
# Get current workspace name
WORKSPACE=$(swaymsg -t get_workspaces | jq -r '.[] | select(.focused) | .name')
# Map workspace names to applications
# Customize these to match your workflow
case "$WORKSPACE" in
*">_"*) kitty ;;
*"dev"*) kitty ;;
*"www"*) firefox ;;
*"files"*) thunar ;;
*"e-mail"*) thunderbird ;;
*"IM"*) telegram-desktop ;;
*"video"*) mpv ;;
*"Music"*) spotify ;;
*"VM"*) virt-manager ;;
*) echo "No app assigned to workspace: $WORKSPACE" ;;
esac

36
.config/sway/scripts/backlight

@ -1,36 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# backlight — Screen brightness control using brightnessctl
#
# Replaces the old ratflow backlight script (xbacklight-based).
# brightnessctl works on Wayland without X11 dependencies.
#
# Usage:
# backlight up — increase brightness by 5%
# backlight down — decrease brightness by 5%
# backlight set N — set brightness to N percent
# backlight get — print current brightness percentage
#
# Dependencies: brightnessctl
#----------------------------------------------------------------
STEP=5
case "$1" in
up)
brightnessctl set "${STEP}%+" -q
;;
down)
brightnessctl set "${STEP}%-" -q
;;
set)
brightnessctl set "${2}%" -q
;;
get)
brightnessctl info | grep -oP '\d+%' | head -1 | tr -d '%'
;;
*)
echo "Usage: backlight {up|down|set N|get}"
exit 1
;;
esac

101
.config/sway/scripts/gammastep-adjust

@ -1,101 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# gammastep-adjust — Adjust gammastep color temperature
#
# Replaces the old ratflow redshift-adjust script.
# gammastep is the Wayland fork of redshift; it uses the same
# temperature range (1000K–25000K, default 6500K = daylight).
#
# Usage:
# gammastep-adjust -100 — make screen warmer (lower temperature by 100K)
# gammastep-adjust +100 — make screen cooler (raise temperature by 100K)
#
# How it works:
# gammastep doesn't support runtime temperature changes directly.
# This script writes the current temperature to a state file,
# kills any running gammastep, and launches a new one in one-shot
# mode (-O) with the new temperature.
#
# State file: /tmp/gammastep-current-temp
# PID file: /tmp/gammastep-pid
# Default: 6500 (neutral/daylight)
#
# Dependencies: gammastep
#----------------------------------------------------------------
set -x
STATE_FILE="/tmp/gammastep-current-temp"
PID_FILE="/tmp/gammastep-pid"
DEFAULT_TEMP=6500
MIN_TEMP=1000
MAX_TEMP=25000
# Read current temperature or use default
if [ -f "$STATE_FILE" ]; then
CURRENT=$(cat "$STATE_FILE")
else
CURRENT=$DEFAULT_TEMP
fi
# Parse argument
DELTA="${1:-0}"
# Strip the sign to get the absolute value
ABS_DELTA="${DELTA#+}"
ABS_DELTA="${ABS_DELTA#-}"
if [ -z "$ABS_DELTA" ]; then
echo "Usage: gammastep-adjust <+/-N>"
echo " Example: gammastep-adjust -100 (warmer)"
echo " Example: gammastep-adjust +100 (cooler)"
exit 1
fi
# Calculate new temperature
NEW_TEMP=$((CURRENT + DELTA))
# Clamp to valid range
if [ "$NEW_TEMP" -lt "$MIN_TEMP" ]; then
NEW_TEMP=$MIN_TEMP
fi
if [ "$NEW_TEMP" -gt "$MAX_TEMP" ]; then
NEW_TEMP=$MAX_TEMP
fi
# Save new state
echo "$NEW_TEMP" >"$STATE_FILE"
# Kill existing gammastep instance(s)
# Priority 1: use PID file if available (most precise)
if [ -f "$PID_FILE" ]; then
OLD_PID=$(cat "$PID_FILE")
if kill -0 "$OLD_PID" 2>/dev/null; then
kill "$OLD_PID" 2>/dev/null
# Give gammastep a moment to release the display and exit
sleep 0.2
fi
rm -f "$PID_FILE"
fi
# Priority 2: kill any stray gammastep processes
# -x (exact match) ensures we don't kill this script (gammastep-adjust)
pkill -x gammastep 2>/dev/null
sleep 0.1
# Launch gammastep with the new temperature.
#
# IMPORTANT: We use "setsid" (create a new session) so that gammastep is
# completely detached from the shell that Sway spawns for this keybinding.
# Without setsid, Sway kills gammastep when the keybinding shell exits,
# even with "&" — because the process is still in the same process group.
# setsid makes gammastep its own session leader, immune to cleanup.
# if [ "$NEW_TEMP" -ge "$DEFAULT_TEMP" ]; then
# # At or above neutral — reset to no tint
# setsid gammastep -x 2>/dev/null &
# echo $! >"$PID_FILE"
# echo "Temperature reset to neutral ($DEFAULT_TEMP K)"
# else
# Below neutral — apply one-shot manual temperature
setsid gammastep -O "$NEW_TEMP" 2>/dev/null &
echo $! >"$PID_FILE"
echo "Temperature set to $NEW_TEMP K"
# fi

44
.config/sway/scripts/output-profile

@ -1,44 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# output-profile — Switch sway output profiles
#
# Replaces xrandr shell scripts used in the old i3 config.
# Uses swaymsg output commands to configure displays.
#
# Usage:
# output-profile projector — enable HDMI output (mirror or extend)
# output-profile edp-only — disable all external outputs
# output-profile dual — dual monitor setup
#
# Dependencies: sway
#
# NOTE: Edit the output names to match your hardware.
# Run `swaymsg -t get_outputs` to list connected outputs.
#----------------------------------------------------------------
# Output names — adjust to match your hardware
LAPTOP="eDP-1"
EXTERNAL="HDMI-A-1"
case "$1" in
projector)
# Enable external output, mirror the laptop display
swaymsg output "$EXTERNAL" enable pos 0 0
swaymsg output "$LAPTOP" pos 0 0
;;
edp-only)
# Disable external output, laptop only
swaymsg output "$EXTERNAL" disable
;;
dual)
# Dual monitor: laptop left, external right
swaymsg output "$LAPTOP" pos 0 0
swaymsg output "$EXTERNAL" pos 1920 0
;;
*)
echo "Usage: output-profile {projector|edp-only|dual}"
echo " Edit this script to match your output names."
echo " Run 'swaymsg -t get_outputs' to list connected outputs."
exit 1
;;
esac

37
.config/sway/scripts/screenshot

@ -1,37 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# screenshot — Capture screen, window, or region
#
# Captures once, saves to ~/Pictures and copies to clipboard.
#
# Usage:
# screenshot full — full screen
# screenshot area — select region with slurp
# screenshot window — focused window
#
# Dependencies: grim, slurp, wl-copy, swaymsg, jq
#----------------------------------------------------------------
dir=~/Pictures
mkdir -p "$dir"
file="$dir/screenshot_$(date +%Y%m%d_%H%M%S).png"
case "$1" in
full)
grim -t png "$file"
;;
area)
geo=$(slurp)
grim -t png -g "$geo" "$file"
;;
window)
geo=$(swaymsg -t get_tree | jq -j '.. | select(.type?) | select(.focused) | .rect | "\(.x),\(.y) \(.width)x\(.height)"')
grim -t png -g "$geo" "$file"
;;
*)
echo "Usage: screenshot {full|area|window}"
exit 1
;;
esac
wl-copy -t image/png < "$file"

46
.config/sway/scripts/swayexit

@ -1,46 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# swayexit — Session management for sway on Wayland
#
# Replaces the old i3exit script (i3/X11-based).
# Uses loginctl for session management (systemd-logind).
#
# Usage:
# swayexit lock — lock the screen (swaylock)
# swayexit logout — exit sway
# swayexit suspend — suspend to RAM
# swayexit hibernate — suspend to disk
# swayexit reboot — reboot the system
# swayexit shutdown — power off the system
#
# Dependencies: swaylock, systemd (loginctl)
#----------------------------------------------------------------
case "$1" in
lock)
swaylock -f -c 000000
;;
logout)
swaymsg exit
;;
suspend)
swaylock -f -c 000000 &
sleep 0.5
systemctl suspend
;;
hibernate)
swaylock -f -c 000000 &
sleep 0.5
systemctl hibernate
;;
reboot)
systemctl reboot
;;
shutdown)
systemctl poweroff
;;
*)
echo "Usage: swayexit {lock|logout|suspend|hibernate|reboot|shutdown}"
exit 1
;;
esac

48
.config/sway/scripts/translate-wl

@ -1,48 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# translate-wl — Translate selected text using translate-shell
# with Wayland clipboard (wl-clipboard)
#
# Replaces the old ratflow trans-xsel script (X11 xsel-based).
# Uses wl-paste to get clipboard content and wl-copy to write
# the translation back, plus a notification via notify-send
# (which works with mako/swaync on Wayland).
#
# Usage:
# translate-wl en:pl — translate English to Polish
# translate-wl pl:en — translate Polish to English
# translate-wl de:en — translate German to English, etc.
#
# Workflow:
# 1. Select text (it goes to Wayland primary/clipboard)
# 2. Press the bound key (e.g. $mod+t)
# 3. Script reads selection via wl-paste, translates,
# shows notification, and copies result to clipboard
#
# Dependencies: translate-shell (trans), wl-clipboard, libnotify
#----------------------------------------------------------------
LANG_PAIR="${1:-en:pl}"
# Get clipboard content (user should select text first)
# wl-paste gets the clipboard content; for primary selection use wl-paste -p
TEXT=$(wl-paste -p 2>/dev/null || wl-paste 2>/dev/null)
if [ -z "$TEXT" ]; then
notify-send -t 3000 "Translation" "No text in clipboard/selection"
exit 1
fi
# Translate using translate-shell
RESULT=$(trans -b "$LANG_PAIR" "$TEXT" 2>/dev/null)
if [ -z "$RESULT" ]; then
notify-send -t 3000 "Translation" "Translation failed"
exit 1
fi
# Copy result to clipboard
echo -n "$RESULT" | wl-copy
# Show notification
notify-send -t 5000 "Translation ($LANG_PAIR)" "$RESULT"

68
.config/sway/scripts/volctl

@ -1,68 +0,0 @@
#!/bin/bash
#----------------------------------------------------------------
# volctl — Volume control wrapper for PipeWire + WirePlumber
#
# Replaces the old ratflow volctl (PulseAudio-based).
# Uses wpctl (WirePlumber CLI) for volume management.
#
# Usage:
# volctl up — increase volume by 5%
# volctl down — decrease volume by 5%
# volctl toggle — toggle mute on default sink
# volctl mute — mute default sink
# volctl unmute — unmute default sink
#
# Environment:
# SINK_NUM — if set, selects Nth sink (0=default, 1=next, etc.)
# mirrors the old VOLCTL_SINK_NUM behavior
#
# Dependencies: wireplumber, wpctl, pipewire, pipewire-pulse
#----------------------------------------------------------------
STEP=5
# Resolve which sink to use based on SINK_NUM (like old VOLCTL_SINK_NUM)
# SINK_NUM=0 or unset → default sink, SINK_NUM=1 → second sink, etc.
get_sink_id() {
local num="${SINK_NUM:-0}"
if [ "$num" = "0" ]; then
echo "@DEFAULT_AUDIO_SINK@"
else
# List sinks and pick the Nth one (1-indexed in SINK_NUM)
local sinks
sinks=$(wpctl status | grep -A 100 'Audio' | grep -A 100 'Sinks:' | grep -oP '\d+\.' | head -n $((num + 1)) | tail -1 | tr -d '.')
if [ -z "$sinks" ]; then
echo "@DEFAULT_AUDIO_SINK@"
else
echo "$sinks"
fi
fi
}
SINK=$(get_sink_id)
case "$1" in
up)
wpctl set-volume -l 1.5 "$SINK" "${STEP}%+"
;;
down)
wpctl set-volume "$SINK" "${STEP}%-"
;;
toggle)
wpctl set-mute "$SINK" toggle
;;
mute)
wpctl set-mute "$SINK" 1
;;
unmute)
wpctl set-mute "$SINK" 0
;;
*)
echo "Usage: volctl {up|down|toggle|mute|unmute}"
echo " Set SINK_NUM env var to select sink (0=default, 1=second, etc.)"
exit 1
;;
esac
# Optional: send signal to waybar to update volume display
# pkill -SIGRTMIN+1 waybar

95
.config/waybar/config.jsonc

@ -1,95 +0,0 @@
// -*- mode: json -*-
{
"layer": "top",
"position": "top",
"modules-left": [
"sway/workspaces",
"sway/window"
],
"modules-center": [],
"modules-right": [
"pulseaudio",
"custom/network",
"custom/disk",
"memory",
"custom/top",
"battery",
"clock#0",
"tray"
],
"sway/workspaces": {
"disable-scroll": true,
"format": "{name}"
},
"sway/window": {
"max-length": 70,
"format": "{title}"
},
"custom/network": {
"exec": "/home/chodak/.config/waybar/network.py --icon-size 12pt",
"interval": 10,
"return-type": "json",
"tooltip": true
},
"clock#0": {
"format": "{:%d/%m/%y %H:%M}",
"tooltip": false
},
"pulseaudio": {
"format": "<span size='10pt' rise='-1500'>{icon}</span> {volume:2}%",
"format-bluetooth": "<span size='10pt' rise='-1500'>{icon}</span> {volume}%",
"format-muted": "MUTE",
"format-icons": {
"headphones": "",
"default": [
"",
""
]
},
"scroll-step": 5,
"on-click": "pamixer -t",
"on-click-right": "pavucontrol"
},
"memory": {
"interval": 5,
"format": "<span size='10pt' rise='-1500'></span> {}%"
},
"custom/top": {
"exec": "~/.config/waybar/top.sh",
"interval": 5,
"return-type": "json",
"tooltip": true
},
"battery": {
"states": {
"good": 95,
"warning": 30,
"critical": 15
},
"format": "<span size='12pt' rise='-1500'>{icon}</span> {capacity}%",
"format-icons": [
"",
"",
"",
"",
""
]
},
"custom/disk": {
"exec": "/home/chodak/.config/waybar/disk.py --icon-size 10pt",
"interval": 30,
"return-type": "json",
"tooltip": true,
"escape": false
},
"tray": {
"icon-size": 24
}
}

169
.config/waybar/disk.py

@ -1,169 +0,0 @@
#!/usr/bin/env python3
"""Waybar disk module: shows disk usage across all mounted partitions."""
import argparse
import json
import os
# Filesystem types to ignore (virtual / non-disk)
IGNORE_FSTYPES = {
"tmpfs", "devtmpfs", "proc", "sysfs", "cgroup", "cgroup2",
"pstore", "bpf", "debugfs", "tracefs", "securityfs", "configfs",
"hugetlbfs", "devpts", "ramfs", "fuse.gvfsd-fuse", "fusectl",
"mqueue", "rpc_pipefs", "overlay", "squashfs",
}
# Pango color thresholds
COLOR_LOW = "#a6e3a1" # green — < 70%
COLOR_MID = "#f9e2af" # yellow — 70–89%
COLOR_HIGH = "#f38ba8" # red — ≥ 90%
DEFAULT_ICON_SIZE = "24pt"
def parse_args():
p = argparse.ArgumentParser()
p.add_argument("--icon-size", default=DEFAULT_ICON_SIZE,
help="Icon size (Pango size, e.g. 24pt)")
return p.parse_args()
def _pct_color(pct: float) -> str:
"""Return a Pango color string for the given usage percentage."""
if pct >= 90:
return COLOR_HIGH
if pct >= 70:
return COLOR_MID
return COLOR_LOW
def _span(color: str, text: str) -> str:
"""Wrap text in a Pango <span> with the given foreground color."""
return f"<span foreground='{color}'>{text}</span>"
def get_partitions():
"""Return list of (device, mountpoint, fstype) for real partitions."""
partitions = []
seen_devices = set()
try:
with open("/proc/mounts") as f:
for line in f:
parts = line.split()
if len(parts) < 3:
continue
device, mountpoint, fstype = parts[:3]
if fstype in IGNORE_FSTYPES:
continue
if not device.startswith("/dev/"):
continue
if device in seen_devices:
continue
seen_devices.add(device)
partitions.append((device, mountpoint, fstype))
except OSError:
pass
return partitions
def get_usage(mountpoint):
"""Return (total_bytes, used_bytes, pct) for a mountpoint, or None."""
try:
st = os.statvfs(mountpoint)
total = st.f_frsize * st.f_blocks
free = st.f_frsize * st.f_bfree
used = total - free
pct = (used / total) * 100 if total > 0 else 0.0
return total, used, pct
except OSError:
return None
def fmt_size(bytes_val):
"""Format bytes as human-readable."""
if bytes_val >= 1 << 40:
return f"{bytes_val / (1 << 40):.1f}T"
if bytes_val >= 1 << 30:
return f"{bytes_val / (1 << 30):.1f}G"
if bytes_val >= 1 << 20:
return f"{bytes_val / (1 << 20):.1f}M"
if bytes_val >= 1 << 10:
return f"{bytes_val / (1 << 10):.1f}K"
return f"{bytes_val}B"
def main():
args = parse_args()
isize = args.icon_size
partitions = get_partitions()
if not partitions:
print(json.dumps(
{"text": "", "tooltip": "No disk partitions found"},
ensure_ascii=False))
return
tooltip_lines = []
root_pct = None
bar_parts = []
for device, mountpoint, fstype in partitions:
usage = get_usage(mountpoint)
if usage is None:
continue
total, used, pct = usage
total_str = fmt_size(total)
used_str = fmt_size(used)
color = _pct_color(pct)
# Icons per mountpoint
if mountpoint == "/":
icon = ""
elif mountpoint == "/home":
icon = ""
elif mountpoint == "/boot":
icon = ""
elif "/media/" in mountpoint or "/run/media/" in mountpoint:
icon = ""
else:
icon = ""
# Tooltip line with colored percentage
pct_span = _span(color, f"{pct:5.1f}%")
warn = "" if pct >= 90 else ""
tooltip_lines.append(
f"{icon} {mountpoint:20s} {used_str:>6s} / {total_str:>6s} ({pct_span}){warn}"
)
# Track root for bar display
if mountpoint == "/":
root_pct = pct
# Build bar text using Pango markup
if root_pct is not None:
bar_icon = "" if root_pct >= 90 else ""
bar_color = _pct_color(root_pct)
bar_text = (
f"<span size='{isize}' rise='-1500'>{bar_icon}</span>"
f" {_span(bar_color, f'{root_pct:.0f}%')}"
)
elif tooltip_lines:
bar_text = f"<span size='{isize}' rise='-1500'></span> —"
else:
bar_text = ""
tooltip = "\n".join(tooltip_lines) if tooltip_lines else "No partitions"
print(json.dumps(
{"text": bar_text, "tooltip": tooltip},
ensure_ascii=False))
if __name__ == "__main__":
main()

151
.config/waybar/network.py

@ -1,151 +0,0 @@
#!/usr/bin/env python3
"""Waybar network module: shows interface, IP, and up/down transfer rate."""
import argparse
import json
import os
import re
import subprocess
import time
STATE_FILE_TMPL = "/tmp/waybar-network-stats-{}"
ICON = "󰲝" # nerd font network icon
NO_NET_ICON = "󰖪"
DEFAULT_ICON_SIZE = "24pt"
def run(cmd: list[str]) -> str:
"""Run a command and return stdout, or empty string on failure."""
try:
return subprocess.check_output(
cmd, stderr=subprocess.DEVNULL, text=True
).strip()
except subprocess.CalledProcessError:
return ""
def get_default_interface() -> str | None:
"""Return the default route interface name."""
output = run(["ip", "route"])
for line in output.splitlines():
if line.startswith("default"):
parts = line.split()
# "default via X.X.X.X dev INTERFACE ..."
if len(parts) >= 5:
return parts[4]
return None
def get_ip(iface: str) -> str | None:
"""Return the IPv4 address of the given interface."""
output = run(["ip", "-4", "addr", "show", iface])
m = re.search(r"inet\s+(\d+\.\d+\.\d+\.\d+)", output)
return m.group(1) if m else None
def iface_type(iface: str) -> str:
"""Classify interface as WiFi, Ethernet, or generic."""
if re.match(r"^(wlan|wlp)", iface):
return "WiFi"
if re.match(r"^(eth|enp|eno|ens)", iface):
return "Ethernet"
return iface
def format_rate(bps: float) -> str:
"""Format bytes-per-second as human-readable with one decimal."""
bps = max(bps, 0)
if bps >= 1_073_741_824:
return f"{bps / 1_073_741_824:.1f}G"
if bps >= 1_048_576:
return f"{bps / 1_048_576:.1f}M"
if bps >= 1024:
return f"{bps / 1024:.1f}K"
return f"{bps:.1f}B"
def parse_args():
p = argparse.ArgumentParser()
p.add_argument("--icon-size", default=DEFAULT_ICON_SIZE,
help="Icon size (Pango size, e.g. 24pt)")
return p.parse_args()
def main() -> None:
args = parse_args()
isize = args.icon_size
iface = get_default_interface()
if iface is None:
print(json.dumps(
{"text": f"{NO_NET_ICON} No net",
"tooltip": "No network connection"},
ensure_ascii=False))
return
ip = get_ip(iface)
if ip is None:
print(json.dumps(
{"text": f"{NO_NET_ICON} No IP",
"tooltip": f"Interface {iface} has no IP"},
ensure_ascii=False))
return
itype = iface_type(iface)
# Read current byte counters
now_ts = time.time_ns()
rx_path = f"/sys/class/net/{iface}/statistics/rx_bytes"
tx_path = f"/sys/class/net/{iface}/statistics/tx_bytes"
try:
with open(rx_path) as f:
now_rx = int(f.read().strip())
with open(tx_path) as f:
now_tx = int(f.read().strip())
except (OSError, ValueError):
now_rx = now_tx = 0
# Transfer rate calculation
rate_down = ""
rate_up = ""
state_file = STATE_FILE_TMPL.format(iface)
if os.path.exists(state_file):
try:
with open(state_file) as f:
prev_rx, prev_tx, prev_ts = map(int, f.read().split())
delta_ns = now_ts - prev_ts
if delta_ns > 0:
delta_rx = now_rx - prev_rx
delta_tx = now_tx - prev_tx
rx_bps = delta_rx * 1e9 / delta_ns
tx_bps = delta_tx * 1e9 / delta_ns
rate_down = format_rate(rx_bps)
rate_up = format_rate(tx_bps)
except (OSError, ValueError):
pass
# Save current state for next run
with open(state_file, "w") as f:
f.write(f"{now_rx} {now_tx} {now_ts}")
# Build output
if rate_down and rate_up:
rate_str = f"{rate_down}{rate_up}"
tooltip_rate = f"{rate_down}/s ↑ {rate_up}/s"
else:
rate_str = ""
tooltip_rate = "↓ ?/s ↑ ?/s"
text = (
f"<span size='{isize}' rise='-1500'>{ICON}</span>"
f" {iface} {ip}{rate_str}"
)
tooltip = f"{itype}: {iface}{ip} | {tooltip_rate}"
print(json.dumps({"text": text, "tooltip": tooltip}, ensure_ascii=False))
if __name__ == "__main__":
main()

97
.config/waybar/network.sh

@ -1,97 +0,0 @@
#!/usr/bin/env bash
# Get the default interface used for routing
INTERFACE=$(ip route 2>/dev/null | grep '^default' | awk '{print $5}' | head -1)
if [ -z "$INTERFACE" ]; then
echo '{"text": "󰖪 No net", "tooltip": "No network connection"}'
exit 0
fi
# Get IPv4 address of the interface
IP=$(ip -4 addr show "$INTERFACE" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
if [ -z "$IP" ]; then
echo '{"text": "󰖪 No IP", "tooltip": "Interface '"$INTERFACE"' has no IP"}'
exit 0
fi
# Determine interface type and set appropriate icon
if [[ "$INTERFACE" =~ ^(wlan|wlp) ]]; then
ICON="󰲝" # generic network icon (nerd font)
TYPE="WiFi"
elif [[ "$INTERFACE" =~ ^(eth|enp|eno|ens) ]]; then
ICON="󰲝" # generic network icon (nerd font)
TYPE="Ethernet"
else
ICON="󰲝" # generic network icon (nerd font)
TYPE="$INTERFACE"
fi
# --- Transfer rate calculation ---
# Path to sysfs statistics
RX_FILE="/sys/class/net/$INTERFACE/statistics/rx_bytes"
TX_FILE="/sys/class/net/$INTERFACE/statistics/tx_bytes"
STATE_FILE="/tmp/waybar-network-stats-$INTERFACE"
# Read current byte counters
NOW_RX=$(cat "$RX_FILE" 2>/dev/null)
NOW_TX=$(cat "$TX_FILE" 2>/dev/null)
NOW_TS=$(date +%s%N) # nanoseconds for precision
# Helper: format bytes/sec to human-readable
format_rate() {
local bytes_per_sec="$1"
if [ "$bytes_per_sec" -lt 0 ]; then
bytes_per_sec=0
fi
if [ "$bytes_per_sec" -ge 1073741824 ]; then
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fG", n / 1073741824 }'
elif [ "$bytes_per_sec" -ge 1048576 ]; then
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fM", n / 1048576 }'
elif [ "$bytes_per_sec" -ge 1024 ]; then
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fK", n / 1024 }'
else
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fB", n }'
fi
}
RATE_DOWN=""
RATE_UP=""
if [ -f "$STATE_FILE" ]; then
# Read previous values: rx tx timestamp_ns
read -r PREV_RX PREV_TX PREV_TS < "$STATE_FILE"
if [ -n "$PREV_RX" ] && [ -n "$PREV_TX" ] && [ -n "$PREV_TS" ]; then
# Calculate time delta in seconds (nanosecond difference)
DELTA_NS=$((NOW_TS - PREV_TS))
if [ "$DELTA_NS" -gt 0 ]; then
DELTA_RX=$((NOW_RX - PREV_RX))
DELTA_TX=$((NOW_TX - PREV_TX))
# bytes per second = delta_bytes / (delta_ns / 1e9)
RX_BPS=$(awk -v rx="$DELTA_RX" -v ns="$DELTA_NS" 'BEGIN { printf "%.0f", rx * 1000000000 / ns }')
TX_BPS=$(awk -v tx="$DELTA_TX" -v ns="$DELTA_NS" 'BEGIN { printf "%.0f", tx * 1000000000 / ns }')
if [ -n "$RX_BPS" ] && [ -n "$TX_BPS" ]; then
RATE_DOWN=$(format_rate "$RX_BPS")
RATE_UP=$(format_rate "$TX_BPS")
fi
fi
fi
fi
# Save current state for next run
echo "$NOW_RX $NOW_TX $NOW_TS" > "$STATE_FILE"
# --- Build output ---
if [ -n "$RATE_DOWN" ] && [ -n "$RATE_UP" ]; then
RATE_STR="${RATE_DOWN}${RATE_UP}"
else
RATE_STR=""
fi
echo "{\"text\": \"<span size='x-large' rise='-1500'>$ICON</span> $INTERFACE $IP${RATE_STR}\", \"tooltip\": \"$TYPE: $INTERFACE$IP | ↓ ${RATE_DOWN:-?}/s ↑ ${RATE_UP:-?}/s\"}"

53
.config/waybar/style.css

@ -1,53 +0,0 @@
* {
font-size: 13px;
font-family: JetBrainsMono NFP;
}
window#waybar {
background: #282828;
color: #fbf1c7;
}
/* All widgets share a stylized rounded background */
#workspaces,
#window,
#clock,
#pulseaudio,
#memory,
#custom-top,
#battery,
#custom-disk,
#custom-network,
#tray {
background: #1d2021;
border-radius: 6px;
margin: 4px 3px;
padding: 0 10px;
color: #f5d67b;
}
#tray {
padding: 0 6px;
}
#pulseaudio.bluetooth {
color: #89b4fa;
}
/* Workspaces: dimmed inactive, bold yellow active */
#workspaces button {
padding: 0 6px;
color: #a89984;
background: transparent;
border-radius: 4px;
}
#workspaces button.focused {
color: #f5d67b;
background: transparent;
font-weight: bold;
}
#workspaces button:hover {
box-shadow: inherit;
text-shadow: inherit;
background: #32302f;
}

30
.config/waybar/top.sh

@ -1,30 +0,0 @@
#!/usr/bin/env bash
# Get the top CPU-consuming process, excluding kernel threads and this script
read -r NAME CPU < <(
ps -eo comm,pcpu --sort=-pcpu --no-headers 2>/dev/null |
awk '{
# Skip kernel threads (names in brackets)
if ($1 ~ /^\[/) next
# Skip this script and ps itself
if ($1 == "top.sh" || $1 == "ps") next
# Output the first matching line and exit
print $1, $2
exit
}'
)
if [ -z "$NAME" ]; then
echo '{"text": " --", "tooltip": "No process data"}'
exit 0
fi
# Round CPU to integer
CPU=$(printf "%.0f" "$CPU")
# Truncate long process names (keep bar readable)
if [ ${#NAME} -gt 10 ]; then
NAME="${NAME:0:9}"
fi
echo "{\"text\": \"<span size='x-large' rise='-1500'>󰍛</span> $NAME ${CPU}%\", \"tooltip\": \"Top CPU: $NAME${CPU}%\"}"

5
.config/waybar/watch.sh

@ -1,5 +0,0 @@
#!/usr/bin/env bash
while inotifywait -e close_write ~/.config/waybar; do
killall -SIGUSR2 waybar
done

21
.config/yazi/flavors/everforest-medium.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 Chromium Oxide
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

21
.config/yazi/flavors/everforest-medium.yazi/LICENSE-tmtheme

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Mitchell Hanberg
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

45
.config/yazi/flavors/everforest-medium.yazi/README.md

@ -1,45 +0,0 @@
<div align="center">
<img src="https://github.com/sxyazi/yazi/blob/main/assets/logo.png?raw=true" alt="Yazi logo" width="20%">
</div>
<h3 align="center">
Example Flavor for <a href="https://github.com/sxyazi/yazi">Yazi</a>
</h3>
## 👀 Preview
<img src="preview.png" width="600" />
## 🎨 Installation
```bash
ya pkg add Chromium-3-Oxide/everforest-medium
```
Or:
```bash
ya pack -a Chromium-3-Oxide/everforest-medium
```
## ⚙ Usage
Add the these lines to your `theme.toml` configuration file to use it:
```toml
[flavor]
dark = "everforest-medium"
```
For Yazi versions before 0.4:
```toml
[flavor]
use = "everforest-medium"
```
## 📜 License
The flavor is MIT-licensed, and the included tmTheme is also MIT-licensed.
Check the [LICENSE](LICENSE) and [LICENSE-tmtheme](LICENSE-tmtheme) file for more details.

179
.config/yazi/flavors/everforest-medium.yazi/flavor.toml

@ -1,179 +0,0 @@
# vim:fileencoding=utf-8:foldmethod=marker
# : Manager {{{
[mgr]
cwd = { fg = "#7fbbb3" }
# Find
find_keyword = { fg = "#dbbc7f", bold = true, italic = true, underline = true }
find_position = { fg = "#d699b6", bg = "reset", bold = true, italic = true }
# Marker
marker_copied = { fg = "#a7c080", bg = "#a7c080" }
marker_cut = { fg = "#e67e80", bg = "#e67e80" }
marker_marked = { fg = "#7fbbb3", bg = "#7fbbb3" }
marker_selected = { fg = "#dbbc7f", bg = "#dbbc7f" }
# Count
count_copied = { fg = "#343f44", bg = "#a7c080" }
count_cut = { fg = "#343f44", bg = "#e67e80" }
count_selected = { fg = "#343f44", bg = "#dbbc7f" }
# Border
border_symbol = "│"
border_style = { fg = "#4f585e" }
# : }}}
# : Tabs {{{
[tabs]
active = { fg = "#343f44", bg = "#a7c080", bold = true }
inactive = { fg = "#a7c080", bg = "#3d484d" }
# : }}}
# : Mode {{{
[mode]
normal_main = { fg = "#3d484d", bg = "#a7c080", bold = true }
normal_alt = { fg = "#7fbbb3", bg = "#4f585e", bold = true }
# Select mode
select_main = { fg = "#3d484d", bg = "#e67e80", bold = true }
select_alt = { fg = "#7fbbb3", bg = "#4f585e", bold = true }
# Unset mode
unset_main = { fg = "#3d484d", bg = "#7fbbb3", bold = true }
unset_alt = { fg = "#7fbbb3", bg = "#4f585e", bold = true }
# : }}}
# : Status bar {{{
[status]
# Permissions
perm_sep = { fg = "#2d353b" }
perm_type = { fg = "#a7c080" }
perm_read = { fg = "#dbbc7f" }
perm_write = { fg = "#e67e80" }
perm_exec = { fg = "#7fbbb3" }
# Progress
progress_label = { bold = true }
progress_normal = { fg = "#7fbbb3", bg = "#232a2e" }
progress_error = { fg = "#e67e80", bg = "#232a2e" }
# : }}}
# : Pick {{{
[pick]
border = { fg = "#7fbbb3" }
active = { fg = "#d699b6", bold = true }
inactive = {}
# : }}}
# : Input {{{
[input]
border = { fg = "#7fbbb3" }
title = {}
value = {}
selected = { reversed = true }
# : }}}
# : Completion {{{
[cmp]
border = { fg = "#7fbbb3" }
# : }}}
# : Tasks {{{
[tasks]
border = { fg = "#7fbbb3" }
title = {}
hovered = { fg = "#d699b6", underline = true }
# : }}}
# : Which {{{
[which]
mask = { bg = "#2d353b" }
cand = { fg = "#7fbbb3" }
rest = { fg = "#2d353b" }
desc = { fg = "#d699b6" }
separator = " "
separator_style = { fg = "#2d353b" }
# : }}}
# : Help {{{
[help]
on = { fg = "#7fbbb3" }
run = { fg = "#d699b6" }
hovered = { reversed = true, bold = true }
footer = { fg = "#2d353b", bg = "#d3c6aa" }
# : }}}
# : Spotter {{{
[spot]
border = { fg = "#7fbbb3" }
title = { fg = "#7fbbb3" }
tbl_col = { fg = "#7fbbb3" }
tbl_cell = { fg = "#dbbc7f", reversed = true }
# : }}}
# : Notification {{{
[notify]
title_info = { fg = "#a7c080" }
title_warn = { fg = "#dbbc7f" }
title_error = { fg = "#e67e80" }
# : }}}
# : File-specific styles {{{
[filetype]
rules = [
# Images
{ mime = "image/*", fg = "#7fbbb3" },
# Media
{ mime = "{audio,video}/*", fg = "#d699b6" },
# Archives
{ mime = "application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}", fg = "#e67e80" },
# Documents
{ mime = "application/{pdf,doc,rtf}", fg = "#7fbbb3" },
# Virtual file system
{ mime = "vfs/{absent,stale}", fg = "#4f585e" },
# Fallback
{ url = "*", fg = "#83c092" },
{ url = "*/", fg = "#a7c080" },
]
# : }}}

BIN
.config/yazi/flavors/everforest-medium.yazi/preview.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

3186
.config/yazi/flavors/everforest-medium.yazi/tmtheme.xml

File diff suppressed because it is too large Load Diff

21
.config/yazi/flavors/gruvbox-material.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 - Matthew Dong
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

201
.config/yazi/flavors/gruvbox-material.yazi/LICENSE-tmtheme

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

42
.config/yazi/flavors/gruvbox-material.yazi/README.md

@ -1,42 +0,0 @@
<div align="center">
<img src="https://github.com/sxyazi/yazi/blob/main/assets/logo.png?raw=true" alt="Yazi logo" width="20%">
</div>
<h3 align="center">
Gruvbox Material Flavor for <a href="https://github.com/sxyazi/yazi">Yazi</a>
</h3>
## 👀 Preview
![gruvbox-material](./preview.png)
## 🎨 Installation
### Using package manager
```bash
ya pkg add matt-dong-123/gruvbox-material
```
### Manual install
```bash
# Linux/macOS
git clone https://github.com/matt-dong-123/gruvbox-material.yazi.git ~/.config/yazi/flavors/gruvbox-material.yazi
# Windows
git clone https://github.com/matt-dong-123/gruvbox-material.yazi.git %AppData%\yazi\config\flavors\gruvbox-material.yazi
```
## ⚙ Usage
Add the these lines to your `theme.toml` configuration file to use it:
```toml
[flavor]
dark = "gruvbox-material"
```
## 📜 License
Check the [LICENSE](LICENSE) file for more details.

214
.config/yazi/flavors/gruvbox-material.yazi/flavor.toml

@ -1,214 +0,0 @@
# vim:fileencoding=utf-8:foldmethod=marker
# : Manager {{{
[mgr]
cwd = { fg = "#89b482" }
# Find
find_keyword = { fg = "#d8a657", bold = true, italic = true, underline = true }
find_position = { fg = "#d3869b", bg = "reset", bold = true, italic = true }
# Marker
marker_copied = { fg = "#a9b665", bg = "#a9b665" }
marker_cut = { fg = "#ea6962", bg = "#ea6962" }
marker_marked = { fg = "#89b482", bg = "#89b482" }
marker_selected = { fg = "#d8a657", bg = "#d8a657" }
# Count
count_copied = { fg = "#282828", bg = "#a9b665" }
count_cut = { fg = "#282828", bg = "#ea6962" }
count_selected = { fg = "#282828", bg = "#d8a657" }
# Border
border_symbol = "│"
border_style = { fg = "#928374" }
# : }}}
# : Tabs {{{
[tabs]
active = { fg = "#282828", bg = "#7daea3", bold = true }
inactive = { fg = "#7daea3", bg = "#32302f" }
# : }}}
# : Mode {{{
[mode]
normal_main = { fg = "#282828", bg = "#7daea3", bold = true }
normal_alt = { fg = "#7daea3", bg = "#32302f" }
# Select mode
select_main = { fg = "#282828", bg = "#89b482", bold = true }
select_alt = { fg = "#89b482", bg = "#32302f" }
# Unset mode
unset_main = { fg = "#282828", bg = "#ea6962", bold = true }
unset_alt = { fg = "#ea6962", bg = "#32302f" }
# : }}}
# : Status bar {{{
[status]
# Permissions
perm_sep = { fg = "#928374" }
perm_type = { fg = "#7daea3" }
perm_read = { fg = "#d8a657" }
perm_write = { fg = "#ea6962" }
perm_exec = { fg = "#a9b665" }
# Progress
progress_label = { fg = "#ddc7a1", bold = true }
progress_normal = { fg = "#a9b665", bg = "#45403d" }
progress_error = { fg = "#d8a657", bg = "#ea6962" }
# : }}}
# : Pick {{{
[pick]
border = { fg = "#7daea3" }
active = { fg = "#d3869b", bold = true }
inactive = {}
# : }}}
# : Input {{{
[input]
border = { fg = "#7daea3" }
title = {}
value = {}
selected = { reversed = true }
# : }}}
# : Completion {{{
[cmp]
border = { fg = "#7daea3" }
# : }}}
# : Tasks {{{
[tasks]
border = { fg = "#7daea3" }
title = {}
hovered = { fg = "#d3869b", bold = true }
# : }}}
# : Which {{{
[which]
mask = { bg = "#32302f" }
cand = { fg = "#89b482" }
rest = { fg = "#a89984" }
desc = { fg = "#d3869b" }
separator = " "
separator_style = { fg = "#7c6f64" }
# : }}}
# : Help {{{
[help]
on = { fg = "#89b482" }
run = { fg = "#d3869b" }
hovered = { reversed = true, bold = true }
footer = { fg = "#32302f", bg = "#d4be98" }
# : }}}
# : Spotter {{{
[spot]
border = { fg = "#7daea3" }
title = { fg = "#7daea3" }
tbl_col = { fg = "#89b482" }
tbl_cell = { fg = "#d3869b", bg = "#45403d" }
# : }}}
# : Notification {{{
[notify]
title_info = { fg = "#a9b665" }
title_warn = { fg = "#d8a657" }
title_error = { fg = "#ea6962" }
# : }}}
# : File-specific styles {{{
[filetype]
rules = [
# Image
{ mime = "image/*", fg = "#89b482" },
# Media
{ mime = "{audio,video}/*", fg = "#d8a657" },
# Archive
{ mime = "application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}", fg = "#d3869b" },
# Document
{ mime = "application/{pdf,doc,rtf}", fg = "#a9b665" },
# Virtual file system
{ mime = "vfs/{absent,stale}", fg = "#a89984" },
# Fallback
{ url = "*", fg = "#d4be98" },
{ url = "*/", fg = "#7daea3" },
]
# : }}}
[icon]
dirs = [
{ name = ".config", text = "", fg = "#d3869b" },
{ name = ".git", text = "", fg = "#89b482" },
{ name = ".github", text = "", fg = "#7daea3" },
{ name = ".npm", text = "", fg = "#7daea3" },
{ name = "Desktop", text = "", fg = "#89b482" },
{ name = "Development", text = "", fg = "#89b482" },
{ name = "Documents", text = "", fg = "#89b482" },
{ name = "Downloads", text = "", fg = "#89b482" },
{ name = "Library", text = "", fg = "#89b482" },
{ name = "Movies", text = "", fg = "#89b482" },
{ name = "Music", text = "", fg = "#89b482" },
{ name = "Pictures", text = "", fg = "#89b482" },
{ name = "Public", text = "", fg = "#89b482" },
{ name = "Videos", text = "", fg = "#89b482" },
]
conds = [
# Special files
{ if = "orphan", text = "", fg = "#d4be98" },
{ if = "link", text = "", fg = "#928374" },
{ if = "block", text = "", fg = "#ea6962" },
{ if = "char", text = "", fg = "#ea6962" },
{ if = "fifo", text = "", fg = "#ea6962" },
{ if = "sock", text = "", fg = "#ea6962" },
{ if = "sticky", text = "", fg = "#ea6962" },
{ if = "dummy", text = "", fg = "#ea6962" },
# Fallback
{ if = "dir", text = "", fg = "#7daea3" },
{ if = "exec", text = "", fg = "#a9b665" },
{ if = "!dir", text = "", fg = "#d4be98" },
]

BIN
.config/yazi/flavors/gruvbox-material.yazi/preview.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

1376
.config/yazi/flavors/gruvbox-material.yazi/tmtheme.xml

File diff suppressed because it is too large Load Diff

11
.config/yazi/init.lua

@ -1,11 +0,0 @@
require("full-border"):setup({
-- Available values: ui.Border.PLAIN, ui.Border.ROUNDED
type = ui.Border.ROUNDED,
})
require("git"):setup({
-- Order of status signs showing in the linemode
order = 1500,
})
-- require("relative-motions"):setup({ show_numbers = "relative", show_motion = true, enter_mode = "first" })

56
.config/yazi/keymap.toml

@ -1,56 +0,0 @@
[[mgr.prepend_keymap]]
on = "M"
run = "plugin mount"
# [[mgr.prepend_keymap]]
# on = [ "m" ]
# run = "plugin relative-motions"
# desc = "Trigger a new relative motion"
[[mgr.prepend_keymap]]
on = "f"
run = "plugin jump-to-char"
desc = "Jump to char"
[[mgr.prepend_keymap]]
on = "F"
run = "filter --smart"
desc = "Filter files"
[[mgr.prepend_keymap]]
on = "l"
run = "plugin smart-enter"
desc = "Enter the child directory, or open the file"
[[mgr.prepend_keymap]]
on = [ "C" ]
run = "plugin chmod"
desc = "Chmod on selected files"
[[mgr.prepend_keymap]]
on = "+"
run = "plugin zoom 1"
desc = "Zoom in hovered file"
[[mgr.prepend_keymap]]
on = "-"
run = "plugin zoom -1"
desc = "Zoom out hovered file"
# [[mgr.prepend_keymap]]
# on = "o"
# run = "plugin open-with-cmd -- block"
# desc = "Open with command in the terminal"
[[mgr.prepend_keymap]]
on = "L"
run = "plugin open-with-cmd"
desc = "Open with command"
[[mgr.prepend_keymap]]
on = "<C-d>"
run = "plugin diff"
desc = "Diff the selected with the hovered file"

69
.config/yazi/package.toml

@ -1,69 +0,0 @@
[[plugin.deps]]
use = "yazi-rs/plugins:mount"
rev = "598cdb6"
hash = "e3260d0b1feded8c8e3ae3afa1169e30"
[[plugin.deps]]
use = "yazi-rs/plugins:smart-enter"
rev = "598cdb6"
hash = "187cc58ba7ac3befd49c342129e6f1b6"
[[plugin.deps]]
use = "yazi-rs/plugins:full-border"
rev = "598cdb6"
hash = "7b625412411be411153886894d9acaf"
[[plugin.deps]]
use = "yazi-rs/plugins:git"
rev = "598cdb6"
hash = "88e56a64b7ce7c4314427452343fef17"
[[plugin.deps]]
use = "yazi-rs/plugins:chmod"
rev = "598cdb6"
hash = "f0c8c378184d5f8abd1b095a443d336d"
[[plugin.deps]]
use = "yazi-rs/plugins:zoom"
rev = "598cdb6"
hash = "fa268cb59989a87780605fdcfb8d99a9"
[[plugin.deps]]
use = "yazi-rs/plugins:piper"
rev = "598cdb6"
hash = "d99cfbc3812e7738505f9e4bedb759cd"
[[plugin.deps]]
use = "boydaihungst/gvfs"
rev = "3abc0a2"
hash = "eed89e75671723c8f9390a2862af0e4e"
[[plugin.deps]]
use = "Ape/open-with-cmd"
rev = "eba191d"
hash = "722a60eca1b338c9c24bb508d2d48578"
[[plugin.deps]]
use = "yazi-rs/plugins:diff"
rev = "598cdb6"
hash = "8b1af6b5a69797ee951f2a80ce570818"
[[plugin.deps]]
use = "dedukun/relative-motions"
rev = "a603d9e"
hash = "e02a788e5b8ae0fb47fd0193dda589cc"
[[plugin.deps]]
use = "yazi-rs/plugins:jump-to-char"
rev = "598cdb6"
hash = "7a4b4237223aaa94e589d1c01a23542a"
[[flavor.deps]]
use = "Chromium-3-Oxide/everforest-medium"
rev = "e1ead7b"
hash = "f7dc46200e53da5e94858630184a9220"
[[flavor.deps]]
use = "matt-dong-123/gruvbox-material"
rev = "e0fd2d8"
hash = "8f46ca96c0bbe1bdfb4fa201dd5eed4b"

21
.config/yazi/plugins/chmod.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

28
.config/yazi/plugins/chmod.yazi/README.md

@ -1,28 +0,0 @@
# chmod.yazi
Execute `chmod` on the selected files to change their mode. This plugin is only available on Unix platforms since it relies on [`chmod(2)`](https://man7.org/linux/man-pages/man2/chmod.2.html).
https://github.com/yazi-rs/plugins/assets/17523360/7aa3abc2-d057-498c-8473-a6282c59c464
## Installation
```sh
ya pkg add yazi-rs/plugins:chmod
```
## Usage
Add this to your `~/.config/yazi/keymap.toml`:
```toml
[[mgr.prepend_keymap]]
on = [ "c", "m" ]
run = "plugin chmod"
desc = "Chmod on selected files"
```
Note that, the keybindings above are just examples, please tune them up as needed to ensure they don't conflict with your other actions/plugins.
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

47
.config/yazi/plugins/chmod.yazi/main.lua

@ -1,47 +0,0 @@
--- @since 26.1.22
local selected_or_hovered = ya.sync(function()
local tab, paths = cx.active, {}
for _, u in pairs(tab.selected) do
paths[#paths + 1] = tostring(u)
end
if #paths == 0 and tab.current.hovered then
paths[1] = tostring(tab.current.hovered.url)
end
return paths
end)
local function fail(s, ...)
ya.notify {
title = "Chmod",
content = string.format(s, ...),
level = "error",
timeout = 5,
}
end
return {
entry = function()
ya.emit("escape", { visual = true })
local urls = selected_or_hovered()
if #urls == 0 then
return ya.notify { title = "Chmod", content = "No file selected", level = "warn", timeout = 5 }
end
local value, event = ya.input {
title = "Chmod:",
pos = { "top-center", y = 3, w = 40 },
}
if event ~= 1 then
return
end
local output, err = Command("chmod"):arg(value):arg(urls):output()
if not output then
fail("Failed to run chmod: %s", err)
elseif not output.status.success then
fail("Chmod failed with stderr:\n%s", output.stderr:gsub("^chmod:%s*", ""))
end
end,
}

21
.config/yazi/plugins/diff.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

28
.config/yazi/plugins/diff.yazi/README.md

@ -1,28 +0,0 @@
# diff.yazi
Diff the selected file with the hovered file, create a living patch, and copy it to the clipboard.
https://github.com/yazi-rs/plugins/assets/17523360/eff5e949-386a-44ea-82f9-4cb4a2c37aad
## Installation
```sh
ya pkg add yazi-rs/plugins:diff
```
## Usage
Add this to your `~/.config/yazi/keymap.toml`:
```toml
[[mgr.prepend_keymap]]
on = "<C-d>"
run = "plugin diff"
desc = "Diff the selected with the hovered file"
```
Note that, the keybindings above are just examples, please tune them up as needed to ensure they don't conflict with your other actions/plugins.
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

41
.config/yazi/plugins/diff.yazi/main.lua

@ -1,41 +0,0 @@
--- @since 26.1.22
local function info(content)
return ya.notify {
title = "Diff",
content = content,
timeout = 5,
}
end
local selected_path = ya.sync(function()
for _, u in pairs(cx.active.selected) do
return u.cache or u
end
end)
local hovered_path = ya.sync(function()
local h = cx.active.current.hovered
return h and h.path
end)
return {
entry = function()
local a, b = selected_path(), hovered_path()
if not a then
return info("No file selected")
elseif not b then
return info("No file hovered")
end
local output, err = Command("diff"):arg("-Naur"):arg(tostring(a)):arg(tostring(b)):output()
if not output then
return info("Failed to run diff, error: " .. err)
elseif output.stdout == "" then
return info("No differences found")
end
ya.clipboard(output.stdout)
info("Diff copied to clipboard")
end,
}

21
.config/yazi/plugins/full-border.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

32
.config/yazi/plugins/full-border.yazi/README.md

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

44
.config/yazi/plugins/full-border.yazi/main.lua

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

21
.config/yazi/plugins/git.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

86
.config/yazi/plugins/git.yazi/README.md

@ -1,86 +0,0 @@
# git.yazi
Show the status of Git file changes as linemode in the file list.
https://github.com/user-attachments/assets/34976be9-a871-4ffe-9d5a-c4cdd0bf4576
## Installation
```sh
ya pkg add yazi-rs/plugins:git
```
## Setup
Add the following to your `~/.config/yazi/init.lua`:
```lua
require("git"):setup {
-- Order of status signs showing in the linemode
order = 1500,
}
```
And register it as fetchers in your `~/.config/yazi/yazi.toml`:
```toml
[[plugin.prepend_fetchers]]
id = "git" # Remove if Yazi > v26.1.22
url = "*"
run = "git"
group = "git"
[[plugin.prepend_fetchers]]
id = "git" # Remove if Yazi > v26.1.22
url = "*/"
run = "git"
group = "git"
```
## Advanced
You can customize the [Style](https://yazi-rs.github.io/docs/configuration/theme#types.style) of the status sign with:
- `[git].unknown` - status cannot/not yet determined
- `[git].modified` - modified file
- `[git].added` - added file
- `[git].untracked` - untracked file
- `[git].ignored` - ignored file
- `[git].deleted` - deleted file
- `[git].updated` - updated file
- `[git].clean` - clean file
For example:
```toml
# theme.toml / flavor.toml
[git]
modified = { fg = "blue" }
deleted = { fg = "red", bold = true }
```
You can also customize the text of the status sign with:
- `[git].unknown_sign` - status cannot/not yet determined
- `[git].modified_sign` - modified file
- `[git].added_sign` - added file
- `[git].untracked_sign` - untracked file
- `[git].ignored_sign` - ignored file
- `[git].deleted_sign` - deleted file
- `[git].updated_sign` - updated file
- `[git].clean_sign` - clean file
For example:
```toml
# theme.toml / flavor.toml
[git]
unknown_sign = " "
modified_sign = "M"
deleted_sign = "D"
clean_sign = "✔"
```
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

259
.config/yazi/plugins/git.yazi/main.lua

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

12
.config/yazi/plugins/git.yazi/types.lua

@ -1,12 +0,0 @@
---@class State
---@field dirs table<string, string|CODES> Mapping between a directory and its corresponding repository
---@field repos table<string, Changes> Mapping between a repository and the status of each of its files
---@class Options
---@field order number The order in which the status is displayed
---@field renamed boolean Whether to include renamed files in the status (or treat them as modified)
-- TODO: move this to `types.yazi` once it's get stable
---@alias UnstableFetcher fun(self: unknown, job: { files: File[] }): boolean, Error?
---@alias Changes table<string, CODES>

21
.config/yazi/plugins/gvfs.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2025 boydaihungst
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

324
.config/yazi/plugins/gvfs.yazi/README.md

@ -1,324 +0,0 @@
# gvfs.yazi
<!-- toc -->
- [Preview](#preview)
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
- [Note for mounting using fstab](#note-for-mounting-using-fstab)
- [Troubleshooting](#troubleshooting)
<!-- tocstop -->
[gvfs.yazi](https://github.com/boydaihungst/gvfs.yazi) uses [gvfs](https://wiki.gnome.org/Projects/gvfs) and [gio from glib](https://github.com/GNOME/glib) to transparently mount and unmount devices or remote storage in read and write mode,
allowing you to navigate inside, view, and edit individual or groups of files and folders.
Supported protocols: MTP, Hard disk/drive, SMB, SFTP, NFS, GPhoto2 (PTP), FTP, Google Drive (via [GOA](./GNOME_ONLINE_ACCOUNTS_GOA.md)), One drive (via [GOA](./GNOME_ONLINE_ACCOUNTS_GOA.md)), DNS-SD, DAV (WebDAV), AFP, AFC. You need to install corresponding packages to use them.
Tested: MTP, Hard disk/drive (Encrypted and Unencrypted), GPhoto2 (PTP), DAV, SFTP, FTP, SMB, NFSv4, Google Drive, One Drive. You may need to unlock and turn screen on to mount some devices (Android MTP, etc.)
> [!NOTE]
>
> - This plugin only supports Linux
## Preview
https://github.com/user-attachments/assets/6aad98f7-081a-4e06-b398-5f7e8ca4ab39
Google-drive:
https://github.com/user-attachments/assets/fb74a710-5f05-4bf4-b95f-10f40583c5a0
## Features
- Supports all gvfs schemes/protocols (mtp, smb, ftp, sftp, nfs, gphoto2, afp, afc, sshfs, dav, davs, dav+sd, davs+sd, dns-sd)
- Mount hardware device or saved scheme/mount URI (use `--select-then-mount`)
- Auto-jump to mounted location after mount (use `select-then-mount --jump`)
- Unmount and eject hardware devices (use `select-then-unmount --eject`)
- Auto select the first device or saved scheme/mount URI if there is only one listed.
- Jump to mounted location (use `jump-to-device`)
- After jumped to mounted location, jump back to the previous location
with a single keybind. Make it easier to copy/paste files. (use `jump-back-prev-cwd`)
- Add/Edit/Remove scheme/mount URI (use `add-mount`, `edit-mount`, `remove-mount`). Check this for schemes/mount URI format: [schemes.html](<https://wiki.gnome.org/Projects(2f)gvfs(2f)schemes.html>)
- (Optional) Remember passwords using Keyring or Password Store (need `secret-tool` + `keyring` or `pass` + `gpg` installed)
## Requirements
1. [yazi >= 25.5.31](https://github.com/sxyazi/yazi)
2. This plugin only supports Linux, and requires having [GLib](https://github.com/GNOME/glib), [gvfs](https://gitlab.gnome.org/GNOME/gvfs) (need D-Bus Session)
```sh
# Ubuntu
sudo apt install gvfs libglib2.0-dev
# Fedora
sudo dnf install gvfs gvfs-fuse
# Arch
sudo pacman -S gvfs glib2
# Gentoo (Use elogind (openrc) or systemd)
# Add fuse USE flag to /etc/portage/package.use/gvfs.conf:
gnome-base/gvfs fuse
# Then run this to install gvfs:
sudo emerge -av gnome-base/gvfs
```
3. And other `gvfs` protocol packages, choose what you need, all of them are optional:
```sh
# Ubuntu
# This included all protocols
sudo apt install gvfs-backends gvfs-libs
# Fedora
sudo dnf install gvfs-afc gvfs-afp gvfs-archive gvfs-goa gvfs-gphoto2 gvfs-mtp gvfs-nfs gvfs-smb
# Arch
sudo pacman -S gvfs-mtp gvfs-afc gvfs-google gvfs-gphoto2 gvfs-nfs gvfs-smb gvfs-afc gvfs-dnssd gvfs-goa gvfs-onedrive gvfs-wsdd
# Gentoo
# Edit /etc/portage/package.use/gvfs.conf again, add more USE flags:
# https://wiki.gentoo.org/wiki/GVfs
gnome-base/gvfs afp gnome-online-accounts google ios mtp nfs onedrive samba zeroconf fuse gphoto2
# Then run this to update gvfs:
sudo emerge -av gnome-base/gvfs
```
4. For headless session (non-active console, like connect to a computer via SSH, etc.)
If you see `GVFS.yazi can only run on DBUS session` error message, please refer to [HEADLESS_WORKAROUND.md](./HEADLESS_WORKAROUND.md) for a workaround.
5. (Optional) Store passwords with Keyring or Password Store (secret-tool + keyring or pass + gpg)
There are two methods to securely store passwords. Please refer to [SECURE_SAVED_PASSWORD.md](./SECURE_SAVED_PASSWORD.md) for more information.
6. Restart to make sure gvfs deamon is started.
## Installation
```sh
ya pkg add boydaihungst/gvfs
```
Modify your `~/.config/yazi/init.lua` to include (`setup` function is required):
```lua
require("gvfs"):setup({
-- (Optional) Allowed keys to select device.
which_keys = "1234567890qwertyuiopasdfghjklzxcvbnm-=[]\\;',./!@#$%^&*()_+{}|:\"<>?",
-- (Optional) Table of blacklisted devices. These devices will be ignored in any actions
-- List of device properties to match, or a string to match the device name:
-- https://github.com/boydaihungst/gvfs.yazi/blob/master/main.lua#L144
blacklist_devices = { { name = "Wireless Device", scheme = "mtp" }, { scheme = "file" }, "Device Name"},
-- (Optional) Save file.
-- Default: ~/.config/yazi/gvfs.private
save_path = os.getenv("HOME") .. "/.config/yazi/gvfs.private",
-- (Optional) Save file for automount devices. Use with `automount-when-cd` action.
-- Default: ~/.config/yazi/gvfs_automounts.private
save_path_automounts = os.getenv("HOME") .. "/.config/yazi/gvfs_automounts.private",
-- (Optional) Input box position.
-- Default: { "top-center", y = 3, w = 60 },
-- Position, which is a table:
-- `1`: Origin position, available values: "top-left", "top-center", "top-right",
-- "bottom-left", "bottom-center", "bottom-right", "center", and "hovered".
-- "hovered" is the position of hovered file/folder
-- `x`: X offset from the origin position.
-- `y`: Y offset from the origin position.
-- `w`: Width of the input.
-- `h`: Height of the input.
input_position = { "center", y = 0, w = 60 },
-- (Optional) Select where to save passwords.
-- Default: nil
-- Available options: "keyring", "pass", or nil
password_vault = "keyring",
-- (Optional) Only need if you set password_vault = "pass"
-- Read the guide at SECURE_SAVED_PASSWORD.md to get your key_grip
key_grip = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
-- (Optional) Auto-save password after mount.
-- Default: false
save_password_autoconfirm = true,
-- (Optional) mountpoint of gvfs. Default: /run/user/USER_ID/gvfs
-- On some system it could be ~/.gvfs
-- You can't decide this path, it will be created automatically. Only changed if you know where gvfs mountpoint is.
-- Use command `ps aux | grep gvfs` to search for gvfs process and get the mountpoint path.
-- root_mountpoint = (os.getenv("XDG_RUNTIME_DIR") or ("/run/user/" .. ya.uid())) .. "/gvfs"
})
```
## Usage
> [!NOTE]
>
> - Moving files to the Trash bin does not work with some protocols (e.g., Android MTP). Please use permanent delete instead.
> - Scheme/Mount URIs shouldn't contain password, because they are saved as plain text in `yazi/config/gvfs.private`.
> - Google Drive, One drive are created via GNOME Online Accounts (GOA).
> Guide to setup [GNOME_ONLINE_ACCOUNTS_GOA.md](./GNOME_ONLINE_ACCOUNTS_GOA.md)
> - MTP, GPhoto2, AFC, Hard disk/drive, fstab with x-gvfs-show mount option, Google Drive + One drive protocols are listed automatically. So you don't need to add them via `add-mount` command.
> For other protocols (smb, ftp, sftp, etc), use `add-mount` command to add [Schemes/Mount URI](<https://wiki.gnome.org/Projects(2f)gvfs(2f)schemes.html>).
> - There is a bug in Yazi that prevents mounted folders from refreshing after they are mounted/unmounted.
> If you encounter this issue, try opening a new tab or moving the cursor up and down to trigger a refresh.
> - Mount Windows bitlocker drives requires bitlocker password to unlock: https://aka.ms/myrecoverykey or https://support.microsoft.com/en-us/windows/find-your-bitlocker-recovery-key-6b71ad27-0b89-ea08-f143-056f5ab347d6
> - Mount hard drives may require polkit rule to fix permission denied error. Refer to [HEADLESS_WORKAROUND.md](./HEADLESS_WORKAROUND.md) for a workaround.
Add this to your `~/.config/yazi/keymap.toml`:
```toml
[mgr]
prepend_keymap = [
# Mount
{ on = [ "M", "m" ], run = "plugin gvfs -- select-then-mount", desc = "Select device then mount" },
# or this if you want to jump to mountpoint after mounted
{ on = [ "M", "m" ], run = "plugin gvfs -- select-then-mount --jump", desc = "Select device to mount and jump to its mount point" },
# This will remount device under current working directory (cwd)
# -> cwd = /run/user/1000/gvfs/DEVICE_1/FOLDER_A
# -> device mountpoint = /run/user/1000/gvfs/DEVICE_1
# -> remount this DEVIEC_1 if needed
{ on = [ "M", "R" ], run = "plugin gvfs -- remount-current-cwd-device", desc = "Remount device under cwd" },
{ on = [ "M", "u" ], run = "plugin gvfs -- select-then-unmount", desc = "Select device then unmount" },
# Or this if you want to unmount and eject device.
# -> Ejected device can safely be removed.
# -> Ejecting a device will unmount all paritions/volumes under it.
# -> Fallback to normal unmount if not supported by device.
{ on = [ "M", "u" ], run = "plugin gvfs -- select-then-unmount --eject", desc = "Select device then eject" },
# Also support force unmount/eject.
# -> Ignore outstanding file operations when unmounting or ejecting
{ on = [ "M", "U" ], run = "plugin gvfs -- select-then-unmount --eject --force", desc = "Select device then force to eject/unmount" },
# Add Scheme/Mount URI:
# -> Available schemes: mtp, gphoto2, smb, sftp, ftp, nfs, dns-sd, dav, davs, dav+sd, davs+sd, afp, afc, sshfs
# -> Read more about the schemes here: https://wiki.gnome.org/Projects(2f)gvfs(2f)schemes.html
# -> Explain about the scheme:
# -> If it shows like this: {ftp,ftps,ftpis}://[user@]host[:port]
# -> All of the value within [] is optional. For values within {}, you must choose exactly one. All others are required.
# -> empty [user] or "anonymous" user is anonymous user in (ftp)
# -> ftp://anonymous@192.168.1.2:9999 -> skip user input step.
# -> ftp://192.168.1.2:9999 -> input empty value in user input box.
# -> Example: {ftp,ftps,ftpis}://[user@]host[:port] => ip and port: "ftp://myusername@192.168.1.2:9999" or domain: "ftps://myusername@github.com"
# -> More examples: smb://user@192.168.1.2/share, smb://WORKGROUP;user@192.168.1.2/share, sftp://user@192.168.1.2/, ftp://192.168.1.2/
# !WARNING: - Scheme/Mount URI shouldn't contain password.
# - Google Drive, One drive are listed automatically via GNOME Online Accounts (GOA). Avoid adding them.
# - MTP, GPhoto2, AFC, Hard disk/drive, fstab with x-gvfs-show are also listed automatically. Avoid adding them.
# - SSH, SFTP, FTP(s), AFC, DNS_SD now support [/share]. For example: sftp://user@192.168.1.2/home/user_name -> /share = /home/user_name
# - ssh:// is alias for sftp://.
# -> {sftp,ssh}://[user@]host[:port]. Host can be Host alias in .ssh/config file, ip or domain.
# -> For example (home is Host alias in .ssh/config file: Host home):
# -> ssh://user_name@home/home/user_name -> this will mount root path, but jump to subfolder /home/user_name
# -> sftp://user_name@192.168.1.2/home/user_name -> same as above but with ip
# -> sftp://user_name@192.168.1.2:9999/home/user_name -> same as above but with ip and port
{ on = [ "M", "a" ], run = "plugin gvfs -- add-mount", desc = "Add a GVFS mount URI" },
# Edit a Scheme/Mount URI
# -> Will clear saved passwords for that mount URI.
{ on = [ "M", "e" ], run = "plugin gvfs -- edit-mount", desc = "Edit a GVFS mount URI" },
# Remove a Scheme/Mount URI
# -> Will clear saved passwords for that mount URI.
{ on = [ "M", "r" ], run = "plugin gvfs -- remove-mount", desc = "Remove a GVFS mount URI" },
# Jump
{ on = [ "g", "m" ], run = "plugin gvfs -- jump-to-device", desc = "Select device then jump to its mount point" },
# If you use `x-systemd.automount` in /etc/fstab or manually added automount unit,
# then you can use `--automount` argument to auto mount device before jump.
# Otherwise it won't show up in the jump list.
{ on = [ "g", "m" ], run = "plugin gvfs -- jump-to-device --automount", desc = "Automount then select device to jump to its mount point" },
{ on = [ "`", "`" ], run = "plugin gvfs -- jump-back-prev-cwd", desc = "Jump back to the position before jumped to device" },
# Automount (This is different from `x-systemd.automount` in /etc/fstab)
# -> Hover over any file/folder under a mounted device then run `automount-when-cd` action to enable automount when cd/jump for that device.
# -> When you cd/jump to unmounted device mountpoint or its sub folder, this will auto-mount the device before jump.
# -> Works with any command or any bookmark plugin that change cwd. For example, use `yamb` to add bookmarks and jump to them, use yazi's built-in `cd` `back` `forward` commands:
# -> { on = [ "m", "a" ], run = [ "plugin yamb -- save", "plugin gvfs -- automount-when-cd" ], desc = "Add bookmark and enable automount when cd"}
{ on = [ "M", "t" ], run = "plugin gvfs -- automount-when-cd", desc = "Enable automount when cd to device under cwd" },
{ on = [ "M", "T" ], run = "plugin gvfs -- automount-when-cd --disabled", desc = "Disable automount when cd to device under cwd" },
]
```
It's highly recommended to add these lines to your `~/.config/yazi/yazi.toml`,
because GVFS is slow that can make yazi freeze when it preloads or previews a large number of files.
Especially when you use `Google-drive` or `One-drive`.
- Replace `1000` with your real user id (run `id -u` to get user id).
- Replace `USER_NAME` with your real user name (run `whoami` to get username).
> [!IMPORTANT]
>
> For yazi (>=v25.12.29) replace `name` with `url`
```toml
[plugin]
prepend_preloaders = [
# Do not preload files in mounted locations:
# Environment variable won't work here.
# Using absolute path instead.
{ name = "/run/user/1000/gvfs/**/*", run = "noop" },
# For mounted hard disk/drive
{ name = "/run/media/USER_NAME/**/*", run = "noop" },
]
prepend_previewers = [
# Allow to preview folder.
{ name = "*/", run = "folder" },
# Do not previewing files in mounted locations.
# Uncomment the line below to allow previewing text files.
# { mime = "{text/*,application/x-subrip}", run = "code" },
# Using absolute path.
{ name = "/run/user/1000/gvfs/**/*", run = "noop" },
# For mounted hard disk/drive.
{ name = "/run/media/USER_NAME/**/*", run = "noop" },
]
```
## Note for mounting using fstab
If you are using fstab to mount, you need to add `x-gvfs-show` to the mount options.
And with it you can only use `jump-to-device` and `jump-back-prev-cwd` actions.
- Example `/etc/fstab`:
- Mount on demand (manually mount):
```
192.168.1.10/hdd /mnt/myshare cifs noauto,credentials=/etc/samba/credentials,x-gvfs-show,iocharset=utf8,uid=1000,gid=1000,file_mode=0660,dir_mode=0770,nofail 0 0
UUID=XXXX-XXXX /mnt/myshare2 exfat noauto,defaults,x-gvfs-show 0 0
```
- Mount on access, add `x-systemd-automount` to the mount options:
Use `jump-to-device --automount`.
This will auto mount all mount entries that have `x-systemd-automount`, before jump to.
- Mount at boot, remove `noauto` from the mount options
Reload fstab:
```sh
sudo systemctl daemon-reload && sudo systemctl restart local-fs.target && sudo mount -a
```
If you changed mount options (like uid=, gid=, umask=, exfat, ntfs, etc.), already-mounted filesystems won't update unless you unmount and remount them.
You can manually remount a specific entry with these commands:
```sh
sudo umount /mnt/myshare
sudo mount -a
```
## Troubleshooting
If you have any problems with one of the protocols, please manually mount it using `gio mount Scheme/Mount URI`. See the [list of supported schemes](<https://wiki.gnome.org/Projects(2f)gvfs(2f)schemes.html>).
Then create an issue ticket and include the output of `gio mount -li` along with the list of mount points under `/run/user/1000/gvfs/` and `/run/media/USERNAME`

23
.config/yazi/plugins/gvfs.yazi/assets/automount.sh

@ -1,23 +0,0 @@
#!/bin/sh
# Iterate over all automount units
for unit in $(systemctl list-units --type=automount --no-legend | awk '{print $1}'); do
# Extract the mount path from the unit name
path=$(systemctl show -p Where --value "$unit")
# Skip certain system directories
case "$path" in
/proc* | /sys* | /dev*) continue ;;
esac
# Derive the corresponding .mount unit name from the path
mount_unit=$(systemd-escape -p --suffix=mount "$path")
# Check if the .mount unit is active (i.e., the filesystem is mounted)
if systemctl is-active --quiet "$mount_unit"; then
continue
fi
# If not mounted, log and then access the directory to trigger the automount
ls "$path" >/dev/null 2>&1 &
done

9
.config/yazi/plugins/gvfs.yazi/assets/gnome-keyring-daemon.service

@ -1,9 +0,0 @@
[Unit]
Description=GNOME Keyring Daemon
[Service]
ExecStart=/usr/bin/gnome-keyring-daemon --foreground --components=secrets,pkcs11,ssh
Restart=on-failure
[Install]
WantedBy=default.target

2530
.config/yazi/plugins/gvfs.yazi/main.lua

File diff suppressed because it is too large Load Diff

21
.config/yazi/plugins/jump-to-char.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

28
.config/yazi/plugins/jump-to-char.yazi/README.md

@ -1,28 +0,0 @@
# jump-to-char.yazi
Vim-like `f<char>`, jump to the next file whose name starts with `<char>`.
https://github.com/yazi-rs/plugins/assets/17523360/aac9341c-b416-4e0c-aaba-889d48389869
## Installation
```sh
ya pkg add yazi-rs/plugins:jump-to-char
```
## Usage
Add this to your `~/.config/yazi/keymap.toml`:
```toml
[[mgr.prepend_keymap]]
on = "f"
run = "plugin jump-to-char"
desc = "Jump to char"
```
Note that, the keybindings above are just examples, please tune them up as needed to ensure they don't conflict with your other actions/plugins.
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

32
.config/yazi/plugins/jump-to-char.yazi/main.lua

@ -1,32 +0,0 @@
--- @since 25.5.31
local AVAILABLE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789."
local changed = ya.sync(function(st, new)
local b = st.last ~= new
st.last = new
return b or not cx.active.finder
end)
local escape = function(s) return s == "." and "\\." or s end
return {
entry = function()
local cands = {}
for i = 1, #AVAILABLE_CHARS do
cands[#cands + 1] = { on = AVAILABLE_CHARS:sub(i, i) }
end
local idx = ya.which { cands = cands, silent = true }
if not idx then
return
end
local kw = escape(cands[idx].on)
if changed(kw) then
ya.emit("find_do", { "^" .. kw })
else
ya.emit("find_arrow", {})
end
end,
}

21
.config/yazi/plugins/mount.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

50
.config/yazi/plugins/mount.yazi/README.md

@ -1,50 +0,0 @@
# mount.yazi
A mount manager for Yazi, providing disk mount, unmount, and eject functionality.
Supported platforms:
- Linux with [`udisksctl`](https://github.com/storaged-project/udisks), `lsblk` and `eject` both provided by [`util-linux`](https://github.com/util-linux/util-linux)
- macOS with `diskutil`, which is pre-installed
https://github.com/user-attachments/assets/c6f780ab-458b-420f-85cf-2fc45fcfe3a2
## Installation
```sh
ya pkg add yazi-rs/plugins:mount
```
## Usage
Add this to your `~/.config/yazi/keymap.toml`:
```toml
[[mgr.prepend_keymap]]
on = "M"
run = "plugin mount"
```
Note that, the keybindings above are just examples, please tune them up as needed to ensure they don't conflict with your other actions/plugins.
## Actions
| Key binding | Alternate key | Action |
| ------------ | ------------- | --------------------- |
| <kbd>q</kbd> | - | Quit the plugin |
| <kbd>k</kbd> | <kbd></kbd> | Move up |
| <kbd>j</kbd> | <kbd></kbd> | Move down |
| <kbd>l</kbd> | <kbd></kbd> | Enter the mount point |
| <kbd>m</kbd> | - | Mount the partition |
| <kbd>u</kbd> | - | Unmount the partition |
| <kbd>e</kbd> | - | Eject the disk |
## TODO
- Custom keybindings
- Windows support (I don't use Windows myself, PRs welcome!)
- Support mount, unmount, and eject the entire disk
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

71
.config/yazi/plugins/mount.yazi/cross.lua

@ -1,71 +0,0 @@
local M = {}
--- @param type "mount"|"unmount"|"eject"
--- @param partition table
function M.operate(type, partition)
if not partition then
return
elseif not partition.sub then
return -- TODO: mount/unmount main disk
end
local cmd, output, err
if ya.target_os() == "macos" then
cmd, output, err = "diskutil", M.diskutil(type, partition.src)
elseif ya.target_os() == "linux" then
if type == "eject" and partition.src:match("^/dev/sr%d+") then
M.udisksctl("unmount", partition.src)
cmd, output, err = "eject", M.eject(partition.src)
elseif type == "eject" then
M.udisksctl("unmount", partition.src)
cmd, output, err = "udisksctl", M.udisksctl("power-off", partition.src)
else
cmd, output, err = "udisksctl", M.udisksctl(type, partition.src)
end
end
if not cmd then
M.fail("mount.yazi is not currently supported on your platform")
elseif not output then
M.fail("Failed to spawn `%s`: %s", cmd, err)
elseif not output.status.success then
M.fail("Failed to %s `%s`: %s", type, partition.src, output.stderr)
end
end
--- @param type "mount"|"unmount"|"eject"
--- @param src string
--- @return Output? output
--- @return Error? err
function M.diskutil(type, src) return Command("diskutil"):arg({ type, src }):output() end
--- @param type "mount"|"unmount"|"power-off"
--- @param src string
--- @return Output? output
--- @return Error? err
function M.udisksctl(type, src)
local args = { type, "-b", src, "--no-user-interaction" }
local output, err = Command("udisksctl"):arg(args):output()
if not output or err then
return nil, err
elseif output.stderr:find("org.freedesktop.UDisks2.Error.NotAuthorizedCanObtain", 1, true) then
local tx, rx = table.unpack(require(".main").permit)
tx:send(true)
ya.emit("which:dismiss", {})
local output, err = require(".sudo").run_with_sudo("udisksctl", args)
rx:recv()
return output, err
else
return output
end
end
--- @param src string
--- @return Output? output
--- @return Error? err
function M.eject(src) return Command("eject"):arg({ "--traytoggle", src }):output() end
function M.fail(...) ya.notify { title = "Mount", content = string.format(...), timeout = 10, level = "error" } end
return M

272
.config/yazi/plugins/mount.yazi/main.lua

@ -1,272 +0,0 @@
--- @since 26.5.6
local toggle_ui = ya.sync(function(self)
if self.children then
Modal:children_remove(self.children)
self.children = nil
else
self.children = Modal:children_add(self, 10)
end
ui.render()
end)
local subscribe = ya.sync(function()
ps.unsub("mount")
ps.sub("mount", function()
-- TODO: use `ya.async()`
ya.emit("plugin", { "mount", "refresh" })
end)
end)
local update_partitions = ya.sync(function(self, partitions)
self.partitions = partitions
self.cursor = math.max(0, math.min(self.cursor or 0, #self.partitions - 1))
ui.render()
end)
local active_partition = ya.sync(function(self) return self.partitions[self.cursor + 1] end)
local update_cursor = ya.sync(function(self, cursor)
if #self.partitions == 0 then
self.cursor = 0
else
self.cursor = ya.clamp(0, self.cursor + cursor, #self.partitions - 1)
end
ui.render()
end)
local M = {
keys = {
{ on = "q", run = "quit" },
{ on = "<Esc>", run = "quit" },
{ on = "<Enter>", run = { "enter", "quit" } },
{ on = "k", run = "up" },
{ on = "j", run = "down" },
{ on = "l", run = { "enter", "quit" } },
{ on = "<Up>", run = "up" },
{ on = "<Down>", run = "down" },
{ on = "<Right>", run = { "enter", "quit" } },
{ on = "m", run = "mount" },
{ on = "u", run = "unmount" },
{ on = "e", run = "eject" },
},
permit = table.pack(ya.chan("mpsc", 1)),
}
function M:new(area)
self:layout(area)
return self
end
function M:layout(area)
local chunks = ui.Layout()
:constraints({
ui.Constraint.Percentage(10),
ui.Constraint.Percentage(80),
ui.Constraint.Percentage(10),
})
:split(area)
local chunks = ui.Layout()
:direction(ui.Layout.HORIZONTAL)
:constraints({
ui.Constraint.Percentage(10),
ui.Constraint.Percentage(80),
ui.Constraint.Percentage(10),
})
:split(chunks[2])
self._area = chunks[2]
end
function M:entry(job)
if job.args[1] == "refresh" then
return update_partitions(self.obtain())
end
toggle_ui()
update_partitions(self.obtain())
subscribe()
local tx1, rx1 = ya.chan("mpsc")
local tx2, rx2 = ya.chan("mpsc")
function producer()
self.permit[1]:send(true)
while true do
self.permit[2]:recv()
local idx = ya.which { cands = self.keys, silent = true }
self.permit[1]:send(true)
local cand = self.keys[idx] or { run = {} }
for _, r in ipairs(type(cand.run) == "table" and cand.run or { cand.run }) do
tx1:send(r)
if r == "quit" then
toggle_ui()
return
end
end
end
end
function consumer1()
repeat
local run = rx1:recv()
if run == "quit" then
tx2:send(run)
break
elseif run == "up" then
update_cursor(-1)
elseif run == "down" then
update_cursor(1)
elseif run == "enter" then
local active = active_partition()
if active and active.dist then
ya.emit("cd", { active.dist })
end
else
tx2:send(run)
end
until not run
end
function consumer2()
repeat
local run = rx2:recv()
if run == "quit" then
break
elseif run == "mount" then
require(".cross").operate("mount", active_partition())
elseif run == "unmount" then
require(".cross").operate("unmount", active_partition())
elseif run == "eject" then
require(".cross").operate("eject", active_partition())
end
until not run
end
ya.join(producer, consumer1, consumer2)
end
function M:reflow() return { self } end
function M:redraw()
local rows = {}
for _, p in ipairs(self.partitions or {}) do
if not p.sub then
rows[#rows + 1] = ui.Row { p.main }
elseif p.sub == "" then
rows[#rows + 1] = ui.Row { p.main, p.label or "", p.dist or "", p.fstype or "" }
else
rows[#rows + 1] = ui.Row { " " .. p.sub, p.label or "", p.dist or "", p.fstype or "" }
end
end
return {
ui.Clear(self._area),
ui.Border(ui.Edge.ALL)
:area(self._area)
:type(ui.Border.ROUNDED)
:style(ui.Style():fg("blue"))
:title(ui.Line("Mount"):align(ui.Align.CENTER)),
ui.Table(rows)
:area(self._area:pad(ui.Pad(1, 2, 1, 2)))
:header(ui.Row({ "Src", "Label", "Dist", "FSType" }):style(ui.Style():bold()))
:row(self.cursor)
:row_style(ui.Style():fg("blue"):underline())
:widths {
ui.Constraint.Length(20),
ui.Constraint.Length(20),
ui.Constraint.Percentage(70),
ui.Constraint.Length(20),
},
}
end
function M.obtain()
local tbl = {}
local last
for _, p in ipairs(fs.partitions()) do
local main, sub = M.split(p.src)
if main and last ~= main then
if p.src == main then
last, p.main, p.sub, tbl[#tbl + 1] = p.src, p.src, "", p
else
last, tbl[#tbl + 1] = main, { src = main, main = main, sub = "" }
end
end
if sub then
if tbl[#tbl].sub == "" and tbl[#tbl].main == main then
tbl[#tbl].sub = nil
end
p.main, p.sub, tbl[#tbl + 1] = main, sub, p
end
end
table.sort(M.fillin(tbl), function(a, b)
if a.main == b.main then
return (a.sub or "") < (b.sub or "")
else
return a.main > b.main
end
end)
return tbl
end
function M.split(src)
local pats = {
{ "^/dev/sd[a-z]", "%d+$" }, -- /dev/sda1
{ "^/dev/nvme%d+n%d+", "p%d+$" }, -- /dev/nvme0n1p1
{ "^/dev/mmcblk%d+", "p%d+$" }, -- /dev/mmcblk0p1
{ "^/dev/disk%d+", ".+$" }, -- /dev/disk1s1
{ "^/dev/sr%d+", ".+$" }, -- /dev/sr0
{ "^/dev/fd%d+", ".+$" }, -- /dev/fd0
{ "^/dev/md%d+", "p%d+$" }, -- /dev/md0p1
{ "^/dev/nbd%d+", "p%d+$" }, -- /dev/nbd0p1
{ "^/dev/bcache%d+", "p%d+$" }, -- /dev/bcache0p1
{ "^/dev/mapper/", ".+$" }, -- /dev/mapper/<name>
}
for _, p in ipairs(pats) do
local main = src:match(p[1])
if main then
return main, src:sub(#main + 1):match(p[2])
end
end
end
function M.fillin(tbl)
if ya.target_os() ~= "linux" then
return tbl
end
local sources, indices = {}, {}
for i, p in ipairs(tbl) do
if p.sub and not p.fstype then
sources[#sources + 1], indices[p.src] = p.src, i
end
end
if #sources == 0 then
return tbl
end
local output, err = Command("lsblk"):arg({ "-p", "-o", "name,fstype", "-J" }):arg(sources):output()
if err then
ya.dbg("Failed to fetch filesystem types for unmounted partitions: " .. err)
return tbl
end
local t = ya.json_decode(output and output.stdout or "")
for _, p in ipairs(t and t.blockdevices or {}) do
tbl[indices[p.name]].fstype = p.fstype
end
return tbl
end
function M:click() end
function M:scroll() end
function M:touch() end
return M

54
.config/yazi/plugins/mount.yazi/sudo.lua

@ -1,54 +0,0 @@
local M = {}
--- Verify if `sudo` is already authenticated
--- @return boolean
--- @return Error?
function M.sudo_already()
local status, err = Command("sudo"):arg({ "--validate", "--non-interactive" }):status()
return status and status.success or false, err
end
--- Run a program with `sudo` privilege
--- @param program string
--- @param args table
--- @return Output? output
--- @return Error? err
function M.run_with_sudo(program, args)
local cmd = Command("sudo")
:arg({ "--stdin", "--user", "#" .. ya.uid(), "--", program })
:arg(args)
:stdin(Command.PIPED)
:stdout(Command.PIPED)
:stderr(Command.PIPED)
if M.sudo_already() then
return cmd:output()
end
local value, event = ya.input {
pos = { "top-center", y = 3, w = 40 },
title = string.format("Password for `sudo %s`:", program),
obscure = true,
}
if not value or event ~= 1 then
return nil, Err("Sudo password input cancelled")
end
local child, err = cmd:spawn()
if not child or err then
return nil, err
end
child:write_all(value .. "\n")
child:flush()
local output, err = child:wait_with_output()
if not output or err then
return nil, err
elseif output.status.success or M.sudo_already() then
return output
else
return nil, Err("Incorrect sudo password")
end
end
return M

19
.config/yazi/plugins/open-with-cmd.yazi/LICENSE

@ -1,19 +0,0 @@
Copyright (c) 2024 Lauri Niskanen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

25
.config/yazi/plugins/open-with-cmd.yazi/README.md

@ -1,25 +0,0 @@
# open-with-cmd.yazi
This is a Yazi plugin for opening files with a prompted command.
## Installation
Install the plugin:
```
ya pkg add Ape/open-with-cmd
```
Create `~/.config/yazi/keymap.toml` and add:
```
[[manager.prepend_keymap]]
on = "o"
run = "plugin open-with-cmd -- block"
desc = "Open with command in the terminal"
[[manager.prepend_keymap]]
on = "O"
run = "plugin open-with-cmd"
desc = "Open with command"
```

19
.config/yazi/plugins/open-with-cmd.yazi/main.lua

@ -1,19 +0,0 @@
return {
entry = function(_, job)
local block = job.args[1] and job.args[1] == "block"
local value, event = ya.input({
title = block and "Open with (block):" or "Open with:",
pos = { "hovered", y = 1, w = 50 },
})
if event == 1 then
local s = ya.target_family() == "windows" and " %*" or ' "$@"'
ya.emit("shell", {
value .. s,
block = block,
orphan = not block,
})
end
end,
}

21
.config/yazi/plugins/piper.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

102
.config/yazi/plugins/piper.yazi/README.md

@ -1,102 +0,0 @@
# piper.yazi
Pipe any shell command as a previewer.
## Installation
```sh
ya pkg add yazi-rs/plugins:piper
```
## Usage
Piper is a general-purpose previewer - you can pass any shell command to `piper` and it will use the command's output as the preview content.
It accepts a string parameter, which is the shell command to be executed, for example:
```toml
# ~/.config/yazi/yazi.toml
[[plugin.prepend_previewers]]
url = "*"
run = 'piper -- echo "$1"'
```
This will set `piper` as the previewer for all file types and use `$1` (file path) as the preview content.
## Variables
Available variables:
- `$w`: the width of the preview area.
- `$h`: the height of the preview area.
- `$1`: the path to the file being previewed.
## Examples
Here are some configuration examples:
### Preview tarballs with [`tar`](https://man7.org/linux/man-pages/man1/tar.1.html)
```toml
[[plugin.prepend_previewers]]
url = "*.tar*"
run = 'piper --format=url -- tar tf "$1"'
```
In this example, `--format=url` tells `piper` to parse the `tar` output as file URLs, so you'll be able to get a list of files with icons.
### Preview CSV with [`bat`](https://github.com/sharkdp/bat)
```toml
[[plugin.prepend_previewers]]
url = "*.csv"
run = 'piper -- bat -p --color=always "$1"'
```
Note that certain distributions might use a different name than `bat`, like Debian and Ubuntu use `batcat`, so please adjust accordingly.
### Preview Markdown with [`glow`](https://github.com/charmbracelet/glow)
```toml
[[plugin.prepend_previewers]]
url = "*.md"
run = 'piper -- CLICOLOR_FORCE=1 glow -w=$w -s=dark "$1"'
```
Note that there's [a bug in Glow v2.0](https://github.com/charmbracelet/glow/issues/440#issuecomment-2307992634) that causes slight color differences between tty and non-tty environments.
### Preview directory tree with [`eza`](https://github.com/eza-community/eza)
```toml
[[plugin.prepend_previewers]]
url = "*/"
run = 'piper -- eza -TL=3 --color=always --icons=always --group-directories-first --no-quotes "$1"'
```
### Preview the schema of a SQLite database
```toml
[[plugin.prepend_previewers]]
mime = "application/sqlite3"
run = 'piper -- sqlite3 "$1" ".schema --indent"'
```
### Use [`hexyl`](https://github.com/sharkdp/hexyl) as fallback previewer
Yazi defaults to using [`file -bL "$1"`](https://github.com/sxyazi/yazi/blob/main/yazi-plugin/preset/plugins/file.lua) if there's no matched previewer.
This example uses `hexyl` as a fallback previewer instead of `file`.
```toml
[[plugin.append_previewers]]
url = "*"
run = 'piper -- hexyl --border=none --terminal-width=$w "$1"'
```
## Related projects
[`faster-piper.yazi`](https://github.com/alberti42/faster-piper.yazi): a cache-based, scrolling-optimized rewrite compatible with `piper.yazi`.
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

71
.config/yazi/plugins/piper.yazi/main.lua

@ -1,71 +0,0 @@
--- @since 26.1.22
local M = {}
local function fail(job, s) ya.preview_widget(job, ui.Text.parse(s):area(job.area):wrap(ui.Wrap.YES)) end
function M:peek(job)
local child, err = Command("sh")
:arg({ "-c", job.args[1], "sh", tostring(job.file.path) })
:env("w", job.area.w)
:env("h", job.area.h)
:env("CYGWIN", "noupcaseenv")
:stdout(Command.PIPED)
:stderr(Command.PIPED)
:spawn()
if not child then
return fail(job, "sh: " .. err)
end
local limit = job.area.h
local i, outs, errs = 0, {}, {}
repeat
local next, event = child:read_line()
if event == 1 then
errs[#errs + 1] = next
elseif event ~= 0 then
break
end
i = i + 1
if i > job.skip then
outs[#outs + 1] = next
end
until i >= job.skip + limit
child:start_kill()
if #errs > 0 then
fail(job, table.concat(errs, ""))
elseif job.skip > 0 and i < job.skip + limit then
ya.emit("peek", { math.max(0, i - limit), only_if = job.file.url, upper_bound = true })
else
ya.preview_widget(job, M.format(job, outs))
end
end
function M:seek(job) require("code"):seek(job) end
function M.format(job, lines)
local format = job.args.format
if format ~= "url" then
local s = table.concat(lines, ""):gsub("\t", string.rep(" ", rt.preview.tab_size))
return ui.Text.parse(s):area(job.area)
end
for i = 1, #lines do
lines[i] = lines[i]:gsub("[\r\n]+$", "")
local icon = File({
url = Url(lines[i]),
cha = Cha { mode = tonumber(lines[i]:sub(-1) == "/" and "40700" or "100644", 8) },
}):icon()
if icon then
lines[i] = ui.Line { ui.Span(" " .. icon.text .. " "):style(icon.style), lines[i] }
end
end
return ui.Text(lines):area(job.area)
end
return M

19
.config/yazi/plugins/relative-motions.yazi/LICENSE

@ -1,19 +0,0 @@
Copyright (c) 2024 dedukun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

145
.config/yazi/plugins/relative-motions.yazi/README.md

@ -1,145 +0,0 @@
# relative-motions.yazi
A [Yazi](https://github.com/sxyazi/yazi) plugin based about vim motions.
<https://github.com/dedukun/relative-motions.yazi/assets/25795432/04fb186a-5efe-442d-8d7b-2dccb6eee408>
## Requirements
- [Yazi](https://github.com/sxyazi/yazi) v25.5.28+
## Installation
```sh
ya pkg add dedukun/relative-motions
```
## Configuration
If you want to use the numbers directly to start a motion add this to your `keymap.toml`:
<details>
```toml
[[mgr.prepend_keymap]]
on = [ "1" ]
run = "plugin relative-motions 1"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "2" ]
run = "plugin relative-motions 2"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "3" ]
run = "plugin relative-motions 3"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "4" ]
run = "plugin relative-motions 4"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "5" ]
run = "plugin relative-motions 5"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "6" ]
run = "plugin relative-motions 6"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "7" ]
run = "plugin relative-motions 7"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "8" ]
run = "plugin relative-motions 8"
desc = "Move in relative steps"
[[mgr.prepend_keymap]]
on = [ "9" ]
run = "plugin relative-motions 9"
desc = "Move in relative steps"
```
</details>
Alternatively you can use a key to trigger a new motion without any initial value, for that add the following in `keymap.toml`:
```toml
[[mgr.prepend_keymap]]
on = [ "m" ]
run = "plugin relative-motions"
desc = "Trigger a new relative motion"
```
---
Additionally there are a couple of initial configurations that can be given to the plugin's `setup` function:
| Configuration | Values | Default | Description |
| -------------- | ----------------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `show_numbers` | `relative`, `absolute`, `relative_absolute` or `none` | `none` | Shows relative or absolute numbers before the file icon |
| `show_motion` | `true` or `false` | `false` | Shows current motion in Status bar |
| `only_motions` | `true` or `false` | `false` | If true, only the motion movements will be enabled, i.e., the commands for delete, cut, yank and visual selection will be disabled |
| `enter_mode` | `cache`, `first` or `cache_or_first` | `cache_or_first` | The method to enter folders |
If you want, for example, to enable relative numbers as well as to show the motion in the status bar,
add the following to Yazi's `init.lua`, i.e. `~/.config/yazi/init.lua`:
```lua
-- ~/.config/yazi/init.lua
require("relative-motions"):setup({ show_numbers="relative", show_motion = true, enter_mode ="first" })
```
> [!NOTE]
> The `show_numbers` and `show_motion` functionalities overwrite [`Current:redraw`](https://github.com/sxyazi/yazi/blob/e3c91115a2c096724303a0b364e7625691e4beba/yazi-plugin/preset/components/current.lua#L28)
> and [`Status:children_redraw`](https://github.com/sxyazi/yazi/blob/e3c91115a2c096724303a0b364e7625691e4beba/yazi-plugin/preset/components/status.lua#L177) respectively.
> If you have custom implementations for any of this functions
> you can add the provided `Entity:number` and `Status:motion` to your implementations, just check [here](https://github.com/dedukun/relative-motions.yazi/blob/main/init.lua#L126) how we are doing things.
## Usage
This plugin adds the some basic vim motions like `3k`, `12j`, `10gg`, etc.
The following table show all the available motions:
| Command | Description |
| -------------- | --------------------- |
| `j`/`<Down>` | Move `n` lines down |
| `k`/`<Up>` | Move `n` lines up |
| `h`/`<Left>` | Move `n` folders back |
| `l`/`<Right>` | Enter `n` folders |
| `gj`/`g<Down>` | Go `n` lines down |
| `gk`/`g<Up>` | Go `n` lines up |
| `gg` | Go to line |
Furthermore, the following operations were also added:
| Command | Description |
| ------- | ------------- |
| `v` | visual select |
| `y` | Yank |
| `x` | Cut |
| `d` | Delete motion |
This however must be followed by a direction, which can be `j`/`<Down>`, `k`/`<Up>` or repeating the command key,
which will operate from the cursor down, e.g. `2yy` will copy two files.
Finally, we also support some tab operations:
| Command | Description |
| ------- | ------------------------------------ |
| `t` | create `n` tabs |
| `H` | Move `n` tabs left |
| `L` | Move `n` tabs right |
| `gt` | Go to the `n` tab |
| `w` | Close tab `n` |
| `W` | Close `n` tabs right |
| `<` | Swap current tab with `n` tabs left |
| `>` | Swap current tab with `n` tabs right |
| `~` | Swap current tab with tab `n` |

406
.config/yazi/plugins/relative-motions.yazi/main.lua

@ -1,406 +0,0 @@
--- @since 25.5.28
-- stylua: ignore
local MOTIONS_AND_OP_KEYS = {
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
{ on = "5" }, { on = "6" }, { on = "7" }, { on = "8" }, { on = "9" },
-- commands
{ on = "d" }, { on = "v" }, { on = "y" }, { on = "x" },
-- tab commands
{ on = "t" }, { on = "L" }, { on = "H" }, { on = "w" },
{ on = "W" }, { on = "<" }, { on = ">" }, { on = "~" },
-- movement
{ on = "g" }, { on = "j" }, { on = "k" }, { on = "h" }, { on = "l" }, { on = "<Down>" }, { on = "<Up>" }, { on = "<Left>" }, { on = "<Right>" }
}
-- stylua: ignore
local MOTION_KEYS = {
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
{ on = "5" }, { on = "6" }, { on = "7" }, { on = "8" }, { on = "9" },
-- movement
{ on = "g" }, { on = "j" }, { on = "k" }, { on = "h" }, { on = "l" }, { on = "<Down>" }, { on = "<Up>" }, { on = "<Left>" }, { on = "<Right>" }
}
-- stylua: ignore
local DIRECTION_KEYS = {
{ on = "j" }, { on = "k" }, { on = "<Down>" }, { on = "<Up>" },
-- tab movement
{ on = "t" }
}
local SHOW_NUMBERS_ABSOLUTE = 0
local SHOW_NUMBERS_RELATIVE = 1
local SHOW_NUMBERS_RELATIVE_ABSOLUTE = 2
local ENTER_MODE_FIRST = 0
local ENTER_MODE_CACHE = 1
local ENTER_MODE_CACHE_OR_FIRST = 2
-----------------------------------------------
----------------- R E N D E R -----------------
-----------------------------------------------
local render_motion_setup = ya.sync(function(_)
if ui.render then
ui.render()
else
ya.render()
end
Status.motion = function() return ui.Span("") end
Status.children_redraw = function(self, side)
local lines = {}
if side == self.RIGHT then
lines[1] = self:motion(self)
end
for _, c in ipairs(side == self.RIGHT and self._right or self._left) do
lines[#lines + 1] = (type(c[1]) == "string" and self[c[1]] or c[1])(self)
end
return ui.Line(lines)
end
-- TODO: check why it doesn't work line this
-- Status:children_add(function() return ui.Span("") end, 1000, Status.RIGHT)
end)
local render_motion = ya.sync(function(_, motion_num, motion_cmd)
if ui.render then
ui.render()
else
ya.render()
end
Status.motion = function(self)
if not motion_num then
return ui.Span("")
end
local style = self:style()
local motion_span
if not motion_cmd then
motion_span = ui.Span(string.format(" %3d ", motion_num))
else
motion_span = ui.Span(string.format(" %3d%s ", motion_num, motion_cmd))
end
local status_config = th.status
local separator_open = status_config.sep_right.open
local separator_close = status_config.sep_right.close
-- TODO: REMOVE THIS IN NEXT RELEASE
local bg_style
if type(style.main.bg) == "function" then
bg_style = style.main:bg()
else
bg_style = style.main.bg
end
return ui.Line {
ui.Span(separator_open):fg(bg_style),
motion_span:style(style.main),
ui.Span(separator_close):fg(bg_style),
ui.Span(" "),
}
end
end)
local render_numbers = ya.sync(function(_, mode)
if ui.render then
ui.render()
else
ya.render()
end
Entity.number = function(_, index, total, file, hovered)
local idx
if mode == SHOW_NUMBERS_RELATIVE then
idx = math.abs(hovered - index)
elseif mode == SHOW_NUMBERS_ABSOLUTE then
idx = file.idx
else -- SHOW_NUMBERS_RELATIVE_ABSOLUTE
if hovered == index then
idx = file.idx
else
idx = math.abs(hovered - index)
end
end
local num_format = "%" .. #tostring(total) .. "d"
-- emulate vim's hovered offset
if hovered == index then
return ui.Span(string.format(num_format .. " ", idx))
else
return ui.Span(string.format(" " .. num_format, idx))
end
end
Current.redraw = function(self)
local files = self._folder.window
if #files == 0 then
return self:empty()
end
local hovered_index
for i, f in ipairs(files) do
if f.is_hovered then
hovered_index = i
break
end
end
local entities, linemodes = {}, {}
for i, f in ipairs(files) do
linemodes[#linemodes + 1] = Linemode:new(f):redraw()
local entity = Entity:new(f)
entities[#entities + 1] = ui.Line({ Entity:number(i, #self._folder.files, f, hovered_index), entity:redraw() })
:style(entity:style())
end
return {
ui.List(entities):area(self._area),
ui.Text(linemodes):area(self._area):align(ui.Align.RIGHT),
}
end
end)
local function render_clear() render_motion() end
-----------------------------------------------
--------- C O M M A N D P A R S E R ---------
-----------------------------------------------
local get_keys = ya.sync(function(state) return state._only_motions and MOTION_KEYS or MOTIONS_AND_OP_KEYS end)
local function normal_direction(dir)
if dir == "<Down>" then
return "j"
elseif dir == "<Up>" then
return "k"
elseif dir == "<Left>" then
return "h"
elseif dir == "<Right>" then
return "l"
end
return dir
end
local function get_cmd(first_char, keys)
local last_key
local lines = first_char or ""
while true do
render_motion(tonumber(lines))
local key = ya.which { cands = keys, silent = true }
if not key then
return nil, nil, nil
end
last_key = keys[key].on
if not tonumber(last_key) then
last_key = normal_direction(last_key)
break
end
lines = lines .. last_key
end
render_motion(tonumber(lines), last_key)
-- command direction
local direction
if last_key == "g" or last_key == "v" or last_key == "d" or last_key == "y" or last_key == "x" then
DIRECTION_KEYS[#DIRECTION_KEYS + 1] = {
on = last_key,
}
local direction_key = ya.which { cands = DIRECTION_KEYS, silent = true }
if not direction_key then
return nil, nil, nil
end
direction = DIRECTION_KEYS[direction_key].on
direction = normal_direction(direction)
end
return tonumber(lines), last_key, direction
end
local function is_tab_command(command)
local tab_commands = { "t", "L", "H", "w", "W", "<", ">", "~" }
for _, cmd in ipairs(tab_commands) do
if command == cmd then
return true
end
end
return false
end
local get_active_tab = ya.sync(function(_) return cx.tabs.idx end)
local get_cache_or_first_dir = ya.sync(function(state)
if state._enter_mode == ENTER_MODE_CACHE then
return nil
elseif state._enter_mode == ENTER_MODE_CACHE_OR_FIRST then
local hovered_file = cx.active.current.hovered
if hovered_file ~= nil and hovered_file.cha.is_dir then
return cx.active.current.cursor
end
end
local files = cx.active.current.files
local index = 1
for i = 1, #files do
if files[i].cha.is_dir then
index = i
break
end
end
return index - 1
end)
-----------------------------------------------
---------- E N T R Y / S E T U P ----------
-----------------------------------------------
return {
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]))
if initial_value == "nil" then
return
end
end
local lines, cmd, direction = get_cmd(initial_value, get_keys())
if not lines or not cmd then
-- command was cancelled
render_clear()
return
end
if cmd == "g" then
if direction == "g" then
ya.mgr_emit("arrow", { "top" })
ya.mgr_emit("arrow", { lines - 1 })
render_clear()
return
elseif direction == "j" then
cmd = "j"
elseif direction == "k" then
cmd = "k"
elseif direction == "t" then
ya.mgr_emit("tab_switch", { lines - 1 })
render_clear()
return
else
-- no valid direction
render_clear()
return
end
end
if cmd == "j" then
ya.mgr_emit("arrow", { lines })
elseif cmd == "k" then
ya.mgr_emit("arrow", { -lines })
elseif cmd == "h" then
for _ = 1, lines do
ya.mgr_emit("leave", {})
end
elseif cmd == "l" then
for _ = 1, lines do
ya.mgr_emit("enter", {})
local file_idx = get_cache_or_first_dir()
if file_idx then
ya.mgr_emit("arrow", { "top" })
ya.mgr_emit("arrow", { file_idx })
end
end
elseif is_tab_command(cmd) then
if cmd == "t" then
for _ = 1, lines do
ya.mgr_emit("tab_create", {})
end
elseif cmd == "H" then
ya.mgr_emit("tab_switch", { -lines, relative = true })
elseif cmd == "L" then
ya.mgr_emit("tab_switch", { lines, relative = true })
elseif cmd == "w" then
ya.mgr_emit("tab_close", { lines - 1 })
elseif cmd == "W" then
local curr_tab = get_active_tab()
local del_tab = curr_tab + lines - 1
for _ = curr_tab, del_tab do
ya.mgr_emit("tab_close", { curr_tab - 1 })
end
ya.mgr_emit("tab_switch", { curr_tab - 1 })
elseif cmd == "<" then
ya.mgr_emit("tab_swap", { -lines })
elseif cmd == ">" then
ya.mgr_emit("tab_swap", { lines })
elseif cmd == "~" then
local jump = lines - get_active_tab()
ya.mgr_emit("tab_swap", { jump })
end
else
ya.mgr_emit("visual_mode", {})
-- invert direction when user specifies it
if direction == "k" then
ya.mgr_emit("arrow", { -lines })
elseif direction == "j" then
ya.mgr_emit("arrow", { lines })
else
ya.mgr_emit("arrow", { lines - 1 })
end
ya.mgr_emit("escape", {})
if cmd == "d" then
ya.mgr_emit("remove", {})
elseif cmd == "y" then
ya.mgr_emit("yank", {})
elseif cmd == "x" then
ya.mgr_emit("yank", { cut = true })
end
end
render_clear()
end,
setup = function(state, args)
if not args then
return
end
-- initialize state variables
state._only_motions = args["only_motions"] or false
if args["show_motion"] then
render_motion_setup()
end
if args["enter_mode"] == "cache" then
state._enter_mode = ENTER_MODE_CACHE
elseif args["enter_mode"] == "first" then
state._enter_mode = ENTER_MODE_FIRST
elseif args["enter_mode"] == "cache_or_first" then
state._enter_mode = ENTER_MODE_CACHE_OR_FIRST
else
state._enter_mode = ENTER_MODE_CACHE_OR_FIRST
end
if args["show_numbers"] == "absolute" then
render_numbers(SHOW_NUMBERS_ABSOLUTE)
elseif args["show_numbers"] == "relative" then
render_numbers(SHOW_NUMBERS_RELATIVE)
elseif args["show_numbers"] == "relative_absolute" then
render_numbers(SHOW_NUMBERS_RELATIVE_ABSOLUTE)
end
end,
}

21
.config/yazi/plugins/smart-enter.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

40
.config/yazi/plugins/smart-enter.yazi/README.md

@ -1,40 +0,0 @@
# smart-enter.yazi
[`Open`][open] files or [`enter`][enter] directories all in one key!
## Installation
```sh
ya pkg add yazi-rs/plugins:smart-enter
```
## Usage
Bind your <kbd>l</kbd> key to the plugin, in your `~/.config/yazi/keymap.toml`:
```toml
[[mgr.prepend_keymap]]
on = "l"
run = "plugin smart-enter"
desc = "Enter the child directory, or open the file"
```
## Advanced
By default, `--hovered` is passed to the [`open`][open] action, make the behavior consistent with [`enter`][enter] avoiding accidental triggers,
which means both will only target the currently hovered file.
If you still want `open` to target multiple selected files, add this to your `~/.config/yazi/init.lua`:
```lua
require("smart-enter"):setup {
open_multi = true,
}
```
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.
[open]: https://yazi-rs.github.io/docs/configuration/keymap/#mgr.open
[enter]: https://yazi-rs.github.io/docs/configuration/keymap/#mgr.enter

11
.config/yazi/plugins/smart-enter.yazi/main.lua

@ -1,11 +0,0 @@
--- @since 25.5.31
--- @sync entry
local function setup(self, opts) self.open_multi = opts.open_multi end
local function entry(self)
local h = cx.active.current.hovered
ya.emit(h and h.cha.is_dir and "enter" or "open", { hovered = not self.open_multi })
end
return { entry = entry, setup = setup }

21
.config/yazi/plugins/zoom.yazi/LICENSE

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 yazi-rs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

55
.config/yazi/plugins/zoom.yazi/README.md

@ -1,55 +0,0 @@
# zoom.yazi
Enlarge or shrink the preview image of a file, which is useful for magnifying small files for viewing.
Supported formats:
- Images - requires [ImageMagick](https://imagemagick.org/) (>= 7.1.1)
Note that, the maximum size of enlarged images is limited by the [`max_width`][max_width] and [`max_height`][max_height] configuration options, so you may need to increase them as needed.
https://github.com/user-attachments/assets/b28912b1-da63-43d3-a21f-b9e6767ed4a9
[max_width]: https://yazi-rs.github.io/docs/configuration/yazi#preview.max_width
[max_height]: https://yazi-rs.github.io/docs/configuration/yazi#preview.max_height
## Installation
```sh
ya pkg add yazi-rs/plugins:zoom
```
## Usage
```toml
# keymap.toml
[[mgr.prepend_keymap]]
on = "+"
run = "plugin zoom 1"
desc = "Zoom in hovered file"
[[mgr.prepend_keymap]]
on = "-"
run = "plugin zoom -1"
desc = "Zoom out hovered file"
```
Note that, the keybindings above are just examples, please tune them up as needed to ensure they don't conflict with your other actions/plugins.
## Advanced
If you want to apply a default zoom parameter to image previews, you can specify it while setting this plugin up as a custom previewer, for example:
```toml
[[plugin.prepend_previewers]]
mime = "image/{jpeg,png,webp}"
run = "zoom 5"
```
## TODO
- [ ] Support more file types (e.g., videos, PDFs), PRs welcome!
## License
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

119
.config/yazi/plugins/zoom.yazi/main.lua

@ -1,119 +0,0 @@
--- @since 26.1.22
local get = ya.sync(function(st, url) return st.last == url and st.level end)
local save = ya.sync(function(st, url, new)
local h = cx.active.current.hovered
if h and h.url == url then
st.last, st.level = url, new
return true
end
end)
local lock = ya.sync(function(st, url, old, new)
if st.last == url and st.level == old then
st.level = new
return true
end
end)
local move = ya.sync(function(st)
local h = cx.active.current.hovered
if not h then
return
end
if st.last ~= h.url then
st.last, st.level = Url(h.url), 0
end
return { url = h.url, level = st.level }
end)
local function end_(job, err)
if not job.old_level then
ya.preview_widget(job, err and ui.Text(err):area(job.area):wrap(ui.Wrap.YES))
elseif err then
ya.notify { title = "Zoom", content = tostring(err), timeout = 5, level = "error" }
end
end
local function canvas(area)
local cw, ch = rt.term.cell_size()
if not cw then
return rt.preview.max_width, rt.preview.max_height
end
return math.min(rt.preview.max_width, math.floor(area.w * cw)),
math.min(rt.preview.max_height, math.floor(area.h * ch))
end
local function peek(_, job)
local url = job.file.url
local info, err = ya.image_info(url)
if not info then
return end_(job, Err("Failed to get image info: %s", err))
end
local level = ya.clamp(-10, job.new_level or get(Url(url)) or tonumber(job.args[1]) or 0, 10)
local sync = function()
if job.old_level then
return lock(url, job.old_level, level)
else
return save(url, level)
end
end
local max_w, max_h = canvas(job.area)
local min_w, min_h = math.min(max_w, info.w), math.min(max_h, info.h)
local new_w = min_w + math.floor(min_w * level * 0.1)
local new_h = min_h + math.floor(min_h * level * 0.1)
if new_w > max_w or new_h > max_h then
if job.old_level then
return sync() -- Image larger than available preview area after zooming
else
new_w, new_h = max_w, max_h -- Run as a previewer, render the image anyway
end
end
local tmp = os.tmpname()
-- stylua: ignore
local output, err = Command("magick"):arg {
tostring(job.file.path),
"-auto-orient", "-strip",
"-sample", string.format("%dx%d", new_w, new_h),
"-quality", rt.preview.image_quality,
string.format("JPG:%s", tmp),
}:output()
if not output then
end_(job, Err("Failed to start `magick`, error: %s", err))
elseif not output.status.success then
end_(job, Err("`magick` exited with error code %s: %s", output.status.code, output.stderr))
elseif sync() then
ya.image_show(Url(tmp), job.area)
end
end_(job)
end
local function entry(self, job)
local st = move()
if not st then
return
end
local motion = tonumber(job.args[1]) or 0
local new = ya.clamp(-10, st.level + motion, 10)
if new ~= st.level then
peek(self, {
area = ui.area("preview"),
args = {},
file = File { url = st.url, cha = Cha { mode = tonumber("100644", 8) } },
skip = 0,
new_level = new,
old_level = st.level,
})
end
end
return { peek = peek, entry = entry }

3
.config/yazi/theme.toml

@ -1,3 +0,0 @@
[flavor]
# dark = "everforest-medium"
dark = "gruvbox-material"

37
.config/yazi/yazi.toml

@ -1,37 +0,0 @@
[[plugin.prepend_fetchers]]
# id = "git" # Remove if Yazi > v26.1.22
url = "*"
run = "git"
group = "git"
[[plugin.prepend_fetchers]]
# id = "git" # Remove if Yazi > v26.1.22
url = "*/"
run = "git"
group = "git"
[opener]
edit = [
{ run = 'nvim "$@"', desc = "Open in Neovim", block = true, for = "unix" },
]
# [[plugin.prepend_previewers]]
# url = "*"
# run = 'piper -- echo "$1"'
[[plugin.prepend_previewers]]
url = "*.md"
run = 'piper -- CLICOLOR_FORCE=1 glow -w=$w -s=dark "$1"'
[[plugin.prepend_previewers]]
url = "*/"
run = 'piper -- eza -TL=3 --color=always --icons=always --group-directories-first --no-quotes "$1"'
[[plugin.prepend_previewers]]
mime = "application/sqlite3"
run = 'piper -- sqlite3 "$1" ".schema --indent"'
[[plugin.append_previewers]]
url = "*"
run = 'piper -- hexyl --border=none --terminal-width=$w "$1"'

25
.dotfiles.d/init/arch/init-cargo-tools.sh

@ -1,25 +0,0 @@
#!/bin/bash
set -euo pipefail
echo "[1/4] Updating pacman and installing prerequisites (curl, base-devel, imagemagick, glow)..."
sudo pacman -Syu --noconfirm
sudo pacman -S --noconfirm curl base-devel imagemagick glow
echo "[2/4] Downloading and installing rustup (latest rustc/cargo)..."
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
sudo pacman -S rustup
rustup default stable
echo "[3/4] Sourcing cargo environment..."
source "$HOME/.cargo/env"
echo " -> Installed: $(rustc --version)"
echo " -> Installed: $(cargo --version)"
echo "[4/4] Installing tools..."
cargo install fsel@3.5.1-kiwicrab
cargo install --force yazi-build
cargo install resvg
echo "Done!"

16
.dotfiles.d/init/arch/init-nvim.sh

@ -1,16 +0,0 @@
#!/bin/env bash
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
sudo pacman -Syu --noconfirm
sudo pacman -S --noconfirm \
jq \
ripgrep \
fd \
zoxide \
base-devel \
just \
neovim
nvim --version

23
.dotfiles.d/init/arch/init-shell.sh

@ -1,23 +0,0 @@
#!/bin/env bash
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
sudo pacman -Syu --noconfirm
sudo pacman -S --noconfirm zsh eza unzip
sudo chsh -s "$(which zsh)" "$USER"
source "${SCRIPT_DIR}/../ensure-locale.sh"
cd ~
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
./.fzf/install
mkdir -p ~/.local/share/fonts
cd ~/.local/share/fonts
fontName=DejaVuSansMono
curl -L -O "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.4.0/${fontName}.zip"
unzip ${fontName}.zip
rm ${fontName}.zip

0
.dotfiles.d/init/ubuntu/init-nvim.sh → .dotfiles.d/init/init-nvim.sh

5
.dotfiles.d/init/ubuntu/init-shell.sh → .dotfiles.d/init/init-shell.sh

@ -2,12 +2,13 @@
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
sudo apt update -y
# ubuntu
#sudo apt update -y
sudo apt install -y zsh eza unzip locales
sudo chsh -s $(which zsh) $USER
source "${SCRIPT_DIR}/../ensure-locale.sh"
source "${SCRIPT_DIR}/ensure-locale.sh"
cd ~
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf

28
.dotfiles.d/init/ubuntu/init-cargo-tools.sh

@ -1,28 +0,0 @@
#!/bin/bash
set -euo pipefail
echo "[1/4] Updating apt and installing prerequisites (curl, build-essential)..."
sudo apt update -qq
sudo apt install -y curl build-essential imagemagick
sudo ln -s /usr/bin/convert /usr/bin/magick || true
echo "[2/4] Downloading and installing rustup (latest rustc/cargo)..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
rustup default stable
echo "[3/4] Sourcing cargo environment..."
source "$HOME/.cargo/env"
echo " -> Installed: $(rustc --version)"
echo " -> Installed: $(cargo --version)"
echo "[4/4] Installing tools..."
cargo install fsel@3.5.1-kiwicrab
cargo install --force yazi-build
cargo install resvg
sudo snap install glow
echo "Done!"

447
.local/bin/btswitch

@ -1,447 +0,0 @@
#!/usr/bin/env bash
set -u
# -------------------------------------------------
# CONFIGURATION
# -------------------------------------------------
WIFI_5G="cintra-5g"
WIFI_24G="cintra-5g"
declare -A BT_DEVICES
BT_DEVICES[TAH8506]="00:1E:7C:CA:77:00"
BT_DEVICES[SHB7150]="00:1E:7C:30:F3:69"
BT_DEVICES[HD450BT]="00:16:94:33:91:51"
BT_DEVICES[XTREME]="41:42:5D:FA:26:0A" # BT Speaker
BT_DEVICES[EM03]="F1:5A:D5:16:57:9D" # BT Speaker/powerbank
BT_DEVICES[X5]="47:0D:FF:C9:62:E1" # Bone Headphones thinkplus-X5
BT_AUTO_DEVICES=("TAH8506" "SHB7150")
BT_SERVICE="bluetooth"
BT_RETRIES=6
BT_DELAY=3
# Polkit rule that lets the current user start/stop bluetooth.service
# without a password, so this script runs sudo-free. Installed on first
# run via ensure_polkit_rule().
BT_POLKIT_RULE_FILE="/etc/polkit-1/rules.d/49-btswitch.rules"
# Sentinel file to track that the rule was installed, since the user
# may not have read/execute access to the polkit rules directory.
BT_POLKIT_SENTINEL="$HOME/.config/btswitch/.polkit_rule_installed"
# -------------------------------------------------
# HELPERS
# -------------------------------------------------
wifi_switch_needed() {
[[ -n "$1" && -n "$2" && "$1" != "$2" ]]
}
ensure_polkit_rule() {
if [[ -f "$BT_POLKIT_SENTINEL" ]]; then
return 0
fi
cat >&2 << EOF
NOTE: This script needs to start/stop the bluetooth service, which normally
requires root. A one-time polkit rule can be installed so "$USER" can do this
without sudo. You will be prompted for your password once to write:
$BT_POLKIT_RULE_FILE
EOF
read -r -p "Install the polkit rule now? [y/N] " answer
case "$answer" in
y | Y | yes | YES) ;;
*)
echo "Skipping. The script cannot control bluetooth.service without it." >&2
return 1
;;
esac
local tmpfile
tmpfile=$(mktemp) || return 1
cat > "$tmpfile" << POLKIT
// Allow user "$USER" to start/stop bluetooth.service without a password.
// Generated by btswitch on $(date -Is).
polkit.addRule(function(action, subject) {
if (action.id === "org.freedesktop.systemd1.manage-units" &&
subject.user === "$USER") {
try {
var unit = action.lookup("unit");
if (unit === "$BT_SERVICE.service") {
return polkit.Result.YES;
}
} catch (e) {}
}
});
POLKIT
sudo cp "$tmpfile" "$BT_POLKIT_RULE_FILE" || {
echo "ERROR: Failed to write $BT_POLKIT_RULE_FILE." >&2
rm -f "$tmpfile"
return 1
}
rm -f "$tmpfile"
sudo chown root:polkitd "$BT_POLKIT_RULE_FILE" 2>/dev/null \
|| sudo chown root:root "$BT_POLKIT_RULE_FILE"
sudo chmod 644 "$BT_POLKIT_RULE_FILE"
mkdir -p "$(dirname "$BT_POLKIT_SENTINEL")"
touch "$BT_POLKIT_SENTINEL"
echo "✔ Installed polkit rule: $BT_POLKIT_RULE_FILE" >&2
echo " (polkitd picks it up automatically; no restart needed.)" >&2
return 0
}
systemctl_bt() {
ensure_polkit_rule || {
echo "ERROR: Cannot control bluetooth.service without the polkit rule." >&2
echo "Run 'sudo systemctl $* $BT_SERVICE' manually, or re-run this script and install the rule." >&2
exit 1
}
if ! systemctl "$@" "$BT_SERVICE"; then
echo "ERROR: systemctl $* $BT_SERVICE failed." >&2
echo "If polkit prompted for a password, the rule file may be missing." >&2
echo "Remove $BT_POLKIT_SENTINEL and re-run to reinstall it." >&2
exit 1
fi
}
bt_info() {
bluetoothctl info "$1" 2> /dev/null
}
bt_is_paired() {
bt_info "$1" | grep -q "Paired: yes"
}
bt_is_trusted() {
bt_info "$1" | grep -q "Trusted: yes"
}
bt_is_connected() {
bt_info "$1" | grep -q "Connected: yes"
}
bt_is_mac_address() {
[[ "$1" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]
}
bt_resolve_device() {
local device="$1"
if bt_is_mac_address "$device"; then
echo "$device"
else
echo "${BT_DEVICES[$device]:-}"
fi
}
bt_get_all_macs() {
local devices=("${!1}")
for dev in "${devices[@]}"; do
local mac
mac=$(bt_resolve_device "$dev")
[[ -n "$mac" ]] && echo "$mac"
done
}
# -------------------------------------------------
# BLUETOOTH CONTROL
# -------------------------------------------------
start_bluetooth() {
echo "Starting Bluetooth service..."
systemctl_bt start
echo "Waiting for bluetoothd to become ready..."
for i in {1..10}; do
if bluetoothctl show | grep -q "Powered: yes"; then
bluetoothctl pairable on > /dev/null 2>&1
return 0
fi
bluetoothctl power on > /dev/null 2>&1
sleep 1
done
echo "ERROR: Bluetooth adapter not found or could not be powered on."
return 1
}
bt_pair_device() {
local mac="$1"
if bt_is_paired "$mac"; then
return 0
fi
echo "✖ Device $mac is not paired. Automatic pairing is not supported."
echo " Please pair it manually, then re-run this command:"
echo ""
echo " bluetoothctl"
echo " [bluetoothctl]# pair $mac"
echo " [bluetoothctl]# trust $mac"
echo " [bluetoothctl]# connect $mac"
echo " [bluetoothctl]# quit"
echo ""
echo " (Put the device in pairing mode first, if needed.)"
return 1
}
bt_ensure_connected() {
local mac="$1"
echo "----------------------------------------"
echo "Checking device: $mac"
if ! bt_is_trusted "$mac"; then
echo "→ Trusting $mac"
bluetoothctl trust "$mac" > /dev/null
fi
for ((i = 1; i <= BT_RETRIES; i++)); do
if bt_is_connected "$mac"; then
echo "✔ Connected: $mac"
return 0
fi
echo "→ Attempt $i/$BT_RETRIES: Connecting to $mac..."
if ! bt_is_paired "$mac"; then
bt_pair_device "$mac" || return 1
fi
bluetoothctl connect "$mac" > /dev/null 2>&1
sleep "$BT_DELAY"
if bt_is_connected "$mac"; then
echo "✔ Success!"
return 0
fi
done
echo "✖ Failed to connect $mac after $BT_RETRIES attempts"
return 1
}
bt_safe_disconnect() {
local mac="$1"
if bt_is_connected "$mac"; then
echo "Disconnecting $mac..."
bluetoothctl disconnect "$mac" > /dev/null 2>&1
else
echo "$mac is already offline."
fi
}
bt_stop_all() {
local devices=("${!1}")
for dev in "${devices[@]}"; do
local mac
mac=$(bt_resolve_device "$dev")
[[ -n "$mac" ]] && bt_safe_disconnect "$mac"
done
}
bt_start_all() {
local devices=("${!1}")
for dev in "${devices[@]}"; do
local mac
mac=$(bt_resolve_device "$dev")
[[ -n "$mac" ]] && bt_ensure_connected "$mac"
done
}
bt_status_all() {
local devices=("${!1}")
for dev in "${devices[@]}"; do
local mac
mac=$(bt_resolve_device "$dev")
if [[ -n "$mac" ]]; then
echo "--- $dev ($mac) ---"
if bt_is_connected "$mac"; then
echo "Status: CONNECTED"
elif bt_is_paired "$mac"; then
echo "Status: Paired (Offline)"
else
echo "Status: Not Paired / Unknown"
fi
fi
done
}
bt_scan() {
local scan_duration=30
declare -A seen_devices
local device_count=0
echo "Scanning for Bluetooth devices for $scan_duration seconds..."
echo "Press Ctrl+C to stop early"
echo "----------------------------------------"
trap 'echo ""; echo "Scan stopped"; exit 0' INT TERM
local start_time=$(date +%s)
local end_time=$((start_time + scan_duration))
while true; do
local current_time=$(date +%s)
if ((current_time >= end_time)); then
break
fi
while IFS= read -r line; do
if [[ $line =~ ^[[:space:]]*([0-9A-F:]{17})[[:space:]]+(.+)$ ]]; then
local mac="${BASH_REMATCH[1]}"
local name="${BASH_REMATCH[2]}"
if [[ -z "${seen_devices[$mac]:-}" ]]; then
seen_devices[$mac]="$name"
((device_count++))
echo "[$device_count] $mac - $name"
fi
fi
done < <(hcitool scan 2> /dev/null | tail -n +2)
sleep 1
done
echo "----------------------------------------"
echo "Scan complete. Found $device_count unique device(s):"
for mac in "${!seen_devices[@]}"; do
echo " $mac - ${seen_devices[$mac]}"
done
trap - INT TERM
}
bt_list() {
echo "=== BT_DEVICES ==="
for name in "${!BT_DEVICES[@]}"; do
echo " $name: ${BT_DEVICES[$name]}"
done
echo ""
echo "=== BT_AUTO_DEVICES ==="
for name in "${BT_AUTO_DEVICES[@]}"; do
echo " $name: ${BT_DEVICES[$name]}"
done
}
# -------------------------------------------------
# MAIN
# -------------------------------------------------
DEVICES=()
TIMED_MINUTES=0
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
-d | --device)
DEVICES+=("$2")
shift 2
;;
-t | --timed)
TIMED_MINUTES="$2"
shift 2
;;
start | stop | status | scan | list)
COMMAND="$1"
shift
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [-d|--device DEVICE] [-t|--timed MINUTES] {start|stop|status|scan|list}"
exit 1
;;
esac
done
}
parse_args "$@"
if [[ -z "${COMMAND:-}" ]]; then
echo "Usage: $0 [-d|--device DEVICE] [-t|--timed MINUTES] {start|stop|status|scan|list}"
exit 1
fi
if [[ ${#DEVICES[@]} -gt 0 ]]; then
for dev in "${DEVICES[@]}"; do
mac=$(bt_resolve_device "$dev")
if [[ -z "$mac" ]]; then
echo "ERROR: Unknown device '$dev'. Valid aliases: ${!BT_DEVICES[@]}"
exit 1
fi
done
fi
case "$COMMAND" in
start)
if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then
nmcli connection up "$WIFI_5G"
fi
start_bluetooth || exit 1
if [[ ${#DEVICES[@]} -gt 0 ]]; then
bt_start_all DEVICES[@]
else
bt_start_all BT_AUTO_DEVICES[@]
fi
if [[ "$TIMED_MINUTES" -gt 0 ]]; then
echo "Will disconnect after $TIMED_MINUTES minute(s)..."
sleep $((TIMED_MINUTES * 60))
echo "Time elapsed. Disconnecting..."
if [[ ${#DEVICES[@]} -gt 0 ]]; then
bt_stop_all DEVICES[@]
else
bt_stop_all BT_AUTO_DEVICES[@]
fi
echo "Stopping Bluetooth service..."
systemctl_bt stop
if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then
nmcli connection up "$WIFI_24G"
fi
fi
;;
stop)
if [[ ${#DEVICES[@]} -gt 0 ]]; then
bt_stop_all DEVICES[@]
else
bt_stop_all BT_AUTO_DEVICES[@]
fi
echo "Stopping Bluetooth service..."
systemctl_bt stop
if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then
nmcli connection up "$WIFI_24G"
fi
;;
status)
bluetoothctl show | grep -E "Name|Powered|Discoverable"
if [[ ${#DEVICES[@]} -gt 0 ]]; then
bt_status_all DEVICES[@]
else
bt_status_all BT_AUTO_DEVICES[@]
fi
;;
scan)
bt_scan
;;
list)
bt_list
;;
esac

26
.local/bin/cat-md

@ -1,26 +0,0 @@
#!/bin/bash
# Usage examples:
# ./cat-md file1.txt file2.txt # Output multiple files as markdown
# ./cat-md directory/ # Output all files in a directory
# ./cat-md file.txt | xclip -selection clipboard # Copy output to X11 clipboard
# ./cat-md file.txt | xsel --clipboard --input # Alternative using xsel
for path in "$@"; do
if [ -d "$path" ]; then
# If it's a directory, call ourselves with each file in it (non-recursively)
for file in "$path"/*; do
if [ -f "$file" ]; then
"$0" "$file"
fi
done
elif [ -f "$path" ]; then
# If it's a file, output the path and content
echo "$path:"
echo '```'
cat "$path"
echo
echo '```'
echo
fi
done

6
.local/share/applications/mimeinfo.cache

@ -1,6 +0,0 @@
[MIME Cache]
application/x-shellscript=nvim.desktop;
inode/directory=yazi.desktop;
text/html=nvim.desktop;
text/markdown=nvim.desktop;
text/plain=nvim.desktop;

8
.local/share/applications/nvim.desktop

@ -1,8 +0,0 @@
[Desktop Entry]
Type=Application
Name=Neovim
Exec=kitty nvim %F
Terminal=false
Icon=nvim
Categories=Utility;TextEditor;
MimeType=text/plain;text/markdown;text/html;application/x-shellscript;

8
.local/share/applications/yazi.desktop

@ -1,8 +0,0 @@
[Desktop Entry]
Type=Application
Name=Yazi
Exec=kitty yazi %f
Terminal=false
Icon=kitty
Categories=Utility;FileManager;
MimeType=inode/directory;

5
.tmux.conf

@ -2,9 +2,6 @@ set -g default-command /usr/bin/zsh
set -g default-terminal "tmux-256color"
run ~/.tmux.d/tmux-gruvbox/gruvbox-tpm.tmux
set -g @tmux-gruvbox 'dark' # or 'dark256', 'light', 'light256'
# disable mouse mode (to use selection mode from current terminal)
set-option -g mouse off
@ -29,7 +26,7 @@ bind-key -n Home send-key C-a
bind-key -n End send-key C-e
# set status bar color
# set -g status-bg "dark cyan"
set -g status-bg "dark cyan"
# window rename
set-option -g status-interval 5

6
.tmux.d/tmux-gruvbox/gruvbox-tpm.tmux

@ -1,6 +0,0 @@
#!/usr/bin/env bash
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CURRENT_DIR}/src/gruvbox-main.sh"
# vim: ai et ft=bash

98
.tmux.d/tmux-gruvbox/src/gruvbox-main.sh

@ -1,98 +0,0 @@
#!/bin/bash
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly CURRENT_DIR
# hold the array of all command to configure tmux theme
declare -a TMUX_CMDS
# load libraries
# shellcheck disable=1091
source "${CURRENT_DIR}/helper_methods.sh"
# shellcheck disable=1091
source "${CURRENT_DIR}/tmux_utils.sh"
readonly TMUX_GRUVBOX="@tmux-gruvbox"
readonly TMUX_GRUVBOX_STATUSBAR_ALPHA="@tmux-gruvbox-statusbar-alpha"
readonly TMUX_GRUVBOX_LEFT_STATUS_A="@tmux-gruvbox-left-status-a"
readonly TMUX_GRUVBOX_RIGHT_STAUTS_X="@tmux-gruvbox-right-status-x"
readonly TMUX_GRUVBOX_RIGHT_STAUTS_Y="@tmux-gruvbox-right-status-y"
readonly TMUX_GRUVBOX_RIGHT_STAUTS_Z="@tmux-gruvbox-right-status-z"
# define simple theme options (no color interpolation required)
readonly DEFAULT_THEME="dark256"
readonly DEFAULT_STATUSBAR_ALPHA='false'
# defaults for theme option (with color interpolation)
readonly DEFAULT_LEFT_STATUS_A='#S'
readonly DEFAULT_RIGHT_STATUS_X='%Y-%m-%d'
readonly DEFAULT_RIGHT_STATUS_Y='%H:%M'
readonly DEFAULT_RIGHT_STATUS_Z='#h'
main() {
TMUX_CMDS=() # clear
# load proper palette for the theme asap to avoid additional variable interpolation
local _theme
_theme=$(tmux_get_option "${TMUX_GRUVBOX}" "${DEFAULT_THEME}")
_statusbar_alpha=$(tmux_get_option "${TMUX_GRUVBOX_STATUSBAR_ALPHA}" "${DEFAULT_STATUSBAR_ALPHA}")
case "$_theme" in
light)
# shellcheck disable=1091
source "${CURRENT_DIR}/palette_gruvbox_light.sh"
# shellcheck disable=1091
source "${CURRENT_DIR}/theme_gruvbox_light.sh"
;;
light256)
# shellcheck disable=1091
source "${CURRENT_DIR}/palette_gruvbox_light256.sh"
# shellcheck disable=1091
source "${CURRENT_DIR}/theme_gruvbox_light256.sh"
;;
dark)
# shellcheck disable=1091
source "${CURRENT_DIR}/palette_gruvbox_dark.sh"
# shellcheck disable=1091
source "${CURRENT_DIR}/theme_gruvbox_dark.sh"
;;
dark256 | *)
# shellcheck disable=1091
source "${CURRENT_DIR}/palette_gruvbox_dark256.sh"
# shellcheck disable=1091
source "${CURRENT_DIR}/theme_gruvbox_dark.sh"
;;
esac
local _status_left _status_right _window_status_current_format _window_status_format
_status_left_a=$(tmux_get_option "$TMUX_GRUVBOX_LEFT_STATUS_A" "$DEFAULT_LEFT_STATUS_A")
_status_right_x=$(tmux_get_option "$TMUX_GRUVBOX_RIGHT_STAUTS_X" "$DEFAULT_RIGHT_STATUS_X")
_status_right_y=$(tmux_get_option "$TMUX_GRUVBOX_RIGHT_STAUTS_Y" "$DEFAULT_RIGHT_STATUS_Y")
_status_right_z=$(tmux_get_option "$TMUX_GRUVBOX_RIGHT_STAUTS_Z" "$DEFAULT_RIGHT_STATUS_Z")
local _theme_args
_theme_args=(
"$_status_left_a"
"$_status_right_x"
"$_status_right_y"
"$_status_right_z"
"$_statusbar_alpha"
)
case $_theme in
light256)
# light256 have slightly different colors placement then regular light 16-bit
theme_set_light256 "${_theme_args[@]}"
;;
light)
theme_set_light "${_theme_args[@]}"
;;
dark | dark256 | *)
theme_set_dark "${_theme_args[@]}"
;;
esac
# execute commands with tmux as array of options
tmux "${TMUX_CMDS[@]}"
}
main "$@"

19
.tmux.d/tmux-gruvbox/src/helper_methods.sh

@ -1,19 +0,0 @@
#!/bin/bash
# simply print passed array
#
# example
#
# myarray=()
# print_array myarray
#
print_array() {
local -n arr # -n available over bash 4.3
arr=$1
echo ""
echo "begin >>>"
printf "%s\n" "${arr[@]}"
echo "<<< end"
echo ""
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save