commit
0f1a3535a4
70 changed files with 4356 additions and 0 deletions
@ -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/* |
@ -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. |
||||
|
||||
 |
@ -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/> |
@ -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 |
@ -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~" } |
@ -0,0 +1,2 @@
|
||||
--theme="ansi-dark" |
||||
--style="numbers,changes,header" |
@ -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 |
@ -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" |
@ -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 |
@ -0,0 +1,3 @@
|
||||
#!/bin/sh |
||||
|
||||
emacsclient -c --socket-name hazel-emacsd $@ |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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) |
||||