summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.config/timewarrior/extensions/__pycache__/common.cpython-313.pycbin0 -> 1735 bytes
-rw-r--r--.config/timewarrior/extensions/common.py30
-rwxr-xr-x.config/timewarrior/extensions/total38
-rwxr-xr-x.config/timewarrior/extensions/waybar52
-rw-r--r--.config/timewarrior/timewarrior.cfg24
-rwxr-xr-xbin/dots4
-rwxr-xr-xbin/equery-fuzzy16
-rwxr-xr-xbin/git-sync38
-rwxr-xr-xbin/grimshot15
-rwxr-xr-xbin/ntfm38
-rwxr-xr-xbin/screenrec28
11 files changed, 283 insertions, 0 deletions
diff --git a/.config/timewarrior/extensions/__pycache__/common.cpython-313.pyc b/.config/timewarrior/extensions/__pycache__/common.cpython-313.pyc
new file mode 100644
index 0000000..eafdadc
--- /dev/null
+++ b/.config/timewarrior/extensions/__pycache__/common.cpython-313.pyc
Binary files differdiff --git a/.config/timewarrior/extensions/common.py b/.config/timewarrior/extensions/common.py
new file mode 100644
index 0000000..19467cb
--- /dev/null
+++ b/.config/timewarrior/extensions/common.py
@@ -0,0 +1,30 @@
+import fileinput, json, sys
+import datetime
+
+def loadstdin() -> (any, any):
+	meta = {}
+	data = []
+
+	for line in fileinput.input(encoding='utf-8'):
+		mp = line.removesuffix('\n').split(': ')
+		if len(mp) == 2:
+			meta[mp[0]] = mp[1]
+
+		if line == "[\n" or len(data) != 0:
+			data.append(line)
+
+		pass
+
+	return (meta, json.loads("".join(data)))
+
+
+def dumpstdout(output) -> None:
+	print(json.dumps(output), end='')
+
+
+def parse_timedelta(s: str) -> datetime.timedelta:
+	t = datetime.datetime.strptime(s, '%H:%M')
+	return datetime.timedelta(hours=t.hour, minutes=t.minute)
+
+if __name__ == "__main__":
+	sys.exit(1)
diff --git a/.config/timewarrior/extensions/total b/.config/timewarrior/extensions/total
new file mode 100755
index 0000000..8742b68
--- /dev/null
+++ b/.config/timewarrior/extensions/total
@@ -0,0 +1,38 @@
+#!/bin/env python3
+
+from common import loadstdin, dumpstdout, parse_timedelta
+from datetime import datetime, timezone, timedelta
+from os import getenv
+from math import ceil
+
+RATE = int(getenv('REPORT_RATE', '0'))
+BILL = parse_timedelta(getenv('REPORT_BILL', '1:00'))
+
+def timedelta_ceil(dur: timedelta, diff: timedelta) -> timedelta:
+	delta = ceil(dur.total_seconds() / diff.total_seconds()) * diff.total_seconds() - dur.total_seconds()
+	return timedelta(seconds=(dur.total_seconds() + delta))
+
+
+def main() -> None:
+	# parse stdin json
+	meta, data = loadstdin()
+
+	# calc total
+	total = timedelta(0)
+	for e in data:
+		startt = datetime.fromisoformat(e['start'])
+		endt = datetime.fromisoformat(e['end'])
+		total += endt - startt
+
+	# calc amount
+	total_billable = timedelta_ceil(total, BILL)
+	total_amount = (total_billable.total_seconds() / 3600) * RATE
+
+	# presentation
+	print(f"total => {total}")
+	print(f"bill  => {total_billable}")
+	print(f"{total_billable} @ {RATE} EUR => {total_amount} EUR")
+
+
+if __name__ == "__main__":
+	main()
diff --git a/.config/timewarrior/extensions/waybar b/.config/timewarrior/extensions/waybar
new file mode 100755
index 0000000..45e3f03
--- /dev/null
+++ b/.config/timewarrior/extensions/waybar
@@ -0,0 +1,52 @@
+#!/bin/env python3
+
+import fileinput, json
+from datetime import datetime, timezone, timedelta
+
+ICO="󰔚"
+CLS="timew"
+ALT="timew"
+
+def main() -> None:
+	# only read actual json
+	input = []
+	for line in fileinput.input(encoding='utf-8'):
+		if len(input) != 0:
+			input.append(line)
+
+		if line == "[\n":
+			input = [line]
+
+		pass
+	
+	# parse json
+	input = json.loads("".join(input))
+
+	# filter for active trackers
+	input = list(filter(lambda x: not "end" in x, list(input)))
+
+	# exit early if no tracker is running
+	if len(input) == 0:
+		output = {}
+	else:
+		# pick first
+		input = input[0]
+		# parse start
+		startt = datetime.fromisoformat(input['start'])
+		# get now
+		nowt = datetime.now(timezone.utc);
+		# round away microseconds
+		nowt = nowt.replace(microsecond=0)
+		# calc diff
+		diff = nowt - startt.astimezone(timezone.utc)
+		# make output
+		output = {
+			'text': f"{ICO} {diff} {",".join(input['tags'])}",
+			'class': CLS,
+			'alt': ALT,
+		}
+
+	print(json.dumps(output), end='')
+
+if __name__ == "__main__":
+	main()
diff --git a/.config/timewarrior/timewarrior.cfg b/.config/timewarrior/timewarrior.cfg
new file mode 100644
index 0000000..25f8573
--- /dev/null
+++ b/.config/timewarrior/timewarrior.cfg
@@ -0,0 +1,24 @@
+define exclusions:
+  monday    = <10:00
+  tuesday   = <10:00
+  wednesday = <09:00
+  thursday  = <10:00
+  friday    = <09:00
+  saturday  = >00:00
+  sunday    = >00:00
+
+
+define theme:
+  colors:
+    today     = white
+    holiday   = gray4
+    label     = gray8
+    ids       = cyan
+    exclusion = "gray4 on gray2"
+
+  palette:
+    color01 = "black on yellow"
+    color02 = "black on red"
+    color03 = "black on blue"
+    color04 = "black on green"
+    color05 = "black on magenta"
diff --git a/bin/dots b/bin/dots
index cee0d73..7076ece 100755
--- a/bin/dots
+++ b/bin/dots
@@ -25,4 +25,8 @@ push)
 	$0 git push inazuma || true
 	$0 git push origin || true
 	;;
