Hazel Levine 3 years ago
commit
0f1a3535a4
  1. 7
      .gitignore
  2. 16
      README.md
  3. 24
      UNLICENSE
  4. 36
      config/X/Xresources
  5. 202
      config/alacritty/alacritty.yml
  6. 2
      config/bat/config
  7. 23
      config/bin/backlight
  8. 23
      config/bin/berun
  9. 24
      config/bin/blocks
  10. 3
      config/bin/emacsc
  11. 14
      config/bin/import-gsettings
  12. 64
      config/bin/keyboard
  13. 68
      config/bin/notify-action-alt
  14. 312
      config/bin/notify-alt
  15. 48
      config/bin/scrot
  16. 37
      config/bin/volume
  17. 86
      config/bin/xbps-menu
  18. 191
      config/doom/blog.org
  19. 306
      config/doom/config.org
  20. 93
      config/doom/init.el
  21. BIN
      config/doom/nice.png
  22. 948
      config/firefox/userChrome.css
  23. 71
      config/fontconfig/conf.d/10-preferred.conf
  24. 25
      config/fontconfig/conf.d/69-emoji.conf
  25. 30
      config/fontconfig/conf.d/70-no-dejavu.conf
  26. 5
      config/fontconfig/fonts.conf
  27. 51
      config/i3status-rust/status.toml
  28. 141
      config/ncmpcpp/config
  29. 84
      config/tmux/tmux.conf
  30. 31
      config/tridactyl/tridactylrc
  31. 31
      config/zathura/zathurarc
  32. 41
      config/zsh/zprofile
  33. 210
      config/zsh/zshrc
  34. 57
      home.nix
  35. 8
      modules/default.nix
  36. 6
      modules/desktop/alacritty.nix
  37. 13
      modules/desktop/default.nix
  38. 19
      modules/desktop/dirs.nix
  39. 25
      modules/desktop/firefox.nix
  40. 16
      modules/desktop/gtk.nix
  41. 26
      modules/desktop/mako.nix
  42. 62
      modules/desktop/mpd.nix
  43. 267
      modules/desktop/sway.nix
  44. 7
      modules/desktop/zathura.nix
  45. 10
      modules/lang/c.nix
  46. 11
      modules/lang/default.nix
  47. 12
      modules/lang/lisp.nix
  48. 14
      modules/lang/python.nix
  49. 7
      modules/lang/rust.nix
  50. 11
      modules/lang/scala.nix
  51. 11
      modules/lang/tex.nix
  52. 8
      modules/tools/bat.nix
  53. 12
      modules/tools/default.nix
  54. 34
      modules/tools/emacs.nix
  55. 29
      modules/tools/git.nix
  56. 45
      modules/tools/mail.nix
  57. 10
      modules/tools/nix.nix
  58. 13
      modules/tools/passwords.nix
  59. 6
      modules/tools/tmux.nix
  60. 27
      modules/tools/zsh.nix
  61. 29
      packages/bw-git-helper.nix
  62. 32
      packages/default.nix
  63. 24
      packages/zr.nix
  64. 68
      system/configuration.nix
  65. 19
      system/desktop.nix
  66. 35
      system/fan-control.nix
  67. 28
      system/fonts.nix
  68. 34
      system/hardware-configuration.nix
  69. 41
      system/networking.nix
  70. 33
      system/power.nix

7
.gitignore vendored

