From f6881cea7a37b81b3e1bff27cf7e9af0205a6315 Mon Sep 17 00:00:00 2001
From: Akemi Izuko
Date: Tue, 6 Sep 2022 23:34:19 -0600
Subject: [PATCH] Init again
The dotfiles are back
---
.gitignore | 66 +++
README.md | 329 +++++++++++
aerc/aerc.conf | 331 +++++++++++
aerc/binds.conf | 123 ++++
alacritty/alacritty.yml | 119 ++++
alacritty/colors.yml | 231 ++++++++
bash/.bash_aliases | 135 +++++
bash/.bash_env | 98 ++++
bash/.bash_functions | 162 +++++
bash/.bash_profile | 95 +++
bash/.bash_prompt | 112 ++++
bash/.bashrc | 18 +
bash/.inputrc | 22 +
bash/.profile | 8 +
bin/battery_status.sh | 38 ++
bin/check_domain.sh | 27 +
bin/colo.sh | 88 +++
bin/ix.sh | 42 ++
bin/kat | 366 ++++++++++++
bin/lgrep | 58 ++
bin/listlong | 75 +++
bin/lyrics_to_html.py | 129 ++++
bin/myip | 67 +++
bin/notes | 36 ++
bin/play_error_sound.sh | 9 +
bin/prettify_bash_history.awk | 9 +
bin/random_password.sh | 55 ++
bin/rpluto.sh | 109 ++++
bin/screenshot_wayland.sh | 241 ++++++++
bin/sway_tree.rs | 228 ++++++++
bin/swaytree.sh | 12 +
bin/switch_keyboards.sh | 65 +++
bin/vii.sh | 22 +
chromium/chromium-flags.conf | 7 +
git/.gitconfig | 29 +
git/.gitignore_global | 10 +
gnupg/gpg-agent.conf | 1 +
install.sh | 349 +++++++++++
macos/DefaultKeyBinding.dict | 48 ++
mako/config | 10 +
mpv/input.conf | 207 +++++++
mpv/mpv.conf | 145 +++++
mpv/scripts/subs_to_clipboard.js | 209 +++++++
package_install.sh | 309 ++++++++++
ripgrep/config | 8 +
sketchybar/com.sketchybar.launcher.template | 32 +
sketchybar/plugins/yabai_spaces.js | 110 ++++
sketchybar/sketchybarrc | 155 +++++
skhd/com.skhd.launcher.template | 42 ++
skhd/scripts/record_audio_line | 41 ++
skhd/scripts/shrink_screenshot_clipboard | 27 +
skhd/scripts/shrink_screenshot_desktop | 26 +
skhd/skhdrc | 460 +++++++++++++++
swappy/config | 9 +
sway/brightness_lock.sh | 28 +
sway/config | 442 ++++++++++++++
sway/cycle_windows.py | 50 ++
sway/pulse_audio_volume.sh | 58 ++
sway/swaybar_status.sh | 53 ++
sway/toggle_fcitx.sh | 8 +
sway/toggle_mute.sh | 43 ++
sway/window_dimensions.sh | 28 +
swaylock/config | 24 +
systemd/xremap.service | 9 +
tmux/tmux.conf | 173 ++++++
vifm/colors/Default.vifm | 85 +++
vifm/colors/gruvbox-dark.vifm | 88 +++
vifm/colors/gruvbox-light.vifm | 79 +++
vifm/scripts/vifm_bg_open.sh | 53 ++
vifm/vifmrc | 346 +++++++++++
vim/.vim/UltiSnips/math_preamble.tex | 83 +++
vim/.vim/UltiSnips/tex.snippets | 551 ++++++++++++++++++
.../colors/base16-atelier-estuary-light.vim | 413 +++++++++++++
.../colors/base16-atelier-plateau-light.vim | 413 +++++++++++++
vim/.vim/colors/base16-dracula.vim | 413 +++++++++++++
vim/.vim/colors/base16-github.vim | 413 +++++++++++++
.../colors/base16-gruvbox-dark-medium.vim | 413 +++++++++++++
vim/.vim/colors/base16-gruvbox-dark-pale.vim | 429 ++++++++++++++
vim/.vim/colors/base16-gruvbox-light-hard.vim | 413 +++++++++++++
.../colors/base16-gruvbox-light-medium.vim | 413 +++++++++++++
vim/.vim/colors/base16-material-palenight.vim | 413 +++++++++++++
vim/.vim/colors/base16-monokai.vim | 413 +++++++++++++
vim/.vim/colors/base16-nord.vim | 413 +++++++++++++
vim/.vim/colors/base16-tomorrow.vim | 413 +++++++++++++
vim/.vim/ftdetect/bash.vim | 4 +
vim/.vim/ftdetect/ipython.vim | 1 +
vim/.vim/ftdetect/mips.vim | 3 +
vim/.vim/ftplugin/awk.vim | 5 +
vim/.vim/ftplugin/bash.vim | 10 +
vim/.vim/ftplugin/c.vim | 12 +
vim/.vim/ftplugin/html.vim | 14 +
vim/.vim/ftplugin/javascript.vim | 9 +
vim/.vim/ftplugin/julia.vim | 9 +
vim/.vim/ftplugin/make.vim | 4 +
vim/.vim/ftplugin/man.vim | 3 +
vim/.vim/ftplugin/markdown.vim | 12 +
vim/.vim/ftplugin/python.vim | 51 ++
vim/.vim/ftplugin/rust.vim | 16 +
vim/.vim/ftplugin/snippets.vim | 10 +
vim/.vim/ftplugin/svelte.vim | 4 +
vim/.vim/ftplugin/tex.vim | 15 +
vim/.vim/ftplugin/vifm.vim | 6 +
vim/.vim/init_scripts/external_plugins.vim | 251 ++++++++
vim/.vim/init_scripts/init.vim | 18 +
vim/.vim/init_scripts/key_mappings.vim | 164 ++++++
vim/.vim/init_scripts/settings.vim | 153 +++++
vim/.vim/plugin/auto_session.vim | 76 +++
vim/.vim/plugin/clear_whitespace.vim | 16 +
vim/.vim/plugin/fix_highlights.vim | 5 +
vim/.vim/plugin/open_url.vim | 25 +
vim/.vim/plugin/pretty_section_comment.vim | 52 ++
vim/.vim/plugin/statusbars/statusline.vim | 354 +++++++++++
vim/.vim/plugin/statusbars/tabline.vim | 230 ++++++++
vim/.vim/syntax/mips.vim | 272 +++++++++
vim/.vimrc | 12 +
vim/nvim/init.vim | 23 +
vim/nvim/plugin | 1 +
vimiv/keys.conf | 102 ++++
vimiv/styles/base16-dracula | 31 +
vimiv/styles/base16-github | 37 ++
vimiv/styles/base16-gruvbox-dark-pale | 36 ++
vimiv/styles/base16-gruvbox-light-hard | 31 +
vimiv/vimiv.conf | 65 +++
warpd/com.warpd.launcher.template | 37 ++
warpd/config | 32 +
xremap/config_console.yml | 13 +
xremap/config_mac.yml | 69 +++
xremap/config_standard.yml | 77 +++
yabai/close_space.js | 44 ++
yabai/cycle_stack.js | 49 ++
yabai/move_to_stack.sh | 26 +
yabai/new_space.js | 19 +
yabai/pin_window.js | 149 +++++
yabai/rofi_window.js | 56 ++
yabai/toggle_outline.bash | 13 +
yabai/yabairc | 55 ++
yofi/yofi.config | 92 +++
137 files changed, 15805 insertions(+)
create mode 100644 .gitignore
create mode 100644 README.md
create mode 100644 aerc/aerc.conf
create mode 100644 aerc/binds.conf
create mode 100644 alacritty/alacritty.yml
create mode 100644 alacritty/colors.yml
create mode 100644 bash/.bash_aliases
create mode 100644 bash/.bash_env
create mode 100644 bash/.bash_functions
create mode 100644 bash/.bash_profile
create mode 100755 bash/.bash_prompt
create mode 100644 bash/.bashrc
create mode 100644 bash/.inputrc
create mode 100644 bash/.profile
create mode 100755 bin/battery_status.sh
create mode 100755 bin/check_domain.sh
create mode 100755 bin/colo.sh
create mode 100755 bin/ix.sh
create mode 100755 bin/kat
create mode 100755 bin/lgrep
create mode 100755 bin/listlong
create mode 100755 bin/lyrics_to_html.py
create mode 100755 bin/myip
create mode 100755 bin/notes
create mode 100755 bin/play_error_sound.sh
create mode 100755 bin/prettify_bash_history.awk
create mode 100755 bin/random_password.sh
create mode 100755 bin/rpluto.sh
create mode 100755 bin/screenshot_wayland.sh
create mode 100644 bin/sway_tree.rs
create mode 100755 bin/swaytree.sh
create mode 100755 bin/switch_keyboards.sh
create mode 100755 bin/vii.sh
create mode 100644 chromium/chromium-flags.conf
create mode 100644 git/.gitconfig
create mode 100644 git/.gitignore_global
create mode 100644 gnupg/gpg-agent.conf
create mode 100755 install.sh
create mode 100644 macos/DefaultKeyBinding.dict
create mode 100644 mako/config
create mode 100644 mpv/input.conf
create mode 100644 mpv/mpv.conf
create mode 100644 mpv/scripts/subs_to_clipboard.js
create mode 100755 package_install.sh
create mode 100644 ripgrep/config
create mode 100644 sketchybar/com.sketchybar.launcher.template
create mode 100755 sketchybar/plugins/yabai_spaces.js
create mode 100755 sketchybar/sketchybarrc
create mode 100644 skhd/com.skhd.launcher.template
create mode 100755 skhd/scripts/record_audio_line
create mode 100755 skhd/scripts/shrink_screenshot_clipboard
create mode 100755 skhd/scripts/shrink_screenshot_desktop
create mode 100644 skhd/skhdrc
create mode 100644 swappy/config
create mode 100755 sway/brightness_lock.sh
create mode 100644 sway/config
create mode 100755 sway/cycle_windows.py
create mode 100755 sway/pulse_audio_volume.sh
create mode 100755 sway/swaybar_status.sh
create mode 100755 sway/toggle_fcitx.sh
create mode 100755 sway/toggle_mute.sh
create mode 100755 sway/window_dimensions.sh
create mode 100644 swaylock/config
create mode 100644 systemd/xremap.service
create mode 100644 tmux/tmux.conf
create mode 100644 vifm/colors/Default.vifm
create mode 100644 vifm/colors/gruvbox-dark.vifm
create mode 100644 vifm/colors/gruvbox-light.vifm
create mode 100755 vifm/scripts/vifm_bg_open.sh
create mode 100644 vifm/vifmrc
create mode 100644 vim/.vim/UltiSnips/math_preamble.tex
create mode 100644 vim/.vim/UltiSnips/tex.snippets
create mode 100644 vim/.vim/colors/base16-atelier-estuary-light.vim
create mode 100644 vim/.vim/colors/base16-atelier-plateau-light.vim
create mode 100644 vim/.vim/colors/base16-dracula.vim
create mode 100644 vim/.vim/colors/base16-github.vim
create mode 100644 vim/.vim/colors/base16-gruvbox-dark-medium.vim
create mode 100644 vim/.vim/colors/base16-gruvbox-dark-pale.vim
create mode 100644 vim/.vim/colors/base16-gruvbox-light-hard.vim
create mode 100644 vim/.vim/colors/base16-gruvbox-light-medium.vim
create mode 100644 vim/.vim/colors/base16-material-palenight.vim
create mode 100644 vim/.vim/colors/base16-monokai.vim
create mode 100644 vim/.vim/colors/base16-nord.vim
create mode 100644 vim/.vim/colors/base16-tomorrow.vim
create mode 100644 vim/.vim/ftdetect/bash.vim
create mode 100644 vim/.vim/ftdetect/ipython.vim
create mode 100644 vim/.vim/ftdetect/mips.vim
create mode 100644 vim/.vim/ftplugin/awk.vim
create mode 100644 vim/.vim/ftplugin/bash.vim
create mode 100644 vim/.vim/ftplugin/c.vim
create mode 100644 vim/.vim/ftplugin/html.vim
create mode 100644 vim/.vim/ftplugin/javascript.vim
create mode 100644 vim/.vim/ftplugin/julia.vim
create mode 100644 vim/.vim/ftplugin/make.vim
create mode 100644 vim/.vim/ftplugin/man.vim
create mode 100644 vim/.vim/ftplugin/markdown.vim
create mode 100644 vim/.vim/ftplugin/python.vim
create mode 100644 vim/.vim/ftplugin/rust.vim
create mode 100644 vim/.vim/ftplugin/snippets.vim
create mode 100644 vim/.vim/ftplugin/svelte.vim
create mode 100644 vim/.vim/ftplugin/tex.vim
create mode 100644 vim/.vim/ftplugin/vifm.vim
create mode 100644 vim/.vim/init_scripts/external_plugins.vim
create mode 100644 vim/.vim/init_scripts/init.vim
create mode 100644 vim/.vim/init_scripts/key_mappings.vim
create mode 100644 vim/.vim/init_scripts/settings.vim
create mode 100644 vim/.vim/plugin/auto_session.vim
create mode 100644 vim/.vim/plugin/clear_whitespace.vim
create mode 100644 vim/.vim/plugin/fix_highlights.vim
create mode 100644 vim/.vim/plugin/open_url.vim
create mode 100644 vim/.vim/plugin/pretty_section_comment.vim
create mode 100644 vim/.vim/plugin/statusbars/statusline.vim
create mode 100644 vim/.vim/plugin/statusbars/tabline.vim
create mode 100644 vim/.vim/syntax/mips.vim
create mode 100644 vim/.vimrc
create mode 100644 vim/nvim/init.vim
create mode 120000 vim/nvim/plugin
create mode 100644 vimiv/keys.conf
create mode 100644 vimiv/styles/base16-dracula
create mode 100644 vimiv/styles/base16-github
create mode 100644 vimiv/styles/base16-gruvbox-dark-pale
create mode 100644 vimiv/styles/base16-gruvbox-light-hard
create mode 100644 vimiv/vimiv.conf
create mode 100644 warpd/com.warpd.launcher.template
create mode 100644 warpd/config
create mode 100644 xremap/config_console.yml
create mode 100644 xremap/config_mac.yml
create mode 100644 xremap/config_standard.yml
create mode 100755 yabai/close_space.js
create mode 100755 yabai/cycle_stack.js
create mode 100755 yabai/move_to_stack.sh
create mode 100755 yabai/new_space.js
create mode 100755 yabai/pin_window.js
create mode 100755 yabai/rofi_window.js
create mode 100755 yabai/toggle_outline.bash
create mode 100755 yabai/yabairc
create mode 100644 yofi/yofi.config
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6cc93d3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,66 @@
+# Reference file for all alacritty options, found at;
+# https://github.com/alacritty/alacritty/releases
+
+# Aerc
+aerc/accounts.conf
+
+# Bin
+bin/sway_tree
+
+# Mpv
+mpv/watch_later
+
+# Other
+other/com.warpd.launcher.plist
+
+# Qutebrowser
+qutebrowser/*
+qutebrowser/config.py
+qutebrowser/gruvbox_qutebrowser.py
+
+# Skhd
+skhd/com.skhd.launcher.plist
+
+# Sketchybar
+sketchybar/com.sketchybar.launcher.plist
+
+# Sway
+sway/toggle_mute_data
+sway/*.avif
+sway/*.jepg
+sway/*.jpg
+sway/*.mp3
+sway/*.png
+
+# Swaylock
+swaylock/*
+!swaylock/config
+
+# Tmux
+tmux/plugins
+
+# Vifm
+vifm/scripts/README
+vifm/fzf-read/bookmarks
+vifm/vifm-help.txt
+vifm/vifminfo.json
+vifm/*.jpg
+
+# Vim
+vim/.vim/plugged
+vim/.vim/autoload/plug.vim
+vim/.vim/vim_notepad.md
+vim/.vim/colors
+vim/nvim/colors
+
+# Vimiv
+vimiv/styles/default
+
+# Warpd
+warpd/com.warpd.launcher.plist
+
+# Xremap
+xremap/config.yml
+
+# Yabai
+yabai/pinned_windows.json
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..93a430e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,329 @@
+Hit the ground flying with dotfiles for Unix-like systems including MacOS. These
+contain all sorts of goodies for bash, vim, shell scripts, unix notes, and much
+more!
+
+# Installation
+
+ $ git clone --depth=1 'ssh://git@github.com:22/Aizuko/configs.git' configs
+ $ cd configs && bash ./install.sh --help
+
+Use `./install.sh install` to symlink configs. Anything not linked will be
+reported and can be viewed at any time with `./install.sh status`. After linking
+files, proceed to the [post-installation](#Post-Installation) section
+
+Don't worry, the script won't overwrite anything and doesn't even touch anything
+without an explicit `install` argument
+
+### Info
+
+Verified platforms:
+
+ - **EndeavourOS 5.19.6** with Bash **5.1.16**
+ - **MacOS 10.15.{3,5}** with Bash **5.1.8** and **3.2.57**
+ - Almost certainly works on any Arch-based distro and likely most of Linux
+
+The mindset behind these:
+
+ - If it can be done in a shell, it probably should be done in a shell
+ - The mouse is too far away
+ - As fast as possible
+
+Configs are kept as consistent as possible between Mac and Linux, without
+sacrificing anything on either end. See the [keybinds for
+reference](#Keybinding-methodology)
+
+Linux is configured to run Sway. It's extremely light and incredibly fast.
+Although almost everything works on Wayland at this point, the Sway config can
+be trivially ported to i3 running on Xorg. An Arch-based distro will make
+installing the right packages easier, though is by no means required
+
+MacOS is configured to run Yabai with Skhd. This takes some tweaking. Check out
+the [Post-installation section for MacOS](#MacOS) beforehand. These config files
+were written on and font MacOS Catalina 10.15. Some things may not work in newer
+versions, though most things should be fine
+
+The `./notes` directory contains various reference files. They can be accessed
+quickly by running `notes`
+
+# Post Installation
+
+## Both
+
+Use `bash package_install.sh status` to see which packages are missing on your
+system. `./package_install.sh install` will try to install additional packages.
+This is very likely to work on MacOS and any `pacman`-using distro. If it's not
+working, install them manually by looking through `./package_install.sh status`
+
+This script does not install many heavier packages, such as `gimp`, `sway`, and
+`ffmpeg`. Check out `./notes/further_installation.md` for a list of these and
+install them manually
+
+## Linux
+
+#### Fonts
+
+Many scripts assume you have access to [Meslo LGM
+NerdFont](https://github.com/ryanoasis/nerd-fonts/tree/master/patched-fonts/Meslo/M).
+These can be replaced easily with any other nerd font. Other fonts may lack
+support for the right character set
+
+ $ mv -i downloaded-fonts/* ~/.local/share/fonts
+ # mv -i downloaded-fonts/* /usr/local/share/fonts
+
+See the [ArchWiki](https://wiki.archlinux.org/title/fonts#Manual_installation)
+for more information. TexLive downloads a lot of additional fonts by default too
+
+#### xRemap
+
+Remapping keys is done through `xremap`. Despite the name, it works flawlessly
+on Wayland, at least in Sway
+
+Depending on your environment, you need to install a different binary, all of
+which are available through `cargo`. For example `cargo install xremap
+--features sway`. Check [here for more
+options](https://github.com/k0kubun/xremap#installation).
+
+If you're using systemd, run the following:
+
+```
+# ln -s ~/.configs_pointer/xremap/config{_console,}.yml
+# mkdir -p /etc/xremap
+# ln -s {~/.configs_pointer,/etc}/xremap/config.yml
+# cp ~/.configs_pointer/systemd/xremap.service /etc/systemd/system/xremap.service
+# cp ~/.cargo/bin/xremap /usr/local/bin/xremap
+# systemctl enable xremap.service
+# systemctl start xremap.service
+# switch_keyboards.sh pc
+```
+
+You can toggle between Mac-style keyboard and standard keyboard with
+`switch_keyboards.sh` see the doc-comment `vi $(which switch_keyboards.sh)` for
+more information
+
+`sway/config` acts as a hotkey daemon and `wtype` can synthesize input
+
+#### Sway
+
+To run sway, install the `sway` and `swaylock` packages. Both configs reference
+`default_wallpaper.png` in their respective directories. Put your wallpaper
+there or change the corresponding `config` file
+
+If sway is acting up, try setting/unsetting `WAYLAND_DISPLAY` and `SWAYSOCK`.
+`swaymsg` also takes an `-s` option which can specify the socket manually
+
+Sway doesn't adjust the gamma on external displays. Compared to MacOS,
+everything looks very washed-out and low contrast. Using `wl-sunset` with `-t
+4000 -T 6500 -g 0.9` brings MacOS-like gamma curves
+
+For more information about sway, read the [i3 User's
+Guide](https://i3wm.org/docs/userguide.html). Particularly chapters 3 and 4 are
+very important for sway
+
+#### Multilingual input
+IME-style inputs require a complicated setup on wayland. The method described
+here unfortunately scales like Xwayland. That is to say it's very blurry on a
+HiDPI display. Also, IMEs don't work in Alacritty yet. Consider [foot
+terminal](https://codeberg.org/dnkl/foot) if this is important
+
+If you only need an IME in Chromium, [Google Input
+Tools](https://chrome.google.com/webstore/detail/google-input-tools/mclkkofklkfljcocdinagocijmpgbhab)
+is a pretty decent solution. It scales properly on wayland and doesn't require a
+spotty setup. However, it doesn't work in the search bar and makes network calls
+for kanji lookups, which can be really slow
+
+Otherwise you can use fcitx5. Choose a supported IME based on what language you
+need [here](https://wiki.archlinux.org/title/Input_method). For the example
+below we'll install Mozc
+
+```bash
+please pacman -S fcitx5 fcitx5-configtool fcitx5-gtk fcitx5-qt fcitx5-mozc
+please pacman -S gtk4 # For Chromium support
+```
+
+Next add these lines to `/etc/environment`
+```
+GTK_IM_MODULE=fcitx
+QT_IM_MODULE=fcitx
+XMODIFIERS=@im=fcitx
+MOZ_ENABLE_WAYLAND=1
+```
+
+Currently, Chromium will only interface with fcitx5 when it's running on the
+non-default gtk4. Add `--gtk-version=4` to `~/.config/chromium-flags.conf`. As
+of writing, this breaks Chromium's built-in file manager, the one for picking
+files. Use Firefox for a better fcitx5 experience
+
+Open fcitx5-configtool to set the required keyboards and change the global
+hotkey. For Mozc, you'd move the Mozc keyboard to the left. Not the other
+Japanese keyboards, those are not IME-based
+
+You may need to reboot wayland or possibly the entire system. Fcitx5 will now be
+available will the following command. Consider adding the following to
+`sway/config` if you want it on startup, or use `` to toggle in on/off
+
+```bash
+fcitx5 -d --replace
+```
+
+#### AV1 media
+AV1 is the hottest new codec on the block, providing compression levels better
+than h265. I've seen it 200x smaller than png, with the same resolution and
+color space
+
+To store images as avif, use `magick convert my_image_name.{png,avif}`. `viu`
+has no support for avif. `imv` supports it out of the box. `vimiv` requires a qt
+plugin for support:
+
+```bash
+please pacman -S libavif
+# Get the latest release from below, for example
+# https://github.com/novomesk/qt-avif-image-plugin/releases/latest
+curl -LO 'https://github.com/novomesk/qt-avif-image-plugin/archive/refs/tags/v0.5.0.tar.gz'
+tar xf qt-avif-image-plugin-0.5.0.tar.gz
+cd qt-avif-image-plugin-0.5.0
+./build_libqavif_dynamic.sh
+please make install
+```
+
+#### Chromium
+Chromium does not support screen sharing by default on wayland. To add support
+go into `chrome://flags` and enable the "WebRTC PipeWire support" flag. Next
+download the following a reboot to allow screen sharing
+
+```
+please pacman -S xdg-desktop-portal-wlr libpipewire02
+```
+
+Consider disabling "Continue running background apps when Chromium is closed" in
+settings
+
+Fix the default fonts in `chrome://settings/fonts`. These are the fallback fonts
+
+#### Firefox
+Firefox will start on xorg by default, unless the `MOZ_ENABLE_WAYLAND=1`
+environment variable is set. Incognito is enabled through the `--private-window`
+flag
+
+Firefox uses `about:config` stored in
+`~/.mozilla/firefox/.default-release/prefs.js`. These are the
+equivalent of Chromium flags. For these configs, simply switch
+`ui.key.menuAccessKeyFocuses` to false, to avoid conflicts with xremap
+
+#### Backlights
+Laptops usually control the backlight via apci. One program to control this is
+[light](https://github.com/haikarainen/light). By default light requires the use
+of root privileges to modify devices. Use systemd rules and the video group to
+allow unprivileged users to run it normally:
+
+```bash
+curl -LO 'https://raw.githubusercontent.com/haikarainen/light/master/90-backlight.rules'
+please mkdir -p /usr/lib/udev/rules.d
+please cp 90-backlight.rules /usr/lib/udev/rules.d
+# Add your user to the video group
+please usermod -aG video emiliko
+```
+
+## MacOS
+
+Macs aren't even close to Linux in virtualisation capabilities, window managers,
+and customizability in general. However, if you're unfortunate enough to find
+yourself with a macbook, all is not lost. Here's a rough porting guide:
+
+| sWayland | MacOS |
+| --------------------- | -------- |
+| SwayWM | [Yabai](https://github.com/koekeishiya/yabai) |
+| xRemap | [Karabiner-Elements](https://karabiner-elements.pqrs.org/) |
+| ~/.config/sway/config | [skhd](https://github.com/koekeishiya/skhd) |
+| swhkd | [skhd](https://github.com/koekeishiya/skhd) |
+| wtype | [skhd](https://github.com/koekeishiya/skhd) |
+| systemd | Launchd |
+| Zathura | [Skim](https://skim-app.sourceforge.io/) |
+| Fuzzel | [Choose](https://github.com/chipsenkbeil/choose) or Spotlight |
+| udisksctl | `diskutil`
+| ~/.local/share/fonts | FontBook |
+| wl-clipboard | `pbcopy` `pbpaste` |
+| sshd | System Preference -> Sharing -> Remote Login |
+| Super/Ctrl | Command |
+| Alt | Opt |
+| $0 | +$1000 |
+
+For Xorg users, `yabai` is to `skhd` what `bspwm` is to `sxhkd`. Also `launchd`
+is wayyy less capable than `systemd` and rarely gets used. The `launchd` script
+in `./bin` wraps around all the commands you'll ever need
+
+To use open source apps, run `sudo spctl --master-disable`, then head to System
+Preferences -> Security & Privacy -> General and select Anywhere at the bottom.
+You can check it's working with `spctl --status`
+
+While you're here, you can go under Software Updates and uncheck everything
+
+#### Window managers
+
+MacOS only allows the default Quartz Compositor, a floating window manager with
+too many animations and almost no keyboard controls. There are two open source
+tiling window managers, which are just scripts overtop Quartz Compositor as
+alternatives. [Amethyst](https://github.com/ianyh/Amethyst) and
+[Yabai](https://github.com/koekeishiya/yabai)
+
+Amethyst provides basic tiling of windows and basic keyboard controls. Yabai is
+effectively a port of bspwm to MacOS and has much more extensive configuration
+than Amethyst, notably controlling workspaces. Unfortunately they don't hold a
+candle to Linux managers. Both can be very laggy and Yabai specifically often
+freezes up for a few seconds, though these are the only options.
+
+To use Yabai, boot into recovery mode, and disable SIP [as explained
+here](https://github.com/koekeishiya/yabai/wiki/Disabling-System-Integrity-Protection).
+Despite what apple says, this doesn't make the system immediately explode.
+Actually there's no difference at all, except being able to use Yabai
+
+# Methodology
+## Keybinding
+Generally keybindings follow this scheme for `skhd`/`xremap`, bash, and vim's
+insert mode. They roughly resemble Emac's default. Outliers are bolded. These
+are written assuming Ctrl is mapped to CapsLock
+
+When possible selecting is preferred to actually deleting the text
+
+| Type | Start of line | Back word | Back character | Forward character | Forward word | End of line |
+| ---- | ------------- | --------- | -------------- | ----------------- | ------------ | ----------- |
+| Movement | `^a` | **`^b`** | **`^j`** | `^f` | **`^w`** | `^e` |
+| Deletion | | **`^u`** | `^h` | `^d` | | `^k` |
+
+Window managers are bound to the Super/Command/Logo key. This conflicts with
+MacOS's defaults at times
+
+## Light and Dark Mode
+
+### Graphical
+
+Light mode remains somewhat spotty and probably will indefinitely. On Wayland
+there's [wluma](https://github.com/maximbaz/wluma) which is a port of MacOS's
+[Lumen](https://github.com/anishathalye/lumen). Both can somewhat help alleviate
+rapid changes in on-screen content brightness
+
+There's a UserStyle.css file, tested with
+[Stylus](https://chrome.google.com/webstore/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne)
+on Chromium which provides dark themes for many additional sites, such as the
+ArchWiki
+
+### Text mode
+
+Alacritty, tmux, vim, vifm, vimiv are all synchronously colored through
+`bin/colo.sh`. This script supports multiple color schemes and makes it easy to
+add new ones.
+
+Vifm has a "light" and "dark" mode which plays better with generally "lighter"
+and "darker" color schemes. This can be manually changed with `:Light` and
+`:Dark`
+
+Vim similarly has shortcuts for the included color schemes. `:Dark[1-4]` and
+`:Light[1-4]` change to some hand-picked good ones. Additionally `:Darkh`
+changes to a higher-contrast version of the `:Dark` color scheme
+
+## Todo
+The only one done configing is you, Ricky
+
+ - Maildir with aerc
+ - [Himalaya](https://git.sr.ht/~soywod/himalaya-cli) instead of aerc?
+ - Setup irc client?
+ - Organize notes
diff --git a/aerc/aerc.conf b/aerc/aerc.conf
new file mode 100644
index 0000000..96ebade
--- /dev/null
+++ b/aerc/aerc.conf
@@ -0,0 +1,331 @@
+#
+# aerc main configuration
+
+[general]
+default-save-path=/dev/shm
+#
+# If set to "gpg", aerc will use system gpg binary and keystore for all crypto
+# operations. Otherwise, the internal openpgp implemenation will be used.
+#
+# Default: internal
+pgp-provider=internal
+
+# By default, the file permissions of accounts.conf must be restrictive and
+# only allow reading by the file owner (0600). Set this option to true to
+# ignore this permission check. Use this with care as it may expose your
+# credentials.
+#
+# Default: false
+unsafe-accounts-conf=false
+
+[ui]
+#
+# Describes the format for each row in a mailbox view. This field is compatible
+# with mutt's printf-like syntax.
+#
+# Default: %D %-17.17n %Z %s
+index-format=%-20.20D %-17.17n %Z %s
+
+#
+# See time.Time#Format at https://godoc.org/time#Time.Format
+#
+# Default: 2006-01-02 03:04 PM (ISO 8601 + 12 hour time)
+timestamp-format=2006-01-02 03:04 PM
+
+#
+# Index-only time format for messages that were received/sent today.
+# If this is not specified, timestamp-format is used instead.
+#
+# Default: "03:04 PM" (12 hour time)
+this-day-time-format=03:04 PM
+
+#
+# Index-only time format for messages that were received/sent within the last
+# 7 days. If this is not specified, timestamp-format is used instead.
+#
+# Default: "Monday 03:04 PM" (Week day + 12 hour time)
+this-week-time-format=Monday 03:04 PM
+
+#
+# Index-only time format for messages that were received/sent this year.
+# If this is not specified, timestamp-format is used instead.
+#
+# Default: "January 02" (Month + month day)
+this-year-time-format=January 02
+
+#
+# Width of the sidebar, including the border.
+#
+# Default: 20
+sidebar-width=20
+
+#
+# Message to display when viewing an empty folder.
+#
+# Default: (no messages)
+empty-message=(no messages)
+
+# Message to display when no folders exists or are all filtered
+#
+# Default: (no folders)
+empty-dirlist=(no folders)
+
+# Enable mouse events in the ui, e.g. clicking and scrolling with the mousewheel
+#
+# Default: false
+mouse-enabled=false
+
+#
+# Ring the bell when new messages are received
+#
+# Default: true
+new-message-bell=true
+
+# Marker to show before a pinned tab's name.
+#
+# Default: `
+pinned-tab-marker='`'
+
+# Describes the format string to use for the directory list
+#
+# Default: %n %>r
+dirlist-format=%n %>r
+
+# Delay after which the messages are actually listed when entering a directory.
+# This avoids loading messages when skipping over folders and makes the UI more
+# responsive. If you do not want that, set it to 0s.
+#
+# Default: 200ms
+dirlist-delay=200ms
+
+# Display the directory list as a foldable tree that allows to collapse and
+# expand the folders.
+#
+# Default: false
+dirlist-tree=false
+
+# List of space-separated criteria to sort the messages by, see *sort*
+# command in *aerc*(1) for reference. Prefixing a criterion with "-r "
+# reverses that criterion.
+#
+# Example: "from -r date"
+#
+# Default: ""
+sort=
+
+# Moves to next message when the current message is deleted
+#
+# Default: true
+next-message-on-delete=true
+
+# The directories where the stylesets are stored. It takes a colon-separated
+# list of directories. If this is unset or if a styleset cannot be found, the
+# following paths will be used as a fallback in that order:
+#
+# ${XDG_CONFIG_HOME:-~/.config}/aerc/stylesets
+# ${XDG_DATA_HOME:-~/.local/share}/aerc/stylesets
+# /usr/local/share/aerc/stylesets
+# /usr/share/aerc/stylesets
+#
+# default: ""
+stylesets-dirs=
+
+# Uncomment to use box-drawing characters for vertical and horizontal borders.
+#
+# Default: spaces
+# border-char-vertical=│
+# border-char-horizontal=─
+
+# Sets the styleset to use for the aerc ui elements.
+#
+# Default: default
+styleset-name=default
+
+# Activates fuzzy search in commands and their arguments: the typed string is
+# searched in the command or option in any position, and need not be
+# consecutive characters in the command or option.
+#fuzzy-complete=false
+
+# How long to wait after the last input before auto-completion is triggered.
+#
+# Default: 250ms
+completion-delay=250ms
+
+#
+# Global switch for completion popovers
+#
+# Default: true
+completion-popovers=true
+
+# Uncomment to use UTF-8 symbols to indicate PGP status of messages
+#
+# Default: ASCII
+#icon-unencrypted=
+#icon-encrypted=✔
+#icon-signed=✔
+#icon-signed-encrypted=✔
+#icon-unknown=✘
+#icon-invalid=⚠
+
+#[ui:account=foo]
+#
+# Enable a threaded view of messages. If this is not supported by the backend
+# (IMAP server or notmuch), threads will be built by the client.
+#
+# Default: false
+#threading-enabled=false
+
+# Force client-side thread building
+#
+# Default: false
+#force-client-threads=false
+
+[statusline]
+# Describes the format string for the statusline.
+#
+# Default: [%a] %S %>%T
+render-format=[%a] %S %>%T
+
+# Specifies the separator between grouped statusline elements.
+#
+# Default: " | "
+# separator=
+
+# Defines the mode for displaying the status elements.
+# Options: text, icon
+#
+# Default: text
+# display-mode=
+
+[viewer]
+#
+# Specifies the pager to use when displaying emails. Note that some filters
+# may add ANSI codes to add color to rendered emails, so you may want to use a
+# pager which supports ANSI codes.
+#
+# Default: less -R
+pager=less -R
+
+#
+# If an email offers several versions (multipart), you can configure which
+# mimetype to prefer. For example, this can be used to prefer plaintext over
+# html emails.
+#
+# Default: text/plain,text/html
+alternatives=text/plain,text/html
+
+#
+# Default setting to determine whether to show full headers or only parsed
+# ones in message viewer.
+#
+# Default: false
+show-headers=false
+
+#
+# Layout of headers when viewing a message. To display multiple headers in the
+# same row, separate them with a pipe, e.g. "From|To". Rows will be hidden if
+# none of their specified headers are present in the message.
+#
+# Default: From|To,Cc|Bcc,Date,Subject
+header-layout=From|To,Cc|Bcc,Date,Subject
+
+# Whether to always show the mimetype of an email, even when it is just a single part
+#
+# Default: false
+always-show-mime=false
+
+# Parses and extracts http links when viewing a message. Links can then be
+# accessed with the open-link command.
+#
+# Default: true
+parse-http-links=true
+
+[compose]
+#
+# Specifies the command to run the editor with. It will be shown in an embedded
+# terminal, though it may also launch a graphical window if the environment
+# supports it. Defaults to $EDITOR, or vi.
+editor=
+
+#
+# Default header fields to display when composing a message. To display
+# multiple headers in the same row, separate them with a pipe, e.g. "To|From".
+#
+# Default: To|From,Subject
+header-layout=To|From,Subject
+
+#
+# Specifies the command to be used to tab-complete email addresses. Any
+# occurrence of "%s" in the address-book-cmd will be replaced with what the
+# user has typed so far.
+#
+# The command must output the completions to standard output, one completion
+# per line. Each line must be tab-delimited, with an email address occurring as
+# the first field. Only the email address field is required. The second field,
+# if present, will be treated as the contact name. Additional fields are
+# ignored.
+address-book-cmd=
+
+#
+# Allow to address yourself when replying
+#
+# Default: true
+reply-to-self=true
+
+[filters]
+#
+# Filters allow you to pipe an email body through a shell command to render
+# certain emails differently, e.g. highlighting them with ANSI escape codes.
+#
+# The first filter which matches the email's mimetype will be used, so order
+# them from most to least specific.
+#
+# You can also match on non-mimetypes, by prefixing with the header to match
+# against (non-case-sensitive) and a comma, e.g. subject,text will match a
+# subject which contains "text". Use header,~regex to match against a regex.
+#subject,~^\[PATCH=colordiff
+text/plain=sed 's/^>\+.*/\x1b[36m&\x1b[0m/'
+text/html=pandoc -f html -t plain
+#image/*=catimg -w $(tput cols) -
+
+[triggers]
+#
+# Triggers specify commands to execute when certain events occur.
+#
+# Example:
+# new-email=exec notify-send "New email from %n" "%s"
+
+#
+# Executed when a new email arrives in the selected folder
+new-email=exec notify-send "New email from %n" "%s"
+
+[templates]
+# Templates are used to populate email bodies automatically.
+#
+
+# The directories where the templates are stored. It takes a colon-separated
+# list of directories. If this is unset or if a template cannot be found, the
+# following paths will be used as a fallback in that order:
+#
+# ${XDG_CONFIG_HOME:-~/.config}/aerc/templates
+# ${XDG_DATA_HOME:-~/.local/share}/aerc/templates
+# /usr/local/share/aerc/templates
+# /usr/share/aerc/templates
+#
+# default: ""
+template-dirs=
+
+# The default template to be used for new messages.
+#
+# default: new_message
+new-message=new_message
+
+# The default template to be used for quoted replies.
+#
+# default: quoted_reply
+quoted-reply=quoted_reply
+
+# The default template to be used for forward as body.
+#
+# default: forward_as_body
+forwards=forward_as_body
diff --git a/aerc/binds.conf b/aerc/binds.conf
new file mode 100644
index 0000000..5cf93cd
--- /dev/null
+++ b/aerc/binds.conf
@@ -0,0 +1,123 @@
+# Binds are of the form =
+# To use '=' in a key sequence, substitute it with "Eq": ""
+# If you wish to bind #, you can wrap the key sequence in quotes: "#" = quit
+ = :prev-tab
+ = :next-tab
+gT = :prev-tab
+gt = :next-tab
+ = :term
+ = :
+
+[messages]
+q = :quit
+
+j = :next
+ = :next
+ = :next 50%
+ = :next 100%
+ = :next 100%
+
+k = :prev
+ = :prev
+ = :prev 50%
+ = :prev 100%
+ = :prev 100%
+gg = :select 0
+G = :select -1
+
+J = :next-folder
+K = :prev-folder
+H = :collapse-folder
+L = :expand-folder
+
+v = :mark -t
+V = :mark -v
+
+T = :toggle-threads
+
+ = :view
+dd = :prompt 'Really delete this message?' 'delete-message'
+A = :archive flat
+
+C = :compose
+
+rr = :reply -a
+rq = :reply -aq
+Rr = :reply
+Rq = :reply -q
+
+#c = :cf
+#$ = :term
+#! = :term
+#| = :pipe
+
+/ = :search
+\ = :filter -a
+n = :next-result
+N = :prev-result
+ = :clear
+
+[messages:folder=Drafts]
+ = :recall
+
+[view]
+/ = :toggle-key-passthrough/
+q = :close
+O = :open
+S = :save
+| = :pipe
+D = :delete
+A = :archive flat
+
+ = :open-link
+
+f = :forward
+rr = :reply -a
+rq = :reply -aq
+Rr = :reply
+Rq = :reply -q
+
+H = :toggle-headers
+ = :prev-part
+ = :next-part
+J = :next
+K = :prev
+
+[view::passthrough]
+$noinherit = true
+$ex =
+ = :toggle-key-passthrough
+
+[compose]
+# Keybindings used when the embedded terminal is not selected in the compose
+# view
+$ex =
+ = :prev-field
+ = :next-field
+ =
+ =
+ =
+ = :next-field
+
+[compose::editor]
+# Keybindings used when the embedded terminal is selected in the compose view
+$noinherit = true
+ = :prev-field
+ = :next-field
+
+[compose::review]
+# Keybindings used when reviewing a message to be sent
+y = :send
+N = :abort
+p = :postpone
+q = :choose -o d discard abort -o p postpone postpone
+e = :edit
+a = :attach
+d = :detach
+
+[terminal]
+$noinherit = true
+$ex =
+
+ = :prev-tab
+ = :next-tab
diff --git a/alacritty/alacritty.yml b/alacritty/alacritty.yml
new file mode 100644
index 0000000..c4a68e8
--- /dev/null
+++ b/alacritty/alacritty.yml
@@ -0,0 +1,119 @@
+#======================
+# Fonts and colors
+#======================
+# Fonts
+font:
+ normal:
+ family: Menlo # Default fallback font
+ # Alternative monospace fallback fonts
+ #family: Monaco
+ #family: Source Code Pro
+
+ family: MesloLGM Nerd Font # Use a Nerd-Font for pretty vim statusline
+ #family: NotoSans Mono # Use a Nerd-Font for pretty vim statusline
+ #family: MesloLGL Nerd Font # Use a Nerd-Font for pretty vim statusline
+ size: 11.5
+
+ offset:
+ x: 1
+ y: 1
+ glyph_offset: # Aligns powerline fonts
+ x: 0
+ y: 1
+
+ use_thin_strokes: true
+
+draw_bold_text_with_bright_colors: false
+
+# Colors (Gruvbox dark)
+colors:
+ # Cursor colors
+ cursor:
+ text: CellBackground
+ cursor: CellForeground
+
+ # Vi mode colors
+ search:
+ matches:
+ foreground: '#000000'
+ background: '#ffffff'
+ focused_match:
+ foreground: CellBackground
+ background: CellForeground
+ bar:
+ background: '#c5c8c6'
+ foreground: '#1d1f21'
+
+ selection:
+ text: '#000000'
+ background: '#e69f67'
+
+import:
+ - ~/.config/alacritty/colors.yml
+
+#==========================
+# Window GUI
+#==========================
+window:
+ title: JoJo
+ position:
+ x: 536
+ y: 164
+ dimensions:
+ columns: 134 # 16 size font
+ lines: 36
+ #columns: 150 # 14 size font
+ #lines: 40
+ padding:
+ x: 4
+ y: 0
+
+ decorations: None
+ startup_mode: Windowed
+ opacity: 1
+
+ title: Alacritty
+ dynamic_title: true
+
+scrolling:
+ history: 10000
+ multiplier: 3
+
+bell:
+ duration: 0
+ color: '#ffff99'
+ command: None
+
+selection:
+ save_to_clipboard: true
+
+cursor:
+ style:
+ shape: Block
+ blinking: Always
+ vi_mode_style: Block
+ blink_interval: 400
+ unfocused_hollow: true
+ thickness: 0.15
+
+live_config_reload: true
+
+shell:
+ program: /bin/bash
+ args:
+ - --login
+
+working_directory: None
+
+mouse:
+ double_click: { threshold: 300 }
+ triple_click: { threshold: 300 }
+ hide_when_typing: true
+
+key_bindings:
+ - { key: LBracket, mods: Control, action: ToggleViMode}
+ - { key: I, mode: Vi, action: ToggleViMode}
+ - { key: N, mods: Alt, action: SpawnNewInstance}
+ - { key: K, mods: Command, chars: "\x08k"}
+ # let tmux see C-Space
+ - { key: Space, mods: Control, chars: "\x00" }
diff --git a/alacritty/colors.yml b/alacritty/colors.yml
new file mode 100644
index 0000000..50159de
--- /dev/null
+++ b/alacritty/colors.yml
@@ -0,0 +1,231 @@
+schemes:
+ gruvbox_dark: &base16-gruvbox-dark-pale
+ primary:
+ background: '#282828'
+ foreground: '#ebdbb2'
+ bright_foreground: '#eaeaea'
+
+ # Normal colors
+ #normal:
+ # black: '#282828'
+ # red: '#cc241d'
+ # green: '#98971a'
+ # yellow: '#d79921'
+ # blue: '#458588'
+ # magenta: '#b16286'
+ # cyan: '#689d6a'
+ # white: '#a89984'
+
+ # Brighter colors by default! May be too bright
+ normal:
+ black: '#282828'
+ red: '#fb4934'
+ green: '#b8bb26'
+ yellow: '#fabd2f'
+ blue: '#83a598'
+ magenta: '#d3869b'
+ cyan: '#8ec07c'
+ white: '#ebdbb2'
+
+ # Bright colors
+ bright:
+ black: '#928374'
+ red: '#fb4934'
+ green: '#b8bb26'
+ yellow: '#fabd2f'
+ blue: '#83a598'
+ magenta: '#d3869b'
+ cyan: '#8ec07c'
+ white: '#ebdbb2'
+
+ gruvbox_light: &base16-gruvbox-light-hard
+ # Light mode ====
+ # http://lawlesscreation.github.io/hex-color-visualiser/
+ #f9f5d7 # White 1
+ #ebdbb2 # White 2
+ #d5c4a1 # White 3
+ #bdae93 # White 4, light grey
+ #665c54 # Grey 1
+ #504945 # Grey 2
+ #3c3836 # Grey 3, light black
+ #282828 # Grey 4, black
+ #9d0006 # Cherry red
+ #af3a03 # Rust red
+ #b57614 # Yellow
+ #79740e # Green
+ #427b58 # Teal
+ #076678 # Blue
+ #8f3f71 # Purple
+ #d65d0e # Orange
+ primary:
+ background: '#FDFFD7' # Linux "white"???
+ #background: '#f9f5d7' # White 1 (brighter)
+ #background: '#fbf1c7' # Sepia white
+ foreground: '#3c3836' # Grey 3, light black
+ bright_foreground: '#282828' # Grey 4, black
+
+ normal:
+ #black: '#f9f5d7' # White 1
+ black: '#fbf1c7' # Sepia white
+ red: '#9d0006' # Cherry red
+ green: '#79740e' # Green
+ yellow: '#b57614' # Yellow
+ cyan: '#427b58' # Teal
+ blue: '#076678' # Blue
+ magenta: '#8f3f71' # Purple
+ white: '#282828' # Grey 4, black
+
+ bright:
+ black: '#f9f5d7' # White 1
+ red: '#9d0006' # Cherry red
+ green: '#79740e' # Green
+ yellow: '#b57614' # Yellow
+ cyan: '#427b58' # Teal
+ blue: '#076678' # Blue
+ magenta: '#8f3f71' # Purple
+ white: '#282828' # Grey 4, black
+
+ # Catppuccin!
+ catppuccin: &catppuccin
+ # Default colors
+ primary:
+ background: '#1E1E28'
+ foreground: '#DADAE8'
+
+ # Colors the cursor will use if `custom_cursor_colors` is true
+ cursor:
+ text: '#1E1E28'
+ cursor: '#B1E3AD'
+
+ # Normal colors
+ normal:
+ black: '#6E6C7E'
+ red: '#E38C8F'
+ green: '#B1E3AD'
+ yellow: '#EBDDAA'
+ blue: '#A4B9EF'
+ magenta: '#C6AAE8'
+ cyan: '#E5B4E2'
+ white: '#DADAE8'
+
+ # Bright colors
+ bright:
+ black: '#6E6C7E'
+ red: '#E38C8F'
+ green: '#B1E3AD'
+ yellow: '#EBDDAA'
+ blue: '#A4B9EF'
+ magenta: '#C6AAE8'
+ cyan: '#E5B4E2'
+ white: '#DADAE8'
+
+ indexed_colors:
+ - { index: 16, color: '#F2CECF' }
+ - { index: 17, color: '#3E4058' }
+
+ palenight: &palenight
+ # Default colors
+ primary:
+ background: '0x292d3e'
+ foreground: '0x959dcb'
+
+ # Colors the cursor will use if `custom_cursor_colors` is true
+ cursor:
+ text: '0x292d3e'
+ cursor: '0x959dcb'
+
+ # Normal colors
+ normal:
+ black: '0x292d3e'
+ red: '0xf07178'
+ green: '0xc3e88d'
+ yellow: '0xffcb6b'
+ blue: '0x82aaff'
+ magenta: '0xc792ea'
+ cyan: '0x89ddff'
+ white: '0x959dcb'
+
+ # Bright colors
+ bright:
+ black: '0x676e95'
+ red: '0xf07178'
+ green: '0xc3e88d'
+ yellow: '0xffcb6b'
+ blue: '0x82aaff'
+ magenta: '0xc792ea'
+ cyan: '0x89ddff'
+ white: '0xffffff'
+
+ indexed_colors:
+ - { index: 16, color: '0xf78c6c' }
+ - { index: 17, color: '0xff5370' }
+ - { index: 18, color: '0x444267' }
+ - { index: 19, color: '0x32374d' }
+ - { index: 20, color: '0x8796b0' }
+ - { index: 21, color: '0x959dcb' }
+
+ dracula: &base16-dracula
+ # Default colors
+ primary:
+ background: '0x282a36'
+ foreground: '0xf8f8f2'
+
+ # Normal colors
+ normal:
+ black: '0x000000'
+ red: '0xff5555'
+ green: '0x50fa7b'
+ yellow: '0xf1fa8c'
+ blue: '0xcaa9fa'
+ magenta: '0xff79c6'
+ cyan: '0x8be9fd'
+ white: '0xbfbfbf'
+
+ # Bright colors
+ bright:
+ black: '0x282a35'
+ red: '0xff6e67'
+ green: '0x5af78e'
+ yellow: '0xf4f99d'
+ blue: '0xcaa9fa'
+ magenta: '0xff92d0'
+ cyan: '0x9aedfe'
+ white: '0xe6e6e6'
+
+ # Defman21
+ github: &base16-github
+ # Default colors
+ primary:
+ background: '0xffffff'
+ foreground: '0x333333'
+
+ # Colors the cursor will use if `custom_cursor_colors` is true
+ cursor:
+ text: '0xffffff'
+ cursor: '0x333333'
+
+ # Normal colors
+ normal:
+ black: '0xffffff'
+ red: '0xed6a43'
+ green: '0x183691'
+ yellow: '0x795da3'
+ blue: '0x795da3'
+ magenta: '0xa71d5d'
+ cyan: '0x183691'
+ white: '0x333333'
+
+ # Bright colors
+ bright:
+ black: '0x969896'
+ red: '0x0086b3'
+ green: '0xf5f5f5'
+ yellow: '0xc8c8fa'
+ blue: '0xe8e8e8'
+ magenta: '0xffffff'
+ cyan: '0x333333'
+ white: '0xffffff'
+
+draw_bold_text_with_bright_colors: false
+# This line is changed by `~/.bash_functions`'s `colo` function
+colors: *base16-gruvbox-dark-pale
diff --git a/bash/.bash_aliases b/bash/.bash_aliases
new file mode 100644
index 0000000..6465909
--- /dev/null
+++ b/bash/.bash_aliases
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+# ===================================================================
+# Core bash aliases
+# ===================================================================
+# Might be necessary for vim
+shopt -s expand_aliases
+
+# Safety aliases
+alias mv='mv -i'
+alias cp='cp -i'
+alias rm='rm -i'
+
+# Legibility
+alias df='df -h'
+alias du='du -h'
+alias tdu='du -h -d1 | sort -h'
+alias free='free -h'
+alias mkdir='mkdir -p'
+alias bat='bat --paging=never'
+alias tt='/usr/bin/time -f "%MKB, %es"'
+alias colo='colo.sh'
+
+# Other
+alias mem='top -l 1 -s 0 | grep PhysMem'
+alias please='sudo -E '
+alias cc="clang -Wall -Wextra -Werror -O2 -std=c99 -pedantic"
+alias lsblkf="lsblk -o name,label,fstype,mountpoint,fsused,size,state"
+alias mr='make run'
+alias ed="ed -p '> :'"
+alias ra='rg --no-ignore -.'
+alias ee='exit'
+alias ffprobe='ffprobe -hide_banner'
+
+
+# ===================================================================
+# Keybindings
+# ===================================================================
+if [[ "${-}" =~ i ]]; then
+ # Vim-ish movement by word
+ bind '"\C-w":"\ef"' # Move forward one word \x1BF
+ bind '"\C-b": backward-word'
+ bind '"\C-j": backward-char' # Back one character
+ bind '"\C-l": complete' # Tab-completion to match vim
+
+ stty werase ^u
+
+ stty -ixon # i-search down with ^s
+
+ # Figure that out:
+ #https://superuser.com/questions/1601543/ctrl-x-e-without-executing-command-immediately
+fi
+
+
+# ===================================================================
+# Navigation aliases
+# ===================================================================
+alias cd..='cd ..'
+alias safe='cd ~/safe'
+
+# Avoid symlink paths
+alias cd='cd -P'
+alias pwd='pwd -P'
+alias cdb='cd $OLDPWD' # Go back a directory. Works with symlinks
+
+
+# ===================================================================
+# Listing aliases
+# ===================================================================
+# List Long - List files in acending order of size
+alias ll='listlong'
+alias ls='listlong --ll-ls'
+
+# Additional listing options with exa
+if command -v exa &> /dev/null; then
+ # Tree List Long - Recursively print a tree view
+ alias tll='listlong --ll-tree'
+ # Git List Long - Recursively print a tree view following .gitignore
+ alias gll='listlong --ll-git-tree'
+ # Directories List Long - List the directory hierarchy
+ alias dll='listlong --ll-dir-tree'
+ # All List Long - Detailed information for files in current working dir
+ alias all='listlong --ll-all'
+ # List symlinks
+ alias llinks='listlong --ll-links'
+fi
+
+
+# ===================================================================
+# Git
+# ===================================================================
+if command -v git &> /dev/null; then
+ alias gitst='git status -s'
+ alias gitllog='git log --graph --all --oneline --decorate --color=always | sed -n 1,5p'
+ alias gitlloga='git log --graph --all --oneline --decorate --color=always | bless'
+ alias gitllogw='git log --graph --all --date=relative --color=always --pretty="format:%C(auto,yellow)%h%C(auto,magenta) %C(auto,blue)%>(14,trunc)%ad %C(auto,green)%<(13,trunc) %aN%C(auto,red)%gD% D %C(auto,reset)%s" | bless'
+ alias gitdesk='github .'
+ alias gitcontrib='
+ git ls-files |
+ while read f
+ do git blame -w -M -C -C --line-porcelain "$f" | grep -I "^author "
+ done | sort -f | uniq -ic | sort -n --reverse'
+fi
+
+
+# ===================================================================
+# External programs
+# ===================================================================
+# nVim
+if command -v nvim &> /dev/null; then
+ alias vi='nvim' vih='nvim +Rooter'
+elif command -v vim &> /dev/null; then
+ alias vi='vim' vih='vim +Rooter'
+fi
+
+# Veracrypt
+if command -v veracrypt &> /dev/null
+ then alias vera='veracrypt -t'; fi
+
+# Vifm
+if command -v vifm &> /dev/null
+ then alias fm='vifm'; fi
+
+# Vimiv
+if command -v vimiv &> /dev/null
+ then alias vii='vii.sh'; fi
+
+# Qemu
+if command -v qemu-system-x86_64 &> /dev/null
+ then alias qemu='qemu-system-x86_64'; fi
+
+# Python
+if command -v python3 &> /dev/null
+ then alias py='python3' venv='source ./bin/activate'; fi
+
+# vim: set ft=bash ff=unix:
diff --git a/bash/.bash_env b/bash/.bash_env
new file mode 100644
index 0000000..6a85003
--- /dev/null
+++ b/bash/.bash_env
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+# PATH extensions ===================================================
+ # Cargo's binaries
+export PATH="${HOME}/bin:${HOME}/.cargo/bin:${PATH}"
+ # Scripts mostly intended for use with hotkeys
+export PATH="${HOME}/.configs_pointer/bin/hotkey_scripts:${PATH}"
+ # Custom scripts
+export PATH="${HOME}/.configs_pointer/bin:${HOME}/.configs_pointer/bin/one_shots:${PATH}"
+
+# History settings ==================================================
+# Ignore duplicates common commands in history
+export HISTCONTROL=ignoreboth
+export HISTIGNORE='history:pwd:exit:ll:ll -a: ls: tree:tty:pass *'
+
+# Infinite history size
+export HISTFILESIZE=
+export HISTSIZE=
+export HISTTIMEFORMAT="%F %T: "
+
+# Different history file to avoid truncation. Still truncates...
+export HISTFILE=~/.bash_eternal_history
+
+# Every prompt writes to history
+PROMPT_COMMAND="history -a; $PROMPT_COMMAND"
+
+# MacOS fixes =======================================================
+if [[ $(uname -s) == 'Darwin' ]]; then
+ # Use coreutils binaries when possible. Man pages still open MacOS binary
+ # by default. Prefix 'g' to open the coreutils manpage
+ export PATH="/usr/local/opt/coreutils/libexec/gnubin/:$PATH"
+
+ # Silence login warning about bash deprecation
+ export BASH_SILENCE_DEPRECATION_WARNING=1
+
+ # `ls --color` for BSD/MacOS
+ export CLICOLOR=1
+fi
+
+# Homebrew ==========================================================
+if [[ -x /home/linuxbrew/.linuxbrew/bin/brew ]]; then
+ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
+fi
+
+# Stop brew from upgrading all formula when installing something
+export HOMEBREW_NO_INSTALL_UPGRADE=1
+
+# Swayland ==========================================================
+if [[ "$(uname -s)" == "Linux" ]] && pidof sway &>/dev/null; then
+ export WAYLAND_DISPLAY=wayland-1
+
+ export SWAYSOCK="/run/user/$(id -u)/sway-ipc.$(id -u).$(pidof sway).sock"
+fi
+
+# Man pages =========================================================
+export MANWIDTH=90
+
+export GIT_PAGER='' # Vim can't properly read git-diff colors
+
+if [[ "$(uname -s)" == "Linux" ]] && command -v nvim &>/dev/null; then
+ export PAGER="/bin/sh -c \"unset PAGER;col -b -x | \
+ nvim -R -c 'set ft=man nomod nolist' -c 'map q :q' \
+ -c 'silent! %s/\v[0-9]+;[0-9];[0-9]+;[0-9]+;[0-9]+m//g' \
+ -c 'silent! %s/0m//g' \
+ -c 'nmap K :Man =expand(\\\"\\\")' -\""
+fi
+
+# Config =============================================================
+export XDG_CONFIG_HOME=~/.config
+export XDG_CACHE_HOME=~/.cache
+export XDG_DATA_HOME=~/.local/share
+export XDG_STATE_HOME=~/.local/state
+export XDG_DATA_DIRS='/usr/local/share:/usr/share'
+export XDG_CONFIG_DIRS='/etc/xdg'
+
+ # Enter GPG password using terminal
+export GPG_TTY=$(tty)
+
+ # For pass -c
+export PASSWORD_STORE_CLIP_TIME=20
+
+ # Open git commits and , now , in nvim. Absolute path is better
+export EDITOR='nvim'
+
+ # Stop bash from exiting from ^d. 8 consecutive ^d will still exit
+export IGNOREEOF=8
+
+ # Ripgrep needs this manually set
+export RIPGREP_CONFIG_PATH=~/.config/ripgrep/config
+
+# Coloring ==========================================================
+# Truecolor support gives full rgb support. This looks something like:
+# \033[${bg};2;${red};${green};${blue};${special}m]
+#
+# For LS_COLORS and similar use:
+# 38;2;${red};${green};${blue};${special}:
+#
+# Special modes can be combined. `1` is bold, `4` is underlined, `1;4` is both
+# vim: set ft=bash ff=unix:
diff --git a/bash/.bash_functions b/bash/.bash_functions
new file mode 100644
index 0000000..8fb2330
--- /dev/null
+++ b/bash/.bash_functions
@@ -0,0 +1,162 @@
+#!/usr/bin/env bash
+
+# ===================================================================
+# Shell fixes
+# ===================================================================
+# SSH alias completion ==============================================
+_ssh()
+{
+ local cur prev opts
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ opts=$(grep '^Host' ~/.ssh/config ~/.ssh/config.d/* 2>/dev/null | grep -v '[?*]' | cut -d ' ' -f 2-)
+
+ COMPREPLY+=( $(compgen -W "$opts" -- ${cur}) )
+ return 0
+}
+complete -F _ssh ssh rpluto
+
+
+# Don't auto-executing line when leaving editor =====================
+_edit_wo_executing() {
+ local editor="${EDITOR:-vi}"
+ tmpf="$(mktemp)"
+ printf '%s\n' "$READLINE_LINE" > "$tmpf"
+ eval "${editor} ${tmpf}"
+ READLINE_LINE="$(<"$tmpf")"
+ READLINE_POINT="${#READLINE_LINE}"
+ rm -f "${tmpf}"
+}
+
+if [[ "$-" =~ "i" ]]; then
+ bind -x '"\C-x\C-e":_edit_wo_executing'
+ bind -x '"\C-g":_edit_wo_executing'
+fi
+
+# End up in the same directory as vifm exited in
+vifmmv() {
+ local dst="$(command vifm --choose-dir - "$@")"
+ if [ -z "$dst" ]; then
+ printf 'Directory was not changed\n'
+ return 1
+ fi
+ cd "$dst"
+}
+
+# Better exiting ====================================================
+# Don't exit with background jobs still running. Particularly for Qemu
+function exit () {
+ if [[ "$(jobs | wc -l)" -ne 0 ]]; then
+ printf 'Exit prevented.\nThere are background jobs:\n'
+ jobs
+ return 1
+ fi
+
+ builtin exit
+}
+
+# Necessary alias ===================================================
+russy () {
+ if [[ "$1" == "baka" ]]; then
+ cargo check
+ elif [[ $# -eq 0 ]] && [[ -e ./src/lib.rs ]]; then
+ cargo test
+ elif [[ $# -eq 0 ]]; then
+ cargo run
+ elif [[ $# -eq 1 ]] && [[ "$1" =~ \.rs$ ]]; then
+ rustc -C opt-level=3 "$1"
+ elif [[ "$1" == "run" && "$2" =~ \.rs$ ]]; then
+ rustc -C opt-level=3 "$2" && ./"${2%.*}"
+ else
+ eval "cargo $@"
+ fi
+}
+
+
+# ===================================================================
+# Switching color schemes
+# ===================================================================
+complete -W \
+ "--help --query dark light dracula github gruvboxdark gruvboxlight" \
+ colo colo.sh
+
+# ===================================================================
+# Additional utilities
+# ===================================================================
+# Colored pagination ================================================
+function bless () {
+ if [[ $1 =~ "-h" ]]; then
+ echo 'USAGE:'
+ echo ' bless '
+ else
+ # Do not quote $1. Prevents piped reads
+ if command -v bat &> /dev/null; then
+ bat --color=always $1 | less -r
+ #cat $1 | vim -R -c 'set ft=man nomod nolist' -c 'map q :q' \
+ # -c 'map ' -c 'map b ' \
+ # -c 'nmap K :Man =expand(\\\"\\\")' -
+ else
+ less -r $1
+ fi
+ fi
+}
+
+# Attach to tmux session ============================================
+function ta() {
+ if [[ -n "$1" ]]; then
+ tmux new -As "$1"
+ elif [[ -n "$TMUX" ]]; then
+ tmux switch-client -n
+ elif [[ ("${-}" =~ i && -z "${TMUX}" && -n "${SSH_CONNECTION}") || -n "${SSH_TTY}" ]]; then
+ tmux new-session -As ssh_tmux 2>&1 \
+ | grep -v 'sessions should be nested with care' # Don't care
+ else
+ tmux attach 2>/dev/null || tmux new -As 0
+ fi
+}
+
+# Image magick ======================================================
+function magika() {
+ if [[ "$1" == "a" || "$1" == "av1" ]]; then
+ magick convert "$2" "${2%.*}.avif"
+ elif [[ "$1" == "i" ]]; then
+ shift
+ magick identify "$@"
+ elif [[ "$1" == "c" ]]; then
+ shift
+ magick convert "$@"
+ else
+ magick "$@"
+ fi
+}
+
+# Make a directory and navigate into it =============================
+function cddir() {
+ if [[ "$#" -lt 1 ]] || [[ "$1" =~ '--help' ]]; then
+ echo 'Function: cddir()'
+ echo 'USAGE:'
+ echo ' cddir '
+ else
+ mkdir -p "$1" && cd ./"$1"
+ fi
+}
+
+# Change the prompt - alias for change_bash_prompt ==================
+function bprompt () {
+ source ~/.bash_prompt "$@"
+}
+
+# Enable truecolors over an ssh connection ==========================
+function truecolor () {
+ export COLORTERM='truecolor'
+
+ if command -v tmux has-session &> /dev/null; then
+ tmux setenv COLORTERM truecolor
+ fi
+
+ source ~/.bash_prompt
+}
+
+
+# vim: set ft=bash ff=unix:
diff --git a/bash/.bash_profile b/bash/.bash_profile
new file mode 100644
index 0000000..0cdbf3c
--- /dev/null
+++ b/bash/.bash_profile
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+
+# Source completion scripts ========================================
+source_completion_scripts () {
+ [ -r "/usr/local/etc/profile.d/bash_completion.sh" ] && . "/usr/local/etc/profile.d/bash_completion.sh"
+
+ [ -f ~/.git-completion.bash ] && . ~/.git-completion.bash
+
+ # Fzf
+ [ -f ~/.fzf.bash ] && . ~/.fzf.bash
+ # Arch uses a different location
+ [ -f /usr/share/fzf/key-bindings.bash ] && . /usr/share/fzf/key-bindings.bash
+
+ if [[ "$(type -t _fzf_setup_completion)" == 'function' ]]; then
+ _fzf_setup_completion path mpv vi vii nvim vimiv cat
+ fi
+}
+
+# Welcome prompts ===================================================
+print_version_and_platform () {
+ local os_name bash_version
+
+ if [[ -n "${BASH_VERSION}" ]]; then
+ bash_version="${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]}"
+ fi
+
+ case "$(uname)" in
+ Linux)
+ os_name="$(awk '/PRETTY_NAME/ {
+ split($0, a, "=")
+ gsub(/"/, "", a[2])
+ print a[2]
+ }' /etc/os-release)"
+ ;;
+ Darwin) os_name="MacOS $(sw_vers -productVersion)" ;;
+ esac
+
+ printf 'GNU bash %s on %s\n\n' \
+ "${bash_version:-Unknown}" "${os_name:-Unknown Platform}"
+}
+
+print_user_msg () {
+ local username tty_name
+
+ username="$(id -un)"
+ tty_name="$(tty | awk '{ print substr($0, 6) }')"
+
+ printf '%s: %s @ %s\n' \
+ "${username}" "${tty_name}" "${HOSTNAME}"
+}
+
+print_welcome_message () {
+ print_version_and_platform
+ cal
+ print_user_msg
+}
+
+# Login items =======================================================
+is_ssh_connection () {
+ [[ "${-}" =~ i ]] && [[ -z "${TMUX}" ]] && [[ -n "${SSH_CONNECTION}" ]] \
+ || [[ -n "${SSH_TTY}" ]]
+}
+
+has_tmux () {
+ command -v tmux &> /dev/null
+}
+
+set_starting_dir () {
+ if [[ "$PWD" == "$HOME" && -d ~/safe && "$IS_VIFM_NEST" != 'T' ]]; then
+ cd ~/safe
+ fi
+}
+
+# =============================================================================
+# Run script
+# =============================================================================
+source ~/.bashrc
+source ~/.bash_prompt
+
+[[ "$IS_VIFM_NEST" == 'T' ]] || print_welcome_message
+printf '\n'
+
+# Start in routing directory on login ====
+set_starting_dir
+
+# Attach ssh connections to a dedicated tmux session ====
+if is_ssh_connection && has_tmux; then
+ tmux new-session -As ssh_tmux 2>&1 \
+ | grep -v 'sessions should be nested with care' # We don't care
+fi
+
+# Bash completion ====
+source_completion_scripts
+
+# vim: set ft=bash ff=unix:
diff --git a/bash/.bash_prompt b/bash/.bash_prompt
new file mode 100755
index 0000000..15221f7
--- /dev/null
+++ b/bash/.bash_prompt
@@ -0,0 +1,112 @@
+#!/usr/bin/env bash
+export PS1
+
+function print_help () {
+ local invoke_name='change_bash_prompt'
+
+ cat << EOF
+Change the current bash prompt
+
+USAGE: $invoke_name [--help] [color-mode] [components ...]
+
+ [-h|--help] Show this message
+
+ host | hostname Hostname of system
+ tty Terminal's name
+ pwd | dir Present working directory
+ user Username
+ git Git branch
+ space | tab 4 white space characters
+ exit | code Last non-zero exit code
+
+EXAMPLES:
+ $invoke_name # Reset prompt
+ $invoke_name tty pwd git exit # Default prompt
+ $invoke_name tab tab user exit # Very minimal
+EOF
+}
+
+# Select color mode =================================================
+function is_default_prompt () {
+ [[ "$#" -eq 0 ]]
+}
+
+function exit_code () {
+ local code="$?"
+
+ if [[ "$code" != "0" ]]; then
+ printf " [%d]" "$code"
+ fi
+}
+
+function change_bash_prompt () {
+ # Set colors ======================================================
+ local purple='\[\033[0;35;1m\]'
+ local yellow='\[\033[0;33;1m\]'
+ local red='\[\033[0;31;1m\]'
+
+ # Prompt components ===============================================
+ local hostname="${purple}"'[\h]'
+ local tty="${purple}$(tty | cut -c6-12)"
+ local cwd="${yellow}"'\W'
+ local user="${red}"'\u'
+ local git="${user}"
+ local exit="${red}"'$(exit_code)'
+ local prompt_end='\[\e[m\]\$ ' # Trailing nbsp (u00A0) for tmux reverse search
+
+ if [ -f ~/.git-prompt.bash ]; then
+ local git="${red}"'$(__git_ps1 "(%s)")'
+ fi
+
+ local prompt=''
+
+ [[ "$IS_VIFM_NEST" != 'T' ]] || prompt+="" # Alert when nested in vifm
+
+ # Default prompts =================================================
+ if is_default_prompt "$@"; then
+ if [[ -n $SSH_TTY ]] || [[ -n $SSH_CLIENT ]] || [[ -n $SSH_CONNECTION ]]; then
+ prompt+="${hostname}:${cwd} ${git}${exit}"
+ else
+ prompt+="${tty}:${cwd} ${git}${exit}"
+ fi
+ fi
+
+ # Build customized prompts ========================================
+ local seperator=':'
+
+ for opt in "$@"; do
+ case "$opt" in
+ host | hostname) prompt+="$hostname" ;;
+ tty) prompt+="$tty" ;;
+ cwd | pwd | dir) prompt+="$cwd" ;;
+ user) prompt+="$user" ;;
+ exit | code) prompt+="$exit" ;;
+ git)
+ prompt+="$git"
+ seperator=''
+ ;;
+ space | tab)
+ prompt+=" "
+ seperator=''
+ ;;
+ -h | --help)
+ print_help "$@"
+ return 0
+ ;;
+ *)
+ printf 'Unrecognized option `%s`\n' "$opt"
+ printf 'Rerun with --help for more information\n'
+ return 1
+ ;;
+ esac
+
+ prompt+="$seperator"
+ seperator=' '
+ done
+
+ PS1="${prompt}${prompt_end}"
+}
+
+change_bash_prompt "$@"
+
+# vim: set ft=bash ff=unix:
diff --git a/bash/.bashrc b/bash/.bashrc
new file mode 100644
index 0000000..4be78d0
--- /dev/null
+++ b/bash/.bashrc
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+# Source all bash configs files, except prompt and profile
+# Adapted from https://github.com/mathiasbynens/dotfiles/blob/main/.bash_profile
+#
+# Source bash_functions twice to fix interdependency between bash_functions and
+# bash_aliases
+source ~/.bash_env
+source ~/.bash_functions
+source ~/.bash_aliases
+source ~/.bash_functions
+
+# shopt -s histappend
+
+# Suppress prompt warning when switching users
+if [[ -r ~/.git-prompt.bash ]]; then
+ source ~/.git-prompt.bash
+fi
diff --git a/bash/.inputrc b/bash/.inputrc
new file mode 100644
index 0000000..516b9fc
--- /dev/null
+++ b/bash/.inputrc
@@ -0,0 +1,22 @@
+# History selection in reverse search
+#"\e[A": history-search-backward
+#"\e[B": history-search-forward
+
+# These keybinds work in readline repls like python
+"\C-p": history-search-backward
+"\C-n": history-search-forward
+
+"\C-f": forward-char
+"\C-j": backward-char
+
+"\C-w": forward-word
+"\C-b": backward-word
+
+"\C-u": backward-kill-word
+
+"\C-l": complete
+
+set colored-stats On
+set completion-ignore-case
+
+# vim: set ff=unix ft=sh:
diff --git a/bash/.profile b/bash/.profile
new file mode 100644
index 0000000..0e6ecf7
--- /dev/null
+++ b/bash/.profile
@@ -0,0 +1,8 @@
+# Infinite history size
+export HISTFILESIZE=
+export HISTSIZE=
+export HISTTIMEFORMAT="%F %T: "
+# Different history file to avoid truncation
+export HISTFILE=~/.bash_eternal_history
+
+# vim: set ft=sh ff=unix:
diff --git a/bin/battery_status.sh b/bin/battery_status.sh
new file mode 100755
index 0000000..44b01ca
--- /dev/null
+++ b/bin/battery_status.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# Filters out and prettifies battery information
+upower --dump | awk '
+ /Device/ {
+ device[++devices_cnt]["name"] = substr($0, 41);
+ i = 1;
+ }
+
+ /(energy|state|percentage|time to)/ { device[devices_cnt][i++] = $0 }
+
+ /model/ {
+ split($0, a);
+
+ for (k in a)
+ if (!(tolower(a[k]) ~ /model:/))
+ device[devices_cnt]["model"] = device[devices_cnt]["model"] " " a[k];
+ }
+
+ END {
+ for (dev in device) {
+ if (length(device[dev]["model"]) > 0)
+ printf "====%s :: %s ========\n",
+ device[dev]["model"], device[dev]["name"];
+ else
+ printf "==== %s ========\n", device[dev]["name"];
+
+ asort(device[dev]);
+
+ for (i in device[dev]) {
+ is_name = (tolower(device[dev][i]) ~ /(device|model)/);
+ is_label = (device[dev][i] ~ /:/);
+
+ if (!is_name && is_label)
+ printf "%s\n", device[dev][i];
+ }
+ }
+ }
+'
diff --git a/bin/check_domain.sh b/bin/check_domain.sh
new file mode 100755
index 0000000..7150e67
--- /dev/null
+++ b/bin/check_domain.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+print_help() {
+ cat <
+HELP
+}
+
+if [[ "$1" =~ ^[a-z0-9-]+(\.[a-z]+)+$ ]]; then
+ whois "$1" | awk -v d_name="$1" '
+ BEGIN { is_available = 1 }
+
+ /Updated Date/ { is_available = 0; print }
+ /Creation Date/ { is_available = 0; print }
+ /Registry Expiry Date/ { is_available = 0; print }
+
+ END {
+ if (is_available) {
+ printf "%s is available!!!\n", d_name
+ system("notify-send -u critical -t 3600000 \""d_name"\" \"Domain "d_name" is available!\"")
+ }
+ }
+ '
+else
+ print_help
+fi
diff --git a/bin/colo.sh b/bin/colo.sh
new file mode 100755
index 0000000..52f8d3d
--- /dev/null
+++ b/bin/colo.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+# Warning: Many other files in these configs depend on this script. Do not
+# rename it or remove it from ~/.configs_pointer/bin/ unnecessarily
+__print_color_help() {
+ cat < "$tmp"
+ mv -f "$tmp" "$ALACRITTY_COLO"
+}
+
+__change_vimiv_colors() {
+ if [[ -w "$VIMIV_CONF" ]]; then
+ local tmp="$(mktemp)"
+ awk -v c="$COLOR_SCHEME" '/^\s*style = /{ $3=c } 1' "$VIMIV_CONF" > "$tmp"
+ mv -f "$tmp" "$VIMIV_CONF"
+ fi
+}
+
+case "$1" in
+ -t | --tone) __query_color_tone ;;
+ -c | --colorscheme) echo "$COLOR_SCHEME" ;;
+ -q | --query) __print_current_colors ;;
+ -h | --help) __print_color_help ;;
+ light | gruvboxlight) __change_colors_to "base16-gruvbox-light-hard" ;;
+ dracula) __change_colors_to "base16-dracula" ;;
+ github) __change_colors_to "base16-github" ;;
+ dark | gruvboxdark) __change_colors_to "base16-gruvbox-dark-pale" ;;
+ *) __print_color_help ;;
+esac
diff --git a/bin/ix.sh b/bin/ix.sh
new file mode 100755
index 0000000..18e4b83
--- /dev/null
+++ b/bin/ix.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# Pastebin for terminal. Copies the paste's URL to the clipboard
+#
+# ix.io isn't very responsive, so it may appear to freeze for a few seconds
+#
+# Use with visual selection in vim:
+# !ix.sh
+#
+# Lifted from: https://exobrain.sean.fish/vim/magic_wands/
+
+if [[ $1 =~ '-h' ]]; then
+ declare -r name="$(basename "$0")"
+
+ cat <> /tmp/ix.log <<<"${STDIN}"
+
+declare url="$(curl -s -F 'f:1=<-' http://ix.io <<<"${STDIN}")" || {
+ play_error_sound
+ exit 1
+}
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ printf '%s' "${url}" | pbcopy
+ osascript -e 'display notification "'"URL: ${url}"'" with title "Vim" subtitle "Copied to clipboard"'
+else
+ printf '%s' "${url}" | wl-copy
+ notify-send -t 2000 'Vim' 'Copied ix url to wl-clipboard'
+fi
+
+# vim: set syn=bash ff=unix:
diff --git a/bin/kat b/bin/kat
new file mode 100755
index 0000000..b6f57fc
--- /dev/null
+++ b/bin/kat
@@ -0,0 +1,366 @@
+#!/usr/bin/env python3
+# Compiler and tester for kattis problems
+#
+# kat expects a ./sample directory with files named /input_[0-9]+/ and a
+# corresponding /output_[0-9]+/ file. These will be run in sequence from lowest
+# to highest number
+#
+# Supported languages:
+# - Rust: Expects a ./src/main.rs file, as well as a ./Cargo.toml
+# - Python: Expects with a single .py file or a main.py or ./src/main.py
+# - C: Expects a ./main.c file or ./src/main.c
+import argparse, sys, os, pathlib, time, subprocess, re
+from abc import ABC, abstractmethod
+from typing import Tuple
+from pathlib import Path
+
+class ProgrammingLang(ABC):
+ @abstractmethod
+ def __init__(self, root: Path, main_file: Path):
+ pass
+
+ @abstractmethod
+ def compile_debug(self):
+ pass
+
+ @abstractmethod
+ def compile_release(self):
+ pass
+
+ @abstractmethod
+ def run_debug(self, input_file, output_file) -> int:
+ pass
+
+ @abstractmethod
+ def run_release(self, input_file, output_file) -> int:
+ pass
+
+class Rust(ProgrammingLang):
+ def __init__(self, root: Path, main_file: Path):
+ self.main_file = main_file
+ self.root = root
+ self.bin_name = root.name
+ self.release_bin = os.path.join(root, 'target', 'release', self.bin_name)
+ self.debug_bin = os.path.join(root, 'target', 'debug', self.bin_name)
+
+ def compile_debug(self):
+ cmd = subprocess.run(['cargo', 'build'], cwd=self.root)
+ if cmd.returncode != 0:
+ raise Exception(f'Compile time error: code {cmd.returncode}')
+
+ def compile_release(self):
+ cmd = subprocess.run(['cargo', 'build', '--release'], cwd=self.root)
+ if cmd.returncode != 0:
+ raise Exception(f'Compile time error: code {cmd.returncode}')
+
+ def __run(self, input_file, output_file, sub_dir: Path) -> int:
+ start = time.time()
+ cmd = subprocess.run(
+ os.path.join(self.root, 'target', sub_dir, self.bin_name),
+ stdin=input_file, stdout=output_file)
+ end = time.time()
+ if cmd.returncode != 0:
+ raise Exception(f'Runtime error: code {cmd.returncode}')
+ return end - start
+
+ def run_debug(self, input_file, output_file) -> int:
+ return self.__run(input_file, output_file, 'debug')
+
+ def run_release(self, input_file, output_file) -> int:
+ return self.__run(input_file, output_file, 'release')
+
+class Clang(ProgrammingLang):
+ def __init__(self, root: Path, main_file: Path):
+ self.main_file = main_file
+ self.root = root
+ self.bin_name = 'clang_out'
+ self.release_bin = self.debug_bin = os.path.join(root, self.bin_name)
+
+ def compile_debug(self):
+ cmd = subprocess.run([
+ 'gcc', '-Wall', '-Wextra', '-Werror',
+ '-g', '-O2', '-std=gnu11', '-static',
+ self.main_file,
+ '-o', self.debug_bin, '-lm'
+ ])
+ if cmd.returncode != 0:
+ raise Exception(f'Compile time error: code {cmd.returncode}')
+
+ def compile_release(self):
+ cmd = subprocess.run([
+ 'gcc', '-g', '-O2', '-std=gnu11', '-static',
+ self.main_file,
+ '-o', self.release_bin, '-lm'
+ ])
+ if cmd.returncode != 0:
+ raise Exception(f'Compile time error: code {cmd.returncode}')
+
+ def run_debug(self, input_file, output_file) -> int:
+ return self.run_release(input_file, output_file)
+
+ def run_release(self, input_file, output_file) -> int:
+ start = time.time()
+ cmd = subprocess.run(self.release_bin,
+ stdin=input_file, stdout=output_file)
+ end = time.time()
+ return end - start
+
+class CPlusPlus(ProgrammingLang):
+ def __init__(self, root: Path, main_file: Path):
+ self.main_file = main_file
+ self.root = root
+ self.bin_name = 'clang_out'
+ self.release_bin = self.debug_bin = os.path.join(root, self.bin_name)
+
+ def compile_debug(self):
+ cmd = subprocess.run([
+ 'g++', '-g', '-O2', '-std=gnu++17', '-static',
+ '-lrt', '-Wl,--whole-archive', '-lpthread',
+ '-Wl,--no-whole-archive',
+ '-Wall', '-Wextra', '-Werror',
+ self.main_file,
+ '-o', self.release_bin
+ ])
+ if cmd.returncode != 0:
+ raise Exception(f'Compile time error: code {cmd.returncode}')
+
+ def compile_release(self):
+ cmd = subprocess.run([
+ 'g++', '-g', '-O2', '-std=gnu++17', '-static',
+ '-lrt', '-Wl,--whole-archive', '-lpthread',
+ '-Wl,--no-whole-archive',
+ self.main_file,
+ '-o', self.release_bin
+ ])
+ if cmd.returncode != 0:
+ raise Exception(f'Compile time error: code {cmd.returncode}')
+
+ def run_debug(self, input_file, output_file) -> int:
+ return self.run_release(input_file, output_file)
+
+ def run_release(self, input_file, output_file) -> int:
+ start = time.time()
+ cmd = subprocess.run(self.release_bin,
+ stdin=input_file, stdout=output_file)
+ end = time.time()
+ return end - start
+
+class Python(ProgrammingLang):
+ def __init__(self, root: Path, main_file: Path):
+ self.main_file = main_file
+ self.root = root
+ self.bin_name = main_file.name
+ self.release_bin = self.debug_bin = main_file
+
+ def compile_debug(self):
+ pass
+
+ def compile_release(self):
+ pass
+
+ def __run(self, input_file, output_file, interpreter) -> int:
+ start = time.time()
+ cmd = subprocess.run([interpreter, self.release_bin],
+ stdin=input_file, stdout=output_file)
+ end = time.time()
+
+ if cmd.returncode != 0:
+ raise Exception(f'Runtime error: {cmd.returncode}')
+ return end - start
+
+ def run_debug(self, input_file, output_file) -> int:
+ return self.__run(input_file, output_file, '/usr/bin/python3')
+
+ def run_release(self, input_file, output_file) -> int:
+ return self.__run(input_file, output_file, '/usr/bin/pypy3')
+
+# Returns the language object
+def find_language(root: Path):
+ ls = os.listdir(root)
+
+ if 'src' in ls:
+ src = os.listdir(os.path.join(root, 'src'))
+
+ if 'main.rs' in src:
+ return Rust(root, Path('src', 'main.rs'))
+ elif 'main.c' in src:
+ return Clang(root, Path('src', 'main.c'))
+ elif 'main.cc' in src:
+ return CPlusPlus(root, Path('src', 'main.cc'))
+ elif 'main.cpp' in src:
+ return CPlusPlus(root, Path('src', 'main.cpp'))
+ elif 'main.py' in src:
+ return Python(root, Path('src', 'main.py'))
+ elif '.py' in '\t'.join(ls):
+ return Python(root, Path('src', next(p for p in ls if '.py' in p)))
+
+ if 'main.rs' in ls:
+ return Rust(root, Path('main.rs'))
+ elif 'main.c' in ls:
+ return Clang(root, Path('main.c'))
+ elif 'main.cc' in ls:
+ return CPlusPlus(root, Path('main.cc'))
+ elif 'main.cpp' in ls:
+ return CPlusPlus(root, Path('main.cpp'))
+ elif 'main.py' in ls:
+ return Python(root, Path('main.py'))
+ elif '.py' in '\t'.join(ls):
+ return Python(root,
+ Path(os.path.join(root, next(p for p in ls if '.py' in p))))
+
+ raise Exception('Language not found or not supported')
+
+def project_root() -> Path:
+ cwd = Path('.').cwd()
+ if cwd.name == 'sample' or cwd.name == 'src':
+ return cwd.parent
+ return cwd
+
+def test_files(root: Path, nb: int) -> Tuple[Path, Path, Path]:
+ t_input = os.path.join(root, f'sample/input_{nb}')
+ t_output = os.path.join(root, f'sample/output_{nb}')
+ real_output = os.path.join(root, f'sample/run_output_{nb}')
+
+ return t_input, t_output, real_output
+
+def is_test_exists(n: str, root: Path) -> bool:
+ samples = os.listdir(os.path.join(root, 'sample'))
+
+ if f'input_{n}' not in samples:
+ print(f'sample/input_{n} not found')
+ return False
+
+ if f'output_{n}' not in samples:
+ print(f'sample/output_{n} not found')
+ return False
+
+ return True
+
+def run_test(lang, n: int, root: Path, is_time: bool, is_debug: bool) -> bool:
+ t_in_name, t_out_name, r_out_name = test_files(root, n)
+
+ r_out = open(r_out_name, 'w')
+ t_out = open(t_out_name, 'r')
+ t_in = open(t_in_name, 'r')
+
+ print(f"==== Testcase {n} ====")
+ if is_debug:
+ run_time = lang.run_debug(t_in, r_out)
+ else:
+ run_time = lang.run_release(t_in, r_out)
+
+ t_in.close()
+ r_out.close()
+
+ if is_time:
+ print("^^^^^^^^^^^^^^^^^^^^^^")
+ print(f"Time: {run_time : 4.3f}s")
+
+ r_out = open(r_out_name, 'r')
+
+ lines_real = r_out.read().splitlines()
+ lines_out = t_out.read().splitlines()
+
+ t_out.close()
+ r_out.close()
+
+ if len(lines_real) != len(lines_out):
+ if not is_time:
+ print("^^^^^^^^^^^^^^^^^^^^^^")
+ print(f"!!! Mismatched output\n"
+ f"Real line count: {len(lines_real)}\n"
+ f"Expected line count: {len(lines_out)}")
+ print(f'!!! Failed on test {n}. See ./sample/run_output_{n}')
+ return False
+
+ for i in range(len(lines_real)):
+ if lines_real[i] != lines_out[i]:
+ if not is_time:
+ print("^^^^^^^^^^^^^^^^^^^^^^")
+ print(f"!!! Mismatched output\n"
+ f"Real Output: `{lines_real[i]}`\n"
+ f"Expected Out: `{lines_out[i]}`")
+
+ print(f'!!! Failed on test {n}. See ./sample/run_output_{n}')
+ return False
+
+ return True
+
+# Returns True if all cases passed. Otherwise returns False and the number of
+# test cases
+def run_tests(lang, root: Path, is_time: bool, is_debug: bool) -> Tuple[bool, int]:
+ try:
+ sample_dir = os.listdir(os.path.join(root, 'sample'))
+ except FileNotFoundError:
+ print("No ./sample directory found. Cannot test script")
+ return [False, None]
+
+ cases = list(filter(lambda x: x is not None,
+ [re.match(r'^input_([0-9]+)$', f) for f in sample_dir]))
+
+ for case in cases:
+ if not is_test_exists(case.group(1), root):
+ raise Exception()
+
+ N = len(cases)
+ cases.sort(key=lambda x: x.group(0))
+
+ for case in cases:
+ try:
+ if not run_test(lang, case.group(1), root, is_time, is_debug):
+ return False, N
+ except Exception as e:
+ print(e)
+ return False, N
+
+ return True, N
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Compiler and tester for kattis problems')
+
+ parser.add_argument("-t", "--time", action="store_true",
+ help="Time the runtime of each test case")
+ parser.add_argument("-d", "--debug", action="store_true",
+ help="Use the debugging compiler")
+ parser.add_argument("test_case", type=str, metavar='T', nargs='?',
+ help="Time one specific test case in debug")
+
+ args = parser.parse_args()
+ root = project_root()
+
+ try:
+ lang = find_language(root)
+ except Exception as e:
+ print(f'Failed to detect language: {e}')
+ sys.exit(1)
+
+ try:
+ if args.debug or args.test_case is not None:
+ lang.compile_debug()
+ else:
+ lang.compile_release()
+ except Exception as e:
+ print(e)
+ sys.exit(1)
+
+ if args.test_case is not None:
+ if is_test_exists(args.test_case, root):
+ if run_test(lang, args.test_case, root, True, True):
+ print(f'Passed test case ({args.test_case})')
+ else:
+ is_passed, n = run_tests(lang, root,
+ args.time or args.test_case,
+ args.debug or args.test_case)
+ if is_passed:
+ print(f'All test ({n}) cases passed!')
+
+if __name__ == '__main__':
+ try:
+ main()
+ except KeyboardInterrupt:
+ print("\nKeyboard interrupt. Program killed");
+ sys.exit(1)
+ else:
+ sys.exit(0)
diff --git a/bin/lgrep b/bin/lgrep
new file mode 100755
index 0000000..9c7382c
--- /dev/null
+++ b/bin/lgrep
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+# Greps file and directory names in given directory for a pattern. If no
+# directory is provided, the present working directory is used
+search_pattern="${1}"
+directory="${2:-$PWD}"
+
+print_help () {
+ local exe_name="$(basename "${0}")"
+
+ cat << HELP_MSG
+List file names matching matching the pattern in a directory
+USAGE:
+ ${exe_name} [dir]
+
+EXAMPLES:
+ ${exe_name} bash ~
+ ${exe_name} rc
+HELP_MSG
+}
+
+is_help () {
+ [[ "${#}" -eq 0 ]] || [[ "${1}" == '--help' ]] || [[ "${1}" == '-h' ]]
+}
+
+#define_colors () {
+# local colors
+# IFS=: colors=(${EXA_COLORS})
+#
+# for color in "${colors[@]}"; do
+# case "${color}" in
+# fi*)
+# color_file='\033['"$(cut -c 4- <<<"${color}")"'' ;;
+# ln*)
+# color_link='\033['"$(cut -c 4- <<<"${color}")"'' ;;
+# esac
+# done
+#}
+
+
+if is_help "${@}"; then
+ print_help "${0}"
+
+elif command -v fd &> /dev/null; then
+ for match in $(fd -aIHd1 "${search_pattern}" "${directory}"); do
+ printf '%s' "$(basename "${match}")"
+
+ if [[ -h "${match}" ]]; then
+ printf ' -> %s'\
+ "$(readlink "${match}" | awk '{ sub("'"$HOME"'", "~"); print }')"
+ fi
+
+ printf '\n'
+ done
+else
+ listlong -a "${directory}" | grep -i --color=always "${search_pattern}"
+fi
+
+# ex: set syntax=bash ff=unix:
diff --git a/bin/listlong b/bin/listlong
new file mode 100755
index 0000000..21b31e4
--- /dev/null
+++ b/bin/listlong
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+#
+# Print a directory listing with multiple default presets. Uses `exa` when
+# available
+#
+# WARNING: Many scripts and aliases in these dotfiles depend on this script. Do
+# not rename it or remove it from $PATH unnecessarily
+
+print_help () {
+ cat << EOF
+Directory listing with sensible defaults. Wraps around 'ls' and 'exa'
+
+USAGE: $(basename "$0") [listing-type] [pass-through-args] [dir]
+
+ [-h|--help] Show this message
+
+ --ll-tree Display a recursive tree hierarchy
+ --ll-git-tree Display a tree following rules in .gitignore
+ --ll-dir-tree Display a tree of directories only
+ --ll-all Display extensive information about the current directory
+ --ll-links List symlinks in the current directory
+ --ll-ls Use of 'ls', even if 'exa' is available
+
+ * Passed as argument to 'exa' or 'ls'
+EOF
+}
+
+declare PRESET PASS_THROUGH FORCE_LS
+
+for opt in "$@"; do
+ case "$opt" in
+ --ll-*)
+ [[ -z "${PRESET}" ]] || continue # Only read first preset argument passed
+
+ case "$opt" in
+ --ll-tree) # Tree List Long - Recursively print a tree view
+ PRESET='-I ".git|target" --tree'
+ ;;
+ --ll-git-tree) # Git List Long - Recursively print a tree view following .gitignore
+ PRESET='--git-ignore --tree'
+ ;;
+ --ll-dir-tree) # Directories List Long - List the directory hierarchy
+ PRESET='--only-dirs --tree'
+ ;;
+ --ll-all) # All List Long - Detailed information for files in current working dir
+ PRESET='--all --header --links --blocks --group --modified --created --accessed'
+ ;;
+ --ll-ls) # Use ls instead of exa. Solves odd exa bugs
+ FORCE_LS='T'
+ ;;
+ --ll-links) # List symlinks
+ PRESET='--color=always | awk "/->/"'
+ ;;
+ esac
+ ;;
+ -h | --help)
+ print_help
+ exit 0
+ ;;
+ *)
+ PASS_THROUGH+="$opt "
+ ;;
+ esac
+done
+
+
+if command -v exa &> /dev/null && [[ "${FORCE_LS}" != 'T' ]]; then
+ eval "exa --long --sort=size --git --group-directories-first ${PRESET} ${PASS_THROUGH}"
+elif ! ls --color &> /dev/null; then
+ # MacOS default ls
+ eval "ls -lhSrG ${PASS_THROUGH}"
+else
+ # GNU ls or similar
+ eval "ls -lhSrG --color --group-directories-first ${PASS_THROUGH}"
+fi
diff --git a/bin/lyrics_to_html.py b/bin/lyrics_to_html.py
new file mode 100755
index 0000000..eb4b67a
--- /dev/null
+++ b/bin/lyrics_to_html.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+import argparse, os, subprocess, sys
+
+def html_body(lyrics: list) -> str:
+ html_body = str();
+
+ is_in_stanza = False;
+ lines_in_stanza = 0;
+
+ for line in lyrics:
+ if not is_in_stanza: # Open new stanza
+ html_body += f'{"":>6}\n';
+ is_in_stanza = True
+ lines_in_stanza = 0
+
+ if line == '\n' and lines_in_stanza > 0: # Close stanza
+ html_body += f'{"":>6}
\n\n'
+ is_in_stanza = False
+ elif line != '\n': # Add non-blank line to stanza
+ html_body += f'{"":>10}{line.strip()}\n'
+ lines_in_stanza += 1
+
+ html_body += f'{"":>6}
\n\n'
+ return html_body
+
+
+def html_from_template(title, icon, body, url) -> str:
+ return html_template_top(title, icon) \
+ + body \
+ + html_template_bottom(title, url);
+
+
+html_template_top = lambda title, icon : """\
+
+
+
+
+
+ """ + title + """
+
+
+
+
+
+"""
+
+html_template_bottom = lambda title, url : f"""
+
+ Link to video: {str(title)}
+
+
+
+"""
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Quickly create an html file from lyrics');
+ parser.add_argument('-t', '--title', metavar='', type=ascii);
+ parser.add_argument('-u', '--url', metavar='', type=ascii);
+ parser.add_argument('-i', '--icon', metavar='', type=ascii);
+ parser.add_argument('-d', '--download', metavar='', type=ascii,
+ help='Download mp3 from url');
+ parser.add_argument('file', type=ascii, nargs='?',
+ help='Read lyrics from file');
+ args = parser.parse_args();
+
+ if args.file is not None or not sys.stdin.isatty():
+ title = args.title[1:-1] if args.title is not None else '';
+ url = args.url[1:-1] if args.url is not None else '';
+ icon = args.icon[1:-1] if args.icon is not None else '';
+
+ # Read lyrics lines
+ if args.file is not None:
+ lyrics_file = open(args.file[1:-1], 'r');
+ lyrics = lyrics_file.readlines();
+ else:
+ lyrics = sys.stdin.readlines();
+
+ body = html_body(lyrics);
+ html = html_from_template(title, icon, body, url);
+
+ sys.stdout.write(html);
+ sys.exit(0);
+ else:
+ parser.print_help();
+ sys.exit(1);
diff --git a/bin/myip b/bin/myip
new file mode 100755
index 0000000..a228b22
--- /dev/null
+++ b/bin/myip
@@ -0,0 +1,67 @@
+#!/bin/bash
+# List system's WAN and LAN ip addresses
+# Depends on ifconfig and awk
+
+if [[ $1 =~ '-h' ]]; then
+ cat < /dev/null; then
+ ip address | awk_lan 'substr(info[2], 2)'
+elif command -v ifconfig &> /dev/null; then
+ ifconfig | awk_lan 'info[1]'
+else
+ echo '`ifconfig` not found'
+fi
+
+# Print network's public IP address
+if command -v dig &> /dev/null; then
+ public_ip=$(dig +short myip.opendns.com @resolver2.opendns.com)
+elif command -v host &> /dev/null; then
+ public_ip=$(host myip.opendns.com resolver1.opendns.com)
+fi
+
+# Backup address fetching. Slower though more reliable
+if [[ -z $public_ip ]]; then
+ if command -v curl &> /dev/null; then
+ public_ip=$(curl --silent https://ifconfig.me/ip)
+ elif command -v wget &> /dev/null; then
+ public_ip=$(wget --quiet -O - https://ifconfig.me/ip)
+ fi
+fi
+
+
+if [[ -n $public_ip ]]; then
+ echo "$public_ip" | awk ' match($0, /([0-9]{1,3}\.){3}[0-9]{1,3}$/) {
+ printf("Public (WAN): %s\n", substr($0, RSTART, RLENGTH))
+ }'
+else
+ echo 'Public IP not found'
+fi
diff --git a/bin/notes b/bin/notes
new file mode 100755
index 0000000..7bd605a
--- /dev/null
+++ b/bin/notes
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# Read notes files from ~/.configs_pointer/notes
+if [[ $1 =~ '-h' ]]; then
+ printf 'Open notes files from ~/.configs_pointer/notes\n'
+ exit 0
+elif ! [[ -h ~/.configs_pointer ]]; then
+ cat </dev/null; then
+ printf 'Requires fzf\n'
+ exit 1
+fi
+
+
+# Fzf for notes file
+if command -v fd &> /dev/null; then
+ notes_file=~/.configs_pointer/notes/"$(fd '.md' ~/.configs_pointer/notes -x basename | fzf)"
+else
+ notes_file="$(find ~/.configs_pointer/notes -type f | fzf)"
+fi
+
+
+# Use best available pagenator
+if command -v nvim &>/dev/null; then
+ nvim -R "${notes_file}"
+elif command -v vim &>/dev/null; then
+ vim -R "${notes_files}"
+elif command -v bat &>/dev/null; then
+ bat --paging=always "${notes_file}"
+else
+ less "${notes_file}"
+fi
+
diff --git a/bin/play_error_sound.sh b/bin/play_error_sound.sh
new file mode 100755
index 0000000..bed28d8
--- /dev/null
+++ b/bin/play_error_sound.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# Play MacOS system error sound: System Preferences -> Sound -> Sound Effects
+
+if [[ $(uname) == 'Darwin' ]]; then
+ afplay $(defaults read .GlobalPreferences.plist \
+ | awk '/sound.beep.sound"/ { gsub(/(.*= ")|(";)/, ""); print }')
+fi
+
+# vim: set syntax=bash ff=unix:
diff --git a/bin/prettify_bash_history.awk b/bin/prettify_bash_history.awk
new file mode 100755
index 0000000..aba8ad1
--- /dev/null
+++ b/bin/prettify_bash_history.awk
@@ -0,0 +1,9 @@
+#!/usr/bin/env -S awk -f
+# Translate the unix-timestamps in bash history to dates. Requires gnu `date`
+{
+ if ($0 ~ /^#[0-9]+$/)
+ system("date -d @" substr($0, 2));
+ else
+ print " "$0
+}
+
diff --git a/bin/random_password.sh b/bin/random_password.sh
new file mode 100755
index 0000000..859c79e
--- /dev/null
+++ b/bin/random_password.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+print_help() {
+ cat <
+
+Examples:
+ $(basename "$0") 20 | wl-copy
+ $(basename "$0") 400 > key_file
+
+Special characters: /[;-]/
+
+Length must be at least $MIN_PASSWORD_LENGTH. Passwords are generated until one of each a
+lowercase, uppercase, digit, and special character are in the password.
+Both special characters are required for passwords >=$LONG_PASSWORD_LENGTH characters long.
+Really long passwords have at least 2 of each special character.
+HELP
+}
+
+shopt -s lastpipe
+declare -ri LONG_PASSWORD_LENGTH=15 MIN_PASSWORD_LENGTH=6
+declare -gri LENGTH="$1"
+declare password=""
+
+generate_password() {
+ dd if=/dev/urandom bs=3 count="$(( 10 * LENGTH ))" 2>/dev/null \
+ | base64 -w0 \
+ | tr '/' '-' \
+ | tr '+' ';' \
+ | cut -c "1-$LENGTH" \
+ | read -r password
+}
+
+contains_characterset() {
+ local p="$password"
+ if [[ $LENGTH -ge $(( 2*LONG_PASSWORD_LENGTH )) ]]; then
+ [[ $p =~ [A-Z] && $p =~ [a-z] && $p =~ [0-9] && $p =~ \;.+\; && $p =~ -.+- ]]
+ elif [[ $LENGTH -ge $LONG_PASSWORD_LENGTH ]]; then
+ [[ $p =~ [A-Z] && $p =~ [a-z] && $p =~ [0-9] && $p =~ \; && $p =~ - ]]
+ else
+ [[ $p =~ [A-Z] && $p =~ [a-z] && $p =~ [0-9] ]] && [[ $p =~ \; || $p =~ - ]]
+ fi
+}
+
+if [[ "$1" =~ ^[0-9]+$ && $1 -ge $MIN_PASSWORD_LENGTH ]]; then
+ while ! contains_characterset; do
+ generate_password "$1"
+ done
+
+ echo "$password"
+else
+ print_help
+ exit 1
+fi
diff --git a/bin/rpluto.sh b/bin/rpluto.sh
new file mode 100755
index 0000000..db70e24
--- /dev/null
+++ b/bin/rpluto.sh
@@ -0,0 +1,109 @@
+#!/usr/bin/env bash
+
+print_long_help() {
+ cat <]
+
+FLAGS:
+ -h, --help show this help message and exit
+
+OPTIONS:
+ -p Port use for on host for the Pluto Server
+
+ARGS:
+ Port on client to connect Pluto Server
+ Either an ~/.ssh/config alias or the host address
+EOF
+}
+
+print_short_help() {
+ cat <]
+
+For more information try --help
+EOF
+}
+
+print_start_msg() {
+ cat </dev/null
+ fi
+
+ ssh -L "$1":localhost:"${3:-7000}" "$2"\
+ "julia -e\
+ \"import Pluto;
+ Pluto.run(
+ port=${3:-7000},
+ require_secret_for_open_links=false,
+ require_secret_for_access=false
+ )\""
+}
+
+exit_msg(){
+ printf "\nNotebook has been shutdown\n"
+ exit 0
+}
+
+
+# Print help and exit ====
+if [[ $1 == '--help' ]]; then
+ print_long_help
+ exit 0
+elif [[ "$1" =~ '-h' ]]; then
+ print_short_help
+ exit 0
+fi
+
+
+# Parse arguments ====
+positional_args=()
+
+while [[ "$#" -gt 0 ]]; do
+ arg="$1"
+
+ case $arg in
+ -p)
+ host_port="$2"
+ shift
+ shift
+ ;;
+ *)
+ positional_args+=("$1")
+ shift
+ ;;
+ esac
+done
+
+set -- "${positional_args[@]}"
+
+# Set graceful exit
+if [[ "$#" -eq 2 ]]; then
+ trap exit_msg SIGINT
+
+ print_start_msg "$1"
+
+ ssh_pluto_tunnel $1 $2 $host_port
+else
+ print_short_help
+ exit 2
+fi
diff --git a/bin/screenshot_wayland.sh b/bin/screenshot_wayland.sh
new file mode 100755
index 0000000..12d9b89
--- /dev/null
+++ b/bin/screenshot_wayland.sh
@@ -0,0 +1,241 @@
+#!/usr/bin/env bash
+# Take and resize screenshots on wayland
+#
+# Input sources: Full, selection, dimensions, latest taken screenshot
+# Filters: Resize, drop-shadow
+# Output sources: File, clipboard
+#
+# Screenshot default: .png
+# Resize default: .avif
+#
+# Each screenshot has 1 or more input sources and 1 or more output sources. The
+# image extention is determined by the output file, --extension option, or
+# defaults. Regardless of extension, every screenshot is first saved as a
+# lossless PNG then converted to other formats. All intermediate files are
+# saved in a temporary directory set by the --tmp-dir option
+#
+# Setting the --tmp-dir alongside the --resize option will modify the latest
+# image in that directory
+print_help() {
+ cat < [FILE]
+
+FLAGS:
+ -c, --clipboard Save the screenshot to your clipboard
+ -h, --help Print this help message and exit
+
+OPTIONS:
+ -d, --drop-shadow Save the screenshot with a drop-shadow on a white background
+ -e, --extension Change image extention saved
+ -r, --resize Resize the latest screenshot instead of taking a new one
+ -s, --size Screenshot exact dimensions
+ -t, --tmp-dir Set the temporary save and resize source directory
+
+ARGS:
+ area Takes a screenshot of an area selected by the mouse. Like cmd+shift+4
+ full Screenshots the full screen
+ markup Edit latest image in swappy. Incompatible with most options
+
+EXAMPLES:
+ $(basename "$1") full ~/Pictures/elaina_bubble_tea.png
+ $(basename "$1") -c area ~/Pictures/elaina_bubble_tea.png
+ $(basename "$1") -c -d 10 -s '20,400 200x180' ~/Pictures/elaina_bubble_tea.png
+ $(basename "$1") --resize 80% ~/Pictures/elaina_bubble_tea.webp
+
+Saves full original copy under /tmp/screenshots_tmp/. The latest resize is
+available at [FILE] or in the clipboard.
+
+Make sure to specify --clipboard or a file path. There is no default!
+HELP
+}
+
+declare CROP SHADOW IS_CLIPBOARD IS_SWAPPY OUTPUT_PATH RESIZE EXT TMP_DIR TMP_PATH
+declare -r SLURP_REGEX="^[0-9]+,[0-9]+[[:space:]][0-9]+x[0-9]+$"
+
+# Not possible to call script without 2 args
+parse_args() {
+ if [[ $# -eq 0 ]]; then
+ print_help "$0"
+ return 1
+ fi
+
+ while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -c | --clipboard)
+ IS_CLIPBOARD=true
+ shift
+ ;;
+ -d | --drop-shadow)
+ shift
+ if [[ "$1" =~ ^[0-9]+x[0-9]+$ ]]; then
+ SHADOW="$1"
+ elif [[ "$1" =~ ^[0-9]+$ ]]; then
+ SHADOW="${1}x${1}"
+ else
+ printf 'No size argument found for --drop-shadow option\n'
+ return 2
+ fi
+ shift
+ ;;
+ -e | --extension)
+ shift
+ if [[ "$1" =~ ^\.[a-z0-9]+$ ]]; then
+ EXT="${1:1}"
+ elif [[ "$1" =~ ^[a-z0-9]+$ ]]; then
+ EXT="$1"
+ fi
+ shift
+ ;;
+ -r | --resize)
+ shift
+ if [[ "$1" =~ [0-9]+%$ ]]; then
+ RESIZE="$1"
+ elif [[ "$1" =~ [0-9]+$ ]]; then
+ RESIZE="$1%"
+ else
+ printf 'Resize amount not specified. Ex: 100%% or 20\n'
+ return 2
+ fi
+ shift
+ ;;
+ -s | --size)
+ shift
+ if [[ "$1" =~ $SLURP_REGEX ]]; then
+ CROP="$1"
+ else
+ printf 'No dimension argument found for --tmp-dir option\n'
+ return 2
+ fi
+ shift
+ ;;
+ -t | --tmp-dir)
+ shift
+ if [[ -z "$1" ]]; then
+ printf 'No directory argument found for --tmp-dir option\n'
+ return 2
+ fi
+ TMP_DIR="$1"
+ shift
+ ;;
+ -h | --help)
+ print_help "$0"
+ return 1
+ ;;
+ area)
+ CROP="area"
+ shift
+ ;;
+ full)
+ CROP="fullscreen"
+ shift
+ ;;
+ markup)
+ IS_SWAPPY=true
+ shift
+ ;;
+ *)
+ if [[ -z "$OUTPUT_PATH" ]]; then
+ OUTPUT_PATH="$1"
+ else
+ printf 'Multiple output paths specified when only one was expected\n'
+ return 2
+ fi
+ shift
+ ;;
+ esac
+ done
+
+ # Assert valid number of inputs and outputs
+ if [[ -z "$CROP" && -z "$RESIZE" && -z "$IS_SWAPPY" ]]; then
+ printf 'No inputs specified!\n'
+ print_help "$0"
+ return 1
+ fi
+}
+
+# Set defaults
+set_global_defaults() {
+ if [[ -z "$EXT" && -n "$OUTPUT_PATH" ]]; then
+ EXT="${OUTPUT_PATH##*.}"
+ elif [[ -z "$EXT" && -n "$RESIZE" ]]; then
+ EXT='avif'
+ elif [[ -z "$EXT" ]]; then
+ EXT='png'
+ fi
+
+ if [[ -z "$TMP_DIR" ]]; then
+ TMP_DIR="$HOME/Desktop/screenshots_tmp"
+ fi
+
+ mkdir -p "$TMP_DIR"
+ TMP_PATH="${TMP_DIR}/$(date +%s).png"
+
+ if ! [[ -w "$TMP_DIR" ]]; then
+ printf 'Temporary path %s is not writable. Check permissions\n' "$TMP_PATH"
+ return 2
+ fi
+}
+
+# Save screenshot into tmp
+get_screenshot() {
+ if [[ "$CROP" == "area" ]]; then
+ grim -g "$(slurp)" "$TMP_PATH"
+ elif [[ "$CROP" == "fullscreen" ]]; then
+ grim "$TMP_PATH"
+ elif [[ "$CROP" =~ $SLURP_REGEX ]]; then
+ grim -g "$CROP" "$TMP_PATH"
+ fi
+}
+
+apply_drop_shadow() {
+ magick convert "$TMP_PATH" \
+ \( +clone -background black -shadow "${SHADOW}+0+0" \) \
+ +swap -background white -layers merge +repage \
+ "$TMP_PATH"
+}
+
+# Resize latest screenshot
+resize_latest_screenshot() {
+ if [[ -n "$IS_SWAPPY" ]] || [[ -n "$RESIZE" && "$RESIZE" == '100%' && "$EXT" == 'png' ]]; then
+ TMP_PATH="$(fd -e 'png' -E '*_*' . "$TMP_DIR" | sort | tail -1)"
+ elif [[ -n "$RESIZE" ]]; then
+ local latest_screenshot="$(fd -e 'png' -E '*_*' . "$TMP_DIR" | sort | tail -1)"
+ TMP_PATH="${latest_screenshot%.*}_${RESIZE}.${EXT}"
+
+ if [[ -z "$latest_screenshot" ]]; then
+ printf 'No screenshots found to resize\n'
+ return 1
+ fi
+
+ magick convert "$latest_screenshot" -resize "$RESIZE" "${EXT^^}:$TMP_PATH"
+ elif [[ "$EXT" != png ]]; then
+ local source_path="$TMP_PATH"
+ TMP_PATH="${source_path%.*}.${EXT}"
+ magick convert "$source_path" "${EXT^^}:$TMP_PATH"
+ fi
+}
+
+# Copy screenshot to destination
+copy_to_destination() {
+ if [[ "$IS_CLIPBOARD" == true ]]; then
+ wl-copy < "$TMP_PATH"
+ elif [[ "$IS_SWAPPY" == true ]]; then
+ swappy -f "$TMP_PATH" -o "${TMP_PATH%.*}_swappy.png"
+ fi
+ if [[ -n "$OUTPUT_PATH" ]]; then
+ cp "$TMP_PATH" "$OUTPUT_PATH"
+ fi
+}
+
+if ! parse_args "$@"; then
+ exit $?
+fi
+set_global_defaults || exit $?
+get_screenshot
+[[ -z "$SHADOW" ]] || apply_drop_shadow
+resize_latest_screenshot || exit $?
+copy_to_destination || exit $?
+
+# wl-copy https://www.reddit.com/r/swaywm/comments/bb4dam/take_screenshot_to_clipboard/
diff --git a/bin/sway_tree.rs b/bin/sway_tree.rs
new file mode 100644
index 0000000..077575f
--- /dev/null
+++ b/bin/sway_tree.rs
@@ -0,0 +1,228 @@
+// Quick and dirty tree representation of sway's tree string
+//
+// Input looks something like:
+// H[T[H[S[Alacritty baobab] T[ArchWiki]]] T[chromium-browser Alacritty]]
+//
+// This can be found, in the case of one workspace, at
+// swaymsg -t get_tree | jq '.nodes[1].nodes[0].representation'
+//
+// Which can then be piped to this script
+// swaymsg -t get_tree | jq '.nodes[1].nodes[0].representation' | sway_tree 2>/dev/null
+//
+// For the example string above, the output will be
+// └─┬(Horizontal)
+// ├─┬(Tabbed)
+// | └─┬(Horizontal)
+// | ├─┬(Stacked)
+// | | ├───> [Alacritty]
+// | | └───> [Baobab]
+// | └─┬(Tabbed)
+// | └───> [ArchWiki]
+// └─┬(Tabbed)
+// ├───> [Chromium-browser]
+// └───> [Alacritty]
+
+use std::io::{self, BufRead};
+
+fn main() {
+ let stdin = io::stdin();
+ let sway_representation = stdin.lock().lines().next()
+ .expect("Could not read from stdin")
+ .expect("Stdio error");
+
+ println!("{}", ParserTree::from(&sway_representation).format());
+}
+
+
+#[derive(Debug)]
+pub enum State {
+ ReadingTitle(String),
+ ExitContainer,
+ EnterContainer,
+}
+
+#[derive(Debug)]
+pub enum Layout {
+ Horizontal,
+ Vertical,
+ Tabbed,
+ Stacked,
+}
+
+#[derive(Debug)]
+pub enum ParserTree {
+ Container(Layout, Vec),
+ Leaf(String),
+ Empty,
+}
+
+impl ParserTree {
+ pub fn new() -> Self {
+ ParserTree::Empty
+ }
+
+ pub fn from(str_rep: &str) -> Self {
+ parse_sway_tree(str_rep)
+ }
+
+ pub fn new_leaf(title: String) -> Self {
+ ParserTree::Leaf(title)
+ }
+
+ pub fn container(layout: Layout, nodes: Vec) -> Self {
+ Self::Container(layout, nodes)
+ }
+
+ // Formats a tree view of parsed tree
+ pub fn format(self) -> String {
+ self.format_recursive(vec![false], true)
+ }
+
+ fn format_recursive(self, mut is_branched: Vec, is_last: bool) -> String {
+ let indent_size = 2;
+
+ let mut indent = (0..((is_branched.len() - 1) * indent_size)).map(|i| {
+ if i % indent_size == 0 && is_branched[i / indent_size + 1] {
+ '|'
+ } else {
+ ' '
+ }
+ }).collect::();
+
+ indent += match is_last {
+ true => "└─",
+ false => "├─",
+ };
+
+ return match self {
+ Self::Container(layout, children) => {
+ indent.push(if children.is_empty() { '─' } else { '┬' });
+
+ let mut container = indent;
+
+ match layout {
+ Layout::Horizontal => container.push_str("(Horizontal)\n"),
+ Layout::Vertical => container.push_str("(Vertical)\n"),
+ Layout::Tabbed => container.push_str("(Tabbed)\n"),
+ Layout::Stacked => container.push_str("(Stacked)\n"),
+ }
+
+ let last_i = children.len() - 1;
+ is_branched.push(!is_last);
+
+ for (i, child) in children.into_iter().enumerate() {
+ container += &child.format_recursive(is_branched.clone(), i == last_i);
+ }
+
+ container
+ }
+ Self::Leaf(title) => {
+ let mut cs = title.chars();
+
+ let title_cased = match cs.next() {
+ None => String::from("Untitled"),
+ Some(f) => f.to_uppercase().collect::() + cs.as_str(),
+ };
+
+ format!("{}> {}\n", indent, title_cased)
+ }
+ Self::Empty => format!("{} - <>\n", indent),
+ }
+ }
+}
+
+
+fn parse_sway_tree(rep: &str) -> ParserTree {
+ let mut state = State::EnterContainer;
+
+ let characters: Vec = rep.chars().collect();
+
+ let mut container_stack: Vec<(Layout, Vec)> = Vec::new();
+
+ let mut c: char;
+ let mut i = 0;
+
+ loop {
+ c = characters[i];
+
+ match state {
+ State::ReadingTitle(ref mut title) => {
+ if c == ']' {
+ let leaf = ParserTree::new_leaf(title.clone());
+
+ let mut container = container_stack.pop().unwrap();
+ container.1.push(leaf);
+
+ let child = ParserTree::container(container.0, container.1);
+
+ if !container_stack.is_empty() {
+ let parent = container_stack.last_mut().unwrap();
+ parent.1.push(child);
+ } else {
+ return child
+ }
+
+ eprintln!("PushLeaf: {:?}", &container_stack);
+
+ state = State::ExitContainer;
+ } else if c == ' ' {
+ let leaf = ParserTree::new_leaf(title.clone());
+
+ let container = container_stack.last_mut().unwrap();
+ container.1.push(leaf);
+
+ eprintln!("PushLeaf: {:?}", &container_stack);
+
+ state = State::EnterContainer;
+ } else {
+ title.push(c);
+ }
+ i += 1;
+ }
+ State::EnterContainer => {
+ let c1 = *characters.get(i + 1).unwrap_or(&'\0');
+
+ if (c == 'H' || c == 'V' || c == 'T' || c == 'S') && c1 == '[' {
+ container_stack.push(init_container(c));
+ eprintln!("AppendChild: {:?}", &container_stack);
+
+ i += 2;
+ } else {
+ state = State::ReadingTitle("".to_string());
+ }
+ }
+ State::ExitContainer => {
+ if c == ']' {
+ eprintln!("AppendParent:{:?}", &container_stack);
+ let container = container_stack.pop().unwrap();
+ let child = ParserTree::container(container.0, container.1);
+
+ if container_stack.len() == 0 {
+ return child
+ } else {
+ let parent = container_stack.last_mut().unwrap();
+ parent.1.push(child);
+ }
+
+ i += 1;
+ } else {
+ eprintln!("NextChild: {:?}", &container_stack);
+ state = State::EnterContainer;
+ i += 1;
+ }
+ }
+ }
+ }
+}
+
+
+// Creates new parts for a container
+fn init_container(layout_char: char) -> (Layout, Vec) {
+ match layout_char {
+ 'H' => (Layout::Horizontal, vec![]),
+ 'V' => (Layout::Vertical, vec![]),
+ 'T' => (Layout::Tabbed, vec![]),
+ 'S' => (Layout::Stacked, vec![]),
+ _ => unreachable!(),
+ }
+}
diff --git a/bin/swaytree.sh b/bin/swaytree.sh
new file mode 100755
index 0000000..9c97222
--- /dev/null
+++ b/bin/swaytree.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+i=0
+
+swaymsg -t get_tree | jq '.nodes[1].nodes[].representation' | tr -d '"' | \
+while read ln; do
+ space_num="$(swaymsg -t get_tree | jq '.nodes[1].nodes['"$i"'].name' | tr -d '"')"
+
+ printf "Workspace %s :: %s\n" "$space_num" "$ln"
+
+ i=$(( i + 1 ))
+ printf "%s" "$ln" | sway_tree 2>/dev/null
+done
diff --git a/bin/switch_keyboards.sh b/bin/switch_keyboards.sh
new file mode 100755
index 0000000..e77ebf4
--- /dev/null
+++ b/bin/switch_keyboards.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+# Usage: ./switch_keyboards.sh [args]
+#
+# Args:
+# console Loads the console version
+# mac Loads the Mac keyboard version
+# pc Loads the standard keyboard version
+#
+# Explanation =========
+# Mac keyboards place their super key adjacent to the spacebar, while standard
+# keyboards put alt in that spot:
+#
+# Macbook: Shift | z
+# Fn | Ctrl | Alt | Super | Space
+#
+# Standard: Shift | z
+# Fn | Ctrl | Super | Alt | Space
+#
+# To preserve consistency when switching keyboards, two versions of the same
+# xremap config.yml are available. This script toggles between the two
+#
+# Xremap can also run in a non-graphical console. For this we don't need to
+# remap Super and Alt, though we still need other keys, like capslock. An
+# optional "console" argument can be passed to this script to load
+# config_console.yml
+print_help() {
+ cat <
+
+ARGS:
+ mac Remaps assuming super is adjacent to the spacebar
+ pc Remaps assuming alt is adjacent to the spacebar
+ console Only remaps capslock to ctrl
+ help Print this message and exit
+HELP
+}
+
+if ! command -v xremap &>/dev/null; then
+ printf "xRemap not found\nLayouts were not switched\n"
+ exit 1
+fi
+
+case "$(echo "$1" | awk '{print tolower($0)}')" in
+ console)
+ ln -sf ~/.config/xremap/config_console.yml ~/.config/xremap/config.yml
+ echo "Switching to minimal console remapping"
+ ;;
+ mac)
+ ln -sf ~/.config/xremap/config_mac.yml ~/.config/xremap/config.yml
+ echo "Switching to mac layout :: ALT | SUPER | SPACE"
+ ;;
+ pc)
+ ln -sf ~/.config/xremap/config_standard.yml ~/.config/xremap/config.yml
+ echo "Switching to standard layout :: SUPER | ALT | SPACE"
+ ;;
+ *)
+ print_help
+ exit 0
+ ;;
+esac
+
+systemctl restart xremap
+sleep 2
diff --git a/bin/vii.sh b/bin/vii.sh
new file mode 100755
index 0000000..c3a6403
--- /dev/null
+++ b/bin/vii.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Opens vimiv in thumbnail mode, when there's at least one image in the cwd
+declare curr_image="$(fd -d 1 -e 'avif' -e 'gif' -e 'heif' -e 'icns' -e 'jpeg' -e 'jpg' -e 'png' -e 'tiff' -e 'webp' | tail -1)"
+
+if [[ -n "$curr_image" ]]; then
+ vimiv \
+ --debug gui.eventhandler \
+ --command 'unbind --mode=image' \
+ --command 'bind h enter library --mode=image' \
+ --command 'bind l enter thumbnail --mode=image' \
+ --command 'enter library' \
+ --command 'enter thumbnail' \
+ --command 'goto 0' \
+ "$curr_image"
+else
+ vimiv \
+ --debug gui.eventhandler \
+ --command 'unbind --mode=image' \
+ --command 'bind h enter library --mode=image' \
+ --command 'bind l enter thumbnail --mode=image' \
+ "$curr_image"
+fi
diff --git a/chromium/chromium-flags.conf b/chromium/chromium-flags.conf
new file mode 100644
index 0000000..9d02c18
--- /dev/null
+++ b/chromium/chromium-flags.conf
@@ -0,0 +1,7 @@
+--incognito
+--ozone-platform-hint=auto
+--enable-features=UseOzonePlatform
+--force-dark-mode
+--enable-features=WebUIDarkMode
+--process-per-site
+#--gtk-version=4
diff --git a/git/.gitconfig b/git/.gitconfig
new file mode 100644
index 0000000..4ef0a0b
--- /dev/null
+++ b/git/.gitconfig
@@ -0,0 +1,29 @@
+[filter "lfs"]
+clean = git-lfs clean -- %f
+smudge = git-lfs smudge -- %f
+process = git-lfs filter-process
+required = true
+
+[user]
+name = Emiliko Mirror
+email = emiliko@mami2.moe
+signingkey = ABCD1234LONGER
+
+[core]
+editor = nvim
+excludesfile = ~/.gitignore_global
+
+[color]
+ui = true
+
+[merge]
+tool = vimdiff
+
+[alias]
+praise = blame
+
+[commit]
+gpgsign = true
+
+[init]
+defaultBranch = main
diff --git a/git/.gitignore_global b/git/.gitignore_global
new file mode 100644
index 0000000..02850da
--- /dev/null
+++ b/git/.gitignore_global
@@ -0,0 +1,10 @@
+# Vim
+*~
+*.swp
+Session.vim
+
+# macOS
+.DS_Store
+
+# Custom
+*.chrome
diff --git a/gnupg/gpg-agent.conf b/gnupg/gpg-agent.conf
new file mode 100644
index 0000000..54f85d5
--- /dev/null
+++ b/gnupg/gpg-agent.conf
@@ -0,0 +1 @@
+pinentry-program /usr/bin/pinentry-tty
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..8be0d30
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,349 @@
+#!/usr/bin/env bash
+declare MODE=""
+declare -r UNIX_CONFIGS=(\
+ # Shell
+ bash/.profile ~/.profile
+ bash/.inputrc ~/.inputrc
+ bash/.bashrc ~/.bashrc
+ bash/.bash_profile ~/.bash_profile
+ bash/.bash_env ~/.bash_env
+ bash/.bash_prompt ~/.bash_prompt
+ bash/.bash_aliases ~/.bash_aliases
+ bash/.bash_functions ~/.bash_functions
+
+ aerc ~/.config/aerc
+ alacritty ~/.config/alacritty
+ git/.gitignore_global ~/.gitignore_global
+ gnupg/gpg-agent.conf ~/.gnupg/gpg-agent.conf
+ mako ~/.config/mako
+ mpv ~/.config/mpv
+ chromium/chromium-flags.conf ~/.config/chromium-flags.conf
+ ripgrep ~/.config/ripgrep
+ swappy ~/.config/swappy
+ tmux ~/.config/tmux
+ vifm ~/.config/vifm
+ vimiv ~/.config/vimiv
+ warpd ~/.config/warpd
+
+ # Vim and Neovim
+ vim/.vim ~/.vim
+ vim/.vimrc ~/.vimrc
+ vim/nvim ~/.config/nvim
+ vim/.vim/plugin ~/.config/nvim/plugin
+ vim/.vim/colors ~/.config/nvim/colors
+ ) \
+ LINUX_ONLY=(\
+ # Swayland
+ sway ~/.config/sway
+ swaylock ~/.config/swaylock
+ xremap ~/.config/xremap
+ yofi ~/.config/yofi
+ ) \
+ MAC_ONLY=(\
+ skhd ~/.config/skhd
+ yabai ~/.config/yabai
+ sketchybar ~/.config/sketchybar
+
+ skhd/com.skhd.launcher.plist ~/Library/LaunchAgents/com.skhd.launcher.plist
+ sketchybar/com.sketchybar.launcher.plist ~/Library/LaunchAgents/com.sketchybar.launcher.plist
+ warpd/com.warpd.launcher.plist ~/Library/LaunchAgents/com.warpd.launcher.plist
+ other/vlcrc ~/Library/Preferences/org.videolan.vlc/vlcrc
+ )
+
+print_help() {
+ cat <
+ bash install.sh [flags]
+HELP
+}
+
+main() {
+ # Verify we're in the right directory ====
+ if [[ "$(is_configs_directory)" != "true" ]]; then
+ printf 'Please move to the top level git directory with this script\n'
+ printf 'Aborting...\n'
+ exit 1
+ fi
+
+ # Verify or install ~/.configs_pointer ====
+ local configs_pointer="$(configs_pointer_is_setup)"
+
+ if [[ "${configs_pointer}" != "valid" ]]; then
+ if [[ "${configs_pointer}" == "does not exist" ]]; then
+ if ! ln -s "$PWD" ~/.configs_pointer; then
+ printf 'Failed to link present directory to ~/.config_pointer\n'
+ printf 'Aborting...\n'
+ exit 1
+ fi
+ else
+ printf '~/.configs_pointer does not point to this directory\n'
+ printf 'Remove ~/.configs_pointer and rerun this script\n'
+ printf 'Aborting...\n'
+ exit 1
+ fi
+ fi
+
+ # Default is status
+ if [[ $# -eq 0 ]]; then
+ iterate_over_configs 'status'
+ exit 0
+ fi
+
+ # Parse arguments ====
+ while [[ $# -gt 0 ]]
+ do
+ case "$1" in
+ -s | --silent) MODE="${MODE} silent" ;;
+ -b | --basename) MODE="${MODE} basename" ;;
+ -h | --help) MODE="${MODE} help" ;;
+ status) MODE="${MODE} status" ;;
+ install) MODE="${MODE} install" ;;
+ *)
+ printf 'Invalid argument: "%s"\n' "$1"
+ print_help
+ exit 1
+ ;;
+ esac
+
+ shift
+ done
+
+ # Run ====
+ if [[ "${MODE}" =~ "help" ]]; then
+ print_help
+ exit 0
+ elif [[ "${MODE}" =~ "status" ]]; then
+ iterate_over_configs 'status'
+ elif [[ "${MODE}" =~ "install" ]]; then
+ fix_launchd_plists
+ iterate_over_configs 'install'
+ create_directory_paths
+ other_setup
+ print_install_completion_msg
+ else
+ print_help
+ fi
+
+ exit 0
+}
+
+#######################################
+# Checks if the script is being run from the configs directory.
+# Return code:
+# 0 if it is the configs directory, 1 otherwise.
+# Return string:
+# Describes why this likely isn't the configs directory.
+#######################################
+is_configs_directory() {
+ if ! [[ -d ./.git ]]; then
+ printf "Git folder not found in pwd\n"
+ printf "no .git directory"
+ return 1
+ elif ! [[ -x ./install.sh ]]; then
+ printf "install.sh not found in pwd\n"
+ printf "file install.sh not in pwd"
+ return 1
+ fi
+
+ printf "true"
+ return 0
+}
+
+configs_pointer_is_setup() {
+ if ! [[ -e ~/.configs_pointer ]]; then
+ printf "does not exist"
+ return 1
+ elif ! [[ -L ~/.configs_pointer ]]; then
+ printf "not a symlink"
+ return 1
+ elif ! [[ -x ~/.configs_pointer/install.sh ]]; then
+ printf "no install.sh at symlink"
+ return 1
+ elif ! cmp -s ~/.configs_pointer/install.sh ./install.sh; then
+ printf "install.sh files differ"
+ return 1
+ else
+ printf "valid"
+ return 0
+ fi
+}
+
+#######################################
+# Return the status of a config.
+# Arguments:
+# 1: Path in configs directory. "from"
+# 2: Path on the system. "to"
+#######################################
+config_status() {
+ if [[ "$1" -ef "$2" ]]; then
+ printf "linked"
+ return 0
+ elif [[ -e "$2" ]]; then
+ printf "conflict"
+ return 1
+ elif ! [[ -e "$1" ]]; then
+ printf "missing"
+ return 1
+ else
+ printf "not_linked"
+ return 1
+ fi
+}
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Usεr iητεrfαcε fμηcτiδηs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+#######################################
+# Prints the status of a config.
+# Arguments:
+# 1: Status in {"not_linked", "conflict", "linked"}
+# 2: System path to config file
+# Outputs:
+# Writes status to stdout
+#######################################
+print_config_status() {
+ if [[ "${MODE}" =~ "basename" ]]; then
+ local name="$(basename "$2")"
+ else
+ local name="$(printf '%s' "$2" | sed 's#'"${HOME}"'#~#')"
+ fi
+
+ if ! [[ "${MODE}" =~ "silent" ]] || [[ "$1" != "linked" ]]; then
+ case "$1" in
+ newly_linked)
+ printf "★ %s :: Newly linked" "${name}" ;;
+ not_linked) printf "✗ %s :: Not Linked" "${name}" ;;
+ conflict) printf "≠ %s :: Conflicting file" "${name}" ;;
+ missing) printf "φ %s :: Missing config file" "${name}" ;;
+ linked) printf "✓ %s :: Linked" "${name}" ;;
+ *) printf "? %s :: Status unclear" "${name}" ;;
+ esac
+
+ printf "\n"
+ fi
+}
+
+print_install_completion_msg() {
+ cat < "${plist}"
+ done
+}
+
+# Launchd requires an absolute path for sketchbar, which isn't available to brew
+other_setup() {
+ if which sketchybar &>/dev/null && ! [[ -e ~/.configs_pointer/sketchybar/sketchybar ]]; then
+ ln -s "$(which sketchybar)" ~/.configs_pointer/sketchybar/sketchybar &>/dev/null
+ fi
+}
+
+#######################################
+# Prints the status of a config.
+# Arguments:
+# 1: Path to config file. The "from" path.
+# 2: Path to system file. The "to" path.
+# Outputs:
+# Writes status to stdout
+#######################################
+install_config() {
+ local status=$(config_status "$1" "$2")
+
+ if [[ "${status}" != "not_linked" ]]; then
+ printf '%s\n' "${status}"
+ return 1
+ fi
+
+ [[ -d "$1" ]] || mkdir -p "$(dirname "$2")"
+
+ if ln -s "$1" "$2"; then
+ printf "newly_linked"
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Arguments
+# 1: Mode in {"status", "install"}
+iterate_over_configs() {
+ if [[ "$(uname -s)" == "Darwin" ]]; then
+ local a=("${UNIX_CONFIGS[@]}" "${MAC_ONLY[@]}")
+ else
+ local a=("${UNIX_CONFIGS[@]}" "${LINUX_ONLY[@]}")
+ fi
+
+ for ((i = 0; i < "${#a[@]}"; i=(i+2) )); do
+ local from="${HOME}/.configs_pointer/${a[$i]}"
+ local to="${a[$i + 1]}"
+
+ if [[ "$1" == "status" ]]; then
+ local status="$(config_status "${from}" "${to}")"
+ print_config_status "${status}" "${to}"
+ elif [[ "$1" == "install" ]]; then
+ local status="$(install_config "${from}" "${to}")"
+ print_config_status "${status}" "${to}"
+ else
+ printf 'Invalid mode "%s" provided\n' "$1"
+ exit 1
+ fi
+ done
+}
+
+main "$@"
+
+# vim: set ft=bash syn=bash sw=2 ff=unix:
diff --git a/macos/DefaultKeyBinding.dict b/macos/DefaultKeyBinding.dict
new file mode 100644
index 0000000..f7e3b47
--- /dev/null
+++ b/macos/DefaultKeyBinding.dict
@@ -0,0 +1,48 @@
+// defaults: https://github.com/ttscoff/KeyBindings
+// explained: https://ss64.com/osx/syntax-keybindings.html
+// discussion: https://gist.github.com/trusktr/1e5e516df4e8032cbc3d
+// Set a binding for repeating action (e.g.: ^u, 5, right arrow)
+// > defaults write -g NSRepeatCountBinding -string "^u"
+//
+// Local list:
+// /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict
+//
+//
+//
+// General methodology stays as with the rest of the configs
+//
+// startOfLine backWord backChar forwardChar forwardWord endOfLine
+// Movements: ^a ^b ^j ^f w^ e^
+// Selections: ^u ^h ^d k^
+
+{
+ // Move by char. Overrides emacs defaults
+ "^f" = (moveForward:);
+ "^j" = (moveBackward:);
+
+ "^d" = (deleteForward:);
+ "^h" = (deleteBackward:);
+
+ // Move by word
+ "^w" = (moveWordForward:);
+ "^b" = (moveWordBackward:);
+
+ // Select by word
+ "^@w" = (moveWordForwardAndModifySelection:);
+ "^@b" = (moveWordBackwardAndModifySelection:);
+
+ // Delete to paragraph/line start/end
+ //"^u" = (moveToBeginningOfParagraphAndModifySelection:, delete:);
+ //"^k" = (moveToEndOfParagraphAndModifySelection:, delete:);
+ "^u" = (moveWordBackwardAndModifySelection:);
+ "^k" = (moveToEndOfParagraphAndModifySelection:);
+
+ // Select to paragraph/line start/end
+ "^@u" = (moveToBeginningOfParagraphAndModifySelection:);
+ "^@k" = (moveToEndOfParagraphAndModifySelection:);
+
+ // Uppercase word
+ "^y" = (uppercaseWord:, moveWordForward:, moveWordBackward:);
+}
+
+// ex: set ft=javascript:
diff --git a/mako/config b/mako/config
new file mode 100644
index 0000000..62b16df
--- /dev/null
+++ b/mako/config
@@ -0,0 +1,10 @@
+font=noto-sans
+background-color=#F4A66EFF
+text-color=#000000
+padding=10
+border-size=4
+border-color=#000000
+border-radius=6
+progress-color=over #000000
+default-timeout=5000
+max-visible=6
diff --git a/mpv/input.conf b/mpv/input.conf
new file mode 100644
index 0000000..ed5d4e4
--- /dev/null
+++ b/mpv/input.conf
@@ -0,0 +1,207 @@
+# mpv keybindings
+#
+# Location of user-defined bindings: ~/.config/mpv/input.conf
+#
+# Lines starting with # are comments. Use SHARP to assign the # key.
+# Copy this file and uncomment and edit the bindings you want to change.
+#
+# List of commands and further details: DOCS/man/input.rst
+# List of special keys: --input-keylist
+# Keybindings testing mode: mpv --input-test --force-window --idle
+#
+# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore').
+#
+# Strings need to be quoted and escaped:
+# KEY show-text "This is a single backslash: \\ and a quote: \" !"
+#
+# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
+# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal).
+#
+# The default keybindings are hardcoded into the mpv binary.
+# You can disable them completely with: --no-input-default-bindings
+
+# Developer note:
+# On compilation, this file is baked into the mpv binary, and all lines are
+# uncommented (unless '#' is followed by a space) - thus this file defines the
+# default key bindings.
+
+# If this is enabled, treat all the following bindings as default.
+# default-bindings start
+
+# MBTN_LEFT ignore # don't do anything
+# MBTN_LEFT_DBL cycle fullscreen # toggle fullscreen
+F cycle fullscreen
+# MBTN_RIGHT cycle pause # toggle pause/playback mode
+# MBTN_BACK playlist-prev # skip to the previous file
+# MBTN_FORWARD playlist-next # skip to the next file
+
+# Mouse wheels, touchpad or other input devices that have axes
+# if the input devices supports precise scrolling it will also scale the
+# numeric value accordingly
+# WHEEL_UP seek 10 # seek 10 seconds forward
+# WHEEL_DOWN seek -10 # seek 10 seconds backward
+# WHEEL_LEFT add volume -2
+# WHEEL_RIGHT add volume 2
+#
+
+# Anime filter keys
+Ctrl+1 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_M.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode A (Fast)"
+Ctrl+2 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_M.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode B (Fast)"
+Ctrl+3 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Upscale_Denoise_CNN_x2_M.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode C (Fast)"
+Ctrl+4 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_M.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl:~~/shaders/Anime4K_Restore_CNN_S.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode A+A (Fast)"
+Ctrl+5 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_M.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_S.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode B+B (Fast)"
+Ctrl+6 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Upscale_Denoise_CNN_x2_M.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Restore_CNN_S.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode C+A (Fast)"
+
+Ctrl+0 no-osd change-list glsl-shaders clr ""; show-text "GLSL shaders cleared"
+
+# # Seek units are in seconds, but note that these are limited by keyframes
+RIGHT seek 4 exact # seek 5 seconds forward
+LEFT seek -4 exact # seek 5 seconds backward
+j seek -12 exact
+l seek 12 exact
+# UP seek 60 # seek 1 minute forward
+# DOWN seek -60 # seek 1 minute backward
+# Do smaller, always exact (non-keyframe-limited), seeks with shift.
+# Don't show them on the OSD (no-osd).
+# Shift+RIGHT no-osd seek 1 exact # seek exactly 1 second forward
+# Shift+LEFT no-osd seek -1 exact # seek exactly 1 second backward
+# Shift+UP no-osd seek 5 exact # seek exactly 5 seconds forward
+# Shift+DOWN no-osd seek -5 exact # seek exactly 5 seconds backward
+# Ctrl+LEFT no-osd sub-seek -1 # seek to the previous subtitle
+# Ctrl+RIGHT no-osd sub-seek 1 # seek to the next subtitle
+# Ctrl+Shift+LEFT sub-step -1 # change subtitle timing such that the previous subtitle is displayed
+# Ctrl+Shift+RIGHT sub-step 1 # change subtitle timing such that the next subtitle is displayed
+# Alt+left add video-pan-x 0.1 # move the video right
+# Alt+right add video-pan-x -0.1 # move the video left
+# Alt+up add video-pan-y 0.1 # move the video down
+# Alt+down add video-pan-y -0.1 # move the video up
+# Alt++ add video-zoom 0.1 # zoom in
+# Alt+- add video-zoom -0.1 # zoom out
+# Alt+BS set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 # reset zoom and pan settings
+# PGUP add chapter 1 # seek to the next chapter
+# PGDWN add chapter -1 # seek to the previous chapter
+# Shift+PGUP seek 600 # seek 10 minutes forward
+# Shift+PGDWN seek -600 # seek 10 minutes backward
+# [ multiply speed 1/1.1 # decrease the playback speed
+# ] multiply speed 1.1 # increase the playback speed
+# { multiply speed 0.5 # halve the playback speed
+# } multiply speed 2.0 # double the playback speed
+# BS set speed 1.0 # reset the speed to normal
+# Shift+BS revert-seek # undo the previous (or marked) seek
+# Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek
+# q quit
+# Q quit-watch-later # exit and remember the playback position
+# q {encode} quit 4
+# ESC set fullscreen no # leave fullscreen
+# ESC {encode} quit 4
+# p cycle pause # toggle pause/playback mode
+. frame-step # advance one frame and pause
+, frame-back-step # go back by one frame and pause
+SPACE cycle pause # toggle pause/playback mode
+k cycle pause # toggle pause/playback mode
+# > playlist-next # skip to the next file
+# ENTER playlist-next # skip to the next file
+# < playlist-prev # skip to the previous file
+# O no-osd cycle-values osd-level 3 1 # toggle displaying the OSD on user interaction or always
+# o show-progress # show playback progress
+# P show-progress # show playback progress
+# i script-binding stats/display-stats # display information and statistics
+# I script-binding stats/display-stats-toggle # toggle displaying information and statistics
+# ` script-binding console/enable # open the console
+# z add sub-delay -0.1 # shift subtitles 100 ms earlier
+# Z add sub-delay +0.1 # delay subtitles by 100 ms
+# x add sub-delay +0.1 # delay subtitles by 100 ms
+[ add sub-delay -0.1 # shift subtitles 100 ms earlier
+] add sub-delay +0.1 # delay subtitles by 100 ms
+{ add sub-delay -10 # shift subtitles 10s earlier
+} add sub-delay +10 # delay subtitles by 10s
+( add audio-delay -0.1 # change audio/video sync by delaying the audio
+) add audio-delay +0.1 # change audio/video sync by shifting the audio earlier
+# ctrl++ add audio-delay 0.100 # change audio/video sync by delaying the audio
+# ctrl+- add audio-delay -0.100 # change audio/video sync by shifting the audio earlier
+# Shift+g add sub-scale +0.1 # increase the subtitle font size
+# Shift+f add sub-scale -0.1 # decrease the subtitle font size
+# 9 add volume -2
+# / add volume -2
+# 0 add volume 2
+# * add volume 2
+m cycle mute # toggle mute
+# 1 add contrast -1
+# 2 add contrast 1
+# 3 add brightness -1
+# 4 add brightness 1
+# 5 add gamma -1
+# 6 add gamma 1
+# 7 add saturation -1
+# 8 add saturation 1
+# Alt+0 set current-window-scale 0.5 # halve the window size
+# Alt+1 set current-window-scale 1.0 # reset the window size
+# Alt+2 set current-window-scale 2.0 # double the window size
+# d cycle deinterlace # toggle the deinterlacing filter
+# r add sub-pos -1 # move subtitles up
+# R add sub-pos +1 # move subtitles down
+# t add sub-pos +1 # move subtitles down
+# v cycle sub-visibility # hide or show the subtitles
+# Alt+v cycle secondary-sub-visibility # hide or show the secondary subtitles
+# V cycle sub-ass-vsfilter-aspect-compat # toggle stretching SSA/ASS subtitles with anamorphic videos to match the historical renderer
+# u cycle-values sub-ass-override "force" "no" # toggle overriding SSA/ASS subtitle styles with the normal styles
+# j cycle sub # switch subtitle track
+# J cycle sub down # switch subtitle track backwards
+n cycle sub # switch subtitle track
+N cycle sub down # switch subtitle track backwards
+# SHARP cycle audio # switch audio track
+a cycle audio
+A cycle audio down
+# _ cycle video # switch video track
+# T cycle ontop # toggle placing the video on top of other windows
+# f cycle fullscreen # toggle fullscreen
+# s screenshot # take a screenshot of the video in its original resolution with subtitles
+# S screenshot video # take a screenshot of the video in its original resolution without subtitles
+# Ctrl+s screenshot window # take a screenshot of the window with OSD and subtitles
+# Alt+s screenshot each-frame # automatically screenshot every frame; issue this command again to stop taking screenshots
+# w add panscan -0.1 # decrease panscan
+# W add panscan +0.1 # shrink black bars by cropping the video
+# e add panscan +0.1 # shrink black bars by cropping the video
+# A cycle-values video-aspect-override "16:9" "4:3" "2.35:1" "-1" # cycle the video aspect ratio ("-1" is the container aspect)
+# POWER quit
+# PLAY cycle pause # toggle pause/playback mode
+# PAUSE cycle pause # toggle pause/playback mode
+# PLAYPAUSE cycle pause # toggle pause/playback mode
+# PLAYONLY set pause no # unpause
+# PAUSEONLY set pause yes # pause
+# STOP quit
+# FORWARD seek 60 # seek 1 minute forward
+# REWIND seek -60 # seek 1 minute backward
+# NEXT playlist-next # skip to the next file
+# PREV playlist-prev # skip to the previous file
+# VOLUME_UP add volume 2
+# VOLUME_DOWN add volume -2
+= add volume 4
+- add volume -4
+# MUTE cycle mute # toggle mute
+CLOSE_WIN quit
+# CLOSE_WIN {encode} quit 4
+ctrl+q quit
+ctrl+w quit
+# E cycle edition # switch edition
+# l ab-loop # set/clear A-B loop points
+# L cycle-values loop-file "inf" "no" # toggle infinite looping
+# ctrl+c quit 4
+# DEL script-binding osc/visibility # cycle OSC visibility between never, auto (mouse-move) and always
+# ctrl+h cycle-values hwdec "auto" "no" # toggle hardware decoding
+# F8 show-text ${playlist} # show the playlist
+# F9 show-text ${track-list} # show the list of video, audio and sub tracks
+
+#
+# Legacy bindings (may or may not be removed in the future)
+#
+# ! add chapter -1 # seek to the previous chapter
+# @ add chapter 1 # seek to the next chapter
+
+#
+# Not assigned by default
+# (not an exhaustive list of unbound commands)
+#
+
+# ? cycle sub-forced-only # toggle DVD forced subs
+# ? stop # stop playback (quit or enter idle mode)
diff --git a/mpv/mpv.conf b/mpv/mpv.conf
new file mode 100644
index 0000000..4a83d33
--- /dev/null
+++ b/mpv/mpv.conf
@@ -0,0 +1,145 @@
+###################
+# custom settings #
+###################
+volume='60' # Don't blast on open (use -/=)
+
+save-position-on-quit # Starts from where you left off last time
+
+#no-input-default-bindings # Disables all keybinds, including scripts!
+no-input-builtin-bindings # Disables all default keybinds
+
+#
+# Example mpv configuration file
+#
+# Warning:
+#
+# The commented example options usually do _not_ set the default values. Call
+# mpv with --list-options to see the default values for most options. There is
+# no builtin or example mpv.conf with all the defaults.
+#
+#
+# Configuration files are read system-wide from /usr/local/etc/mpv.conf
+# and per-user from ~/.config/mpv/mpv.conf, where per-user settings override
+# system-wide settings, all of which are overridden by the command line.
+#
+# Configuration file settings and the command line options use the same
+# underlying mechanisms. Most options can be put into the configuration file
+# by dropping the preceding '--'. See the man page for a complete list of
+# options.
+#
+# Lines starting with '#' are comments and are ignored.
+#
+# See the CONFIGURATION FILES section in the man page
+# for a detailed description of the syntax.
+#
+# Profiles should be placed at the bottom of the configuration file to ensure
+# that settings wanted as defaults are not restricted to specific profiles.
+
+##################
+# video settings #
+##################
+
+# Start in fullscreen mode by default.
+#fs=yes
+
+# force starting with centered window
+#geometry=50%:50%
+
+# don't allow a new window to have a size larger than 90% of the screen size
+#autofit-larger=90%x90%
+
+# Do not close the window on exit.
+#keep-open=yes
+
+# Do not wait with showing the video window until it has loaded. (This will
+# resize the window once video is loaded. Also always shows a window with
+# audio.)
+#force-window=immediate
+
+# Disable the On Screen Controller (OSC).
+#osc=no
+
+# Keep the player window on top of all other windows.
+#ontop=yes
+
+# Specify high quality video rendering preset (for --vo=gpu only)
+# Can cause performance problems with some drivers and GPUs.
+#profile=gpu-hq
+
+# Force video to lock on the display's refresh rate, and change video and audio
+# speed to some degree to ensure synchronous playback - can cause problems
+# with some drivers and desktop environments.
+#video-sync=display-resample
+
+# Enable hardware decoding if available. Often, this does not work with all
+# video outputs, but should work well with default settings on most systems.
+# If performance or energy usage is an issue, forcing the vdpau or vaapi VOs
+# may or may not help.
+#hwdec=auto
+
+##################
+# audio settings #
+##################
+
+# Specify default audio device. You can list devices with: --audio-device=help
+# The option takes the device string (the stuff between the '...').
+#audio-device=alsa/default
+
+# Do not filter audio to keep pitch when changing playback speed.
+#audio-pitch-correction=no
+
+# Output 5.1 audio natively, and upmix/downmix audio with a different format.
+#audio-channels=5.1
+# Disable any automatic remix, _if_ the audio output accepts the audio format.
+# of the currently played file. See caveats mentioned in the manpage.
+# (The default is "auto-safe", see manpage.)
+#audio-channels=auto
+
+##################
+# other settings #
+##################
+
+# Pretend to be a web browser. Might fix playback with some streaming sites,
+# but also will break with shoutcast streams.
+#user-agent="Mozilla/5.0"
+
+# cache settings
+#
+# Use a large seekable RAM cache even for local input.
+#cache=yes
+#
+# Use extra large RAM cache (needs cache=yes to make it useful).
+#demuxer-max-bytes=500M
+#demuxer-max-back-bytes=100M
+#
+# Disable the behavior that the player will pause if the cache goes below a
+# certain fill size.
+#cache-pause=no
+#
+# Store cache payload on the hard disk instead of in RAM. (This may negatively
+# impact performance unless used for slow input such as network.)
+#cache-dir=~/.cache/
+#cache-on-disk=yes
+
+# Display English subtitles if available.
+#slang=en
+
+# Play Finnish audio if available, fall back to English otherwise.
+#alang=fi,en
+
+# Change subtitle encoding. For Arabic subtitles use 'cp1256'.
+# If the file seems to be valid UTF-8, prefer UTF-8.
+# (You can add '+' in front of the codepage to force it.)
+#sub-codepage=cp1256
+
+# You can also include other configuration files.
+#include=/path/to/the/file/you/want/to/include
+
+############
+# profiles #
+############
+[waifu]
+sub-font='Hiragino Sans W3'
+#sub-auto='all'
+audio-device='coreaudio/~:AMS2_StackedOutput:0'
+#sub-file-paths='../'
diff --git a/mpv/scripts/subs_to_clipboard.js b/mpv/scripts/subs_to_clipboard.js
new file mode 100644
index 0000000..d0b2062
--- /dev/null
+++ b/mpv/scripts/subs_to_clipboard.js
@@ -0,0 +1,209 @@
+// Copy the current subtitles to the clipboard
+//
+// You may select the copied subtitles with `qwer` by default or just
+// `` to copy all of them
+//
+// Make sure to edit g.afterCopyAction[Mac|Linux] below. This command will be
+// run by bash after the subtitles are copied to clipboard. For example to
+// search them up in an online dictionary
+
+
+// Rebind keys here
+var key_binds = {
+ // Keys to move selection. Letters mean `move`.
+ // moveLP increases the selection size by 1 character to the left
+ moveLP: "q",
+ moveLM: "w",
+ moveRM: "e",
+ moveRP: "r",
+
+ // Start and stop copying
+ copyKey: "TAB",
+};
+
+
+// Global
+var g = {
+ osd: mp.create_osd_overlay("ass-events"),
+ has_moved_selection: false,
+ sub_chars: undefined,
+ sub_len: function () { return this.sub_chars.length },
+ start: 0,
+ end: 0,
+
+ // Shell script to run after copying. Both examples below assume chrome
+ // with a dictionary is open on workspace 3 and the "seach box focus"
+ // Chrome extension is installed
+ // MacOS version ======
+ // Uses skhd, not preinstalled
+ afterCopyActionMac: "/usr/bin/env -S bash -c '"
+ + 'skhd -k "cmd + shift - a"' // Move to left desktop
+ + ' && sleep .6'
+ + ' && skhd -k "ctrl - l"' // Focus search bar
+ + ' && sleep .1'
+ + ' && skhd -k "cmd - a"' // Select entire search bar
+ + ' && skhd -k "cmd - v"' // Paste clipboard
+ + ' && skhd -k "return"' // Search
+ + "'",
+ // Linux version ======
+ // Uses wtype, intended for swayland
+ afterCopyActionLinux: "/usr/bin/env -S bash -c '"
+ + 'wtype -M logo -k 3' // Move to workspace 3
+ + ' && sleep .2'
+ + ' && wtype -M alt -k l' // Focus jisho.org searchbar
+ + ' && sleep .2'
+ + ' && wtype -M ctrl -k v' // Paste
+ + ' && wtype -k return' // Search
+ + "'",
+};
+
+
+mp.add_key_binding(key_binds.copyKey, "startCopySubs", main);
+
+
+function main() {
+ if (!initSelection()) {
+ mp.osd_message('No subtitles found', 1);
+ }
+
+ mp.add_forced_key_binding(key_binds.moveLP, "moveLP", function () { moveSelection(true, 'left') });
+ mp.add_forced_key_binding(key_binds.moveLM, "moveLM", function () { moveSelection(false, 'left') });
+ mp.add_forced_key_binding(key_binds.moveRM, "moveRM", function () { moveSelection(false, 'right') });
+ mp.add_forced_key_binding(key_binds.moveRP, "moveRP", function () { moveSelection(true, 'right') });
+
+ mp.add_forced_key_binding(key_binds.copyKey, "copySubs", function () {
+ copySelection();
+ mp.add_forced_key_binding(key_binds.copyKey, "startCopySubs", main);
+ });
+
+ g.has_moved_selection = false;
+}
+
+
+// Create a new selection printing on OSD
+// Returns true when a new selection has been created
+function initSelection() {
+ g.sub_chars = [];
+ var chars = mp.get_property('sub-text')
+ .replace('\n', '\\N')
+ .replace(/\u202A/g, '') // Left to right embed
+ .replace(/\u202C/g, '') // Right to left embed
+ .split('');
+
+ if (chars.length === 0) return false;
+
+ // Combine \N with previous character
+ for (var i = 0; i < chars.length; i++) {
+ if (chars[i+1] + chars[i+2] === '\\N')
+ g.sub_chars.push(chars[i] + chars[++i] + chars[++i])
+ else
+ g.sub_chars.push(chars[i]);
+ }
+
+ // Select middle half of subs, the [1/4, 3/4] range
+ g.start = Math.floor(g.sub_len() / 4);
+ g.end = Math.floor(g.sub_len() * 3 / 4);
+
+ renderSelection();
+ return true
+}
+
+
+// Write updated selection to osd
+function renderSelection() {
+ var ass_str = "";
+
+ // Color selected characters in gruvbox yellow
+ for (var i = 0; i < g.sub_len(); i++) {
+ if (i === g.start) ass_str += "{\\c&H1476B7&}";
+ ass_str += g.sub_chars[i];
+ if (i === g.end) ass_str += "{\\c&HFFFFFF&}";
+ }
+
+ g.osd.data = "{\\an2}" + ass_str;
+ g.osd.update();
+}
+
+
+// Increase or decrease the selection. At least one character must be selected
+function moveSelection(is_additive, side) {
+ if (is_additive && side === 'left')
+ g.start -= (g.start !== 0);
+ else if (side === 'left')
+ g.start += (g.start < g.end);
+ else if (is_additive)
+ g.end += (g.end !== g.sub_len());
+ else
+ g.end -= g.start < g.end;
+
+ g.has_moved_selection = true;
+ renderSelection();
+}
+
+
+// Remove selection from OSD and reset it to as before
+function clearSelection() {
+ for (var bind in key_binds)
+ mp.remove_key_binding(key_binds[bind]);
+ g.osd.remove();
+ g.sub_chars = [];
+}
+
+
+// Copy the current selection to the clipboard
+function copySelection() {
+ var selected = g.sub_chars.join('').replace(/\\N/g, ''); // Removes linebreaks
+
+ if (g.has_moved_selection) {
+ selected = selected.slice(g.start, g.end + 1);
+ }
+ clearSelection();
+
+ kernel_name = mp.command_native({
+ name: "subprocess",
+ capture_stdout: true,
+ args: ["uname", "-s"],
+ }).stdout;
+
+ if (kernel_name.match("Darwin")) {
+ mp.command("run bash -c \"echo '" + selected + "' | pbcopy\"");
+ mp.osd_message('Copied to clipboard', 1);
+
+ if (g.afterCopyActionMac)
+ mp.command("run " + g.afterCopyActionMac);
+ } else if (kernel_name.match("Linux")) {
+ mp.command("run bash -c \"echo '" + selected + "' | wl-copy\"");
+ mp.osd_message('Copied to clipboard', 1);
+
+ if (g.afterCopyActionLinux)
+ mp.command("run " + g.afterCopyActionLinux);
+ } else {
+ mp.msg.log("error", "Unrecognized kernel name: '" + kernel_name + "'");
+ }
+}
+
+
+// Depreciated
+function copySubs() {
+ var subs = mp.get_property('sub-text').replace(/\u202a/g, '');
+
+ mp.command("run bash -c \"echo '" + subs + "' | pbcopy\"");
+
+ mp.osd_message('Copied to clipboard', 1);
+
+ //var is_windows = mp.get_property_native('options/vo-mmcss-profile', o).match(/o/);
+ //var is_mac = mp.get_property_native('options/cocoa-force-dedicated-gpu', o).match(/o/);
+
+ //mp.msg.info(is_windows ? "Is windows" : "Not windows?");
+ //mp.msg.info(is_mac ? "Is mac" : "Not a mac?");
+
+ //if (is_windows) {
+ // mp.osd_message('Windows is not supported at this time\nClipboard unchanged', 4);
+ // return
+ //} else if (is_mac) {
+ // mp.command("run /usr/bin/env -S bash -c 'echo \"" + subs + "\" | pbcopy'");
+ //} else {
+ // mp.command("run /usr/bin/env -S bash -c 'echo \"" + subs + "\" | xclip'");
+ //}
+}
+
diff --git a/package_install.sh b/package_install.sh
new file mode 100755
index 0000000..ef35ac9
--- /dev/null
+++ b/package_install.sh
@@ -0,0 +1,309 @@
+#!/usr/bin/env bash
+declare PACMAN=""
+
+# Linux and Cargo packages are written in pairs: (package_name, binary_name).
+# Brew packages only use their binary name and are intended for MacOS.
+# The binary name is used to check if the package is already installed from
+# another source
+declare -r \
+ LINUX_PACKAGES=(\
+ 'dante' 'aerc'
+ 'w3m' 'aerc'
+ 'aerc' 'aerc'
+ 'alacritty' 'alacritty'
+ 'bat' 'bat'
+ 'calc' 'calc'
+ 'dust' 'dust'
+ 'exa' 'exa'
+ 'fd' 'fd'
+ 'foliate' 'foliate'
+ 'fuzzel' 'fuzzel'
+ 'fzf' 'fzf'
+ 'gawk' 'gawk'
+ 'git' 'git'
+ 'git-lfs' 'git-lfs'
+ 'grim' 'grim'
+ 'pass' 'pass'
+ 'slurp' 'slurp'
+ 'swappy' 'swappy'
+ 'imv' 'imv'
+ 'jq' 'jq'
+ 'mpv' 'mpv'
+ 'neofetch' 'neofetch'
+ 'neovim' 'nvim'
+ 'paru' 'paru'
+ 'ripgrep' 'rg'
+ 'sway' 'sway'
+ 'swaybg' 'swaybg'
+ 'swaylock' 'swaylock'
+ 'tealdeer' 'tldr'
+ 'tmux' 'tmux'
+ 'udisks2' 'udisksctl'
+ 'vifm' 'vifm'
+ 'viu' 'viu'
+ 'wl-clipboard' 'wl-paste'
+ 'wtype' 'wtype'
+ 'zathura-pdf-mupdf' 'zathura'
+ 'zathura' 'zathura'
+ ) \
+ CARGO_PACKAGES=(\
+ 'alacritty' 'alacritty'
+ 'bat' 'bat'
+ 'du-dust' 'dust'
+ 'exa' 'exa'
+ 'fd-find' 'fd'
+ 'ripgrep' 'rg'
+ 'tealdeer' 'tldr'
+ 'viu' 'viu'
+ ) \
+ BREW_PACKAGES=(\
+ 'bash' 'bat' 'calc' 'coreutils' 'dust' 'exa' 'fd' 'fzf' 'gawk' 'git'
+ 'imagemagick' 'jq' 'mmv' 'mpv' 'neofetch' 'node' 'nvim' 'pngpaste'
+ 'python3' 'ripgrep' 'skhd' 'tealdeer' 'tmux' 'vifm' 'viu' 'yabai'
+ ) \
+ AUR_PACKAGES=(\
+ 'mmv' 'mmv'
+ 'nerd-fonts-meslo' 'font-manager'
+ 'vimiv-qt-git' 'vimiv'
+ 'warpd-wayland-git' 'warpd'
+ 'wev' 'wev'
+ 'wlsunset' 'wlsunset'
+ )
+
+print_help() {
+ cat </dev/null && [[ "$(uname -s)" == "Darwin" ]]; then
+ eval "$(curl -fsSL 'https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh')"
+ fi
+
+ if command -v paru &> /dev/null; then PACMAN='paru -S'
+ elif command -v pacman &> /dev/null; then PACMAN='sudo pacman -S'
+ elif command -v apt-get &> /dev/null; then PACMAN='sudo apt-get install'
+ elif command -v apk &> /dev/null; then PACMAN='sudo apk add'
+ elif command -v rpm &> /dev/null; then PACMAN='rpm -ihv'
+ elif command -v brew &> /dev/null; then PACMAN='brew install'
+ else
+ return 1
+ fi
+}
+
+list_packages() {
+ if [[ "$(uname -s)" == "Darwin" ]]; then
+ printf "==== Installed by \`%s\` =============\n" "${PACMAN}"
+
+ for pkg in "${BREW_PACKAGES[@]}"; do
+ print_package_status "$pkg" "brew"
+ done
+ elif [[ "$(uname -s)" == "Linux" ]]; then
+ printf "==== Installed by \`%s\` =============\n" "${PACMAN}"
+
+ for ((i = 0; i < "${#LINUX_PACKAGES[@]}"; i=(i+2) )); do
+ print_package_status "${LINUX_PACKAGES[$i + 1]}" "$PACMAN"
+ done
+ fi
+
+ printf "==== Installed by \`cargo install\` =============\n"
+ for ((i = 0; i < "${#CARGO_PACKAGES[@]}"; i=(i+2) )); do
+ print_package_status "${CARGO_PACKAGES[$i + 1]}" "cargo"
+ done
+}
+
+print_package_status() {
+ if [[ "$2" == "cargo" ]] && [[ -x "${HOME}/.cargo/bin/$1" ]]; then
+ printf "✓ %s :: Installed\n" "$1"
+ elif [[ "$2" == "cargo" ]]; then
+ printf "✗ %s :: Not installed\n" "$1"
+ elif [[ "$2" == brew* ]] && brew list "$1" &>/dev/null; then
+ printf "✓ %s :: Installed\n" "$1"
+ elif [[ "$2" == brew* ]]; then
+ printf "✗ %s :: Not installed\n" "$1"
+ elif command -v "$1" &> /dev/null; then
+ printf "✓ %s :: Installed\n" "$1"
+ else
+ printf "✗ %s :: Not installed\n" "$1"
+ fi
+}
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Pαckαgε iηsταllεrs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+install_web_packages() {
+ if ! command -v rustup &>/dev/null && ask "Install rustup?"; then
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+ fi
+
+ if ! [[ -e ~/.config/tmux/plugins/tpm ]] && ask "Install tmux's plugin manager?"; then
+ git clone --depth 1 'https://github.com/tmux-plugins/tpm' ~/.config/tmux/plugins/tpm
+ ~/.config/tmux/plugins/tpm/tpm
+ ~/.config/tmux/plugins/tpm/bin/install_plugins
+ ~/.config/tmux/plugins/tpm/tpm
+ fi
+
+ if [[ ! -f ~/.git-prompt.bash ]] && ask "Download git-prompt for bash?"; then
+ curl --output ~/.git-prompt.bash\
+ 'https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh'
+ fi
+
+ if [[ ! -f ~/.git-completion.bash ]] && ask "Download git-completion for bash?"; then
+ curl --output ~/.git-completion.bash\
+ 'https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash'
+ fi
+
+ if [[ ! -f ~/.fzf.bash ]] && ask "Download fzf-completion for bash?"; then
+ curl --output ~/.fzf.bash\
+ 'https://raw.githubusercontent.com/junegunn/fzf/master/shell/completion.bash'
+ fi
+
+ if ask "Install vim plugins?"; then
+ if command -v vim &>/dev/null; then
+ vim +$'if !has(\'nvim\') | PlugInstall --sync | endif' +qall
+ elif command -v vi &>/dev/null; then
+ vi +$'if !has(\'nvim\') | PlugInstall --sync | endif' +qall
+ else
+ printf "Run :PlugInstall in nVim to finish setting up vim's plugins\n"
+ fi
+
+ if command -v pip3 &>/dev/null && ! pip3 list 2>&1 | grep -q '^pynvim'; then
+ pip3 install pynvim
+ fi
+ fi
+}
+
+install_cargo_packages() {
+ if ! command -v cargo &> /dev/null; then
+ printf 'Cargo package manager not found\n'
+ return 1
+ fi
+
+ for ((i = 0; i < "${#CARGO_PACKAGES[@]}"; i=(i+2) )); do
+ local bin="${CARGO_PACKAGES[$i + 1]}"
+ local name="${CARGO_PACKAGES[$i]}"
+
+ if ! command -v "${bin}" &>/dev/null && ask "Cargo install ${name}?"; then
+ cargo install "${name}"
+ fi
+ done
+}
+
+install_brew_packages() {
+ brew tap koekeishiya/formulae
+
+ printf 'Checking brew packages. Brew is slow. This may take a while...\n'
+
+ for pkg in "${BREW_PACKAGES[@]}"; do
+ if [[ -z "$(brew list "${pkg}")" ]] \
+ && ! command -v "${pkg}" &>/dev/null \
+ && ask "Install ${pkg}?"; then
+ brew install "${pkg}"
+ fi
+ done
+}
+
+# May or may not work. Tested with pacman on arch
+install_linux_packages() {
+ for ((i = 0; i < "${#LINUX_PACKAGES[@]}"; i=(i+2) )); do
+ local bin="${LINUX_PACKAGES[$i + 1]}"
+ local name="${LINUX_PACKAGES[$i]}"
+
+ if ! command -v "${bin}" &>/dev/null && ask "Install ${name}?"; then
+ eval "${PACMAN} ${name}"
+ fi
+ done
+}
+
+# Very tentative. Only works on linux and only installs essentials for ssh
+install_curl_packages() {
+ mkdir -p ~/bin
+
+ if ! command -v fzf &>/dev/null && ask 'Download fzf?'; then
+ curl --output 'fzf_download.tar.gz' \
+ -LO 'https://github.com/junegunn/fzf/releases/download/0.28.0/fzf-0.28.0-linux_amd64.tar.gz'
+ tar xf 'fzf_download.tar.gz'
+ chmod u+x ./fzf
+ rm -f 'fzf_download.tar.gz'
+ fi
+
+ if ! command -v neofetch &>/dev/null && ask 'Download neofetch?'; then
+ curl --output "neofetch.tar.gz" \
+ -LO 'https://github.com/dylanaraps/neofetch/archive/refs/tags/7.1.0.tar.gz'
+ tar xf 'neofetch.tar.gz'
+ mv ./neofetch-*/neofetch ./neofetch
+ rm -rf 'neofetch.tar.gz' 'neofetch-7.1.0'
+ fi
+
+ if ! command -v tmux &>/dev/null && ask 'Download tmux?'; then
+ curl --output 'tmux.tar.gz' \
+ -LO 'https://github.com/tmux/tmux/releases/download/3.2a/tmux-3.2a.tar.gz'
+ tar xf 'tmux.tar.gz'
+ (cd tmux-* && ./configure && make && mv ./tmux ../tmux)
+ rm -rf 'tmux.tar.gz' ./tmux-*
+ fi
+
+ if ! command -v nvim &>/dev/null && ask 'Download neovim?'; then
+ curl -LO 'https://github.com/neovim/neovim/releases/latest/download/nvim.appimage'
+ chmod u+x ./nvim.appimage
+ mv ./nvim.appimage ./nvim
+ fi
+}
+
+#######################################
+# Arguments:
+# 1: Prompt message
+# Return:
+# 0 for yes, 1 for no
+#######################################
+ask () {
+ read -rp $'\n'"$1 ([y]/n) "
+ [[ "${REPLY:-y}" =~ ^[Yy][es]?$ ]]
+}
+
+
+main "$@"
+
+# vim: set ft=bash syn=bash sw=2 ff=unix:
diff --git a/ripgrep/config b/ripgrep/config
new file mode 100644
index 0000000..f62167a
--- /dev/null
+++ b/ripgrep/config
@@ -0,0 +1,8 @@
+--glob
+!git/*
+
+--glob
+!node_modules
+
+--glob
+!target
diff --git a/sketchybar/com.sketchybar.launcher.template b/sketchybar/com.sketchybar.launcher.template
new file mode 100644
index 0000000..2b5ba0b
--- /dev/null
+++ b/sketchybar/com.sketchybar.launcher.template
@@ -0,0 +1,32 @@
+
+
+
+
+ Label
+ com.sketchybar.launcher
+
+ ProgramArguments
+
+ HOMEPATH/bin/sketchybar
+
+
+ EnvironmentVariables
+
+ PATH
+ HOMEPATH/.config/sketchybar:HOMEPATH/.config/sketchybar/plugins:/bin:/usr/local/bin
+
+
+ RunAtLoad
+
+
+ ThrottleInterval
+ 10
+
+ StandardOutPath
+ /tmp/sketchy.out
+
+ StandardErrorPath
+ /tmp/sketchy.err
+
+
+
diff --git a/sketchybar/plugins/yabai_spaces.js b/sketchybar/plugins/yabai_spaces.js
new file mode 100755
index 0000000..c56efdb
--- /dev/null
+++ b/sketchybar/plugins/yabai_spaces.js
@@ -0,0 +1,110 @@
+#!/usr/bin/env node
+// Tmux-line inspired yabai spaces on sketchybar
+const sh = require('child_process');
+
+const mode = process.argv[2];
+const curr_space_id = process.env.YABAI_SPACE_ID;
+const prev_space_id = process.env.YABAI_RECENT_SPACE_ID;
+
+if (mode === "--update" )
+ updateSketchybar();
+else if (mode === "--refresh")
+ refreshOnly(prev_space_id, curr_space_id);
+else
+ console.error(`Mode ${mode} is invalid\nUse one of --refresh or --update`);
+
+// Wrapper around child process spawn
+function spawn(cmd, args, name) {
+ let output = sh.spawnSync(cmd, args);
+
+ if (output.status !== 0) {
+ console.error(`${name} failed with exit code ${output.status}`);
+
+ if (output.stderr) console.error(output.stderr.toString());
+ else console.log("No stderr");
+
+ process.exit(1);
+ }
+
+ return output
+}
+
+
+// Refreshes "focus" colors between previous and current space
+// Args: ID of current and previous spaces
+function refreshOnly(prev, curr) {
+ prev = `yabai_space_${prev}`;
+ curr = `yabai_space_${curr}`;
+
+ spawn(
+ "sketchybar",
+ [
+ "--set", prev,
+ `label.background.color=0xFF4E4E4E`,
+ `label.color=0xFFEBDBB2`,
+
+ "--set", curr,
+ `label.background.color=0xFFC8CB36`,
+ `label.color=0xFF000000`,
+ ],
+ `Refreshing ${prev} and ${curr}`
+ );
+}
+
+
+// Removes all current yabai spaces from sketchybar. Then creates new spaces
+// from current data
+function updateSketchybar() {
+ let spaces = spawn("yabai", ["-m", "query", "--spaces"], "Yabai query");
+
+ spaces = JSON.parse(spaces.stdout);
+
+ removeSketchybarSpaces();
+
+ // Reorder spaces based on index. Yabai does not guarantee order
+ let ordered_spaces = new Array(spaces.length);
+
+ spaces.forEach(s => {
+ ordered_spaces[s.index - 1] = {
+ id: s.id,
+ is_focused: s.focused === 1,
+ };
+ });
+
+ // Construct sketchybar shell call
+ let sketchy_args = new Array();
+
+ ordered_spaces.forEach((s, i) => {
+ sketchy_args.push(
+ "--add", "space", `yabai_space_${s.id}`, "left",
+ "--set", `yabai_space_${s.id}`,
+ `label=E${i + 1}`, // Works best with crashnumberingserif font
+ "label.font=crashnumberingserif:Normal:28.0",
+ `label.color=0xFF${s.is_focused ? "000000" : "EBDBB2"}`,
+ "label.background.height=30",
+ "label.background.corner_radius=20",
+ `label.background.color=0xFF${s.is_focused ? "C8CB36" : "4E4E4E"}`,
+ "label.padding_left=6",
+ "label.padding_right=20",
+ `click_script=yabai -m space --focus ${i + 1}`
+ );
+ });
+
+ spawn("sketchybar", sketchy_args, "Sketchybar add all spaces");
+}
+
+
+// Remove all yabai spaces from sketchybar
+function removeSketchybarSpaces() {
+ let bar = spawn("sketchybar", ["--query", "bar"], "Sketchybar query");
+
+ let tag, sketchy_args = new Array();
+
+ JSON.parse(bar.stdout).items.forEach(item => {
+ tag = item.match(/yabai_space_[0-9]+/);
+
+ if (tag) sketchy_args.push("--remove", tag);
+ });
+
+ if (sketchy_args.length) spawn("sketchybar", sketchy_args, "Remove all");
+}
diff --git a/sketchybar/sketchybarrc b/sketchybar/sketchybarrc
new file mode 100755
index 0000000..b9abfb2
--- /dev/null
+++ b/sketchybar/sketchybarrc
@@ -0,0 +1,155 @@
+#!/usr/bin/env bash
+# This is a demo config to bring across some of the most important commands more easily.
+# For a more advanced configuration example see https://github.com/FelixKratz/SketchyBar/discussions/47#discussion-3587958
+FONT="Meslo"
+
+############## BAR ##############
+sketchybar -m --bar height=35 \
+ blur_radius=40 \
+ position=bottom \
+ padding_left=10 \
+ padding_right=10 \
+ corner_radius=20 \
+ topmost=false \
+ color=0x44000000
+ #color=0x44FF8700
+#spaces=()
+#for i in {1..8}
+#do
+# spaces+=(--add space space$i left \
+# --set space$i associated_display=1 associated_space=$i icon=$i)
+#done
+
+sketchybar -m \
+ --add item yabai_spaces left \
+ --set yabai_spaces script="~/.config/sketchybar/plugins/yabai_spaces.js --update" \
+ --subscribe yabai_spaces #front_app_switched #\
+ #"${spaces[@]}"
+
+sketchybar -m --add event window_created \
+ --add event window_destroyed
+
+############## GLOBAL DEFAULTS ##############
+sketchybar -m --default updates=when_shown \
+ drawing=on \
+ cache_scripts=on \
+ icon.font="Hack Nerd Font:Bold:17.0" \
+ icon.color=0xffffffff \
+ label.font="Hack Nerd Font:Bold:14.0" \
+ label.color=0xffffffff
+
+############## SPACE DEFAULTS ##############
+sketchybar -m --default label.padding_left=2 \
+ label.padding_right=2 \
+ icon.padding_left=8 \
+ label.padding_right=8
+
+############## PRIMARY DISPLAY SPACES ##############
+#sketchybar -m --add space code left \
+# --set code associated_display=1 \
+# associated_space=1 \
+# icon.font="Hack Nerd Font:Bold:20.0" \
+# icon= \
+# icon.highlight_color=0xff48aa2a \
+# label=code \
+# click_script="yabai -m space --focus 1" \
+# \
+# --add space tex left \
+# --set tex associated_display=1 \
+# associated_space=2 \
+# icon= \
+# icon.highlight_color=0xfffab402 \
+# label=tex \
+# click_script="yabai -m space --focus 2"
+
+
+############## ITEM DEFAULTS ###############
+#sketchybar -m --default label.padding_left=2 \
+# icon.padding_right=2 \
+# icon.padding_left=6 \
+# label.padding_right=6
+#
+#
+############### LEFT ITEMS ##############
+#sketchybar -m --add item space_separator left \
+# --set space_separator icon= \
+# associated_space=1 \
+# icon.padding_left=15 \
+# label.padding_right=15 \
+# icon.font="Hack Nerd Font:Bold:15.0" \
+# \
+# --add item gitNotifications left \
+# --set gitNotifications associated_space=1 \
+# update_freq=300 \
+# icon.font="Hack Nerd Font:Bold:18.0" \
+# icon= \
+# script="~/.config/sketchybar/plugins/gitNotifications.sh" \
+# click_script="open https://github.com/notifications" \
+# --subscribe gitNotifications system_woke \
+# \
+# --add item githubIndicator left \
+# --set githubIndicator associated_space=1 \
+# update_freq=1000 \
+# icon.font="Hack Nerd Font:Bold:18.0" \
+# icon= \
+# click_script="open https://github.com" \
+# script="~/.config/sketchybar/plugins/githubIndicator.sh" \
+# --subscribe githubIndicator system_woke \
+# \
+# --add item topmem left \
+# --set topmem associated_space=1 \
+# icon.padding_left=10 \
+# update_freq=15 \
+# script="~/.config/sketchybar/plugins/topmem.sh"
+#
+############### RIGHT ITEMS ##############
+#sketchybar -m --add item clock right \
+# --set clock update_freq=10 \
+# script="~/.config/sketchybar/plugins/clock.sh" \
+# \
+# --add item mailIndicator right \
+# --set mailIndicator associated_space=1,2,3 \
+# update_freq=30 \
+# script="~/.config/sketchybar/plugins/mailIndicator.sh" \
+# icon.font="Hack Nerd Font:Bold:20.0" \
+# icon= \
+# click_script="osascript -e 'tell application \"Mail\" to activate'"
+#
+## Creating Graphs
+#sketchybar -m --add graph cpu_user right 200 \
+# --set cpu_user graph.color=0xffffffff \
+# update_freq=2 \
+# width=0 \
+# associated_space=1 \
+# label.padding_left=0 \
+# icon= \
+# script="~/.config/sketchybar/plugins/cpu_graph.sh" \
+# lazy=on \
+# \
+# --add graph cpu_sys right 200 \
+# --set cpu_sys label.padding_left=0 \
+# associated_space=1 \
+# icon= \
+# graph.color=0xff48aa2a \
+# \
+# --add item topproc right \
+# --set topproc associated_space=1 \
+# label.padding_right=10 \
+# update_freq=15 \
+# script="~/.config/sketchybar/plugins/topproc.sh"
+
+###################### CENTER ITEMS ###################
+
+# Adding custom events which can listen on distributed notifications from other running processes
+#sketchybar -m --add event spotify_change "com.spotify.client.PlaybackStateChanged" \
+# --add item spotifyIndicator center \
+# --set spotifyIndicator script="~/.config/sketchybar/plugins/spotifyIndicator.sh" \
+# --set spotifyIndicator click_script="osascript -e 'tell application \"Spotify\" to pause'" \
+# --subscribe spotifyIndicator spotify_change
+
+############## FINALIZING THE SETUP ##############
+sketchybar -m --update
+
+~/.config/sketchybar/plugins/yabai_spaces.js --refresh
+echo "sketchybar configuration loaded.."
+
diff --git a/skhd/com.skhd.launcher.template b/skhd/com.skhd.launcher.template
new file mode 100644
index 0000000..0eae8a0
--- /dev/null
+++ b/skhd/com.skhd.launcher.template
@@ -0,0 +1,42 @@
+
+
+
+
+ Label
+ com.skhd.launcher
+
+ ProgramArguments
+
+ /usr/local/bin/skhd
+ --no-hotload
+
+
+ EnvironmentVariables
+
+ PATH
+ HOMEPATH/.configs_pointer/skhd/scripts:HOMEPATH/bin:HOMEPATH/.configs_pointer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+
+
+ RunAtLoad
+
+
+ KeepAlive
+
+ SuccessfulExit
+
+ Crashed
+
+
+
+
+
+ ThrottleInterval
+ 10
+
+ StandardOutPath
+ /tmp/skhd.out
+
+ StandardErrorPath
+ /tmp/skhd.err
+
+
diff --git a/skhd/scripts/record_audio_line b/skhd/scripts/record_audio_line
new file mode 100755
index 0000000..371b930
--- /dev/null
+++ b/skhd/scripts/record_audio_line
@@ -0,0 +1,41 @@
+#!/bin/bash
+# Record a few seconds of system audio, and save. Intended to seamlessly record
+# audio for anki cards, while watching anime. MacOS only
+#
+# May require changing capture device. Find available options with:
+# $ ffmpeg -f avfoundation -list_devices true -i ""
+# Change the number in the ffmpeg argument to desired device. BlackHole-2ch is
+# recommended for recording macos system audio. Make sure vlc's output device
+# is an aggregate of BlackHole-2ch and the speakers
+#
+# External dependencies: ffmepg, BlackHole-2ch
+
+if [[ $(uname) != 'Darwin' ]]; then
+ printf 'This is meant for MacOS\nAborting...\n'
+ exit 1
+fi
+
+recording_name="$(date +'%m_%d_%Y-%H_%M_%S' | awk '{printf("%s%s", $0, ".mp3")}')"
+
+mkdir -p ~/Desktop/anki_recordings
+
+ffmpeg \
+ -f avfoundation \
+ -i ":2" -filter:a "atempo=0.95" \
+ -t "${1:-6}" \
+ ~/"Desktop/anki_recordings/${recording_name}"
+
+unset recording_name
+
+# Further reference ====
+# Rec audio with ffmpeg
+# https://apple.stackexchange.com/questions/326388/terminal-command-to-record-audio-through-macbook-microphone
+#
+# With vlc? Wouldn't require BlackHole-2ch this way
+# https://forum.videolan.org/viewtopic.php?t=87923
+#
+# Trim on the fly? Save a unix timestamp in a file, then have ffmpeg trim the
+# recording based on the time in the file. Use a second hotkey to edit the
+# file's time with the current timestamp. Default should be +10s from start
+# https://unix.stackexchange.com/questions/182602/trim-audio-file-using-start-and-stop-times
+# ex: set syntax=bash:ff=unix:
diff --git a/skhd/scripts/shrink_screenshot_clipboard b/skhd/scripts/shrink_screenshot_clipboard
new file mode 100755
index 0000000..28d1b1d
--- /dev/null
+++ b/skhd/scripts/shrink_screenshot_clipboard
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+# $ shrink_screenshot_clipboard [resize-percent]
+#
+# Resize the image on the clipboard and save as
+# ~/Desktop/shrink_screenshot_out.png. Intended for use with the MacOS
+# screenshot tool
+#
+# External dependencies: pngpaste, convert (ImageMagick)
+
+if [[ $(uname) != 'Darwin' ]]; then
+ printf 'This is meant for MacOS\nAborting...\n'
+ exit 1
+fi
+
+ # Random seed at the end to avoid conflicts
+screenshot=$(mktemp)
+
+if pngpaste - > "$screenshot"; then
+ convert "$screenshot" -resize "${1:-50}%" ~/Desktop/shrink_screenshot_out.png
+else
+ # Play error sound to notify script failing
+ play_error_sound
+ osascript -e 'display notification "Failed to resize clipboard" with title "Skhd"'
+fi
+
+unset screenshot
+# vim: set syn=bash ff=unix:
diff --git a/skhd/scripts/shrink_screenshot_desktop b/skhd/scripts/shrink_screenshot_desktop
new file mode 100755
index 0000000..0aef065
--- /dev/null
+++ b/skhd/scripts/shrink_screenshot_desktop
@@ -0,0 +1,26 @@
+#!/bin/bash
+# $ shrink_screenshot_desktop [resize-percent]
+#
+# Half the size of the lastest screenshot on the desktop. Saves as
+# ~/Desktop/shrink_screenshot_out.png. Intended for use with the MacOS
+# screenshot tool
+#
+# External dependencies: fd, convert (ImageMagick)
+
+if [[ $(uname) != 'Darwin' ]]; then
+ printf 'This is meant for MacOS\nAborting...\n'
+ exit 1
+fi
+
+#fd 'Screen Shot' --extension 'png' ~/Desktop | awk 'END { gsub(/ /, " ", $0); print }'
+#screenshot=~/"Desktop/$(ls -tr ~/Desktop | grep 'Screen Shot .*\.png$' | tail -n 1)"
+screenshot="$(ls -tr ~/Desktop/*"Screen Shot"*".png" | tail -n 1)"
+
+if [[ $screenshot != '' ]]; then
+ convert "$screenshot" -resize "${1:-50}%" ~/Desktop/shrink_screenshot_out.png
+else
+ # Play error sound to notify script failing
+ play_error_sound
+fi
+unset screenshot
+# ex: set syntax=bash:ff=unix:
diff --git a/skhd/skhdrc b/skhd/skhdrc
new file mode 100644
index 0000000..2a0967a
--- /dev/null
+++ b/skhd/skhdrc
@@ -0,0 +1,460 @@
+# Reference:
+# https://github.com/koekeishiya/skhd/blob/master/examples/skhdrc
+# https://github.com/koekeishiya/skhd/issues/1
+
+# Applications without hotkeys
+.blacklist [
+ #"iTerm2"
+ "Terminal"
+ "MacVim"
+ "Parallels Desktop"
+ #"qutebrowser"
+ #"cool-retro-term"
+]
+
+# Match Firefox's incognito shortcut to Chrome's
+cmd + shift - n [
+ "Firefox" : skhd -k "cmd + shift - p"
+ * ~
+]
+
+cmd + ctrl - n [
+ "Google Chrome" : skhd -k "cmd + shift - n" \
+ && skhd -t "~/Documents/other_stuff/canvas/Konachan.com - 320663 book dampi elaina_(majo_no_tabitabi) flowers gray_eyes gray_hair long_hair majo_no_tabitabi stairs witch.jpg" \
+ && skhd -k "return"
+ * ~
+]
+
+# Prevent full quit
+cmd - q [
+ "Google Chrome": play_error_sound
+ "Preview": play_error_sound
+ * ~
+]
+
+cmd + ctrl - y : skhd -k "alt - left"\
+ && skhd -t "~~"\
+ && skhd -k "alt - right"\
+ && skhd -t "~~"
+
+cmd + ctrl - r : skhd -t "AsExpectedOfRust"
+
+cmd + ctrl - a : open -na "Chromium" --args --incognito \
+ --window-size=1250,800 --window-position=200,140
+
+# Rofi menu
+#cmd + shift - space : ~/.configs_pointer/skhd/scripts/rofi_macos
+
+#0x35 : skhd -k "0x32"
+
+#cmd - r : skhd -t "step"; skhd -k "0x24"
+#ctrl - h : skhd -k "backspace"
+
+
+#default < escape : skhd -k "0x32"
+#default < cmd - escape : skhd -k "cmd - 0x32"
+#default < 0x35 : skhd -k "~"
+
+#[ Never Quit ]
+#@PassThroughOther
+#@Include Google Chrome
+#@Include Preview
+#
+# :: play_error_sound
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Kεybδαrd δvεrr𝓲dεs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+# By letter ====
+ctrl - j [
+ "Alacritty" ~
+ * : skhd -k "left"
+]
+ctrl - f [
+ "Alacritty" ~
+ * : skhd -k "right"
+]
+ctrl - h [
+ "Alacritty" ~
+ * : skhd -k "backspace"
+]
+ctrl - d [
+ "Alacritty" ~
+ "qutebrowser" ~
+ * : skhd -k "delete"
+]
+# Vertically ====
+ctrl - p [
+ "Alacritty" ~
+ * : skhd -k "up"
+]
+ctrl - n [
+ "Alacritty" ~
+ * : skhd -k "down"
+]
+# By word ====
+ctrl - b [
+ "Alacritty" ~
+ * : skhd -k "alt - left"
+]
+ctrl - w [
+ "Alacritty" ~
+ * : skhd -k "alt - right"
+]
+ctrl - u [
+ "Alacritty" ~
+ "qutebrowser" ~
+ * : skhd -k "alt + shift - left"
+]
+ctrl - r [
+ "Alacritty" ~
+ * : skhd -k "alt + shift - right"
+]
+# By line ====
+ctrl - a [
+ "Alacritty" ~
+ * : skhd -k "cmd - left"
+]
+ctrl - e [
+ "Alacritty" ~
+ * : skhd -k "cmd - right"
+]
+ctrl - k [
+ "Alacritty" ~
+ "qutebrowser" ~
+ * : skhd -k "cmd + shift - right"
+]
+# Other ====
+ctrl - 0x21 [ #
+ "Alacritty" ~
+ * : skhd -k "escape"
+]
+ctrl - y [
+ "Alacritty" ~
+ * : skhd -k "cmd - c"
+]
+
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Gεnεrαl cδmmαnd mδdε |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+:: general @ : sketchybar -m --bar color=0xFFFF8700 # \
+ #ffplay -t '1000' -nodisp -autoexit -loglevel error \
+ #~/.config/skhd/stutter-woosh.wav
+
+# Toggle general mode ====
+default < cmd - g ; general
+general < escape ; default
+general < ctrl - 0x21 : sketchybar -m --bar color=0x44000000; \
+ skhd -k "escape"
+
+# Shrink screenshot and save to desktop ====
+general < 0 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 100 # Save clipboard to desktop
+general < 9 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 90 # Shrink from clipboard
+general < 8 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 80
+general < 7 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 70
+general < 6 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 60
+general < 5 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 50
+general < 4 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 40
+general < 3 : skhd -k "ctrl - 0x21"; shrink_screenshot_clipboard 30
+#general < d : skhd -k "ctrl - 0x21"; shrink_screenshot_desktop # Lastest screenshot on ~/Desktop
+
+# Vi-like scrolling for browsers ====
+general < g : skhd -k "ctrl - 0x21"; skhd -k "cmd - up"; skhd -k "cmd + ctrl - g"
+general < shift- g : skhd -k "ctrl - 0x21"; skhd -k "cmd - down"; skhd -k "cmd + ctrl - g"
+general < ctrl - u : skhd -k "ctrl - 0x21"; skhd -k "alt - up"; skhd -k "cmd + ctrl - g"
+general < ctrl - d : skhd -k "ctrl - 0x21"; skhd -k "alt - down"; skhd -k "cmd + ctrl - g"
+general < k : skhd -k "ctrl - 0x21"; skhd -k "up"; skhd -k "cmd + ctrl - g"
+general < j : skhd -k "ctrl - 0x21"; skhd -k "down"; skhd -k "cmd + ctrl - g"
+general < shift- h : skhd -k "ctrl - 0x21"; skhd -k "cmd - left"; skhd -k "cmd + ctrl - g"
+general < shift- l : skhd -k "ctrl - 0x21"; skhd -k "cmd - right";skhd -k "cmd + ctrl - g"
+general < shift- j : skhd -k "ctrl - 0x21"; skhd -k "cmd + alt - left"; skhd -k "cmd + ctrl - g"
+general < shift- k : skhd -k "ctrl - 0x21"; skhd -k "cmd + alt - right";skhd -k "cmd + ctrl - g"
+
+
+cmd + ctrl - q : record_audio_line 10 # Audio capture while watching on vlc
+
+
+# Other convenience tools ====
+### Upload clipboard to pastebin
+cmd + ctrl - x : pbpaste | ix
+
+### Backup and restore chrome incognito windows
+cmd + ctrl - e : chrome_session close \
+ ~/.config/skhd/last_incognito_window.chrome \
+ && osascript -e \
+ 'display notification "Chrome window backed up" with title "Skhd"'
+
+cmd + ctrl - r : chrome_session restore \
+ ~/.config/skhd/last_incognito_window.chrome
+
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Yαbαi ωiηdδω mαηαgεr |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+# Keybind methodology:
+# In general
+# Spaces use gamer-style `wasd`
+# Windows use vim-style `hjkl`
+#
+# <>:
+# All default mode bindings are indentically available in yabai mode
+# cmd shift {a,d} : switches to adjacent space
+# cmd shift {h,j,k,l} : switches to window in that direction
+# cmd {[, ]} : move window onto left or right stack
+# cmd shift {[, ]} : move window onto top or bottom stack
+# cmd tab : cycle across stacks clockwise
+# cmd ` : cycle within stack
+#
+#
+# <>:
+# Prefix : cmd e
+# Escape : esc, enter,
+#
+# x : close window
+#
+# = : Balance bsp tree on y axis
+#
+# === Stacks
+#
+# === Resize window
+# {q,w,e,r} : Resize window on horizontally. qw resize left, er resize right
+# lcmd {q,w,e,r} : Resize window on vertically. qw resize top, er resize bottom
+# Add shift to the above for a smaller increment
+#
+# === Spaces
+# shift {a,d} : Move window to adjacent space, and switch to that space
+# ctrl {a,d} : Reorder space
+# n : Create new space on right, move current window and switch to it
+# ctrl q : Close space
+#
+# === Floating
+# ctrl [0-9] : Set numpad position of floating window TODO
+#
+# === Pinning
+# m : Swap to pinning mode
+# c : From pinning mode, clears pin list
+# [0-9] : From pinning mode, pins current window to specified number
+# alt [0-9] : From default mode, switch to pinned window
+# shift cmd space : From default mode pulls up rofi menu for pinned windows
+#
+# Oneshots
+default < cmd + shift - a : yabai -m space --focus prev
+default < cmd + shift - d : yabai -m space --focus next
+#default < cmd - h : # Stop accidentally hiding windows
+## Switching windows
+default < lcmd - h : yabai -m window --focus west
+default < lcmd - j : yabai -m window --focus south
+default < lcmd - k : yabai -m window --focus north
+default < lcmd - l : yabai -m window --focus east
+
+# Moving windows onto stacks
+default < lcmd - 0x21 : ~/.config/yabai/move_to_stack.sh 'west'
+default < lcmd - 0x1E : ~/.config/yabai/move_to_stack.sh 'east'
+default < shift + lcmd - 0x21 : ~/.config/yabai/move_to_stack.sh 'north'
+default < shift + lcmd - 0x1E : ~/.config/yabai/move_to_stack.sh 'south'
+
+# Cycle within stack with
+#default < lcmd - 0x32 : yabai -m window --focus stack.prev\
+# || yabai -m window --focus stack.last
+#default < lcmd + shift - 0x32 : yabai -m window --focus stack.next\
+# || yabai -m window --focus stack.first
+## Cycle between stacks with
+#default < cmd - 0x30 : yabai -m window --focus \
+# "$(yabai -m query --windows --space | ~/.config/yabai/cycle_stack.js)"
+
+
+# Pop out window
+cmd + ctrl - p : yabai -m window --toggle float && \
+ yabai -m window --grid 40:40:0:2:33:38
+# Center window
+cmd + ctrl - c : yabai -m window --toggle float && \
+ yabai -m window --grid 80:80:11:2:58:71
+
+# Yabai Mode ========================================================
+# Assumes enter and exit sounds are set up
+:: yabai @ : sketchybar -m --bar color=0xFFC8CB36; #\
+ #ffplay -nodisp -autoexit -t "1000" \
+ #~/.config/skhd/slow_air_woosh.wav &>/dev/null
+
+default < lcmd - e ; yabai
+yabai < escape ; default
+yabai < return : sketchybar -m --bar color=0x44000000; \
+ skhd -k "escape" #&&\
+ #ffplay -nodisp -autoexit -t "700"\
+ #~/.config/skhd/correct_ping.wav &>/dev/null
+yabai < ctrl - k : sketchybar -m --bar color=0x44000000; skhd -k "escape"
+yabai < ctrl - 0x21 : sketchybar -m --bar color=0x44000000; skhd -k "escape"
+ #ffplay -nodisp -autoexit -t "700"\
+ #~/.config/skhd/correct_ping.wav &>/dev/null
+
+
+#╔─────────────────────────────────────────────────────────────────────╗
+#│ Wiηdδωs |
+#╚─────────────────────────────────────────────────────────────────────╝
+# Window switching
+yabai < lcmd - h : yabai -m window --focus west
+yabai < lcmd - j : yabai -m window --focus south
+yabai < lcmd - k : yabai -m window --focus north
+yabai < lcmd - l : yabai -m window --focus east
+
+# Move windows within a space
+# Lcmd: Move | Rcmd: Swap
+yabai < lcmd + shift - h : yabai -m window --warp west
+yabai < lcmd + shift - j : yabai -m window --warp south
+yabai < lcmd + shift - k : yabai -m window --warp north
+yabai < lcmd + shift - l : yabai -m window --warp east
+
+yabai < rcmd - h : yabai -m window --swap west
+yabai < rcmd - j : yabai -m window --swap south
+yabai < rcmd - k : yabai -m window --swap north
+yabai < rcmd - l : yabai -m window --swap east
+
+# Manipulate bsp
+yabai < ctrl - b : yabai -m space --layout bsp; ~/.config/yabai/toggle_outline.bash
+yabai < ctrl - f : yabai -m space --layout float
+yabai < ctrl - y : yabai -m space --mirror y-axis
+yabai < ctrl - x : yabai -m space --mirror x-axis
+yabai < ctrl - r : yabai -m space --rotate 270
+yabai < ctrl - s : yabai -m window --toggle split
+yabai < ctrl - o : ~/.config/yabai/toggle_border.bash
+yabai < 0x18 : yabai -m space --balance # = sign
+
+# Swapping stacks
+# --swap moves target window onto current window. We want the opposite
+yabai < cmd - 0x21 : ~/.config/yabai/move_to_stack.sh 'west'
+yabai < cmd - 0x1E : ~/.config/yabai/move_to_stack.sh 'east'
+yabai < shift + cmd - 0x21 : ~/.config/yabai/move_to_stack.sh 'north'
+yabai < shift + cmd - 0x1E : ~/.config/yabai/move_to_stack.sh 'south'
+
+# Cycle within stack with
+yabai < lcmd - 0x32 : yabai -m window --focus stack.prev\
+ || yabai -m window --focus stack.last
+yabai < lcmd + shift - 0x32 : yabai -m window --focus stack.next\
+ || yabai -m window --focus stack.first
+# Cycle between stacks with
+#TODO: Depreciate or fix
+#yabai < cmd - 0x30 : yabai -m window --focus \
+# "$(yabai -m query --windows --space | ~/.config/yabai/cycle_stack.js)"
+
+yabai < x : yabai -m window --close
+yabai < 0x1B : yabai -m window --minimize # Uses -
+
+# Rofi select windows with ;
+yabai < 0x29 : skhd -k "return" && ~/.config/yabai/rofi_window.js
+
+# Move window between spaces
+yabai < shift - a : yabai -m window --space prev && \
+ yabai -m space --focus prev
+yabai < shift - d : yabai -m window --space next && \
+ yabai -m space --focus next
+
+# Resize window
+ # Horizontal
+yabai < q : yabai -m window --resize left:-30:0
+yabai < w : yabai -m window --resize left:30:0
+yabai < e : yabai -m window --resize right:-30:0
+yabai < r : yabai -m window --resize right:30:0
+ # Vertical
+yabai < lcmd - q : yabai -m window --resize top:0:-30
+yabai < lcmd - w : yabai -m window --resize top:0:30
+yabai < lcmd - e : yabai -m window --resize bottom:0:-30
+yabai < lcmd - r : yabai -m window --resize bottom:0:30
+ # Horizontal - fine
+yabai < shift - q : yabai -m window --resize left:-10:0
+yabai < shift - w : yabai -m window --resize left:10:0
+yabai < shift - e : yabai -m window --resize right:-10:0
+yabai < shift - r : yabai -m window --resize right:10:0
+ # Vertical - fine
+yabai < lcmd + shift - q : yabai -m window --resize top:0:-10
+yabai < lcmd + shift - w : yabai -m window --resize top:0:10
+yabai < lcmd + shift - e : yabai -m window --resize bottom:0:-10
+yabai < lcmd + shift - r : yabai -m window --resize bottom:0:10
+
+# Pinning windows ===
+:: pinning @ : sketchybar -m --bar color=0xFFB8BB26
+yabai < m ; pinning
+pinning < escape ; default
+pinning < ctrl - 0x21 ; yabai
+
+pinning < c : ~/.config/yabai/pin_window.js --clear; skhd -k "ctrl - 0x21"
+
+pinning < 1 : ~/.config/yabai/pin_window.js --set 1 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 2 : ~/.config/yabai/pin_window.js --set 2 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 3 : ~/.config/yabai/pin_window.js --set 3 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 4 : ~/.config/yabai/pin_window.js --set 4 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 5 : ~/.config/yabai/pin_window.js --set 5 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 6 : ~/.config/yabai/pin_window.js --set 6 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 7 : ~/.config/yabai/pin_window.js --set 7 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 8 : ~/.config/yabai/pin_window.js --set 8 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+pinning < 9 : ~/.config/yabai/pin_window.js --set 9 \
+ $(yabai -m query --windows --space | jq '.[0]["id"]'); \
+ skhd -k "ctrl - 0x21"
+
+# Focuses pinned window
+yabai < alt - 1 : ~/.config/yabai/pin_window.js --focus 1
+yabai < alt - 2 : ~/.config/yabai/pin_window.js --focus 2
+yabai < alt - 3 : ~/.config/yabai/pin_window.js --focus 3
+yabai < alt - 4 : ~/.config/yabai/pin_window.js --focus 4
+yabai < alt - 5 : ~/.config/yabai/pin_window.js --focus 5
+yabai < alt - 6 : ~/.config/yabai/pin_window.js --focus 6
+yabai < alt - 7 : ~/.config/yabai/pin_window.js --focus 7
+yabai < alt - 8 : ~/.config/yabai/pin_window.js --focus 8
+yabai < alt - 9 : ~/.config/yabai/pin_window.js --focus 9
+
+default < alt - 1 : ~/.config/yabai/pin_window.js --focus 1
+default < alt - 2 : ~/.config/yabai/pin_window.js --focus 2
+default < alt - 3 : ~/.config/yabai/pin_window.js --focus 3
+default < alt - 4 : ~/.config/yabai/pin_window.js --focus 4
+default < alt - 5 : ~/.config/yabai/pin_window.js --focus 5
+default < alt - 6 : ~/.config/yabai/pin_window.js --focus 6
+default < alt - 7 : ~/.config/yabai/pin_window.js --focus 7
+default < alt - 8 : ~/.config/yabai/pin_window.js --focus 8
+default < alt - 9 : ~/.config/yabai/pin_window.js --focus 9
+
+default < cmd + shift - space : ~/.config/yabai/pin_window.js --rofi
+
+yabai < f : yabai -m window --toggle float
+
+# Spaces ====
+# Switch space
+yabai < cmd + shift - a : yabai -m space --focus prev && yabai -m window --focus
+yabai < cmd + shift - d : yabai -m space --focus next && yabai -m window --focus
+
+default < cmd + shift - 1 : yabai -m space --focus 1 && yabai -m window --focus
+default < cmd + shift - 2 : yabai -m space --focus 2 && yabai -m window --focus
+default < cmd + shift - 3 : yabai -m space --focus 3 && yabai -m window --focus
+default < cmd + shift - 4 : yabai -m space --focus 4 && yabai -m window --focus
+default < cmd + shift - 9 : yabai -m space --focus last && yabai -m window --focus
+
+# Reorder space
+yabai < ctrl - a : yabai -m space --move prev && ~/.config/sketchybar/plugins/yabai_spaces.js --update
+yabai < ctrl - d : yabai -m space --move next && ~/.config/sketchybar/plugins/yabai_spaces.js --update
+yabai < n : ~/.config/yabai/new_space.js && ~/.config/sketchybar/plugins/yabai_spaces.js --update
+yabai < ctrl - q : ~/.config/yabai/close_space.js && ~/.config/sketchybar/plugins/yabai_spaces.js --update
+
+# Float ====
+# Center window
+yabai < c : yabai -m window --toggle float && \
+ yabai -m window --grid 80:80:11:2:58:71
+
+# Picture in picture
+yabai < p : yabai -m window --toggle sticky && \
+ yabai -m window --toggle pip
+
diff --git a/swappy/config b/swappy/config
new file mode 100644
index 0000000..002d97e
--- /dev/null
+++ b/swappy/config
@@ -0,0 +1,9 @@
+[Default]
+save_dir=/dev/shm
+save_filename_format=%s_swappy.png
+show_panel=true
+line_size=5
+text_size=20
+text_font=lovebeat
+paint_mode=brush
+early_exit=false
diff --git a/sway/brightness_lock.sh b/sway/brightness_lock.sh
new file mode 100755
index 0000000..fece529
--- /dev/null
+++ b/sway/brightness_lock.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Locks the screen and lowers-brightness. Restores brightness on unlock
+declare brightness_lvl;
+
+if ! command -v ddcutil &>/dev/null && command -v light &>/dev/null; then
+ lvl="$(light -G)"
+
+ (swaylock; light -S "$lvl") &
+ light -S 3
+elif command -v ddcutil &>/dev/null; then
+ lvl="$(ddcutil getvcp 10 | awk '{
+ gsub(" ",""); # Remove spaces
+ split($0, a, "=");
+ split(a[2], a, ",");
+ print a[1]
+ }')"
+
+ if [[ "$lvl" =~ ^[0-9]+$ ]]; then
+ (swaylock; ddcutil setvcp 10 "$lvl") &
+ ddcutil setvcp 10 1
+ else
+ swaylock
+ fi
+else
+ swaylock
+fi
+
+
diff --git a/sway/config b/sway/config
new file mode 100644
index 0000000..5389817
--- /dev/null
+++ b/sway/config
@@ -0,0 +1,442 @@
+# Default config for sway
+#
+# Copy this to ~/.config/sway/config and edit it to your liking.
+#
+# Read `man 5 sway` for a complete reference.
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Sεττiηg ναriαblεs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+# Linux MacOS Wayland identifier code
+# Alt Opt Alt_{L,R} Mod1 00000008
+# Logo key Command Super_{L,R} Mod4 00000040
+# Control Ctrl Control_{L,R} Control 00000004
+# Shift Shift Shift_{L,R}
+# Fn Fn XF86Fn
+#
+# Arrow keys are Left|Down|Up|Right
+#
+set $mod1 Mod4
+set $mod2 Mod4+Shift
+
+# Pane movement keys - vim
+set $pane_left h
+set $pane_down j
+set $pane_up k
+set $pane_right l
+
+# Symmetric keys - mpv
+set $left_outer q
+set $left_inner w
+set $right_inner e
+set $right_outer r
+
+# Space movement keys - gaming
+set $space_up w
+set $space_left a
+set $space_down s
+set $space_right d
+
+# Resize keys - vim windows
+set $size_up comma
+set $size_down period
+
+set $term alacritty
+set $menu fuzzel -fmonospace:size=14 -l10 -w40 \
+ -b222222e0 -t8ec07cff -mffaf00ff -s222222ff -Sebdbb2ff -Cffaf00ff
+
+
+# Sound effects and additional features
+set $volume_command ~/.config/sway/pulse_audio_volume.sh
+set $volume_notify_sound ~/.config/sway/pop_sound.mp3
+
+set $screenshot_sound ffplay -nodisp -autoexit -v error \
+ ~/.config/sway/screenshot_sound.mp3
+
+# TODO: Unique sensible name
+set $original_path ~/Desktop/shrink_screenshot_out.png
+set $compress_path ~/Desktop/shrink_screenshot_out.webp
+set $shrink_path ~/Desktop/shrink_screenshot_out.png
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Pαηεs αηd cδηταiηεrs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+ # Move focus
+bindsym $mod1+$pane_left focus left
+bindsym $mod1+$pane_down focus down
+bindsym $mod1+$pane_up focus up
+bindsym $mod1+$pane_right focus right
+
+ # Move focused window
+bindsym $mod2+$pane_left move left
+bindsym $mod2+$pane_down move down
+bindsym $mod2+$pane_up move up
+bindsym $mod2+$pane_right move right
+
+ # Layout modifiers
+bindsym $mod2+f floating toggle
+bindsym $mod2+s layout stacking
+bindsym $mod2+t layout tabbed
+bindsym $mod2+r layout toggle
+
+ # Binary split container
+bindsym $mod1+b split toggle
+bindsym $mod1+v split none
+bindsym $mod1+m fullscreen
+
+ # Switch container layout Stacking|Tabbed|Rotate-bsp
+bindsym $mod1+s layout stacking
+bindsym $mod1+t layout tabbed
+bindsym $mod1+r layout toggle split
+
+ # Traverse window tree
+bindsym $mod1+u focus parent
+bindsym $mod1+d focus child
+
+ # Alt-tab cycles windows, like on proprietary systems
+bindsym $mod1+tab exec ~/.config/sway/cycle_windows.py next
+bindsym $mod2+tab exec ~/.config/sway/cycle_windows.py previous
+
+ # Swap focus between the tiling area and the floating area
+#bindsym $mod+space focus mode_toggle
+
+ # Important rust jerk
+bindsym $mod1+ctrl+r exec wtype "asExpectedOfRust"
+
+# rEsize containers ====
+bindsym $mod1+e mode "resize"
+
+mode "resize" {
+ # Horizontal, shift for fine adjust
+ bindsym $size_up resize grow width 16px
+ bindsym $size_down resize shrink width 16px
+ bindsym $size_up+Shift resize grow width 4px
+ bindsym $size_down+Shift resize shrink width 4px
+
+ # Vertical, shift for fine adjust
+ bindsym $mod1+$size_down resize shrink height 16px
+ bindsym $mod1+$size_up resize grow height 16px
+ bindsym $mod1+$size_down+Shift resize shrink height 4px
+ bindsym $mod1+$size_up+Shift resize grow height 4px
+
+ # Escaping
+ bindsym $mod1+f mode "workspace_tuning"
+
+ bindsym Shift+end mode "default"
+ bindsym Ctrl+k mode "default"
+ bindsym Ctrl+bracketleft mode "default"
+ bindsym Escape mode "default"
+}
+
+# Gaps ====
+bindsym $mod2+bracketright gaps inner current minus 3
+bindsym $mod2+bracketleft gaps inner current plus 3
+#bindsym $mod2+equal gaps toggle
+ # Standard outer gapping for 27" screen
+bindsym $mod2+c gaps vertical current set 100, \
+ gaps horizontal current set 200
+ # Same as above, shifted left slightly
+bindsym $mod2+g gaps vertical current set 100, \
+ gaps left current set 150, \
+ gaps right current set 250
+
+bindsym $mod1+g mode "gapping"
+mode "gapping" {
+ # General resize
+ bindsym $mod2+bracketright gaps inner current minus 3
+ bindsym $mod2+bracketleft gaps inner current plus 3
+
+ # Horizontal
+ bindsym q gaps left current minus 2
+ bindsym w gaps left current plus 2
+ bindsym e gaps right current plus 2
+ bindsym r gaps right current minus 2
+
+ # Vertical
+ bindsym $mod1+q gaps top current minus 2
+ bindsym $mod1+w gaps top current plus 2
+ bindsym $mod1+e gaps bottom current plus 2
+ bindsym $mod1+r gaps bottom current minus 2
+
+ # Escaping
+ bindsym Shift+end mode "default"
+ bindsym Ctrl+k mode "default"
+ bindsym Ctrl+bracketleft mode "default"
+ bindsym Escape mode "default"
+}
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Wδrksραcεs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+bindsym $mod1+bracketleft workspace prev
+bindsym $mod1+bracketright workspace next
+
+bindsym $mod2+a workspace prev
+bindsym $mod2+d workspace next
+
+bindsym $mod1+1 workspace number 1
+bindsym $mod1+2 workspace number 2
+bindsym $mod1+3 workspace number 3
+bindsym $mod1+4 workspace number 4
+bindsym $mod1+5 workspace number 5
+bindsym $mod1+6 workspace number 6
+bindsym $mod1+7 workspace number 7
+bindsym $mod1+8 workspace number 8
+bindsym $mod1+9 workspace number 9
+
+# Advanced workspace tuning ====
+bindsym $mod1+f mode "workspace_tuning"
+
+mode "workspace_tuning" {
+
+ # Move focused container to workspace
+ bindsym 1 move container to workspace number 1
+ bindsym 2 move container to workspace number 2
+ bindsym 3 move container to workspace number 3
+ bindsym 4 move container to workspace number 4
+ bindsym 5 move container to workspace number 5
+ bindsym 6 move container to workspace number 6
+ bindsym 7 move container to workspace number 7
+ bindsym 8 move container to workspace number 8
+ bindsym 9 move container to workspace number 9
+
+ # Swap containers
+ bindsym $mod1+$pane_left mark --add "_swap", focus left, swap container with mark "_swap", focus left, unmark "_swap"
+ bindsym $mod1+$pane_down mark --add "_swap", focus down, swap container with mark "_swap", focus down, unmark "_swap"
+ bindsym $mod1+$pane_up mark --add "_swap", focus up, swap container with mark "_swap", focus up, unmark "_swap"
+ bindsym $mod1+$pane_right mark --add "_swap", focus right, swap container with mark "_swap", focus right, unmark "_swap"
+
+ # Stack, Tab, Rotate
+ bindsym s layout stacking
+ bindsym t layout tabbed
+ bindsym r layout toggle split
+
+ bindsym f fullscreen
+ bindsym Shift+f fullscreen
+
+ # Escaping
+ bindsym $mod1+e mode "resize"
+
+ bindsym Shift+end mode "default"
+ bindsym Ctrl+k mode "default"
+ bindsym Ctrl+bracketleft mode "default"
+ bindsym Escape mode "default"
+}
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Iηρμτ αηd δμτρμτ αdjμsτmεητs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+# Trackpad more like MacOS
+input 1452:634:bcm5974 {
+ tap enabled
+ natural_scroll enabled
+ accel_profile adaptive
+ pointer_accel 0.36
+}
+
+output * background ~/.config/sway/secondary_wallpaper.png fill
+output eDP-1 background ~/.config/sway/default_wallpaper.png fill
+output DP-1 background ~/.config/sway/default_wallpaper.png fill
+output DP-3 background ~/.config/sway/default_wallpaper.png fill
+
+output DP-1 scale 2
+output DP-3 scale 2
+
+default_border pixel 2
+ # Adjust gamma. More important for external displays. Laptops are usually fine
+exec wlsunset -t 4000 -T 6500 -g 0.9
+
+# Volume controls
+bindsym XF86AudioRaiseVolume exec $volume_command 4 $volume_notify_sound
+bindsym XF86AudioLowerVolume exec $volume_command -4 $volume_notify_sound
+bindsym shift+XF86AudioRaiseVolume exec $volume_command 1 $volume_notify_sound
+bindsym shift+XF86AudioLowerVolume exec $volume_command -1 $volume_notify_sound
+bindsym XF86AudioMute exec ~/.config/sway/toggle_mute.sh
+
+# External brightness control
+ # For laptops
+bindsym XF86MonBrightnessUp exec light -A 1
+bindsym XF86MonBrightnessDown exec light -U 1
+ # For external monitors
+bindsym F4 exec ddcutil setvcp 10 - 4
+bindsym F5 exec ddcutil setvcp 10 + 4
+bindsym Shift+F4 exec ddcutil setvcp 10 - 1
+bindsym Shift+F5 exec ddcutil setvcp 10 + 1
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Hδτkεy dαεmδη |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+ # Terminal
+bindsym $mod2+Return exec $term
+ # Chromium
+bindsym $mod2+n exec chromium
+ # Firefox
+bindsym $mod2+p exec MOZ_ENABLE_WAYLAND=1 firefox --private-window
+ # App launcher, like spotlight
+bindsym $mod1+space exec $menu
+ # Reload sway config
+bindsym $mod1+ctrl+s reload
+ # Close window
+bindsym $mod2+q kill
+ # Dragging windows
+floating_modifier $mod1 normal
+ # Screenlock
+bindsym $mod2+i exec ~/.config/sway/brightness_lock.sh
+ # Scratchpad
+bindsym $mod1+Shift+minus move scratchpad
+bindsym $mod1+minus scratchpad show
+ # Warpd - Keyboard-driven mouse
+bindsym Mod4+Control+j exec warpd --hint
+bindsym Mod4+Control+n exec warpd --normal
+ # Xremap
+exec sudo ~/.configs_pointer/bin/switch_keyboard.sh pc
+ # IME Module
+bindsym $mod1+i exec ~/.config/sway/toggle_fcitx.sh
+ # Mako notifications
+exec mako
+ # Exit sway (logs you out of your Wayland session)
+bindsym $mod2+Escape exec swaynag -t warning -m 'Are you sure you want to exit sway?' -b 'Yes, exit sway' 'swaymsg exit'
+
+# Screenshots ====
+bindsym $mod2+6 mode "screenshots"
+bindsym $mod2+5 mode "screenshots"; exec ~/.configs_pointer/bin/screenshot_wayland.sh area --clipboard && $screenshot_sound
+bindsym $mod2+4 mode "screenshots"; exec ~/.configs_pointer/bin/screenshot_wayland.sh \
+ -c -d 40 -s "$(~/.config/sway/window_dimensions.sh)" $original_path && $screenshot_sound
+
+mode "screenshots" {
+ # Screenshooting in processing "steps"
+ # 1. Get screenshot
+ bindsym a exec ~/.configs_pointer/bin/screenshot_wayland.sh area --clipboard \
+ $original_path && $screenshot_sound
+ bindsym f exec ~/.configs_pointer/bin/screenshot_wayland.sh full --clipboard \
+ $original_path && $screenshot_sound
+ bindsym s mode "default"; exec ~/.configs_pointer/bin/screenshot_wayland.sh markup
+
+ # 2. Downsize the screenshot, since 4k is too big
+ bindsym 1 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '10%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 2 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '20%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 3 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '30%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 4 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '40%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 5 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '50%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 6 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '60%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 7 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '70%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 8 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '80%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 9 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '90%' --clipboard --extension png $shrink_path && $screenshot_sound
+ bindsym 0 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '100%' --clipboard --extension png $shrink_path && $screenshot_sound
+
+ # OR compress image
+ bindsym space mode "shrink_screenshots"
+
+ # 3. Copy the smaller image back to clipboard and return to default
+ bindsym return mode "default"
+ bindsym Shift+end mode "default"
+ bindsym Ctrl+k mode "default"
+ bindsym Ctrl+bracketleft mode "default"
+ bindsym Escape mode "default"
+}
+
+mode "shrink_screenshots" {
+ # 2. Compress the screenshot, hard
+ bindsym 1 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '10%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 2 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '20%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 3 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '30%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 4 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '40%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 5 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '50%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 6 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '60%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 7 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '70%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 8 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '80%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 9 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '90%' --clipboard --extension webp $compress_path && $screenshot_sound
+ bindsym 0 exec ~/.configs_pointer/bin/screenshot_wayland.sh --resize '100' --clipboard --extension webp $compress_path && $screenshot_sound
+
+ bindsym space mode "screenshots"
+
+ # 3. Back out
+ bindsym return mode "default"
+ bindsym Shift+end mode "default"
+ bindsym Ctrl+k mode "default"
+ bindsym Ctrl+bracketleft mode "default"
+ bindsym Escape mode "default"
+}
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Sτylεs |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+bar {
+ position bottom
+
+ binding_mode_indicator yes
+
+ # Vertical horizontal
+ gaps 0 10
+
+ mode dock
+
+ status_command while ~/.config/sway/swaybar_status.sh; do sleep 60; done
+
+ colors {
+ # Foreground color
+ statusline #e7d6ad
+ background #22222200
+
+ # border background text
+ focused_workspace #F4B36Eff #F4B36Eff #000000
+ inactive_workspace #00000000 #444444 #e7d6ad
+ urgent_workspace #fadb2f #fadb2f #000000
+
+ #binding_mode #8ec07c #8ec07c #000000
+ #binding_mode #8ec07c #d3869b #000000
+ binding_mode #fadb2f #fadb2f #000000
+ }
+}
+
+# Colors
+client.focused #F4A66E #F4A66E #000000 #F4A66E #F4A66E
+#client.focused #FFFFFF #FFFFFF #000000 #ffffff #ffffff
+
+#╔─────────────────────────────────────────────────────────────────────────────╗
+#│ Oτhεr |
+#╚─────────────────────────────────────────────────────────────────────────────╝
+# Sleep settings for laptops TODO: systemctl suspend?
+set $laptop 'eDP-1'
+set $sleep sleep 3 && swaylock
+
+bindswitch --reload --locked lid:on exec \
+ swaymsg output $laptop dpms off && swaylock
+bindswitch --reload --locked lid:off exec \
+ swaymsg output $laptop dpms on
+
+#bindswitch --reload --locked lid:on exec swaymsg output $laptop_screen disable
+
+#bindswitch --reload --locked lid:on exec '[ $(swaymsg -t get_outputs | grep name | wc -l) == 1 ] && ($sleep) || ($notify "Clamshell mode" "Laptop screen off" && swaymsg output $laptop_screen disable)'
+#
+#bindswitch --reload --locked lid:off output $laptop_screen enable
+
+include /etc/sway/config.d/*
+
+#
+# Example configuration:
+#
+# output HDMI-A-1 resolution 1920x1080 position 1920,0
+#
+# You can get the names of your outputs by running: swaymsg -t get_outputs
+
+#
+#exec swayidle -w \
+# timeout 101 'swaylock' \
+# timeout 314 'swaymsg "output * dpms off"' \
+# resume 'swaymsg "output * dpms on"' \
+# timeout 626 'systemctl suspend ' \
+# before-sleep 'swaylock'
+
+### Idle configuration
+#
+# Example configuration:
+#
+# exec swayidle -w \
+# timeout 300 'swaylock -f -c 000000' \
+# timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \
+# before-sleep 'swaylock -f -c 000000'
+#
+# This will lock your screen after 300 seconds of inactivity, then turn off
+# your displays after another 300 seconds, and turn your screens back on when
+# resumed. It will also lock your screen before your computer goes to sleep.
diff --git a/sway/cycle_windows.py b/sway/cycle_windows.py
new file mode 100755
index 0000000..ce04ae6
--- /dev/null
+++ b/sway/cycle_windows.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+# From https://gist.github.com/SidharthArya/f4d80c246793eb61be0ae928c9184406
+import sys
+import json
+import subprocess
+
+direction=bool(sys.argv[1] == 'next')
+swaymsg = subprocess.run(['swaymsg', '-t', 'get_tree'], stdout=subprocess.PIPE)
+data = json.loads(swaymsg.stdout)
+current = data["nodes"][1]["current_workspace"]
+workspace = int(data["nodes"][1]["current_workspace"])-1
+roi = data["nodes"][1]["nodes"][workspace]
+temp = roi
+windows = list()
+
+def getNextWindow():
+ if focus < len(windows) - 1:
+ return focus+1
+ else:
+ return 0
+
+def getPrevWindow():
+ if focus > 0:
+ return focus-1
+ else:
+ return len(windows)-1
+
+def makelist(temp):
+ for nodes in "floating_nodes", "nodes":
+ for i in range(len(temp[nodes])):
+ if temp[nodes][i]["name"] is None:
+ makelist(temp[nodes][i])
+ else:
+ windows.append(temp[nodes][i])
+
+def focused(temp_win):
+ for i in range(len(temp_win)):
+ if temp_win[i]["focused"] == True:
+ return i
+
+makelist(temp)
+focus = focused(windows)
+
+if direction:
+ attr = f"[con_id={windows[getNextWindow()]['id']}]"
+else:
+ attr = f"[con_id={windows[getPrevWindow()]['id']}]"
+
+sway = subprocess.run(['swaymsg', attr, 'focus'])
+sys.exit(sway.returncode)
diff --git a/sway/pulse_audio_volume.sh b/sway/pulse_audio_volume.sh
new file mode 100755
index 0000000..af8f21a
--- /dev/null
+++ b/sway/pulse_audio_volume.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+# Simple wrapper around pactl to keep volume in [0,100]% range. Optionally
+# plays an indicator sound after changing the volume
+#
+# Args:
+# 1: Change amount in percent. An integer
+# 2: Sound file to play. No sound is played if omitted or invalid
+declare -r ADJUST="$1"
+declare -r NOTIFY_SOUND="$2"
+
+declare -r MAX_VOLUME="100"
+
+set_volume() {
+ if ! pactl set-sink-volume @DEFAULT_SINK@ "${1}%"; then
+ printf "Failed to set default sink volume\n" >&2
+ exit 1
+ fi
+
+ [[ -z "$NOTIFY_SOUND" ]] || play_notify_sound "$NOTIFY_SOUND"
+}
+
+play_notify_sound() {
+ if ! [[ -r "$1" ]]; then
+ printf "File '%s' is not readable" "$1" >&2
+ exit 1
+ fi
+
+ if command -v ffmpeg &>/dev/null; then
+ ffplay -nodisp -autoexit -v error "$1"
+ elif command -v afplay &>/dev/null; then
+ afplay "$1"
+ else
+ printf "Failed to find sound player for volume indication sound\n" >&2
+ fi
+}
+
+if ! [[ "$ADJUST" =~ ^-?[0-9]+$ ]]; then
+ printf "No volume change amount provided\n" >&2
+ exit 1
+fi
+
+readonly curr_volume=$(pactl get-sink-volume @DEFAULT_SINK@ | awk '
+ match($0, /[0-9]+%/) { printf "%s", substr($0, RSTART, RLENGTH - 1) }')
+
+if ! [[ "$curr_volume" =~ ^[0-9]+$ ]]; then
+ printf "Failed to find default sink's volume: %s\n" "$curr_volume" >&2
+fi
+
+declare -ir new_volume=$(($curr_volume + $ADJUST))
+
+printf "Changing volumes from %d -> %d\n" "$curr_volume" "$new_volume" >&2
+if [[ "$new_volume" -gt "$MAX_VOLUME" ]]; then
+ set_volume "$MAX_VOLUME"
+elif [[ "$new_volume" -lt "0" ]]; then
+ set_volume "0"
+else
+ set_volume "$new_volume"
+fi
diff --git a/sway/swaybar_status.sh b/sway/swaybar_status.sh
new file mode 100755
index 0000000..c59a854
--- /dev/null
+++ b/sway/swaybar_status.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+battery_charge() {
+ if [[ -r /sys/class/power_supply/BAT0/uevent ]]; then
+ cat /sys/class/power_supply/BAT0/uevent | awk '
+ /CHARGE_NOW/ { split($0, a, "="); curr = a[2]; n++ }
+ /CHARGE_FULL=/ { split($0, a, "="); full = a[2]; n++ }
+
+ END { if (n == 2) printf "%.1f", curr / full * 100 }
+ '
+ fi
+}
+
+display_brightness() {
+ if command -v ddcutil &>/dev/null; then
+ ddcutil getvcp 10 | awk '
+ match($0, /[0-9]+,/) { printf "%s", substr($0, RSTART, RLENGTH - 1) }'
+ else
+ light -G | awk '{ split($0, a, "."); printf "%s", a[1] }'
+ fi
+}
+
+get_volume() {
+ pactl get-sink-volume @DEFAULT_SINK@ | awk '
+ match($0, /[0-9]+%/) { printf "%s", substr($0, RSTART, RLENGTH - 1) }'
+}
+
+remaining_ram() {
+ free --mega | awk '/Mem/ {
+ split($0, a, " ")
+
+ used = a[3] / 1000
+ shared = a[5] / 1000
+ available = a[7] / 1000
+
+ printf "%0.1fG / %.1fG", used + shared, available
+ }'
+}
+
+ramu="$(remaining_ram)"
+brightness="$(display_brightness)"
+volume="$(get_volume)"
+charge="$(battery_charge)"
+time="$(date +'%d %a %l:%M %p' | awk '{ gsub(/ +/, " "); print }')"
+
+output=''
+
+[[ -z "$brightness" ]] || output+="${brightness}cd | "
+[[ -z "$volume" ]] || output+="${volume}dB | "
+[[ -z "$charge" ]] || output+="[${charge}%] | "
+[[ -z "$ramu" ]] || output+="${ramu} | "
+[[ -z "$time" ]] || output+="$time"
+
+printf "%s" "$output"
diff --git a/sway/toggle_fcitx.sh b/sway/toggle_fcitx.sh
new file mode 100755
index 0000000..4415de2
--- /dev/null
+++ b/sway/toggle_fcitx.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+CURRENT_ID="$(pgrep ^fcitx5$)"
+
+if [[ -n "$CURRENT_ID" ]]; then
+ kill "$CURRENT_ID"
+else
+ fcitx5 -d --replace
+fi
diff --git a/sway/toggle_mute.sh b/sway/toggle_mute.sh
new file mode 100755
index 0000000..b992f8e
--- /dev/null
+++ b/sway/toggle_mute.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# Toggles between muted and the previous volume. Uses `pactl`
+#
+# EXAMPLES:
+# ./toggle_mute.sh # Default toggles based on current volume
+# ./toggle_mute.sh mute
+# ./toggle_mute.sh unmute
+declare -r vol="$(pactl get-sink-volume @DEFAULT_SINK@ | awk '{ printf $5 }')"
+declare -r store=~/.config/sway/toggle_mute_data
+
+# Saves the current non-zero volume and mutes
+mute_and_save () {
+ [[ "$vol" == "0%" ]] || printf "%s" "$vol" > "$store"
+ pactl set-sink-volume @DEFAULT_SINK@ 0%
+}
+
+# Restores previous volume, or sets to 10%
+unmute () {
+ if [[ "$vol" == "0%" && "$(head "$store")" =~ [0-9]+% ]]; then
+ pactl set-sink-volume @DEFAULT_SINK@ "$(head "$store")"
+ else
+ pactl set-sink-volume @DEFAULT_SINK@ 10%
+ fi
+}
+
+# Main ======
+case "$1" in
+ mute)
+ mute_and_save
+ ;;
+ unmute)
+ unmute
+ ;;
+ *)
+ if [[ "$vol" == "0%" ]]; then
+ unmute
+ else
+ mute_and_save
+ fi
+ ;;
+esac
+
+ffplay -nodisp -autoexit -v error ~/.config/sway/pop_sound.mp3
diff --git a/sway/window_dimensions.sh b/sway/window_dimensions.sh
new file mode 100755
index 0000000..8cae310
--- /dev/null
+++ b/sway/window_dimensions.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Gets a slurp-like output for the focused window with sway borders cropped
+declare -a a=( $(swaymsg -t get_tree | jq '..
+ | (.nodes? // empty)[] | select(.focused==true)
+ | .rect.x, .window_rect.x, .rect.y, .window_rect.y, .window_rect.width, .window_rect.height, .rect.height') )
+
+if [[ ${#a[@]} -eq 0 ]]; then
+ a=( $(swaymsg -t get_tree | jq '..
+ | (.floating_nodes? // empty)[] | select(.focused==true)
+ | .rect.x, .window_rect.x, .rect.y, .window_rect.y, .window_rect.width, .window_rect.height, .rect.height') )
+fi
+
+if [[ ${#a[@]} -ne 7 ]]; then
+ printf 'Failed to find window\n'
+ exit 1
+elif [[ $((${a[5]} + ${a[3]})) -eq ${a[6]} ]]; then
+ printf '%d,%d %dx%d\n' \
+ "$((${a[0]} + ${a[1]}))" \
+ "${a[2]}" \
+ "${a[4]}" \
+ "$((${a[5]} - ${a[3]}))"
+else
+ printf '%d,%d %dx%d\n' \
+ "$((${a[0]} + ${a[1]}))" \
+ "$((${a[2]} + ${a[3]}))" \
+ "${a[4]}" \
+ "${a[5]}"
+fi
diff --git a/swaylock/config b/swaylock/config
new file mode 100644
index 0000000..30be9c1
--- /dev/null
+++ b/swaylock/config
@@ -0,0 +1,24 @@
+show-failed-attempts
+image=~/.config/swaylock/default_wallpaper.png
+bs-hl-color=83A598
+
+indicator-radius=60
+indicator-thickness=20
+
+inside-color=D3869B
+ring-color=8EC07C
+key-hl-color=FABD2F
+line-color=FABD2F00
+text-color=222222
+
+inside-ver-color=222222
+ring-ver-color=EBDBB2
+text-ver-color=EBDBB2
+
+inside-wrong-color=282828
+ring-wrong-color=FB4934
+text-wrong-color=EBDBB2
+
+inside-clear-color=222222
+ring-clear-color=EBDBB2
+text-clear-color=EBDBB2
diff --git a/systemd/xremap.service b/systemd/xremap.service
new file mode 100644
index 0000000..dbd007d
--- /dev/null
+++ b/systemd/xremap.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=xRemap keyboard remapper
+
+[Service]
+Type=simple
+ExecStart=/usr/local/bin/xremap /etc/xremap/config.yml
+
+[Install]
+WantedBy=default.target
diff --git a/tmux/tmux.conf b/tmux/tmux.conf
new file mode 100644
index 0000000..5f1750c
--- /dev/null
+++ b/tmux/tmux.conf
@@ -0,0 +1,173 @@
+# General Settings ==================================================
+# Ctrl-space as prefix
+unbind-key C-b
+unbind-key C-Space
+set-option -g prefix C-Space
+bind-key C-Space send-prefix
+
+set -s copy-command 'wl-copy'
+set -g mouse on
+
+# vi keybinds in copy mode
+set-window-option -g mode-keys vi
+set -g mode-keys vi
+set-option -s set-clipboard off
+
+# Start window index at 1, for chromium-like tab switching
+set -g base-index 1
+
+# 100k line scrollback
+set-option -g history-limit 100000
+
+# Avoid ESC delay
+set -s escape-time 0
+
+# Full colors
+set -g default-terminal "xterm-256color" # 'xterm' not 'tmux' for vim's sake
+set -ag terminal-overrides ",*256*:RGB"
+
+# Window and Panes ==================================================
+# Fast Alt-bound keybinds
+ # Adjacent windows
+bind-key -n M-l next
+bind-key -n M-h prev
+
+ # Move between panes. Mix of vim up/down and vimium's tabs left/right
+bind-key -n M-k select-pane -t '{top-right}'
+bind-key -n M-j select-pane -t '{bottom-left}'
+
+ # Move windows
+bind-key -n M-[ swap-window -t -1 \; prev
+bind-key -n M-] swap-window -t +1 \; next
+
+ # Goto window, like chromium tabs
+bind-key -n M-1 select-window -t 1
+bind-key -n M-2 select-window -t 2
+bind-key -n M-3 select-window -t 3
+bind-key -n M-4 select-window -t 4
+bind-key -n M-5 select-window -t 5
+bind-key -n M-6 select-window -t 6
+bind-key -n M-7 select-window -t 7
+bind-key -n M-8 select-window -t '{end}'
+
+# Slower prefix-bound keybinds
+ # Move between panes
+bind h select-pane -L
+bind j select-pane -D
+bind k select-pane -U
+bind l select-pane -R
+
+ # Resize panes
+bind -r C-h resize-pane -L
+bind -r C-j resize-pane -D
+bind -r C-k resize-pane -U
+bind -r C-l resize-pane -R
+
+ # Swap panes
+bind-key L swap-pane -s '{right-of}'
+bind-key K swap-pane -s '{up-of}'
+bind-key J swap-pane -s '{down-of}'
+bind-key H swap-pane -s '{left-of}'
+
+ # Split panes like vim
+bind v split-window -h -c '#{pane_current_path}'
+bind s split-window -v -c '#{pane_current_path}'
+bind T new-window -c "#{pane_current_path}"
+
+ # Move current pane between windows
+bind-key g command-prompt -p "grab pane from:" "join-pane -s '%%'"
+bind-key m command-prompt -p "move pane to:" "join-pane -t '%%'"
+
+ # Pop out current pane into a new window
+bind-key p break-pane -t :
+
+ # Toggle pane synchronization
+bind-key C-s setw synchronize-panes
+
+ # Switch sessions with ( )
+bind-key -n M-0 switch-client -n
+bind-key -n M-9 switch-client -p
+
+# Tmux Keybinds =====================================================
+# Reload tmux quickly
+unbind R
+bind R source-file ~/.config/tmux/tmux.conf \; display 'Reloaded tmux config'
+
+# Faster command prompt
+bind ';' command-prompt -I ""
+
+# F12 toggles the outer tmux session's key interception. Keys get passed
+# through to the inner session
+bind -T root F12 \
+ set prefix None \;\
+ set key-table off \;\
+ if -F '#{pane_in_mode}' 'send-keys -X cancel' \;\
+ set status-position top \;\
+ refresh-client -S
+
+bind -T off F12 \
+ set -u prefix C-Space \;\
+ set -u key-table \;\
+ set status-position bottom \;\
+ refresh-client -S
+
+# Copy mode keybinds
+ # Move to line ends
+bind-key -T copy-mode-vi 'L' send-keys '$'
+bind-key -T copy-mode-vi 'H' send-keys '^'
+
+ # Navigate to previous command prompt
+bind-key b copy-mode\;\
+ send-keys -X start-of-line\;\
+ send-keys -X search-backward " "
+
+ # Copy mode selection
+bind P paste-buffer
+bind-key -T copy-mode-vi v send-keys -X begin-selection
+bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle
+bind-key -T copy-mode-vi C-k send-keys -X cancel
+
+ # Copy via mouse selection or y key
+bind-key -T copy-mode-vi y send-keys -X copy-pipe 'wl-copy'
+bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe 'wl-copy'
+
+# Statusline ========================================================
+set-option -g status-position bottom
+set -g status-left-length 32
+
+set -g status-bg "black"
+set -g status-fg "grey"
+
+set-option -g status-left "#[fg=yellow, bg=black bold] #H "
+
+set-window-option -g window-status-current-format "\
+#[fg=black, bg=green] #I* \
+#[fg=black, bg=green bold] #W \
+#[fg=green, bg=black]"
+
+set-window-option -g window-status-format "\
+#[fg=black, bg=grey]\
+#[fg=black, bg=grey] #I #W \
+#[fg=grey, bg=black]"
+
+set-option -g status-right "\
+#[fg=yellow, bg=black] #S #(whoami) \
+#[fg=black, bg=yellow] CPU: #{cpu_percentage} "
+
+set-window-option -g window-status-separator ''
+
+# Plugins ===========================================================
+set -g @plugin 'nhdaly/tmux-better-mouse-mode'
+set -g @plugin 'tmux-plugins/tmux-cpu'
+
+set -g @scroll-speed-num-lines-per-scroll "1"
+set -g @emulate-scroll-for-no-mouse-alternate-buffer "on" # Scroll manpages
+set -g @plugin 'mattdavis90/base16-tmux'
+
+set -g @colors-base16 'gruvbox-light-soft'
+
+run '~/.config/tmux/plugins/tpm/tpm'
+
+# Overwriting options ===============================================
+set -g pane-active-border-style "fg=white"
+set -g pane-border-style "fg=brightblack"
diff --git a/vifm/colors/Default.vifm b/vifm/colors/Default.vifm
new file mode 100644
index 0000000..e7101eb
--- /dev/null
+++ b/vifm/colors/Default.vifm
@@ -0,0 +1,85 @@
+" You can edit this file by hand.
+" The " character at the beginning of a line comments out the line.
+" Blank lines are ignored.
+
+" The Default color scheme is used for any directory that does not have
+" a specified scheme and for parts of user interface like menus. A
+" color scheme set for a base directory will also
+" be used for the sub directories.
+
+" The standard ncurses colors are:
+" Default = -1 = None, can be used for transparency or default color
+" Black = 0
+" Red = 1
+" Green = 2
+" Yellow = 3
+" Blue = 4
+" Magenta = 5
+" Cyan = 6
+" White = 7
+
+" Light versions of colors are also available (set bold attribute):
+" LightBlack
+" LightRed
+" LightGreen
+" LightYellow
+" LightBlue
+" LightMagenta
+" LightCyan
+" LightWhite
+
+" Available attributes (some of them can be combined):
+" bold
+" underline
+" reverse or inverse
+" standout
+" italic (on unsupported systems becomes reverse)
+" none
+
+" Vifm supports 256 colors you can use color numbers 0-255
+" (requires properly set up terminal: set your TERM environment variable
+" (directly or using resources) to some color terminal name (e.g.
+" xterm-256color) from /usr/lib/terminfo/; you can check current number
+" of colors in your terminal with tput colors command)
+
+" highlight group cterm=attrs ctermfg=foreground_color ctermbg=background_color
+
+highlight clear
+
+highlight Win cterm=none ctermfg=white ctermbg=black
+highlight Directory cterm=bold ctermfg=cyan ctermbg=default
+highlight Link cterm=bold ctermfg=yellow ctermbg=default
+highlight BrokenLink cterm=bold ctermfg=red ctermbg=default
+highlight HardLink cterm=none ctermfg=yellow ctermbg=default
+highlight Socket cterm=bold ctermfg=magenta ctermbg=default
+highlight Device cterm=bold ctermfg=red ctermbg=default
+highlight Fifo cterm=bold ctermfg=cyan ctermbg=default
+highlight Executable cterm=bold ctermfg=green ctermbg=default
+highlight Selected cterm=bold ctermfg=magenta ctermbg=default
+highlight CurrLine cterm=bold,reverse ctermfg=default ctermbg=default
+highlight TopLine cterm=none ctermfg=black ctermbg=white
+highlight TopLineSel cterm=bold ctermfg=black ctermbg=default
+highlight StatusLine cterm=bold ctermfg=black ctermbg=white
+highlight WildMenu cterm=underline,reverse ctermfg=white ctermbg=black
+highlight CmdLine cterm=none ctermfg=white ctermbg=black
+highlight ErrorMsg cterm=none ctermfg=red ctermbg=black
+highlight Border cterm=none ctermfg=black ctermbg=white
+highlight OtherLine ctermfg=default ctermbg=default
+highlight JobLine cterm=bold,reverse ctermfg=black ctermbg=white
+highlight SuggestBox cterm=bold ctermfg=default ctermbg=default
+highlight CmpMismatch cterm=bold ctermfg=white ctermbg=red
+highlight AuxWin ctermfg=default ctermbg=default
+highlight TabLine cterm=none ctermfg=white ctermbg=black
+highlight TabLineSel cterm=bold,reverse ctermfg=default ctermbg=default
+highlight User1 ctermfg=default ctermbg=default
+highlight User2 ctermfg=default ctermbg=default
+highlight User3 ctermfg=default ctermbg=default
+highlight User4 ctermfg=default ctermbg=default
+highlight User5 ctermfg=default ctermbg=default
+highlight User6 ctermfg=default ctermbg=default
+highlight User7 ctermfg=default ctermbg=default
+highlight User8 ctermfg=default ctermbg=default
+highlight User9 ctermfg=default ctermbg=default
+highlight OtherWin ctermfg=default ctermbg=default
+highlight LineNr ctermfg=default ctermbg=default
+highlight OddLine ctermfg=default ctermbg=default
diff --git a/vifm/colors/gruvbox-dark.vifm b/vifm/colors/gruvbox-dark.vifm
new file mode 100644
index 0000000..54d059a
--- /dev/null
+++ b/vifm/colors/gruvbox-dark.vifm
@@ -0,0 +1,88 @@
+" gruvbox color scheme approximation for vifm
+
+" Reset all styles first
+highlight clear
+
+" Window colors
+"highlight Border cterm=none ctermfg=black ctermbg=white
+"highlight TopLine cterm=none ctermfg=black ctermbg=white
+"highlight TopLineSel cterm=bold ctermfg=black ctermbg=default
+
+highlight Win cterm=none ctermfg=white ctermbg=black
+highlight OtherWin cterm=none ctermfg=black ctermbg=white
+
+highlight LineNr ctermfg=default ctermbg=default
+highlight OddLine ctermfg=default ctermbg=default
+
+highlight Border cterm=none ctermfg=235 ctermbg=default
+highlight TopLine cterm=none ctermfg=214 ctermbg=235
+highlight TopLineSel cterm=bold ctermfg=214 ctermbg=237
+highlight CurrLine cterm=bold,reverse ctermfg=default ctermbg=default
+
+highlight TopLine cterm=bold ctermfg=white ctermbg=239
+highlight TopLineSel cterm=bold ctermfg=black ctermbg=green
+
+highlight TabLine cterm=bold ctermfg=default ctermbg=default
+highlight TabLineSel cterm=bold ctermfg=black ctermbg=green
+
+highlight Border cterm=bold ctermfg=white ctermbg=239
+highlight StatusLine cterm=bold ctermfg=white ctermbg=239
+
+" Filetype colors ===================================================
+"highlight Directory cterm=bold ctermfg=cyan ctermbg=default
+highlight Directory cterm=bold ctermfg=blue ctermbg=default
+highlight Directory cterm=bold ctermfg=109 ctermbg=default
+"highlight Link cterm=bold ctermfg=yellow ctermbg=default
+highlight Link cterm=bold ctermfg=magenta ctermbg=default
+highlight BrokenLink cterm=bold ctermfg=red ctermbg=default
+highlight HardLink cterm=none ctermfg=yellow ctermbg=default
+highlight Socket cterm=bold ctermfg=magenta ctermbg=default
+highlight Device cterm=bold ctermfg=red ctermbg=default
+highlight Fifo cterm=bold ctermfg=yellow ctermbg=default
+highlight Executable cterm=bold ctermfg=green ctermbg=default
+
+ " Visual selection
+highlight Selected cterm=bold ctermfg=default ctermbg=239
+ " Highlight on cursor for the inactive pane
+highlight OtherLine ctermfg=default ctermbg=239
+
+
+highlight WildMenu cterm=underline,reverse ctermfg=white ctermbg=black
+highlight CmdLine cterm=none ctermfg=white ctermbg=black
+highlight ErrorMsg cterm=none ctermfg=red ctermbg=black
+highlight JobLine cterm=bold,reverse ctermfg=black ctermbg=white
+highlight SuggestBox cterm=bold ctermfg=default ctermbg=default
+highlight CmpMismatch cterm=bold ctermfg=white ctermbg=red
+highlight AuxWin ctermfg=default ctermbg=default
+
+"highlight TabLine cterm=none ctermfg=white ctermbg=black
+"highlight TabLineSel cterm=bold,reverse ctermfg=default ctermbg=default
+
+highlight User1 ctermfg=default ctermbg=default
+highlight User2 ctermfg=default ctermbg=default
+highlight User3 ctermfg=default ctermbg=default
+highlight User4 ctermfg=default ctermbg=default
+highlight User5 ctermfg=default ctermbg=default
+highlight User6 ctermfg=default ctermbg=default
+highlight User7 ctermfg=default ctermbg=default
+highlight User8 ctermfg=default ctermbg=default
+highlight User9 ctermfg=default ctermbg=default
+highlight OtherWin ctermfg=default ctermbg=default
+
+" Special files =====================================================
+ " Darkish purple for media
+highlight {*.aac,*.anx,*.asf,*.au,*.avi,*.ts,*.axa,*.axv,*.divx,*.flac,*.m2a,
+ \*.m2v,*.m4a,*.m4p,*.m4v,*.mid,*.midi,*.mka,*.mkv,*.mov,*.mp3,*.mp4,
+ \*.flv,*.mp4v,*.mpc,*.mpeg,*.mpg,*.nuv,*.oga,*.ogg,*.ogv,*.ogx,*.pbm,
+ \*.pgm,*.qt,*.ra,*.ram,*.rm,*.spx,*.vob,*.wav,*.wma,*.wmv,*.xvid,
+ \*.ac3,*.webm} cterm=bold
+ \ ctermfg=139 ctermbg=default
+
+ " Same darkish purple for pictures
+highlight {*.avif,*.bmp,*.gif,*.jpeg,*.jpg,*.ico,*.png,*.ppm,*.svg,*.svgz,*.tga,
+ \*.tif,*.tiff,*.webp,*.xbm,*.xcf,*.xpm,*.xspf,*.xwd} cterm=bold
+ \ ctermfg=139 ctermbg=default
+
+ " Project root files
+highlight {README*,SUMMARY.md,MAKEFILE} cterm=underline,bold
+ \ ctermfg=yellow ctermbg=default
diff --git a/vifm/colors/gruvbox-light.vifm b/vifm/colors/gruvbox-light.vifm
new file mode 100644
index 0000000..b49d9d7
--- /dev/null
+++ b/vifm/colors/gruvbox-light.vifm
@@ -0,0 +1,79 @@
+" Light mode gruvbox. Only slight changes from darkmode
+
+" Reset all styles first
+highlight clear
+
+" Window colors
+highlight Win cterm=none ctermfg=white ctermbg=black
+highlight OtherWin cterm=none ctermfg=black ctermbg=white
+
+highlight LineNr ctermfg=default ctermbg=default
+highlight OddLine ctermfg=default ctermbg=default
+
+highlight Border cterm=none ctermfg=235 ctermbg=default
+highlight TopLine cterm=none ctermfg=214 ctermbg=235
+highlight TopLineSel cterm=bold ctermfg=214 ctermbg=237
+highlight CurrLine cterm=bold,reverse ctermfg=default ctermbg=default
+highlight CurrLine cterm=bold,reverse ctermfg=default ctermbg=default
+
+highlight TopLine cterm=bold ctermfg=black ctermbg=white
+highlight TopLineSel cterm=bold ctermfg=black ctermbg=green
+
+highlight TabLine cterm=bold ctermfg=default ctermbg=default
+highlight TabLineSel cterm=bold ctermfg=black ctermbg=green
+
+highlight Border cterm=bold ctermfg=white ctermbg=white
+highlight StatusLine cterm=bold ctermfg=black ctermbg=white
+
+" Filetype colors ===================================================
+highlight Directory cterm=bold ctermfg=blue ctermbg=default
+highlight Link cterm=bold ctermfg=magenta ctermbg=default
+highlight BrokenLink cterm=bold ctermfg=red ctermbg=default
+highlight HardLink cterm=none ctermfg=yellow ctermbg=default
+highlight Socket cterm=bold ctermfg=magenta ctermbg=default
+highlight Device cterm=bold ctermfg=red ctermbg=default
+highlight Fifo cterm=bold ctermfg=yellow ctermbg=default
+highlight Executable cterm=bold ctermfg=green ctermbg=default
+
+highlight Selected cterm=bold ctermfg=default ctermbg=251
+highlight OtherLine ctermfg=default ctermbg=251
+
+highlight WildMenu cterm=underline,reverse ctermfg=white ctermbg=black
+highlight CmdLine cterm=none ctermfg=white ctermbg=black
+highlight ErrorMsg cterm=none ctermfg=red ctermbg=black
+highlight JobLine cterm=bold,reverse ctermfg=black ctermbg=white
+highlight SuggestBox cterm=bold ctermfg=default ctermbg=default
+highlight CmpMismatch cterm=bold ctermfg=white ctermbg=red
+highlight AuxWin ctermfg=default ctermbg=default
+
+"highlight TabLine cterm=none ctermfg=white ctermbg=black
+"highlight TabLineSel cterm=bold,reverse ctermfg=default ctermbg=default
+
+highlight User1 ctermfg=default ctermbg=default
+highlight User2 ctermfg=default ctermbg=default
+highlight User3 ctermfg=default ctermbg=default
+highlight User4 ctermfg=default ctermbg=default
+highlight User5 ctermfg=default ctermbg=default
+highlight User6 ctermfg=default ctermbg=default
+highlight User7 ctermfg=default ctermbg=default
+highlight User8 ctermfg=default ctermbg=default
+highlight User9 ctermfg=default ctermbg=default
+highlight OtherWin ctermfg=default ctermbg=default
+
+" Special files =====================================================
+ " Darkish purple for media
+highlight {*.aac,*.anx,*.asf,*.au,*.avi,*.ts,*.axa,*.axv,*.divx,*.flac,*.m2a,
+ \*.m2v,*.m4a,*.m4p,*.m4v,*.mid,*.midi,*.mka,*.mkv,*.mov,*.mp3,*.mp4,
+ \*.flv,*.mp4v,*.mpc,*.mpeg,*.mpg,*.nuv,*.oga,*.ogg,*.ogv,*.ogx,*.pbm,
+ \*.pgm,*.qt,*.ra,*.ram,*.rm,*.spx,*.vob,*.wav,*.wma,*.wmv,*.xvid,
+ \*.ac3,*.webm} cterm=bold
+ \ ctermfg=5 ctermbg=default
+
+ " Same darkish purple for pictures
+highlight {*.avif,*.bmp,*.gif,*.jpeg,*.jpg,*.ico,*.png,*.ppm,*.svg,*.svgz,*.tga,
+ \*.tif,*.tiff,*.webp,*.xbm,*.xcf,*.xpm,*.xspf,*.xwd} cterm=bold
+ \ ctermfg=5 ctermbg=default
+
+ " Project root files
+highlight {README*,SUMMARY.md,MAKEFILE,makefile,Cargo.toml} cterm=underline,bold
+ \ ctermfg=yellow ctermbg=default
diff --git a/vifm/scripts/vifm_bg_open.sh b/vifm/scripts/vifm_bg_open.sh
new file mode 100755
index 0000000..0d211d3
--- /dev/null
+++ b/vifm/scripts/vifm_bg_open.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+print_help() {
+ cat <&1 | awk '/Stream.+Video/')"
+
+ if [[ -n "$TMUX" && -z "$has_video" ]]; then
+ tmux split-window -h
+ sleep .2 # Let bash login, otherwise command won't get sent
+ tmux send-keys "mpv $1" Enter
+ else
+ mpv --force-window "$1" &>/dev/null &
+ fi
+ ;;
+ html)
+ chromium "$1" &>/dev/null &
+ ;;
+ esac
+}
+
+if [[ -z ${SWAYSOCK+x} ]]; then
+ printf 'Sway not running. Will not open gui apps\n' >&2
+ exit 1
+fi
+
+for arg in "$@"
+do
+ case "$arg" in
+ -h|--help)
+ print_help
+ exit 0
+ ;;
+ *)
+ open_file "$arg"
+ ;;
+ esac
+done
+
+#swaymsg [con_mark=vifm_window] focus
diff --git a/vifm/vifmrc b/vifm/vifmrc
new file mode 100644
index 0000000..71d267f
--- /dev/null
+++ b/vifm/vifmrc
@@ -0,0 +1,346 @@
+" [n]ormal, [v]isual, [d]ialogue, [q]uick view, [m]enu, [c]ommand
+" Ctrl+k as Esc
+nnoremap
+vnoremap
+dnoremap
+qnoremap q
+mnoremap
+cnoremap
+
+" Quickly access command line
+nnoremap ; :
+vnoremap ; :
+mnoremap ; :
+ " Run external command
+nnoremap ! :!!
+
+" Invert sorting order
+nnoremap r :invert o
+
+" Special filters with ,
+nnoremap , z
+
+" Toggle explore
+qnoremap e q
+
+" Vifm unique mappings ==============================================
+" Open editor for command line
+nnoremap : q:
+
+" Toggle previewing "o[ther] viewer"
+nnoremap o :view
+qnoremap o :view
+vnoremap o :viewgv
+
+" Open sorting menu
+nnoremap s :sort
+
+" Open bash shell in cwd
+nnoremap :!/usr/bin/env IS_VIFM_NEST='T' bash -l
+nnoremap :!/usr/bin/env IS_VIFM_NEST='T' bash -l
+
+" Open cwd in finder
+nnoremap ofinder :!open .
+
+nnoremap ogadd :!git add %c
+
+" Logical conflict mappings
+ " Navigate back from symlinks
+nnoremap H :cd -
+"nnoremap L l
+
+ " Open file in existing instance of macvim
+nnoremap O :!mvim --remote-tab-silent %f
+
+" Windows and buffers ===============================================
+" Window control with leader
+"nnoremap w
+
+" Open and switch to split, like in vim
+nnoremap ws :split
+nnoremap wv :vsplit
+
+" Expand current window
+nnoremap wo :only
+
+" Close current window
+nnoremap wc :only
+
+" eXchange windows
+nnoremap wx x
+
+" Open a new tab
+nnoremap wT :tabnew
+" Close tab
+nnoremap wC :tabclose
+
+ " Quick window switching. [N]ormal and [Q]uick view modes
+nnoremap l l
+nnoremap h h
+nnoremap j j
+nnoremap k k
+
+qnoremap l l
+qnoremap h h
+qnoremap j j
+qnoremap k k
+
+ " Window movement
+nnoremap h H
+nnoremap j J
+nnoremap k K
+nnoremap l L
+
+" Window resizing
+ " < increases, > decreases
+nnoremap , 4>
+nnoremap . 4<
+nnoremap , 4+
+nnoremap . 4-
+
+ " Set windows to be equally sized
+nnoremap = =
+
+" Emacs-like movements
+ " Move by character
+cnoremap
+cnoremap
+ " Delete by character. Note: not
+cnoremap
+cnoremap
+ " Move by word
+cnoremap
+cnoremap
+ " Delete left word
+cnoremap
+ " Jump to end of line
+cnoremap
+cnoremap
+
+" Clipboard ==============================================
+" Copy file or directory paths to clipboard
+if executable('pbcopy')
+ nnoremap yd :!echo %d | pbcopy
+ nnoremap yf :!echo %c:p | pbcopy
+ nnoremap yp :!echo %c:p | sed 's#'"${HOME}"'#~#' | pbcopy
+elseif executable('wl-copy')
+ nnoremap yd :!echo %d | wl-copy
+ nnoremap yf :!echo %c:p | wl-copy
+ nnoremap yp :!echo %c:p | sed 's#'"${HOME}"'#~#' | wl-copy
+elseif executable('xclip')
+ nnoremap yd :!echo %d | xclip %i
+ nnoremap yf :!echo %c:p | xclip %i
+ nnoremap yp :!echo %c:p | sed 's#'"${HOME}"'#~#' | xclip %i
+elseif executable('xsel')
+ nnoremap yd :!echo -n %d | xsel --input --primary %i &&
+ \ echo -n %d | xsel --clipboard --input %i
+ nnoremap yf :!echo -n %c:p | xsel --input --primary %i &&
+ \ echo -n %c:p | xsel --clipboard --input %i
+endif
+
+" Experimental ===========================================
+nnoremap m :sync %d
+ " Toggle dotfiles
+"nnoremap gh :set dotfiles!
+"nnoremap . :set dotfiles!
+ " Smaller scrolling movements
+"nnoremap 6k
+"vnoremap 6k
+"nnoremap 6j
+"vnoremap 6j
+
+nnoremap orestore :!git restore %c
+nnoremap oadd :!git add %c
+
+"command! pngcopy :!osascript -e 'set the clipboard to (read (POSIX file "'.%c.'") as PNG picture)'
+
+" ===================================================================
+" Settings
+" ===================================================================
+ " Don't use this directly. loads additional configs
+set shell='/usr/bin/env bash'
+set vicmd='nvim --'
+
+set syscalls "nosyscalls for third party tools like `cp` instead
+
+set vifminfo=dhistory,savedirs,chistory,state,tui,shistory,
+ \phistory,fhistory,dirstack,registers,bookmarks,bmarks
+
+set trash " Required for moving files with dd/p
+set history=1000 " Directory history scrollback
+set undolevels=1000 " Maximum undos stored
+
+set nofollowlinks
+set sortnumbers
+set timefmt=%m/%d\ %H:%M " See `man date` or `man strftime` for details
+
+" Show list of matches on tab completion in command-line mode
+set wildmenu
+set wildstyle=popup
+
+set vimhelp " Extra highlighting with vim's help file format
+set nohlsearch " Don't highlight search results automatically
+set incsearch " Incremental highlights while typing
+set scrolloff=2
+
+ " Backwards compatibility. Enables without 't'
+set cpoptions="fs"
+
+set sort +size
+ " Resolve symlinked paths like cd -P
+set chaselinks
+
+set tablabel="%t"
+set statusline="%16A %u:%-g %s (%d) -> %T"
+
+command! Light :colorscheme gruvbox-light Default Default-256
+command! Dark :colorscheme gruvbox-dark Default Default-256
+
+if system('colo.sh --tone') == 'light'
+ Light
+else
+ Dark
+endif
+
+" ===================================================================
+" Preload defaults
+" ===================================================================
+" :mark mark /full/directory/path [filename]
+" Common directories
+mark h ~/
+mark c ~/.configs_pointer/
+mark d ~/Downloads/
+mark s ~/safe/
+mark v ~/.config/vifm/
+
+set millerview
+
+
+" ===================================================================
+" Commands
+" ===================================================================
+" Only 3 view modes are available. Full screen and 2 window splits
+" :only :split :vsplit
+command! hsplit :split
+
+command! duplicate :clone
+
+command! mview :set millerview!
+
+command! finder :!open .
+
+" Git-like shortcuts
+command! stash :norm! zR
+command! stashpop :norm! zM
+command! stashdrop :norm! zO
+
+" Vifm doesn't support escaping modfiers like `exe "norm! \h"`, so we use
+" a remap ahead of time
+nnoremap + h
+command! preview :tabnew | set nomillerview | vsplit | sync! | exe 'norm +' | exe ':24wincmd-' | view
+" i for image
+nnoremap i :preview
+nnoremap i :!~/.configs_pointer/bin/vii.sh &>/dev/null &
+
+" ===================================================================
+" Fzf intergration
+" https://github.com/vifm/vifm/issues/279#issuecomment-319980898
+" ===================================================================
+ " Write the current bookmarks to a file
+command! fzfreadbmarks :exe "normal! :bmarks\r:write ~/.config/vifm/fzf-read/bookmarks\rq"
+
+ " Automatically navigate into directories and symlinks to directories
+command! navigateIfDir :if system('[[ ! -d '.expand('%c').' ]] || printf "T"') == 'T' | exe 'norm l' | endif
+
+" Prefer to use popup window. Requires 90 $COLUMNS and tmux >=3.2. Yabai on
+" MacOS causes it to crash regardless. Use full-screen as a fallback
+command! fzfbmarks
+ \ :if $TMUX != '' && &columns > 90
+ \ | exe 'cd "'.system('cat ~/.config/vifm/fzf-read/bookmarks | fzf-tmux -p 90,30 | sed "s/:.*//" ').'"'
+ \ | else
+ \ | exe 'cd "'.term('cat ~/.config/vifm/fzf-read/bookmarks | fzf 2>/dev/tty | sed "s/:.*//" ').'"'
+ \ | endif
+
+command! fdcddir
+ \ :if $TMUX != '' && &columns > 90
+ \ | exe 'cd "'.system('fd -HE ''.git'' -t d . | fzf-tmux -p 90,30').'"'
+ \ | else
+ \ | exe 'cd "'.term('fd -HE ''.git'' -t d . | fzf 2>/dev/tty').'"'
+ \ | endif
+
+command! fdeditfiles
+ \ :if $TMUX != '' && &columns > 90
+ \ | exe 'edit "'.system('fd -HE ''.git'' -t f . | fzf-tmux -p 90,30').'"'
+ \ | else
+ \ | exe 'edit "'.term('fd -HE ''.git'' -t f . | fzf 2>/dev/tty').'"'
+ \ | endif
+
+command! fdmvcursor
+ \ :if $TMUX != '' && &columns > 90
+ \ | exe 'goto "'.system('fd --maxdepth=1 -HE ''.git'' . | fzf-tmux -p 90,30').'"' | navigateIfDir
+ \ | else
+ \ | exe 'goto "'.term('fd --maxdepth=1 -HE ''.git'' . | fzf 2>/dev/tty').'"' | navigateIfDir
+ \ | endif
+
+ " Read in latests bookmarks before fzfinding through them
+command! fzfmarks :fzfreadbmarks | fzfbmarks
+
+nnoremap r :fzfmarks
+nnoremap e :fdcddir
+nnoremap f :fdeditfiles
+nnoremap ; :fdmvcursor
+
+
+" ===================================================================
+" Defaults
+" ===================================================================
+" Directory-local options, see :h vifm-'sort'
+autocmd DirEnter ~/Downloads setlocal sort=-mtime
+
+" Tmux won't work with sixel at all. Alacritty is currently very unstable with
+" it and flickers a lot. Set $TMUX for blurrier faster version. Quanity on
+" MacOS with viu seems to get worse the more images you preview
+if $TMUX == ''
+ fileviewer