Compare commits

...
3 Commits
Author SHA1 Message Date
hektor be62f224a6 refactor(git-hooks): simplify git hooks
check / lint (push) Successful in 18s
2026-11-06 21:00:20 +01:00
hektor 9110789527 refactor: nixify / clean remaining dots scripts 2026-11-06 21:00:20 +01:00
hektor 9030f33842 refactor: nixify / clean dots config 2026-11-06 21:00:20 +01:00
87 changed files with 301 additions and 4979 deletions

No files matched your search

-1
View File
@@ -42,7 +42,6 @@ inputs.colmena.lib.makeHive (
specialArgs = { specialArgs = {
inherit inputs lib'; inherit inputs lib';
outputs = self; outputs = self;
dotsPath = ../dots;
}; };
}; };
} }
-26
View File
@@ -1,26 +0,0 @@
# Scripts
Mostly tiny helper scripts \& experiments, some more useful than others.
## Setup
Make sure the scripts are in your `$PATH` and executable.
To add the complete directory of scripts to your `$PATH`:
```bash
export PATH=~/.bin:$PATH
```
To make a any script `<script>` executable:
```bash
chmod +x <script>
```
## Notes
Statusbar scripts are prefixed with `sb` under the assumption you're using
`polybar` (scripts my need changes to be used with different statusbars).
Some scripts have dependencies (e.g. `fzf`, `jq`, `xclip`, ...), make sure you
have them installed.
-6
View File
@@ -1,6 +0,0 @@
#!/usr/bin/env bash
# Tiny AUR clone helper
# aurpac <package-name>
git clone "https://aur.archlinux.org/$1.git"
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
ipython -i /home/h/.bin/calc.py
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Open webcam window
ffplay -f v4l2 -x 640 -y 480 -i /dev/video0 >/dev/null 2>&1 & disown
-7
View File
@@ -1,7 +0,0 @@
#!/usr/bin/env node
const fs = require('fs')
const objLength = obj => Object.keys(obj).length
fs.readFile(process.argv[2], (err, data) => (err ? console.error(err) : console.log(objLength(JSON.parse(data)))))
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
xdg-open https://devdocs.io/offline
-10
View File
@@ -1,10 +0,0 @@
#!/usr/bin/env bash
options="Mouse\nHeadphones"
selected="$(echo -e "$options" | fzf)"
case "$selected" in
"Mouse") toggle-bt-device E4:19:21:56:C8:70;;
"Headphones") toggle-bt-device 38:18:4C:D4:74:42;;
esac
-2
View File
@@ -1,2 +0,0 @@
pactl load-module module-jack-source connect=0
pactl load-module module-loopback source=jack_in
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env python
import yaml, json, sys
print(yaml.dump(json.load(open(sys.argv[1])), allow_unicode=True), end='')
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
sudo pacman -Qtdq | sudo pacman -Rns -
-9
View File
@@ -1,9 +0,0 @@
#!/usr/bin/env bash
session="r5rs"
tmux attach-session -t "$session" || tmux new-session -s "$session" \; \
split-window -h -t $session \; \
send-keys -t 1 "nvim -c \"set ft=scheme\"" C-m \; \
send-keys -t 2 "plt-r5rs --no-prim" C-m \; \
select-pane -t 1
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
sed -i -r 's/\[*\]\(\.\/([A-z-]*.md)/\]\(\1/g' *.md
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env bash
# Backup existing password databases and
# database keys (using date in filename date -u
# +%Y-%m-%d_%H-%M-%S)
RCLONE_REMOTE="proton-drive"
for f in "$HOME/doc"/*.{kdbx,kdbx.key}; do
[ -e "$f" ] || continue
echo "Backing up $f to $f-$(date -u +%Y-%m-%d_%H-%M-%S)"
cp "$f" "$f-$(date -u +%Y-%m-%d_%H-%M-%S)"
done
echo "Restoring KeePassXC databases and database keys"
rclone copyto \
"$RCLONE_REMOTE:doc"/ "$HOME/doc/" \
--progress \
--include "/*.{kdbx,kdbx.key}"
-23
View File
@@ -1,23 +0,0 @@
#!/usr/bin/env bash
function start() {
adb start-server
nohup gnirehtet autorun &> /dev/null &
printf "Started reverse tethering \n"
}
function stop() {
adb kill-server
gnirehtet stop
pkill gnirehtet
printf "Stopped reverse tethering \n"
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
*) printf "start | stop | restart \n" >&2
exit 1
;;
esac
-75
View File
@@ -1,75 +0,0 @@
#!/usr/bin/env bash
# Save (encrypted) password database to cloud storage
#
# Usage:
# save-passwddb - Save databases to cloud
# save-passwddb init - Restore databases from cloud (with single backup archive)
RCLONE_REMOTE="proton"
SOURCE_DIR="$HOME/doc"
TARGET_DIR="$RCLONE_REMOTE:doc"
BACKUP_DIR="$HOME/doc/bak"
function save_databases() {
if [ 0 -lt "$(ls $SOURCE_DIR/*.kdbx 2>/dev/null | wc -w)" ]; then
echo "[save] Saving KeePassXC databases and database keys"
rclone copy "$SOURCE_DIR" "$TARGET_DIR" \
--include "/*.{kdbx,kdbx.key}" \
--progress
echo "[save] Done"
else
echo "[save] No password database found, restore with:"
echo ""
echo " $0 init"
exit 1
fi
}
function backup_existing() {
mkdir -p "$BACKUP_DIR"
local timestamp=$(date +%Y%m%d-%H%M%S)
local backup_file="$BACKUP_DIR/passwddb_backup_${timestamp}.tar.gz"
echo "[backup] Creating backup archive: ${backup_file}"
tar -czf "$backup_file" -C "$SOURCE_DIR" $(find "$SOURCE_DIR" -maxdepth 1 -type f \( -name "*.kdbx" -o -name "*.kdbx.key" \) -printf "%f ")
echo "[backup] Backup complete"
}
function restore_databases() {
echo "[init] Checking for existing files..."
local existing_files=$(find "$SOURCE_DIR" -maxdepth 1 -type f \( -name "*.kdbx" -o -name "*.kdbx.key" \) -print)
if [ -n "$existing_files" ]; then
echo "[init] Found existing database files:"
echo "$existing_files" | while read -r file; do
echo " - $file"
done
read -p "[init] Create backup archive of existing files? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
backup_existing
fi
fi
echo "[init] Restoring KeePassXC databases and database keys"
mkdir -p "$SOURCE_DIR"
rclone copy "$TARGET_DIR" "$SOURCE_DIR" \
--include "*.{kdbx,kdbx.key}" \
--progress
echo "[init] Done"
}
case "$1" in
""|save)
save_databases
;;
init)
restore_databases
;;
*)
echo "Usage: $0 [init|save]"
exit 1
;;
esac
-22
View File
@@ -1,22 +0,0 @@
#!/usr/bin/env bash
# Anki review percentage for statusbar
num_to_review=200
# Get current card count from Anki
count=$(curl -s 127.0.0.1:8765 -X POST -d '{"action": "getNumCardsReviewedToday", "version": 6}' | jq '.result')
if [ -z "$count" ]
then
if [ -s /tmp/anki-reviews ]; then
true
else
echo "-1" > /tmp/anki-reviews
fi
else
echo "$count" > /tmp/anki-reviews
fi
num_reviews=$(cat /tmp/anki-reviews)
echo -n -e " Reviews: $(python3 -c "print('{:.2%}'.format($num_reviews/$num_to_review))") "
-13
View File
@@ -1,13 +0,0 @@
#!/usr/bin/env bash
cap="$(cat /sys/class/power_supply/BAT0/capacity)"
if [ "$cap" -ge 33 ];then
color="\x01"
elif [ "$cap" -ge 10 ]; then
color="\x03"
else
color="\x04"
fi
echo -n -e "$color $cap% \x01"
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
echo -n -e "Week $(date '+%V') $(date '+%a %d %b %H:%M') "
-7
View File
@@ -1,7 +0,0 @@
#!/bin/sh
if grep -xq 'up' /sys/class/net/w*/operstate 2>/dev/null ; then
wifiicon="$(awk '/^\s*w/ { print "WiFi", int($3 * 100 / 70) "% " }' /proc/net/wireless)"
fi
printf " %s%s%s" "$wifiicon" "$(sed "s/down//;s/up/Ethernet/" /sys/class/net/e*/operstate 2>/dev/null)"
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
[ -f "/home/h/.local/share/pomo" ] && cat /home/h/.local/share/pomo || echo ""
-4
View File
@@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Render contents of $HOME/.project if present
[ -f "$HOME/.project" ] && cat "$HOME/.project" || echo ""
-7
View File
@@ -1,7 +0,0 @@
#!/usr/bin/env bash
num_done="$(task end.after:today status:completed count)"
num_pending="$(($(task count status:pending) + $num_done))"
num_waiting="$(($(task count status:waiting)))"
echo -e "Tasks: $num_done/$num_pending+$num_waiting"
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env sh
# Reference: https://github.com/mil-ad/polybar-wireguard
connected_interfaces=$(networkctl | grep -P "\d+ .* wireguard routable" -o | cut -d" " -f2)
if [ -n "$connected_interfaces" ];
then
for interface in $connected_interfaces; do echo "$interface"; done
else
exit 1
fi
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env bash
# Script to create script
if [ -z "$1" ]; then
echo "Usage: script <scriptname>"
exit
fi
path="$HOME/.bin/$1"
# Prevent overwriting existing script
set -o noclobber
# Create script
cat > "$path" << EOF
#!/usr/bin/env bash
EOF
chmod +x "$path"
# Open script in editor on line 3
"$EDITOR" +3 "$path"
-208
View File
@@ -1,208 +0,0 @@
#!/bin/bash
pac_list=(
at
automake
autopep8
base
base-devel
bash-completion
bash-language-server
bc
brightnessctl
chromium
dmidecode
entr
eslint_d
feh
firefox-developer-edition
firefox-tridactyl
firefox-tridactyl-native
firefox-tridactyl-native-debug
fzf
gcc
git
haskell-language-server
haskell-ormolu
hsetroot
htop
httpie
jq
keepassxc
kitty
lua-language-server
make
man-db
man-pages
neovim
nmap
nodejs-lts-jod
pacman-contrib
pandoc-cli
pandoc-crossref
parallel
pass
pkgbuild-language-server
pnpm
ripgrep
sshfs
stylelint
svelte-language-server
tailwindcss-language-server
task
tldr
tmux
tmuxp
tree
tree-sitter-cli
ts-node
typescript-language-server
unzip
vim-language-server
wget
xclip
yaml-language-server
)
aurpac_list=(
hadolint-bin
nvm
nvimpager
paru
tmux-bash-completion-git
ttf-iosevka-term-ss08
vim-plug
vtsls
xbanish
)
install() {
local package="$1"
if pacman -Qi "$package" &> /dev/null; then
echo "$package is already installed"
else
echo "Installing " "$package"
sudo pacman -S --noconfirm --needed "$package"
fi
}
aurpac() {
git clone "https://aur.archlinux.org/$1.git" "$HOME/.build/$1"
}
install_packages() {
announce "Installing packages"
local count
for pac in "${pac_list[@]}" ; do
count=$((count+1))
install "$pac";
done
echo "$count packages installed"
}
install_dotfiles() {
announce "Installing dotfiles"
origin="https://git.hektormisplon.xyz/hektor/dots"
git clone "$origin" "$HOME/dots"
cp -r "$HOME/dots/.git" "$HOME/.git"
git --git-dir="$HOME/.git" config --local status.showUntrackedFiles no
git --git-dir="$HOME/.git" stash -m "[dots]"
git --git-dir="$HOME/.git" stash apply
git --git-dir="$HOME/.git" restore "$HOME"
}
install_aur_packages() {
announce "Installing AUR packages"
local count
for package in "${aurpac_list[@]}" ; do
if pacman -Qi "$1" &> /dev/null; then
echo "$1 is already installed"
else
count=$((count+1))
aurpac "$package" && makepkg -si -D "$HOME/.build/$package"
fi
done
echo "$count AUR packages installed"
}
setup_neovim() {
announce "Setting up NeoVim"
git clone --depth=1 https://github.com/savq/paq-nvim.git \
"${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/pack/paqs/start/paq-nvim
}
setup_keyboard() {
announce "Setting up keyboard"
install "interception-tools"
install "interception-caps2esc"
udevmon_config_contents="\
- JOB: intercept -g \$DEVNODE | caps2esc -m 1 | uinput -d \$DEVNODE
DEVICE:
EVENTS:
EV_KEY: [KEY_CAPSLOCK]"
if [ -f /etc/interception/udevmon.yaml ] && diff -q <(echo "$udevmon_config_contents") /etc/interception/udevmon.yaml; then
echo "udevmon config already exists"
echo "$udevmon_config_contents"
elif [ -f /etc/interception/udevmon.yaml ]; then
echo "interception udevmon.yaml already exists"
cat /etc/interception/udevmon.yaml
echo "verify if this config matches the one below"
echo "$udevmon_config_contents"
else
echo "interception udevmon.yaml does not exist, creating one"
sudo bash -c "echo '$udevmon_config_contents' > /etc/interception/udevmon.yaml"
fi
sudo systemctl enable --now udevmon.service
if pgrep -x caps2esc > /dev/null; then
echo "caps2esc is already running"
else
caps2esc -m 1
fi
}
configure_gnome() {
announce "Configuring Gnome"; setup-gnome
}
setup_firewall() {
announce "Configuring firewalld"
install firewalld
sudo systemctl enable --now firewalld
}
setup_docker() {
announce "Setting up Docker"
install docker
install docker-compose
sudo systemctl enable --now docker.socket
sudo usermod -aG docker "$USER"
echo "User added to docker group, please restart your session"
}
announce() {
local message="$1"
echo " "
echo "[dots] $message"
echo " "
}
confirm() {
local question="$1"
read -r -p "[dots] $question? [y/N]" -n 1
case "$REPLY" in y|Y ) "$2";; * ) echo "Skipping"; esac
}
printf '%s\n' "${pac_list[@]}"
confirm "Install these packages? " install_packages
printf '%s\n' "${aurpac_list[@]}"
confirm "Install these AUR packages? " install_aur_packages
confirm "Setup NeoVim? " setup_neovim
confirm "Install dotfiles? " install_dotfiles
confirm "Setup keyboard? " setup_keyboard
if pacman -Qi "gdm" &> /dev/null; then
confirm "Configure Gnome? " configure_gnome
fi
confirm "Setup firewall? " setup_firewall
confirm "Setup Docker? " setup_docker
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
ssh_hosts="$(grep -E 'Host [a-z0-9\-]*$' ~/.ssh/config | awk '{print $2}')"
echo "$ssh_hosts"
-26
View File
@@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -euf -o pipefail
VIM=${VIM:-"vim"}
TMUX=${TMUX:-"tmux"}
FILE=${FILE:-"$(date +%F).tidal"}
SESSION=${SESSION:-"tidal"}
TIDAL_BOOT_PATH=${TIDAL_BOOT_PATH:-""}
GHCI=${GHCI:-""}
args=${*:-$FILE}
# attach if session else create
$TMUX attach-session -t "$SESSION" || $TMUX new-session -s "$SESSION" \; \
split-window -h -t "$SESSION" \; \
send-keys -t 0 "$VIM $args" C-m \; \
send-keys -t 1 "TIDAL_BOOT_PATH=$TIDAL_BOOT_PATH GHCI=$GHCI tidal" C-m \; \
new-window -t "$SESSION":2 -n SuperDirt \; \
send-keys -t 0 "jack_control start && sclang ~/dev/live/scripts/start.scd" C-m \; \
select-window -t 1 \; \
resize-pane -t 1 -x 100 \; \
resize-pane -t 0 -x 125 \; \
select-pane -t 0
-13
View File
@@ -1,13 +0,0 @@
#!/usr/bin/env bash
session="main"
tmux attach-session -t $session || tmux new-session -s $session \; \
rename-window task \; \
send-keys -t 1 "task" C-m \; \
new-window -n zk \; \
send-keys -t 2 "nvim $ZK_PATH/index.md" C-m \; \
new-window -n term \; \
new-window -n music \; \
send-keys -t 4 "echo 'TODO: open music player'" C-m \; \
select-window -t 1 \;
-11
View File
@@ -1,11 +0,0 @@
#!/usr/bin/env bash
status="$(bluetoothctl info "$1" | grep Connected | cut -f 2 -d ':' | cut -f 2 -d ' ')"
if [ "$status" == "yes" ]
then
bluetoothctl disconnect "$1"
else
trust "$1"
bluetoothctl connect "$1"
fi
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
sudo pacman -Syu
-1
View File
@@ -1 +0,0 @@
[{ "key": "ctrl+b", "command": "workbench.action.toggleSidebarVisibility" }]
-114
View File
@@ -1,114 +0,0 @@
{
/* view */
"workbench.statusBar.visible": true,
"workbench.activityBar.visible": false,
"breadcrumbs.enabled": false,
"editor.minimap.enabled": false,
"window.menuBarVisibility": "hidden",
"workbench.editor.showTabs": false,
"workbench.editor.showIcons": false,
/* font */
"editor.fontSize": 20,
"editor.fontLigatures": true,
"editor.fontFamily": "Iosevka",
"terminal.integrated.fontSize": 20,
/* editor */
"editor.lineNumbers": "relative",
"editor.glyphMargin": false,
"terminal.integrated.allowMnemonics": false,
"workbench.colorCustomizations": {
"editorGroup.emptyBackground": "#0c0c0c",
"scrollbar.shadow": "#000",
"widget.shadow": "#000",
"editorWidget.background": "#0c0c0c",
"editor.background": "#0c0c0c",
"sideBar.background": "#0c0c0c",
"editorGroupHeader.noTabsBackground": "#0c0c0c",
"scrollbarSlider.background": "#222",
"scrollbarSlider.activeBackground": "#222",
"scrollbarSlider.hoverBackground": "#333",
"statusBar.noFolderBackground": "#0c0c0c",
"statusBar.border": "#0c0c0c",
"statusBar.background": "#0c0c0c",
"statusBar.foreground": "#555"
},
"editor.tokenColorCustomizations": {
"comments": "#555",
"functions": "#aaa",
"numbers": "#fff",
"strings": "#fff",
"types": "#aaa",
"variables": "#aaa",
"keywords": "#aaa"
},
/* vim keybindings */
"vim.incsearch": true,
"vim.hlsearch": true,
"vim.leader": "<space>",
"vim.normalModeKeyBindingsNonRecursive": [
/* quick quit */
{
"before": ["<leader>", "q"],
"commands": [":q"]
},
{
"before": ["<leader>", "w"],
"commands": [":w"]
},
{
"before": ["<leader>", "Q"],
"commands": [":q!"]
},
{
"before": ["<leader>", "W"],
"commands": [":w!"]
},
/* split */
{
"before": ["<leader>", "s", "s"],
"commands": [":sp"]
},
{
"before": ["<leader>", "s", "v"],
"commands": [":vs"]
},
/* clear search highlight */
{
"before": ["<leader>", "<leader>"],
"commands": [":nohl"]
}
],
"vim.insertModeKeyBindings": [
/* quick exit insert */
{
"before": ["j", "j"],
"after": ["<Esc>"]
}
],
"vim.handleKeys": {
"<C-a>": false,
"<C-f>": false
},
/* eslint & prettier */
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"workbench.colorTheme": "Absolute Black",
"window.zoomLevel": 1,
"javascript.updateImportsOnFileMove.enabled": "always"
}
-12
View File
@@ -1,12 +0,0 @@
prev_img h
next_img l
scroll_left L
scroll_right H
scroll_up J
scroll_down K
zoom_in j
zoom_out k
zoom_fit z
zoom_default =
mirror bar
close q Q
-3
View File
@@ -1,3 +0,0 @@
feh \
-B black \
--auto-zoom
-36
View File
@@ -1,36 +0,0 @@
[General]
checkForUpdates=false
disabledTrayIcon=true
uiColor=#cccccc
fontFamily=Inter
drawColor=#ffffff
savePath=/home/h/doc/clips
copyPathAfterSave=true
saveLastRegion=true
saveAsFileExtension=png
userColors=picker, #800000, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ffffff, #000000
[Shortcuts]
TYPE_ARROW=a
TYPE_CIRCLE=o
TYPE_CIRCLECOUNT=Shift+o
TYPE_COMMIT_CURRENT_TOOL=Ctrl+Return
TYPE_COPY=y
TYPE_DELETE_CURRENT_TOOL=
TYPE_DRAWER=l
TYPE_EXIT=q
TYPE_IMAGEUPLOADER=
TYPE_MARKER=m
TYPE_MOVESELECTION=Ctrl+M
TYPE_MOVE_DOWN=j
TYPE_MOVE_LEFT=h
TYPE_MOVE_RIGHT=l
TYPE_MOVE_UP=k
TYPE_OPEN_APP=o
TYPE_PENCIL=d
TYPE_PIN=Enter
TYPE_PIXELATE=p
TYPE_RECTANGLE=r
TYPE_REDO=Ctrl+r
TYPE_RESIZE_DOWN=Shift+j
TYPE_RESIZE_LEFT=Shift+h
-16
View File
@@ -1,16 +0,0 @@
git_protocol: ssh
prompt: enabled
aliases:
co: pr checkout
c: repo clone
f: repo fork
rc: repo create
rv: repo view
re: repo edit
rm: repo remove
rn: repo rename
lr: repo list
li: issue list
al: alias
al-: alias delete
version: "1"
-5
View File
@@ -1,5 +0,0 @@
[Settings]
gtk-font-name=Inter 12
gtk-application-prefer-dark-theme=true
gtk-icon-theme-name=Adwaita
gtk-theme-name=Adwaita
File diff suppressed because it is too large. Load diff
-32
View File
@@ -1,32 +0,0 @@
[General]
ConfigVersion=2
[Browser]
CustomProxyLocation=
Enabled=true
[GUI]
ApplicationTheme=dark
CompactMode=false
HidePreviewPanel=false
HideToolbar=false
MinimizeOnClose=true
MinimizeToTray=true
ShowTrayIcon=true
TrayIconAppearance=colorful
[KeeShare]
Active="<?xml version=\"1.0\"?><KeeShare><Active/></KeeShare>\n"
Foreign="<?xml version=\"1.0\"?>\n<KeeShare xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n <Foreign/>\n</KeeShare>\n"
Own="<?xml version=\"1.0\"?><KeeShare><PrivateKey>MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9Ji74dnjo0qzbUFKEoNnMHsdX7mBXuJcu8zsl7vfkKLiAGIQiP9BQc/JnFr28W92fQz8uXVtm7NgnKJQkT7wzFyBdspmNDzosS58EIQVKe5p+uMaaGZ5z6j1DtLCFo7PLCnhasBluC0W1+37s7NtRD6bFo1r6QHupY63mBsSvJhAcmS+6bM7xS7PcK0WTVTsK1MWYZLOkYMWQ0AW/t4PZfqeKvalqheiR8oUIDeY7+7fqvQr5SAhL0yinbtaqWmPqcd5QWyPqVkbKclw4Uecw+JW+yR9uEOP9butP74r36LUUfsTJHE2/sB2KJFRN/aUm2ZEYhzexMYSfgnrq0KCLAgMBAAECggEACV8N7rN39BkUBV2qaPXLNKjFuZ6O2WnE28ejQ5LeZ0h5M6eDTGsa+BF2jhL7XYyzo0NiqvpnH+dWIkKJbG8i5OkdamcB4pJBkJZCj6LPL0yGcAbZmCLyzc1qMaOPJ1/f9YxUQDH/YItgbc7DEBwAFbkPyzT3ufRd7BuLLx1gu0iypHhBok9kXA4WgkUihLNXXVvSIGcVy+q9wpgOiw5jLC79qwqIp39Tlt6PKryODulqWIeoeSIgAu5tgUy4O3He6AZwqBprIfJSiJOwfdBd8FchQJQDgl0fyDR10VIUNbjgm+kxWssq4oNJ7+2n14Gdfwpy2K7oO9DYeqjBrv2p4QKBgQDqY8/5ufsJ9hKhQRX3vju+FEDLKvjjKH7/6puDwcvC1GgvshQSvCo9ZVIajwSmEoWq2LTDiPlUPFINKnALQiHCbRfNeS1Tws4cK4AAZnR+CGKkox9J5MWCDVzI2/82R9/9ZX4OO+As5+Od503Grmy+Zi0Redm+r4aK04gm3LfqGwKBgQDOlpOXFyYbb473TFkf9ZfyETZGkjlCzf4uPwPuJ3njWZfwPE2Gb+quZDLSmYp9JhzIFoapnQrjSFCVyzBYIIuz3jipb5MbQxc6FPSjw0pPowWdPkEL1CT5mpZFojop+I/TnEEG+Lv039O3cGlL2zagiBHRw0ediD6z0vnoOBeKUQKBgQDjlJBuKC9gp6XFHp4G05XMZHvZCNtqLHrLX28qSjPe80BJ9z1YR4032bYThYP9AAT7MripFskICh2dHPR3afm/fw9aeWsSZhab8XyyZsh7SwcEVkJeDBvdv720ZS9y8+y/bBkuFuL+lxVBz0GMRPXfFPRzgH10kZcwGl2bZjnIuwKBgQCVabQu95AZEbM9yps/ERom+ineGo2Ncnyep/bIvQZb1wWbu5F6ZOE/5boYNPJDl1gDor8cVzdzsG6QGBfL9SX1HgivCsJDWl+nI1bYRjsto8NAubDDxFhFqnd6v1z/1AT50C37w9P0xBlUt9mAAnjc2+y/YFQgbFSlLDaQrFjiMQKBgFJrLF21Uk6ALZa4R0eOyLKhuagw3uxmNvccNG8VL5DwYVCUS7/8SkPhO5yvbcA87Y1VnM20tUr047K4U83uFNxBnPMmxlhMsxtqjw+VV6Us6uh2ASaLZ9iP9iwkn5e37WLWX+XsewoGrW/YsONwIT0dnZDPRbxhPdJn8azSJqQr</PrivateKey><PublicKey><Signer>h</Signer><Key>MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9Ji74dnjo0qzbUFKEoNnMHsdX7mBXuJcu8zsl7vfkKLiAGIQiP9BQc/JnFr28W92fQz8uXVtm7NgnKJQkT7wzFyBdspmNDzosS58EIQVKe5p+uMaaGZ5z6j1DtLCFo7PLCnhasBluC0W1+37s7NtRD6bFo1r6QHupY63mBsSvJhAcmS+6bM7xS7PcK0WTVTsK1MWYZLOkYMWQ0AW/t4PZfqeKvalqheiR8oUIDeY7+7fqvQr5SAhL0yinbtaqWmPqcd5QWyPqVkbKclw4Uecw+JW+yR9uEOP9butP74r36LUUfsTJHE2/sB2KJFRN/aUm2ZEYhzexMYSfgnrq0KCLAgMBAAECggEACV8N7rN39BkUBV2qaPXLNKjFuZ6O2WnE28ejQ5LeZ0h5M6eDTGsa+BF2jhL7XYyzo0NiqvpnH+dWIkKJbG8i5OkdamcB4pJBkJZCj6LPL0yGcAbZmCLyzc1qMaOPJ1/f9YxUQDH/YItgbc7DEBwAFbkPyzT3ufRd7BuLLx1gu0iypHhBok9kXA4WgkUihLNXXVvSIGcVy+q9wpgOiw5jLC79qwqIp39Tlt6PKryODulqWIeoeSIgAu5tgUy4O3He6AZwqBprIfJSiJOwfdBd8FchQJQDgl0fyDR10VIUNbjgm+kxWssq4oNJ7+2n14Gdfwpy2K7oO9DYeqjBrv2p4QKBgQDqY8/5ufsJ9hKhQRX3vju+FEDLKvjjKH7/6puDwcvC1GgvshQSvCo9ZVIajwSmEoWq2LTDiPlUPFINKnALQiHCbRfNeS1Tws4cK4AAZnR+CGKkox9J5MWCDVzI2/82R9/9ZX4OO+As5+Od503Grmy+Zi0Redm+r4aK04gm3LfqGwKBgQDOlpOXFyYbb473TFkf9ZfyETZGkjlCzf4uPwPuJ3njWZfwPE2Gb+quZDLSmYp9JhzIFoapnQrjSFCVyzBYIIuz3jipb5MbQxc6FPSjw0pPowWdPkEL1CT5mpZFojop+I/TnEEG+Lv039O3cGlL2zagiBHRw0ediD6z0vnoOBeKUQKBgQDjlJBuKC9gp6XFHp4G05XMZHvZCNtqLHrLX28qSjPe80BJ9z1YR4032bYThYP9AAT7MripFskICh2dHPR3afm/fw9aeWsSZhab8XyyZsh7SwcEVkJeDBvdv720ZS9y8+y/bBkuFuL+lxVBz0GMRPXfFPRzgH10kZcwGl2bZjnIuwKBgQCVabQu95AZEbM9yps/ERom+ineGo2Ncnyep/bIvQZb1wWbu5F6ZOE/5boYNPJDl1gDor8cVzdzsG6QGBfL9SX1HgivCsJDWl+nI1bYRjsto8NAubDDxFhFqnd6v1z/1AT50C37w9P0xBlUt9mAAnjc2+y/YFQgbFSlLDaQrFjiMQKBgFJrLF21Uk6ALZa4R0eOyLKhuagw3uxmNvccNG8VL5DwYVCUS7/8SkPhO5yvbcA87Y1VnM20tUr047K4U83uFNxBnPMmxlhMsxtqjw+VV6Us6uh2ASaLZ9iP9iwkn5e37WLWX+XsewoGrW/YsONwIT0dnZDPRbxhPdJn8azSJqQr</Key></PublicKey></KeeShare>\n"
QuietSuccess=true
[PasswordGenerator]
AdditionalChars=
ExcludedChars=
Length=40
Logograms=true
WordCount=9
[SSHAgent]
Enabled=true
-20
View File
@@ -1,20 +0,0 @@
[Default Applications]
inode/x-empty=nvim.desktop
inode/directory=nvim.desktop
text/plain=nvim.desktop
text/html=firefoxdeveloperedition.desktop
image/gif=feh.desktop
image/jpeg=feh.desktop
image/png=feh.desktop
video/mp4=mpv.desktop
video/webm=mpv.desktop
model/stl=com.ultimaker.cura.desktop
application/pdf=org.pwmt.zathura.desktop
x-scheme-handler/msteams=teams-for-linux.desktop
x-scheme-handler/web+stremio=firefox.desktop
x-scheme-handler/http=firefoxdeveloperedition.desktop
x-scheme-handler/https=firefoxdeveloperedition.desktop
x-scheme-handler/chrome=firefoxdeveloperedition.desktop
x-scheme-handler/sidequest=SideQuest.desktop
x-scheme-handler/mailto=firefox.desktop
x-scheme-handler/webcal=firefox.desktop
Binary file not shown.
-15
View File
@@ -1,15 +0,0 @@
l seek +5
h seek -5
k seek +30
j seek -30
+ add video-zoom 0.1
- add video-zoom -0.1
= set video-zoom 0; set video-pan-x 0; set video-pan-y 0
H add video-pan-x 0.01
L add video-pan-x -0.01
K add video-pan-y 0.01
J add video-pan-y -0.01
m cycle mute
-16
View File
@@ -1,16 +0,0 @@
vo=gpu
profile=gpu-hq
hwdec=auto
msg-color=yes
cursor-autohide=300
cursor-autohide-fs-only=yes
save-position-on-quit=yes
keep-open=yes
# Custom osc
osc=no
cursor-autohide=3500
osd-bar=no
osc-vidscale=no
File diff suppressed because it is too large. Load diff
-60
View File
@@ -1,60 +0,0 @@
context.properties = {}
context.spa-libs = {
audio.convert.* = audioconvert/libspa-audioconvert
support.* = support/libspa-support
}
context.modules = [
{ name = libpipewire-module-rt
args = { nice.level = -11 }
flags = [ ifexists nofail ]
}
{ name = libpipewire-module-protocol-native }
{ name = libpipewire-module-client-node }
{ name = libpipewire-module-adapter }
{ name = libpipewire-module-metadata }
{ name = libpipewire-module-protocol-pulse
args = { }
}
]
context.exec = [
{ path = "pactl" args = "load-module module-always-sink" }
# Automatically switch to (bluetooth) headphones
{ path = "pactl" args = "load-module module-switch-on-connect" }
]
stream.properties = { }
pulse.properties = {
server.address = [ "unix:native" ]
vm.overrides = { pulse.min.quantum = 1024/48000 }
}
pulse.rules = [
{
matches = [ { } ]
actions = { update-props = { } }
}
{
matches = [
{ application.process.binary = "teams" }
{ application.process.binary = "teams-insiders" }
{ application.process.binary = "skypeforlinux" }
]
actions = { quirks = [ force-s16-info ] }
}
{
matches = [ { application.process.binary = "firefox" } ]
actions = { quirks = [ remove-capture-dont-move ] }
}
{
matches = [ { application.name = "~speech-dispatcher*" } ]
actions = {
update-props = {
pulse.min.req = 1024/48000 # 21ms
pulse.min.quantum = 1024/48000 # 21ms
}
}
}
]
-11
View File
@@ -1,11 +0,0 @@
[google-drive]
type = drive
scope = drive
token =
[onedrive-vub]
type = webdav
url =
vendor = sharepoint
user =
pass =
-71
View File
@@ -1,71 +0,0 @@
{
"101B:E2D1E989": {
"_name": "Marathon Mouse M705 (M-R0009)",
"side-scroll": true,
"smooth-scroll": true
},
"405E:C347528E": {
"_absent": [
"hi-res-scroll",
"lowres-smooth-scroll",
"smart-shift",
"thumb-scroll-mode",
"thumb-scroll-invert",
"onboard_profiles",
"report_rate",
"dpi",
"dpi-sliding",
"speed-change",
"backlight",
"backlight-timed",
"fn-swap",
"disable-keyboard-keys",
"divert-crown",
"crown-smooth",
"divert-gkeys",
"m-key-leds",
"mr-key-led",
"multiplatform",
"gesture2-gestures",
"gesture2-divert",
"gesture2-params"
],
"_modelId": "B015405E0000",
"_name": "M720 Triathlon Multi-Device Mouse",
"_sensitive": {
"change-host": true,
"divert-keys": true,
"hires-smooth-invert": false,
"hires-smooth-resolution": false,
"mouse-gestures": false,
"pointer_speed": false,
"reprogrammable-keys": true
},
"_serial": "C347528E",
"_unitId": "F204EB17",
"divert-keys": {
"208": 0,
"215": 0,
"82": 0,
"83": 0,
"86": 0,
"91": 0,
"93": 0
},
"hires-smooth-invert": false,
"hires-smooth-resolution": false,
"mouse-gestures": 0,
"pointer_speed": 195,
"reprogrammable-keys": {
"208": 208,
"80": 80,
"81": 81,
"82": 82,
"83": 83,
"86": 86,
"91": 91,
"93": 93
}
},
"_version": "1.1.2"
}
-4
View File
@@ -1,4 +0,0 @@
# Spotify cache size
The contents of `prefs.example` can be added to the `prefs` file in this
directory to change the cache size to 1GB.
-1
View File
@@ -1 +0,0 @@
storage.size=1024
@@ -1,11 +0,0 @@
[Unit]
Description=Save KeypassXC password database to cloud
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/home/h/.bin/save-passwddb
[Install]
WantedBy=multi-user.target
@@ -1,10 +0,0 @@
[Unit]
Description=Save Keepass password database to cloud daily
[Timer]
OnCalendar=daily
RandomizedDelaySec=12h
Persistent=true
[Install]
WantedBy=timers.target
-1
View File
@@ -1 +0,0 @@
enabled=False
-15
View File
@@ -1,15 +0,0 @@
# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run.
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/"
XDG_DOWNLOAD_DIR="$HOME/dl"
XDG_DOCUMENTS_DIR="$HOME/doc"
XDG_PUBLICSHARE_DIR="$HOME/"
XDG_MUSIC_DIR="$HOME/"
XDG_PICTURES_DIR="$HOME/"
XDG_TEMPLATES_DIR="$HOME/"
XDG_VIDEOS_DIR="$HOME/"
-6
View File
@@ -1,6 +0,0 @@
---
extends: default
rules:
document-start: disable
comments-indentation: disable
-13
View File
@@ -1,13 +0,0 @@
# My dotfiles
To get started, run the following:
```
bash <(curl -s https://git.hektormisplon.xyz/hektor/dots/raw/branch/master/.bin/setup)
```
Note: will not set up *everything* (e.g. `/etc` configs, dependencies...), but
should get you up and running.
2025-10-04: I am migrating from Arch Linux to NixOS. For this transition, these
dotfiles are currently included as a subtree in my [NixOS repository](https://git.hektormisplon.xyz/hektor/nix).
+16 -21
View File
@@ -9,6 +9,9 @@ let
pre-commit-check = git-hooks.lib.${system}.run { pre-commit-check = git-hooks.lib.${system}.run {
inherit src; inherit src;
default_stages = [ "pre-commit" ];
hooks = { hooks = {
nixfmt = { nixfmt = {
enable = true; enable = true;
@@ -16,32 +19,24 @@ let
}; };
statix.enable = true; statix.enable = true;
deadnix.enable = true; deadnix.enable = true;
flake-check = {
enable = true;
entry = "${pkgs.lib.getExe pkgs.nix} flake check";
stages = [ "pre-push" ];
pass_filenames = false;
always_run = true;
};
}; };
}; };
in in
{ {
checks = { checks.pre-commit-check = pre-commit-check;
inherit pre-commit-check;
};
formatter = formatter = pkgs.nixfmt-tree;
let
inherit (pre-commit-check) config;
inherit (config) package configFile;
script = ''
${pkgs.lib.getExe package} run --all-files --config ${configFile}
'';
in
pkgs.writeShellScriptBin "pre-commit-run" script;
devShells = { devShells.default = pkgs.mkShell {
default = inherit (pre-commit-check) shellHook;
let packages = pre-commit-check.enabledPackages;
inherit (pre-commit-check) shellHook enabledPackages;
in
pkgs.mkShell {
inherit shellHook;
buildInputs = enabledPackages;
};
}; };
} }
+2 -1
View File
@@ -24,6 +24,7 @@
}; };
anki.enable = true; anki.enable = true;
audio.enable = true; audio.enable = true;
bin.enable = true;
browser.primary = "librewolf"; browser.primary = "librewolf";
cloud.hetzner.enable = true; cloud.hetzner.enable = true;
comms.signal.enable = true; comms.signal.enable = true;
@@ -45,6 +46,7 @@
}; };
keyboard.vortexCore.enable = true; keyboard.vortexCore.enable = true;
keepassxc.enable = true; keepassxc.enable = true;
mpv.enable = true;
music.enable = true; music.enable = true;
newsboat.enable = true; newsboat.enable = true;
nvim.enable = true; nvim.enable = true;
@@ -56,7 +58,6 @@
shell = { shell = {
enable = true; enable = true;
bash.aliases.lang-js = true; bash.aliases.lang-js = true;
bash.addBinToPath = true;
}; };
ssh.enable = true; ssh.enable = true;
taskwarrior.enable = true; taskwarrior.enable = true;
+2 -1
View File
@@ -23,6 +23,7 @@
anki.enable = true; anki.enable = true;
archiving.enable = true; archiving.enable = true;
audio.enable = true; audio.enable = true;
bin.enable = true;
browser.enable = true; browser.enable = true;
browser.primary = "librewolf"; browser.primary = "librewolf";
cloud.hetzner.enable = true; cloud.hetzner.enable = true;
@@ -38,6 +39,7 @@
}; };
k8s.k9s.enable = true; k8s.k9s.enable = true;
keepassxc.enable = true; keepassxc.enable = true;
mpv.enable = true;
music.enable = true; music.enable = true;
newsboat.enable = true; newsboat.enable = true;
my.xdg.enable = true; my.xdg.enable = true;
@@ -49,7 +51,6 @@
shell = { shell = {
enable = true; enable = true;
bash.aliases.lang-js = true; bash.aliases.lang-js = true;
bash.addBinToPath = true;
}; };
ssh.enable = true; ssh.enable = true;
deploy.enable = true; deploy.enable = true;
+4
View File
@@ -11,6 +11,10 @@ let
in in
{ {
options.anki.enable = lib.mkEnableOption "Anki"; options.anki.enable = lib.mkEnableOption "Anki";
options.anki.reviewsCache = lib.mkOption {
default = "/tmp/anki-reviews";
type = lib.types.str;
};
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
secrets.files.anki = [ secrets.files.anki = [
+87
View File
@@ -0,0 +1,87 @@
{
config,
lib,
pkgs,
...
}:
let
script =
name: args:
pkgs.writeShellApplication (
{
inherit name;
text = builtins.readFile ./scripts/${name};
}
// args
);
pythonScript =
name: runtimeInputs:
pkgs.writeShellApplication {
inherit name runtimeInputs;
text = ''exec ${lib.getExe pkgs.python3} ${pkgs.writeTextDir name (builtins.readFile ./scripts/${name})}/${name} "$@"'';
};
ssh-hosts = script "ssh-hosts" {
runtimeInputs = with pkgs; [
gnugrep
gawk
];
};
scripts = with pkgs; {
bak.runtimeInputs = [ coreutils ];
notify.runtimeInputs = [ libnotify ];
pdftitle.runtimeInputs = [
poppler-utils
gawk
coreutils
];
fzf-book.runtimeInputs = [
findutils
fzf
coreutils
];
fzf-ssh.runtimeInputs = [
ssh-hosts
fzf
];
save-ssh-host = {
runtimeInputs = [
ssh-hosts
fzf
];
excludeShellChecks = [ "SC2029" ];
};
fzf-fontnames.runtimeInputs = [
fontconfig
fzf
gawk
coreutils
];
get-anki-decks.runtimeInputs = [
curl
jq
];
get-anki-reviews-status = {
runtimeInputs = [ coreutils ];
runtimeEnv.ANKI_REVIEWS = config.anki.reviewsCache;
};
};
pythonScripts = with pkgs; {
pomo = [ libnotify ];
taskdeps = [ ];
};
in
{
options.bin.enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
config = lib.mkIf config.bin.enable {
home.packages = [
ssh-hosts
]
++ lib.mapAttrsToList script scripts
++ lib.mapAttrsToList pythonScript pythonScripts;
};
}
@@ -1,5 +1,3 @@
#!/usr/bin/env bash
# back up a file by copying it to a new file with a .bak extension # back up a file by copying it to a new file with a .bak extension
# reference: https://askubuntu.com/questions/962489/is-there-any-way-to-create-backup-copy-of-a-file-without-type-its-name-twice # reference: https://askubuntu.com/questions/962489/is-there-any-way-to-create-backup-copy-of-a-file-without-type-its-name-twice
@@ -1,10 +1,8 @@
#!/usr/bin/env bash
# Generate menu of book filenames and save paths # Generate menu of book filenames and save paths
# Preview window contains metadata # Preview window contains metadata
function get_book_paths { function get_book_paths {
find /home/h/doc/books/ -regex '.*\.\(pdf\|epub\|djvu\)' -type f | sort find "$HOME/doc/books/" -regex '.*\.\(pdf\|epub\|djvu\)' -type f | sort
} }
function select_file { function select_file {
@@ -21,10 +19,8 @@ function open {
fi fi
} }
case "$1" in case "${1:-}" in
--open) open "$(select_file)" ;; --open) open "$(select_file)" ;;
--help) printf "open \n" >&2 ;; --help) printf "open \n" >&2 ;;
*) open "$(select_file)" ;; *) open "$(select_file)" ;;
esac esac
[[ -n "$selected" ]] && xdg-open "$selected" &> /dev/null & disown
@@ -1,5 +1,3 @@
#!/usr/bin/env bash
fn="/tmp/fontnames.txt" fn="/tmp/fontnames.txt"
contains_dash() { contains_dash() {
@@ -7,16 +5,16 @@ contains_dash() {
} }
update() { update() {
echo "" > "$fn" : > "$fn"
font_list=$(fc-list -f "%{fullname}\n") font_list=$(fc-list -f "%{fullname}\n")
echo "$font_list" | while read line ; do echo "$font_list" | while read -r line ; do
first="$(echo "$line" | cut -d',' -f1)" first="$(echo "$line" | cut -d',' -f1)"
last="$(echo "$line" | cut -d',' -f2)" last="$(echo "$line" | cut -d',' -f2)"
if $(contains_dash "$first"); then if contains_dash "$first"; then
echo "$last" >> "$fn" echo "$last" >> "$fn"
else else
echo "$first" >> "$fn" echo "$first" >> "$fn"
@@ -24,7 +22,7 @@ update() {
done done
} }
case "$1" in case "${1:-}" in
--update) update;; --update) update;;
*) cat "$fn" | sort | uniq | awk 'NF' | fzf;; *) sort -u "$fn" | awk 'NF' | fzf;;
esac esac
@@ -1,3 +1 @@
#!/usr/bin/env bash
ssh "$(ssh-hosts | fzf)" ssh "$(ssh-hosts | fzf)"
@@ -1,3 +1 @@
#!/usr/bin/env bash
curl 127.0.0.1:8765 -X POST -d '{"action": "deckNames", "version": 6}' | jq '.result[]' -r curl 127.0.0.1:8765 -X POST -d '{"action": "deckNames", "version": 6}' | jq '.result[]' -r
@@ -1,8 +1,6 @@
#!/usr/bin/env bash
# Get Anki review status from exit code # Get Anki review status from exit code
num_reviews="$(cat /tmp/anki-reviews)" num_reviews="$(cat "$ANKI_REVIEWS")"
if [ "$num_reviews" -ge "400" ] if [ "$num_reviews" -ge "400" ]
then then
@@ -1,8 +1,6 @@
#!/usr/bin/env bash
# Pipe into notify-send # Pipe into notify-send
# #
# e.g. `echo "Hello world" | notify` # e.g. `echo "Hello world" | notify`
read -r msg read -r msg || true
notify-send "$msg" "$@" notify-send "$msg" "$@"
@@ -1,3 +1 @@
#!/usr/bin/env bash
pdfinfo "$1" | head -n 1 | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}' pdfinfo "$1" | head -n 1 | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'
@@ -10,11 +10,11 @@ Pomodoro timer
import atexit import atexit
import os import os
import signal
import subprocess
from argparse import ArgumentParser from argparse import ArgumentParser
from time import sleep from time import sleep
from plyer import notification
POMO_PATH = os.path.join( POMO_PATH = os.path.join(
os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share")), "pomo" os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share")), "pomo"
) )
@@ -30,34 +30,28 @@ def format_mins_secs(mins, secs):
return f"{mins:02d}:{secs:02d}" return f"{mins:02d}:{secs:02d}"
def make_countdown():
def countdown(duration): def countdown(duration):
while duration != 0: while duration != 0:
mins = duration // 60 mins = duration // 60
secs = duration % 60 secs = duration % 60
time_str = format_mins_secs(mins, secs) with open(POMO_PATH, "w") as f:
os.system(f'echo -n "{time_str}" > {POMO_PATH}') f.write(format_mins_secs(mins, secs))
sleep(1) sleep(1)
duration -= 1 duration -= 1
return countdown
def main(args): def main(args):
work_duration = args.work_duration * 60 work_duration = args.work_duration * 60
break_duration = args.break_duration * 60 break_duration = args.break_duration * 60
repeats = args.repeats repeats = args.repeats
work_countdown = make_countdown()
break_countdown = make_countdown()
while repeats != 0: while repeats != 0:
notification.notify(title="Get started") subprocess.run(["notify-send", "Get started"])
work_countdown(work_duration) countdown(work_duration)
if break_duration != 0: if break_duration != 0:
notification.notify(title="Time for a break") subprocess.run(["notify-send", "Time for a break"])
break_countdown(break_duration) countdown(break_duration)
notification.notify(title="Break is over, back to work") subprocess.run(["notify-send", "Break is over, back to work"])
repeats -= 1 repeats -= 1
@@ -84,4 +78,10 @@ if __name__ == "__main__":
args = parser.parse_args() args = parser.parse_args()
signal.signal(signal.SIGINT, handle_signal)
signal.signal(signal.SIGTERM, handle_signal)
if args.clear:
clear()
else:
main(args) main(args)
@@ -1,5 +1,3 @@
#!/usr/bin/env bash
selected_hosts="$(ssh-hosts | fzf -m)" selected_hosts="$(ssh-hosts | fzf -m)"
for host in $selected_hosts; do for host in $selected_hosts; do
+1
View File
@@ -0,0 +1 @@
grep -E 'Host [a-z0-9\-]*$' ~/.ssh/config | awk '{print $2}'
@@ -7,12 +7,8 @@ from collections import defaultdict
def get_task_data(): def get_task_data():
command = ( command = ["task", "+PENDING", "or", "+WAITING", "-COMPLETED", "-DELETED", "export"]
"task +PENDING or +WAITING -COMPLETED -DELETED export | " return json.loads(subprocess.check_output(command))
"jq '[.[] | {uuid: .uuid, id, depends: .depends, description: .description, status: .status }]'"
)
output = subprocess.check_output(command, shell=True)
return json.loads(output)
def parse_task_data(data): def parse_task_data(data):
@@ -27,8 +23,7 @@ def parse_task_data(data):
"description": task.get("description", "No description"), "description": task.get("description", "No description"),
"status": task.get("status", "Unknown status"), "status": task.get("status", "Unknown status"),
} }
if task["depends"]: for dependency in task.get("depends", []):
for dependency in task["depends"]:
dependency_graph[dependency].append(task_id) dependency_graph[dependency].append(task_id)
dependent_tasks.add(task_id) dependent_tasks.add(task_id)
@@ -36,52 +31,6 @@ def parse_task_data(data):
return task_details, dependency_graph, root_tasks return task_details, dependency_graph, root_tasks
def get_all_parents(task_id, dependency_graph):
return [
parent for parent, children in dependency_graph.items() if task_id in children
]
def build_ascii_dag(
task_id,
task_details,
dependency_graph,
prefix="",
is_last=True,
show_id=True,
visited=None,
):
if visited is None:
visited = set()
if task_id in visited:
return [f"{prefix}{'└── ' if is_last else '├── '}... (cycle detected)"]
visited.add(task_id)
task_info = task_details[task_id]
task_line = f"{prefix}{'└── ' if is_last else '├── '}{task_info['id'] + ': ' if show_id else ''}{task_info['description']} ({task_info['status']})"
lines = [task_line]
children = dependency_graph.get(task_id, [])
for idx, child in enumerate(children):
child_is_last = idx == len(children) - 1
child_prefix = prefix + (" " if is_last else "│ ")
lines.extend(
build_ascii_dag(
child,
task_details,
dependency_graph,
child_prefix,
child_is_last,
show_id,
visited.copy(),
)
)
return lines
def render_dependency_dag(task_details, dependency_graph, root_tasks, show_id): def render_dependency_dag(task_details, dependency_graph, root_tasks, show_id):
dag_lines = [] dag_lines = []
global_visited = set() global_visited = set()
+1
View File
@@ -9,6 +9,7 @@
./firefox.nix ./firefox.nix
./librewolf.nix ./librewolf.nix
./chromium.nix ./chromium.nix
./tridactyl.nix
]; ];
options.browser = { options.browser = {
+17
View File
@@ -0,0 +1,17 @@
{
config,
lib,
...
}:
let
browsers = [
config.browser.primary
config.browser.secondary
];
in
{
config = lib.mkIf (lib.elem "firefox" browsers || lib.elem "librewolf" browsers) {
xdg.configFile."tridactyl/tridactylrc".source = ./tridactylrc;
};
}
File renamed without changes.
+21 -1
View File
@@ -6,6 +6,26 @@
{ {
config = lib.mkIf (config.git.enable && config.git.github.enable) { config = lib.mkIf (config.git.enable && config.git.github.enable) {
programs.gh.enable = true; programs.gh = {
enable = true;
settings = {
git_protocol = "ssh";
prompt = "enabled";
aliases = {
co = "pr checkout";
c = "repo clone";
f = "repo fork";
rc = "repo create";
rv = "repo view";
re = "repo edit";
rm = "repo remove";
rn = "repo rename";
lr = "repo list";
li = "issue list";
al = "alias";
al- = "alias delete";
};
};
};
}; };
} }
+38
View File
@@ -0,0 +1,38 @@
{ config, lib, ... }:
{
options.mpv.enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
config = lib.mkIf config.mpv.enable {
programs.mpv = {
enable = true;
config = {
vo = "gpu";
profile = "gpu-hq";
hwdec = "auto";
msg-color = "yes";
cursor-autohide = 300;
cursor-autohide-fs-only = "yes";
save-position-on-quit = "yes";
keep-open = "yes";
};
bindings = {
l = "seek +5";
h = "seek -5";
k = "seek +30";
j = "seek -30";
"+" = "add video-zoom 0.1";
"-" = "add video-zoom -0.1";
"=" = "set video-zoom 0; set video-pan-x 0; set video-pan-y 0";
H = "add video-pan-x 0.01";
L = "add video-pan-x -0.01";
K = "add video-pan-y 0.01";
J = "add video-pan-y -0.01";
m = "cycle mute";
};
};
};
}
+4
View File
@@ -23,6 +23,10 @@ in
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.packages = [ spotifyWithWayland ]; home.packages = [ spotifyWithWayland ];
home.activation.spotifyCacheSize = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
run mkdir -p ${config.xdg.configHome}/spotify
run ${lib.getExe pkgs.crudini} --ini-options=nospace --set ${config.xdg.configHome}/spotify/prefs "" storage.size 1024
'';
programs.ncspot = { programs.ncspot = {
enable = true; enable = true;
settings = { settings = {
-8
View File
@@ -1,7 +1,6 @@
{ {
config, config,
lib, lib,
lib',
... ...
}: }:
@@ -22,11 +21,6 @@ in
}; };
}; };
addBinToPath = lib.mkOption {
type = lib.types.bool;
default = false;
};
extraInit = lib.mkOption { extraInit = lib.mkOption {
type = lib.types.lines; type = lib.types.lines;
default = ""; default = "";
@@ -65,7 +59,5 @@ in
${cfg.extraInit} ${cfg.extraInit}
''; '';
}; };
home.sessionPath = lib.optional cfg.addBinToPath "${lib'.dotsPath}/.bin";
}; };
} }
+15
View File
@@ -0,0 +1,15 @@
# Anki review percentage for statusbar
num_to_review=200
# Get current card count from Anki
count=$(curl -s 127.0.0.1:8765 -X POST -d '{"action": "getNumCardsReviewedToday", "version": 6}' | jq '.result') || count=
if [ -n "$count" ]; then
echo "$count" > "$ANKI_REVIEWS"
elif [ ! -s "$ANKI_REVIEWS" ]; then
echo "-1" > "$ANKI_REVIEWS"
fi
num_reviews=$(cat "$ANKI_REVIEWS")
echo -n " Reviews: $(awk -v n="$num_reviews" -v t="$num_to_review" 'BEGIN { printf "%.2f%%", 100 * n / t }') "
+2
View File
@@ -0,0 +1,2 @@
pomo="${XDG_DATA_HOME:-$HOME/.local/share}/pomo"
if [ -f "$pomo" ]; then cat "$pomo"; fi
+2
View File
@@ -0,0 +1,2 @@
# Render contents of $HOME/.project if present
if [ -f "$HOME/.project" ]; then cat "$HOME/.project"; fi
+5
View File
@@ -0,0 +1,5 @@
num_done="$(task end.after:today status:completed count)"
num_pending="$(($(task count status:pending) + num_done))"
num_waiting="$(task count status:waiting)"
echo "Tasks: $num_done/$num_pending+$num_waiting"
+56
View File
@@ -1,10 +1,37 @@
{
config,
lib,
pkgs,
...
}:
let
status =
name: args:
lib.getExe (
pkgs.writeShellApplication (
{
inherit name;
text = builtins.readFile ./scripts/${name};
}
// args
)
);
in
{ {
programs.waybar.settings = [ programs.waybar.settings = [
(
{ {
height = 16; height = 16;
spacing = 4; spacing = 4;
modules-left = [ "niri/workspaces" ]; modules-left = [ "niri/workspaces" ];
modules-right = [ modules-right = [
"custom/project"
"custom/pomo"
]
++ lib.optional config.taskwarrior.enable "custom/tasks"
++ lib.optional config.anki.enable "custom/anki"
++ [
"pulseaudio" "pulseaudio"
"memory" "memory"
"cpu" "cpu"
@@ -54,6 +81,35 @@
format-disconnected = "{ifname} disconnected"; format-disconnected = "{ifname} disconnected";
tooltip-format = "{ifname}: {ipaddr}/{cidr}"; tooltip-format = "{ifname}: {ipaddr}/{cidr}";
}; };
"custom/project" = {
exec = status "sb-project" { runtimeInputs = [ pkgs.coreutils ]; };
interval = 30;
};
"custom/pomo" = {
exec = status "sb-pomo" { runtimeInputs = [ pkgs.coreutils ]; };
interval = 1;
};
} }
// lib.optionalAttrs config.taskwarrior.enable {
"custom/tasks" = {
exec = status "sb-tasks" { runtimeInputs = [ config.programs.taskwarrior.package ]; };
interval = 60;
};
}
// lib.optionalAttrs config.anki.enable {
"custom/anki" = {
exec = status "sb-anki" {
runtimeInputs = with pkgs; [
coreutils
curl
gawk
jq
];
runtimeEnv.ANKI_REVIEWS = config.anki.reviewsCache;
};
interval = 300;
};
}
)
]; ];
} }
+1 -3
View File
@@ -4,7 +4,5 @@ let
fs = import ./fs.nix { inherit lib; }; fs = import ./fs.nix { inherit lib; };
hosts = import ./hosts.nix { inherit lib; }; hosts = import ./hosts.nix { inherit lib; };
secrets = import ./secrets.nix { inherit lib; }; secrets = import ./secrets.nix { inherit lib; };
dotsPath = ../dots;
in in
fs // hosts // secrets // { inherit dotsPath; } fs // hosts // secrets
-1
View File
@@ -21,7 +21,6 @@
alsa.support32Bit = true; alsa.support32Bit = true;
pulse.enable = true; pulse.enable = true;
}; };
pulseaudio.extraConfig = "load-module module-switch-on-connect";
}; };
}; };
} }