@ -0,0 +1,7 @@
config/doom/private.el
config/doom/config.el
config/doom/blog.el
config/doom/packages.el
*.elc
system/wg-privkey
config/mpdscribble/*

16
README.md

@ -0,0 +1,16 @@
etc
---
My personal dotfiles.
This branch is dedicated to my experiments with NixOS. It will likely be merged
into master momentarily, as my new system runs NixOS.
To install it:
- Copy things *selectively* in `system/` to `/etc/nixos` -- much of this is
only relevant if you are on my machine
- ln -s "$(pwd)" ~/.config/nixpkgs
- `home-manager switch`
...but why would you install my dotfiles? They're mine, not yours. Go away.
![why are you looking at the alt text](https://p.qtp2t.club/selif/setup.png)

24
UNLICENSE

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

36
config/X/Xresources

@ -0,0 +1,36 @@
! xft font rendering
Xft.antialias: 1
Xft.hinting: 1
Xft.hintstyle: hintfull
Xft.lcdfilter: lcddefault
Xft.rgba: rgb
! gruvbox
! hard contrast: *background: #f9f5d7
*background: #fbf1c7
! soft contrast: *background: #f2e5bc
*foreground: #3c3836
! Black + DarkGrey
*color0: #fdf4c1
*color8: #928374
! DarkRed + Red
*color1: #cc241d
*color9: #9d0006
! DarkGreen + Green
*color2: #98971a
*color10: #79740e
! DarkYellow + Yellow
*color3: #d79921
*color11: #b57614
! DarkBlue + Blue
*color4: #458588
*color12: #076678
! DarkMagenta + Magenta
*color5: #b16286
*color13: #8f3f71
! DarkCyan + Cyan
*color6: #689d6a
*color14: #427b58
! LightGrey + White
*color7: #7c6f64
*color15: #3c3836

202
config/alacritty/alacritty.yml

@ -0,0 +1,202 @@
## hazel's alacritty configuration
window:
dimensions:
columns: 80
lines: 24
padding:
x: 10
y: 10
decorations: full
# When true, bold text is drawn using the bright variant of colors.
draw_bold_text_with_bright_colors: true
font:
normal:
family: FiraCode
style: Regular
bold:
family: FiraCode
style: Regular
italic:
family: FiraCode
style: Regular
size: 10.0
offset:
x: 0
y: 0
glyph_offset:
x: 0
y: 0
# Colors (Gruvbox light)
colors:
# Default colors
primary:
# hard contrast: background = '0xf9f5d7'
background: '0xfbf1c7'
# soft contrast: background = '0xf2e5bc'
foreground: '0x3c3836'
# Normal colors
normal:
black: '0xfbf1c7'
red: '0xcc241d'
green: '0x98971a'
yellow: '0xd79921'
blue: '0x458588'
magenta: '0xb16286'
cyan: '0x689d6a'
white: '0x7c6f64'
# Bright colors
bright:
black: '0x928374'
red: '0x9d0006'
green: '0x79740e'
yellow: '0xb57614'
blue: '0x076678'
magenta: '0x8f3f71'
cyan: '0x427b58'
white: '0x3c3836'
visual_bell:
animation: EaseOutExpo
duration: 0
background_opacity: 1.0
mouse_bindings:
- { mouse: Middle, action: PasteSelection }
mouse:
double_click: { threshold: 300 }
triple_click: { threshold: 300 }
faux_scrolling_lines: 1
hide_when_typing: true
url:
launcher:
program: xdg-open
args: []
selection:
semantic_escape_chars: ",โ”‚`|:\"' ()[]{}<>"
cursor:
style: Underline
unfocused_hollow: true
live_config_reload: true
key_bindings:
- { key: V, mods: Control|Shift, action: Paste }
- { key: C, mods: Control|Shift, action: Copy }
- { key: Paste, action: Paste }
- { key: Copy, action: Copy }
- { key: Q, mods: Command, action: Quit }
- { key: W, mods: Command, action: Quit }
- { key: Insert, mods: Shift, action: PasteSelection }
- { key: Key0, mods: Control, action: ResetFontSize }
- { key: Equals, mods: Control, action: IncreaseFontSize }
- { key: Subtract, mods: Control, action: DecreaseFontSize }
- { key: Home, chars: "\x1bOH", mode: AppCursor }
- { key: Home, chars: "\x1b[H", mode: ~AppCursor }
- { key: End, chars: "\x1bOF", mode: AppCursor }
- { key: End, chars: "\x1b[F", mode: ~AppCursor }
- { key: PageUp, mods: Shift, chars: "\x1b[5;2~" }
- { key: PageUp, mods: Control, chars: "\x1b[5;5~" }
- { key: PageUp, chars: "\x1b[5~" }
- { key: PageDown, mods: Shift, chars: "\x1b[6;2~" }
- { key: PageDown, mods: Control, chars: "\x1b[6;5~" }
- { key: PageDown, chars: "\x1b[6~" }
- { key: Tab, mods: Shift, chars: "\x1b[Z" }
- { key: Back, chars: "\x7f" }
- { key: Back, mods: Alt, chars: "\x1b\x7f" }
- { key: Insert, chars: "\x1b[2~" }
- { key: Delete, chars: "\x1b[3~" }
- { key: Left, mods: Shift, chars: "\x1b[1;2D" }
- { key: Left, mods: Control, chars: "\x1b[1;5D" }
- { key: Left, mods: Alt, chars: "\x1b[1;3D" }
- { key: Left, chars: "\x1b[D", mode: ~AppCursor }
- { key: Left, chars: "\x1bOD", mode: AppCursor }
- { key: Right, mods: Shift, chars: "\x1b[1;2C" }
- { key: Right, mods: Control, chars: "\x1b[1;5C" }
- { key: Right, mods: Alt, chars: "\x1b[1;3C" }
- { key: Right, chars: "\x1b[C", mode: ~AppCursor }
- { key: Right, chars: "\x1bOC", mode: AppCursor }
- { key: Up, mods: Shift, chars: "\x1b[1;2A" }
- { key: Up, mods: Control, chars: "\x1b[1;5A" }
- { key: Up, mods: Alt, chars: "\x1b[1;3A" }
- { key: Up, chars: "\x1b[A", mode: ~AppCursor }
- { key: Up, chars: "\x1bOA", mode: AppCursor }
- { key: Down, mods: Shift, chars: "\x1b[1;2B" }
- { key: Down, mods: Control, chars: "\x1b[1;5B" }
- { key: Down, mods: Alt, chars: "\x1b[1;3B" }
- { key: Down, chars: "\x1b[B", mode: ~AppCursor }
- { key: Down, chars: "\x1bOB", mode: AppCursor }
- { key: F1, chars: "\x1bOP" }
- { key: F2, chars: "\x1bOQ" }
- { key: F3, chars: "\x1bOR" }
- { key: F4, chars: "\x1bOS" }
- { key: F5, chars: "\x1b[15~" }
- { key: F6, chars: "\x1b[17~" }
- { key: F7, chars: "\x1b[18~" }
- { key: F8, chars: "\x1b[19~" }
- { key: F9, chars: "\x1b[20~" }
- { key: F10, chars: "\x1b[21~" }
- { key: F11, chars: "\x1b[23~" }
- { key: F12, chars: "\x1b[24~" }
- { key: F1, mods: Shift, chars: "\x1b[1;2P" }
- { key: F2, mods: Shift, chars: "\x1b[1;2Q" }
- { key: F3, mods: Shift, chars: "\x1b[1;2R" }
- { key: F4, mods: Shift, chars: "\x1b[1;2S" }
- { key: F5, mods: Shift, chars: "\x1b[15;2~" }
- { key: F6, mods: Shift, chars: "\x1b[17;2~" }
- { key: F7, mods: Shift, chars: "\x1b[18;2~" }
- { key: F8, mods: Shift, chars: "\x1b[19;2~" }
- { key: F9, mods: Shift, chars: "\x1b[20;2~" }
- { key: F10, mods: Shift, chars: "\x1b[21;2~" }
- { key: F11, mods: Shift, chars: "\x1b[23;2~" }
- { key: F12, mods: Shift, chars: "\x1b[24;2~" }
- { key: F1, mods: Control, chars: "\x1b[1;5P" }
- { key: F2, mods: Control, chars: "\x1b[1;5Q" }
- { key: F3, mods: Control, chars: "\x1b[1;5R" }
- { key: F4, mods: Control, chars: "\x1b[1;5S" }
- { key: F5, mods: Control, chars: "\x1b[15;5~" }
- { key: F6, mods: Control, chars: "\x1b[17;5~" }
- { key: F7, mods: Control, chars: "\x1b[18;5~" }
- { key: F8, mods: Control, chars: "\x1b[19;5~" }
- { key: F9, mods: Control, chars: "\x1b[20;5~" }
- { key: F10, mods: Control, chars: "\x1b[21;5~" }
- { key: F11, mods: Control, chars: "\x1b[23;5~" }
- { key: F12, mods: Control, chars: "\x1b[24;5~" }
- { key: F1, mods: Alt, chars: "\x1b[1;6P" }
- { key: F2, mods: Alt, chars: "\x1b[1;6Q" }
- { key: F3, mods: Alt, chars: "\x1b[1;6R" }
- { key: F4, mods: Alt, chars: "\x1b[1;6S" }
- { key: F5, mods: Alt, chars: "\x1b[15;6~" }
- { key: F6, mods: Alt, chars: "\x1b[17;6~" }
- { key: F7, mods: Alt, chars: "\x1b[18;6~" }
- { key: F8, mods: Alt, chars: "\x1b[19;6~" }
- { key: F9, mods: Alt, chars: "\x1b[20;6~" }
- { key: F10, mods: Alt, chars: "\x1b[21;6~" }
- { key: F11, mods: Alt, chars: "\x1b[23;6~" }
- { key: F12, mods: Alt, chars: "\x1b[24;6~" }
- { key: F1, mods: Super, chars: "\x1b[1;3P" }
- { key: F2, mods: Super, chars: "\x1b[1;3Q" }
- { key: F3, mods: Super, chars: "\x1b[1;3R" }
- { key: F4, mods: Super, chars: "\x1b[1;3S" }
- { key: F5, mods: Super, chars: "\x1b[15;3~" }
- { key: F6, mods: Super, chars: "\x1b[17;3~" }
- { key: F7, mods: Super, chars: "\x1b[18;3~" }
- { key: F8, mods: Super, chars: "\x1b[19;3~" }
- { key: F9, mods: Super, chars: "\x1b[20;3~" }
- { key: F10, mods: Super, chars: "\x1b[21;3~" }
- { key: F11, mods: Super, chars: "\x1b[23;3~" }
- { key: F12, mods: Super, chars: "\x1b[24;3~" }

2
config/bat/config

@ -0,0 +1,2 @@
--theme="ansi-dark"
--style="numbers,changes,header"

23
config/bin/backlight

@ -0,0 +1,23 @@
#!/bin/sh
send_notification() {
backlight=$(brightnessctl -m | cut -d, -f4 | sed 's/%//' | awk '{print int($1 / 2.9)}')
# Make the bar with the special character โ”€ (it's not dash -)
# https://en.wikipedia.org/wiki/Box-drawing_character
bar=$(seq -s "โ”€" "$backlight" | sed 's/[0-9]//g')
# Send the notification
makoctl dismiss
notify-send -t 1000 "mon: $bar"
}
case $1 in
up)
brightnessctl -q set +10%
send_notification
;;
down)
brightnessctl -q set 10%-
send_notification
;;
*) echo "usage: backlight [up|down]" ;;
esac

23
config/bin/berun

@ -0,0 +1,23 @@
#!/bin/sh
## TODO: figure out whatever the fuck is happening here
#MONITORS="$(swaymsg -t get_outputs | jq -r 'length')"
#FOCUSED="$(swaymsg -t get_workspaces | jq -r '.. | select(.focused?) | .output')"
#case $FOCUSED in
# eDP1)
#esac
BG="$(xrq background)"
FG="$(xrq foreground)"
BLK="$(xrq color0)"
HL="$(xrq color1)"
FONT="FiraCode 9"
PROMPT=">"
LINES=10
LH=20
bemenu -m -1 -n -p "$PROMPT" -l "$LINES" --fn "$FONT" -H "$LH" --scrollbar always \
--tb "$HL" --tf "$BLK" --nb "$BG" --nf "$FG" \
--hb "$BG" --hf "$HL" --fb "$BLK" --ff "$FG" \
--scb "$BLK" --scf "$HL"

24
config/bin/blocks

@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Show the terminal colourscheme as blocks
# Inspired by u/dkeg
# Cheers! Addy
f=3 b=4
for j in f b; do
for i in {0..7}; do
printf -v $j$i %b "\e[${!j}${i}m"
done
done
d=$'\e[1m'
t=$'\e[0m'
v=$'\e[7m'
cat << EOF
$f1โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f2โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f3โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f4โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f5โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f6โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t
$f1โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f2โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f3โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f4โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f5โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f6โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t
$f1โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f2โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f3โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f4โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f5โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t $f6โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$dโ–ˆโ–ˆ$t
$ftโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$d$f7โ–ˆโ–ˆ$t $ftโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$d$f7โ–ˆโ–ˆ$t $ftโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$d$f7โ–ˆโ–ˆ$t $ftโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$d$f7โ–ˆโ–ˆ$t $ftโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$d$f7โ–ˆโ–ˆ$t $ftโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ$d$f7โ–ˆโ–ˆ$t
EOF

3
config/bin/emacsc

@ -0,0 +1,3 @@
#!/bin/sh
emacsclient -c --socket-name hazel-emacsd $@

14
config/bin/import-gsettings

@ -0,0 +1,14 @@
#!/bin/sh
if [ -z "$@" ]; then
echo "usage: import-gsettings <gsettings key>:<settings.ini key> <gsettings key>:<settings.ini key> ..."
return 1
fi
expression=""
for pair in "$@"; do
IFS=:; set -- $pair
expressions="$expressions -e 's:^$2=(.*)$:gsettings set org.gnome.desktop.interface $1 \1:e'"
done
IFS=
eval exec sed -E $expressions "${XDG_CONFIG_HOME:-$HOME/.config}"/gtk-3.0/settings.ini >/dev/null

64
config/bin/keyboard

@ -0,0 +1,64 @@
#!/usr/bin/env bash
#
# Control keyboard layout and backlight (Lenovo ThinkPad tested only)
#
# Author: Dave Eddy <dave@daveeddy.com>
# Date: June 25, 2018
# License: MIT
TMPFILE=/tmp/keyboard-status
# taken from https://wiki.archlinux.org/index.php/Keyboard_backlight
setKeyboardLight() {
echo "$1" > "$TMPFILE"
dbus-send --system --type=method_call \
--dest='org.freedesktop.UPower' \
'/org/freedesktop/UPower/KbdBacklight' \
'org.freedesktop.UPower.KbdBacklight.SetBrightness' \
"int32:$1"
}
# cycle the current state of the keyboard backlight
cycleKeyboardLight() {
local cur
cur="$(cat $TMPFILE)"
case "$cur" in
0) setKeyboardLight 1;;
1) setKeyboardLight 2;;
2) setKeyboardLight 0;;
*) exit 1;;
esac
}
usage() {
local prog=${0##*/}
cat <<-EOF
Usage: $prog <command>
Examples
# control backlight
$prog [off | dim | bright/on]
# print help
$prog help
EOF
}
if [[ ! -f "$TMPFILE" ]]; then
echo '0' > "$TMPFILE"
fi
case "$1" in
# lights
off) setKeyboardLight 0;;
dim) setKeyboardLight 1;;
on|bright) setKeyboardLight 2;;
cycle) cycleKeyboardLight;;
help|-h) usage; exit 0;;
*) usage >&2; exit 1;;
esac

