refactor: nixify / clean remaining dots scripts

This commit is contained in:
hektor committed 2026-11-06 21:00:20 +01:00
1 parent 9030f33842
commit 9110789527
53 files changed
+265 -655

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
-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
-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
-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).
+1 -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;
@@ -57,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;
+1 -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;
@@ -50,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,17 +30,14 @@ 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 with open(POMO_PATH, "w") as f:
time_str = format_mins_secs(mins, secs) f.write(format_mins_secs(mins, secs))
os.system(f'echo -n "{time_str}" > {POMO_PATH}') sleep(1)
sleep(1) duration -= 1
duration -= 1
return countdown
def main(args): def main(args):
@@ -48,16 +45,13 @@ def main(args):
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()
main(args) signal.signal(signal.SIGINT, handle_signal)
signal.signal(signal.SIGTERM, handle_signal)
if args.clear:
clear()
else:
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,61 +23,14 @@ 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)
root_tasks = set(task_details.keys()) - dependent_tasks root_tasks = set(task_details.keys()) - dependent_tasks
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()
-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"
+110 -54
View File
@@ -1,59 +1,115 @@
{
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; {
spacing = 4; height = 16;
modules-left = [ "niri/workspaces" ]; spacing = 4;
modules-right = [ modules-left = [ "niri/workspaces" ];
"pulseaudio" modules-right = [
"memory" "custom/project"
"cpu" "custom/pomo"
"network" ]
"clock" ++ lib.optional config.taskwarrior.enable "custom/tasks"
"battery" ++ lib.optional config.anki.enable "custom/anki"
]; ++ [
clock = { "pulseaudio"
format = "W{:%V %d %b %H:%M}"; "memory"
tooltip-format = "{calendar}"; "cpu"
format-alt = "{:%Y-%m-%d %H:%M:%S}"; "network"
}; "clock"
battery = { "battery"
bat = "BAT0"; ];
adapter = "ADP1"; clock = {
interval = 5; format = "W{:%V %d %b %H:%M}";
full-at = 99; tooltip-format = "{calendar}";
states = { format-alt = "{:%Y-%m-%d %H:%M:%S}";
good = 80;
warning = 20;
critical = 10;
}; };
format = "{capacity}%--"; battery = {
format-charging = "{capacity}%++"; bat = "BAT0";
format-plugged = "{capacity}%"; adapter = "ADP1";
format-alt = "{time} {power}W"; interval = 5;
}; full-at = 99;
pulseaudio = { states = {
format = "VOL {volume}%"; good = 80;
format-muted = "muted"; warning = 20;
on-click = "pavucontrol"; critical = 10;
}; };
memory = { format = "{capacity}%--";
interval = 2; format-charging = "{capacity}%++";
format = "RAM {percentage}%"; format-plugged = "{capacity}%";
format-alt = "RAM {used:0.1f}G/{total:0.1f}G"; format-alt = "{time} {power}W";
}; };
cpu = { pulseaudio = {
interval = 2; format = "VOL {volume}%";
format = "CPU {usage}%"; format-muted = "muted";
format-alt = "CPU {avg_frequency}GHz"; on-click = "pavucontrol";
}; };
network = { memory = {
interval = 5; interval = 2;
format-wifi = "{ifname} {ipaddr} {essid}"; format = "RAM {percentage}%";
format-ethernet = "{ifname} {ipaddr}"; format-alt = "RAM {used:0.1f}G/{total:0.1f}G";
format-disconnected = "{ifname} disconnected"; };
tooltip-format = "{ifname}: {ipaddr}/{cidr}"; cpu = {
}; interval = 2;
} format = "CPU {usage}%";
format-alt = "CPU {avg_frequency}GHz";
};
network = {
interval = 5;
format-wifi = "{ifname} {ipaddr} {essid}";
format-ethernet = "{ifname} {ipaddr}";
format-disconnected = "{ifname} disconnected";
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