commit f6881cea7a37b81b3e1bff27cf7e9af0205a6315
Author: Akemi Izuko
Date: Tue Sep 6 23:34:19 2022 -0600
Init again
The dotfiles are back
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}