68
config/bin/notify-action-alt

@ -0,0 +1,68 @@
#!/usr/bin/env bash
GDBUS_MONITOR_PID=/tmp/notify-action-dbus-monitor.$$.pid
GDBUS_MONITOR=(gdbus monitor --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications)
NOTIFICATION_ID="$1"
if [[ -z "$NOTIFICATION_ID" ]]; then
echo "no notification id passed: $@"
exit 1;
fi
shift
ACTION_COMMANDS=("$@")
if [[ -z "$ACTION_COMMANDS" ]]; then
echo "no action commands passed: $@"
exit 1;
fi
cleanup() {
rm -f "$GDBUS_MONITOR_PID"
}
create_pid_file(){
rm -f "$GDBUS_MONITOR_PID"
umask 077
touch "$GDBUS_MONITOR_PID"
}
invoke_action() {
invoked_action_id="$1"
local action="" cmd=""
for index in "${!ACTION_COMMANDS[@]}"; do
if [[ $((index % 2)) == 0 ]]; then
action="${ACTION_COMMANDS[$index]}"
else
cmd="${ACTION_COMMANDS[$index]}"
if [[ "$action" == "$invoked_action_id" ]]; then
bash -c "${cmd}" &
fi
fi
done
}
monitor() {
create_pid_file
( "${GDBUS_MONITOR[@]}" & echo $! >&3 ) 3>"$GDBUS_MONITOR_PID" | while read -r line
do
local closed_notification_id="$(sed '/^\/org\/freedesktop\/Notifications: org.freedesktop.Notifications.NotificationClosed (uint32 \([0-9]\+\), uint32 [0-9]\+)$/!d;s//\1/' <<< "$line")"
if [[ -n "$closed_notification_id" ]]; then
if [[ "$closed_notification_id" == "$NOTIFICATION_ID" ]]; then
invoke_action close
break
fi
else
local action_invoked="$(sed '/\/org\/freedesktop\/Notifications: org.freedesktop.Notifications.ActionInvoked (uint32 \([0-9]\+\), '\''\(.*\)'\'')$/!d;s//\1:\2/' <<< "$line")"
IFS=: read invoked_id action_id <<< "$action_invoked"
if [[ "$invoked_id" == "$NOTIFICATION_ID" ]]; then
invoke_action "$action_id"
break
fi
fi
done
kill $(<"$GDBUS_MONITOR_PID")
cleanup
}
monitor

