commit 4bfcf634ed639174f66675073230732a90a3d51b
Author: awy <awy@awy.one>
Date: Sun, 14 Dec 2025 00:18:52 +0300
init
Diffstat:
122 files changed, 5540 insertions(+), 0 deletions(-)
diff --git a/.config/fnott/fnott.ini b/.config/fnott/fnott.ini
@@ -0,0 +1,26 @@
+layer=overlay
+
+max-width=300
+min-width=300
+max-icon-size=32
+
+background=000000FF
+border-color=285577FF
+border-size=2
+
+title-font=monospace:size=14
+title-color=FFFFFFFF
+title-format=
+summary-font=monospace:size=14
+summary-color=FFFFFFFF
+body-font=monospace:size=14
+body-color=FFFFFFFF
+
+progress-bar-color=285577FF
+
+default-timeout=5
+idle-timeout=120
+
+[critical]
+border-color=900000FF
+default-timeout=15
diff --git a/.config/fontconfig/fonts.conf b/.config/fontconfig/fonts.conf
@@ -0,0 +1,40 @@
+<?xml version='1.0'?>
+<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+<fontconfig>
+ <alias>
+ <family>serif</family>
+ <prefer>
+ <family>FreeSerif</family>
+ <family>Noto Color Emoji</family>
+ <family>FontAwesome</family>
+ <family>SymbolsNerdFont Propo</family>
+ </prefer>
+ </alias>
+ <alias>
+ <family>sans-serif</family>
+ <prefer>
+ <family>FreeSans</family>
+ <family>Noto Color Emoji</family>
+ <family>FontAwesome</family>
+ <family>SymbolsNerdFont Propo</family>
+ </prefer>
+ </alias>
+ <alias>
+ <family>sans</family>
+ <prefer>
+ <family>FreeSans</family>
+ <family>Noto Color Emoji</family>
+ <family>FontAwesome</family>
+ <family>SymbolsNerdFont Propo</family>
+ </prefer>
+ </alias>
+ <alias>
+ <family>monospace</family>
+ <prefer>
+ <family>FreeMono</family>
+ <family>Noto Color Emoji</family>
+ <family>FontAwesome</family>
+ <family>SymbolsNerdFont Propo</family>
+ </prefer>
+ </alias>
+</fontconfig>
diff --git a/.config/foot/foot.ini b/.config/foot/foot.ini
@@ -0,0 +1,18 @@
+[main]
+include=/usr/share/foot/themes/xterm
+font=monospace:size=14
+font-size-adjustment=3
+gamma-correct-blending=false
+resize-by-cells=false
+initial-window-size-chars=80x24
+
+[key-bindings]
+clipboard-copy=Mod1+c
+clipboard-paste=Mod1+v
+scrollback-up-line=Mod1+k
+scrollback-down-line=Mod1+j
+font-increase=Mod1+Shift+k
+font-decrease=Mod1+Shift+j
+font-reset=Mod1+0
+show-urls-launch=Mod1+l
+show-urls-copy=Mod1+y
diff --git a/.config/lazygit/config.yml b/.config/lazygit/config.yml
@@ -0,0 +1,11 @@
+git:
+ paging:
+ colorArg: always
+ pager: delta --dark --paging=never
+keybinding:
+ universal:
+ nextBlock-alt2: <disabled>
+ nextTab: <tab>
+ prevTab: <disabled>
+gui:
+ border: single
diff --git a/.config/lazygit/themes.gitconfig b/.config/lazygit/themes.gitconfig
@@ -0,0 +1,667 @@
+# To use these themes, first include this file in your own gitconfig file:
+#
+# [include]
+# path = PATH/TO/delta/themes.gitconfig
+#
+# Then, in your own gitconfig file, activate the chosen theme, e.g.
+#
+# [delta]
+# features = kingfisher
+#
+# Please add your own themes to this file, and open a PR.
+#
+# Instructions:
+#
+# 1. The name of the theme must be the name of some sort of wild organism:
+# mammal, bird, plant, mollusk -- whatever. It can be in any language.
+#
+# 2. Use `delta --show-config` to list all the style settings that are active in
+# your current delta environment, but only include settings in your theme
+# that are essential to its appearance.
+#
+# 3. Include either `dark = true` or `light = true` according to whether it is
+# designed for a light or dark terminal background. (This marks a feature as
+# a "theme", causing it to be picked up by `delta --show-themes`).
+#
+# 4. Feel free to include a comment line indicating who is the author of the
+# theme. E.g. a link to your github user page.
+
+[delta "colibri"]
+ # author: https://github.com/pablospe
+ # Based on woolly-mammoth: https://github.com/Kr1ss-XD.
+ commit-decoration-style = 130 box
+ dark = true
+ file-decoration-style = "#606018" overline
+ file-added-label = [●]
+ file-copied-label = [C]
+ file-modified-label = [+]
+ file-removed-label = [⛌]
+ file-renamed-label = [→]
+ file-style = 232 bold 184
+ hunk-header-style = syntax bold italic 237
+ line-numbers = true
+ line-numbers-left-format = "{nm:>1}┊"
+ line-numbers-left-style = red
+ line-numbers-minus-style = red bold
+ line-numbers-plus-style = green bold
+ line-numbers-right-format = " {np:>1}┊"
+ line-numbers-right-style = green
+ line-numbers-zero-style = "#545474" italic
+ minus-emph-style = normal "#80002a"
+ minus-style = normal "#5e0000"
+ plus-emph-style = syntax bold "#007e5e"
+ plus-style = syntax "#003500"
+ syntax-theme = OneHalfDark
+ whitespace-error-style = "#80002a" reverse
+ zero-style = syntax
+ blame-format = "{author:<18} ({commit:>7}) ┊{timestamp:^16}┊ "
+
+[delta "collared-trogon"]
+ # author: https://github.com/clnoll
+ commit-decoration-style = bold box ul
+ dark = true
+ file-decoration-style = none
+ file-style = omit
+ hunk-header-decoration-style = "#022b45" box ul
+ hunk-header-file-style = "#999999"
+ hunk-header-line-number-style = bold "#003300"
+ hunk-header-style = file line-number syntax
+ line-numbers = true
+ line-numbers-left-style = "#022b45"
+ line-numbers-minus-style = "#80002a"
+ line-numbers-plus-style = "#003300"
+ line-numbers-right-style = "#022b45"
+ line-numbers-zero-style = "#999999"
+ minus-emph-style = normal "#80002a"
+ minus-style = normal "#330011"
+ plus-emph-style = syntax "#003300"
+ plus-style = syntax "#001a00"
+ syntax-theme = Nord
+
+[delta "coracias-caudatus"]
+ # author: https://github.com/clnoll
+ commit-decoration-style = ol "#7536ff"
+ commit-style = "#200078"
+ file-decoration-style = none
+ file-style = omit
+ hunk-header-decoration-style = "#cfd6ff" ul
+ hunk-header-file-style = "#858dff"
+ hunk-header-line-number-style = "#7536ff"
+ hunk-header-style = file line-number syntax
+ light = true
+ line-numbers = true
+ line-numbers-left-format = "{nm:>4} ."
+ line-numbers-left-style = "#e3ab02"
+ line-numbers-minus-style = "#ff38b6"
+ line-numbers-plus-style = "#00e0c2"
+ line-numbers-right-format = "{np:>4} "
+ line-numbers-right-style = white
+ line-numbers-zero-style = "#cccccc"
+ minus-emph-style = bold "#ff3838" "#ffe3f7"
+ minus-style = "#ff0080"
+ plus-emph-style = "#008a81" bold "#00ffbf"
+ plus-style = syntax "#cffff3"
+ syntax-theme = GitHub
+
+[delta "hoopoe"]
+ # author: https://github.com/dandavison
+ light = true
+ pink = "#ffe0e0"
+ dark-pink = "#ffc0c0"
+ green = "#d0ffd0"
+ dark-green = "#a0efa0"
+ dark-green-2 = "#067a00"
+ minus-style = normal hoopoe.pink
+ minus-emph-style = normal hoopoe.dark-pink
+ minus-non-emph-style = minus-style
+ plus-style = syntax hoopoe.green
+ plus-emph-style = syntax hoopoe.dark-green
+ plus-non-emph-style = plus-style
+ minus-empty-line-marker-style = minus-style
+ plus-empty-line-marker-style = plus-style
+ commit-decoration-style = blue ol
+ commit-style = raw
+ file-style = omit
+ hunk-header-decoration-style = blue box
+ hunk-header-file-style = red
+ hunk-header-line-number-style = hoopoe.dark-green-2
+ hunk-header-style = file line-number syntax
+ syntax-theme = GitHub
+ zero-style = syntax
+
+[delta "tangara-chilensis"]
+ # author: https://github.com/clnoll
+ commit-decoration-style = bold box ul "#34fd50"
+ dark = true
+ file-decoration-style = none
+ file-style = omit
+ hunk-header-decoration-style = "#00b494" box ul
+ hunk-header-file-style = "#999999"
+ hunk-header-line-number-style = bold "#03a4ff"
+ hunk-header-style = file line-number syntax
+ line-numbers = true
+ line-numbers-left-style = black
+ line-numbers-minus-style = "#B10036"
+ line-numbers-plus-style = "#03a4ff"
+ line-numbers-right-style = black
+ line-numbers-zero-style = "#999999"
+ minus-emph-style = normal "#de004e"
+ minus-style = normal "#990017"
+ plus-emph-style = syntax "#03a4ff"
+ plus-style = syntax "#450eff"
+ side-by-side = true
+ syntax-theme = Vibrant Sunburst
+
+[delta "villsau"]
+ # author: https://github.com/torarnv
+ dark = true
+ file-style = omit
+ hunk-header-decoration-style = omit
+ hunk-header-file-style = magenta
+ hunk-header-line-number-style = dim magenta
+ hunk-header-style = file line-number syntax
+ line-numbers = false
+ minus-emph-style = bold red 52
+ minus-empty-line-marker-style = normal "#3f0001"
+ minus-non-emph-style = dim red
+ minus-style = bold red
+ plus-emph-style = bold green 22
+ plus-empty-line-marker-style = normal "#002800"
+ plus-non-emph-style = dim green
+ plus-style = bold green
+ syntax-theme = OneHalfDark
+ whitespace-error-style = reverse red
+ zero-style = dim syntax
+
+[delta "woolly-mammoth"]
+ # author: https://github.com/Kr1ss-XD
+ commit-decoration-style = 232 130 box
+ commit-style = 232 bold italic 130
+ dark = true
+ file-added-label = [+]
+ file-copied-label = [C]
+ file-decoration-style = "#606018" overline
+ file-modified-label = [M]
+ file-removed-label = [-]
+ file-renamed-label = [R]
+ file-style = 232 bold 184
+ hunk-header-decoration-style = none
+ hunk-header-style = syntax bold italic 237
+ line-numbers = true
+ line-numbers-left-format = "{nm:>1}┊"
+ line-numbers-left-style = red
+ line-numbers-minus-style = red italic black
+ line-numbers-plus-style = green italic black
+ line-numbers-right-format = "{np:>1}┊"
+ line-numbers-right-style = green
+ line-numbers-zero-style = "#545474" italic
+ minus-emph-style = syntax bold "#780000"
+ minus-style = syntax "#400000"
+ plus-emph-style = syntax bold "#007800"
+ plus-style = syntax "#004000"
+ syntax-theme = Vibrant Sunburst
+ whitespace-error-style = "#280050" reverse
+ zero-style = syntax
+ blame-format = "{author:<18} ({commit:>7}) ┊{timestamp:^16}┊ "
+ blame-palette = "#101010 #200020 #002800 #000028 #202000 #280000 #002020 #002800 #202020"
+
+[delta "calochortus-lyallii"]
+ # author: https://github.com/manojkarthick
+ commit-decoration-style = none
+ dark = true
+ file-added-label = [+]
+ file-copied-label = [C]
+ file-decoration-style = none
+ file-modified-label = [M]
+ file-removed-label = [-]
+ file-renamed-label = [R]
+ file-style = 232 bold 184
+ hunk-header-decoration-style = none
+ hunk-header-file-style = "#999999"
+ hunk-header-line-number-style = bold "#03a4ff"
+ hunk-header-style = file line-number syntax
+ line-numbers = true
+ line-numbers-left-style = black
+ line-numbers-minus-style = "#B10036"
+ line-numbers-plus-style = "#03a4ff"
+ line-numbers-right-style = black
+ line-numbers-zero-style = "#999999"
+ minus-emph-style = syntax bold "#780000"
+ minus-style = syntax "#400000"
+ plus-emph-style = syntax bold "#007800"
+ plus-style = syntax "#004000"
+ whitespace-error-style = "#280050" reverse
+ zero-style = syntax
+ syntax-theme = Nord
+
+[delta "mantis-shrimp"]
+ #author: https://github.com/2kabhishek
+ dark = true
+ side-by-side = true
+ keep-plus-minus-markers = true
+ hyperlinks = true
+ file-added-label = [+]
+ file-copied-label = [==]
+ file-modified-label = [*]
+ file-removed-label = [-]
+ file-renamed-label = [->]
+ file-style = omit
+ zero-style = syntax
+ syntax-theme = Monokai Extended
+ commit-decoration-style ="#11ce16" box
+ commit-style = "#ffd21a" bold italic
+ hunk-header-decoration-style = "#1688f0" box ul
+ hunk-header-file-style = "#c63bee" ul bold
+ hunk-header-line-number-style = "#ffd21a" box bold
+ hunk-header-style = file line-number syntax bold italic
+ line-numbers = true
+ line-numbers-left-format = "{nm:>1}|"
+ line-numbers-left-style = "#1688f0"
+ line-numbers-minus-style = "#ff0051" bold
+ line-numbers-plus-style = "#03e57f" bold
+ line-numbers-right-format = "{np:>1}|"
+ line-numbers-right-style = "#1688f0"
+ line-numbers-zero-style = "#aaaaaa" italic
+ minus-emph-style = syntax bold "#b80000"
+ minus-style = syntax "#5d001e"
+ plus-emph-style = syntax bold "#007800"
+ plus-style = syntax "#004433"
+ whitespace-error-style = "#280050"
+
+[delta "mantis-shrimp-lite"]
+ #author: https://github.com/2kabhishek
+ dark = true
+ side-by-side = true
+ keep-plus-minus-markers = true
+ file-added-label = [+]
+ file-copied-label = [==]
+ file-modified-label = [*]
+ file-removed-label = [-]
+ file-renamed-label = [->]
+ file-style = omit
+ zero-style = syntax
+ syntax-theme = Monokai Extended
+ commit-decoration-style = green box
+ commit-style = yellow bold italic
+ hunk-header-decoration-style = blue box ul
+ hunk-header-file-style = purple ul bold
+ hunk-header-line-number-style = yellow box bold
+ hunk-header-style = file line-number syntax bold italic
+ line-numbers = true
+ line-numbers-left-format = "{nm:>1}|"
+ line-numbers-left-style = blue
+ line-numbers-minus-style = red bold
+ line-numbers-plus-style = green bold
+ line-numbers-right-format = "{np:>1}|"
+ line-numbers-right-style = blue
+ line-numbers-zero-style = white italic
+ minus-emph-style = syntax bold red
+ plus-emph-style = syntax bold green
+ whitespace-error-style = purple bold
+
+[delta "zebra-dark"]
+ minus-style = syntax "#330f0f"
+ minus-emph-style = syntax "#4f1917"
+ plus-style = syntax "#0e2f19"
+ plus-emph-style = syntax "#174525"
+ map-styles = \
+ bold purple => syntax "#330f29", \
+ bold blue => syntax "#271344", \
+ bold cyan => syntax "#0d3531", \
+ bold yellow => syntax "#222f14"
+ zero-style = syntax
+ whitespace-error-style = "#aaaaaa"
+
+[delta "zebra-light"]
+ minus-style = syntax "#fbdada"
+ minus-emph-style = syntax "#f6b6b6"
+ plus-style = syntax "#d6ffd6"
+ plus-emph-style = syntax "#adffad"
+ map-styles = \
+ bold purple => syntax "#feecf7", \
+ bold blue => syntax "#e5dff6", \
+ bold cyan => syntax "#d8fdf6", \
+ bold yellow => syntax "#f4ffe0"
+ zero-style = syntax
+ whitespace-error-style = "#aaaaaa"
+
+[delta "chameleon"]
+ #author: https://github.com/AirOnSkin
+ dark = true
+ line-numbers = true
+ side-by-side = true
+ keep-plus-minus-markers = false
+ syntax-theme = Nord
+ file-style = "#434C5E" bold
+ file-decoration-style = "#434C5E" ul
+ file-added-label = [+]
+ file-copied-label = [==]
+ file-modified-label = [*]
+ file-removed-label = [-]
+ file-renamed-label = [->]
+ hunk-header-style = omit
+ line-numbers-left-format = " {nm:>3} │"
+ line-numbers-left-style = red
+ line-numbers-right-format = " {np:>3} │"
+ line-numbers-right-style = green
+ line-numbers-minus-style = red italic black
+ line-numbers-plus-style = green italic black
+ line-numbers-zero-style = "#434C5E" italic
+ minus-style = bold red
+ minus-emph-style = bold "#202020" "#FF5555"
+ minus-non-emph-style = bold
+ plus-style = bold green
+ plus-emph-style = bold "#202020" "#50FA7B"
+ plus-non-emph-style = bold
+ zero-style = syntax
+ blame-code-style = syntax
+ blame-format = "{author:<18} ({commit:>9}) {timestamp:^16}"
+ blame-palette = "#2E3440" "#3B4252" "#434C5E" "#4C566A"
+ merge-conflict-begin-symbol = ~
+ merge-conflict-end-symbol = ~
+ merge-conflict-ours-diff-header-style = "#F1FA8C" bold
+ merge-conflict-ours-diff-header-decoration-style = "#434C5E" box
+ merge-conflict-theirs-diff-header-style = "#F1FA8C" bold
+ merge-conflict-theirs-diff-header-decoration-style = "#434C5E" box
+
+[delta "gruvmax-fang"]
+ # author: https://github.com/maxfangx
+ # General appearance
+ dark = true
+ syntax-theme = gruvbox-dark
+ # File
+ file-style = "#FFFFFF" bold
+ file-added-label = [+]
+ file-copied-label = [==]
+ file-modified-label = [*]
+ file-removed-label = [-]
+ file-renamed-label = [->]
+ file-decoration-style = "#434C5E" ul
+ file-decoration-style = "#84786A" ul
+ # No hunk headers
+ hunk-header-style = omit
+ # Line numbers
+ line-numbers = true
+ line-numbers-left-style = "#84786A"
+ line-numbers-right-style = "#84786A"
+ line-numbers-minus-style = "#A02A11"
+ line-numbers-plus-style = "#479B36"
+ line-numbers-zero-style = "#84786A"
+ line-numbers-left-format = " {nm:>3} │"
+ line-numbers-right-format = " {np:>3} │"
+ # Diff contents
+ inline-hint-style = syntax
+ minus-style = syntax "#330011"
+ minus-emph-style = syntax "#80002a"
+ minus-non-emph-style = syntax auto
+ plus-style = syntax "#001a00"
+ plus-emph-style = syntax "#003300"
+ plus-non-emph-style = syntax auto
+ whitespace-error-style = "#FB4934" reverse
+ # Commit hash
+ commit-decoration-style = normal box
+ commit-style = "#ffffff" bold
+ # Blame
+ blame-code-style = syntax
+ blame-format = "{author:>18} ({commit:>8}) {timestamp:<13} "
+ blame-palette = "#000000" "#1d2021" "#282828" "#3c3836"
+ # Merge conflicts
+ merge-conflict-begin-symbol = ⌃
+ merge-conflict-end-symbol = ⌄
+ merge-conflict-ours-diff-header-style = "#FABD2F" bold
+ merge-conflict-theirs-diff-header-style = "#FABD2F" bold overline
+ merge-conflict-ours-diff-header-decoration-style = ''
+ merge-conflict-theirs-diff-header-decoration-style = ''
+
+[delta "discord"]
+ commit-style = omit
+ file-style = 34 ul
+ file-decoration-style = none
+ hunk-header-style = omit
+ minus-style = 31
+ minus-non-emph-style = 31
+ minus-emph-style = 40
+ minus-empty-line-marker-style = 31
+ zero-style = 30
+ plus-style = 32
+ plus-non-emph-style = 32
+ plus-emph-style = 40
+ grep-file-style = 34
+ grep-line-number-style = 34
+ whitespace-error-style = 41
+ blame-code-style = omit
+ true-color = never
+ file-modified-label = changed:
+ right-arrow = >
+ hyperlinks = false
+ keep-plus-minus-markers = true
+ diff-stat-align-width = 10
+ syntax-theme = none
+ width = variable
+
+[delta "mellow-barbet"]
+ # author: https://github.com/kvrohit
+ # To configure terminal colors see https://github.com/kvrohit/mellow.nvim#terminals
+ dark = true
+ syntax-theme = base16
+ line-numbers = true
+ side-by-side = true
+ file-style = brightwhite
+ file-decoration-style = none
+ file-added-label = [+]
+ file-copied-label = [==]
+ file-modified-label = [*]
+ file-removed-label = [-]
+ file-renamed-label = [->]
+ hunk-header-decoration-style = "#3e3e43" box ul
+ plus-style = brightgreen black
+ plus-emph-style = black green
+ minus-style = brightred black
+ minus-emph-style = black red
+ line-numbers-minus-style = brightred
+ line-numbers-plus-style = brightgreen
+ line-numbers-left-style = "#3e3e43"
+ line-numbers-right-style = "#3e3e43"
+ line-numbers-zero-style = "#57575f"
+ zero-style = syntax
+ whitespace-error-style = black bold
+ blame-code-style = syntax
+ blame-palette = "#161617" "#1b1b1d" "#2a2a2d" "#3e3e43"
+ merge-conflict-begin-symbol = ~
+ merge-conflict-end-symbol = ~
+ merge-conflict-ours-diff-header-style = yellow bold
+ merge-conflict-ours-diff-header-decoration-style = "#3e3e43" box
+ merge-conflict-theirs-diff-header-style = yellow bold
+ merge-conflict-theirs-diff-header-decoration-style = "#3e3e43" box
+
+[delta "arctic-fox"]
+ # author: https://github.com/anthony-halim
+ dark = true
+ syntax-theme = Nord
+ file-added-label = [+]
+ file-copied-label = [==]
+ file-modified-label = [*]
+ file-removed-label = [-]
+ file-renamed-label = [->]
+ file-style = omit
+ hunk-header-decoration-style = "#5E81AC" ul
+ hunk-header-file-style = blue ul bold
+ hunk-header-line-number-style = yellow box bold
+ hunk-header-style = file line-number syntax bold italic
+ plus-style = brightgreen
+ plus-emph-style = black green
+ minus-style = brightred
+ minus-emph-style = black red
+ line-numbers = true
+ line-numbers-minus-style = brightred
+ line-numbers-plus-style = brightgreen
+ line-numbers-left-style = "#5E81AC"
+ line-numbers-right-style = "#5E81AC"
+ line-numbers-zero-style = "#4C566A"
+ zero-style = syntax
+ whitespace-error-style = black bold
+ blame-code-style = syntax
+ blame-format = "{author:<18} {commit:<6} {timestamp:<15}"
+ blame-palette = "#2E3440" "#3B4252" "#434C5E"
+ merge-conflict-begin-symbol = ~
+ merge-conflict-end-symbol = ~
+ merge-conflict-ours-diff-header-style = yellow bold
+ merge-conflict-ours-diff-header-decoration-style = "#5E81AC" box
+ merge-conflict-theirs-diff-header-style = yellow bold
+ merge-conflict-theirs-diff-header-decoration-style = "#5E81AC" box
+
+[delta "corvus"]
+ # author: https://github.com/evilwaveforms
+ dark = true
+ commit-style = "#949494"
+ file-style = omit
+ syntax-theme = none
+ hunk-header-decoration-style = "#949494" ul
+ hunk-header-file-style = "#949494"
+ hunk-header-style = "#949494"
+ line-numbers = true
+ line-numbers-left-style = "#949494"
+ line-numbers-right-style = "#949494"
+ line-numbers-left-format = "{nm:>2}|"
+ line-numbers-right-format = "{np:>3} "
+ line-numbers-plus-style = "#54c047"
+ line-numbers-minus-style = bold "#591102"
+ plus-style = "#54c047"
+ plus-emph-style = bold "#54c047"
+ plus-non-emph-style = dim "#54c047"
+ minus-style = normal "#591102"
+ minus-emph-style = normal "#591102"
+ minus-non-emph-style = bold "#591102"
+ blame-code-style = omit
+ blame-format = "{author:<18} {commit:<6} {timestamp:<15}"
+ blame-palette = "#000000" "#343434"
+ zero-style = dim
+
+[delta "platypus"]
+ # Author: https://github.com/sarpuser
+ dark = true
+ side-by-side = true
+ true-color = always
+ file-added-label = [+]
+ file-copied-label = [==]
+ file-modified-label = [M]
+ file-removed-label = [-]
+ file-renamed-label = [->]
+ file-style = "#ff9b00" ul bold
+ file-decoration-style = "#ea00ff" box ul
+ zero-style = syntax
+ syntax-theme = Solarized (dark)
+ commit-decoration-style ="#ea00ff" ul
+ hunk-header-decoration-style = omit
+ hunk-header-file-style = "#ff9b00" ul bold
+ hunk-header-line-number-style = "#ffd21a" bold
+ hunk-header-style = line-number syntax bold italic
+ line-numbers = true
+ line-numbers-left-format = "{nm:>1}|"
+ line-numbers-left-style = "#ea00ff"
+ line-numbers-minus-style = "#ff0051" bold
+ line-numbers-plus-style = "#1ac71e" bold
+ line-numbers-right-format = "{np:>1}|"
+ line-numbers-right-style = "#ea00ff"
+ line-numbers-zero-style = "#aaaaaa" italic
+ minus-emph-style = syntax bold "#b80000"
+ minus-style = syntax "#5d001e"
+ plus-emph-style = syntax bold "#1a861a"
+ plus-style = syntax "#2a5e37"
+ whitespace-error-style = "#280050"
+ wrap-max-lines = unlimited
+ wrap-right-percent = 1
+
+[delta "weeping-willow"]
+ # See 'mirthful-willow' for light mode version.
+ # Heavily inspired by the themes above. Thank you. <3
+ # author: https://github.com/lvdh
+ # colors: `pastel list`
+ dark = true
+ right-arrow = >
+ syntax-theme = Coldark-Dark
+ # -- git
+ blame-format = " ({commit:>7}) {author:<18} {timestamp:^13} "
+ blame-palette = "normal midnightblue indigo navy darkblue darkslateblue purple rebeccapurple darkviolet"
+ commit-decoration-style = none
+ commit-style = bold black orange
+ # -- grep
+ grep-file-style = olive
+ grep-line-number-style = olive
+ # -- diff
+ keep-plus-minus-markers = true
+ line-numbers = true
+ line-numbers-minus-style = red
+ line-numbers-plus-style = green
+ line-numbers-left-style = gray
+ line-numbers-left-format = "{nm:>1}┊"
+ line-numbers-right-style = gray
+ line-numbers-right-format = "{np:>1}┊"
+ line-numbers-zero-style = gray
+ minus-emph-style = ghostwhite crimson underline
+ minus-empty-line-marker-style = syntax maroon
+ minus-style = syntax darkred
+ plus-emph-style = ghostwhite olivedrab underline
+ plus-empty-line-marker-style = syntax seagreen
+ plus-style = syntax darkgreen
+ whitespace-error-style = black ghostwhite
+ zero-style = syntax
+ # -- decorations
+ file-decoration-style = olive overline
+ file-added-label = [+]
+ file-copied-label = [*]
+ file-modified-label = [~]
+ file-removed-label = [-]
+ file-renamed-label = [>]
+ file-style = orange bold
+ hunk-header-decoration-style = none
+ hunk-header-file-style = olive
+ hunk-header-line-number-style = orange
+ hunk-header-style = file line-number orchid
+
+[delta "mirthful-willow"]
+ # See 'weeping-willow' for dark mode version.
+ # Heavily inspired by the themes above. Thank you. <3
+ # author: https://github.com/lvdh
+ # colors: `pastel list`
+ light = true
+ right-arrow = >
+ syntax-theme = Coldark-Cold
+ # -- git
+ blame-format = " ({commit:>7}) {author:<18} {timestamp:^13} "
+ blame-palette = "powderblue papayawhip thistle skyblue lavender plum paleturquoise lightcyan violet"
+ commit-decoration-style = none
+ commit-style = bold black orange
+ # -- grep
+ grep-file-style = darkgoldenrod
+ grep-line-number-style = darkgoldenrod
+ # -- diff
+ keep-plus-minus-markers = true
+ line-numbers = true
+ line-numbers-minus-style = red
+ line-numbers-plus-style = green
+ line-numbers-left-style = gray
+ line-numbers-left-format = "{nm:>1}┊"
+ line-numbers-right-style = gray
+ line-numbers-right-format = "{np:>1}┊"
+ line-numbers-zero-style = gray
+ minus-emph-style = ghostwhite tomato underline
+ minus-empty-line-marker-style = syntax orangered
+ minus-style = syntax lightpink
+ plus-emph-style = ghostwhite limegreen underline
+ plus-empty-line-marker-style = syntax forestgreen
+ plus-style = syntax lightgreen
+ whitespace-error-style = black ghostwhite
+ zero-style = syntax
+ # -- decorations
+ file-decoration-style = darkgoldenrod overline
+ file-added-label = [+]
+ file-copied-label = [*]
+ file-modified-label = [~]
+ file-removed-label = [-]
+ file-renamed-label = [>]
+ file-style = orange bold
+ hunk-header-decoration-style = none
+ hunk-header-file-style = darkgoldenrod
+ hunk-header-line-number-style = orange
+ hunk-header-style = file line-number darkviolet
diff --git a/.config/mimeapps.list b/.config/mimeapps.list
@@ -0,0 +1,20 @@
+[Default Applications]
+
+# xdg-open will use these settings to determine how to open filetypes.
+# These .desktop entries can also be seen and changed in ~/.local/share/applications/
+
+text/x-shellscript=text.desktop;
+x-scheme-handler/magnet=torrent.desktop;
+application/x-bittorrent=torrent.desktop;
+x-scheme-handler/mailto=mail.desktop;
+text/plain=text.desktop;
+application/postscript=pdf.desktop;
+application/pdf=pdf.desktop;
+image/png=img.desktop;
+image/jpeg=img.desktop;
+image/gif=img.desktop;
+application/rss+xml=rss.desktop
+video/x-matroska=video.desktop
+video/mp4=video.desktop
+x-scheme-handler/lbry=lbry.desktop
+inode/directory=file.desktop
diff --git a/.config/mpd/mpd.conf b/.config/mpd/mpd.conf
@@ -0,0 +1,19 @@
+music_directory "/mnt/ssd/music"
+playlist_directory "~/.config/mpd/playlists"
+
+auto_update "yes"
+bind_to_address "127.0.0.1"
+restore_paused "yes"
+max_output_buffer_size "16384"
+
+audio_output {
+ type "pipewire"
+ name "PipeWire Sound Server"
+}
+
+audio_output {
+ type "fifo"
+ name "Visualizer feed"
+ path "/tmp/mpd.fifo"
+ format "44100:16:2"
+}
diff --git a/.config/mpv/input.conf b/.config/mpv/input.conf
@@ -0,0 +1,5 @@
+l seek 5
+h seek -5
+j seek -60
+k seek 60
+S cycle sub
diff --git a/.config/mpv/mpv.conf b/.config/mpv/mpv.conf
@@ -0,0 +1,15 @@
+# uosc provides seeking & volume indicators (via flash-timeline and flash-volume commands)
+# if you decide to use them, you don't need osd-bar
+osd-bar=no
+
+# uosc will draw its own window controls and border if you disable window border
+border=no
+
+profile=high-quality
+vo=gpu-next
+gpu-api=vulkan
+gpu-context=waylandvk
+hwdec=auto
+target-colorspace-hint=yes
+alang=eng
+slang=
diff --git a/.config/newsraft/config b/.config/newsraft/config
@@ -0,0 +1,11 @@
+open-in-browser-command linkhandler "%l"
+#bind t exec qndl "%l"
+#bind a exec "tsp yt-dlp --embed-metadata -xic -f bestaudio/best --restrict-filenames"
+unbind d
+unbind a
+unbind A
+unbind v
+bind a mark-read; jump-to-next
+bind A mark-unread; jump-to-next
+bind v exec setsid -f mpv "%l"
+bind d exec setsid -f dmenuhandler "%l"
diff --git a/.config/nvim/init.lua b/.config/nvim/init.lua
@@ -0,0 +1,19 @@
+-- Bootstrap lazy.nvim
+local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
+if not (vim.uv or vim.loop).fs_stat(lazypath) then
+ local lazyrepo = "https://github.com/folke/lazy.nvim.git"
+ local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
+ if vim.v.shell_error ~= 0 then
+ vim.api.nvim_echo({
+ { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
+ { out, "WarningMsg" },
+ { "\nPress any key to exit..." },
+ }, true, {})
+ vim.fn.getchar()
+ os.exit(1)
+ end
+end
+vim.opt.rtp:prepend(lazypath)
+
+require("options")
+require("lazy").setup("plugins")
diff --git a/.config/nvim/lua/options.lua b/.config/nvim/lua/options.lua
@@ -0,0 +1,17 @@
+vim.o.number = true
+vim.o.relativenumber = true
+vim.o.wrap = false
+vim.o.tabstop = 2
+vim.o.shiftwidth = 2
+vim.o.softtabstop = 2
+vim.o.expandtab = true
+vim.o.swapfile = false
+vim.g.mapleader = " "
+vim.o.clipboard = "unnamedplus"
+vim.o.undofile = true
+vim.o.cursorline = true
+vim.o.cursorlineopt = "number"
+vim.o.title = true
+vim.o.signcolumn = "yes"
+vim.g.mapleader = " "
+vim.api.nvim_set_keymap('n', ',c', ':w! | !compiler "%:p"<CR>', { noremap = true, silent = true })
diff --git a/.config/nvim/lua/plugins.lua b/.config/nvim/lua/plugins.lua
@@ -0,0 +1 @@
+return {}
diff --git a/.config/nvim/lua/plugins/comment.lua b/.config/nvim/lua/plugins/comment.lua
@@ -0,0 +1,8 @@
+return {
+ {
+ "numToStr/Comment.nvim",
+ config = function()
+ require('Comment').setup()
+ end
+ }
+}
diff --git a/.config/nvim/lua/plugins/completions.lua b/.config/nvim/lua/plugins/completions.lua
@@ -0,0 +1,44 @@
+return {
+ {
+ "hrsh7th/cmp-nvim-lsp"
+ },
+ {
+ "L3MON4D3/LuaSnip",
+ dependencies = {
+ "saadparwaiz1/cmp_luasnip",
+ "rafamadriz/friendly-snippets",
+ },
+ },
+ {
+ "hrsh7th/nvim-cmp",
+ config = function()
+ local cmp = require("cmp")
+ require("luasnip.loaders.from_vscode").lazy_load()
+
+ cmp.setup({
+ snippet = {
+ expand = function(args)
+ require("luasnip").lsp_expand(args.body)
+ end,
+ },
+ window = {
+ -- completion = cmp.config.window.bordered(),
+ -- documentation = cmp.config.window.bordered(),
+ },
+ mapping = cmp.mapping.preset.insert({
+ ["<C-b>"] = cmp.mapping.scroll_docs(-4),
+ ["<C-f>"] = cmp.mapping.scroll_docs(4),
+ ["<C-Space>"] = cmp.mapping.complete(),
+ ["<C-e>"] = cmp.mapping.abort(),
+ ["<CR>"] = cmp.mapping.confirm({ select = true }),
+ }),
+ sources = cmp.config.sources({
+ { name = "nvim_lsp" },
+ { name = "luasnip" }, -- For luasnip users.
+ }, {
+ { name = "buffer" },
+ }),
+ })
+ end,
+ },
+}
diff --git a/.config/nvim/lua/plugins/explorer.lua b/.config/nvim/lua/plugins/explorer.lua
@@ -0,0 +1,27 @@
+--[[ return {
+ "nvim-neo-tree/neo-tree.nvim",
+ branch = "v3.x",
+ dependencies = {
+ "nvim-lua/plenary.nvim",
+ "nvim-mini/mini.icons",
+ "MunifTanjim/nui.nvim",
+ },
+ config = function()
+ vim.keymap.set("n", "<C-n>", ":Neotree filesystem reveal left<CR>", {})
+ vim.keymap.set("n", "<leader>bf", ":Neotree buffers reveal float<CR>", {})
+ require("mini.icons").mock_nvim_web_devicons()
+ end,
+} ]]
+
+return {
+ {
+ 'stevearc/oil.nvim',
+ ---@module 'oil'
+ ---@type oil.SetupOpts
+ opts = {},
+ dependencies = { { "nvim-mini/mini.icons", opts = {} } },
+ lazy = false,
+ vim.keymap.set("n", "<leader>e", "<cmd>Oil<CR>", {}),
+ -- vim.keymap.set("n", "<leader>bf", "<cmd>Oil --float<CR>", {})
+ }
+}
diff --git a/.config/nvim/lua/plugins/gitsigns.lua b/.config/nvim/lua/plugins/gitsigns.lua
@@ -0,0 +1,11 @@
+return {
+ {
+ "tpope/vim-fugitive",
+ },
+ {
+ "lewis6991/gitsigns.nvim",
+ config = function()
+ require("gitsigns").setup()
+ end,
+ }
+}
diff --git a/.config/nvim/lua/plugins/indent.lua b/.config/nvim/lua/plugins/indent.lua
@@ -0,0 +1,8 @@
+return {
+ {
+ "lukas-reineke/indent-blankline.nvim",
+ config = function()
+ require("ibl").setup()
+ end,
+ }
+}
diff --git a/.config/nvim/lua/plugins/lsp.lua b/.config/nvim/lua/plugins/lsp.lua
@@ -0,0 +1,57 @@
+return {
+ {
+ "williamboman/mason.nvim",
+ lazy = false,
+ config = function()
+ require("mason").setup()
+ end,
+ },
+ {
+ "williamboman/mason-lspconfig.nvim",
+ lazy = false,
+ opts = {
+ auto_install = true,
+ ensure_installed = { "helm_ls", "dockerls" },
+ },
+ },
+ {
+ "neovim/nvim-lspconfig",
+ lazy = false,
+ config = function()
+ local capabilities = require('cmp_nvim_lsp').default_capabilities()
+
+ vim.lsp.enable({
+ "lua_ls", "clangd", "rust_analyzer", "bashls",
+ "html", "cssls", "jsonls", "helm_ls", "yamlls",
+ "dockerfile-language-server", "tinymist", "gopls",
+ "pylsp"
+ })
+
+ vim.lsp.config("*", {
+ capabilities = capabilities
+ })
+
+ vim.diagnostic.config({
+ virtual_text = {
+ prefix = '',
+ spacing = 4,
+ },
+ signs = {
+ text = {
+ [vim.diagnostic.severity.ERROR] = '',
+ [vim.diagnostic.severity.WARN] = '',
+ },
+ },
+ underline = true,
+ update_in_insert = true,
+ severity_sort = true,
+ })
+
+ vim.keymap.set('n', '<leader>lf', vim.lsp.buf.format)
+ -- vim.keymap.set("n", "K", vim.lsp.buf.hover, {})
+ -- vim.keymap.set("n", "<leader>gd", vim.lsp.buf.definition, {})
+ -- vim.keymap.set("n", "<leader>gr", vim.lsp.buf.references, {})
+ -- vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, {})
+ end,
+ },
+}
diff --git a/.config/nvim/lua/plugins/lualine.lua b/.config/nvim/lua/plugins/lualine.lua
@@ -0,0 +1,10 @@
+return {
+ {
+ 'nvim-lualine/lualine.nvim',
+ dependencies = { 'nvim-mini/mini.icons' },
+ config = function()
+ require('lualine').setup()
+ require("mini.icons").mock_nvim_web_devicons()
+ end,
+ }
+}
diff --git a/.config/nvim/lua/plugins/markdown.lua b/.config/nvim/lua/plugins/markdown.lua
@@ -0,0 +1,10 @@
+return {
+ {
+ "MeanderingProgrammer/render-markdown.nvim",
+ -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-mini/mini.nvim' }, -- if you use the mini.nvim suite
+ dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-mini/mini.icons' }, -- if you use standalone mini plugins
+ ---@module 'render-markdown'
+ ---@type render.md.UserConfig
+ opts = {}
+ }
+}
diff --git a/.config/nvim/lua/plugins/telescope.lua b/.config/nvim/lua/plugins/telescope.lua
@@ -0,0 +1,25 @@
+return {
+ {
+ "nvim-telescope/telescope-ui-select.nvim",
+ },
+ {
+ "nvim-telescope/telescope.nvim",
+ tag = "0.1.9",
+ dependencies = { "nvim-lua/plenary.nvim" },
+ config = function()
+ require("telescope").setup({
+ extensions = {
+ ["ui-select"] = {
+ require("telescope.themes").get_dropdown({}),
+ },
+ },
+ })
+ local builtin = require("telescope.builtin")
+ vim.keymap.set("n", "<C-p>", builtin.find_files, {})
+ vim.keymap.set("n", "<leader>fg", builtin.live_grep, {})
+ vim.keymap.set("n", "<leader><leader>", builtin.oldfiles, {})
+
+ require("telescope").load_extension("ui-select")
+ end,
+ },
+}
diff --git a/.config/nvim/lua/plugins/theme.lua b/.config/nvim/lua/plugins/theme.lua
@@ -0,0 +1,7 @@
+return {
+ "bjarneo/pixel.nvim",
+ priority = 1000,
+ config = function()
+ vim.cmd.colorscheme("pixel")
+ end,
+}
diff --git a/.config/nvim/lua/plugins/treesitter.lua b/.config/nvim/lua/plugins/treesitter.lua
@@ -0,0 +1,14 @@
+return {
+ {
+ "nvim-treesitter/nvim-treesitter",
+ build = ":TSUpdate",
+ config = function()
+ local config = require("nvim-treesitter.configs")
+ config.setup({
+ auto_install = true,
+ highlight = { enable = true },
+ indent = { enable = true },
+ })
+ end
+ }
+}
diff --git a/.config/nvim/lua/plugins/trim.lua b/.config/nvim/lua/plugins/trim.lua
@@ -0,0 +1,8 @@
+return {
+ {
+ "cappyzawa/trim.nvim",
+ config = function()
+ require('trim').setup()
+ end
+ }
+}
diff --git a/.config/paru/paru.conf b/.config/paru/paru.conf
@@ -0,0 +1,3 @@
+[bin]
+Sudo = doas
+FileManager = nvim
diff --git a/.config/pipewire/pipewire.conf.d/user-session.conf b/.config/pipewire/pipewire.conf.d/user-session.conf
@@ -0,0 +1,9 @@
+context.exec = [
+ { path = "/usr/bin/wireplumber" args = "" condition = [ { exec.session-manager = null } { exec.session-manager = true } ] }
+ { path = "/usr/bin/pipewire" args = "-c pipewire-pulse.conf" condition = [ { exec.pipewire-pulse = null } { exec.pipewire-pulse = true } ] }
+]
+
+context.properties = {
+ default.clock.rate = 192000
+ default.clock.allowed-rates = [ 44100 48000 96000 192000 ]
+}
diff --git a/.config/qt5ct/qt5ct.conf b/.config/qt5ct/qt5ct.conf
@@ -0,0 +1,32 @@
+[Appearance]
+color_scheme_path=/usr/share/qt5ct/colors/darker.conf
+custom_palette=true
+icon_theme=breeze-dark
+standard_dialogs=xdgdesktopportal
+style=Fusion
+
+[Fonts]
+fixed="FreeMono,12,-1,5,50,0,0,0,0,0,Regular"
+general="FreeSans,12,-1,5,50,0,0,0,0,0,Regular"
+
+[Interface]
+activate_item_on_single_click=1
+buttonbox_layout=0
+cursor_flash_time=1000
+dialog_buttons_have_icons=1
+double_click_interval=400
+gui_effects=@Invalid()
+keyboard_scheme=2
+menus_have_icons=true
+show_shortcuts_in_context_menus=true
+stylesheets=@Invalid()
+toolbutton_style=4
+underline_shortcut=1
+wheel_scroll_lines=3
+
+[SettingsWindow]
+geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\n\0\0\0\0\0\0\0\xe\xfb\0\0\x5s\0\0\n\0\0\0\0\0\0\0\xe\xff\0\0\x2\xf3\0\0\0\0\x2\0\0\0\n\0\0\0\n\0\0\0\0\0\0\0\xe\xfb\0\0\x5s)
+
+[Troubleshooting]
+force_raster_widgets=1
+ignored_applications=@Invalid()
diff --git a/.config/qt6ct/qt6ct.conf b/.config/qt6ct/qt6ct.conf
@@ -0,0 +1,32 @@
+[Appearance]
+color_scheme_path=/usr/share/qt6ct/colors/darker.conf
+custom_palette=true
+icon_theme=breeze-dark
+standard_dialogs=xdgdesktopportal
+style=Fusion
+
+[Fonts]
+fixed="FreeMono,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,Regular"
+general="FreeSans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,Regular"
+
+[Interface]
+activate_item_on_single_click=1
+buttonbox_layout=0
+cursor_flash_time=1000
+dialog_buttons_have_icons=1
+double_click_interval=400
+gui_effects=@Invalid()
+keyboard_scheme=2
+menus_have_icons=true
+show_shortcuts_in_context_menus=true
+stylesheets=@Invalid()
+toolbutton_style=4
+underline_shortcut=1
+wheel_scroll_lines=3
+
+[SettingsWindow]
+geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\n\0\0\0\0\0\0\0\xe\xfb\0\0\x5s\0\0\n\0\0\0\0\0\0\0\xe\xfb\0\0\x5s\0\0\0\0\0\0\0\0\n\0\0\0\n\0\0\0\0\0\0\0\xe\xfb\0\0\x5s)
+
+[Troubleshooting]
+force_raster_widgets=1
+ignored_applications=@Invalid()
diff --git a/.config/rmpc/config.ron b/.config/rmpc/config.ron
@@ -0,0 +1,201 @@
+#![enable(implicit_some)]
+#![enable(unwrap_newtypes)]
+#![enable(unwrap_variant_newtypes)]
+(
+ address: "127.0.0.1:6600",
+ volume_step: 5,
+ scrolloff: 2,
+ max_fps: 60,
+ wrap_navigation: true,
+ theme: "def",
+ lyrics_dir: "/mnt/ssd/music",
+ on_song_change: ["~/.config/rmpc/scripts/statusbar"],
+ on_resize: None,
+ status_update_interval_ms: 1000,
+ enable_mouse: true,
+ enable_config_hot_reload: true,
+ album_art: (
+ method: Auto,
+ max_size_px: (width: 0, height: 0),
+ vertical_align: Top,
+ horizontal_align: Center,
+ ),
+ keybinds: (
+ global: {
+ ":": CommandMode,
+ ",": VolumeDown,
+ "s": Stop,
+ ".": VolumeUp,
+ "<Tab>": NextTab,
+ "<S-Tab>": PreviousTab,
+ "1": SwitchToTab("Queue"),
+ // "2": SwitchToTab("Directories"),
+ "2": SwitchToTab("Artists"),
+ "3": SwitchToTab("Albums"),
+ "4": SwitchToTab("Genres"),
+ "5": SwitchToTab("Playlists"),
+ "6": SwitchToTab("Search"),
+ "q": Quit,
+ ">": NextTrack,
+ "p": TogglePause,
+ "<": PreviousTrack,
+ "f": SeekForward,
+ "z": ToggleRepeat,
+ "x": ToggleRandom,
+ "c": ToggleConsume,
+ "v": ToggleSingle,
+ "b": SeekBack,
+ "~": ShowHelp,
+ "I": ShowCurrentSongInfo,
+ "O": ShowOutputs,
+ "P": ShowDecoders,
+ },
+ navigation: {
+ "k": Up,
+ "j": Down,
+ "h": Left,
+ "l": Right,
+ "<Up>": Up,
+ "<Down>": Down,
+ "<Left>": Left,
+ "<Right>": Right,
+ "<C-k>": PaneUp,
+ "<C-j>": PaneDown,
+ "<C-h>": PaneLeft,
+ "<C-l>": PaneRight,
+ "<C-u>": UpHalf,
+ "N": PreviousResult,
+ "a": Add,
+ "A": AddAll,
+ "r": Rename,
+ "n": NextResult,
+ "g": Top,
+ "<Space>": Select,
+ "<C-Space>": InvertSelection,
+ "G": Bottom,
+ "<CR>": Confirm,
+ "i": FocusInput,
+ "J": MoveDown,
+ "<C-d>": DownHalf,
+ "/": EnterSearch,
+ "<C-c>": Close,
+ "<Esc>": Close,
+ "K": MoveUp,
+ "D": Delete,
+ },
+ queue: {
+ "D": DeleteAll,
+ "<CR>": Play,
+ "<C-s>": Save,
+ "a": AddToPlaylist,
+ "d": Delete,
+ "i": ShowInfo,
+ "C": JumpToCurrent,
+ },
+ ),
+ search: (
+ case_sensitive: false,
+ mode: Contains,
+ tags: [
+ (value: "any", label: "Any Tag"),
+ (value: "artist", label: "Artist"),
+ (value: "album", label: "Album"),
+ (value: "albumartist", label: "Album Artist"),
+ (value: "title", label: "Title"),
+ ],
+ ),
+ tabs: [
+ (
+ name: "Queue",
+ pane: Split(
+ direction: Vertical,
+ panes: [
+ (
+ size: "100%",
+ borders: "NONE",
+ pane: Split(
+ borders: "NONE",
+ direction: Horizontal,
+ panes: [
+ (
+ size: "70%",
+ borders: "ALL",
+ pane: Pane(Queue),
+ ),
+ (
+ size: "30%",
+ borders: "ALL",
+ pane: Split(
+ direction: Vertical,
+ panes: [
+ (
+ size: "75%",
+ borders: "NONE",
+ pane: Pane(AlbumArt),
+ ),
+ (
+ size: "35%",
+ borders: "NONE",
+ pane: Split(
+ direction: Vertical,
+ panes: [
+ (
+ size: "100%",
+ pane: Pane(Lyrics),
+ ),
+ ]
+ ),
+ ),
+ ]
+ ),
+ ),
+ ]
+ ),
+ ),
+ ],
+ ),
+ ),
+ // (
+ // name: "Directories",
+ // pane: Split(
+ // direction: Horizontal,
+ // panes: [(size: "100%", borders: "ALL", pane: Pane(Directories))],
+ // ),
+ // ),
+ (
+ name: "Artists",
+ pane: Split(
+ direction: Horizontal,
+ panes: [(size: "100%", borders: "ALL", pane: Pane(Artists))],
+ ),
+ ),
+ (
+ name: "Albums",
+ pane: Split(
+ direction: Horizontal,
+ panes: [(size: "100%", borders: "ALL", pane: Pane(Albums))],
+ ),
+ ),
+ (
+ name: "Genres",
+ pane: Split(
+ direction: Horizontal,
+ panes: [(size: "100%", borders: "ALL", pane: Pane(Browser(root_tag: "genre", separator: ";")))],
+ ),
+ ),
+ (
+ name: "Playlists",
+ pane: Split(
+ direction: Horizontal,
+ panes: [(size: "100%", borders: "ALL", pane: Pane(Playlists))],
+ ),
+ ),
+ (
+ name: "Search",
+ pane: Split(
+ direction: Horizontal,
+ panes: [(size: "100%", borders: "ALL", pane: Pane(Search))],
+ ),
+ ),
+ ],
+)
diff --git a/.config/rmpc/scripts/statusbar b/.config/rmpc/scripts/statusbar
@@ -0,0 +1,2 @@
+#!/bin/sh
+/usr/bin/pkill -RTMIN+11 i3blocks
diff --git a/.config/rmpc/themes/def.ron b/.config/rmpc/themes/def.ron
@@ -0,0 +1,193 @@
+#![enable(implicit_some)]
+#![enable(unwrap_newtypes)]
+#![enable(unwrap_variant_newtypes)]
+(
+ default_album_art_path: None,
+ show_song_table_header: true,
+ draw_borders: true,
+ browser_column_widths: [20, 38, 42],
+ background_color: None,
+ modal_backdrop: true,
+ text_color: "white",
+ header_background_color: None,
+ modal_background_color: None,
+ preview_label_style: (fg: "#b48ead"),
+ preview_metadata_group_style: (fg: "#88c0d0"),
+ tab_bar: (
+ enabled: true,
+ active_style: (fg: "black", bg: "yellow", modifiers: "Bold"),
+ inactive_style: (fg: "white", bg: None, modifiers: ""),
+ ),
+ highlighted_item_style: (fg: "magenta", modifiers: "Bold"),
+ current_item_style: (fg: "black", bg: "yellow", modifiers: "Bold"),
+ borders_style: (fg: "yellow", modifiers: "Bold"),
+ highlight_border_style: (fg: "yellow"),
+ symbols: (song: " ", dir: " ", playlist: " ", marker: "* ", ellipsis: "..."),
+ progress_bar: (
+ symbols: ["█", "█", "█", "█", "█"],
+ track_style: (fg: "dark_gray"),
+ elapsed_style: (fg: "yellow"),
+ thumb_style: (fg: "yellow"),
+ ),
+ scrollbar: (
+ symbols: ["│", "█", "▲", "▼"],
+ track_style: (fg: "yellow"),
+ ends_style: (fg: "light_yellow"),
+ thumb_style: (fg: "light_yellow"),
+ ),
+ song_table_format: [
+ (
+ prop: (kind: Property(Artist), style: (fg: "green"),
+ default: (kind: Text("Unknown"), style: (fg: "green"))
+ ),
+ width: "20%",
+ ),
+ (
+ prop: (kind: Property(Title), style: (fg: "white"),
+ highlighted_item_style: (fg: "white", modifiers: "Bold"),
+ default: (kind: Property(Filename), style: (fg: "white"),)
+ ),
+ width: "35%",
+ ),
+ (
+ prop: (kind: Property(Album), style: (fg: "blue"),
+ default: (kind: Text("Unknown Album"), style: (fg: "gray"))
+ ),
+ width: "30%",
+ ),
+ (
+ prop: (kind: Property(Duration), style: (fg: "magenta"),
+ default: (kind: Text("-"))
+ ),
+ width: "15%",
+ alignment: Right,
+ ),
+ ],
+ layout: Split(
+ direction: Vertical,
+ panes: [
+ (
+ size: "3",
+ pane: Pane(Tabs),
+ ),
+ (
+ size: "5",
+ pane: Split(
+ direction: Horizontal,
+ panes: [
+ (
+ size: "100%",
+ borders: "ALL",
+ pane: Split(
+ direction: Vertical,
+ panes: [
+ (
+ size: "4",
+ borders: "NONE",
+ pane: Pane(Header),
+ ),
+ (
+ size: "1",
+ borders: "NONE",
+ pane: Pane(ProgressBar),
+ ),
+ ]
+ )
+ ),
+ ]
+ ),
+ ),
+ (
+ size: "100%",
+ pane: Split(
+ direction: Horizontal,
+ panes: [
+ (
+ size: "100%",
+ borders: "NONE",
+ pane: Pane(TabContent),
+ ),
+ ]
+ ),
+ ),
+ ],
+ ),
+ header: (
+ rows: [
+ (
+ left: [
+ (kind: Text(""), style: (fg: "light_yellow", modifiers: "Bold")),
+ (kind: Property(Status(StateV2(playing_label: " ", paused_label: " ", stopped_label: " ")))),
+ (kind: Text(" "), style: (fg: "light_yellow", modifiers: "Bold")),
+ (kind: Property(Widget(ScanStatus)))
+ ],
+ center: [
+ (kind: Property(Song(Title)), style: (fg: "white",modifiers: "Bold"),
+ default: (kind: Property(Song(Filename)), style: (fg: "white",modifiers: "Bold"))
+ )
+ ],
+ right: [
+ (kind: Text(""), style: (fg: "light_yellow", modifiers: "Bold")),
+ (kind: Property(Status(Volume)), style: (fg: "white", modifiers: "Bold")),
+ (kind: Text("%"), style: (fg: "light_yellow", modifiers: "Bold"))
+ ]
+ ),
+ (
+ left: [
+ (kind: Text("[ "),style: (fg: "light_yellow", modifiers: "Bold")),
+ (kind: Property(Status(Elapsed)),style: (fg: "white")),
+ (kind: Text(" / "),style: (fg: "yellow", modifiers: "Bold")),
+ (kind: Property(Status(Duration)),style: (fg: "white")),
+ (kind: Text(" | "),style: (fg: "yellow")),
+ (kind: Property(Status(Bitrate)),style: (fg: "white")),
+ (kind: Text(" kbps"),style: (fg: "yellow")),
+ (kind: Text("]"),style: (fg: "light_yellow", modifiers: "Bold"))
+ ],
+ center: [
+ (kind: Property(Song(Artist)), style: (fg: "white", modifiers: "Bold"),
+ default: (kind: Text("Unknown Artist"), style: (fg: "white", modifiers: "Bold"))
+ ),
+ (kind: Text(" - ")),
+ (kind: Property(Song(Album)),style: (fg: "white" ),
+ default: (kind: Text("Unknown Album"), style: (fg: "white", modifiers: "Bold"))
+ )
+ ],
+ right: [
+ (kind: Text("[ "),style: (fg: "light_yellow")),
+ (kind: Property(Status(RepeatV2(
+ on_label: "", off_label: "",
+ on_style: (fg: "white", modifiers: "Bold"), off_style: (fg: "dark_gray", modifiers: "Bold"))))),
+ (kind: Text(" | "),style: (fg: "yellow")),
+ (kind: Property(Status(RandomV2(
+ on_label: "", off_label: "",
+ on_style: (fg: "white", modifiers: "Bold"), off_style: (fg: "dark_gray", modifiers: "Bold"))))),
+ (kind: Text(" | "),style: (fg: "yellow")),
+ (kind: Property(Status(ConsumeV2(
+ on_label: "", off_label: "", oneshot_label: "",
+ on_style: (fg: "white", modifiers: "Bold"), off_style: (fg: "dark_gray", modifiers: "Bold"))))),
+ (kind: Text(" | "),style: (fg: "yellow")),
+ (kind: Property(Status(SingleV2(
+ on_label: "", off_label: "", oneshot_label: "", off_oneshot_label: "",
+ on_style: (fg: "white", modifiers: "Bold"), off_style: (fg: "dark_gray", modifiers: "Bold"))))),
+ (kind: Text(" ]"),style: (fg: "light_yellow")),
+ ]
+ ),
+ ],
+ ),
+ browser_song_format: [
+ (
+ kind: Group([
+ (kind: Property(Track)),
+ (kind: Text(" ")),
+ ])
+ ),
+ (
+ kind: Group([
+ (kind: Property(Artist)),
+ (kind: Text(" - ")),
+ (kind: Property(Title)),
+ ]),
+ default: (kind: Property(Filename))
+ ),
+ ],
+)
diff --git a/.config/shell/aliasrc b/.config/shell/aliasrc
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Use neovim for vim if present.
+[ -x "$(command -v nvim)" ] && alias vim="nvim" vimdiff="nvim -d"
+
+[ -f "$MBSYNCRC" ] && alias mbsync="mbsync -c $MBSYNCRC"
+
+# doas not required for some system commands
+for command in mount umount dinitctl pacman updatedb su shutdown poweroff reboot ; do
+ alias $command="doas $command"
+done; unset command
+
+se() {
+ choice="$(fd . --base-directory=$HOME/.local/bin -t f --min-depth=1 | fzf)"
+ [ -f "$HOME/.local/bin/$choice" ] && $EDITOR "$HOME/.local/bin/$choice"
+}
+
+# Verbosity and settings that you pretty much just always are going to want.
+alias \
+ cp="cp -iv" \
+ mv="mv -iv" \
+ rm="rm -vI" \
+ bc="bc -ql" \
+ rsync="rsync -vrPlu" \
+ mkd="mkdir -pv" \
+ yt="yt-dlp --embed-metadata -i" \
+ yta="yt -x -f bestaudio/best" \
+ ytt="yt --skip-download --write-thumbnail" \
+ ffmpeg="ffmpeg -hide_banner"
+
+# Colorize commands when possible.
+alias \
+ ll="eza -lh --group-directories-first --color=auto --color-scale=all --color-scale-mode=fixed --icons --no-quotes --smart-group -s size --total-size --no-user --no-permissions" \
+ ls="eza --group-directories-first --color=auto --icons --no-quotes -s name" \
+ lsf="eza -f --group-directories-first --color=auto --icons --no-quotes -s name" \
+ lsd="eza -D --group-directories-first --color=auto --icons --no-quotes -s name" \
+ lst="eza -lh --group-directories-first --color=auto --color-scale --icons --no-quotes --smart-group -s time --total-size --no-user --no-permissions" \
+ cat="bat -P" \
+ ccat="highlight --out-format=ansi" \
+ ip="ip -color=auto"
+
+# These common commands are just too long! Abbreviate them.
+alias \
+ cl="clear" \
+ ka="killall" \
+ trem="transmission-remote" \
+ YT="youtube-viewer" \
+ sdn="shutdown -h now" \
+ e="$EDITOR" \
+ v="$EDITOR" \
+ p="paru" \
+ z="zathura" \
+ lg="lazygit" \
+ sx="swayimg" \
+ md="monerod --prune-blockchain --fast-block-sync 1 --data-dir /mnt/ssd/monero/bitmonero" \
+ fetch="fastfetch" \
+ de="doasedit"
+
+# Git related
+alias \
+ g="git" \
+ gs="git status --short" \
+ gd="git diff" \
+ ga="git add" \
+ gc="git commit" \
+ gp="git push" \
+ gu="git pull" \
+ gl="git log" \
+ gb="git branch" \
+ gi="git init" \
+ gcl="git clone"
+
+alias \
+ magit="nvim -c MagitOnly" \
+ ref="shortcuts >/dev/null; source ${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutrc ; source ${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutenvrc ; source ${XDG_CONFIG_HOME:-$HOME/.config}/shell/zshnameddirrc"
diff --git a/.config/shell/bm-dirs b/.config/shell/bm-dirs
@@ -0,0 +1,14 @@
+# You can add comments to these files with #
+cac ${XDG_CACHE_HOME:-$HOME/.cache}
+cf ${XDG_CONFIG_HOME:-$HOME/.config}
+D ${XDG_DOWNLOAD_DIR:-$HOME/Downloads}
+d ${XDG_DOCUMENTS_DIR:-$HOME/Documents}
+dt ${XDG_DATA_HOME:-$HOME/.local/share}
+rr /mnt/ssd/projects
+h $HOME
+m ${XDG_MUSIC_DIR:-$HOME/Music}
+mn /mnt
+pp ${XDG_PICTURES_DIR:-$HOME/Pictures}
+sc $HOME/.local/bin
+src $HOME/.local/src
+vv ${XDG_VIDEOS_DIR:-$HOME/Videos}
diff --git a/.config/shell/bm-files b/.config/shell/bm-files
@@ -0,0 +1,16 @@
+# These files automatically update when edited/saved in vim:
+
+# keys filename description
+bf ${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-files # This file, a list of bookmarked files
+bd ${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-dirs # A list of bookmarked directories similar to this file
+
+# These do not update automatically, but on the next new instance of a program:
+
+cfv ${XDG_CONFIG_HOME:-$HOME/.config}/nvim/init.vim # vim/neovim config
+cfz $ZDOTDIR/.zshrc # zsh (shell) config
+cfa ${XDG_CONFIG_HOME:-$HOME/.config}/shell/aliasrc # aliases used by zsh (and potentially other shells)
+cfp ${XDG_CONFIG_HOME:-$HOME/.config}/shell/profile # profile file for login settings for zsh
+cfm ${XDG_CONFIG_HOME:-$HOME/.config}/mutt/muttrc # mutt (email client) config
+cfn ${XDG_CONFIG_HOME:-$HOME/.config}/newsboat/config # newsboat (RSS reader)
+cfu ${XDG_CONFIG_HOME:-$HOME/.config}/newsboat/urls # RSS urls for newsboat
+cfmc ${XDG_CONFIG_HOME:-$HOME/.config}/rmpc/config.ron # rmpc (music player) config
diff --git a/.config/shell/inputrc b/.config/shell/inputrc
@@ -0,0 +1,19 @@
+$include /etc/inputrc
+set editing-mode vi
+$if mode=vi
+
+set show-mode-in-prompt on
+set vi-ins-mode-string \1\e[6 q\2
+set vi-cmd-mode-string \1\e[2 q\2
+
+set keymap vi-command
+# these are for vi-command mode
+Control-l: clear-screen
+Control-a: beginning-of-line
+
+set keymap vi-insert
+# these are for vi-insert mode
+Control-l: clear-screen
+Control-a: beginning-of-line
+
+$endif
diff --git a/.config/shell/profile b/.config/shell/profile
@@ -0,0 +1,115 @@
+#!/bin/sh
+# shellcheck disable=SC2155
+
+# Profile file, runs on login. Environmental variables are set here.
+
+# Add all directories in `~/.local/bin` to $PATH
+export PATH="$PATH:$(find ~/.local/bin -type d | paste -sd ':' -)"
+
+unsetopt PROMPT_SP 2>/dev/null
+
+# Default programs:
+export EDITOR="nvim"
+export MANPAGER='nvim +Man!'
+export TERMINAL="footclient"
+export TERMINAL_PROG="footclient"
+export TERMCMD="footclient"
+export BROWSER="icecat"
+
+unset SSH_AGENT_PID
+if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
+ export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
+fi
+
+# Change the default crypto/weather monitor sites.
+# export CRYPTOURL="rate.sx"
+# export WTTRURL="wttr.in"
+
+# ~/ Clean-up:
+export XDG_CONFIG_HOME="$HOME/.config"
+export XDG_DATA_HOME="$HOME/.local/share"
+export XDG_CACHE_HOME="$HOME/.cache"
+export XDG_STATE_HOME="$HOME/.local/state"
+export XDG_MUSIC_DIR="/mnt/ssd/music"
+export NOTMUCH_CONFIG="$XDG_CONFIG_HOME/notmuch-config"
+export WGETRC="$XDG_CONFIG_HOME/wget/wgetrc"
+export INPUTRC="$XDG_CONFIG_HOME/shell/inputrc"
+export ZDOTDIR="$XDG_CONFIG_HOME/zsh"
+#export GNUPGHOME="$XDG_DATA_HOME/gnupg"
+export WINEPREFIX="$XDG_DATA_HOME/wineprefixes/default"
+export KODI_DATA="$XDG_DATA_HOME/kodi"
+export PASSWORD_STORE_DIR="$XDG_DATA_HOME/password-store"
+export TMUX_TMPDIR="$XDG_RUNTIME_DIR"
+export ANDROID_SDK_HOME="$XDG_CONFIG_HOME/android"
+export CARGO_HOME="$XDG_DATA_HOME/cargo"
+export GOPATH="$XDG_DATA_HOME/go"
+export GOMODCACHE="$XDG_CACHE_HOME/go/mod"
+export ANSIBLE_CONFIG="$XDG_CONFIG_HOME/ansible/ansible.cfg"
+export UNISON="$XDG_DATA_HOME/unison"
+export HISTFILE="$XDG_DATA_HOME/history"
+export MBSYNCRC="$XDG_CONFIG_HOME/mbsync/config"
+export ELECTRUMDIR="$XDG_DATA_HOME/electrum"
+export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/pythonrc"
+export SQLITE_HISTORY="$XDG_DATA_HOME/sqlite_history"
+export NPM_CONFIG_USERCONFIG="$XDG_CONFIG_HOME/npm/npmrc"
+export CUDA_CACHE_PATH="$XDG_CACHE_HOME/nv"
+export KUBECONFIG="$XDG_CONFIG_HOME/kube/config"
+export KUBECACHEDIR="$XDG_CACHE_HOME/kube"
+export DOCKER_CONFIG="$XDG_CONFIG_HOME/docker"
+export PASSWORD_STORE_CLIP_TIME=5
+export W3M_DIR="$XDG_STATE_HOME/w3m"
+
+# Other program settings:
+export DICS="/usr/share/stardict/dic/"
+export DOAS_ASKPASS="$HOME/.local/bin/dmenupass"
+export LESS="R"
+export LESS_TERMCAP_mb="$(printf '%b' '[1;31m')"
+export LESS_TERMCAP_md="$(printf '%b' '[1;36m')"
+export LESS_TERMCAP_me="$(printf '%b' '[0m')"
+export LESS_TERMCAP_so="$(printf '%b' '[01;44;33m')"
+export LESS_TERMCAP_se="$(printf '%b' '[0m')"
+export LESS_TERMCAP_us="$(printf '%b' '[1;32m')"
+export LESS_TERMCAP_ue="$(printf '%b' '[0m')"
+export LESSOPEN="| /usr/bin/highlight -O ansi %s 2>/dev/null"
+export QT_QPA_PLATFORMTHEME="qt5ct" # Have QT use gtk3 theme.
+export MOZ_USE_XINPUT2=1 # Mozilla smooth scrolling/touchpads.
+export AWT_TOOLKIT="MToolkit wmname LG3D" # May have to install wmname
+export _JAVA_AWT_WM_NONREPARENTING=1 # Fix for Java applications in dwm
+export LIBVA_DRIVER_NAME=nvidia
+export __GLX_VENDOR_LIBRARY_NAME=nvidia
+export MOZ_DISABLE_RDD_SANDBOX=1 # For HW in Firefox on nvidia gpu
+export ELECTRON_OZONE_PLATFORM_HINT=auto # Electron fix
+export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 # Disables decorations for QT applications
+export FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS \
+--layout=reverse --height 40% \
+--color=fg:#e5e9f0,bg:-1,hl:#81a1c1 \
+--color=fg+:#e5e9f0,bg+:#3b4252,hl+:#81a1c1 \
+--color=info:#eacb8a,prompt:#bf6069,pointer:#b48dac \
+--color=marker:#a3be8b,spinner:#b48dac,header:#a3be8b
+--cycle
+--scroll-off=8
+--tabstop=4
+--preview-window=border-sharp
+--highlight-line
+--no-ansi
+--scrollbar=█
+--wrap-sign=
+--bind=ctrl-u:preview-half-page-up
+--bind=ctrl-d:preview-half-page-down
+--bind=ctrl-l:forward-char
+--bind=ctrl-h:backward-char
+--bind=resize:refresh-preview
+"
+export YT_X_FZF_OPTS="$FZF_DEFAULT_OPTS"
+export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#665c54"
+export BAT_THEME="gruvbox-dark"
+export GTK_USE_PORTAL=1
+export ENABLE_HDR_WSI=1
+export PROTON_ENABLE_WAYLAND=1
+export WLR_RENDERER=vulkan
+
+[ ! -f "$XDG_CONFIG_HOME/shell/shortcutrc" ] && setsid -f shortcuts >/dev/null 2>&1
+
+# Start graphical server on user's current tty if not already running.
+# [ "$(tty)" = "/dev/tty1" ] && ! pidof -s Hyprland >/dev/null 2>&1 && exec dbus-run-session Hyprland
+[ "$(tty)" = "/dev/tty1" ] && ! pidof -s sway >/dev/null 2>&1 && exec dbus-run-session sway --unsupported-gpu
diff --git a/.config/sway/config b/.config/sway/config
@@ -0,0 +1,272 @@
+set $mod Mod4
+# Home row direction keys, like vim
+set $left h
+set $down j
+set $up k
+set $right l
+
+set $term footclient
+set $menu mew-run
+
+# autostart
+exec start-pipewire
+exec singboxwrap
+exec fnott
+exec gpg-agent --daemon
+exec gnome-keyring-daemon --start --components=secrets
+exec foot --server
+exec portal
+exec mpd
+# exec stmpdup
+exec swayidle
+
+output DP-3 resolution 3840x2160@165Hz position 2560 0 scale 1.5 render_bit_depth 10 hdr off
+output DP-2 resolution 2560x1440@165Hz position 0 0 scale 1
+
+workspace 1 output DP-2
+workspace 2 output DP-3
+
+# seat seat0 xcursor_theme hicolor
+
+# floating window assigments
+for_window [window_role = "pop-up"] floating enable
+for_window [window_role = "bubble"] floating enable
+for_window [window_role = "dialog"] floating enable
+for_window [window_type = "dialog"] floating enable
+for_window [window_role = "task_dialog"] floating enable
+for_window [window_type = "menu"] floating enable
+for_window [app_id = "floating"] floating enable
+for_window [app_id = "floating_update"] floating enable, resize set width 1000px height 600px
+for_window [class = "(?i)pinentry"] floating enable
+for_window [title = "Administrator privileges required"] floating enable
+for_window [title = "About GNU IceCat"] floating enable
+for_window [window_role = "About"] floating enable
+for_window [app_id="icecat" title="Library"] floating enable, border pixel 1, sticky enable
+for_window [app_id="termfloat"] floating enable
+for_window [app_id="termfloat"] resize set height 540
+for_window [app_id="termfloat"] resize set width 960
+for_window [class="^steam$" title="^Friends List$"] floating enable
+for_window [class="^steam$" title="Steam - News"] floating enable
+for_window [class="^steam$" title=".* - Chat"] floating enable
+for_window [class="^steam$" title=".* Settings$"] floating enable
+for_window [class="^steam$" title=".* - event started"] floating enable
+for_window [class="^steam$" title=".* CD key"] floating enable
+for_window [class="^steam$" title="^Steam - Self Updater$"] floating enable
+for_window [class="^steam$" title="^Screenshot Uploader$"] floating enable
+for_window [class="^steam$" title="^Recordings & Screenshots$"] floating enable
+for_window [class="^steam$" title="^Steam Guard - Computer Authorization Required$"] floating enable
+for_window [title="^Steam Keyboard$"] floating enable
+for_window [app_id="termfilechooser"] floating enable
+for_window [app_id="termfilechooser"] resize set height 960
+for_window [app_id="termfilechooser"] resize set width 960
+
+for_window [app_id="showmethekey-gtk"] floating enable
+for_window [app_id="showmethekey-gtk"] resize set height 160
+for_window [app_id="showmethekey-gtk"] resize set width 1260
+for_window [app_id="showmethekey-gtk"] move down 500
+no_focus [app_id="showmethekey-gtk"]
+
+floating_modifier $mod normal
+
+# binds
+bindsym $mod+Return exec $term
+bindsym $mod+q kill
+# bindsym $mod+r exec $term -e yazi
+# bindsym $mod+e exec 'sh -c "$term -e neomutt; pkill -RTMIN+12 i3blocks"'
+bindsym $mod+d exec $menu
+bindsym $mod+Shift+d exec tessen
+# bindsym $mod+minus exec 'wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-; kill -44 $(pidof i3blocks)'
+bindsym $mod+underscore exec 'wpctl set-volume @DEFAULT_AUDIO_SINK@ 15%-; kill -44 $(pidof i3blocks)'
+bindsym $mod+equal exec 'wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+; kill -44 $(pidof i3blocks)'
+bindsym $mod+plus exec 'wpctl set-volume @DEFAULT_AUDIO_SINK@ 15%+; kill -44 $(pidof i3blocks)'
+bindsym $mod+backspace exec sysact
+bindsym $mod+Shift+backspace exec sysact
+bindsym $mod+Shift+q exec sysact
+bindsym $mod+Shift+c reload
+bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit'
+bindsym $mod+Print exec dmenurecord
+bindsym $mod+Shift+Print exec 'dmenurecord kill'
+bindsym $mod+Tab exec chooseprofile
+bindsym $mod+grave exec bookmarks
+bindsym $mod+Shift+grave exec define
+bindsym $mod+Shift+n exec 'sh -c "$term -T newsraft -e newsraft; pkill -RTMIN+6 i3blocks"'
+bindsym $mod+m exec $term -e rmpc
+bindsym $mod+Shift+m exec 'wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle; kill -44 $(pidof i3blocks)'
+bindsym $mod+comma exec mpc prev
+bindsym $mod+Shift+comma exec mpc seek 0%
+bindsym $mod+period exec mpc next
+bindsym $mod+Shift+period exec mpc repeat
+bindsym $mod+insert exec wtype $(rg -v '^#' ~/.local/share/larbs/snippets | mew -i -l 50 | cut -d' ' -f1)
+bindsym $mod+f1 exec singboxwrap menu
+bindsym $mod+f4 exec '$term -e pulsemixer; kill -44 $(pidof i3blocks)'
+bindsym $mod+f6 exec torwrap
+bindsym $mod+f7 exec td-toggle
+bindsym $mod+f8 exec mailup
+bindsym $mod+f9 exec mounter
+bindsym $mod+f10 exec unmounter
+bindsym $mod+f11 exec "mpv --untimed --no-cache --no-osc --no-input-default-bindings --profile=low-latency --input-conf=/dev/null --title=webcam $(ls /dev/video[0,2,4,6,8] | tail -n 1)"
+bindsym XF86AudioPlay exec mpc toggle
+bindsym $mod+p exec mpc toggle
+bindsym $mod+Shift+p exec 'mpc pause; pauseallmpv'
+bindsym XF86AudioNext exec mpc next
+bindsym XF86AudioPrev exec mpc prev
+bindsym $mod+bracketleft exec mpc seek -10
+bindsym $mod+Shift+bracketleft exec mpc seek -60
+bindsym $mod+bracketright exec mpc seek +10
+bindsym $mod+Shift+bracketright exec mpc seek +60
+bindsym --whole-window BTN_EXTRA exec 'wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle; kill -57 $(pidof i3blocks)'
+bindsym Print exec 'grim pic-full-$(date '+%y%m%d-%H%M-%S').png'
+bindsym Shift+Print exec maimpick
+bindsym $mod+Scroll_Lock exec killall showmethekey-gtk || showmethekey-gtk -A
+#
+# Moving around:
+#
+ # Move your focus around
+ bindsym $mod+$left focus left
+ bindsym $mod+$down focus down
+ bindsym $mod+$up focus up
+ bindsym $mod+$right focus right
+ # Or use $mod+[up|down|left|right]
+ bindsym $mod+Left focus left
+ bindsym $mod+Down focus down
+ bindsym $mod+Up focus up
+ bindsym $mod+Right focus right
+
+ # Move the focused window with the same, but add Shift
+ bindsym $mod+Shift+$left move left
+ bindsym $mod+Shift+$down move down
+ bindsym $mod+Shift+$up move up
+ bindsym $mod+Shift+$right move right
+ # Ditto, with 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
+#
+# Workspaces:
+#
+ # Switch to workspace
+ bindsym $mod+1 workspace number 1
+ bindsym $mod+2 workspace number 2
+ bindsym $mod+3 workspace number 3
+ bindsym $mod+4 workspace number 4
+ bindsym $mod+5 workspace number 5
+ bindsym $mod+6 workspace number 6
+ bindsym $mod+7 workspace number 7
+ bindsym $mod+8 workspace number 8
+ bindsym $mod+9 workspace number 9
+ bindsym $mod+0 workspace number 10
+ # Move focused container to workspace
+ bindsym $mod+Shift+1 move container to workspace number 1
+ bindsym $mod+Shift+2 move container to workspace number 2
+ bindsym $mod+Shift+3 move container to workspace number 3
+ bindsym $mod+Shift+4 move container to workspace number 4
+ bindsym $mod+Shift+5 move container to workspace number 5
+ bindsym $mod+Shift+6 move container to workspace number 6
+ bindsym $mod+Shift+7 move container to workspace number 7
+ bindsym $mod+Shift+8 move container to workspace number 8
+ bindsym $mod+Shift+9 move container to workspace number 9
+ bindsym $mod+Shift+0 move container to workspace number 10
+ # Note: workspaces can have any name you want, not just numbers.
+ # We just use 1-10 as the default.
+#
+# Layout stuff:
+#
+ # You can "split" the current object of your focus with
+ # $mod+b or $mod+v, for horizontal and vertical splits
+ # respectively.
+ bindsym $mod+b splith
+ bindsym $mod+v splitv
+
+ # Switch the current container between different layout styles
+ bindsym $mod+s layout stacking
+ bindsym $mod+w exec icecat
+ bindsym $mod+Shift+w layout tabbed
+ bindsym $mod+e layout toggle split
+
+ bindsym $mod+f fullscreen
+
+ # Toggle the current focus between tiling and floating mode
+ bindsym $mod+Shift+space floating toggle
+
+ # Swap focus between the tiling area and the floating area
+ bindsym $mod+space focus mode_toggle
+
+ # Move focus to the parent container
+ bindsym $mod+a focus parent
+#
+# Scratchpad:
+#
+ # Sway has a "scratchpad", which is a bag of holding for windows.
+ # You can send windows there and get them back later.
+
+ # Move the currently focused window to the scratchpad
+ bindsym $mod+Shift+minus move scratchpad
+
+ # Show the next scratchpad window or hide the focused scratchpad window.
+ # If there are multiple scratchpad windows, this command cycles through them.
+ bindsym $mod+minus scratchpad show
+#
+# Resizing containers:
+#
+mode "resize" {
+ # left will shrink the containers width
+ # right will grow the containers width
+ # up will shrink the containers height
+ # down will grow the containers height
+ bindsym $left resize shrink width 10px
+ bindsym $down resize grow height 10px
+ bindsym $up resize shrink height 10px
+ bindsym $right resize grow width 10px
+
+ # Ditto, with arrow keys
+ bindsym Left resize shrink width 10px
+ bindsym Down resize grow height 10px
+ bindsym Up resize shrink height 10px
+ bindsym Right resize grow width 10px
+
+ # Return to default mode
+ bindsym Return mode "default"
+ bindsym Escape mode "default"
+}
+bindsym $mod+r mode "resize"
+#
+# Utilities:
+#
+ # Special keys to adjust volume via PulseAudio
+ bindsym --locked XF86AudioMute exec pactl set-sink-mute \@DEFAULT_SINK@ toggle
+ bindsym --locked XF86AudioLowerVolume exec pactl set-sink-volume \@DEFAULT_SINK@ -5%
+ bindsym --locked XF86AudioRaiseVolume exec pactl set-sink-volume \@DEFAULT_SINK@ +5%
+ bindsym --locked XF86AudioMicMute exec pactl set-source-mute \@DEFAULT_SOURCE@ toggle
+
+ # Special keys to control media via playerctl
+ bindsym --locked XF86AudioPlay exec mpc toggle
+ bindsym --locked XF86AudioPause exec mpc toggle
+ bindsym --locked XF86AudioPrev exec mpc prev
+ bindsym --locked XF86AudioNext exec mpc next
+ bindsym --locked XF86AudioStop exec mpc stop
+
+ # Special keys to adjust brightness via brightnessctl
+ bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
+ bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
+
+
+input * {
+ xkb_layout "us,ru"
+ xkb_options "grp:win_space_toggle,caps:escape"
+ accel_profile flat
+}
+
+input "type:keyboard" {
+ repeat_rate 45
+ repeat_delay 300
+}
+
+bar {
+ position top
+ status_command i3blocks
+ font pango:FreeMono Bold 10
+ separator_symbol ""
+}
+
+include /etc/sway/config.d/*
diff --git a/.config/swayidle/config b/.config/swayidle/config
@@ -0,0 +1,3 @@
+timeout 300 'swaylock -f'
+timeout 330 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"'
+before-sleep 'swaylock -f'
diff --git a/.config/swayimg/config b/.config/swayimg/config
@@ -0,0 +1,38 @@
+[general]
+overlay = no
+[viewer]
+window = #000000
+scale = fit
+[gallery]
+window = #000000
+[list]
+all = yes
+[keys.viewer]
+h = step_left
+j = step_down
+k = step_up
+l = step_right
+n = next_file
+p = prev_file
+w = zoom fit
+g = first_file
+Shift+g = last_file
+Ctrl+x = exec ~/.config/swayimg/key-handler "%"
+r = rotate_right
+Shift+r = rotate_left
+Alt+Shift+k = zoom +20
+Alt+Shift+j = zoom -20
+[keys.gallery]
+h = step_left
+j = step_down
+k = step_up
+l = step_right
+g = first_file
+Shift+g = last_file
+[info]
+info_timeout = 0
+[info.viewer]
+top_left = none
+top_right = none
+bottom_left = +name
+bottom_right = +scale,+frame,+index
diff --git a/.config/swayimg/key-handler b/.config/swayimg/key-handler
@@ -0,0 +1,35 @@
+#!/bin/sh
+file=$1
+ [ -z "$selection" ] && selection=$(printf "w - Set as wallpaper\nc - Copy to dir\nm - Move to dir\nr - Rotate 90°\nR - Rotate -90°\nf - Flip horizontal\ny - Copy filename to clipboard\nY - Copy full path to clipboard\nd - Delete\ng - Open in GIMP\ni - Show media info" |
+ mew -i -l 12 -p "Choose action for selected files:")
+ action=$(printf "%s" "$selection" | cut -d'-' -f1 | tr -d ' ')
+ case "$action" in
+ "w") setbg "$file" & ;;
+ "c")
+ [ -z "$destdir" ] && destdir="$(sed "s/#.*$//;/^\s*$/d" ${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-dirs | awk '{print $2}' | mew -l 20 -i -p "Copy file(s) to where?" | sed "s|~|$HOME|g")"
+ [ ! -d "$destdir" ] && notify-send "$destdir is not a directory, cancelled." && exit
+ cp "$file" "$destdir" && notify-send -i "$(readlink -f "$file")" "$file copied to $destdir." &
+ ;;
+ "m")
+ [ -z "$destdir" ] && destdir="$(sed "s/#.*$//;/^\s*$/d" ${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-dirs | awk '{print $2}' | mew -l 20 -i -p "Move file(s) to where?" | sed "s|~|$HOME|g")"
+ [ ! -d "$destdir" ] && notify-send "$destdir is not a directory, cancelled." && exit
+ mv "$file" "$destdir" && notify-send -i "$(readlink -f "$file")" "$file moved to $destdir." &
+ ;;
+ "r")
+ magick "$file" -rotate 90 "$file" ;;
+ "R")
+ magick "$file" -rotate -90 "$file" ;;
+ "f")
+ magick "$file" -flop "$file" ;;
+ "y")
+ printf "%s" "$file" | tr -d '\n' | wl-copy &&
+ notify-send "$file copied to clipboard" & ;;
+ "Y")
+ readlink -f "$file" | tr -d '\n' | wl-copy &&
+ notify-send "$(readlink -f "$file") copied to clipboard" & ;;
+ "d")
+ [ "$(printf "No\\nYes" | mew -i -p "Really delete $file?")" = "Yes" ] && rm "$file" && notify-send "$file deleted." ;;
+ "g") ifinstalled gimp && setsid -f gimp "$file" ;;
+ "i") notify-send "File information" "$(mediainfo "$file" | sed "s/[ ]\+:/:/g;s/: /: <b>/;s/$/<\/b>/" | rg "<b>")" ;;
+ *) notify-send "No keybind for that key" ;;
+ esac
diff --git a/.config/swaylock/config b/.config/swaylock/config
@@ -0,0 +1 @@
+color=#000000
diff --git a/.config/tmux/tmux.conf b/.config/tmux/tmux.conf
@@ -0,0 +1,69 @@
+# # List of plugins
+# set -g @plugin 'tmux-plugins/tpm'
+# set -g @plugin 'tmux-plugins/tmux-sensible'
+
+# ========== General options ==========
+# Neovim told me to set these parameters
+set-option -sg escape-time 10
+set-option -g focus-events on
+# Tell tmux that foot support true color
+set -sa terminal-features 'foot*:sixel:sync:RGB:256:hyperlinks:usstyle:rectfill:focus:mouse'
+# Limit scrollback buffer to 100k lines
+set -g history-limit 100000
+# needed for large sixels
+set -gq input-buffer-size 10485760
+# Automatically renumber windows when a window is closed
+set -g renumber-windows on
+set -g display-panes-time 60000
+# Update envvars so hyprctl works
+set -g update-environment DISPLAY
+set -ga update-environment HYPRLAND_INSTANCE_SIGNATURE
+set -ga update-environment HYPRLAND_CMD
+set -ga update-environment WAYLAND_DISPLAY
+set -ga update-environment SWAYSOCK
+set -ga update-environment I3SOCK
+
+set -g base-index 1
+set -g pane-base-index 1
+
+# ========== Keybinds ==========
+# Enable mouse
+set -g mouse on
+
+# Prefix is Ctrl-a
+set -g prefix C-a
+bind C-a send-prefix
+unbind C-b
+
+# Vim-like keybinds
+set -g mode-keys vi
+set -g status-keys vi
+
+# reload config on r
+bind r source-file "~/.config/tmux/tmux.conf"
+
+# Split pane into two
+bind \\ split-window -h -c "#{pane_current_path}"
+bind - split-window -v -c "#{pane_current_path}"
+unbind '"'
+unbind %
+
+# moving between panes with vim movement keys
+bind h select-pane -L
+bind j select-pane -D
+bind k select-pane -U
+bind l select-pane -R
+
+# Moving between windows with j and k
+# If a window to the right of the current window exists, switch to it, otherwise create a new one
+bind -r C-k if-shell -F '#{==:#{active_window_index},#{last_window_index}}' 'new-window' 'select-window -n'
+# If the current window is the leftmost window, do nothing
+bind -r C-j if-shell -F '#{>:#{window_index},0}' 'select-window -p'
+
+# resize panes with vim movement keys
+bind -r H resize-pane -L 1
+bind -r J resize-pane -D 1
+bind -r K resize-pane -U 1
+bind -r L resize-pane -R 1
+
+run '~/.config/tmux/plugins/tpm/tpm'
diff --git a/.config/user-dirs.dirs b/.config/user-dirs.dirs
@@ -0,0 +1 @@
+XDG_DESKTOP_DIR="$HOME/"
diff --git a/.config/wget/wgetrc b/.config/wget/wgetrc
@@ -0,0 +1 @@
+hsts-file=~/.cache/wget-hsts
diff --git a/.config/xdg-desktop-portal-termfilechooser/config b/.config/xdg-desktop-portal-termfilechooser/config
@@ -0,0 +1,2 @@
+[filechooser]
+env=TERMCMD="footclient -a termfilechooser"
diff --git a/.config/xdg-desktop-portal-wlr/config b/.config/xdg-desktop-portal-wlr/config
@@ -0,0 +1,3 @@
+[screencast]
+chooser_type=dmenu
+chooser_cmd=mew
diff --git a/.config/xdg-desktop-portal/config b/.config/xdg-desktop-portal/config
@@ -0,0 +1,3 @@
+[preferred]
+default=wlr;termfilechooser
+org.freedesktop.impl.portal.FileChooser=termfilechooser
diff --git a/.config/yazi/init.lua b/.config/yazi/init.lua
@@ -0,0 +1,4 @@
+require("session"):setup {
+ sync_yanked = true,
+}
+require("git"):setup()
diff --git a/.config/yazi/plugins/git.yazi/main.lua b/.config/yazi/plugins/git.yazi/main.lua
@@ -0,0 +1,261 @@
+--- @since 25.5.31
+
+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 = {
+ excluded = 100, -- ignored directory
+ ignored = 6, -- ignored file
+ untracked = 5,
+ modified = 4,
+ added = 3,
+ deleted = 2,
+ updated = 1,
+ unknown = 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.unknown) > 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.unknown 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
+ -- TODO: remove this
+ if ui.render then
+ ui.render()
+ else
+ ya.render()
+ end
+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
+
+ -- TODO: remove this
+ if ui.render then
+ ui.render()
+ else
+ ya.render()
+ end
+ 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.ignored] = t.ignored and ui.Style(t.ignored) or ui.Style():fg("darkgray"),
+ [CODES.untracked] = t.untracked and ui.Style(t.untracked) or ui.Style():fg("magenta"),
+ [CODES.modified] = t.modified and ui.Style(t.modified) or ui.Style():fg("yellow"),
+ [CODES.added] = t.added and ui.Style(t.added) or ui.Style():fg("green"),
+ [CODES.deleted] = t.deleted and ui.Style(t.deleted) or ui.Style():fg("red"),
+ [CODES.updated] = t.updated and ui.Style(t.updated) or ui.Style():fg("yellow"),
+ }
+ local signs = {
+ [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 "",
+ }
+
+ Linemode:children_add(function(self)
+ local url = self._file.url
+ local repo = st.dirs[tostring(url.base)]
+ local code
+ if repo then
+ code = repo == CODES.excluded and CODES.ignored or st.repos[repo][tostring(url):sub(#repo + 2)]
+ end
+
+ if not code or 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
+ 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)
+ :stdout(Command.PIPED)
+ :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 `unknown`,
+ -- 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.unknown
+ end
+
+ add(tostring(cwd), repo, changed)
+
+ return false
+end
+
+return { setup = setup, fetch = fetch }
diff --git a/.config/yazi/yazi.toml b/.config/yazi/yazi.toml
@@ -0,0 +1,12 @@
+[mgr]
+show_hidden = true
+
+[[plugin.prepend_fetchers]]
+id = "git"
+name = "*"
+run = "git"
+
+[[plugin.prepend_fetchers]]
+id = "git"
+name = "*/"
+run = "git"
diff --git a/.config/yt-dlp/config b/.config/yt-dlp/config
@@ -0,0 +1 @@
+--mtime
diff --git a/.config/zathura/zathurarc b/.config/zathura/zathurarc
@@ -0,0 +1,25 @@
+set sandbox none
+set statusbar-h-padding 0
+set statusbar-v-padding 0
+set page-padding 1
+set selection-clipboard clipboard
+map u scroll half-up
+map d scroll half-down
+map D toggle_page_mode
+map r reload
+map R rotate
+map K zoom in
+map J zoom out
+map i recolor
+map p print
+map g goto top
+map [fullscreen] u scroll half-up
+map [fullscreen] d scroll half-down
+map [fullscreen] D toggle_page_mode
+map [fullscreen] r reload
+map [fullscreen] R rotate
+map [fullscreen] K zoom in
+map [fullscreen] J zoom out
+map [fullscreen] i recolor
+map [fullscreen] p print
+map [fullscreen] g goto top
diff --git a/.config/zsh/.zshrc b/.config/zsh/.zshrc
@@ -0,0 +1,121 @@
+# Enable colors and change prompt:
+autoload -U colors && colors # Load colors
+
+clp(){
+ yes | paru -Scc
+}
+
+autoload -Uz vcs_info
+
+# enable only git
+zstyle ':vcs_info:*' enable git
+
+# setup a hook that runs before every ptompt.
+precmd_vcs_info() { vcs_info }
+precmd_functions+=( precmd_vcs_info )
+
+# add a function to check for untracked files in the directory.
+# from https://github.com/zsh-users/zsh/blob/master/Misc/vcs_info-examples
+zstyle ':vcs_info:git*+set-message:*' hooks git-untracked
+#
++vi-git-untracked(){
+ if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \
+ git status --porcelain | grep '??' &> /dev/null ; then
+ # This will show the marker if there are any untracked files in repo.
+ # If instead you want to show the marker only if there are untracked
+ # files in $PWD, use:
+ #[[ -n $(git ls-files --others --exclude-standard) ]] ; then
+ hook_com[staged]+='!' # signify new files with a bang
+ fi
+}
+
+zstyle ':vcs_info:*' check-for-changes true
+# zstyle ':vcs_info:git:*' formats " %r/%S %b %m%u%c "
+zstyle ':vcs_info:git:*' formats " %{$fg[red]%}%m%u%c%{$fg[white]%}*%{$fg[white]%}%b"
+
+# format our main prompt for hostname current folder, and permissions.
+PROMPT="%{$fg[blue]%}%~"
+# PROMPT="%B%{$fg[blue]%}[%{$fg[white]%}%n%{$fg[red]%}@%{$fg[white]%}%m%{$fg[blue]%}] %(?:%{$fg_bold[green]%}➜ :%{$fg_bold[red]%}➜ )%{$fg[cyan]%}%c%{$reset_color%}"
+# PROMPT="%{$fg[green]%}%n@%m %~ %{$reset_color%}%#> "
+PROMPT+="\$vcs_info_msg_0_"
+PROMPT+=" %(?:%{$fg_bold[magenta]%}>:%{$fg_bold[red]%}>)%{$reset_color%} "
+setopt autocd # Automatically cd into typed directory.
+stty stop undef # Disable ctrl-s to freeze terminal.
+setopt interactive_comments
+setopt prompt_subst
+# History in cache directory:
+HISTSIZE=10000000
+SAVEHIST=10000000
+HISTFILE="${XDG_CACHE_HOME:-$HOME/.cache}/zshhistory"
+setopt inc_append_history
+
+# Load aliases and shortcuts if existent.
+[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutrc" ] && source "${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutrc"
+[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutenvrc" ] && source "${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutenvrc"
+[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/shell/aliasrc" ] && source "${XDG_CONFIG_HOME:-$HOME/.config}/shell/aliasrc"
+[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/shell/zshnameddirrc" ] && source "${XDG_CONFIG_HOME:-$HOME/.config}/shell/zshnameddirrc"
+
+# Basic auto/tab complete:
+autoload -U compinit
+zstyle ':completion:*' menu select
+zmodload zsh/complist
+compinit
+_comp_options+=(globdots) # Include hidden files.
+
+# vi mode
+bindkey -v
+export KEYTIMEOUT=1
+
+# Use vim keys in tab complete menu:
+bindkey -M menuselect 'h' vi-backward-char
+bindkey -M menuselect 'k' vi-up-line-or-history
+bindkey -M menuselect 'l' vi-forward-char
+bindkey -M menuselect 'j' vi-down-line-or-history
+bindkey -v '^?' backward-delete-char
+
+# Change cursor shape for different vi modes.
+function zle-keymap-select () {
+ case $KEYMAP in
+ vicmd) echo -ne '\e[6 q';;
+ viins|main) echo -ne '\033[0 q';;
+ esac
+}
+zle -N zle-keymap-select
+zle-line-init() {
+ zle -K viins # initiate `vi insert` as keymap (can be removed if `bindkey -V` has been set elsewhere)
+ echo -ne '\033[0 q'
+}
+zle -N zle-line-init
+
+function preexec {
+ print -Pn "\e]0;${(q)1}\e\\"
+}
+
+# Use yazi to switch directories and bind it to ctrl-o
+function y() {
+ local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd
+ yazi "$@" --cwd-file="$tmp"
+ if cwd="$(command cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
+ builtin cd -- "$cwd"
+ fi
+ rm -f -- "$tmp" > /dev/null
+}
+
+bindkey -s '^o' '^uy\n'
+
+bindkey -s '^a' '^ubc -lq\n'
+
+bindkey -s '^f' '^ucd "$(dirname "$(fzf)")"\n'
+
+bindkey '^[[P' delete-char
+
+# Edit line in vim with ctrl-e:
+autoload edit-command-line; zle -N edit-command-line
+bindkey '^e' edit-command-line
+bindkey -M vicmd '^[[P' vi-delete-char
+bindkey -M vicmd '^e' edit-command-line
+bindkey -M visual '^[[P' vi-delete
+
+source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
+# Load syntax highlighting; should be last.
+source /usr/share/zsh/plugins/fast-syntax-highlighting/fast-syntax-highlighting.plugin.zsh 2>/dev/null
diff --git a/.local/bin/bookmarks b/.local/bin/bookmarks
@@ -0,0 +1,142 @@
+#!/bin/dash
+
+URLQUERY_FILE="${HOME}/.local/share/urlquery"
+ACTION_MENU="@@"
+
+CLIPBOARD() {
+ wl-paste
+}
+
+DMENU() {
+ mew -i -l "${1}" -p "${2}"
+}
+
+error_notify() {
+ notify-send "${1}"
+ exit "1"
+}
+
+ensure_file_exists() {
+ [ -f "${URLQUERY_FILE}" ] || {
+ notify-send "${URLQUERY_FILE} does not exist. Creating it now."
+ printf "SearXNG=https://searx.tiekoetter.com/search?q=\n" > "${URLQUERY_FILE}"
+ }
+}
+
+get_selection() {
+ cut -d= -f1 "${URLQUERY_FILE}" | DMENU "${LINE_COUNT}" "Bookmarks"
+}
+
+update_file() {
+ pattern="${1}"
+ replacement="${2}"
+
+ sed "/${pattern}/c\\${replacement}" "${URLQUERY_FILE}" > "${URLQUERY_FILE}.tmp" &&
+ mv "${URLQUERY_FILE}.tmp" "${URLQUERY_FILE}" ||
+ error_notify "Failed to update the file."
+}
+
+is_valid_url() {
+ printf "%s\n" "${1}" | rg -q "^https?://[^[:space:]/?#][^[:space:]]+$"
+}
+
+add_bookmark() {
+ URL="$(CLIPBOARD)"
+
+ is_valid_url "${URL}" || error_notify "The clipboard content is not a valid URL."
+
+ rg -q "=${URL}$" "${URLQUERY_FILE}" &&
+ notify-send "The URL is already in the list." && return
+
+ NAME="$(printf "" | DMENU "0" "Name")"
+
+ [ -n "${NAME}" ] && printf "%s\n" "${NAME}=${URL}" >> "${URLQUERY_FILE}" &&
+ notify-send "'${NAME}' is bookmarked."
+}
+
+delete_bookmark() {
+ NAME="$(get_selection)"
+
+ [ -z "${NAME}" ] && error_notify "Failed to delete the bookmark." && return
+
+ sed "/^${NAME}=/d" "${URLQUERY_FILE}" > "${URLQUERY_FILE}.tmp"
+ mv "${URLQUERY_FILE}.tmp" "${URLQUERY_FILE}"
+
+ [ -s "${URLQUERY_FILE}" ] && rg -q "\S" "${URLQUERY_FILE}" || rm "${URLQUERY_FILE}"
+
+ notify-send "'${NAME}' is deleted."
+}
+
+edit_name() {
+ OLD_NAME="${1}"
+ NEW_NAME="$(printf "" | DMENU "0" "New Name")"
+
+ [ -z "${NEW_NAME}" ] && return
+
+ URL="$(rg "^${OLD_NAME}=" "${URLQUERY_FILE}" | cut -d= -f2)"
+
+ update_file "^${OLD_NAME}=" "${NEW_NAME}=${URL}"
+}
+
+edit_url() {
+ NAME="${1}"
+ NEW_URL="$(echo "" | DMENU "0" "New URL")"
+
+ [ -z "${NEW_URL}" ] && return
+
+ update_file "^${NAME}=.*" "${NAME}=${NEW_URL}"
+}
+
+edit_bookmark() {
+ NAME="$(get_selection)"
+
+ [ -z "${NAME}" ] && error_notify "Failed to edit the bookmark." && return
+
+ FIELD="$(printf "Name\nURL\n" | DMENU "2" "Edit")"
+
+ case "${FIELD}" in
+ "Name")edit_name "${NAME}";;
+ "URL")edit_url "${NAME}"
+ esac
+
+ notify-send "'${NAME}' is updated."
+}
+
+open_bookmark() {
+ URL="$(rg "^${SELECTION}=" "${URLQUERY_FILE}" | cut -d= -f2-)"
+
+ [ -z "${URL}" ] && notify-send "Bookmark not found." && exit "1"
+
+ case "${URL}" in
+ *"search"* | *"wiki"* | *"packages"* | *"chatgpt"*) QUERY="$(echo "" | DMENU "0" "Search")"
+ URL="${URL}${QUERY}"
+ ;;
+ esac
+
+ "${BROWSER}" "${URL}" || notify-send "Failed to open the URL."
+}
+
+ensure_file_exists
+
+LINE_COUNT="$(wc -l < "${URLQUERY_FILE}")"
+
+[ "${LINE_COUNT}" -ge "15" ] && LINE_COUNT="15"
+
+SELECTION="$(get_selection)"
+
+[ -z "${SELECTION}" ] && exit
+
+case "${SELECTION}" in
+ "${ACTION_MENU}")
+ ACTION="$(printf "Add\nDelete\nEdit\n" | DMENU "3" "Action")"
+
+ case "${ACTION}" in
+ "Add") add_bookmark ;;
+ "Delete") delete_bookmark ;;
+ "Edit") edit_bookmark ;;
+ esac
+ ;;
+ *)
+ open_bookmark
+ ;;
+esac
diff --git a/.local/bin/booksplit b/.local/bin/booksplit
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Requires ffmpeg
+
+[ ! -f "$2" ] && printf "The first file should be the audio, the second should be the timecodes.\\n" && exit
+
+echo "Enter the album/book title:"; read -r booktitle
+echo "Enter the artist/author:"; read -r author
+echo "Enter the publication year:"; read -r year
+
+inputaudio="$1"
+ext="${1##*.}"
+
+# Get a safe file name from the book.
+escbook="$(echo "$booktitle" | iconv -c -f UTF-8 -t ASCII//TRANSLIT | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed "s/-\+/-/g;s/\(^-\|-\$\)//g")"
+
+! mkdir -p "$escbook" &&
+ echo "Do you have write access in this directory?" &&
+ exit 1
+
+# Get the total number of tracks from the number of lines.
+total="$(wc -l < "$2")"
+
+cmd="ffmpeg -i \"$inputaudio\" -nostdin -y"
+
+while read -r x;
+do
+ end="$(echo "$x" | cut -d' ' -f1)"
+ file="$escbook/$(printf "%.2d" "$track")-$esctitle.$ext"
+ if [ -n "$start" ]; then
+ cmd="$cmd -metadata artist=\"$author\" -metadata title=\"$title\" -metadata album=\"$booktitle\" -metadata year=\"$year\" -metadata track=\"$track\" -metadata total=\"$total\" -ss \"$start\" -to \"$end\" -vn -c:a copy \"$file\" "
+ fi
+ title="$(echo "$x" | cut -d' ' -f2-)"
+ esctitle="$(echo "$title" | iconv -c -f UTF-8 -t ASCII//TRANSLIT | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed "s/-\+/-/g;s/\(^-\|-\$\)//g")"
+ track="$((track+1))"
+ start="$end"
+done < "$2"
+
+# Last track must be added out of the loop.
+file="$escbook/$(printf "%.2d" "$track")-$esctitle.$ext"
+cmd="$cmd -metadata artist=\"$author\" -metadata title=\"$title\" -metadata album=\"$booktitle\" -metadata year=\"$year\" -metadata track=\"$track\" -ss \"$start\" -vn -c copy \"$file\""
+
+eval "$cmd"
diff --git a/.local/bin/check_lyrics b/.local/bin/check_lyrics
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+MUSIC_DIR="${1:-.}"
+
+# Check FLAC files for matching lyrics
+fd --glob "*.flac" -t f "$MUSIC_DIR" | while IFS= read -r flac_file; do
+ base_name="${flac_file%.flac}"
+ lyrics_file="${base_name}.lrc"
+ if [ ! -f "$lyrics_file" ]; then
+ echo "Mismatch: $(basename "$flac_file" .flac) exists, but $(basename "$lyrics_file") is missing"
+ fi
+done
+
+# Check for orphaned lyrics files
+fd --glob "*.lrc" -t f "$MUSIC_DIR" | while IFS= read -r lyrics_file; do
+ base_name="${lyrics_file%.lrc}"
+ flac_file="${base_name}.flac"
+ if [ ! -f "$flac_file" ]; then
+ echo "Orphaned: $(basename "$lyrics_file" .lrc) exists, but $(basename "$flac_file") is missing"
+ fi
+done
diff --git a/.local/bin/chkmd5m b/.local/bin/chkmd5m
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Compare MD5 hashes of audio streams from multiple files using ffmpeg
+
+if [ "$#" -lt 2 ]; then
+ echo "Usage: $0 <file1> <file2> [file3 ...]"
+ exit 1
+fi
+
+get_md5() {
+ ffmpeg -v error -i "$1" -map 0:a:0 -f md5 - 2>/dev/null | cut -d= -f2
+}
+
+echo "Comparing audio hashes:"
+echo
+
+first_file=$1
+first_hash=$(get_md5 "$first_file")
+
+echo "$first_file : $first_hash"
+shift
+
+for file in "$@"; do
+ hash=$(get_md5 "$file")
+ echo "$file : $hash"
+ if [ "$hash" = "$first_hash" ]; then
+ echo "✅ Matches $first_file"
+ else
+ echo "❌ Differs from $first_file"
+ fi
+ echo
+done
diff --git a/.local/bin/chooseprofile b/.local/bin/chooseprofile
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+profiles=$(awk -F= '/^\[Profile/ {profile=$1} /Name/ && !/default/ {print $2}' ~/.mozilla/icecat/profiles.ini)
+
+profile=$(echo "$profiles" | mew -p "Select IceCat Profile" -l 10)
+
+if [ -z "$profile" ] || ! echo "$profiles" | rg -q "^$profile$"; then
+ echo "Invalid selection or no profile selected. Exiting."
+ exit 1
+fi
+
+swaymsg exec "icecat -P $profile"
diff --git a/.local/bin/compiler b/.local/bin/compiler
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# This script will compile or run another finishing operation on a document. I
+# have this script run via vim.
+
+# Compiles .tex. groff (.mom, .ms), .rmd, .md, .org. Opens .sent files as sent
+# presentations. Runs scripts based on extension or shebang.
+
+file="${1}"
+ext="${file##*.}"
+dir=${file%/*}
+base="${file%.*}"
+
+cd "${dir}" || exit "1"
+
+case "${ext}" in
+ [0-9]) preconv "${file}" | refer -PS -e | groff -mandoc -T pdf > "${base}.pdf" ;;
+ mom|ms) preconv "${file}" | refer -PS -e | groff -T pdf -m"${ext}" > "${base}.pdf" ;;
+ c) cc "${file}" -o "${base}" && "${base}" ;;
+ cob) cobc -x -o "$base" "$file" && "$base" ;;
+ cpp|cc) g++ "${file}" -o "${base}" && "${base}" ;;
+ cs) mcs "${file}" && mono "${base}.exe" ;;
+ go) go run "${file}" ;;
+ h) doas make install ;;
+ java) javac -d classes "${file}" && java -cp classes "${base}" ;;
+ m) octave "${file}" ;;
+ md) [ -x "$(command -v lowdown)" ] && \
+ lowdown --parse-no-intraemph "${file}" -Tms | groff -mpdfmark -ms -kept -T pdf > "${base}.pdf" || \
+ [ -x "$(command -v groffdown)" ] && \
+ groffdown -i "${file}" | groff -T pdf > "${base}.pdf" || \
+ pandoc -t ms --highlight-style="kate" -s -o "${base}.pdf" "${file}" ;;
+ org) emacs "${file}" --batch -u "${USER}" -f org-latex-export-to-pdf ;;
+ py) python "${file}" ;;
+ rink) rink -f "${file}" ;;
+ [rR]md) Rscript -e "rmarkdown::render('${file}', quiet=TRUE)" ;;
+ rs) cargo build && cargo run --quiet ;;
+ sass) sassc -a "${file}" "${base}.css" ;;
+ scad) openscad -o "${base}.stl" "${file}" ;;
+ sent) setsid -f sent "${file}" 2> "/dev/null" ;;
+ tex) latexmk ;;
+ *) sed -n '/^#!/s/^#!//p; q' "${file}" | xargs -r -I % "${file}" ;;
+esac
diff --git a/.local/bin/cron/README.md b/.local/bin/cron/README.md
@@ -0,0 +1,14 @@
+# Important Note
+
+These cronjobs have components that require information about your current display to display notifications correctly.
+
+When you add them as cronjobs, I recommend you precede the command with commands as those below:
+
+```
+export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u $USER)/bus; export WAYLAND_DISPLAY=wayland-1; . $HOME/.zprofile; then_command_goes_here
+```
+
+This ensures that notifications will display, wtype/wlrctl commands will function and environmental variables will work as well.
+
+# Also important
+DBUS_SESSION_BUS_ADDRESS variable will always have a random address in the /tmp directory when you are using dinit as your init system.
diff --git a/.local/bin/cron/checkup b/.local/bin/cron/checkup
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Syncs repositories and downloads updates, meant to be run as a cronjob.
+
+doas pacman -Syyuw --noconfirm || notify-send "Error downloading updates.
+
+Check your internet connection, if pacman is already running, or run update manually to see errors."
+pkill -RTMIN+8 "${STATUSBAR:-i3blocks}"
+
+if pacman -Qu | rg -v "\[ignored\]"
+then
+ notify-send "Repository Sync" "Updates available."
+fi
diff --git a/.local/bin/cron/crontog b/.local/bin/cron/crontog
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Toggles all cronjobs off/on.
+# Stores disabled crontabs in ~/.config/cronsaved until restored.
+
+([ -f "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved ] && crontab - < "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved && rm "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved && notify-send "🕓 Cronjobs re-enabled.") || ( crontab -l > "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved && crontab -r && notify-send "🕓 Cronjobs saved and disabled.")
diff --git a/.local/bin/cron/mailup b/.local/bin/cron/mailup
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+pgrep -f mailsync && exit
+
+echo 🔃 > /tmp/mailupdate
+pkill -RTMIN+12 "${STATUSBAR:-i3blocks}"
+/usr/bin/mailsync
+rm -f /tmp/mailupdate
+pkill -RTMIN+12 "${STATUSBAR:-i3blocks}"
diff --git a/.local/bin/cron/newsup b/.local/bin/cron/newsup
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Set as a cron job to check for new RSS entries for newsboat.
+# If newsboat is open, sends it an "R" key to refresh.
+
+export XDG_RUNTIME_DIR=/run/user/1000
+export WAYLAND_DISPLAY=wayland-1
+
+pgrep -f newsboat$ && /usr/bin/wlrctl window focus title:newsboat && /usr/bin/wlrctl keyboard type R && exit
+
+echo "<span color='#7F7F7F'>[updating]</span>" > /tmp/newsupdate
+pkill -RTMIN+6 "${STATUSBAR:-i3blocks}"
+/usr/bin/newsboat -x reload
+rm -f /tmp/newsupdate
+pkill -RTMIN+6 "${STATUSBAR:-i3blocks}"
diff --git a/.local/bin/define b/.local/bin/define
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+word=${1:-$(xclip -o -selection primary 2>/dev/null || wl-paste 2>/dev/null)}
+
+# Check for empty word or special characters
+[[ -z "$word" || "$word" =~ [\/] ]] && notify-send -h string:bgcolor:#bf616a -t 3000 "Invalid input." && exit 0
+
+query=$(curl -s --connect-timeout 5 --max-time 10 "https://api.dictionaryapi.dev/api/v2/entries/en_US/$word")
+
+# Check for connection error (curl exit status stored in $?)
+[ $? -ne 0 ] && notify-send -h string:bgcolor:#bf616a -t 3000 "Connection error." && exit 1
+
+# Check for invalid word response
+[[ "$query" == *"No Definitions Found"* ]] && notify-send -h string:bgcolor:#bf616a -t 3000 "Invalid word." && exit 0
+
+# Show only first 3 definitions
+def=$(echo "$query" | jq -r '[.[].meanings[] | {pos: .partOfSpeech, def: .definitions[].definition}] | .[:3].[] | "\n\(.pos). \(.def)"')
+
+# Requires a notification daemon to be installed
+notify-send -t 60000 "$word -" "$def"
+
+
+### MORE OPTIONS :)
+
+# Show first definition for each part of speech (thanks @morgengabe1 on youtube)
+# def=$(echo "$query" | jq -r '.[0].meanings[] | "\(.partOfSpeech): \(.definitions[0].definition)\n"')
+
+# Show all definitions
+# def=$(echo "$query" | jq -r '.[].meanings[] | "\n\(.partOfSpeech). \(.definitions[].definition)"')
+
+# Regex + rg for just definition, if anyone prefers that to jq
+# def=$(rg -Po '"definition":"\K(.*?)(?=")' <<< "$query")
+
+# bold=$(tput bold) # Print text bold with echo, for visual clarity
+# normal=$(tput sgr0) # Reset text to normal
+# echo "${bold}Definition of $word"
+# echo "${normal}$def"
diff --git a/.local/bin/displayselect b/.local/bin/displayselect
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# A UI for detecting and selecting all displays. Probes xrandr for connected
+# displays and lets user select one to use. User may also select "manual
+# selection" which opens arandr.
+
+twoscreen() { # If multi-monitor is selected and there are two screens.
+
+ mirror=$(printf "no\\nyes" | dmenu -i -p "Mirror displays?")
+ # Mirror displays using native resolution of external display and a scaled
+ # version for the internal display
+ if [ "$mirror" = "yes" ]; then
+ external=$(echo "$screens" | dmenu -i -p "Optimize resolution for:")
+ internal=$(echo "$screens" | rg -v "$external")
+
+ res_external=$(xrandr --query | sed -n "/^$external/,/\+/p" | \
+ tail -n 1 | awk '{print $1}')
+ res_internal=$(xrandr --query | sed -n "/^$internal/,/\+/p" | \
+ tail -n 1 | awk '{print $1}')
+
+ res_ext_x=$(echo "$res_external" | sed 's/x.*//')
+ res_ext_y=$(echo "$res_external" | sed 's/.*x//')
+ res_int_x=$(echo "$res_internal" | sed 's/x.*//')
+ res_int_y=$(echo "$res_internal" | sed 's/.*x//')
+
+ scale_x=$(echo "$res_ext_x / $res_int_x" | bc -l)
+ scale_y=$(echo "$res_ext_y / $res_int_y" | bc -l)
+
+ xrandr --output "$external" --auto --scale 1.0x1.0 \
+ --output "$internal" --auto --same-as "$external" \
+ --scale "$scale_x"x"$scale_y"
+ else
+
+ primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
+ secondary=$(echo "$screens" | rg -v ^"$primary"$)
+ direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
+ xrandr --output "$primary" --auto --scale 1.0x1.0 --output "$secondary" --"$direction"-of "$primary" --auto --scale 1.0x1.0
+ fi
+ }
+
+morescreen() { # If multi-monitor is selected and there are more than two screens.
+ primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
+ secondary=$(echo "$screens" | rg -v ^"$primary"$ | dmenu -i -p "Select secondary display:")
+ direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
+ tertiary=$(echo "$screens" | rg -v ^"$primary"$ | rg -v ^"$secondary"$ | dmenu -i -p "Select third display:")
+ xrandr --output "$primary" --auto --output "$secondary" --"$direction"-of "$primary" --auto --output "$tertiary" --"$(printf "left\\nright" | rg -v "$direction")"-of "$primary" --auto
+ }
+
+multimon() { # Multi-monitor handler.
+ case "$(echo "$screens" | wc -l)" in
+ 2) twoscreen ;;
+ *) morescreen ;;
+ esac ;}
+
+onescreen() { # If only one output available or chosen.
+ xrandr --output "$1" --auto --scale 1.0x1.0 $(echo "$allposs" | rg -v "\b$1" | awk '{print "--output", $1, "--off"}' | paste -sd ' ' -)
+ }
+
+postrun() { # Stuff to run to clean up.
+ setbg # Fix background if screen size/arangement has changed.
+ { killall dunst ; setsid -f dunst ;} >/dev/null 2>&1 # Restart dunst to ensure proper location on screen
+ }
+
+# Get all possible displays
+allposs=$(xrandr -q | rg "connected")
+
+# Get all connected screens.
+screens=$(echo "$allposs" | awk '/ connected/ {print $1}')
+
+# If there's only one screen
+[ "$(echo "$screens" | wc -l)" -lt 2 ] &&
+ { onescreen "$screens"; postrun; notify-send "💻 Only one screen detected." "Using it in its optimal settings..."; exit ;}
+
+# Get user choice including multi-monitor and manual selection:
+chosen=$(printf "%s\\nmulti-monitor\\nmanual selection" "$screens" | dmenu -i -p "Select display arangement:") &&
+case "$chosen" in
+ "manual selection") arandr ; exit ;;
+ "multi-monitor") multimon ;;
+ *) onescreen "$chosen" ;;
+esac
+
+postrun
diff --git a/.local/bin/dmenuhandler b/.local/bin/dmenuhandler
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# Feed this script a link and it will give mew
+# some choice programs to use to open it.
+feed="${1:-$(true | mew -p 'Paste URL or file path')}"
+
+case "$(printf "copy url\\nswayimg\\nsetbg\\nPDF\\nbrowser\\nlynx\\nvim\\nmpv\\nmpv loop\\nmpv float\\nqueue download\\nqueue yt-dlp\\nqueue yt-dlp audio" | mew -i -p "Open it with?")" in
+ "copy url") echo "$feed" | wl-copy ;;
+ mpv) setsid -f mpv -quiet "$feed" >/dev/null 2>&1 ;;
+ "mpv loop") setsid -f mpv -quiet --loop "$feed" >/dev/null 2>&1 ;;
+ "mpv float") setsid -f "$TERMINAL" -e mpv --geometry=+0-0 --autofit=30% --title="mpvfloat" "$feed" >/dev/null 2>&1 ;;
+ "queue yt-dlp") qndl "$feed" >/dev/null 2>&1 ;;
+ "queue yt-dlp audio") qndl "$feed" 'yt-dlp -o "%(title)s.%(ext)s" -f bestaudio --embed-metadata --restrict-filenames' ;;
+ "queue download") qndl "$feed" 'curl -LO' >/dev/null 2>&1 ;;
+ PDF) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && zathura "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;;
+ swayimg) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && swayimg "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;;
+ vim) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && setsid -f "$TERMINAL" -e "$EDITOR" "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;;
+ setbg) curl -L "$feed" > $XDG_CACHE_HOME/pic ; swaybg -i $XDG_CACHE_HOME/pic -m fill & >/dev/null 2>&1 ;;
+ browser) setsid -f "$BROWSER" "$feed" >/dev/null 2>&1 ;;
+ lynx) lynx "$feed" >/dev/null 2>&1 ;;
+esac
diff --git a/.local/bin/dmenumountcifs b/.local/bin/dmenumountcifs
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Gives a mew prompt to mount unmounted local NAS shares for read/write.
+# Requirements - "%wheel ALL=(ALL) NOPASSWD: ALL"
+#
+# Browse for mDNS/DNS-SD services using the Avahi daemon...
+srvname=$(avahi-browse _smb._tcp -t | awk '{print $4}' | mew -i -p "Which NAS?") || exit 1
+notify-send "Searching for network shares..." "Please wait..."
+# Choose share disk...
+share=$(smbclient -L "$srvname" -N | rg Disk | awk '{print $1}' | mew -i -p "Mount which share?") || exit 1
+# Format URL...
+share2mnt=//"$srvname".local/"$share"
+
+sharemount() {
+ mounted=$(mount -v | rg "$share2mnt") || ([ ! -d /mnt/"$share" ] && doas mkdir /mnt/"$share")
+ [ -z "$mounted" ] && doas mount -t cifs "$share2mnt" -o user=nobody,password="",noperm /mnt/"$share" && notify-send "Netshare $share mounted" && exit 0
+ notify-send "Netshare $share already mounted"; exit 1
+}
+
+sharemount
diff --git a/.local/bin/dmenupass b/.local/bin/dmenupass
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# This script is the SUDO_ASKPASS variable, meaning that it will be used as a
+# password prompt if needed.
+
+mew -P -p "password:" <&-
diff --git a/.local/bin/dmenurecord b/.local/bin/dmenurecord
@@ -0,0 +1,121 @@
+#!/bin/sh
+
+getdim() {
+ gpu-screen-recorder --list-capture-options | sed 's/|[0-9]\{1,\}x[0-9]\{1,\}//g' \
+ | rofi -dmenu -no-custom -p "Select output: "
+}
+
+updateicon() { \
+ echo "$1" > /tmp/recordingicon
+ pkill -RTMIN+9 "${STATUSBAR:-i3blocks}"
+}
+
+killrecording() {
+ recpid="$(bat /tmp/recordingpid)"
+ echo $recpid
+ kill -2 "$recpid"
+ rm -f /tmp/recordingpid
+ updateicon ""
+ pkill -RTMIN+9 "${STATUSBAR:-i3blocks}"
+}
+
+screencast() { gpu-screen-recorder \
+ -w "$(getdim)" \
+ -fm content \
+ -f 60 \
+ -a default_output \
+ -a default_input \
+ -o "$HOME/screencast-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+ updateicon " "
+}
+
+video() { gpu-screen-recorder \
+ -w "$(getdim)" \
+ -fm content \
+ -f 60 \
+ -o "$HOME/video-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+ updateicon ""
+}
+
+webcamhidef() { ffmpeg \
+ -f v4l2 \
+ -i /dev/video0 \
+ -video_size 1920x1080 \
+ "$HOME/webcam-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+ updateicon ""
+}
+
+webcam() { ffmpeg \
+ -f v4l2 \
+ -i /dev/video0 \
+ -video_size 640x480 \
+ "$HOME/webcam-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+ updateicon ""
+}
+
+
+audio() { \
+ ffmpeg \
+ -f alsa -i default \
+ -c:a flac \
+ "$HOME/audio-$(date '+%y%m%d-%H%M-%S').flac" &
+ echo $! > /tmp/recordingpid
+ updateicon ""
+}
+
+replay() { gpu-screen-recorder \
+ -w "$(getdim)" \
+ -fm content \
+ -f 60 \
+ -r 60 \
+ -c mkv \
+ -a default_output \
+ -a default_input \
+ -o "/mnt/ssd/rndm/clips/replays" &
+ echo $! > /tmp/recordingpid
+ updateicon " "
+}
+
+savereplay() {
+ recpid="$(bat /tmp/recordingpid)"
+ echo $recpid
+ kill -37 "$recpid"
+ pkill -RTMIN+9 "${STATUSBAR:-i3blocks}"
+ notify-send "Replay" "Last 60 seconds saved"
+ exit
+}
+
+askrecording() { \
+ choice=$(printf "screencast\\nreplay\\nvideo\\naudio\\nwebcam\\nwebcam (hi-def)" | rofi -dmenu -no-custom -i -p "Select recording style")
+ case "$choice" in
+ screencast) screencast;;
+ replay) replay;;
+ audio) audio;;
+ video) video;;
+ webcam) webcam;;
+ "webcam (hi-def)") webcamhidef;;
+ esac
+}
+
+asktoend() { \
+ if grep -q "" /tmp/recordingicon; then
+ response=$(printf "No\\nYes" | rofi -dmenu -no-custom -i -p "Replay is active. Save it?") &&
+ [ "$response" = "Yes" ] && savereplay
+ fi
+
+ response=$(printf "No\\nYes" | rofi -dmenu -no-custom -i -p "Recording still active. End recording?") &&
+ [ "$response" = "Yes" ] && killrecording
+}
+
+case "$1" in
+ screencast) screencast;;
+ replay) replay;;
+ audio) audio;;
+ video) video;;
+ kill) killrecording;;
+ *) ([ -f /tmp/recordingpid ] && asktoend && exit) || askrecording;;
+esac
diff --git a/.local/bin/doas_askpass b/.local/bin/doas_askpass
@@ -0,0 +1,47 @@
+#!/usr/bin/expect --
+
+# askpass implementation for doas
+# example usage: DOAS_ASKPASS="mew -P -p password:" doas_askpass echo working
+
+# don't mind the man behind the curtain
+log_user 0
+
+# no command, then nothing to do
+if { $argc == 0 } { exit 0 }
+
+# treat all arguments as command input
+set cmd [lrange $argv 0 end];
+
+# read askpass from env or fallback to dmenu_pass ()
+if {[info exists ::env(DOAS_ASKPASS)]} {
+ set askpass "$::env(DOAS_ASKPASS)"
+} else {
+ set askpass "dmenu_pass password:"
+}
+
+# read password from user
+set pwd [exec {*}$askpass]
+
+# spawn doas operation
+spawn doas {*}$cmd
+
+# send password and execute command
+expect "doas*password:" {
+ send -- "$pwd\r"
+ expect \r
+ log_user 1
+ expect eof
+}
+
+# get the exit status of the spawned doas command
+set status [wait]
+
+# check exit code (4th element of wait result)
+set exit_code [lindex $status 3]
+
+# exit with 1 if doas failed, else 0
+if { $exit_code != 0 } {
+ exit 1
+} else {
+ exit 0
+}
diff --git a/.local/bin/getbib b/.local/bin/getbib
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+BIB_FILE="${HOME}/latex/uni.bib"
+[ -f "${BIB_FILE}" ] || BIB_FILE="${2:-$(find "${HOME}" -path "${HOME}/.*" \
+ -prune -o -type "f" -name "*.bib" -print -quit)}"
+
+{ [ -f "${BIB_FILE}" ] || [ "${2}" ]; } || {
+ printf "%s\n" "Create a .bib file or provide as \$2." && exit "1"
+}
+
+filter() {
+ sed -n -E 's/.*((DOI|doi)((\.(org))?\/?|:? *))([^: ]+[^ .]).*/\6/p; T; q'
+}
+
+fpdf() {
+ pdf="${1}"
+ doi="$(pdfinfo "${pdf}" 2> "/dev/null" | filter)"
+
+ [ "${doi}" ] || doi="$(pdftotext -q -l "2" "${pdf}" - 2> "/dev/null" | filter)"
+
+ [ "${doi}" ] || printf "%s\n" "No DOI found for PDF: ${pdf}" >&2
+
+ printf "%s\n" "${doi}"
+}
+
+arrange() {
+ sed 's/\}, /\},\n /g
+ s/, /,\n /
+ s/ }/\n}/
+ s/,\s*pages=/,\n\tpages=/' |
+ sed '1s/^ *//
+ 1s/[0-9]*\([0-9]\{2\}\)/\1/
+ 1s/_//
+ 1s/.*/\L&/
+ s/.*=/\L&/
+ s/=/ = /'
+}
+
+doi2bib() {
+ doi="${1#doi:}"
+ url="https://api.crossref.org/works/${doi}/transform/application/x-bibtex"
+ entry="$(curl -kLsS --no-fail "${url}" | arrange)"
+ red='\033[0;31m'
+ reset='\033[0m'
+
+ printf "${red}%s${reset}\n" "${entry}"
+
+ [ "${entry%"${entry#?}"}" != "@" ] && {
+ printf "%s\n" "Failed to fetch bibtex entry for DOI: ${doi}"
+ return "1"
+ }
+
+ rg -iFq "doi = {${doi}}" "${BIB_FILE}" 2> "/dev/null" && {
+ printf "%s\n" "Bibtex entry for DOI: ${doi} already exists in the file."
+ } || {
+ [ -s "${BIB_FILE}" ] && printf "\n" >> "${BIB_FILE}"
+ printf "%s\n" "${entry}" >> "${BIB_FILE}"
+ printf "%s\n" "Added bibtex entry for DOI: ${doi}"
+ }
+}
+
+[ "${1}" ] || {
+ printf "%s\n" "Give either a pdf file or a DOI or a directory path that has PDFs as an argument."
+ exit "1"
+}
+
+[ -f "${1}" ] && doi="$(fpdf "${1}")" && doi2bib "${doi}" && exit "0"
+
+[ -d "${1}" ] && for i in "${1}"/*.pdf; do doi="$(fpdf "${i}")" && doi2bib "${doi}"; done && exit "0"
+
+doi="$(printf "%s\n" "${1}" | filter)" && doi2bib "${doi}"
diff --git a/.local/bin/getcomproot b/.local/bin/getcomproot
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# A helper script for LaTeX/groff files used by `compiler` and `opout`.
+# The user can add the root file of a larger project as a comment as below:
+# % root = mainfile.tex
+# And the compiler script will run on that instead of the opened file.
+
+texroot="$(sed -n 's/^\s*%.*root\s*=\s*\(\S\+\).*/\1/p' "${1}")"
+[ -f "${texroot}" ] && readlink -f "${texroot}" || exit "1"
diff --git a/.local/bin/ifinstalled b/.local/bin/ifinstalled
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# Some optional functions in LARBS require programs not installed by default. I
+# use this little script to check to see if a command exists and if it doesn't
+# it informs the user that they need that command to continue. This is used in
+# various other scripts for clarity's sake.
+
+for x in "$@"; do
+ if ! which "$x" >/dev/null 2>&1 && ! pacman -Qq "$x" >/dev/null 2>&1; then
+ notify-send "📦 $x" "must be installed for this function." && exit 1 ;
+ fi
+done
diff --git a/.local/bin/linkhandler b/.local/bin/linkhandler
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Feed script a url or file location.
+# If an image, it will view in swayimg,
+# if a video or gif, it will view in mpv
+# if a music file or pdf, it will download,
+# otherwise it opens link in browser.
+
+if [ -z "$1" ]; then
+ url="$(wl-paste)"
+else
+ url="$1"
+fi
+
+# Check if the URL is from inv.nadeko.net and adjust it for YouTube
+echo "$url" | rg -q 'inv.nadeko.net/watch'
+if [ $? -eq 0 ]; then
+ url="https://www.youtube.com/watch?v=$(echo "$url" | sed 's/.*inv\.nadeko\.net\/watch?v=\([^&]*\)/\1/')"
+fi
+
+case "$url" in
+ *mkv|*webm|*mp4|*youtube.com/watch*|*youtube.com/playlist*|*youtube.com/v/*|*youtube.com/shorts*|*youtu.be*|*hooktube.com*|*bitchute.com*|*videos.lukesmith.xyz*|*odysee.com*)
+ setsid -f mpv -quiet "$url" >/dev/null 2>&1 ;;
+ *png|*jpg|*jpe|*jpeg|*gif|*webp)
+ curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && swayimg "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *pdf|*cbz|*cbr)
+ curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && zathura "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *mp3|*flac|*opus|*mp3?source*)
+ qndl "$url" 'curl -LO' >/dev/null 2>&1 ;;
+ *)
+ [ -f "$url" ] && setsid -f "$TERMINAL" -e "$EDITOR" "$url" >/dev/null 2>&1 || setsid -f "$BROWSER" "$url" >/dev/null 2>&1
+esac
diff --git a/.local/bin/maimpick b/.local/bin/maimpick
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# This is bound to Shift+PrintScreen by default, requires grim (also optionally tesseract and swappy). It lets you
+# choose the kind of screenshot to take, including copying the image or even
+# highlighting an area to copy.
+
+# variables
+output="$(date '+%y%m%d-%H%M-%S').png"
+wclip_cmd="wl-copy -t image/png"
+ocr_cmd="wl-copy"
+
+case "$(printf "a selected area\\ncurrent window\\nfull screen\\na selected area (copy)\\ncurrent window (copy)\\nfull screen (copy)\\na selected area (swappy)\\ncurrent window (swappy)\\nfull screen (swappy)\\ncopy selected image to text" | mew -l 10 -i -p "Screenshot which area?")" in
+ "a selected area") geometry=$(slurp) && sleep 0.2 && grim -g "$geometry" pic-selected-"${output}" && notify-send "📸 maimpick" "Screenshot saved as pic-selected-$output." ;;
+ "current window")
+ geometry=$(swaymsg --raw -t get_tree | jq -r '.. | select(type == "object" and .focused == true) | .rect | "\(.x),\(.y) \(.width)x\(.height)"')
+ sleep 0.2
+ grim -g "$geometry" pic-window-"${output}" && notify-send "📸 maimpick" "Screenshot saved as pic-window-$output." ;;
+ "full screen") geometry=$(slurp -o) && sleep 0.2 && grim -g "$geometry" pic-full-"${output}" && notify-send "📸 maimpick" "Screenshot saved as pic-full-$output." ;;
+ "a selected area (copy)") geometry=$(slurp) && sleep 0.2 && grim -g "$geometry" - | ${wclip_cmd} && notify-send "📸 maimpick" "Selected area screenshot copied to clipboard." ;;
+ "current window (copy)")
+ geometry=$(swaymsg --raw -t get_tree | jq -r '.. | select(type == "object" and .focused == true) | .rect | "\(.x),\(.y) \(.width)x\(.height)"')
+ sleep 0.2
+ grim -g "$geometry" - | ${wclip_cmd} && notify-send "📸 maimpick" "Window screenshot copied to clipboard." ;;
+ "full screen (copy)") geometry=$(slurp -o) && sleep 0.2 && grim -g "$geometry" - | ${wclip_cmd} && notify-send "📸 maimpick" "Full screen screenshot copied to clipboard.";;
+ "a selected area (swappy)") geometry=$(slurp) && sleep 0.2 && grim -g "$geometry" - | swappy -f - ;;
+ "current window (swappy)")
+ geometry=$(swaymsg --raw -t get_tree | jq -r '.. | select(type == "object" and .focused == true) | .rect | "\(.x),\(.y) \(.width)x\(.height)"')
+ sleep 0.2
+ grim -g "$geometry" - | swappy -f - ;;
+ "full screen (swappy)") geometry=$(slurp -o) && sleep 0.2 && grim -g "$geometry" - | swappy -f - ;;
+ "copy selected image to text") tmpfile=$(mktemp /tmp/ocr-XXXXXX.png) && slurp | grim -g - - > "$tmpfile" && tesseract "$tmpfile" - -l eng | ${ocr_cmd} && rm "$tmpfile" && notify-send "📸 maimpick" "Detected text copied to clipboard.\n$(wl-paste)" ;;
+ *) notify-send "📸 maimpick" "Wrong option."
+esac
diff --git a/.local/bin/mounter b/.local/bin/mounter
@@ -0,0 +1,114 @@
+#!/bin/bash
+
+IFS='
+'
+# Function for escaping cell-phone names.
+escape(){ echo "$@" | iconv -cf UTF-8 -t ASCII//TRANSLIT | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed "s/-\+/-/g;s/\(^-\|-\$\)//g" ;}
+
+# Check for phones.
+phones="$(simple-mtpfs -l 2>/dev/null | sed "s/^/📱/")"
+mountedphones="$(rg "simple-mtpfs" /etc/mtab)"
+# If there are already mounted phones, remove them from the list of mountables.
+[ -n "$mountedphones" ] && phones="$(for phone in $phones; do
+ for mounted in $mountedphones; do
+ escphone="$(escape "$phone")"
+ [[ "$mounted" =~ "$escphone" ]] && break 1
+ done && continue 1
+ echo "$phone"
+done)"
+
+# Check for drives.
+lsblkoutput="$(doas lsblk -rpo "uuid,name,type,size,label,mountpoint,fstype")"
+# Get all LUKS drives
+allluks="$(echo "$lsblkoutput" | rg crypto_LUKS)"
+# Get a list of the LUKS drive UUIDs already decrypted.
+decrypted="$(find /dev/disk/by-id/dm-uuid-CRYPT-LUKS2-* | sed "s|.*LUKS2-||;s|-.*||")"
+# Functioning for formatting drives correctly for mew:
+filter() { sed "s/ /:/g" | awk -F':' '$7==""{printf "%s%s (%s) %s\n",$1,$3,$5,$6}' ; }
+
+# Get only LUKS drives that are not decrypted.
+unopenedluks="$(for drive in $allluks; do
+ uuid="${drive%% *}"
+ uuid="${uuid//-}" # This is a bashism.
+ [ -n "$decrypted" ] && for open in $decrypted; do
+ [ "$uuid" = "$open" ] && break 1
+ done && continue 1
+ echo "🔒 $drive"
+done | filter)"
+
+# Get all normal, non-encrypted or decrypted partitions that are not mounted.
+normalparts="$(echo "$lsblkoutput"| rg -v crypto_LUKS | rg 'part|rom|crypt' | sed "s/^/💾 /" | filter )"
+
+# Add all to one variable. If no mountable drives found, exit.
+alldrives="$(echo "$phones
+$unopenedluks
+$normalparts" | sed "/^$/d;s/ *$//")"
+
+# Quit the script if a sequential command fails.
+set -e
+
+test -n "$alldrives"
+
+# Feed all found drives to mew and get user choice.
+chosen="$(echo "$alldrives" | mew -p "Mount which drive?" -i)"
+
+# Function for prompting user for a mountpoint.
+getmount(){
+ mp="$(find /mnt /media /mount /home -maxdepth 1 -type d 2>/dev/null | mew -i -p "Mount this drive where?")"
+ test -n "$mp"
+ if [ ! -d "$mp" ]; then
+ mkdiryn=$(printf "No\\nYes" | mew -i -p "$mp does not exist. Create it?")
+ [ "$mkdiryn" = "Yes" ] && (mkdir -p "$mp" || doas_askpass mkdir -p "$mp")
+ fi
+}
+
+attemptmount(){
+ # Attempt to mount without a mountpoint, to see if drive is in fstab.
+ doas mount "$chosen" || return 1
+ notify-send "💾Drive Mounted." "$chosen mounted."
+ exit
+}
+
+case "$chosen" in
+ 💾*)
+ chosen="${chosen%% *}"
+ chosen="${chosen:1}" # This is a bashism.
+ parttype="$(echo "$lsblkoutput" | rg "$chosen" | awk '{print $NF}' | tr -d '[:space:]\r\n')"
+ attemptmount || getmount
+ case "${parttype##* }" in
+ vfat) doas mount -t vfat "$chosen" "$mp" -o rw,umask=0000 ;;
+ btrfs) doas mount "$chosen" "$mp" ;;
+ ntfs) doas mount -t ntfs3 "$chosen" "$mp" ;;
+ *) doas mount "$chosen" "$mp" -o uid="$(id -u)",gid="$(id -g)" ;;
+ esac
+ notify-send "💾Drive Mounted." "$chosen mounted to $mp."
+ ;;
+
+ 🔒*)
+ chosen="${chosen%% *}"
+ chosen="${chosen:1}" # This is a bashism.
+ # Number the drive.
+ while true; do
+ [ -f "/dev/mapper/usb$num" ] || break
+ num="$(printf "%02d" "$((num +1))")"
+ done
+
+ # Decrypt in a terminal window
+ ${TERMINAL:-st} -a termfloat -e doas cryptsetup open "$chosen" "usb$num"
+ # Check if now decrypted.
+ test -b "/dev/mapper/usb$num"
+
+ attemptmount || getmount
+ doas mount "/dev/mapper/usb$num" "$mp"
+ notify-send "🔓Decrypted drive Mounted." "$chosen decrypted and mounted to $mp."
+ ;;
+
+ 📱*)
+ notify-send "❗Note" "Remember to allow file access on your phone now."
+ getmount
+ number="${chosen%%:*}"
+ number="${chosen:1}" # This is a bashism.
+ doas_askpass simple-mtpfs -o allow_other -o fsname="simple-mtpfs-$(escape "$chosen")" --device "$number" "$mp"
+ notify-send "🤖 Android Mounted." "Android device mounted to $mp."
+ ;;
+esac
diff --git a/.local/bin/noisereduce b/.local/bin/noisereduce
@@ -0,0 +1,81 @@
+#!/usr/bin/sh
+
+usage ()
+{
+ printf "Usage : noisereduce <input video file> <output video file>\n"
+ exit
+}
+
+# Tests for requirements
+ifinstalled ffmpeg || { echo >&2 "We require 'ffmpeg' but it's not installed."; exit 1; }
+ifinstalled sox || { echo >&2 "We require 'ffmpeg' but it's not installed."; exit 1; }
+
+if [ "$#" -ne 2 ]
+then
+ usage
+fi
+
+if [ ! -e "$1" ]
+then
+ printf "File not found: %s\n" "$1"
+ exit
+fi
+
+if [ -e "$2" ]
+then
+ printf "File %s already exists, overwrite? [y/N]\n: " "$2"
+ read -r yn
+ case $yn in
+ [Yy]* ) ;;
+ * ) exit;;
+ esac
+fi
+
+inBasename=$(basename "$1")
+inExt="${inBasename##*.}"
+
+isVideoStr=$(ffprobe -v warning -show_streams "$1" | rg codec_type=video)
+if [ -n "$isVideoStr" ]
+then
+ isVideo=1
+ printf "Detected %s as a video file\n" "$inBasename"
+else
+ isVideo=0
+ printf "Detected %s as an audio file\n" "$inBasename"
+fi
+
+printf "Sample noise start time [00:00:00]: "
+read -r sampleStart
+if [ -z "$sampleStart" ] ; then sampleStart="00:00:00"; fi
+printf "Sample noise end time [00:00:00.900]: "
+read -r sampleEnd
+if [ -z "$sampleEnd" ] ; then sampleEnd="00:00:00.900"; fi
+printf "Noise reduction amount [0.21]: "
+read -r sensitivity
+if [ -z "$sensitivity" ] ; then sensitivity="0.21"; fi
+
+
+tmpVidFile="/tmp/noiseclean_tmpvid.$inExt"
+tmpAudFile="/tmp/noiseclean_tmpaud.wav"
+noiseAudFile="/tmp/noiseclean_noiseaud.wav"
+noiseProfFile="/tmp/noiseclean_noise.prof"
+tmpAudCleanFile="/tmp/noiseclean_tmpaud-clean.wav"
+
+printf "Cleaning noise on %s...\n" "$1"
+
+if [ $isVideo -eq "1" ]; then
+ ffmpeg -v warning -y -i "$1" -qscale:v 0 -vcodec copy -an "$tmpVidFile"
+ ffmpeg -v warning -y -i "$1" -qscale:a 0 "$tmpAudFile"
+else
+ cp "$1" "$tmpAudFile"
+fi
+ffmpeg -v warning -y -i "$1" -vn -ss "$sampleStart" -t "$sampleEnd" "$noiseAudFile"
+sox "$noiseAudFile" -n noiseprof "$noiseProfFile"
+sox "$tmpAudFile" "$tmpAudCleanFile" noisered "$noiseProfFile" "$sensitivity"
+if [ $isVideo -eq "1" ]; then
+ ffmpeg -v warning -y -i "$tmpAudCleanFile" -i "$tmpVidFile" -vcodec copy -qscale:v 0 -qscale:a 0 "$2"
+else
+ cp "$tmpAudCleanFile" "$2"
+fi
+
+printf "Done"
diff --git a/.local/bin/opout b/.local/bin/opout
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# opout: "open output": A general handler for opening a file's intended output,
+# usually the pdf of a compiled document. I find this useful especially
+# running from vim.
+
+basename="${1%.*}"
+
+case "${*}" in
+ *.tex|*.sil|*.m[dse]|*.[rR]md|*.mom|*.[0-9]) target="$(getcomproot "$1" || echo "$1")" ; setsid -f xdg-open "${target%.*}".pdf >/dev/null 2>&1 ;;
+ *.html) setsid -f "$BROWSER" "$basename".html >/dev/null 2>&1 ;;
+ *.sent) setsid -f sent "$1" >/dev/null 2>&1 ;;
+esac
diff --git a/.local/bin/pauseallmpv b/.local/bin/pauseallmpv
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# You might notice all mpv commands are aliased to have this input-ipc-server
+# thing. That's just for this particular command, which allows us to pause
+# every single one of them with one command! This is bound to super + shift + p
+# (with other things) by default and is used in some other places.
+
+for i in $(ls /tmp/mpvSockets/*); do
+ echo '{ "command": ["set_property", "pause", true] }' | socat - "$i";
+done
diff --git a/.local/bin/peertubetorrent b/.local/bin/peertubetorrent
@@ -0,0 +1,9 @@
+#!/bin/sh
+# torrent peertube videos, requires the transadd script
+# first argument is the video link, second is the quality (360, 480 or 1080)
+# 13/07/20 - Arthur Bais
+
+instance=$(echo "$1" | sed "s|/w.\+||")
+vidid=$(echo "$1" | sed "s|.\+/||")
+link=$(curl -s "$instance/api/v1/videos/$vidid" | rg -o "$instance/download/torrents/.\{37\}$2.torrent")
+transadd "$link"
diff --git a/.local/bin/podentr b/.local/bin/podentr
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# entr command to run `queueandnotify` when newsboat queue is changed
+
+[ "$(pgrep -x "$(basename "$0")" | wc -l)" -gt 2 ] && exit
+
+echo "${XDG_DATA_HOME:-$HOME/.local/share}"/newsboat/queue | entr -p queueandnotify 2>/dev/null
diff --git a/.local/bin/portal b/.local/bin/portal
@@ -0,0 +1,7 @@
+#!/bin/sh
+sleep 1
+killall xdg-desktop-portal-wlr
+killall xdg-desktop-portal
+killall xdg-desktop-portal-termfilechooser
+/usr/lib/xdg-desktop-portal-wlr &
+/usr/lib/xdg-desktop-portal-termfilechooser -r &
diff --git a/.local/bin/qndl b/.local/bin/qndl
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# $1 is a url; $2 is a command
+[ -z "$1" ] && exit
+base="$(basename "$1")"
+notify-send "⏳ Queuing $base..."
+cmd="$2"
+[ -z "$cmd" ] && cmd="yt-dlp --embed-metadata -ic"
+idnum="$(tsp $cmd "$1")"
+realname="$(echo "$base" | sed "s/?\(source\|dest\).*//;s/%20/ /g")"
+tsp -D "$idnum" mv "$base" "$realname"
+tsp -D "$idnum" notify-send "👍 $realname done."
diff --git a/.local/bin/queueandnotify b/.local/bin/queueandnotify
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Podboat sucks. This script replaces it.
+# It reads the newsboat queue, queuing downloads with taskspooler.
+# It also removes the junk from extensions.
+queuefile="${XDG_DATA_HOME:-$HOME/.local/share}/newsboat/queue"
+
+while read -r line; do
+ [ -z "$line" ] && continue
+ url="${line%%[ ]*}"
+ qndl "$url" "curl -LO"
+done < "$queuefile"
+
+echo > "$queuefile"
diff --git a/.local/bin/randombg b/.local/bin/randombg
@@ -0,0 +1,35 @@
+#!/bin/sh
+killall swaybg
+PIDFILE="/tmp/randombg.pid"
+# Check if the PID file exists and if the process is running
+if [ -e "$PIDFILE" ] && kill -0 "$(bat "$PIDFILE")"; then
+ echo "Another instance of the script is already running."
+ kill -9 "$(bat $PIDFILE)" # Forcefully kill the old process
+fi
+echo $$ > "$PIDFILE"
+
+cleanup() {
+ [ -n "$OLD_PID" ] && kill "$OLD_PID" 2>/dev/null
+ rm -f "$PIDFILE"
+ exit 0
+}
+trap cleanup INT TERM EXIT
+
+sleep_interruptible() {
+ t=$1
+ while [ "$t" -gt 0 ]; do
+ sleep 1 || return
+ t=$((t-1))
+ done
+}
+
+swaybg -i "$(fd . /mnt/ssd/papes -t f | shuf -n1)" -m fill &
+OLD_PID=$!
+while true; do
+ sleep_interruptible 300
+ swaybg -i "$(fd . /mnt/ssd/papes -t f | shuf -n1)" -m fill &
+ NEXT_PID=$!
+ sleep_interruptible 5
+ kill $OLD_PID
+ OLD_PID=$NEXT_PID
+done
diff --git a/.local/bin/rssadd b/.local/bin/rssadd
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if echo "$1" | rg -q "https*://\S\+\.[A-Za-z]\+\S*" ; then
+ url="$1"
+else
+ url="$(rg -Eom1 '<[^>]+(rel="self"|application/[a-z]+\+xml)[^>]+>' "$1" |
+ rg -o "https?://[^\" ]")"
+
+ echo "$url" | rg -q "https*://\S\+\.[A-Za-z]\+\S*" ||
+ notify-send "That doesn't look like a full URL." && exit 1
+fi
+
+RSSFILE="${XDG_CONFIG_HOME:-$HOME/.config}/newsboat/urls"
+if awk '{print $1}' "$RSSFILE" | rg "^$url$" >/dev/null; then
+ notify-send "You already have this RSS feed."
+else
+ echo "$url" >> "$RSSFILE" && notify-send "RSS feed added."
+fi
diff --git a/.local/bin/rssget b/.local/bin/rssget
@@ -0,0 +1,115 @@
+#!/bin/bash
+
+# Searches the website for RSS feeds and adds them to newsboat url list. Can
+# also find hidden RSS feeds on various websites, namely Youtube, Reddit,
+# Vimeo, Github, Gitlab and Medium. Gets site url as $1 or (if not present)
+# from X clipboard. Gets tags as $2. If it finds more than one feed, calls
+# mew for the user to choose which one to add. I have bound it to a keyboard
+# shortcut so i copy a site link and easily add its feed to the reader.
+
+# Inspired by and based on the logic of this extension:
+# https://github.com/shevabam/get-rss-feed-url-extension
+
+# This script requires rssadd to add feeds to the list.
+
+getlink () {
+ local url="$1"
+ feeds="$(curl -s "$url" | rg -x '.*type=.*(rss|rdf|atom).*' | sed 's/ //g')"
+ url="$(echo $url | sed 's|^\(https://[^/]*/\).*|\1|')"
+
+ for rsspath in $feeds; do
+ rsspath="$(echo $rsspath | sed -n "s|.*href=['\"]\([^'\"]*\)['\"].*|\1|p")"
+ if echo "$rsspath" | rg "http" > /dev/null; then
+ link="$rsspath"
+ elif echo "$rsspath" | rg "^/" > /dev/null; then
+ link="$url$(echo $rsspath | sed 's|^/||')"
+ else
+ link="$url$rsspath"
+ fi
+ echo $link
+ done
+}
+
+getRedditRss() {
+ echo "${1%/}.rss"
+}
+
+getYoutubeRss() {
+ local url="$1"
+ path=$(echo "$url" | sed -e 's|^http[s]*://||')
+ case "$path" in
+ *"/channel/"*) channel_id="$(echo $path | sed -r 's|.*channel/([^/]*).*|\1|')" && feed="https://www.youtube.com/feeds/videos.xml?channel_id=${channel_id}" ;;
+ *"/c/"*|*"/user/"*)
+ feed=$(wget -q "$url" -O tmp_rssget_yt \
+ && sed -n 's|.*\("rssUrl":"[^"]*\).*|\1|; p' tmp_rssget_yt \
+ | rg rssUrl \
+ | sed 's|"rssUrl":"||') ;;
+ esac
+ echo "$feed"
+}
+
+getVimeoRss() {
+ local url="$1"
+ if echo "$url" | rg -q "/videos$"; then
+ feed_url=$(echo "$url" | sed 's/\/videos$//' | sed 's/\/$/\/rss/')
+ else
+ feed_url="${url}/videos/rss"
+ fi
+ echo "$feed_url"
+}
+
+getGithubRss () {
+ local url="${1%/}"
+ if echo $url | rg "github.com/[^/]*/[a-zA-Z0-9].*" >/dev/null ; then
+ echo "${url}/commits.atom"
+ echo "${url}/releases.atom"
+ echo "${url}/tags.atom"
+ elif echo $url | rg "github.com/[^/]*(/)" >/dev/null ; then
+ echo "${url}.atom"
+ fi
+}
+
+getGitlabRss () {
+ local url="${1%/}"
+ echo "${url}.atom"
+}
+
+getMediumRss () {
+ echo $1 | sed 's|/tag/|/feed/|'
+}
+
+
+if [ -n "$1" ] ; then
+ url="$1"
+else
+ url="$(wl-paste)"
+ [ -z "$url" ] && echo "usage: $0 url 'tag1 tag2 tag3'" && exit 1
+fi
+
+declare -a list=()
+
+yt_regex="^(http(s)?://)?((w){3}\.)?(youtube\.com|invidio\.us|invidious\.flokinet\.to|invidious\.materialio\.us|iv\.datura\.network|invidious\.perennialte\.ch|invidious\.fdn\.fr|invidious\.private\.coffee|invidious\.protokolla\.fi|invidious\.privacyredirect\.com|yt\.artemislena\.eu|yt\.drgnz\.club|invidious\.incogniweb\.net|yewtu\.be|inv\.tux\.pizza|invidious\.reallyaweso\.me|iv\.melmac\.space|inv\.us\.projectsegfau\.lt|inv\.nadeko\.net|invidious\.darkness\.services|invidious\.jing\.rocks|invidious\.privacydev\.net|inv\.in\.projectsegfau\.lt|invidious\.drgns\.space)/(channel|user|c).+"
+reddit_regex="^(http(s)?://)?((w){3}\.)?reddit\.com.*"
+vimeo_regex="^(http(s)?://)?((w){3}.)?vimeo\.com.*"
+if echo $url | rg -x "$yt_regex" >/dev/null ; then
+ list="$(getYoutubeRss "$url")"
+elif echo $url | rg -x "$reddit_regex" >/dev/null ; then
+ list="$(getRedditRss "$url")"
+# vimeo actually works with getlink
+elif echo $url | rg "$vimeo_regex" >/dev/null ; then
+ list="$(getVimeoRss "$url")"
+elif echo $url | rg "github.com" >/dev/null ; then
+ list="$(getGithubRss "$url")"
+# gitlab also works with getlink
+elif echo $url | rg "gitlab.com/[a-zA-Z0-9].*" >/dev/null ; then
+ list="$(getGitlabRss "$url")"
+elif echo $url | rg "medium.com/tag" >/dev/null ; then
+ list="$(getMediumRss "$url")"
+else
+ list="$(getlink "$url")"
+fi
+
+[ "$(echo "$list" | wc -l)" -eq 1 ] && chosen_link="$list" || chosen_link=$(printf '%s\n' "${list[@]}" | mew -p "Choose a feed:")
+tags="$2"
+ifinstalled rssadd && rssadd "$chosen_link" "$tags"
+echo "$chosen_link" "$tags"
diff --git a/.local/bin/sd b/.local/bin/sd
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Open a terminal window in the same directory as the currently active window.
+
+windowPID=$(swaymsg --raw -t get_tree | jq -r '.. | select(type == "object" and .focused == true) | .pid')
+PIDlist=$(pstree -lpATna "$windowPID" | sed -En 's/.*,([0-9]+).*/\1/p' | tac)
+for PID in $PIDlist; do
+ cmdline=$(ps -o args= -p "$PID")
+ process_group_leader=$(ps -o comm= -p "$(ps -o pgid= -p "$PID" | tr -d ' ')")
+ cwd=$(readlink /proc/"$PID"/cwd)
+ # zsh and yazi won't be ignored even if it shows ~ or /
+ case "$cmdline" in
+ 'Yazi') continue ;;
+ "${SHELL##*/}"|'yazi'|'yazi '*) break ;;
+ esac
+ # git (and its sub-processes) will show the root of a repository instead of the actual cwd, so they're ignored
+ [ "$process_group_leader" = 'git' ] || [ ! -d "$cwd" ] && continue
+ # This is to ignore programs that show ~ or / instead of the actual working directory
+ [ "$cwd" != "$HOME" ] && [ "$cwd" != '/' ] && break
+done
+[ "$PWD" != "$cwd" ] && [ -d "$cwd" ] && { cd "$cwd" || exit 1; }
+"$TERMINAL"
diff --git a/.local/bin/setbg b/.local/bin/setbg
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# This script does the following:
+# Run by itself, set the wallpaper (at X start).
+# If given a file, set that as the new wallpaper.
+# If given a directory, choose random file in it.
+# If wal is installed, also generates a colorscheme.
+
+# Location of link to wallpaper link.
+bgloc="${XDG_DATA_HOME:-$HOME/.local/share}/bg"
+
+# Configuration files of applications that have their themes changed by pywal.
+dunstconf="${XDG_CONFIG_HOME:-$HOME/.config}/dunst/dunstrc"
+zathuraconf="${XDG_CONFIG_HOME:-$HOME/.config}/zathura/zathurarc"
+
+# Give -s as parameter to make notifications silent.
+while getopts "s" o; do case "${o}" in
+ s) silent='1' ;;
+esac done
+
+shift $((OPTIND - 1))
+
+trueloc="$(readlink -f "$1")" &&
+case "$(file --mime-type -b "$trueloc")" in
+ image/* ) ln -sf "$trueloc" "$bgloc" && [ -z "$silent" ] && notify-send -i "$bgloc" "Changing wallpaper..." ;;
+ inode/directory ) ln -sf "$(find "$trueloc" -iregex '.*.\(jpg\|jpeg\|png\|gif\)' -type f | shuf -n 1)" "$bgloc" && [ -z "$silent" ] && notify-send -i "$bgloc" "Random Wallpaper chosen." ;;
+ *) [ -z "$silent" ] && notify-send "🖼️ Error" "Not a valid image or directory." ; exit 1;;
+esac
+
+# If pywal is installed, use it.
+if command -v wal >/dev/null 2>&1 ; then
+ wal -n -i "$(readlink -f $bgloc)" -o "${XDG_CONFIG_HOME:-$HOME/.config}/wal/postrun" >/dev/null 2>&1
+# If pywal is removed, return config files to normal.
+else
+ [ -f "$dunstconf.bak" ] && unlink "$dunstconf" && mv "$dunstconf.bak" "$dunstconf"
+ [ -f "$zathuraconf.bak" ] && unlink "$zathuraconf" && mv "$zathuraconf.bak" "$zathuraconf"
+fi
+
+killall swaybg
+swaybg -i "$bgloc" -m fill &
+# If running, dwm hit the key to refresh the color scheme.
+# pidof dwm >/dev/null && xdotool key super+F5
diff --git a/.local/bin/shortcuts b/.local/bin/shortcuts
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+bmdirs="${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-dirs"
+bmfiles="${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-files"
+
+# Output locations. Unactivated progs should go to /dev/null.
+shell_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutrc"
+shell_env_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutenvrc"
+zsh_named_dirs="${XDG_CONFIG_HOME:-$HOME/.config}/shell/zshnameddirrc"
+lf_shortcuts="/dev/null"
+vim_shortcuts="/dev/null"
+qute_shortcuts="/dev/null"
+fish_shortcuts="/dev/null"
+vifm_shortcuts="/dev/null"
+yazi_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/yazi/keymap.toml"
+
+# Remove, prepare files
+rm -f "$lf_shortcuts" "$qute_shortcuts" "$zsh_named_dirs" "$vim_shortcuts" "$yazi_shortcuts" 2>/dev/null
+printf "# vim: filetype=sh\\n" > "$fish_shortcuts"
+printf "# vim: filetype=sh\\nalias " > "$shell_shortcuts"
+printf "# vim: filetype=sh\\n" > "$shell_env_shortcuts"
+printf "\" vim: filetype=vim\\n" > "$vifm_shortcuts"
+
+# Format the `directories` file in the correct syntax and sent it to all three configs.
+eval "echo \"$(bat "$bmdirs")\"" | \
+awk "!/^\s*#/ && !/^\s*\$/ {gsub(\"\\\s*#.*$\",\"\");
+ printf(\"%s=\42cd %s && ls -A\42 \\\\\n\",\$1,\$2) >> \"$shell_shortcuts\" ;
+ printf(\"[ -n \42%s\42 ] && export %s=\42%s\42 \n\",\$1,\$1,\$2) >> \"$shell_env_shortcuts\" ;
+ printf(\"hash -d %s=%s \n\",\$1,\$2) >> \"$zsh_named_dirs\" ;
+ printf(\"abbr %s \42cd %s; and ls -A\42\n\",\$1,\$2) >> \"$fish_shortcuts\" ;
+ printf(\"map g%s :cd %s<CR>\nmap t%s <tab>:cd %s<CR><tab>\nmap M%s <tab>:cd %s<CR><tab>:mo<CR>\nmap Y%s <tab>:cd %s<CR><tab>:co<CR> \n\",\$1,\$2, \$1, \$2, \$1, \$2, \$1, \$2) >> \"$vifm_shortcuts\" ;
+ printf(\"config.bind(';%s', \42set downloads.location.directory %s ;; hint links download\42) \n\",\$1,\$2) >> \"$qute_shortcuts\" ;
+ printf(\"map C%s cd \42%s\42 \n\",\$1,\$2) >> \"$lf_shortcuts\" ;
+ printf(\"cmap ;%s %s\n\",\$1,\$2) >> \"$vim_shortcuts\" ;
+ split(\$1, a, \"\")
+ chars = \"\"
+ for (i = 1; i <= length(a); i++) {
+ chars = chars sprintf(\"\\\"%s\\\"\", a[i])
+ if (i < length(a)) chars = chars \", \"
+ }
+ printf(\"[[mgr.prepend_keymap]]\\non = [\\\"g\\\", %s]\\nrun = \\\"cd %s\\\"\\n\\n\", chars, \$2) >> \"$yazi_shortcuts\" }"
+
+# Format the `files` file in the correct syntax and sent it to both configs.
+eval "echo \"$(bat "$bmfiles")\"" | \
+awk "!/^\s*#/ && !/^\s*\$/ {gsub(\"\\\s*#.*$\",\"\");
+ printf(\"%s=\42\$EDITOR %s\42 \\\\\n\",\$1,\$2) >> \"$shell_shortcuts\" ;
+ printf(\"[ -n \42%s\42 ] && export %s=\42%s\42 \n\",\$1,\$1,\$2) >> \"$shell_env_shortcuts\" ;
+ printf(\"hash -d %s=%s \n\",\$1,\$2) >> \"$zsh_named_dirs\" ;
+ printf(\"abbr %s \42\$EDITOR %s\42 \n\",\$1,\$2) >> \"$fish_shortcuts\" ;
+ printf(\"map %s :e %s<CR> \n\",\$1,\$2) >> \"$vifm_shortcuts\" ;
+ printf(\"map E%s \$\$EDITOR \42%s\42 \n\",\$1,\$2) >> \"$lf_shortcuts\" ;
+ printf(\"cmap ;%s %s\n\",\$1,\$2) >> \"$vim_shortcuts\" ;
+ split(\$1, a, \"\")
+ chars = \"\"
+ for (i = 1; i <= length(a); i++) {
+ chars = chars sprintf(\"\\\"%s\\\"\", a[i])
+ if (i < length(a)) chars = chars \", \"
+ }
+ printf(\"[[mgr.prepend_keymap]]\\non = [\\\"e\\\", %s]\\nrun = 'shell --block \\\"\$EDITOR %s\\\"'\\n\\n\", chars, \$2) >> \"$yazi_shortcuts\" }"
diff --git a/.local/bin/singboxwrap b/.local/bin/singboxwrap
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+config_dir="/mnt/ssd/settings/sing-box"
+default_path="${XDG_DATA_HOME:-$HOME/.local/share}/singboxcfg"
+
+input=$1
+
+run_singbox () {
+ [ -z "${1}" ] && exit
+ sing-box check -c "$1" && {
+ pidof sing-box >/dev/null && killall sing-box
+ setsid -f sing-box -c "$1" run
+ if [ "$input" = menu ]; then
+ notify-send "sing-box with $(readlink "$1") is running now"
+ fi
+ } || notify-send "Config check has failed. Check your configuration at $(readlink $1)" & exit 1
+}
+
+choose_menu () {
+ choose="$(fd . $config_dir -d 1 -t f | mew -p "Config to use")"
+ [ -z "${choose}" ] && exit
+ ln -sf "$choose" "$default_path"
+ echo "$default_path"
+}
+
+if [ ! -f "$default_path" ]; then
+ input="menu"
+fi
+
+case $input in
+ menu) run_singbox $(choose_menu) ;;
+ *) run_singbox $default_path ;;
+esac
diff --git a/.local/bin/slider b/.local/bin/slider
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+# Give a file with images and timecodes and creates a video slideshow of them.
+#
+# Timecodes must be in format 00:00:00.
+#
+# Imagemagick and ffmpeg required.
+
+# Application cache if not stated elsewhere.
+cache="${XDG_CACHE_HOME:-$HOME/.cache}/slider"
+
+while getopts "hvrpi:c:a:o:d:f:t:e:x:s:" o; do case "${o}" in
+ c) bgc="$OPTARG" ;;
+ t) fgc="$OPTARG" ;;
+ f) font="$OPTARG" ;;
+ i) file="$OPTARG" ;;
+ a) audio="$OPTARG" ;;
+ o) outfile="$OPTARG" ;;
+ d) prepdir="$OPTARG" ;;
+ r) redo="$OPTARG" ;;
+ s) ppt="$OPTARG" ;;
+ e) endtime="$OPTARG" ;;
+ x) res="$OPTARG"
+ echo "$res" | rg -qv "^[0-9]\+x[0-9]\+$" &&
+ echo "Resolution must be dimensions separated by a 'x': 1280x720, etc." &&
+ exit 1 ;;
+ p) echo "Purge old build files in $cache? [y/N]"
+ read -r confirm
+ echo "$confirm" | rg -iq "^y$" && rm -rf "$cache" && echo "Done."
+ exit ;;
+ v) verbose=True ;;
+ *) echo "$(basename "$0") usage:
+ -i input timecode list (required)
+ -a audio file
+ -c color of background (use html names, black is default)
+ -t text color for text slides (white is default)
+ -s text font size for text slides (150 is default)
+ -f text font for text slides (sans serif is default)
+ -o output video file
+ -e if no audio given, the time in seconds that the last slide will be shown (5 is default)
+ -x resolution (1920x1080 is default)
+ -d tmp directory
+ -r rerun imagemagick commands even if done previously (in case files or background has changed)
+ -p purge old build files instead of running
+ -v be verbose" && exit 1
+
+esac done
+
+# Check that the input file looks like it should.
+{ head -n 1 "$file" 2>/dev/null | rg -q "^00:00:00 " ;} || {
+ echo "Give an input file with -i." &&
+ echo "The file should look as this example:
+
+00:00:00 first_image.jpg
+00:00:03 otherdirectory/next_image.jpg
+00:00:09 this_image_starts_at_9_seconds.jpg
+etc...
+
+Timecodes and filenames must be separated by Tabs." &&
+ exit 1
+ }
+
+if [ -n "${audio+x}" ]; then
+ # Check that the audio file looks like an actual audio file.
+ case "$(file --dereference --brief --mime-type -- "$audio")" in
+ audio/*) ;;
+ *) echo "That doesn't look like an audio file."; exit 1 ;;
+ esac
+ totseconds="$(date '+%s' -d $(ffmpeg -i "$audio" 2>&1 | awk '/Duration/ {print $2}' | sed s/,//))"
+fi
+
+prepdir="${prepdir:-$cache/$file}"
+outfile="${outfile:-$file.mp4}"
+prepfile="$prepdir/$file.prep"
+
+[ -n "${verbose+x}" ] && echo "Preparing images... May take a while depending on the number of files."
+mkdir -p "$prepdir"
+
+{
+while read -r x;
+do
+ # Get the time from the first column.
+ time="${x%% *}"
+ seconds="$(date '+%s' -d "$time")"
+ # Duration is not used on the first looped item.
+ duration="$((seconds - prevseconds))"
+
+ # Get the filename/text content from the rest.
+ content="${x#* }"
+ base="$(basename "$content")"
+ base="${base%.*}.jpg"
+
+ if [ -f "$content" ]; then
+ # If images have already been made in a previous run, do not recreate
+ # them unless -r was given.
+ { [ ! -f "$prepdir/$base" ] || [ -n "${redo+x}" ] ;} &&
+ magick -size "${res:-1920x1080}" canvas:"${bgc:-black}" -gravity center "$content" -resize 1920x1080 -composite "$prepdir/$base"
+ else
+ { [ ! -f "$prepdir/$base" ] || [ -n "${redo+x}" ] ;} &&
+ magick -size "${res:-1920x1080}" -background "${bgc:-black}" -fill "${fgc:-white}" -font "${font:-Sans}" -pointsize "${ppt:-150}" -gravity center label:"$content" "$prepdir/$base"
+ fi
+
+ # If the first line, do not write yet.
+ [ "$time" = "00:00:00" ] || echo "file '$prevbase'
+duration $duration"
+
+ # Keep the information required for the next file.
+ prevbase="$base"
+ prevtime="$time"
+ prevseconds="$(date '+%s' -d "$prevtime")"
+done < "$file"
+# Do last file which must be given twice as follows
+endtime="$((totseconds-seconds))"
+echo "file '$base'
+duration ${endtime:-5}
+file '$base'"
+} > "$prepfile"
+if [ -n "${audio+x}" ]; then
+ ffmpeg -hide_banner -y -f concat -safe 0 -i "$prepfile" -i "$audio" -c:a aac -vsync vfr -c:v libx264 -pix_fmt yuv420p "$outfile"
+else
+ ffmpeg -hide_banner -y -f concat -safe 0 -i "$prepfile" -vsync vfr -c:v libx264 -pix_fmt yuv420p "$outfile"
+fi
+
+# Might also try:
+# -vf "fps=${fps:-24},format=yuv420p" "$outfile"
+# but has given some problems.
diff --git a/.local/bin/spec b/.local/bin/spec
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+me=$(basename "$0")
+
+if [ -z "$1" ] ; then
+ exit 1;
+fi
+
+TEMP=$(mktemp -u -t "${me}" 2>/dev/null || mktemp -u -t "${me}"-XXXXXXXXXX)
+TEMPIMG="${TEMP}.png"
+TEMPTXT="${TEMP}.txt"
+
+basename "$1" > "${TEMPTXT}"
+
+ffmpeg -v quiet -y -i "$1" -filter_complex showspectrumpic=s=2560x1024,drawtext="expansion=none:textfile='${TEMPTXT}':x=(w-tw)/2:y=16:fontcolor='white':fontsize=20" "$TEMPIMG"
+exitcode=$?
+if [ $exitcode -ne 0 ] ; then
+ rm "$TEMPTXT"
+ exit $exitcode
+fi
+
+dummy=$(xdg-open "$TEMPIMG")
+rm "$TEMPIMG" "$TEMPTXT"
diff --git a/.local/bin/start-pipewire b/.local/bin/start-pipewire
@@ -0,0 +1,5 @@
+#!/bin/sh
+killall pipewire
+killall pipewire-pulse
+killall wireplumber
+setsid -f pipewire
diff --git a/.local/bin/statusbar/sb-microphone b/.local/bin/statusbar/sb-microphone
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+ 1) setsid -w -f "$TERMINAL" -e pulsemixer; pkill -RTMIN+23 "${STATUSBAR:-i3blocks}" ;;
+ 2) wpctl set-mute @DEFAULT_SOURCE@ toggle ;;
+ 4) wpctl set-volume @DEFAULT_SOURCE@ 1%+ ;;
+ 5) wpctl set-volume @DEFAULT_SOURCE@ 1%- ;;
+ 8) setsid -f "$TERMINAL" -e "$EDITOR" "$0" >/dev/null 2>&1 ;;
+esac
+
+vol="$(wpctl get-volume @DEFAULT_AUDIO_SOURCE@)"
+
+[ "$vol" != "${vol%\[MUTED\]}" ] && echo "<span color='#FF0000'>muted</span>" && exit
+
+vol="${vol#Volume: }"
+
+split() {
+ # For ommiting the . without calling and external program.
+ IFS=$2
+ set -- $1
+ printf '%s' "$@"
+}
+
+vol="$(printf "%.0f" "$(split "$vol" ".")")"
+
+echo "$vol%"
diff --git a/.local/bin/statusbar/sb-news b/.local/bin/statusbar/sb-news
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+ 1) setsid "$TERMINAL" -T newsboat -e newsboat >/dev/null 2>&1 ;;
+ 2) setsid -f newsup >/dev/null && exit ;;
+ 8) setsid -f "$TERMINAL" -e "$EDITOR" "$0" >/dev/null 2>&1 ;;
+esac
+
+cat /tmp/newsupdate 2>/dev/null || echo "$(newsboat -x print-unread | awk '{ if($1>0) print $1}')$(bat "${XDG_CONFIG_HOME:-$HOME/.config}"/newsboat/.update 2>/dev/null)"
diff --git a/.local/bin/statusbar/sb-pacpackages b/.local/bin/statusbar/sb-pacpackages
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+ 1) setsid -f "$TERMINAL" -e sb-popupgrade >/dev/null 2>&1 ;;
+ 2) notify-send "$(/usr/bin/pacman -Qu)" ;;
+ 8) setsid -f "$TERMINAL" -e "$EDITOR" "$0" >/dev/null 2>&1 ;;
+esac
+
+pacman -Qu | rg -Fcv "[ignored]" | sed "s/^//;s/^📦0$//g"
diff --git a/.local/bin/statusbar/sb-popupgrade b/.local/bin/statusbar/sb-popupgrade
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+printf "Beginning upgrade.\\n"
+
+paru
+pkill -RTMIN+8 "${STATUSBAR:-i3blocks}"
+
+printf "\\nUpgrade complete.\\nPress <Enter> to exit window.\\n\\n"
+read -r _
diff --git a/.local/bin/sysact b/.local/bin/sysact
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# A mew wrapper script for system functions.
+export WM="sway"
+case "$(readlink -f /sbin/init)" in
+ *systemd*) ctl='systemctl' ;;
+ *) ctl='loginctl' ;;
+esac
+
+wmpid(){ # This function is needed if there are multiple instances of the window manager.
+ tree="$(pstree -ps $$)"
+ tree="${tree#*$WM(}"
+ echo "${tree%%)*}"
+}
+
+lock(){
+ mpc pause
+ pauseallmpv
+ wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
+ kill -44 $(pidof i3blocks)
+ swaylock
+ wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
+ kill -44 $(pidof i3blocks)
+}
+
+case "$(printf "🔒 lock\n🚪 leave $WM\n♻️ renew $WM\n🐻 hibernate\n🔃 reboot\n🖥 shutdown\n💤 sleep\n📺 display off" | mew -i -p 'Action: ')" in
+ '🔒 lock') lock ;;
+ "🚪 leave $WM") swaymsg exit ;;
+ "♻️ renew $WM") swaymsg reload ;;
+ '🐻 hibernate') $ctl hibernate -i ;;
+ '💤 sleep') $ctl suspend -i ;;
+ '🔃 reboot') $ctl reboot -i ;;
+ '🖥️shutdown') $ctl poweroff -i ;;
+ '📺 display off') xset dpms force off ;;
+ *) exit 1 ;;
+esac
diff --git a/.local/bin/tag b/.local/bin/tag
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+err() { echo "Usage:
+ tag [OPTIONS] file
+Options:
+ -a: artist/author
+ -t: song/chapter title
+ -A: album/book title
+ -n: track/chapter number
+ -N: total number of tracks/chapters
+ -d: year of publication
+ -g: genre
+ -c: comment
+You will be prompted for title, artist, album and track if not given." && exit 1 ;}
+
+while getopts "a:t:A:n:N:d:g:c:" o; do case "${o}" in
+ a) artist="${OPTARG}" ;;
+ t) title="${OPTARG}" ;;
+ A) album="${OPTARG}" ;;
+ n) track="${OPTARG}" ;;
+ N) total="${OPTARG}" ;;
+ d) date="${OPTARG}" ;;
+ g) genre="${OPTARG}" ;;
+ c) comment="${OPTARG}" ;;
+ *) printf "Invalid option: -%s\\n" "$OPTARG" && err ;;
+esac done
+
+shift $((OPTIND - 1))
+
+file="$1"
+
+temp="$(mktemp -p "$(dirname "$file")")"
+trap 'rm -f $temp' HUP INT QUIT TERM PWR EXIT
+
+[ ! -f "$file" ] && echo 'Provide file to tag.' && err
+
+[ -z "$title" ] && echo 'Enter a title.' && read -r title
+[ -z "$artist" ] && echo 'Enter an artist.' && read -r artist
+[ -z "$album" ] && echo 'Enter an album.' && read -r album
+[ -z "$track" ] && echo 'Enter a track number.' && read -r track
+
+cp -f "$file" "$temp" && ffmpeg -i "$temp" -map 0 -y -codec copy \
+ -metadata title="$title" \
+ -metadata album="$album" \
+ -metadata artist="$artist" \
+ -metadata track="${track}${total:+/"$total"}" \
+ ${date:+-metadata date="$date"} \
+ ${genre:+-metadata genre="$genre"} \
+ ${comment:+-metadata comment="$comment"} "$file"
diff --git a/.local/bin/td-toggle b/.local/bin/td-toggle
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# If transmission-daemon is running, will ask to kill, else will ask to start.
+
+if pidof transmission-daemon >/dev/null ;
+then
+ [ "$(printf "No\\nYes" | mew -i -p "Turn off transmission-daemon?")" = "Yes" ] && killall transmission-daemon && notify-send "transmission-daemon disabled."
+else
+ ifinstalled transmission-cli || exit
+ [ "$(printf "No\\nYes" | mew -i -p "Turn on transmission daemon?")" = "Yes" ] && transmission-daemon && notify-send "transmission-daemon enabled."
+fi
+sleep 3 && pkill -RTMIN+7 "${STATUSBAR:-i3blocks}"
diff --git a/.local/bin/torwrap b/.local/bin/torwrap
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+ifinstalled stig transmission-cli || exit 1
+
+! pidof transmission-daemon >/dev/null && transmission-daemon && notify-send "Starting torrent daemon..."
+
+$TERMINAL -e stig; pkill -RTMIN+7 "${STATUSBAR:-i3blocks}"
diff --git a/.local/bin/transadd b/.local/bin/transadd
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# Mimeapp script for adding torrent to transmission-daemon, but will also start the daemon first if not running.
+
+# transmission-daemon sometimes fails to take remote requests in its first moments, hence the sleep.
+
+pidof transmission-daemon >/dev/null || (transmission-daemon && notify-send "Starting transmission daemon..." && sleep 3 && pkill -RTMIN+7 "${STATUSBAR:-i3blocks}")
+
+transmission-remote -a "$@" && notify-send "🔽 Torrent added."
diff --git a/.local/bin/unix b/.local/bin/unix
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+#original artwork by http://www.sanderfocus.nl/#/portfolio/tech-heroes
+#converted to shell by #nixers @ irc.unix.chat
+
+bat << 'eof'
+ [38;5;255m,_ ,_==▄▂[0m
+ [38;5;255m, ▂▃▄▄▅▅[48;5;240m▅[48;5;20m▂[48;5;240m▅¾[0m. [38;5;199m/ [38;5;20m/[0m
+ [38;5;255m[48;5;20m▄[0m[38;5;255m[48;5;199m▆[38;5;16m[48;5;255m<´ [38;5;32m"[38;5;34m»[38;5;255m▓▓[48;5;32m▓[48;5;240m%[0m\ [38;5;199m/ [38;5;20m/ [38;5;45m/ [38;5;118m/[0m
+ [38;5;255m,[38;5;255m[48;5;240m▅[38;5;16m[48;5;255m7" [38;5;160m´[38;5;34m>[38;5;255m[48;5;39m▓▓[38;5;199m[48;5;255m▓[0m[38;5;255m% [38;5;20m/ [38;5;118m/ [38;5;199m> [38;5;118m/ [38;5;199m>[38;5;255m/[38;5;45m%[0m
+ [38;5;255m▐[48;5;240m[38;5;255m¶[48;5;240m[38;5;255m▓[48;5;255m [38;5;196m,[38;5;34m»[48;5;201m[38;5;255m▓▓[0m[38;5;255m¾´[0m [38;5;199m/[38;5;255m> %[38;5;199m/[38;5;118m%[38;5;255m/[38;5;199m/ [38;5;45m/ [38;5;199m/[0m
+ [38;5;255m[48;5;240m▓[48;5;255m[38;5;16m▃[48;5;16m[38;5;255m▅▅[38;5;16m[48;5;255m▅▃,,[38;5;32m▄[38;5;16m▅[38;5;255m[48;5;16m▅▅[38;5;255m[48;5;20mÆ[0m[38;5;255m\[0m[38;5;20m/[38;5;118m/[38;5;255m /[38;5;118m/[38;5;199m/[38;5;255m>[38;5;45m// [38;5;255m/[38;5;118m>[38;5;199m/ [38;5;20m/[0m
+ [48;5;20m[38;5;255mV[48;5;255m[38;5;16m║[48;5;20m[38;5;255m«[0m[38;5;255m¼.;[48;5;240m[38;5;255m→[48;5;255m[38;5;16m ║[0m[38;5;255m<«.,[48;5;25m[38;5;255m`[48;5;240m=[0m[38;5;20m/[38;5;199m/ [38;5;255m/>[38;5;45m/[38;5;118m/[38;5;255m%/[38;5;199m% / [38;5;20m/[0m
+ [38;5;20m//[48;5;255m[38;5;16m╠<´ -²,)[48;5;16m[38;5;255m(▓[48;5;255m[38;5;16m~"-[38;5;199m╝/[0m[38;5;255m¾[0m[38;5;199m/ [38;5;118m%[38;5;255m/[38;5;118m>[38;5;45m/ [38;5;118m/[38;5;199m>[0m
+ [38;5;20m/ / [38;5;118m/ [48;5;20m[38;5;255m▐[48;5;240m[38;5;16m%[48;5;255m -./▄▃▄[48;5;16m[38;5;255m▅[48;5;255m[38;5;16m▐[48;5;255m[38;5;16m, [38;5;199m/[48;5;199m[38;5;255m7[0m[38;5;20m/[38;5;199m/[38;5;255m;/[38;5;199m/[38;5;118m% [38;5;20m/ /[0m
+ [38;5;20m/ [38;5;199m/[38;5;255m/[38;5;45m/[38;5;118m/[38;5;255m[48;5;240m`[48;5;20m[38;5;255m▌[48;5;20m[38;5;255m▐[48;5;255m[38;5;16m %z[0m[38;5;255mWv xX[48;5;20m[38;5;255m▓[48;5;34m[38;5;255m▇[48;5;199m[38;255m▌[0m[38;5;20m/[38;5;199m/[38;5;255m&;[38;5;20m% [38;5;199m/ [38;5;20m/[0m
+ [38;5;20m/ / [38;5;255m/ [38;5;118m%[38;5;199m/[38;5;255m/%/[48;5;240m[38;5;255m¾[48;5;255m[38;5;16m½´[38;5;255m[48;5;16m▌[0m[38;5;246m▃▄[38;5;255m▄▄[38;5;246m▄▃▃[0m[48;5;16m[38;5;255m▐[38;5;255m[48;5;199m¶[48;5;20m[38;5;255m\[0m[38;5;20m/[0m[48;5;255m[38;5;240m&[0m [38;5;20m/[0m
+ [38;5;199m<[38;5;118m/ [38;5;45m/[38;5;255m</[38;5;118m%[38;5;255m/[38;5;45m/[38;5;255m`[48;5;16m▓[48;5;255m[38;5;16m![48;5;240m[38;5;255m%[48;5;16m[38;5;255m▓[0m[38;5;255m%[48;5;240m[38;5;255m╣[48;5;240m[38;5;255;╣[0m[38;5;255mW[0m[38;5;250mY<Y)[48;5;255m[38;5;16my&[0m[38;5;255m/`[48;5;240m\[0m
+ [38;5;20m/ [38;5;199m/ [38;5;199m%[38;5;255m/%[38;5;118m/[38;5;45m/[38;5;255m<[38;5;118m/[38;5;199m%[38;5;45m/[38;5;20m/[48;5;240m[38;5;255m\[38;5;16m[48;5;255mi7; ╠N[0m[38;5;246m>[38;5;255m)VY>[48;5;240m[38;5;255m7[0m[38;5;255m; [38;5;255m[48;5;240m\[0m[38;5;255m_[0m [38;5;255mUNIX IS VERY SIMPLE [38;5;45mIT JUST NEEDS A[0m
+ [38;5;20m/ [38;5;255m/[38;5;118m<[38;5;255m/ [38;5;45m/[38;5;255m/<[38;5;199m/[38;5;20m/[38;5;199m/[38;5;20m<[38;5;255m_/%\[38;5;255m[48;5;16m▓[48;5;255m[38;5;16m V[0m[38;5;255m%[48;5;255m[38;5;16mW[0m[38;5;255m%£)XY[0m [38;5;240m_/%[38;5;255m‾\_,[0m [38;5;45mGENIUS TO UNDERSTAND ITS SIMPLICITY[38;5;255m[0m
+ [38;5;199m/ [38;5;255m/ [38;5;199m/[38;5;255m/[38;5;118m%[38;5;199m/[48;5;240m[38;5;255m_,=-[48;5;20m-^[0m[38;5;255m/%/%%[48;5;255m[38;5;16m\¾%[0m[38;5;255m¶[0m[48;5;255m[38;5;16m%[0m[38;5;255m%}[0m [38;5;240m/%%%[38;5;20m%%[38;5;240m%;\,[0m
+ [38;5;45m%[38;5;20m/[38;5;199m< [38;5;20m/[48;5;20m[38;5;255m_/[48;5;240m [0m[38;5;255m%%%[38;5;240m%%[38;5;20m;[38;5;255mX[38;5;240m%[38;5;20m%[38;5;255m\%[38;5;240m%;, _/%%%;[38;5;20m,[38;5;240m \[0m
+ [38;5;118m/ [38;5;20m/ [38;5;240m%[38;5;20m%%%%[38;5;240m%;, [38;5;255m\[38;5;240m%[38;5;20m%[38;5;255ml[38;5;240m%%;// _/[38;5;20m%;,[0m [38;5;234mdmr[0m
+ [38;5;20m/ [38;5;240m%[38;5;20m%%;,[0m [38;5;255m<[38;5;20m;[38;5;240m\-=-/ /[0m
+ [38;5;20m;,[0m [38;5;240ml[0m
+eof
diff --git a/.local/bin/unmounter b/.local/bin/unmounter
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -e
+
+mounteddroids="$(rg simple-mtpfs /etc/mtab | awk '{print "📱" $2}')"
+lsblkoutput="$(lsblk -nrpo "name,type,size,mountpoint")"
+mounteddrives="$(echo "$lsblkoutput" | awk '($2=="part"||$2="crypt")&&$4!~/\/boot|\/home$|SWAP/&&length($4)>1{printf "💾%s (%s)\n",$4,$3}')"
+
+allunmountable="$(echo "$mounteddroids
+$mounteddrives" | sed "/^$/d;s/ *$//")"
+test -n "$allunmountable"
+
+chosen="$(echo "$allunmountable" | mew -i -p "Unmount which drive?")"
+chosen="${chosen%% *}"
+test -n "$chosen"
+
+doas umount -l "/${chosen#*/}"
+notify-send "Device unmounted." "$chosen has been unmounted."
+
+# Close the chosen drive if decrypted.
+cryptid="$(echo "$lsblkoutput" | rg "/${chosen#*/}$")"
+cryptid="${cryptid%% *}"
+test -b /dev/mapper/"${cryptid##*/}"
+doas_askpass cryptsetup close "$cryptid"
+notify-send "🔒Device decryption closed." "Drive is now securely locked again."
diff --git a/.local/bin/weath b/.local/bin/weath
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Get the weather on the terminal. You can pass an alternative location as a parameter,
+# and/or use the 'cp' option to copy the forecast as plaintext to the clipboard.
+
+report="${XDG_CACHE_HOME:-$HOME/.cache}/weatherreport"
+
+if [ "$1" = 'cp' ]; then
+ # shellcheck disable=SC2015
+ [ -z "$2" ] && sed 's/\x1b\[[^m]*m//g' "$report" | wl-copy &&
+ notify-send "Weather forecast for '${LOCATION:-$(head -n 1 "$report" | cut -d' ' -f3-)}' copied to clipboard." ||
+ { data="$(curl -sfm 5 "${WTTRURL:-wttr.in}/$2?T")" &&
+ notify-send "Weather forecast for '$2' copied to clipboard." &&
+ echo "$data" | wl-copy ||
+ notify-send 'Failed to get weather forecast!' 'Check your internet connection and the supplied location.'; }
+else
+ [ -n "$2" ] &&
+ notify-send "Invalid option '$1'! The only valid option is 'cp'." &&
+ exit 1
+
+ # shellcheck disable=SC2015
+ [ -z "$1" ] && less -S "$report" ||
+ data="$(curl -sfm 5 "${WTTRURL:-wttr.in}/$1")" && echo "$data" | less -S ||
+ notify-send 'Failed to get weather forecast!' 'Check your internet connection and the supplied location.'
+fi
diff --git a/.local/bin/xdg-terminal-exec b/.local/bin/xdg-terminal-exec
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+"$TERMINAL" -e "$@"
diff --git a/.local/share/applications/file.desktop b/.local/share/applications/file.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=File Manager
+Exec=/usr/bin/footclient -e yazi %u
diff --git a/.local/share/applications/img.desktop b/.local/share/applications/img.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=Image viewer
+Exec=/usr/bin/swayimg %f
diff --git a/.local/share/applications/mail.desktop b/.local/share/applications/mail.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=Mail
+Exec=/usr/bin/footclient -e neomutt %u
diff --git a/.local/share/applications/pdf.desktop b/.local/share/applications/pdf.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=PDF reader
+Exec=/usr/bin/zathura %u
diff --git a/.local/share/applications/rss.desktop b/.local/share/applications/rss.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=RSS feed addition
+Exec=/usr/bin/env rssadd %U
diff --git a/.local/share/applications/text.desktop b/.local/share/applications/text.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=Text editor
+Exec=/usr/bin/footclient -e nvim %u
diff --git a/.local/share/applications/torrent.desktop b/.local/share/applications/torrent.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=Torrent
+Exec=/usr/bin/env transadd %U
diff --git a/.local/share/applications/video.desktop b/.local/share/applications/video.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=Application
+Name=Video viewer
+Exec=/usr/bin/mpv -quiet %f
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 2025 awy
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) 2025 awy
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/README.md b/README.md
@@ -0,0 +1,9 @@
+Sway Deployment Script
+======================
+Installs all needed dependencies
+and deploys my dotfiles
+
+## Install
+```sh
+doas ./rice.sh
+```
diff --git a/aurdeps.txt b/aurdeps.txt
@@ -0,0 +1,7 @@
+sing-box
+#sing-geoip-rule-set
+#sing-geosite-rule-set
+gpu-screen-recorder
+doasedit-alternative
+newsraft
+dragon-drop-git
diff --git a/dependencies.txt b/dependencies.txt
@@ -0,0 +1,131 @@
+# COMPRESSION #
+7zip
+unrar
+unzip
+
+# SWAY #
+sway
+swayidle
+swaylock
+fnott
+foot
+xdg-desktop-portal-wlr
+xdg-desktop-portal-termfilechooser
+i3blocks
+mew
+
+# PROGRAMS #
+neovim
+lynx
+wget
+
+# SHELL & YAZI #
+jq
+fzf
+zsh
+zsh-completions
+zsh-autosuggestions
+zathura
+zathura-pdf-mupdf
+wl-clipboard
+yazi
+bat
+chafa
+bc
+eza
+ripgrep
+fd
+git-delta
+
+# BROWSER #
+icecat
+
+# SOUND #
+pipewire
+pipewire-pulse
+wireplumber
+pulsemixer
+
+# FONTS #
+gnu-free-fonts
+ttf-nerd-fonts-symbols
+noto-fonts-emoji
+fontconfig
+
+# MONITORING #
+btop
+
+# MULTIMEDIA #
+ffmpeg
+mediainfo
+mpv
+imagemagick
+swayimg
+mpc
+mpd
+rmpc
+grim
+swappy
+slurp
+swaybg
+
+# DATA HOARDING #
+yt-dlp
+transmission-cli
+
+# UTILS #
+make
+gnupg
+gnome-keyring
+openssh
+fakeroot
+polkit
+fastfetch
+libnotify
+pkgconf
+exfat-utils
+tesseract-data-eng
+tesseract
+mandoc
+calcurse
+cmake
+wlrctl
+tllist
+
+# TESSEN DEPS #
+tessen
+gopass
+which
+wtype
+
+# MUTT-WIZARD DEPS #
+neomutt
+isync
+msmtp
+cronie-dinit
+
+# WAYLAND #
+qt6-wayland
+qt5-wayland
+xorg-xrandr
+xorg-xwayland
+wayland-protocols
+
+# STYLING #
+gnome-themes-extra
+qt5ct
+qt6ct
+
+# DOAS ASKPASS #
+expect
+
+# LANGUAGE SERVERS #
+clang
+rust-analyzer
+vscode-css-languageserver
+vscode-json-languageserver
+vscode-html-languageserver
+yaml-language-server
+bash-language-server
+shellcheck
+lua-language-server
diff --git a/rice.sh b/rice.sh
@@ -0,0 +1,198 @@
+#!/bin/sh
+set -e
+WORKDIRECTORY=$PWD
+
+if [ "$(id -u)" -ne 0 ]
+ then printf "The script has to be run as root.\n"
+ exit
+fi
+
+if [ -x "$(command -v doas)" ]; then
+ PERMUSER=$DOAS_USER
+ evalcommand="doas -u $PERMUSER"
+ cp /etc/doas.conf /etc/doas.bak
+ echo "permit nopass :wheel" > /etc/doas.conf
+ echo "permit nopass root" >> /etc/doas.conf
+else
+ PERMUSER=$SUDO_USER
+ evalcommand="sudo -u $PERMUSER"
+ echo "%wheel ALL=(ALL) NOPASSWD: ALL
+ Defaults:%wheel,root runcwd=*" >/etc/sudoers.d/temp
+fi
+
+run_as_user() {
+ $evalcommand "$@"
+}
+
+usermod -aG seat $PERMUSER
+
+DEPLIST="`sed -e 's/#.*$//' -e '/^$/d' dependencies.txt | tr '\n' ' '`"
+pacman -S $DEPLIST --noconfirm --needed
+
+# run_as_user git submodule update --init --recursive
+
+run_as_user cp -r "$WORKDIRECTORY"/.config /home/"$PERMUSER"
+run_as_user cp -r "$WORKDIRECTORY"/.local /home/"$PERMUSER"
+run_as_user cp -a "$WORKDIRECTORY"/.zprofile /home/"$PERMUSER"
+
+run_as_user mkdir -p /home/"$PERMUSER"/.config/git
+run_as_user touch /home/"$PERMUSER"/.config/git/config
+run_as_user mkdir -p /home/"$PERMUSER"/.config/npm
+run_as_user touch /home/"$PERMUSER"/.config/npm/npmrc
+run_as_user mkdir -p /home/"$PERMUSER"/.config/mpd/playlists
+run_as_user mkdir -p /home/"$PERMUSER"/.local/share/themes
+run_as_user mkdir -p /home/"$PERMUSER"/.local/share/icons
+
+cd "$WORKDIRECTORY" || exit
+run_as_user git clone https://github.com/zdharma-continuum/fast-syntax-highlighting
+mkdir -p /usr/share/zsh/plugins
+cp -rf fast-syntax-highlighting /usr/share/zsh/plugins
+cd "$WORKDIRECTORY"
+
+run_as_user mkdir -p /home/"$PERMUSER"/.ssh
+run_as_user mkdir -p /home/"$PERMUSER"/.gnupg
+run_as_user touch /home/"$PERMUSER"/.gnupg/gpg-agent.conf
+
+cat <<EOL >> /home/$PERMUSER/.gnupg/gpg-agent.conf
+enable-ssh-support
+pinentry-program /usr/bin/pinentry-gnome3
+default-cache-ttl 34560000
+max-cache-ttl 34560000
+EOL
+
+cat <<EOL >> /home/$PERMUSER/.config/npm/npmrc
+prefix=\${XDG_DATA_HOME}/npm
+cache=\${XDG_CACHE_HOME}/npm
+init-module=\${XDG_CONFIG_HOME}/npm/config/npm-init.js
+logs-dir=\${XDG_STATE_HOME}/npm/logs
+EOL
+
+run_as_user find /home/"$PERMUSER"/.gnupg -type f -exec chmod 600 {} \;
+run_as_user find /home/"$PERMUSER"/.gnupg -type d -exec chmod 700 {} \;
+run_as_user find /home/"$PERMUSER"/.ssh -type f -exec chmod 600 {} \;
+run_as_user find /home/"$PERMUSER"/.ssh -type d -exec chmod 700 {} \;
+
+chsh -s /bin/zsh "$PERMUSER"
+
+# Make pacman colorful, concurrent downloads and Pacman eye-candy.
+grep -q "ILoveCandy" /etc/pacman.conf || sed -i "/#VerbosePkgLists/a ILoveCandy" /etc/pacman.conf
+sed -Ei "s/^#(ParallelDownloads).*/\1 = 5/;/^#Color$/s/#//" /etc/pacman.conf
+
+# Disable Pacman sandbox since kernel doesn't support landlock (only for custom kernels from my artix script)
+# sed -Ei "s/^#(DisableSandbox).*/\1/" /etc/pacman.conf
+
+# Use all cores for compilation.
+sed -i "s/-j2/-j$(nproc)/;/^#MAKEFLAGS/s/^#//" /etc/makepkg.conf
+
+if [ -x "$(command -v doas)" ]; then
+ # Use doas for Pacman authentification
+ sed -i 's/#PACMAN_AUTH=.*$/PACMAN_AUTH=(doas)/' /etc/makepkg.conf
+fi
+
+cat <<EOL >> /usr/share/libalpm/hooks/statusbar.hook
+[Trigger]
+Operation = Upgrade
+Type = Package
+Target = *
+
+[Action]
+Description = Updating statusbar...
+When = PostTransaction
+Exec = /usr/bin/pkill -RTMIN+8 i3blocks
+EOL
+
+cat <<EOL >> /etc/pacman.d/hooks/sing-box.hook
+[Trigger]
+Type = Package
+Operation = Install
+Operation = Upgrade
+Target = sing-box
+
+[Action]
+Description = Setting caps for sing-box...
+When = PostTransaction
+Exec = /usr/bin/setcap cap_net_admin=ep /usr/sbin/sing-box
+EOL
+
+run_as_user git clone https://aur.archlinux.org/paru.git
+cd paru
+run_as_user makepkg -csi --noconfirm
+cd "$WORKDIRECTORY"
+DEPLIST="`sed -e 's/#.*$//' -e '/^$/d' aurdeps.txt | tr '\n' ' '`"
+run_as_user paru --sudo doas -S $DEPLIST --noconfirm
+run_as_user dbus-launch gsettings set org.gnome.desktop.interface gtk-theme "Adwaita-dark"
+run_as_user dbus-launch gsettings set org.gnome.desktop.wm.preferences theme "Adwaita-dark"
+run_as_user dbus-launch gsettings set org.gnome.desktop.wm.preferences button-layout 'appmenu'
+run_as_user dbus-launch gsettings set org.gnome.desktop.interface font-name "sans 11"
+cd ..
+rm -rf swaydots
+rm -rf paru
+rm -rf go
+
+dinitctl enable cronie
+echo "*/30 * * * * export DBUS_SESSION_BUS_ADDRESS=\$(rg --null-data \"DBUS_SESSION_BUS_ADDRESS\" \"/proc/\$(pgrep -x swaybar)/environ\" | sed 's/DBUS_SESSION_BUS_ADDRESS=//'); /home/$PERMUSER/.local/bin/cron/newsup
+*/30 * * * * export DBUS_SESSION_BUS_ADDRESS=\$(rg --null-data \"DBUS_SESSION_BUS_ADDRESS\" \"/proc/\$(pgrep -x swaybar)/environ\" | sed 's/DBUS_SESSION_BUS_ADDRESS=//'); /home/$PERMUSER/.local/bin/cron/checkup
+*/5 * * * * export DBUS_SESSION_BUS_ADDRESS=\$(rg --null-data \"DBUS_SESSION_BUS_ADDRESS\" \"/proc/\$(pgrep -x swaybar)/environ\" | sed 's/DBUS_SESSION_BUS_ADDRESS=//'); /home/$PERMUSER/.local/bin/cron/mailup" | run_as_user crontab -
+
+echo "0 */1 * * * ntpdate pool.ntp.org" | crontab -
+
+cd /home/"$PERMUSER"
+run_as_user git clone https://git.awy.one/autofox
+cd autofox
+run_as_user ./configure_icecat.sh
+cd /home/"$PERMUSER"
+rm -rf autofox
+
+run_as_user git clone https://git.awy.one/statusbar
+cd statusbar
+run_as_user make
+cd /home/"$PERMUSER"
+rm -rf statusbar
+
+# MPV
+thumbfastlua_url=https://raw.githubusercontent.com/po5/thumbfast/refs/heads/master/thumbfast.lua
+thumbfastconf_url=https://raw.githubusercontent.com/po5/thumbfast/refs/heads/master/thumbfast.conf
+sponsorblock_url=https://codeberg.org/jouni/mpv_sponsorblock_minimal/raw/branch/master/sponsorblock_minimal.lua
+config_dir="/home/$PERMUSER/.config/mpv"
+scriptopts_dir="$config_dir/script-opts"
+
+run_as_user mkdir -p "$config_dir/scripts"
+run_as_user mkdir -p $scriptopts_dir || echo "Couldn't create: $scriptopts_dir"
+
+# thumbfast
+run_as_user curl -Ls -o "$config_dir/scripts/thumbfast.lua" $thumbfastlua_url || echo "Couldn't download: $thumbfastlua_url"
+run_as_user curl -Ls -o "$scriptopts_dir/thumbfast.conf" $thumbfastconf_url || echo "Couldn't download: $thumbfastconf_url"
+sed -Ei "s/(network).*/\1=yes/" "$scriptopts_dir/thumbfast.conf"
+
+# sponsorblock
+run_as_user curl -Ls -o "$config_dir/scripts/sponsorblock_minimal.lua" $sponsorblock_url || echo "Couldn't download: $sponsorblock_url"
+
+#uosc
+run_as_user wget "https://github.com/tomasklaen/uosc/releases/latest/download/uosc.zip"
+run_as_user unzip uosc.zip -d "$config_dir"
+run_as_user wget "https://github.com/tomasklaen/uosc/releases/latest/download/uosc.conf"
+run_as_user mv uosc.conf "$scriptopts_dir"
+
+# pam
+sed -i '/auth[[:space:]]*include[[:space:]]*system-local-login/a auth optional pam_gnome_keyring.so' /etc/pam.d/login
+sed -i '/session[[:space:]]*include[[:space:]]*system-local-login/a session optional pam_gnome_keyring.so auto_start' /etc/pam.d/login
+echo "password optional pam_gnome_keyring.so" >> /etc/pam.d/passwd
+
+yes | run_as_user paru --sudo doas -Scc
+rm -rf /home/"$PERMUSER"/.cargo
+
+if [ -x "$(command -v doas)" ]; then
+ rm /etc/doas.conf
+ mv /etc/doas.bak /etc/doas.conf
+else
+ rm /etc/sudoers.d/temp
+fi
+
+chown -R $PERMUSER:wheel /home/$PERMUSER
+
+# cleanup
+rm -rf /home/$PERMUSER/.cache/go-build
+rm -f /home/$PERMUSER/.wget-hsts
+rm -f /home/"$PERMUSER"/uosc.zip
+
+echo "Your linux is riced!"