+untracked)
+	shift
+	exec $0 git ls-files -o $*
+	;;
 esac
diff --git a/bin/equery-fuzzy b/bin/equery-fuzzy
new file mode 100755
index 0000000..1f0202a
--- /dev/null
+++ b/bin/equery-fuzzy
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -eu
+rel="equery list -f -op -F '[\$location] \$category/\$name-\$fullversion::\$repo' {q} || :"
+opn="echo {2}"
+pre="equery -N meta {2} && hr && equery -N uses {2}"
+exec fzf --layout=reverse --height='~60%' \
+	--disabled \
+	--ansi \
+	--query "${1:-portage}" \
+	--accept-nth="2" \
+	--preview="$pre" \
+	--preview-window=down,wrap \
+	--bind=start:reload:"$rel" \
+	--bind=change:reload:"$rel" \
+	--bind=tab:replace-query \
+	--bind=enter:replace-query+become:"$opn"
diff --git a/bin/git-sync b/bin/git-sync
new file mode 100755
index 0000000..b18c94d
--- /dev/null
+++ b/bin/git-sync
@@ -0,0 +1,38 @@
+#!/bin/bash
+set -eu
+[ -n "${DEBUG:-}" ] && set -x
+
+# use cli arg
+base_branch=${1:-}
+
+# detect base branch (when git-new was used)
+[ -n "$base_branch" ] || base_branch=$(git symbolic-ref --short refs/bases/"$(git symbolic-ref --short HEAD)" 2>/dev/null || :)
+
+# detect trunk via origin/HEAD
+[ -n "$base_branch" ] || base_branch=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null || :)
+
+# fallback to base branch => current branch
+[ -n "$base_branch" ] || base_branch=$(git symbolic-ref --short HEAD 2>/dev/null || :)
+
+# resolve upstream
+if [[ "$base_branch" = "origin/"* ]]; then
+	upstream=$base_branch
+else
+	upstream=$(git rev-parse --abbrev-ref --symbolic-full-name "$base_branch"'@{u}')
+fi
+
+[ -n "${base_branch:?}" ] || exit 1
+[ -n "${upstream:?}" ] || exit 1
+
+echo "Syncing with $upstream (base: $base_branch)"
+
+# fetch upstream
+git fetch ${upstream/\// }
+
+# check if base and upstream have diverged
+if ! git diff --quiet "$upstream" "$base_branch"; then
+	git diff --stat "$upstream" "$base_branch"
+fi
+
+# rebase
+git rebase --interactive "$upstream"
diff --git a/bin/grimshot b/bin/grimshot
new file mode 100755
index 0000000..b946c27
--- /dev/null
+++ b/bin/grimshot
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -eu
+
+screenshot_dir=$XDG_PICTURES_DIR/screenshots
+screenshot_path=$screenshot_dir/"$(date --iso-8601=seconds).png"
+
+mkdir -p $screenshot_dir || exit 1
+
+grim -g "$(slurp)" "$screenshot_path" || exit 1
+
+wl-copy --type image/png < "$screenshot_path" || exit 1
+
+wl-copy --primary "$screenshot_path" || exit 1
+
+fyi -a grimshot -i "$screenshot_path" "grimshot" "$screenshot_path"
diff --git a/bin/ntfm b/bin/ntfm
new file mode 100755
index 0000000..dd7344f
--- /dev/null
+++ b/bin/ntfm
@@ -0,0 +1,38 @@
+#!/bin/bash
+set -eu
+
+# shellcheck disable=2034
+description="notification manager"
+
+FUZL_PROMPT=ntfm
+. libfuzl.sh
+
+main() {
+	local nid
+
+	nid=$(makoctl list |
+		awk '/Notification/{match($0,/[0-9]+/); print substr($0,RSTART,RLENGTH) "\t" substr($0,RSTART+RLENGTH+1)}' |
+		fuzl_menu $FUZL_MENU_FILTER --with-nth=2 --accept-nth=1 --no-run-if-empty)
+	[ -n "$nid" ] || return
+
+	fuzl_action_add menu "󰮫" "open menu"
+	fuzl_action_add dismiss "󰅗" "dimiss"
+	fuzl_action_menu "$nid"
+}
+
+#
+# actions
+#
+
+ntfm_menu() {
+	local nid=${1:?}
+	exec makoctl menu -n "$nid" -- fuzzel -d
+}
+
+ntfm_dismiss() {
+	local nid=${1:?}
+	exec makoctl dismiss -n "$nid"
+}
+
+
+main
diff --git a/bin/screenrec b/bin/screenrec
new file mode 100755
index 0000000..5324ead
--- /dev/null
+++ b/bin/screenrec
@@ -0,0 +1,28 @@
+#!/bin/sh
+set -eu
+
+update_waybar() {
+	sleep .5
+	pkill -RTMIN+1 -x waybar
+}
+
+trap '{ update_waybar & disown; }' SIGCHLD EXIT
+
+if [ "${1:-}" = "stop" ]; then
+	exec pkill -HUP -x wl-screenrec
+fi
+
+screengrab_dir=$XDG_VIDEOS_DIR/screengrabs
+screengrab_path=$screengrab_dir/"$(date --iso-8601=seconds).mkv"
+
+mkdir -p $screengrab_dir || exit 1
+
+output=$(slurp -b '#000000aa' -c '#4E437188' -w 50 -f '%o' -or)
+
+update_waybar & disown
+
+wl-screenrec --filename="$screengrab_path" --output="$output" $@ || true
+
+wl-copy "$screengrab_path"
+
+fyi -a screenrec "screenrec" "$screengrab_path"