312
config/bin/notify-alt

@ -0,0 +1,312 @@
#!/usr/bin/env bash
# notify-send.sh - drop-in replacement for notify-send with more features
# Copyright (C) 2015-2019 notify-send.sh authors (see AUTHORS file)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Desktop Notifications Specification
# https://developer.gnome.org/notification-spec/
VERSION=1.0
NOTIFY_ARGS=(--session
--dest org.freedesktop.Notifications
--object-path /org/freedesktop/Notifications)
EXPIRE_TIME=-1
APP_NAME="${0##*/}"
REPLACE_ID=0
URGENCY=1
HINTS=()
SUMMARY_SET=n
help() {
cat <<EOF
Usage:
notify-send.sh [OPTION...] <SUMMARY> [BODY] - create a notification
Help Options:
-?|--help Show help options
Application Options:
-u, --urgency=LEVEL Specifies the urgency level (low, normal, critical).
-t, --expire-time=TIME Specifies the timeout in milliseconds at which to expire the notification.
-f, --force-expire Forcefully closes the notification when the notification has expired.
-a, --app-name=APP_NAME Specifies the app name for the icon.
-i, --icon=ICON[,ICON...] Specifies an icon filename or stock icon to display.
-c, --category=TYPE[,TYPE...] Specifies the notification category.
-h, --hint=TYPE:NAME:VALUE Specifies basic extra data to pass. Valid types are int, double, string and byte.
-o, --action=LABEL:COMMAND Specifies an action. Can be passed multiple times. LABEL is usually a button's label. COMMAND is a shell command executed when action is invoked.
-d, --default-action=COMMAND Specifies the default action which is usually invoked by clicking the notification.
-l, --close-action=COMMAND Specifies the action invoked when notification is closed.
-p, --print-id Print the notification ID to the standard output.
-r, --replace=ID Replace existing notification.
-R, --replace-file=FILE Store and load notification replace ID to/from this file.
-s, --close=ID Close notification.
-v, --version Version of the package.
EOF
}
convert_type() {
case "$1" in
int) echo int32 ;;
double|string|byte) echo "$1" ;;
*) echo error; return 1 ;;
esac
}
make_action_key() {
echo "$(tr -dc _A-Z-a-z-0-9 <<< \"$1\")${RANDOM}"
}
make_action() {
local action_key="$1"
printf -v text "%q" "$2"
echo "\"$action_key\", \"$text\""
}
make_hint() {
type=$(convert_type "$1")
[[ ! $? = 0 ]] && return 1
name="$2"
[[ "$type" = string ]] && command="\"$3\"" || command="$3"
echo "\"$name\": <$type $command>"
}
concat_actions() {
local result="$1"
shift
for s in "$@"; do
result="$result, $s"
done
echo "[$result]"
}
concat_hints() {
local result="$1"
shift
for s in "$@"; do
result="$result, $s"
done
echo "{$result}"
}
parse_notification_id(){
sed 's/(uint32 \([0-9]\+\),)/\1/g'
}
notify() {
local actions="$(concat_actions "${ACTIONS[@]}")"
local hints="$(concat_hints "${HINTS[@]}")"
NOTIFICATION_ID=$(gdbus call "${NOTIFY_ARGS[@]}" \
--method org.freedesktop.Notifications.Notify \
"$APP_NAME" "$REPLACE_ID" "$ICON" "$SUMMARY" "$BODY" \
"${actions}" "${hints}" "int32 $EXPIRE_TIME" \
| parse_notification_id)
if [[ -n "$STORE_ID" ]] ; then
echo "$NOTIFICATION_ID" > $STORE_ID
fi
if [[ -n "$PRINT_ID" ]] ; then
echo "$NOTIFICATION_ID"
fi
if [[ -n "$FORCE_EXPIRE" ]] ; then
type bc &> /dev/null || { echo "bc command not found. Please install bc package."; exit 1; }
SLEEP_TIME="$(bc <<< "scale=3; $EXPIRE_TIME / 1000")"
( sleep "$SLEEP_TIME" ; notify_close "$NOTIFICATION_ID" ) &
fi
maybe_run_action_handler
}
notify_close () {
gdbus call "${NOTIFY_ARGS[@]}" --method org.freedesktop.Notifications.CloseNotification "$1" >/dev/null
}
process_urgency() {
case "$1" in
low) URGENCY=0 ;;
normal) URGENCY=1 ;;
critical) URGENCY=2 ;;
*) echo "Unknown urgency $URGENCY specified. Known urgency levels: low, normal, critical."
exit 1
;;
esac
}
process_category() {
IFS=, read -a categories <<< "$1"
for category in "${categories[@]}"; do
hint="$(make_hint string category "$category")"
HINTS=("${HINTS[@]}" "$hint")
done
}
process_hint() {
IFS=: read type name command <<< "$1"
if [[ -z "$name" ]] || [[ -z "$command" ]] ; then
echo "Invalid hint syntax specified. Use TYPE:NAME:VALUE."
exit 1
fi
hint="$(make_hint "$type" "$name" "$command")"
if [[ ! $? = 0 ]] ; then
echo "Invalid hint type \"$type\". Valid types are int, double, string and byte."
exit 1
fi
HINTS=("${HINTS[@]}" "$hint")
}
maybe_run_action_handler() {
if [[ -n "$NOTIFICATION_ID" ]] && [[ -n "$ACTION_COMMANDS" ]]; then
local notify_action="$(dirname ${BASH_SOURCE[0]})/notify-action.sh"
if [[ -x "$notify_action" ]] ; then
"$notify_action" "$NOTIFICATION_ID" "${ACTION_COMMANDS[@]}" &
exit 0
else
echo "executable file not found: $notify_action"
exit 1
fi
fi
}
process_action() {
IFS=: read name command <<<"$1"
if [[ -z "$name" ]] || [[ -z "$command" ]]; then
echo "Invalid action syntax specified. Use NAME:COMMAND."
exit 1
fi
local action_key="$(make_action_key "$name")"
ACTION_COMMANDS=("${ACTION_COMMANDS[@]}" "$action_key" "$command")
local action="$(make_action "$action_key" "$name")"
ACTIONS=("${ACTIONS[@]}" "$action")
}
process_special_action() {
action_key="$1"
command="$2"
if [[ -z "$action_key" ]] || [[ -z "$command" ]]; then
echo "Command must not be empty"
exit 1
fi
ACTION_COMMANDS=("${ACTION_COMMANDS[@]}" "$action_key" "$command")
if [[ "$action_key" != close ]]; then
local action="$(make_action "$action_key" "$name")"
ACTIONS=("${ACTIONS[@]}" "$action")
fi
}
process_posargs() {
if [[ "$1" = -* ]] && ! [[ "$positional" = yes ]] ; then
echo "Unknown option $1"
exit 1
else
if [[ "$SUMMARY_SET" = n ]]; then
SUMMARY="$1"
SUMMARY_SET=y
else
BODY="$1"
fi
fi
}
while (( $# > 0 )) ; do
case "$1" in
-\?|--help)
help
exit 0
;;
-v|--version)
echo "${0##*/} $VERSION"
exit 0
;;
-u|--urgency|--urgency=*)
[[ "$1" = --urgency=* ]] && urgency="${1#*=}" || { shift; urgency="$1"; }
process_urgency "$urgency"
;;
-t|--expire-time|--expire-time=*)
[[ "$1" = --expire-time=* ]] && EXPIRE_TIME="${1#*=}" || { shift; EXPIRE_TIME="$1"; }
;;
-f|--force-expire)
FORCE_EXPIRE=yes
;;
-a|--app-name|--app-name=*)
[[ "$1" = --app-name=* ]] && APP_NAME="${1#*=}" || { shift; APP_NAME="$1"; }
;;
-i|--icon|--icon=*)
[[ "$1" = --icon=* ]] && ICON="${1#*=}" || { shift; ICON="$1"; }
;;
-c|--category|--category=*)
[[ "$1" = --category=* ]] && category="${1#*=}" || { shift; category="$1"; }
process_category "$category"
;;
-h|--hint|--hint=*)
[[ "$1" = --hint=* ]] && hint="${1#*=}" || { shift; hint="$1"; }
process_hint "$hint"
;;
-o | --action | --action=*)
[[ "$1" == --action=* ]] && action="${1#*=}" || { shift; action="$1"; }
process_action "$action"
;;
-d | --default-action | --default-action=*)
[[ "$1" == --default-action=* ]] && default_action="${1#*=}" || { shift; default_action="$1"; }
process_special_action default "$default_action"
;;
-l | --close-action | --close-action=*)
[[ "$1" == --close-action=* ]] && close_action="${1#*=}" || { shift; close_action="$1"; }
process_special_action close "$close_action"
;;
-p|--print-id)
PRINT_ID=yes
;;
-r|--replace|--replace=*)
[[ "$1" = --replace=* ]] && REPLACE_ID="${1#*=}" || { shift; REPLACE_ID="$1"; }
;;
-R|--replace-file|--replace-file=*)
[[ "$1" = --replace-file=* ]] && filename="${1#*=}" || { shift; filename="$1"; }
if [[ -s "$filename" ]]; then
REPLACE_ID="$(< $filename)"
fi
STORE_ID="$filename"
;;
-s|--close|--close=*)
[[ "$1" = --close=* ]] && close_id="${1#*=}" || { shift; close_id="$1"; }
notify_close "$close_id"
exit $?
;;
--)
positional=yes
;;
*)
process_posargs "$1"
;;
esac
shift
done
# urgency is always set
HINTS=("$(make_hint byte urgency "$URGENCY")" "${HINTS[@]}")
if [[ "$SUMMARY_SET" = n ]] ; then
help
exit 1
else
notify
fi

48
config/bin/scrot

@ -0,0 +1,48 @@
#!/bin/sh
SCROT_FILE="/home/hazel/usr/img/scrots/$(date +"scr_%Y-%m-%d_%H-%M-%S").png"
send_notification() {
if [ -n "$1" ]; then
wl-copy "$1"
notify-send -i "$SCROT_FILE" "Screenshot saved!" "URL: $1" -t 2500
else
# only copy the image if we aren't already copying the URL
wl-copy -t image/png < "$SCROT_FILE"
notify-send -i "$SCROT_FILE" "Screenshot saved!" -t 2500
fi
}
grab_selection() {
SCROT_AREA="$(swaymsg -t get_tree | jq -r '.. | (.nodes? // empty)[] | select(.pid and .visible) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp)"
grim -g "$SCROT_AREA" "$SCROT_FILE"
}
grab_full() {
grim "$SCROT_FILE"
}
upload_scrot() {
API_KEY="$(jq -r '.apikey' < "$HOME"/.config/linx-client.conf)" # reinventing the wheel
curl -s -H "Linx-Api-Key: $API_KEY" -H "Linx-Randomize: yes" -H "Accept: application/json" \
-T "$SCROT_FILE" https://p.qtp2t.club/upload/ | jq -r '.url'
}
case "$1" in
selup)
grab_selection && send_notification "$(upload_scrot)"
;;
sel)
grab_selection && send_notification
;;
fullup)
grab_full && send_notification "$(upload_scrot)"
;;
full)
grab_full && send_notification
;;
*)
echo "usage: scrot [full|sel|fullup|selup]"
return 1
;;
esac

37
config/bin/volume

@ -0,0 +1,37 @@
#!/bin/sh
send_notification() {
volume=$(ponymix --sink get-volume | awk '{print int($1 / 2.9)}')
# Make the bar with the special character โ”€ (it's not dash -)
# https://en.wikipedia.org/wiki/Box-drawing_character
bar=$(seq -s "โ”€" "$volume" | sed 's/[0-9]//g')
# Send the notification
makoctl dismiss
notify-send -t 1000 "vol: $bar"
}
case $1 in
up)
# Set the volume on (if it was muted)
ponymix --sink unmute
# Up the volume (+ 5%)
ponymix --sink increase 5
send_notification
;;
down)
ponymix --sink unmute
ponymix --sink decrease 5
send_notification
;;
mute)
# Toggle mute
ponymix --sink toggle
if ponymix --sink is-muted; then
makoctl dismiss
notify-send -t 1000 "volume muted"
else
send_notification
fi
;;
*) echo "usage: volume [up|down|mute]" ;;
esac

86
config/bin/xbps-menu

@ -0,0 +1,86 @@
#!/bin/sh
# https://github.com/BanchouBoo/dots/blob/master/bin/xbps-menu
# ^ not licensed but...
# sets XDG_CACHE_HOME to it's default if not set
: "${XDG_CACHE_HOME:=$HOME/.cache}"
cache_file="$XDG_CACHE_HOME/xbps-menu/pkglist"
options="install
update
sync
remove
autoremove
clean"
install_preview='pkg={}; pkg="${pkg%% *}"; xbps-query "$pkg" --property state > /dev/null &&
# stat="Status: \033[2K\033[00;32mInstalled\033[0m" ||
# stat="Status: \033[2K\033[0;31mNot installed\033[0m"
stat="Status: Installed" ||
stat="Status: Not installed"
depends=$(xbps-query -R "$pkg" --property run_depends | sed "2,99 s/^/\t\t/")
printf "$stat \tDependencies:\t%s\n" "$depends" | column --separator " " --table'
remove_preview='pkg={}; pkg="${pkg%% *}"; revdeps=$(xbps-query --revdeps "$pkg" | sed "2,99 s/^/\t\t/")
printf "Dependents:\t%s\n" "$revdeps"'
log() {
printf "\n[\033[00;34m..\033[0m] %s\n" "$@"
}
install() {
if [ ! -f "$cache_file" ]; then
log "Cache file doesn't exist, syncing repos and generating cache"
sync
fi
packages=$(
sk --multi --preview "$install_preview" \
--preview-window "up" < "$cache_file" | \
while read -r package; do
echo "${package%% *}"
done)
[ "$packages" ] && doas xbps-install -f $packages
}
update() {
doas xbps-install -u
}
# syncs the repos and updates the cache
sync() {
log "Syncing remote repositories"
doas xbps-install -S
mkdir -p "$XDG_CACHE_HOME/xbps-menu"
xbps-query -Rs "*" | while read -r line; do
echo "${line#????}"
done > "$cache_file"
}
remove() {
packages=$(
xbps-query -s "*" | while read -r line; do
echo "${line#????}"
done | \
sk --multi --preview "$remove_preview" \
--preview-window "up" | \
while read -r package; do
echo "${package%% *}"
done)
[ "$packages" ] && doas xbps-remove -R $packages
}
autoremove() {
log "Removing orphaned packages"
doas xbps-remove -o
}
clean() {
log "Cleaning cached packages"
doas xbps-remove -O
}
while :; do
selection=$(echo "$options" | sk)
[ "$selection" ] || exit
"$selection"
done

191
config/doom/blog.org

@ -0,0 +1,191 @@
#+TITLE: The Blag
#+AUTHOR: Hazel Levine
#+EMAIL: rose.hazel@protonmail.ch
#+STARTUP: nofold
This is the source code powering my blog, available at [[https://blog.qtp2t.club][blog.qtp2t.club]]. It sure
does exist. More info can be found on the blog itself [[https://blog.qtp2t.club/2020-01-13-blorgging.html][here]], but basically this
uses pure Org mode with no external dependencies.
* Global variables
These are defined for later configuration and to avoid repetition, as well as to
modularize things such that if I ever change my home directory structure it
doesn't break everything.
We define where we want to store the files:
#+BEGIN_SRC emacs-lisp
(setq blog/site-project-path "/home/hazel/usr/doc/blog/")
#+END_SRC
Where we want the exported HTML to go:
#+BEGIN_SRC emacs-lisp
(setq blog/site-publish-path (concat blog/site-project-path "build/"))
#+END_SRC
As well as extra content to put in the header and footer. Note that setting
these as variables means =blog.el= has to be reloaded whenever you change the
contents of these files, which has bitten me in the butt /multiple/ times.
#+BEGIN_SRC emacs-lisp
(setq blog/site-extra-head-file (concat blog/site-project-path "templates/headext.html"))
(setq blog/site-header-file (concat blog/site-project-path "templates/header.html"))
(setq blog/site-footer-file (concat blog/site-project-path "templates/footer.html"))
#+END_SRC
Finally, we host MathJax locally, to avoid using CDNs, as well as the fact that
Org doesn't tango nice with MathJax 3.x for some reason. We use the Neo-Euler
font because I think it looks cool. Note that when deploying this, you probably
don't want to =scp= MathJax; it'll take forever.
#+BEGIN_SRC emacs-lisp
(setq blog/mathjax-options
'((path "./static/mj/MathJax.js?config=TeX-AMS-MML_HTMLorMML")
(scale "100") (align "left") (indent "2em") (tagside "right")
(mathml nil) (font "Neo-Euler")))
#+END_SRC
* Functions
We define a means to add HTML files as part of a file, such that we can add our
custom headers and footers:
#+BEGIN_SRC emacs-lisp
(defun blog/add-html-file (arg)
(with-temp-buffer
(insert-file-contents arg)
(buffer-string)))
#+END_SRC
We then take our previous variables defining the header and footer of the site
and convert them into raw strings for usage in Org's exporter:
#+BEGIN_SRC emacs-lisp
(setq blog/site-extra-head-raw (blog/add-html-file blog/site-extra-head-file))
(setq blog/site-header-raw (blog/add-html-file blog/site-header-file))
(setq blog/site-footer-raw (blog/add-html-file blog/site-footer-file))
#+END_SRC
Additionally, we define a way to format a site entry in our table of contents:
#+BEGIN_SRC emacs-lisp
(defun blog/site-format-entry (entry style project)
(format "[[file:%s][%s]] --- %s"
entry
(org-publish-find-title entry project)
(format-time-string "%Y-%m-%d" (org-publish-find-date entry project))))
#+END_SRC
* Org-publish
This is the meat of it; what tells Org that we're actually looking to make a
website out of miscalleneous files scattered in my documents folder. It's one
giant call to =setq=.
We tell Org that the site is a concatenation of all of its components, that we
want to export HTML, and to look recursively. We also tell Org to put stuff in
that's defined later.
#+BEGIN_SRC emacs-lisp :noweb yes
(setq org-publish-project-alist
`(("site"
:components ("site-static", "site-images", "site-articles", "site-dl", "site-rss"))
<<static>>
<<rss>>
<<html1>>
<<html2>>
<<html3>>
:publishing-function org-html-publish-to-html
:recursive t)))
#+END_SRC
** Static
Static resources, such as MathJax and CSS, should be copied directly to their
respective folders. This also applies for images and public files (=dl=). We
send these files to =blog/site-project-path=. The built-in publishing function
=org-publish-attachment= copies the file directly, and we also tell Org to
search recursively in case there are any subfolders.
#+NAME: static
#+BEGIN_SRC emacs-lisp :tangle no
("site-static"
:base-directory ,(concat blog/site-project-path "static/")
:base-extension ".*"
:publishing-directory ,(concat blog/site-publish-path "static/")
:publishing-function org-publish-attachment
:recursive t)
("site-images"
:base-directory ,(concat blog/site-project-path "img")
:base-extension ".*"
:publishing-directory ,(concat blog/site-publish-path "img/")
:publishing-function org-publish-attachment
:recursive t)
("site-dl"
:base-directory ,(concat blog/site-project-path "dl")
:base-extension ".*"
:publishing-directory ,(concat blog/site-publish-path "dl/")
:publishing-function org-publish-attachment
:recursive t)
#+END_SRC
** RSS
I still like RSS. Also, one person asked for it, so I'm happy to oblige. For
some reason, Org likes to repeat the XML header three times (???) at the
beginning of the resulting XML file, so I go back and manually delete it every
time.
We tell it to look over all the articles, tell it where the blog is, and tell it
to look over =index.org= (which is our table of contents) and nothing else. We
also use =org-rss-publish-to-rss=, which pretty much does what it says it does.
#+NAME: rss
#+BEGIN_SRC emacs-lisp :tangle no
("site-rss"
:base-directory ,(concat blog/site-project-path "articles/")
:base-extension "org"
:publishing-directory ,blog/site-publish-path
:publishing-function org-rss-publish-to-rss
:html-link-home "https://blog.qtp2t.club"
:html-link-use-abs-url t
:title "Ziodyne"
:section-numbers nil
:exclude ".*"
:include ("index.org")
:table-of-contents nil)
#+END_SRC
** Articles (HTML)
We tell Org to look over our articles directory, only search through Org files,
and put everything in the site's publish path:
#+NAME: html1
#+BEGIN_SRC emacs-lisp :tangle no
("site-articles"
:base-directory ,(concat blog/site-project-path "articles/")
:base-extension "org"
:publishing-directory ,blog/site-publish-path
#+END_SRC
We tell it that we're using HTML5, to include the extra headers, preamble, and
postamble, and that we're operating on the root of the subdomain, as well as
define MathJax to be itself:
#+NAME: html2
#+BEGIN_SRC emacs-lisp :tangle no
:html-doctype "html5"
:html-link-home "/"
:html-head nil
:html-head-extra ,blog/site-extra-head-raw
:html-head-include-default-style nil
:html-head-include-scripts nil
:html-home/up-format ""
:html-preamble ,blog/site-header-raw
:html-postamble ,blog/site-footer-raw
:html-mathjax-options ,blog/mathjax-options
#+END_SRC
We generate the sitemap, tell it to save the result to =index.org=, and to list
anti-chronologically. We also use the previously defined function
=blog/site-format-entry= to... format entries.
#+NAME: html3
#+BEGIN_SRC emacs-lisp :tangle no
:makeindex nil
:auto-sitemap t
:sitemap-filename "index.org"
:sitemap-title "Ramblings"
:sitemap-style list
:sitemap-sort-files anti-chronologically
:sitemap-format-entry blog/site-format-entry
:with-toc nil
:section-numbers nil
#+END_SRC

306
config/doom/config.org

@ -0,0 +1,306 @@
#+TITLE: Hazel's DOOM Emacs configuration
#+AUTHOR: Hazel Levine
#+EMAIL: rose.hazel@protonmail.ch
#+STARTUP: nofold
Whee, literate programming, whoo. I get to type words here. These are words on a
screen. Typing. With /haaaaaaands/.
In this file, we tangle the following:
#+BEGIN_SRC emacs-lisp
;;; config.el -*- lexical-binding: t -*-
#+END_SRC
#+BEGIN_SRC emacs-lisp :tangle ~/.config/doom/packages.el
;;; packages.el -*- lexical-binding: t -*-
#+END_SRC
Any calls to =package!= generally get tangled to =packages.el=, whereas
everything else goes to =config.el=.
* Introduction
** =whoami=
#+BEGIN_SRC emacs-lisp
(setq user-full-name "Hazel Levine"
user-mail-address "me@qtp2t.club")
#+END_SRC
** Custom Elisp
Load up where Void installs the =maxima-emacs= package, for later:
#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path "/usr/share/emacs/site-lisp")
#+END_SRC
Additionally, load the source code powering
[[https://blog.qtp2t.club][my blog.]]
#+BEGIN_SRC emacs-lisp
(org-babel-load-file (concat doom-private-dir "blog.org"))
#+END_SRC
* UI
** Fonts
I've had font rendering issues with Emacs for /years/, ever since I picked it
up. Namely, Emacs' font always looked just different enough from that of
whatever terminal emulator I'm using to be annoying. Thankfully, [[https://github.com/rocx/.emacs.d][rocx's emacs
config]] held the solution by forcing Emacs to use XFT (which is what =urxvt=, my
terminal emulator, also uses).
I first define a function to create an XFT font string from whatever font, size,
and options I want:
#+BEGIN_SRC emacs-lisp
(defun hzl/xft-font-string (name size &optional properties)
;; https://keithp.com/~keithp/render/Xft.tutorial
(concat (format "%s-%d" name size)
(when properties
(apply #'concat (mapcar (lambda (prop)
(format ":%s=%s" (car prop) (cdr prop)))
properties)))))
#+END_SRC
Across my system, I use [[https://github.com/NerdyPepper/curie][curie]] for anything "system-related" (notifications,
bars, etc...), [[https://github.com/tonsky/FiraCode][Fira Code]] for monospace (read: programming) font with [[https://www.nerdfonts.com/][Nerd Fonts]]
patches, and [[https://fonts.adobe.com/fonts/source-sans][Source Sans Pro]] everywhere else. Size 9 seems to be readable on
both my 1920x1080 external monitor and 1600x900 ThinkPad.
#+BEGIN_SRC emacs-lisp
(defvar hzl/monospace-font
(hzl/xft-font-string "FiraCode" 10
'((hintstyle . 3)
(hinting . true)
(lcdfilter . 3)
(antialias . true))))
(defvar hzl/variable-pitch-font
(hzl/xft-font-string "Source Sans Pro" 10
'((hintstyle . 3)
(autohint . true)
(lcdfilter . 3)
(antialias . true))))
(setq doom-font hzl/monospace-font)
(setq doom-variable-pitch-font hzl/variable-pitch-font)
#+END_SRC
** Colorscheme
I use [[http://sourcerer.xero.nu/][xero's sourcerer]] because it's readable, easy on the eyes, and plays well
with a lot of wallpapers (spoken like a true ricer).
#+BEGIN_SRC emacs-lisp
(setq doom-theme 'doom-gruvbox-light)
#+END_SRC
** Everything else
Enable line numbers, because those are nice, and make 'em relative:
#+BEGIN_SRC emacs-lisp
(setq display-line-numbers-type 'relative)
#+END_SRC
Set the startup screen image to something comfy:
#+BEGIN_SRC emacs-lisp
(setq fancy-splash-image (concat doom-private-dir "nice.png"))
#+END_SRC
* Functionality
For the most part, DOOM Emacs handles 99% of the things I want to do in a text
editor and more, which is why this section is pretty brief.
Pretty much all of the functions I write end up under the "namespace"
=hzl/whatever=, on the merit that I want to avoid any clashes anywhere.
** Void package templates
Void packages are written in a single shell script, so bind that mode to any
file with the name =template=.
#+BEGIN_SRC emacs-lisp
(add-to-list 'auto-mode-alist '("/template\\'" . sh-mode))
#+END_SRC
** MPDel music player
I usually use =ncmpcpp= for music, but sometimes when I'm working I use this.
It's all MPD, so it's not like they conflict.
We grab both MPDel and its Ivy interface:
#+BEGIN_SRC emacs-lisp :tangle ~/.config/doom/packages.el
(package! mpdel)
(package! ivy-mpdel)
#+END_SRC
We also disable evil in MPDel because its keybindings are contingent on doing
so.
#+BEGIN_SRC emacs-lisp
(use-package! mpdel
:config
(mpdel-mode)
(set-evil-initial-state! '(mpdel-playlist-mode
mpdel-browser-mode
mpdel-song-mode
mpdel-tablist-mode)
'emacs))
#+END_SRC
* Productivity, papers, etc
For the boring stuff that's not /quite/ programming.
** TeXcount
This is a binding to a Perl script installed via =tlmgr= that... counts words.
Considering most of the papers I write have hard minimum/maximum limits, this
comes in pretty useful pretty often.
#+BEGIN_SRC emacs-lisp
(defun hzl/texcount ()
;; Counts words in a TeX file.
(interactive)
(let*
((this-file (buffer-file-name))
(enc-str (symbol-name buffer-file-coding-system))
(enc-opt
(cond
((string-match "utf-8" enc-str) "-utf8")
((string-match "latin" enc-str) "-latin1")
("-encoding=guess")))
(word-count
(with-output-to-string
(with-current-buffer standard-output
(call-process "texcount" nil t nil "-0" enc-opt this-file)))))
(message word-count)))
#+END_SRC
...and then, actually bind it to =C-c w= in LaTeX mode.
#+BEGIN_SRC emacs-lisp
(add-hook 'LaTeX-mode-hook (lambda () (define-key LaTeX-mode-map "\C-cw" 'hzl/texcount)))
#+END_SRC
** AucTeX =latexmk=
I use =latexmk= to build my LaTeX work because I use external files for my
bibliographies.
#+BEGIN_SRC emacs-lisp :tangle ~/.config/doom/packages.el
(package! auctex-latexmk)
#+END_SRC
We tell it to run the auto-setup function and use PDFs:
#+BEGIN_SRC emacs-lisp
(use-package! auctex-latexmk
:config
(auctex-latexmk-setup)
(setq auctex-latexmk-inherit-TeX-pdf-mode t))
#+END_SRC
** Maxima
I use this CAS in conjunction with Org to take notes in my physics class, as
well as to take notes on personal projects. It also automatically renders to
LaTeX, and has a really clean Emacs interface. This isn't installed via
=use-package!=, it's the =maxima-emacs= package on Void, which is why it's a
series of autoloads.
#+BEGIN_SRC emacs-lisp
(autoload 'maxima-mode "maxima" "Maxima mode" t)
(autoload 'imaxima "imaxima" "Frontend for maxima with image support" t)
(autoload 'maxima "maxima" "Maxima interaction" t)
(autoload 'imath-mode "imath" "Imath mode for math formula input" t)
#+END_SRC
Bind =M-x imaxima= to use =maxima-mode=:
#+BEGIN_SRC emacs-lisp
(setq imaxima-use-maxima-mode-flag t)
#+END_SRC
And bind the right file extensions:
#+BEGIN_SRC emacs-lisp
(add-to-list 'auto-mode-alist '("\\.ma[cx]" . maxima-mode))
#+END_SRC
** =mu4e=
Since ProtonMail offers an IMAP/SMTP bridge now on Linux, I can use this.
Tell =mu4e= to use =mbsync=. =offlineimap= was the only piece of software on my
machine binding me to Python 2.
#+BEGIN_SRC emacs-lisp
(setq +mu4e-backend 'mbsync)
#+END_SRC
Tell it where I save my mail:
#+BEGIN_SRC emacs-lisp
(setq mu4e-maildir "/home/hazel/var/mail/protonmail"
mu4e-attachment-dir "/home/hazel/var/mail/protonmail/attachments")
#+END_SRC
We tell it how I save my email, too:
#+BEGIN_SRC emacs-lisp
(set-email-account! "ProtonMail"
'((mu4e-sent-folder . "/Sent")
(mu4e-drafts-folder . "/Drafts")
(mu4e-trash-folder . "/Trash")
(mu4e-refile-folder . "/All Mail")
(smtpmail-smtp-user . "me@qtp2t.club")
(smtpmail-smtp-service . 1025)
(user-mail-address . "me@qtp2t.club"))
t)
#+END_SRC
This took me forever to figure out. In order to let Emacs send mail from the
ProtonMail Bridge's SMTP server, you have to allow its self-signed certificate.
To get this certificate, you can execute the command:
#+BEGIN_SRC sh :tangle no
openssl s_client -connect 127.0.0.1:1025 -starttls smtp 2>/dev/null </dev/null | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > out.pem
#+END_SRC
Then copy the resulting file =out.pem= to wherever you want, and:
#+BEGIN_SRC emacs-lisp
(add-to-list 'gnutls-trustfiles "/home/hazel/var/certs/protonmail_bridge.pem")
#+END_SRC
** Org-mode
Set the bullets to pretty stuff:
#+BEGIN_SRC emacs-lisp
(setq org-bullets-bullet-list '("โ˜ฏ" "โ˜ฐ" "โ˜ฑ" "โ˜ฒ" "โ˜ณ" "โ˜ด" "โ˜ต" "โ˜ถ" "โ˜ท"))
(setq org-ellipsis "โ†")
#+END_SRC
Make sure that Org doesn't try to clutter my home directory, and put stuff where
it's supposed to be:
#+BEGIN_SRC emacs-lisp
(setq org-directory "~/usr/doc/org/")
#+END_SRC
Set DOOM's scratch buffer, available at any point with =SPC x=, to Org, which I
find useful for taking quick notes:
#+BEGIN_SRC emacs-lisp
(setq doom-scratch-buffer-major-mode 'org-mode)
#+END_SRC
** PDF Tools
Not sure if I'll stick to this over Zathura, but it's nice to have everything in
Emacs. This is bundled with DOOM, so I just tell AucTeX to open stuff up in it.
#+BEGIN_SRC emacs-lisp
(setq TeX-view-program-selection '((output-pdf "PDF Tools")))
(add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer)
#+END_SRC
* Programming languages
The cool stuff. Unless it's Java.
** FRC Mode
This is a =gradlew= wrapper I hacked together really fast while sitting in my
physics class not paying attention. The officially sanctioned IDE for FIRST
Robotics is Visual Studio Code, which I hate with a burning passion for numerous
reasons.
We grab it directly from my Git, since it's not in ELPA (and probably never will
be):
#+BEGIN_SRC emacs-lisp :tangle ~/.config/doom/packages.el
(package! frc-mode
:recipe (:host nil :repo "https://git.qtp2t.club/hazel/frc-mode"))
#+END_SRC
And tell it to run with all Java files. I'd never willingly write Java outside
of FRC, so it's fine.
#+BEGIN_SRC emacs-lisp
(use-package! frc-mode
:hook (java-mode . frc-mode))
#+END_SRC
** =rust-analyzer=
Iunno, man. Sure. Why not. Racer and RLS keep giving me issues.
#+BEGIN_SRC emacs-lisp
(setq rustic-lsp-server 'rust-analyzer)
#+END_SRC
** vimrc mode
Hey. HEY. CHILL. The irony is not lost on me. This is actually for editing my
[[https://tridactyl.xyz][Tridactyl]] config.
#+BEGIN_SRC emacs-lisp
(define-generic-mode 'vimrc-generic-mode
'()
'()
'(("^[\t ]*:?\\(!\\|ab\\|map\\|unmap\\)[^\r\n\"]*\"[^\r\n\"]*\\(\"[^\r\n\"]*\"[^\r\n\"]*\\)*$"
(0 font-lock-warning-face))
("\\(^\\|[\t ]\\)\\(\".*\\)$")
(2 font-lock-comment-face)
("\"\\([^\n\r\"\\]\\|\\.\\)*\""
(0 font-lock-string-face)))
'("/vimrc\\'" "\\.vim\\(rc\\)?\\'")
'((lambda ()
(modify-syntax-entry ?\" ".")))
"Generic mode for Vim configuration files.")
#+END_SRC
** Shen
A really cool experimental, portable, and typed Lisp. I like it a lot, but I
don't know much about it on the merit that it's locked behind a paywall of a
book that I can't afford nor pirate.
#+BEGIN_SRC emacs-lisp :tangle ~/.config/doom/packages.el
(package! shen-mode)
#+END_SRC

93
config/doom/init.el

@ -0,0 +1,93 @@
;;; init.el -*- lexical-binding: t; -*-
;; ,;' `:. NOTE: THERE ARE TWO BFGS IN HELL
;; :: _ ;;
;; `:_|_;'
;; !
(doom! :completion
company
(ivy +icons +prescient)
:ui
doom
doom-dashboard
doom-quit
hl-todo
modeline
nav-flash
ophints
(popup +all +defaults)
(pretty-code +fira)
treemacs
vc-gutter
vi-tilde-fringe
window-select
workspaces
zen
:editor
(evil +everywhere)
file-templates
fold
multiple-cursors
parinfer
rotate-text
snippets
:emacs
(dired +icons +ranger)
electric
ibuffer
vc
:term
eshell
vterm
:checkers
syntax
spell ; ...is this annoying? yes! do i need it for editing latex papers?
; also yes!
:tools
debugger
direnv
(eval +overlay)
gist
(lookup +docsets)