aboutsummaryrefslogtreecommitdiff
path: root/home/dot_local/share
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2026-08-02 14:48:29 +0200
committerLoek Le Blansch <loek@pipeframe.xyz>2026-08-02 14:48:29 +0200
commite43eb1177872f52e949fb5f0f93396ed94b0d093 (patch)
tree78b73af6a989fa2996d71b112e161b70d35081ef /home/dot_local/share
parent2f14a896e4b897bd747c24d7ad8e9e7bb3237d03 (diff)
move to chezmoi
Diffstat (limited to 'home/dot_local/share')
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/BottomBar.css7
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/DeckBrowser.css5
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/Editor.css20
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/TopToolbar.css2
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/empty_CardLayout.css0
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Overview.css0
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Reviewer.css0
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/empty_ReviewerBottomBar.css0
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/empty_legacy.css0
-rw-r--r--home/dot_local/share/Anki2/addons21/308574457/user_files/global.css2
-rw-r--r--home/dot_local/share/Anki2/addons21/mode/__init__.py18
-rw-r--r--home/dot_local/share/Anki2/gldriver61
-rw-r--r--home/dot_local/share/applications/addtorrent.desktop8
-rw-r--r--home/dot_local/share/applications/discord.desktop10
-rw-r--r--home/dot_local/share/applications/mozc-dictionary.desktop11
-rw-r--r--home/dot_local/share/applications/mozc-settings.desktop11
-rw-r--r--home/dot_local/share/bin/executable_163
-rw-r--r--home/dot_local/share/bin/executable_=45
-rw-r--r--home/dot_local/share/bin/executable_addtoqueue3
-rw-r--r--home/dot_local/share/bin/executable_addtorrent41
-rw-r--r--home/dot_local/share/bin/executable_androidwifistore2pass43
-rw-r--r--home/dot_local/share/bin/executable_ansi2polybar67
-rw-r--r--home/dot_local/share/bin/executable_bgcol9
-rw-r--r--home/dot_local/share/bin/executable_bootloader13
-rw-r--r--home/dot_local/share/bin/executable_brightness29
-rw-r--r--home/dot_local/share/bin/executable_caffeine8
-rw-r--r--home/dot_local/share/bin/executable_cc1080p302
-rw-r--r--home/dot_local/share/bin/executable_cc720p602
-rw-r--r--home/dot_local/share/bin/executable_ccpreview74
-rw-r--r--home/dot_local/share/bin/executable_clean3
-rw-r--r--home/dot_local/share/bin/executable_darkroom20
-rw-r--r--home/dot_local/share/bin/executable_dbg27
-rw-r--r--home/dot_local/share/bin/executable_dbg_xprop10
-rw-r--r--home/dot_local/share/bin/executable_decsync2plain60
-rw-r--r--home/dot_local/share/bin/executable_delta4
-rw-r--r--home/dot_local/share/bin/executable_discord3
-rw-r--r--home/dot_local/share/bin/executable_dox-open31
-rw-r--r--home/dot_local/share/bin/executable_editor2
-rw-r--r--home/dot_local/share/bin/executable_extmon26
-rw-r--r--home/dot_local/share/bin/executable_fcitx5-temp-off8
-rw-r--r--home/dot_local/share/bin/executable_fcitx5-temp-restore7
-rw-r--r--home/dot_local/share/bin/executable_ffmpeg-resize82
-rw-r--r--home/dot_local/share/bin/executable_folder2cd23
-rw-r--r--home/dot_local/share/bin/executable_fontfix39
-rw-r--r--home/dot_local/share/bin/executable_fork2
-rw-r--r--home/dot_local/share/bin/executable_fv2
-rw-r--r--home/dot_local/share/bin/executable_gpg-git4
-rw-r--r--home/dot_local/share/bin/executable_helium-browser5
-rw-r--r--home/dot_local/share/bin/executable_hide4
-rw-r--r--home/dot_local/share/bin/executable_icalcat12
-rw-r--r--home/dot_local/share/bin/executable_installbd20
-rw-r--r--home/dot_local/share/bin/executable_java7
-rw-r--r--home/dot_local/share/bin/executable_kbindicator19
-rw-r--r--home/dot_local/share/bin/executable_khal16
-rw-r--r--home/dot_local/share/bin/executable_khard12
-rw-r--r--home/dot_local/share/bin/executable_labels2lrc30
-rw-r--r--home/dot_local/share/bin/executable_latex-doc4
-rw-r--r--home/dot_local/share/bin/executable_lf23
-rw-r--r--home/dot_local/share/bin/executable_lights5
-rw-r--r--home/dot_local/share/bin/executable_lock4
-rw-r--r--home/dot_local/share/bin/executable_lorem12
-rw-r--r--home/dot_local/share/bin/executable_lrc2labels7
-rw-r--r--home/dot_local/share/bin/executable_mbsync2
-rw-r--r--home/dot_local/share/bin/executable_mk87
-rw-r--r--home/dot_local/share/bin/executable_mktags61
-rw-r--r--home/dot_local/share/bin/executable_mozc-config-filter6
-rw-r--r--home/dot_local/share/bin/executable_nginx-dev86
-rw-r--r--home/dot_local/share/bin/executable_open12
-rw-r--r--home/dot_local/share/bin/executable_panic36
-rw-r--r--home/dot_local/share/bin/executable_pause10
-rw-r--r--home/dot_local/share/bin/executable_pdfsize2
-rw-r--r--home/dot_local/share/bin/executable_pew3
-rw-r--r--home/dot_local/share/bin/executable_podcast2m3u33
-rw-r--r--home/dot_local/share/bin/executable_preview75
-rw-r--r--home/dot_local/share/bin/executable_prompt33
-rw-r--r--home/dot_local/share/bin/executable_qrclip2
-rw-r--r--home/dot_local/share/bin/executable_reload2
-rw-r--r--home/dot_local/share/bin/executable_rofi4
-rw-r--r--home/dot_local/share/bin/executable_scene56
-rw-r--r--home/dot_local/share/bin/executable_screenrecord8
-rw-r--r--home/dot_local/share/bin/executable_screenwatch11
-rw-r--r--home/dot_local/share/bin/executable_sdk10_compiledb38
-rw-r--r--home/dot_local/share/bin/executable_set-default32
-rw-r--r--home/dot_local/share/bin/executable_setwacom2
-rw-r--r--home/dot_local/share/bin/executable_single2folder16
-rw-r--r--home/dot_local/share/bin/executable_spec2
-rw-r--r--home/dot_local/share/bin/executable_subrename54
-rw-r--r--home/dot_local/share/bin/executable_time2tsv107
-rw-r--r--home/dot_local/share/bin/executable_timefmt24
-rw-r--r--home/dot_local/share/bin/executable_timerep82
-rw-r--r--home/dot_local/share/bin/executable_timesum4
-rw-r--r--home/dot_local/share/bin/executable_toetsrooster2ical38
-rw-r--r--home/dot_local/share/bin/executable_vdirsyncer6
-rw-r--r--home/dot_local/share/bin/executable_venvgen47
-rw-r--r--home/dot_local/share/bin/executable_vodchat3
-rw-r--r--home/dot_local/share/bin/executable_wacommode58
-rw-r--r--home/dot_local/share/bin/executable_wacomshortcuts12
-rw-r--r--home/dot_local/share/bin/executable_wacomtouch14
-rw-r--r--home/dot_local/share/bin/executable_xbindkeys2
-rw-r--r--home/dot_local/share/bin/executable_yt-vod17
-rw-r--r--home/dot_local/share/bin/symlink_mode1
-rw-r--r--home/dot_local/share/bin/symlink_sh1
-rw-r--r--home/dot_local/share/fcitx5/themes/mode/base.conf42
-rw-r--r--home/dot_local/share/mode/executable_mode148
-rw-r--r--home/dot_local/share/mode/plug.d/10_lib46
-rw-r--r--home/dot_local/share/mode/plug.d/20_export_colors17
-rw-r--r--home/dot_local/share/mode/plug.d/20_export_mode9
-rw-r--r--home/dot_local/share/mode/plug.d/20_export_vim_theme6
-rw-r--r--home/dot_local/share/mode/plug.d/50_accent15
-rw-r--r--home/dot_local/share/mode/reload.d/brave80
-rw-r--r--home/dot_local/share/mode/reload.d/executable_dunst3
-rw-r--r--home/dot_local/share/mode/reload.d/executable_fcitx53
-rw-r--r--home/dot_local/share/mode/reload.d/executable_i32
-rw-r--r--home/dot_local/share/mode/reload.d/executable_nvim6
-rw-r--r--home/dot_local/share/mode/reload.d/executable_polybar3
-rw-r--r--home/dot_local/share/mode/reload.d/executable_term30
-rw-r--r--home/dot_local/share/mode/reload.d/gtk8
-rw-r--r--home/dot_local/share/mode/switch.d/executable_anki120
-rw-r--r--home/dot_local/share/mode/switch.d/executable_chromium48
-rw-r--r--home/dot_local/share/mode/switch.d/executable_discord34
-rw-r--r--home/dot_local/share/mode/switch.d/executable_dunst24
-rw-r--r--home/dot_local/share/mode/switch.d/executable_fcitx567
-rw-r--r--home/dot_local/share/mode/switch.d/executable_gtk11
-rw-r--r--home/dot_local/share/mode/switch.d/executable_i314
-rw-r--r--home/dot_local/share/mode/switch.d/executable_kitty27
-rw-r--r--home/dot_local/share/mode/switch.d/executable_mode10
-rw-r--r--home/dot_local/share/mode/switch.d/executable_polybar16
-rw-r--r--home/dot_local/share/mode/switch.d/executable_vim59
-rw-r--r--home/dot_local/share/mode/switch.d/executable_wall2
-rw-r--r--home/dot_local/share/mode/switch.d/executable_xrdb22
-rw-r--r--home/dot_local/share/mode/switch.d/executable_zathura27
-rw-r--r--home/dot_local/share/mode/themes/github-black25
-rw-r--r--home/dot_local/share/mode/themes/github-dark25
-rw-r--r--home/dot_local/share/mode/themes/github-light25
-rw-r--r--home/dot_local/share/mode/themes/rose-pine-dawn28
-rw-r--r--home/dot_local/share/mode/themes/symlink_dark1
-rw-r--r--home/dot_local/share/mode/themes/symlink_light1
-rw-r--r--home/dot_local/share/mode/themes/xcode-dark24
-rw-r--r--home/dot_local/share/oh-my-zsh/completions/_fork2
-rw-r--r--home/dot_local/share/oh-my-zsh/themes/loek.zsh-theme17
-rw-r--r--home/dot_local/share/pass-extensions/executable_directory.bash12
-rw-r--r--home/dot_local/share/pass-extensions/executable_duplicates.bash45
-rw-r--r--home/dot_local/share/pass-extensions/executable_exit.bash2
-rw-r--r--home/dot_local/share/pass-extensions/executable_g.bash2
-rw-r--r--home/dot_local/share/pass-extensions/executable_names.bash46
-rw-r--r--home/dot_local/share/pass-extensions/executable_treasure.bash47
-rw-r--r--home/dot_local/share/pass-extensions/symlink_dir.bash1
-rw-r--r--home/dot_local/share/pass-extensions/symlink_dupes.bash1
-rw-r--r--home/dot_local/share/private_gnupg/private_gpg-agent.conf3
149 files changed, 3262 insertions, 0 deletions
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/BottomBar.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/BottomBar.css
new file mode 100644
index 0000000..5e3dc77
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/BottomBar.css
@@ -0,0 +1,7 @@
+#outer {
+ padding-top: 2px;
+ border: none;
+}
+
+center#outer ~ div { display: none; }
+
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/DeckBrowser.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/DeckBrowser.css
new file mode 100644
index 0000000..79b8e39
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/DeckBrowser.css
@@ -0,0 +1,5 @@
+tr.deck td {
+ --border-subtle: var(--canvas-inset);
+ border-bottom: none;
+}
+
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/Editor.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/Editor.css
new file mode 100644
index 0000000..c826858
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/Editor.css
@@ -0,0 +1,20 @@
+body
+{ background-color: var(--canvas); }
+
+.rich-text-input,
+.tag-editor
+{ padding: 0.5ex !important; }
+
+body
+{ font-size: 10pt !important; }
+
+anki-editable { background-color: #ff00ff; }
+
+.editor-field
+{ border-color: var(--canvas-inset) !important; }
+
+.tag-editor {
+ border: none !important;
+ margin: 0 !important;
+}
+
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/TopToolbar.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/TopToolbar.css
new file mode 100644
index 0000000..7a3eeeb
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/TopToolbar.css
@@ -0,0 +1,2 @@
+body .header { border-bottom: none !important; }
+
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_CardLayout.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_CardLayout.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_CardLayout.css
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Overview.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Overview.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Overview.css
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Reviewer.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Reviewer.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_Reviewer.css
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_ReviewerBottomBar.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_ReviewerBottomBar.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_ReviewerBottomBar.css
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_legacy.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_legacy.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/empty_legacy.css
diff --git a/home/dot_local/share/Anki2/addons21/308574457/user_files/global.css b/home/dot_local/share/Anki2/addons21/308574457/user_files/global.css
new file mode 100644
index 0000000..a30eb51
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/308574457/user_files/global.css
@@ -0,0 +1,2 @@
+button { border: none !important; }
+
diff --git a/home/dot_local/share/Anki2/addons21/mode/__init__.py b/home/dot_local/share/Anki2/addons21/mode/__init__.py
new file mode 100644
index 0000000..78d0d58
--- /dev/null
+++ b/home/dot_local/share/Anki2/addons21/mode/__init__.py
@@ -0,0 +1,18 @@
+#!/bin/python3
+from aqt import mw
+from aqt.utils import tr
+from aqt.theme import Theme
+from os import environ
+from pathlib import Path
+
+THEME_DARK = 2
+THEME_LIGHT = 1
+
+path = Path(environ['XDG_CACHE_HOME'], 'mode/state/mode')
+with path.open() as file:
+ mode = file.read().strip()
+ if mode == "dark":
+ mw.set_theme(Theme(THEME_DARK))
+ if mode == "light":
+ mw.set_theme(Theme(THEME_LIGHT))
+
diff --git a/home/dot_local/share/Anki2/gldriver6 b/home/dot_local/share/Anki2/gldriver6
new file mode 100644
index 0000000..865faf1
--- /dev/null
+++ b/home/dot_local/share/Anki2/gldriver6
@@ -0,0 +1 @@
+auto
diff --git a/home/dot_local/share/applications/addtorrent.desktop b/home/dot_local/share/applications/addtorrent.desktop
new file mode 100644
index 0000000..fe590d6
--- /dev/null
+++ b/home/dot_local/share/applications/addtorrent.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=addtorrent
+Name[ja]=トレントを追加
+Exec=addtorrent %U
+Type=Application
+Hidden=true
+MimeType=application/x-bittorrent;x-scheme-handler/magnet;
+
diff --git a/home/dot_local/share/applications/discord.desktop b/home/dot_local/share/applications/discord.desktop
new file mode 100644
index 0000000..403a457
--- /dev/null
+++ b/home/dot_local/share/applications/discord.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Name=Discord
+StartupWMClass=discord
+Comment=All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone.
+GenericName=Internet Messenger
+Exec=discord
+Icon=discord
+Type=Application
+Categories=Network;InstantMessaging;
+MimeType=x-scheme-handler/betterdiscord;
diff --git a/home/dot_local/share/applications/mozc-dictionary.desktop b/home/dot_local/share/applications/mozc-dictionary.desktop
new file mode 100644
index 0000000..c4f6193
--- /dev/null
+++ b/home/dot_local/share/applications/mozc-dictionary.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=Mozc dictionary tool
+Name[ja]=Mozc 辞書ツール
+Name[nl]=Mozc woordenboekhulpprogramma
+GenericName[ja]=日本語入力の辞書ツール
+GenericName[nl]=Hulpprogramma voor woordenboek van Japanse invoer
+GenericName=Japanese input method dictionary tool
+Exec=/usr/lib/mozc/mozc_tool --mode=dictionary_tool
+Icon=mozc
+Type=Application
+Categories=Settings;
diff --git a/home/dot_local/share/applications/mozc-settings.desktop b/home/dot_local/share/applications/mozc-settings.desktop
new file mode 100644
index 0000000..bcfde2d
--- /dev/null
+++ b/home/dot_local/share/applications/mozc-settings.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=Mozc settings
+Name[ja]=Mozc プロパティ
+Name[nl]=Mozc instellingen
+GenericName[ja]=日本語入力の設定
+GenericName[nl]=Instellingen voor Japanse invoermethode
+GenericName=Japanese IME configuration
+Exec=/usr/lib/mozc/mozc_tool --mode=config_dialog
+Icon=mozc
+Type=Application
+Categories=Settings;
diff --git a/home/dot_local/share/bin/executable_16 b/home/dot_local/share/bin/executable_16
new file mode 100644
index 0000000..f8cc49f
--- /dev/null
+++ b/home/dot_local/share/bin/executable_16
@@ -0,0 +1,3 @@
+#!/bin/sh
+python3 -c 'import sys ; print(f"{int(sys.stdin.read().strip()):x}")'
+
diff --git a/home/dot_local/share/bin/executable_= b/home/dot_local/share/bin/executable_=
new file mode 100644
index 0000000..5e69f91
--- /dev/null
+++ b/home/dot_local/share/bin/executable_=
@@ -0,0 +1,45 @@
+#!/bin/python3 --
+from sys import argv as _argv
+from os import environ as _environ, path as _path
+from math import *
+
+_ans_path = _path.join(_environ["XDG_CACHE_HOME"], "calc_ans")
+try:
+ _ans_file = open(_ans_path, "r+")
+except:
+ _ans_file = open(_ans_path, "w+")
+_exit_code = 0
+
+ans = 0
+try:
+ _ans_str = _ans_file.read()
+ if "." in _ans_str:
+ ans = float(_ans_str)
+ else:
+ ans = int(_ans_str)
+except:
+ pass
+
+deg = pi / 180
+
+MIN = min
+MAX = max
+BIT = lambda n: 1 << n
+GENMASK = lambda h, l: (BIT(MAX(h, l) + 1) - 1) ^ (BIT(MIN(h, l)) - 1)
+KB = lambda x: x << 10
+MB = lambda x: x << 20
+GB = lambda x: x << 30
+
+try:
+ ans = eval(" ".join(_argv[1:]))
+ print(ans)
+except:
+ pass
+
+_ans_file.truncate(0)
+_ans_file.seek(0)
+_ans_file.write(str(ans))
+_ans_file.close()
+
+exit(_exit_code)
+
diff --git a/home/dot_local/share/bin/executable_addtoqueue b/home/dot_local/share/bin/executable_addtoqueue
new file mode 100644
index 0000000..535e250
--- /dev/null
+++ b/home/dot_local/share/bin/executable_addtoqueue
@@ -0,0 +1,3 @@
+#!/bin/sh
+exec st -T "[floating]" -g 120x20 -e fzmp
+
diff --git a/home/dot_local/share/bin/executable_addtorrent b/home/dot_local/share/bin/executable_addtorrent
new file mode 100644
index 0000000..bf238d6
--- /dev/null
+++ b/home/dot_local/share/bin/executable_addtorrent
@@ -0,0 +1,41 @@
+#!/bin/sh
+progname="$(basename "$0")"
+
+title="Torrent"
+msg_ok="Torrent successfully added"
+msg_err="Could not add torrent"
+usage="usage: $progname URL"
+err_no_seedbox="error: \$SEEDBOX_LOGIN is not set"
+
+case "$LANG" in
+ ja_JP*)
+ title="トレント"
+ msg_ok="一つのトレントを追加しました"
+ msg_err="トレントを追加できませんでした"
+ usage="用法: $progname URL"
+ err_no_seedbox="エラー: \$SEEDBOX_LOGINに値がありません"
+ ;;
+esac
+
+die() {
+ echo "$1"
+ exit 1
+}
+
+[ $# -eq 0 ] && die "$usage"
+[ -z "$SEEDBOX_LOGIN" ] && die "$err_no_seedbox"
+
+ssh "$SEEDBOX_LOGIN" transmission-remote -a "'$(echo "$1" | sed "s/'/'\\''/g")'"
+if [ $? -eq 0 ]; then
+ msg="$msg_ok"
+ urgency="normal"
+else
+ msg="$msg_err"
+ urgency="critical"
+fi
+
+notify-send \
+ --app-name "$title" \
+ --urgency "$urgency" \
+ "$title" "$msg"
+
diff --git a/home/dot_local/share/bin/executable_androidwifistore2pass b/home/dot_local/share/bin/executable_androidwifistore2pass
new file mode 100644
index 0000000..b03eb9d
--- /dev/null
+++ b/home/dot_local/share/bin/executable_androidwifistore2pass
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Use xmlstarlet and ADB to pull WifiConfigStore.xml from a (rooted) Android
+# phone and import wifi network passwords into pass. Tested with a rooted pixel
+# 4a (sunfish) running LineageOS 21 (Android 14)
+
+TAB="$(printf '\t')"
+
+get_wifi_cfg() {
+ adb shell cat /data/misc/apexdata/com.android.wifi/WifiConfigStore.xml
+ if [ $? -ne 0 ] ; then
+ echo "note: try running \`adb root\` first"
+ exit 1
+ fi
+}
+
+parse_filter() {
+ xmlstarlet select --template \
+ --match '/WifiConfigStoreData/NetworkList/Network' \
+ --if './WifiConfiguration/string[@name="PreSharedKey"]' \
+ --value-of './WifiConfiguration/string[@name="SSID"]' \
+ --output "$TAB" \
+ --value-of './WifiConfiguration/string[@name="PreSharedKey"]' \
+ --nl
+}
+
+cut_quotes() {
+ cut -c2- | rev | cut -c2- | rev
+}
+
+import_pass() {
+ while read line; do
+ SSID="$(echo "$line" | cut -d"$TAB" -f1 | cut_quotes)"
+ PASSWD="$(echo "$line" | cut -d"$TAB" -f2 | cut_quotes)"
+ PASS_NAME="net/$(echo "$SSID" | tr '/' '-')/passwd"
+
+ printf 'insert SSID "%s" as %s ...' "$SSID" "$PASS_NAME"
+ echo "$PASSWD" | pass insert --multiline "$PASS_NAME" 1>/dev/null 2>/dev/null
+ printf ' %s\n' "$([ $? -eq 0 ] && echo "OK" || echo "ERROR")"
+ done
+}
+
+get_wifi_cfg | parse_filter | import_pass
+
diff --git a/home/dot_local/share/bin/executable_ansi2polybar b/home/dot_local/share/bin/executable_ansi2polybar
new file mode 100644
index 0000000..e543ce5
--- /dev/null
+++ b/home/dot_local/share/bin/executable_ansi2polybar
@@ -0,0 +1,67 @@
+#!/bin/sh
+# convert ansi escape codes into polybar/lemonbar color tags. this script makes
+# some very dumb assumptions about which escape codes will be in the input
+# stream, and is by no means complete, just good enough
+
+. "$XDG_CACHE_HOME/mode/state/theme"
+export bg fg $(seq 0 15 | sed 's/^/color/')
+
+exec gawk '
+function flush_buffer() {
+ switch (buf) {
+ case 0: printf "%{T-}%{F-}%{B-}%{u-}%{o-}" ; break
+ case 1: printf "%{T2}" ; break
+ case 30: printf "%{F" ENVIRON["color0"] "}" ; break
+ case 31: printf "%{F" ENVIRON["color1"] "}" ; break
+ case 32: printf "%{F" ENVIRON["color2"] "}" ; break
+ case 33: printf "%{F" ENVIRON["color3"] "}" ; break
+ case 34: printf "%{F" ENVIRON["color4"] "}" ; break
+ case 35: printf "%{F" ENVIRON["color5"] "}" ; break
+ case 36: printf "%{F" ENVIRON["color6"] "}" ; break
+ case 37: printf "%{F" ENVIRON["color7"] "}" ; break
+ case 90: printf "%{F" ENVIRON["color8"] "}" ; break
+ case 91: printf "%{F" ENVIRON["color9"] "}" ; break
+ case 92: printf "%{F" ENVIRON["color10"] "}" ; break
+ case 93: printf "%{F" ENVIRON["color11"] "}" ; break
+ case 94: printf "%{F" ENVIRON["color12"] "}" ; break
+ case 95: printf "%{F" ENVIRON["color13"] "}" ; break
+ case 96: printf "%{F" ENVIRON["color14"] "}" ; break
+ case 97: printf "%{F" ENVIRON["color15"] "}" ; break
+ default: break
+ }
+ buf = ""
+}
+function reset() {
+ bold = 0
+ buf = ""
+ esc = 0
+}
+BEGIN {
+ RS = "(.)" # make awk read character by character
+ reset()
+}
+# start of escape code
+esc == 0 && RT == "\x1b" { esc += 1 }
+
+# ignore some characters for buffering
+esc > 0 && RT == "\x1b" { next }
+esc > 0 && RT == "[" { next }
+
+esc > 0 && RT == ";" {
+ flush_buffer()
+ next
+}
+
+# end of escape code
+esc > 0 && RT == "m" {
+ flush_buffer()
+ reset()
+ next
+}
+
+esc > 0 { buf = buf RT }
+
+# print while not reading escape code
+esc == 0 { printf RT }
+'
+
diff --git a/home/dot_local/share/bin/executable_bgcol b/home/dot_local/share/bin/executable_bgcol
new file mode 100644
index 0000000..276e479
--- /dev/null
+++ b/home/dot_local/share/bin/executable_bgcol
@@ -0,0 +1,9 @@
+#!/bin/sh
+COLOR="$1"
+if [ -z "$COLOR" ] ; then
+ . "$XDG_CACHE_HOME/mode/state/theme"
+ COLOR="$bg"
+fi
+magick -size 1x1 "xc:$COLOR" /tmp/bgcol.png
+feh --no-fehbg --bg-tile /tmp/bgcol.png
+rm /tmp/bgcol.png
diff --git a/home/dot_local/share/bin/executable_bootloader b/home/dot_local/share/bin/executable_bootloader
new file mode 100644
index 0000000..c310d4f
--- /dev/null
+++ b/home/dot_local/share/bin/executable_bootloader
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+bye () {
+ echo "run me as root!"
+ exit 1
+}
+
+[ $(id -g) -ne 0 ] && bye
+
+# mount /boot
+# pacman --noconfirm -S linux
+grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB # --removable
+grub-mkconfig -o /boot/grub/grub.cfg
diff --git a/home/dot_local/share/bin/executable_brightness b/home/dot_local/share/bin/executable_brightness
new file mode 100644
index 0000000..c1c6139
--- /dev/null
+++ b/home/dot_local/share/bin/executable_brightness
@@ -0,0 +1,29 @@
+#!/bin/sh
+case "$*" in
+ +*) action="+" ;;
+ -*) action="-" ;;
+ *) action="=" ;;
+esac
+value="$(echo "$*" | tr -dc '[[:digit:]]')"
+
+if [ -n "$(command -v xbacklight)" ] ; then
+ [ "$action" = "+" ] && action="-inc"
+ [ "$action" = "-" ] && action="-dec"
+ [ "$action" = "=" ] && action="-set"
+
+ fork xbacklight -time 100 -fps 60 $action $value
+
+ exit 0
+
+elif [ -n "$(command -v ddcutil)" ] ; then
+ [ "$action" = "=" ] && action=""
+
+ for bus in 2 3 ; do
+ fork ddcutil --bus="$bus" --skip-ddc-checks --noverify setvcp 10 $action $value
+ done
+
+ exit 0
+
+fi
+exit 1
+
diff --git a/home/dot_local/share/bin/executable_caffeine b/home/dot_local/share/bin/executable_caffeine
new file mode 100644
index 0000000..9901426
--- /dev/null
+++ b/home/dot_local/share/bin/executable_caffeine
@@ -0,0 +1,8 @@
+#!/bin/sh
+xset s off -dpms
+reset() {
+ trap - EXIT
+ xset s default
+}
+trap reset INT
+sleep infinity
diff --git a/home/dot_local/share/bin/executable_cc1080p30 b/home/dot_local/share/bin/executable_cc1080p30
new file mode 100644
index 0000000..6619a17
--- /dev/null
+++ b/home/dot_local/share/bin/executable_cc1080p30
@@ -0,0 +1,2 @@
+#!/bin/sh
+ccpreview 1920 1080 30
diff --git a/home/dot_local/share/bin/executable_cc720p60 b/home/dot_local/share/bin/executable_cc720p60
new file mode 100644
index 0000000..c78fe6d
--- /dev/null
+++ b/home/dot_local/share/bin/executable_cc720p60
@@ -0,0 +1,2 @@
+#!/bin/sh
+ccpreview 1280 720 60
diff --git a/home/dot_local/share/bin/executable_ccpreview b/home/dot_local/share/bin/executable_ccpreview
new file mode 100644
index 0000000..9f13acc
--- /dev/null
+++ b/home/dot_local/share/bin/executable_ccpreview
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+# capture card sysfs device path
+SYSFS_PATH="/devices/pci0000:00/0000:00:14.0/usb1/1-12"
+
+# script args
+WIDTH="$1"
+HEIGHT="$2"
+FRAMERATE="$3"
+
+# find audio device (pulseaudio)
+PULSE_DEVICE="$(pactl -f json list sources | jq \
+ --arg sysfs_path "$SYSFS_PATH" --raw-output \
+ '.[] | select(.properties["sysfs.path"] | . != null and startswith($sysfs_path)) | .name')"
+AUDIO_URL="av://pulse:$PULSE_DEVICE"
+
+# find video device (video4linux)
+V4L_PATH="$(find "/sys$SYSFS_PATH" -name 'video4linux' | head -n1)"
+V4L_PATH="$(find "$V4L_PATH" -name 'index' | xargs grep -l '^0$')"
+V4L_PATH="$(echo "$V4L_PATH" | sed 's#/index$#/uevent#')"
+VIDEO_DEVICE="$(. "$V4L_PATH" ; echo "/dev/$DEVNAME")"
+VIDEO_DEVICE="$(readlink -f "$VIDEO_DEVICE")"
+VIDEO_URL="av://v4l2:$VIDEO_DEVICE"
+
+RESOLUTION="${WIDTH}x${HEIGHT}"
+
+fork() {
+ JOBS="$JOBS $(
+ "$@" > /dev/null 2> /dev/null &
+ echo $!
+ )"
+}
+
+# set capture card v4l parameters
+v4l2-ctl --silent --device "$VIDEO_DEVICE" \
+ --set-parm "$FRAMERATE" \
+ --set-fmt-video "width=$WIDTH,height=$HEIGHT,pixelformat=MJPG" \
+ --set-ctrl "brightness=0,contrast=128,saturation=128,hue=0"
+
+_mpv() {
+ fork mpv \
+ --quiet --msg-level=input=no \
+ --no-config --input-conf=/dev/null \
+ --no-osc --no-border \
+ --no-input-default-bindings --pause=no --force-seekable=no \
+ --cache=no \
+ "$@"
+}
+
+# audio preview
+_mpv \
+ --no-demuxer-thread \
+ --audio-buffer=0 \
+ --cache-pause=no \
+ --interpolation=no \
+ --stream-buffer-size=4k \
+ --profile=low-latency \
+ --speed=1.001 \
+ "$AUDIO_URL"
+
+# video preview
+_mpv \
+ --untimed --no-correct-pts --no-demuxer-thread \
+ --profile=low-latency \
+ --demuxer-lavf-o-add=input_format=mjpeg \
+ --demuxer-lavf-o-add=framerate="$FRAMERATE" \
+ --demuxer-lavf-o-add=resolution="$RESOLUTION" \
+ --demuxer-lavf-o-add=rw_timeout=30000000 \
+ --speed=1.05 \
+ "$VIDEO_URL"
+
+sleep infinity
+kill -9 -- $JOBS
+
diff --git a/home/dot_local/share/bin/executable_clean b/home/dot_local/share/bin/executable_clean
new file mode 100644
index 0000000..8c824f1
--- /dev/null
+++ b/home/dot_local/share/bin/executable_clean
@@ -0,0 +1,3 @@
+#!/bin/sh
+[ -n "$UB_SOCKET" ] && ueberzugpp cmd --socket "$UB_SOCKET" --action remove --identifier PREVIEW
+
diff --git a/home/dot_local/share/bin/executable_darkroom b/home/dot_local/share/bin/executable_darkroom
new file mode 100644
index 0000000..28e2589
--- /dev/null
+++ b/home/dot_local/share/bin/executable_darkroom
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+SCREENS="`xrandr | grep ' connected ' | cut -f1 -d' '`"
+
+mxr() {
+ for screen in $SCREENS; do
+ xrandr --output "$screen" $@
+ done
+}
+
+if [ -e "$XDG_CACHE_HOME/darkroom" ]; then
+ rm -f "$XDG_CACHE_HOME/darkroom"
+ mxr --gamma '1:1:1'
+else
+ mkdir -p "$XDG_CACHE_HOME"
+ touch "$XDG_CACHE_HOME/darkroom"
+ killall -q redshift # redshift hijacks gamma
+ mxr --gamma '1:0.0001:0.0001'
+ lights darkroom
+fi
diff --git a/home/dot_local/share/bin/executable_dbg b/home/dot_local/share/bin/executable_dbg
new file mode 100644
index 0000000..d042ba5
--- /dev/null
+++ b/home/dot_local/share/bin/executable_dbg
@@ -0,0 +1,27 @@
+#!/bin/sh
+GDB="arm-none-eabi-gdb"
+
+found_executable=false
+
+while ! $found_executable ; do
+ [ ! -e build/zephyr ] && break
+ [ ! -e build/zephyr/zephyr.elf ] && break
+ set -- --se="build/zephyr/zephyr.elf" "$@"
+
+ [ -e build/tfm/bin/tfm_s.elf ] && set -- "$@" --eval-command="add-symbol-file build/tfm/bin/tfm_s.elf"
+
+ found_executable=true
+done
+
+while ! $found_executable ; do
+ exec="$(find . -maxdepth 3 -name '*.elf' | head -n1)"
+ [ -n "$exec" ] && set -- "$@" --se="$exec"
+ found_executable=true
+ break
+done
+
+set -- "$@" --eval-command="set jlink autoconnect on"
+set -- "$@" --eval-command="set jlink watchdog on"
+
+exec "$GDB" "$@"
+
diff --git a/home/dot_local/share/bin/executable_dbg_xprop b/home/dot_local/share/bin/executable_dbg_xprop
new file mode 100644
index 0000000..1aa0b0c
--- /dev/null
+++ b/home/dot_local/share/bin/executable_dbg_xprop
@@ -0,0 +1,10 @@
+#!/bin/sh
+# debug xprop
+#
+# runs xprop for all newly created windows (when mouse capture is not
+# available)
+
+xev -root -1 |\
+ grep --line-buffered '^CreateNotify' |\
+ awk --non-decimal-data -F', ' '{ system("sleep 0.1"); printf("%d\n", substr($6, 8)); fflush(stdout) }' |\
+ xargs -I{} sh -c 'echo "------ window data for window {}"; xprop -id {}'
diff --git a/home/dot_local/share/bin/executable_decsync2plain b/home/dot_local/share/bin/executable_decsync2plain
new file mode 100644
index 0000000..745a1c2
--- /dev/null
+++ b/home/dot_local/share/bin/executable_decsync2plain
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+EXEC_NAME="$(basename "$0")"
+EXTENSION="$1"
+
+usage() {
+ cat << EOF
+usage: $EXEC_NAME [EXT]
+
+examples:
+ cd Decsync/calendars/$(uuidgen)/v2/DeviceName-DecSyncCC-$RANDOM ; $EXEC_NAME ics
+
+ cd Decsync/contacts/$(uuidgen)/v2/DeviceName-DecSyncCC-$RANDOM ; $EXEC_NAME vcf
+
+$EXEC_NAME will attempt to guess the appropriate file extension based on the parent folder names. the first parent folder that matches exactly one of the following determines the file extension:
+ calendars -> .ics
+ contacts -> .vcf
+ tasks -> .ics
+
+if no file extension is found and none is explicitly provided, $EXEC_NAME will exit.
+EOF
+}
+
+if [ "$1" = "-h" ] || [ "$1" = "--help" ] ; then
+ usage
+ exit 0
+fi
+
+if [ ! -e sequences ] ; then
+ echo "error: could not find decsync sequences file"
+ exit 1
+fi
+
+# auto detect extension if not explicitly provided
+if [ -z "$EXTENSION" ] ; then
+ EXTENSION="$(realpath "$PWD" | tr '/' '\n' | tac | while read -r folder ; do
+ case "$folder" in
+ calendars|tasks) echo ics ; break ;;
+ contacts) echo vcf ; break ;;
+ esac
+ done)"
+fi
+
+if [ -z "$EXTENSION" ] ; then
+ echo "error: could not detect EXT"
+ exit 1
+fi
+
+COLLECTION_PREFIX="$(jq --raw-output 'if .[2] == "name" then "\(.[3])/" else empty end' info)"
+mkdir -p "$COLLECTION_PREFIX"
+
+jq --raw-output '. | keys | join("\n")' sequences |\
+ sed '/^info$/d' |\
+ tr '\n' '\0' |\
+ xargs -0 -n1 cat |\
+while read -r line ; do
+ filename="$COLLECTION_PREFIX$(echo "$line" | jq --raw-output '.[0][1]').$EXTENSION"
+ echo "$filename"
+ echo "$line" | jq --raw-output '.[3]' > "$filename"
+done
diff --git a/home/dot_local/share/bin/executable_delta b/home/dot_local/share/bin/executable_delta
new file mode 100644
index 0000000..83fb629
--- /dev/null
+++ b/home/dot_local/share/bin/executable_delta
@@ -0,0 +1,4 @@
+#!/bin/sh
+[ -e "$XDG_CACHE_HOME/mode/state/vars" ] && . "$XDG_CACHE_HOME/mode/state/vars"
+[ "$mode" = "light" ] && theme="--light" || theme="--dark"
+exec /bin/delta "$theme" "$@"
diff --git a/home/dot_local/share/bin/executable_discord b/home/dot_local/share/bin/executable_discord
new file mode 100644
index 0000000..d2f894b
--- /dev/null
+++ b/home/dot_local/share/bin/executable_discord
@@ -0,0 +1,3 @@
+#!/bin/sh
+installbd
+exec /usr/bin/discord "$@"
diff --git a/home/dot_local/share/bin/executable_dox-open b/home/dot_local/share/bin/executable_dox-open
new file mode 100644
index 0000000..493c435
--- /dev/null
+++ b/home/dot_local/share/bin/executable_dox-open
@@ -0,0 +1,31 @@
+#!/bin/node
+
+import { glob, readFile } from 'node:fs/promises';
+import { spawn } from 'node:child_process';
+import { argv, chdir, cwd } from 'node:process';
+import { join } from 'node:path';
+
+argv.shift();
+argv.shift();
+chdir("search");
+
+var symbols = {};
+for await (const chunk of glob('all_*.js')) {
+ const contents = await readFile(chunk);
+ const searchData = eval(`${contents}; searchData`);
+ const here = cwd();
+
+ for (const [ _id, [ symbol, ...entry ] ] of searchData) {
+ symbols[symbol] = entry.map(e => `file://${join(here, e[0])}`);
+ }
+}
+
+for (const symbol of argv) {
+ if (!(symbol in symbols)) {
+ console.error(`No doxygen index for symbol \`${symbol}\``);
+ continue;
+ }
+ const urls = symbols[symbol];
+ spawn('xdg-open', [ urls[0], ]);
+}
+
diff --git a/home/dot_local/share/bin/executable_editor b/home/dot_local/share/bin/executable_editor
new file mode 100644
index 0000000..d4bf664
--- /dev/null
+++ b/home/dot_local/share/bin/executable_editor
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec nvim -p "$@"
diff --git a/home/dot_local/share/bin/executable_extmon b/home/dot_local/share/bin/executable_extmon
new file mode 100644
index 0000000..dcaa0b3
--- /dev/null
+++ b/home/dot_local/share/bin/executable_extmon
@@ -0,0 +1,26 @@
+#!/bin/sh
+out_int="eDP1"
+out_ext="HDMI1"
+res_int="1366x768"
+res_ext="1920x1080"
+
+off() {
+ xrandr \
+ --output "$out_ext" --off \
+ --output "$out_int" --mode "$res_int" --panning "$res_int" --transform none --primary \
+ --fb "$res_int"
+}
+
+on() {
+ xrandr \
+ --fb "$res_ext" \
+ --output "$out_int" --mode "$res_int" --panning "$res_ext" --scale-from "$res_ext" \
+ --output "$out_ext" --mode "$res_ext" --scale 1x1 --same-as "$out_int" --primary
+}
+
+[ "$1" = "on" ] && on
+[ "$1" = "off" ] && off
+
+# reload polybar (doesn't adjust to new resolution automatically)
+fork polybar-msg cmd restart
+
diff --git a/home/dot_local/share/bin/executable_fcitx5-temp-off b/home/dot_local/share/bin/executable_fcitx5-temp-off
new file mode 100644
index 0000000..b2f8ea9
--- /dev/null
+++ b/home/dot_local/share/bin/executable_fcitx5-temp-off
@@ -0,0 +1,8 @@
+#!/bin/sh
+mkdir -p "$XDG_DATA_HOME/fcitx5"
+fcitx5-remote > "$XDG_DATA_HOME/fcitx5/state"
+fcitx5-remote -n > "$XDG_DATA_HOME/fcitx5/ime_name"
+
+fcitx5-remote -c
+fcitx5-remote -s 'keyboard-us'
+
diff --git a/home/dot_local/share/bin/executable_fcitx5-temp-restore b/home/dot_local/share/bin/executable_fcitx5-temp-restore
new file mode 100644
index 0000000..d00b11c
--- /dev/null
+++ b/home/dot_local/share/bin/executable_fcitx5-temp-restore
@@ -0,0 +1,7 @@
+#!/bin/sh
+[ ! -e "$XDG_DATA_HOME/fcitx5/state" ] && exit
+[ ! -e "$XDG_DATA_HOME/fcitx5/ime_name" ] && exit
+
+[ `cat "$XDG_DATA_HOME/fcitx5/state"` = "1" ] && fcitx5-remote -c
+[ `cat "$XDG_DATA_HOME/fcitx5/state"` = "2" ] && fcitx5-remote -o
+cat "$XDG_DATA_HOME/fcitx5/ime_name" | xargs fcitx5-remote -s
diff --git a/home/dot_local/share/bin/executable_ffmpeg-resize b/home/dot_local/share/bin/executable_ffmpeg-resize
new file mode 100644
index 0000000..4270278
--- /dev/null
+++ b/home/dot_local/share/bin/executable_ffmpeg-resize
@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# Re-encode a video to a target size in MB.
+# Example:
+# ./this_script.sh video.mp4 15
+
+T_SIZE="$2" # target size in MB
+T_FILE="${1%.*}-$2MB.mp4" # filename out
+
+# Original duration in seconds
+O_DUR=$(\
+ ffprobe \
+ -v error \
+ -show_entries format=duration \
+ -of csv=p=0 "$1")
+
+# Original audio rate
+O_ARATE=$(\
+ ffprobe \
+ -v error \
+ -select_streams a:0 \
+ -show_entries stream=bit_rate \
+ -of csv=p=0 "$1")
+
+# Original audio rate in KiB/s
+O_ARATE=$(\
+ awk \
+ -v arate="$O_ARATE" \
+ 'BEGIN { printf "%.0f", (arate / 1024) }')
+
+# Target size is required to be less than the size of the original audio stream
+T_MINSIZE=$(\
+ awk \
+ -v arate="$O_ARATE" \
+ -v duration="$O_DUR" \
+ 'BEGIN { printf "%.2f", ( (arate * duration) / 8192 ) }')
+
+# Equals 1 if target size is ok, 0 otherwise
+IS_MINSIZE=$(\
+ awk \
+ -v size="$T_SIZE" \
+ -v minsize="$T_MINSIZE" \
+ 'BEGIN { print (minsize < size) }')
+
+# Give useful information if size is too small
+if [[ $IS_MINSIZE -eq 0 ]]; then
+ printf "%s\n" "Target size ${T_SIZE}MB is too small!" >&2
+ printf "%s %s\n" "Try values larger than" "${T_MINSIZE}MB" >&2
+ exit 1
+fi
+
+# Set target audio bitrate
+T_ARATE=$O_ARATE
+
+
+# Calculate target video rate - MB -> KiB/s
+T_VRATE=$(\
+ awk \
+ -v size="$T_SIZE" \
+ -v duration="$O_DUR" \
+ -v audio_rate="$O_ARATE" \
+ 'BEGIN { print ( ( size * 8192.0 ) / ( 1.048576 * duration ) - audio_rate) }')
+
+# Perform the conversion
+ffmpeg \
+ -y \
+ -i "$1" \
+ -c:v libx264 \
+ -b:v "$T_VRATE"k \
+ -pass 1 \
+ -an \
+ -f mp4 \
+ /dev/null \
+&& \
+ffmpeg \
+ -i "$1" \
+ -c:v libx264 \
+ -b:v "$T_VRATE"k \
+ -pass 2 \
+ -c:a aac \
+ -b:a "$T_ARATE"k \
+ "$T_FILE"
diff --git a/home/dot_local/share/bin/executable_folder2cd b/home/dot_local/share/bin/executable_folder2cd
new file mode 100644
index 0000000..558c6ab
--- /dev/null
+++ b/home/dot_local/share/bin/executable_folder2cd
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+FILEEXT="flac"
+set -e
+
+convert() {
+ wav="${1%.flac}-cd.wav"
+ echo "ffmpeg -loglevel warning -y -i \"$1\" -sample_fmt s16 -ar 44100 \"$wav\""
+ ffmpeg -loglevel warning -y -i "$1" -sample_fmt s16 -ar 44100 "$wav"
+}
+
+export -f convert
+parallel -j4 convert ::: *.$FILEEXT
+
+FILES=`find . -name '*-cd.wav' -printf '%f\n' | sort -n`
+echo "$FILES" | xargs -d"\n" -t wodim -sao -audio -pad speed=20
+
+echo "wodim -eject"
+wodim -eject
+
+echo "rm -f *-cd.wav"
+rm -f *-cd.wav
+
diff --git a/home/dot_local/share/bin/executable_fontfix b/home/dot_local/share/bin/executable_fontfix
new file mode 100644
index 0000000..1c9beaf
--- /dev/null
+++ b/home/dot_local/share/bin/executable_fontfix
@@ -0,0 +1,39 @@
+#!/bin/python3
+
+import os
+import sys
+from pathlib import Path
+
+from fontTools import ttLib
+
+PROPID_FAMILY = 1
+PROPID_SUBFAMILY = 2
+PROPID_FULLNAME = 4
+PROPID_PSNAME = 6
+
+PLATFORM_MS = 1
+PLATFORM_MAC = 3
+
+# see
+# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
+# for magic numbers
+
+for folder in Path(".").iterdir():
+ print(f"{folder}/")
+ family_name = str(folder.stem)
+ for file in folder.glob("*.ttf"):
+ subfamily_name = file.stem.removeprefix(family_name).strip()
+ with ttLib.TTFont(file) as ttf:
+ nametable = ttf["name"]
+ full_name = f"{family_name} {subfamily_name}"
+ postscript_name = f"{family_name}-{subfamily_name}".replace(" ", "")
+ nametable.setName(family_name, PROPID_FAMILY, PLATFORM_MS, 0, 0)
+ nametable.setName(family_name, PROPID_FAMILY, PLATFORM_MAC, 1, 1033)
+ nametable.setName(subfamily_name, PROPID_SUBFAMILY, PLATFORM_MS, 0, 0)
+ nametable.setName(subfamily_name, PROPID_SUBFAMILY, PLATFORM_MAC, 1, 1033)
+ nametable.setName(full_name, PROPID_FULLNAME, PLATFORM_MS, 0, 0)
+ nametable.setName(full_name, PROPID_FULLNAME, PLATFORM_MAC, 1, 1033)
+ nametable.setName(postscript_name, PROPID_PSNAME, PLATFORM_MS, 0, 0)
+ nametable.setName(postscript_name, PROPID_PSNAME, PLATFORM_MAC, 1, 1033)
+ ttf.save(file)
+ print(f" {file.name}: [{family_name} :: {subfamily_name}]")
diff --git a/home/dot_local/share/bin/executable_fork b/home/dot_local/share/bin/executable_fork
new file mode 100644
index 0000000..63e7541
--- /dev/null
+++ b/home/dot_local/share/bin/executable_fork
@@ -0,0 +1,2 @@
+#!/bin/sh
+(setsid "$@" > /dev/null 2> /dev/null &)
diff --git a/home/dot_local/share/bin/executable_fv b/home/dot_local/share/bin/executable_fv
new file mode 100644
index 0000000..5ce4f2e
--- /dev/null
+++ b/home/dot_local/share/bin/executable_fv
@@ -0,0 +1,2 @@
+#!/bin/sh
+fzf --multi --print0 | exec xargs -r0 $EDITOR
diff --git a/home/dot_local/share/bin/executable_gpg-git b/home/dot_local/share/bin/executable_gpg-git
new file mode 100644
index 0000000..df0feca
--- /dev/null
+++ b/home/dot_local/share/bin/executable_gpg-git
@@ -0,0 +1,4 @@
+#!/bin/sh
+GPG_KEY_ID="$GPG_ID_GIT" # see ~/.profile
+GPG_KEY_PASSPHRASE="$(pass "gpg/$GPG_KEY_ID.asc" | head -n1)"
+gpg --batch --no-tty --pinentry-mode loopback --passphrase "$GPG_KEY_PASSPHRASE" "$@"
diff --git a/home/dot_local/share/bin/executable_helium-browser b/home/dot_local/share/bin/executable_helium-browser
new file mode 100644
index 0000000..96e1864
--- /dev/null
+++ b/home/dot_local/share/bin/executable_helium-browser
@@ -0,0 +1,5 @@
+#!/bin/sh
+/usr/bin/helium-browser \
+ --load-extension="$XDG_CACHE_HOME/mode/chromium" \
+ --password-store=basic \
+ "$@"
diff --git a/home/dot_local/share/bin/executable_hide b/home/dot_local/share/bin/executable_hide
new file mode 100644
index 0000000..cb49be0
--- /dev/null
+++ b/home/dot_local/share/bin/executable_hide
@@ -0,0 +1,4 @@
+#!/bin/sh
+for file in "$@" ; do
+ mv "$file" ".$file"
+done
diff --git a/home/dot_local/share/bin/executable_icalcat b/home/dot_local/share/bin/executable_icalcat
new file mode 100644
index 0000000..2e89afd
--- /dev/null
+++ b/home/dot_local/share/bin/executable_icalcat
@@ -0,0 +1,12 @@
+#!/bin/sh
+cat << "EOF"
+BEGIN:VCALENDAR
+VERSION:2.0
+EOF
+
+cat "$@" | sed -n -e '/^BEGIN:VEVENT$/,/^END:VEVENT$/p'
+
+cat << "EOF"
+END:VCALENDAR
+EOF
+
diff --git a/home/dot_local/share/bin/executable_installbd b/home/dot_local/share/bin/executable_installbd
new file mode 100644
index 0000000..ae17002
--- /dev/null
+++ b/home/dot_local/share/bin/executable_installbd
@@ -0,0 +1,20 @@
+#!/bin/sh
+discord_path="$(dirname "$(find "$XDG_CONFIG_HOME/discord" -name core.asar)")"
+discord_version="$(echo "$discord_path" | tr '/' '\n' | tac | sed -n '/^[0-9.]\+$/p' | head -n1)"
+betterdiscord_path="$XDG_CONFIG_HOME/BetterDiscord/data/betterdiscord.asar"
+cache_file="$XDG_CACHE_HOME/bdversion"
+
+if [ "$discord_path" -nt "$betterdiscord_path" ] ; then
+ echo "download betterdiscord.asar"
+ curl -sLo - 'https://betterdiscord.app/Download/betterdiscord.asar' > "$betterdiscord_path"
+fi
+if ! grep "$(basename "$betterdiscord_path")" "$discord_path/index.js" > /dev/null ; then
+ echo "patch discord desktop core index.js"
+ printf 'require("%s");\n%s' "$betterdiscord_path" "$(cat "$discord_path/index.js")" > "$discord_path/index.js"
+fi
+
+# store discord version used for this install
+mkdir -p "$(dirname "$cache_file")"
+echo "$discord_version" > "$cache_file"
+
+echo "done!"
diff --git a/home/dot_local/share/bin/executable_java b/home/dot_local/share/bin/executable_java
new file mode 100644
index 0000000..06fdb61
--- /dev/null
+++ b/home/dot_local/share/bin/executable_java
@@ -0,0 +1,7 @@
+#!/bin/sh
+export _JAVA_AWT_WM_NONREPARENTING=1
+exec /usr/bin/java \
+ -Djava.util.prefs.userRoot="$XDG_CONFIG_HOME/java" \
+ -Dawt.useSystemAAFontSettings=on \
+ -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel \
+ "$@"
diff --git a/home/dot_local/share/bin/executable_kbindicator b/home/dot_local/share/bin/executable_kbindicator
new file mode 100644
index 0000000..6ffcd53
--- /dev/null
+++ b/home/dot_local/share/bin/executable_kbindicator
@@ -0,0 +1,19 @@
+#!/bin/sh
+query_kb_layout() {
+ CONTROLLER="$(qdbus 'org.fcitx.Fcitx5' '/controller' 'org.fcitx.Fcitx.Controller1.CurrentInputMethod')"
+ case $CONTROLLER in
+ "keyboard-us") echo "英数" ;;
+ "keyboard-us-intl") echo "英数(国際)" ;;
+ "mozc") echo "日本語" ;;
+ *) ;;
+ esac
+}
+
+query_kb_layout
+
+dbus-monitor --address "$(fcitx5-remote -a)" "member='SetCurrentIM',destination='org.fcitx.Fcitx5'" |\
+ grep --line-buffered 'SetCurrentIM' |\
+ while read -r line ; do
+ query_kb_layout
+ done
+
diff --git a/home/dot_local/share/bin/executable_khal b/home/dot_local/share/bin/executable_khal
new file mode 100644
index 0000000..71e5392
--- /dev/null
+++ b/home/dot_local/share/bin/executable_khal
@@ -0,0 +1,16 @@
+#!/bin/sh
+CFG="$XDG_CONFIG_HOME/khal/config"
+if [ "$CFG" -ot "$XDG_CONFIG_HOME/khal/config.sh" ] ; then
+ cat - "$XDG_CONFIG_HOME/khal/base" << "EOF" > "$CFG"
+# THIS FILE IS AUTO-GENERATED, EDIT config_gen OR base INSTEAD!!!
+
+EOF
+ "$XDG_CONFIG_HOME/khal/config_gen" >> "$CFG"
+fi
+
+# aliases
+[ "$1" = "i" ] && { shift ; set -- interactive "$@" ; }
+[ "$1" = "l" ] && { shift ; set -- list "$@" ; }
+
+exec /usr/bin/khal "$@"
+
diff --git a/home/dot_local/share/bin/executable_khard b/home/dot_local/share/bin/executable_khard
new file mode 100644
index 0000000..cb02889
--- /dev/null
+++ b/home/dot_local/share/bin/executable_khard
@@ -0,0 +1,12 @@
+#!/bin/sh
+CFG="$XDG_CONFIG_HOME/khard/khard.conf"
+if [ "$CFG" -ot "$XDG_CONFIG_HOME/khard/config.sh" ] ; then
+ cat - "$XDG_CONFIG_HOME/khard/base" << "EOF" > "$CFG"
+# THIS FILE IS AUTO-GENERATED, EDIT config_gen OR base INSTEAD!!!
+
+EOF
+ "$XDG_CONFIG_HOME/khard/config_gen" >> "$CFG"
+fi
+
+exec /usr/bin/khard "$@"
+
diff --git a/home/dot_local/share/bin/executable_labels2lrc b/home/dot_local/share/bin/executable_labels2lrc
new file mode 100644
index 0000000..c8abc1c
--- /dev/null
+++ b/home/dot_local/share/bin/executable_labels2lrc
@@ -0,0 +1,30 @@
+#!/bin/python3
+
+import re
+import sys
+
+for line in sys.stdin:
+ line = line.rstrip("\n")
+ fields = line.split("\t")
+
+ if len(fields) < 3:
+ continue
+
+ time = fields[0]
+
+ # Equivalent of:
+ # gensub(/([0-9]+)\.([0-9]{,2})([0-9]*)/, "\\1\\2.\\3", "g", time)
+ time = re.sub(r'(\d+)\.(\d{0,2})(\d*)', r'\1\2.\3', time)
+
+ # AWK rounds by adding 0.5 then truncating.
+ time = int(float(time) + 0.5)
+
+ millis = time % 100
+ time //= 100
+
+ seconds = time % 60
+ time //= 60
+
+ minutes = time % 100
+
+ print(f"[{minutes:02d}:{seconds:02d}.{millis:02d}]{fields[2]}")
diff --git a/home/dot_local/share/bin/executable_latex-doc b/home/dot_local/share/bin/executable_latex-doc
new file mode 100644
index 0000000..6d785f1
--- /dev/null
+++ b/home/dot_local/share/bin/executable_latex-doc
@@ -0,0 +1,4 @@
+#!/bin/sh
+set -e
+cd /usr/share/doc/texlive/latex
+fork xdg-open "$(find . -name '*.pdf' | fzf)"
diff --git a/home/dot_local/share/bin/executable_lf b/home/dot_local/share/bin/executable_lf
new file mode 100644
index 0000000..430ae0b
--- /dev/null
+++ b/home/dot_local/share/bin/executable_lf
@@ -0,0 +1,23 @@
+#!/bin/sh
+lf=/usr/bin/lf
+
+UB_PID=0
+UB_SOCKET=""
+UB_PID_FILE="$(mktemp)"
+
+cleanup() {
+ exec 3>&-
+ ueberzugpp cmd -s "$UB_SOCKET" -a exit
+}
+
+# don't try to use ueberzug over ssh
+[ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ] && exec $lf "$@"
+
+ueberzugpp layer --silent --no-stdin --use-escape-codes --pid-file "$UB_PID_FILE" >/dev/null
+UB_PID="$(cat "$UB_PID_FILE")"
+rm -f "$UB_PID_FILE"
+UB_SOCKET="/tmp/ueberzugpp-$UB_PID.socket"
+export UB_PID UB_SOCKET
+trap cleanup HUP INT QUIT TERM EXIT
+$lf "$@" 3>&-
+
diff --git a/home/dot_local/share/bin/executable_lights b/home/dot_local/share/bin/executable_lights
new file mode 100644
index 0000000..69ea06c
--- /dev/null
+++ b/home/dot_local/share/bin/executable_lights
@@ -0,0 +1,5 @@
+#!/bin/sh
+cmd="$1"
+[ -z "$cmd" ] && cmd="toggle"
+curl -X POST "$HASS_SERVER/api/webhook/$cmd"
+
diff --git a/home/dot_local/share/bin/executable_lock b/home/dot_local/share/bin/executable_lock
new file mode 100644
index 0000000..988c0ec
--- /dev/null
+++ b/home/dot_local/share/bin/executable_lock
@@ -0,0 +1,4 @@
+#!/bin/sh
+xset s 15 15
+slock
+xset s default
diff --git a/home/dot_local/share/bin/executable_lorem b/home/dot_local/share/bin/executable_lorem
new file mode 100644
index 0000000..5ef3171
--- /dev/null
+++ b/home/dot_local/share/bin/executable_lorem
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+lorem_text="$(cat << EOF
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Gravida dictum fusce ut placerat orci nulla pellentesque. Laoreet id donec ultrices tincidunt arcu. Tortor aliquam nulla facilisi cras fermentum odio eu feugiat. A scelerisque purus semper eget duis at tellus. A iaculis at erat pellentesque adipiscing commodo elit at imperdiet. Arcu bibendum at varius vel pharetra vel turpis nunc eget. Euismod in pellentesque massa placerat duis. Lorem ipsum dolor sit amet consectetur adipiscing elit. Ultrices in iaculis nunc sed augue lacus. Vestibulum mattis ullamcorper velit sed. Adipiscing diam donec adipiscing tristique risus nec feugiat in fermentum. Elit pellentesque habitant morbi tristique senectus et. Ullamcorper sit amet risus nullam eget felis eget nunc lobortis. Vestibulum sed arcu non odio. Vestibulum sed arcu non odio euismod lacinia. Maecenas pharetra convallis posuere morbi leo urna molestie at. Sit amet consectetur adipiscing elit duis tristique sollicitudin. Curabitur gravida arcu ac tortor dignissim convallis aenean et. Nunc sed blandit libero volutpat sed cras ornare arcu. Eu nisl nunc mi ipsum faucibus vitae aliquet nec. Vehicula ipsum a arcu cursus. Arcu felis bibendum ut tristique et. Lobortis scelerisque fermentum dui faucibus in ornare. In arcu cursus euismod quis viverra nibh cras pulvinar. Integer malesuada nunc vel risus. Elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus. Viverra nam libero justo laoreet. Felis bibendum ut tristique et. Neque volutpat ac tincidunt vitae semper quis. Semper feugiat nibh sed pulvinar proin gravida hendrerit. Arcu bibendum at varius vel pharetra vel turpis. Tincidunt arcu non sodales neque. Id aliquet risus feugiat in ante metus. Eget magna fermentum iaculis eu non diam. Tempor id eu nisl nunc mi ipsum. Bibendum enim facilisis gravida neque convallis a cras semper. Parturient montes nascetur ridiculus mus. Tortor pretium viverra suspendisse potenti nullam ac. Mauris vitae ultricies leo integer malesuada nunc. Integer eget aliquet nibh praesent. Lorem ipsum dolor sit amet consectetur. Sit amet consectetur adipiscing elit pellentesque habitant. Habitant morbi tristique senectus et netus et malesuada. Cursus metus aliquam eleifend mi in nulla posuere sollicitudin. Tincidunt dui ut ornare lectus sit amet est. Elementum curabitur vitae nunc sed velit dignissim sodales. Senectus et netus et malesuada fames ac turpis egestas sed. Scelerisque viverra mauris in aliquam sem fringilla ut. Nunc eget lorem dolor sed viverra ipsum nunc aliquet. Egestas egestas fringilla phasellus faucibus scelerisque eleifend donec. Id neque aliquam vestibulum morbi blandit cursus. Enim tortor at auctor urna nunc id cursus metus. Dignissim convallis aenean et tortor at risus viverra. Et malesuada fames ac turpis egestas. Id cursus metus aliquam eleifend mi in nulla posuere. Egestas dui id ornare arcu odio. At elementum eu facilisis sed odio. Ultrices vitae auctor eu augue ut lectus arcu bibendum at. Amet volutpat consequat mauris nunc congue nisi vitae. Enim lobortis scelerisque fermentum dui faucibus in ornare quam. Libero id faucibus nisl tincidunt eget. Amet risus nullam eget felis eget. Ultricies mi eget mauris pharetra. Magnis dis parturient montes nascetur ridiculus mus mauris vitae. Lectus magna fringilla urna porttitor rhoncus dolor purus. Elementum eu facilisis sed odio morbi quis commodo odio. Tincidunt vitae semper quis lectus. Sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu. Pretium viverra suspendisse potenti nullam ac. Sed egestas egestas fringilla phasellus faucibus scelerisque eleifend donec. Tortor consequat id porta nibh venenatis. Elit at imperdiet dui accumsan sit amet nulla. Sem viverra aliquet eget sit. At in tellus integer feugiat scelerisque varius morbi enim. Dictum fusce ut placerat orci nulla pellentesque. Sed risus pretium quam vulputate dignissim. Tincidunt dui ut ornare lectus sit amet est placerat in. Urna nec tincidunt praesent semper feugiat.
+EOF
+)"
+
+if [ -z "$1" ]; then
+ echo "$lorem_text"
+else
+ echo "$lorem_text" | cut -f1-$1 --delimiter=" "
+fi
diff --git a/home/dot_local/share/bin/executable_lrc2labels b/home/dot_local/share/bin/executable_lrc2labels
new file mode 100644
index 0000000..a23b299
--- /dev/null
+++ b/home/dot_local/share/bin/executable_lrc2labels
@@ -0,0 +1,7 @@
+#!/bin/gawk -f
+match($0, /^\[([0-9]{2}):([0-9]{2}\.[0-9]{2})\](.*)/, group) {
+ time = group[1] * 60 + group[2]
+ lyric = group[3]
+
+ printf("%.2f\t%.2f\t%s\n", time, time, lyric)
+}
diff --git a/home/dot_local/share/bin/executable_mbsync b/home/dot_local/share/bin/executable_mbsync
new file mode 100644
index 0000000..3f6aa09
--- /dev/null
+++ b/home/dot_local/share/bin/executable_mbsync
@@ -0,0 +1,2 @@
+#!/bin/sh
+/usr/bin/mbsync --config "$XDG_CONFIG_HOME/mbsyncrc" "$@"
diff --git a/home/dot_local/share/bin/executable_mk b/home/dot_local/share/bin/executable_mk
new file mode 100644
index 0000000..051235a
--- /dev/null
+++ b/home/dot_local/share/bin/executable_mk
@@ -0,0 +1,87 @@
+#!/bin/sh
+progname="$(basename "$0")"
+showmode() {
+ ! [ -n "$FROM_PROMPT" ] && return
+ ! [ -t 1 ] && return
+
+ mode=" ($1)"
+ col=$(( $(tput cols) - $(echo "$mode" | wc -L) + 1 ))
+ printf '\e[1A\e['$col'G\e[1;30m%s\e[0m\n' "$mode"
+}
+
+make_tags() {
+ build_dir="${1-build}"
+
+ if [ -e "$build_dir/domains.yaml" ] ; then
+ yaml2json "$build_dir/domains.yaml" | jq --raw-output '. as $r | $r.flash_order[] as $n | $r.domains[] | select(.name == $n) | .build_dir' | while IFS= read -r build_dir; do
+ echo "Processing: $build_dir"
+ done
+ fi
+
+}
+
+mode_west() {
+ showmode 'west'
+ if [ -z "$*" ] ; then
+ set -- build
+ [ -e sysbuild ] || [ -e sysbuild.conf ] && set -- "$@" --sysbuild
+ fi
+ west "$@"
+ ec=$?
+
+ mktags build &
+
+ exit $ec
+}
+path="."
+for x in $(seq 10) ; do
+ [ -e "$path/.west" ] && mode_west "$@"
+ [ "$path" -ef "$path/.." ] && break
+ path="$path/.."
+done
+
+mode_cmake() {
+ showmode 'cmake'
+ builddir="build"
+
+ [ "$*" = "clean" ] && exec rm -rf "$builddir"
+
+ export CMAKE_GENERATOR="Ninja"
+
+ # re-run configuration if fresh or CMakeLists was changed
+ if [ ! -e "$builddir/build.ninja" ] ||
+ [ "CMakeLists.txt" -nt "$builddir/build.ninja" ] ; then
+ cmake --log-level WARNING -B "$builddir" || exit $?
+ fi
+
+ # build
+ cmake --build "$builddir" -- "$@"
+ ec=$?
+
+ # generate vim tags (continue after mk exits)
+ mktags "$builddir" &
+
+ exit $ec
+}
+[ -e "CMakeLists.txt" ] && mode_cmake "$@"
+
+mode_make() {
+ showmode 'make'
+ exec make "$@"
+}
+[ -e "makefile" ] && mode_make "$@"
+[ -e "Makefile" ] && mode_make "$@"
+
+mode_latexmk() {
+ showmode 'latexmk'
+
+ [ "$*" = "clean" ] && exec latexmk -c
+
+ exec latexmk "$@"
+}
+[ -e "latexmkrc" ] && mode_latexmk "$@"
+[ -e ".latexmkrc" ] && mode_latexmk "$@"
+
+echo "$progname: unable to determine project build system!" >&2
+exit 1
+
diff --git a/home/dot_local/share/bin/executable_mktags b/home/dot_local/share/bin/executable_mktags
new file mode 100644
index 0000000..2daf25c
--- /dev/null
+++ b/home/dot_local/share/bin/executable_mktags
@@ -0,0 +1,61 @@
+#!/bin/python3
+
+from subprocess import run, DEVNULL
+from pathlib import Path
+from dataclasses import dataclass
+from argparse import ArgumentParser
+
+@dataclass
+class Options:
+ build_dir: Path
+
+def parse_arguments() -> Options:
+ parser = ArgumentParser(prog="mktags", description="generate vim tags file from build directory")
+ parser.add_argument("build_dir", type=Path, help="build directory", nargs='?', default=Path("build"))
+
+ options = parser.parse_args()
+ return Options(**vars(options))
+
+def index_files(build_dir: Path) -> list[Path]:
+ lines = [line for line in run(("ninja", "-C", str(build_dir), "-t", "deps"), text=True, capture_output=True).stdout.splitlines()]
+ lines = [line.lstrip() for line in lines if line.startswith(" ")]
+ return [Path(line) for line in lines]
+
+def get_sysbuild_files(domains_yml: Path) -> list[Path]:
+ if not domains_yml.exists():
+ return []
+
+ from yaml import safe_load
+ yaml = safe_load(domains_yml.read_text())
+
+ build_dirs = [next(Path(domain['build_dir']) for domain in yaml['domains'] if domain['name'] == domain_name) for domain_name in yaml['flash_order']]
+
+ files: set[Path] = set()
+ for dir in build_dirs:
+ files.update(get_files(dir))
+
+ return list(files)
+
+def get_files(build_dir: Path) -> list[Path]:
+ files = []
+
+ files += get_sysbuild_files(build_dir.joinpath("domains.yaml"))
+ files += index_files(build_dir)
+
+ return files
+
+def gen_tags(files: list[Path]) -> str:
+ filelist = "\n".join(str(file) for file in files)
+ return run(("ctags", "-L", "-", "-f", "-"), text=True, input=filelist, capture_output=True).stdout
+
+if __name__ == "__main__":
+ options = parse_arguments()
+
+ files = get_files(options.build_dir)
+
+ files = list(set(files))
+
+ tags = gen_tags(files)
+
+ options.build_dir.joinpath("tags").write_text(tags)
+
diff --git a/home/dot_local/share/bin/executable_mozc-config-filter b/home/dot_local/share/bin/executable_mozc-config-filter
new file mode 100644
index 0000000..522275a
--- /dev/null
+++ b/home/dot_local/share/bin/executable_mozc-config-filter
@@ -0,0 +1,6 @@
+#!/bin/sh
+yay_dir="$(yay -Pg | jq --raw-output .buildDir)"
+config_proto="$(mktemp)"
+git --git-dir="$yay_dir/mozc-ut/mozc" show HEAD:src/protocol/config.proto > "$config_proto"
+protoc --proto_path /tmp --decode=mozc.config.Config "$config_proto" < "$1"
+rm -f "$config_proto"
diff --git a/home/dot_local/share/bin/executable_nginx-dev b/home/dot_local/share/bin/executable_nginx-dev
new file mode 100644
index 0000000..40e73ad
--- /dev/null
+++ b/home/dot_local/share/bin/executable_nginx-dev
@@ -0,0 +1,86 @@
+#!/bin/sh
+folder="$PWD"
+port=8080
+try_files='/$uri /$uri.html /$uri/index.html =404'
+access_log='/dev/stdout'
+cache_control='
+ proxy_store off;
+ proxy_cache off;
+ add_header Last-Modified $date_gmt;
+ add_header Cache-Control "private no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
+ if_modified_since off;
+ expires off;
+ etag off;
+'
+
+usage() {
+ cat << EOF
+usage: $(basename "$0") [options] [folder]
+
+options:
+ -p PORT host server on port PORT (default $port)
+ -t STR set try_files pattern to STR (default '$try_files')
+ -C enable server cache (disabled by default)
+ -v verbose mode (prints config before starting server)
+ -q quiet mode (disable access_log)
+ -x automatically open a browser
+ -h show this help
+EOF
+exit $1
+}
+
+ARGC=0
+while getopts hvp:Ct:qx OPT; do
+ [ $OPTIND -gt $ARGC ] && ARGC=$OPTIND
+ case $OPT in
+ h) usage 0 ;;
+ p) port="$OPTARG" ;;
+ t) try_files="$OPTARG" ;;
+ v) print_config=1 ;;
+ C) cache_control='' ;;
+ q) access_log="/dev/null" ;;
+ x) open_browser=1 ;;
+ \?|*) usage 1 ;;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+[ $# -ge 1 ] && folder="$(readlink -f "$1")"
+
+config="$(mktemp)"
+pidfile="$(mktemp)"
+cat << EOF > "$config"
+worker_processes 1;
+daemon off;
+pid $pidfile;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ types_hash_max_size 4096;
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ $cache_control
+
+ access_log $access_log;
+
+ server {
+ listen $port;
+ listen [::]:$port;
+
+ root $folder;
+
+ location / {
+ try_files $try_files;
+ }
+ }
+}
+EOF
+[ $print_config ] && cat "$config"
+[ $open_browser ] && (xdg-open "http://localhost:$port" 1> /dev/null 2> /dev/null &)
+nginx -c "$config"
+rm -f "$config" "$pidfile"
+
diff --git a/home/dot_local/share/bin/executable_open b/home/dot_local/share/bin/executable_open
new file mode 100644
index 0000000..7856488
--- /dev/null
+++ b/home/dot_local/share/bin/executable_open
@@ -0,0 +1,12 @@
+#!/bin/sh
+case "$(file --mime-type -Lb "$1")" in
+ text/*)
+ exec $EDITOR -- "$@"
+ ;;
+ *)
+ for file in "$@"; do
+ fork xdg-open "$file"
+ done
+ ;;
+esac
+
diff --git a/home/dot_local/share/bin/executable_panic b/home/dot_local/share/bin/executable_panic
new file mode 100644
index 0000000..7455786
--- /dev/null
+++ b/home/dot_local/share/bin/executable_panic
@@ -0,0 +1,36 @@
+#!/bin/sh
+silent() {
+ "$@" 1>/dev/null 2> /dev/null &
+}
+
+on() {
+ # clear desktop
+ silent i3-msg focus output primary
+ silent i3-msg workspace 'panic1'
+ silent i3-msg focus output right
+ silent i3-msg workspace 'panic2'
+
+ # stop playing media (if any)
+ silent mpc pause
+ silent playerctl -a pause
+
+ # mute mic/headphones
+ silent pactl set-sink-mute @DEFAULT_SINK@ true
+ silent pactl set-source-mute @DEFAULT_SOURCE@ true
+}
+
+off() {
+ # unmute mic/headphones
+ silent pactl set-sink-mute @DEFAULT_SINK@ false
+ silent pactl set-source-mute @DEFAULT_SOURCE@ false
+}
+
+panicfile="$XDG_CACHE_HOME/panic"
+if [ -e "$panicfile" ] ; then
+ rm "$panicfile"
+ off
+else
+ touch "$panicfile"
+ on
+fi
+
diff --git a/home/dot_local/share/bin/executable_pause b/home/dot_local/share/bin/executable_pause
new file mode 100644
index 0000000..8eedbfb
--- /dev/null
+++ b/home/dot_local/share/bin/executable_pause
@@ -0,0 +1,10 @@
+#!/bin/sh
+ec=0
+if [ $# -ge 1 ] ; then
+ "$@"
+ ec=$?
+fi
+printf "Press enter to exit..."
+read
+exit $ec
+
diff --git a/home/dot_local/share/bin/executable_pdfsize b/home/dot_local/share/bin/executable_pdfsize
new file mode 100644
index 0000000..14f940d
--- /dev/null
+++ b/home/dot_local/share/bin/executable_pdfsize
@@ -0,0 +1,2 @@
+#!/bin/sh
+pdfinfo -box "$1" | awk '/^Page size:/ { print $3 * 2.54 / 72.0 * 10 "mm" " x " $5 * 2.54 / 72.0 * 10 "mm" }'
diff --git a/home/dot_local/share/bin/executable_pew b/home/dot_local/share/bin/executable_pew
new file mode 100644
index 0000000..70a9673
--- /dev/null
+++ b/home/dot_local/share/bin/executable_pew
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+kill -9 $(xprop | grep "_NET_WM_PID(CARDINAL)" | cut -d' ' -f3)
diff --git a/home/dot_local/share/bin/executable_podcast2m3u b/home/dot_local/share/bin/executable_podcast2m3u
new file mode 100644
index 0000000..c3b692e
--- /dev/null
+++ b/home/dot_local/share/bin/executable_podcast2m3u
@@ -0,0 +1,33 @@
+#!/bin/sh
+URL="$1"
+TAB="$(printf '\t')"
+curl -sLo- "$URL" |\
+xmlstarlet select --template \
+ --match '/rss/channel/item' \
+ --value-of './itunes:duration' \
+ --output "$TAB" \
+ --value-of './title' \
+ --output "$TAB" \
+ --value-of './enclosure/@url' \
+ --nl |\
+awk -F "$TAB" '
+BEGIN {
+ printf("#EXTM3U\n")
+}
+function time2secs(time) {
+ seconds = 0
+ gsub(/,/, ".", time)
+ els = split(time, el, ":")
+ if (els == 0) return seconds;
+ seconds += el[els--]
+ if (els == 0) return seconds;
+ seconds += el[els--] * 60
+ if (els == 0) return seconds;
+ seconds += el[els--] * 60 * 60
+ return seconds;
+}
+{
+ printf("#EXTINF:%s,%s\n%s\n", time2secs($1), $2, $3)
+}
+'
+
diff --git a/home/dot_local/share/bin/executable_preview b/home/dot_local/share/bin/executable_preview
new file mode 100644
index 0000000..819938b
--- /dev/null
+++ b/home/dot_local/share/bin/executable_preview
@@ -0,0 +1,75 @@
+#!/bin/sh
+[ -n "$1" ] && FILE="$1" || {
+ echo "error: no input file"
+ exit 1
+}
+[ -n "$2" ] && WIDTH="$(( "$2" - 1 ))" || WIDTH="$(tput cols)"
+[ -n "$3" ] && HEIGHT="$3" || HEIGHT="$(tput lines)"
+[ -n "$4" ] && POS_X="$4" || POS_X="0"
+[ -n "$5" ] && POS_Y="$5" || POS_Y="0"
+
+MIMETYPE="$(file --mime-type -Lb "$FILE")"
+EXT="${FILE#*.}"
+
+if [ "$MIMETYPE" = "text/plain" ] ; then
+ [ "$EXT" = "md" ] && MIMETYPE="text/markdown"
+ [ "$EXT" = "rst" ] && MIMETYPE="text/x-rst"
+fi
+[ "$MIMETYPE" = "application/javascript" ] && MIMETYPE="text/javascript"
+
+render_manpage() {
+ exec groff -T utf8 -m man -rcR=1 -rIN=0 -rLL="${WIDTH}n" << EOF
+.nr an-suppress-header-and-footer 1
+.TH
+$(cat | preconv)
+EOF
+}
+
+case "$MIMETYPE" in
+ image/*)
+ if [ -z "$UB_SOCKET" ] ; then
+ echo "ueberzug not available"
+ else
+ ueberzugpp cmd \
+ --socket "$UB_SOCKET" \
+ --action add \
+ --identifier PREVIEW \
+ --file "$FILE" \
+ --max-width "$WIDTH" --max-height "$HEIGHT" \
+ --xpos "$POS_X" --ypos "$POS_Y"
+ exit 1 # <- disable cache
+ fi
+ ;;
+ text/markdown)
+ pandoc --from=gfm --to=man "$FILE" | render_manpage
+ ;;
+ text/x-rst)
+ pandoc --from=rst --to=man "$FILE" | render_manpage
+ ;;
+ text/*)
+ bat \
+ --terminal-width="$WIDTH" \
+ --paging=never \
+ --color=always \
+ -- "$FILE"
+ ;;
+ application/x-tar|\
+ application/x-bzip|\
+ application/x-bzip2|\
+ application/gzip|\
+ application/zip|\
+ application/x-7z-compressed|\
+ application/vnd.rar)
+ bsdtar -tf "$FILE"
+ ;;
+ application/json)
+ jq --color-output . "$FILE"
+ ;;
+ *)
+ echo "$MIMETYPE"
+ file -b "$FILE" | fold --width="$WIDTH" --spaces
+ ;;
+esac
+
+exit 0
+
diff --git a/home/dot_local/share/bin/executable_prompt b/home/dot_local/share/bin/executable_prompt
new file mode 100644
index 0000000..7dde932
--- /dev/null
+++ b/home/dot_local/share/bin/executable_prompt
@@ -0,0 +1,33 @@
+#!/bin/sh
+fmt_esc() {
+ printf "%s$1%s" "$eo" "$ec"
+}
+
+fmt_segment() {
+ content="$1"
+ [ -z "$content" ] && return
+ printf '%s%s%s -> %s' "$(fmt_esc '\e[90m')" "${content}" "$(fmt_esc '\e[30m')" "$(fmt_esc '\e[0m')"
+}
+
+fmt_environment() {
+ content="$1"
+ [ -z "$content" ] && return
+ printf '%s(%s%s%s)%s ' "$(fmt_esc '\e[30;40m')" "$(fmt_esc '\e[97m')" "$content" "$(fmt_esc '\e[30;40m')" "$(fmt_esc '\e[0m')"
+}
+
+[ -n "$1" ] && fmt_environment "$1"
+fmt_environment "$VIRTUAL_ENV_PROMPT"
+
+# only display hostname in prompt if connected over SSH
+[ -n "$SSH_CLIENT" ] && fmt_segment "$(hostname)"
+
+# current working directory
+here="$PWD"
+[ "$here" = "$HOME" ] && here="~"
+fmt_segment "$(basename "$here")"
+
+# git status
+git rev-parse --is-inside-work-tree 1> /dev/null 2> /dev/null && fmt_segment "git $(git rev-parse --abbrev-ref HEAD 2> /dev/null)"
+
+# exit happily
+exit 0
diff --git a/home/dot_local/share/bin/executable_qrclip b/home/dot_local/share/bin/executable_qrclip
new file mode 100644
index 0000000..41bdab7
--- /dev/null
+++ b/home/dot_local/share/bin/executable_qrclip
@@ -0,0 +1,2 @@
+#!/bin/sh
+maim -usb 4 -c 0,0,0 | zbarimg --raw --quiet -
diff --git a/home/dot_local/share/bin/executable_reload b/home/dot_local/share/bin/executable_reload
new file mode 100644
index 0000000..4b87658
--- /dev/null
+++ b/home/dot_local/share/bin/executable_reload
@@ -0,0 +1,2 @@
+#!/bin/sh
+i3-msg exit
diff --git a/home/dot_local/share/bin/executable_rofi b/home/dot_local/share/bin/executable_rofi
new file mode 100644
index 0000000..d573764
--- /dev/null
+++ b/home/dot_local/share/bin/executable_rofi
@@ -0,0 +1,4 @@
+#!/bin/sh
+[ -e "$XDG_CONFIG_HOME/gtk-4.0/env" ] && . "$XDG_CONFIG_HOME/gtk-4.0/env"
+. "$XDG_CACHE_HOME/mode/state/vars"
+exec /bin/rofi -no-default-config "$@"
diff --git a/home/dot_local/share/bin/executable_scene b/home/dot_local/share/bin/executable_scene
new file mode 100644
index 0000000..c7faff6
--- /dev/null
+++ b/home/dot_local/share/bin/executable_scene
@@ -0,0 +1,56 @@
+#!/bin/sh
+CACHE_FILE="$XDG_CACHE_HOME/hass-scenes"
+TAB="$(printf '\t')"
+
+update_cache() {
+ rm -f "$CACHE_FILE"
+ curl -s -X GET \
+ -H "Authorization: Bearer $HASS_TOKEN" \
+ -H "Content-Type: application/json" \
+ "$HASS_SERVER/api/states" |\
+ jq --raw-output '
+ .[] |
+ select(.entity_id | startswith("scene.")) |
+ "\(.attributes.friendly_name)\t\(.entity_id)"
+ ' > "$CACHE_FILE"
+}
+
+# update cache if it does not exist
+[ ! -e "$CACHE_FILE" ] && update_cache
+
+# update the cache if requested explicitly
+[ "$1" = "--update" ] && {
+ update_cache
+ exit
+}
+
+# update the cache if it is older than
+MAX_CACHE_AGE=$(( 60 * 60 * 24 )) # one day
+[ $(( $(date +%s) - $MAX_CACHE_AGE )) -gt $(date -r "$CACHE_FILE" +%s) ] && update_cache
+
+if [ $# -eq 0 ] ; then
+ # pick a scene using rofi in dmenu mode
+ scene="$(cat "$CACHE_FILE" |\
+ rofi \
+ -dmenu \
+ -display-columns 1 \
+ -display-column-separator "$TAB" |\
+ cut -d"$TAB" -f2 |\
+ jq --raw-input)"
+else
+ # non interactive scene pick
+ scene="$(cat "$CACHE_FILE" |\
+ grep -w "$*" | head -n1 |\
+ cut -d"$TAB" -f2 |\
+ jq --raw-input)"
+fi
+
+# exit if no scene was selected / found
+[ -z "$scene" ] && exit 0
+
+jq -n --argjson scene "$scene" '{"entity_id": $scene}' |\
+ curl -s -X POST -d @- \
+ -H "Authorization: Bearer $HASS_TOKEN" \
+ -H "Content-Type: application/json" \
+ "$HASS_SERVER/api/services/scene/turn_on" > /dev/null
+
diff --git a/home/dot_local/share/bin/executable_screenrecord b/home/dot_local/share/bin/executable_screenrecord
new file mode 100644
index 0000000..1045a6e
--- /dev/null
+++ b/home/dot_local/share/bin/executable_screenrecord
@@ -0,0 +1,8 @@
+#!/bin/sh
+exec giph "$@" \
+ --framerate 60 \
+ --select \
+ --bordersize 4 \
+ --color 255,255,255 \
+ "$(date +'%Y-%m-%d_%H-%M-%S.mp4')"
+
diff --git a/home/dot_local/share/bin/executable_screenwatch b/home/dot_local/share/bin/executable_screenwatch
new file mode 100644
index 0000000..d556fac
--- /dev/null
+++ b/home/dot_local/share/bin/executable_screenwatch
@@ -0,0 +1,11 @@
+#!/bin/sh
+# repeatedly open terminal at $dev, even when $dev temporarily dissapears
+dev="$1"
+while inotifywait -qq -e create --include "$dev" "$(dirname "$dev")"; do
+ sleep 0.1 # wait until device is initialized
+ screen "$@"
+
+ # break out of loop if device still exists when screen exits (manual screen exit)
+ [ -e "$dev" ] && break
+done
+
diff --git a/home/dot_local/share/bin/executable_sdk10_compiledb b/home/dot_local/share/bin/executable_sdk10_compiledb
new file mode 100644
index 0000000..6e62d47
--- /dev/null
+++ b/home/dot_local/share/bin/executable_sdk10_compiledb
@@ -0,0 +1,38 @@
+#!/bin/python3
+
+from shlex import split, join
+from sys import argv
+from os import getcwd
+import subprocess
+
+process = subprocess.run(argv[1:], stdout=subprocess.PIPE, stderr=None, env={"LANG": "C"})
+
+dir_stack = [getcwd()]
+expanded_output = []
+
+for line in process.stdout.decode('utf-8').split('\n'):
+ expanded_args = []
+ args = split(line)
+
+ if line.startswith('make: Entering directory'):
+ dir_stack.append(args[-1])
+ expanded_output.append(line)
+ continue
+ if line.startswith('make: Leaving directory'):
+ dir_stack.pop()
+ expanded_output.append(line)
+ continue
+
+ for arg in args:
+ if not arg.startswith('@'):
+ expanded_args.append(arg)
+ continue
+ with open(dir_stack[-1] + '/' + arg[1:], 'r') as file:
+ expanded_args += split(file.read())
+ expanded_output.append(subprocess.list2cmdline(expanded_args))
+
+process = subprocess.Popen(["compiledb"], stdin=subprocess.PIPE, stdout=None, stderr=None, text=True)
+process.stdin.write("\n".join(expanded_output))
+process.stdin.close()
+process.wait()
+
diff --git a/home/dot_local/share/bin/executable_set-default b/home/dot_local/share/bin/executable_set-default
new file mode 100644
index 0000000..d93f65c
--- /dev/null
+++ b/home/dot_local/share/bin/executable_set-default
@@ -0,0 +1,32 @@
+#!/bin/sh
+SCRIPT_NAME="$(basename "$0")"
+
+usage() {
+ code=0
+ if [ -z "$1" ] ; then
+ cat << EOF
+Set desktop entry ENTRY as default application for opening files with the same
+type as FILE
+
+EOF
+ else
+ echo "error: $1" >&2
+ code=1
+ fi
+ cat << EOF
+usage:
+ $SCRIPT_NAME ENTRY FILE [FILE]
+EOF
+ exit $code
+}
+
+[ $# -eq 0 ] && usage
+DESKTOP_ENTRY="$1"; shift
+[ -z "$DESKTOP_ENTRY" ] && usage "no desktop entry"
+[ $# -lt 1 ] && usage "no reference file(s)"
+
+for file in "$@" ; do
+ mimetype="$(xdg-mime query filetype "$file")"
+ xdg-mime default "$DESKTOP_ENTRY" "$mimetype"
+done
+
diff --git a/home/dot_local/share/bin/executable_setwacom b/home/dot_local/share/bin/executable_setwacom
new file mode 100644
index 0000000..d7427a6
--- /dev/null
+++ b/home/dot_local/share/bin/executable_setwacom
@@ -0,0 +1,2 @@
+#!/bin/sh
+xsetwacom set "Wacom Intuos PT S 2 Pen stylus" $@
diff --git a/home/dot_local/share/bin/executable_single2folder b/home/dot_local/share/bin/executable_single2folder
new file mode 100644
index 0000000..b3b2d30
--- /dev/null
+++ b/home/dot_local/share/bin/executable_single2folder
@@ -0,0 +1,16 @@
+#!/bin/sh
+file=$1
+foldername=$(basename "$file" .flac)
+
+echo "mkdir \"$foldername\""
+mkdir "$foldername"
+
+echo "mv \"$file\" \"$foldername\""
+mv "$file" "$foldername"
+
+echo "extract folder.png"
+metaflac --export-picture-to="${foldername}/folder.png" "${foldername}/${file}"
+
+echo "make sure folder.png is a png"
+magick "${foldername}/folder.png" "${foldername}/folder.png"
+
diff --git a/home/dot_local/share/bin/executable_spec b/home/dot_local/share/bin/executable_spec
new file mode 100644
index 0000000..7d500dc
--- /dev/null
+++ b/home/dot_local/share/bin/executable_spec
@@ -0,0 +1,2 @@
+#!/bin/sh
+sox "$1" -n spectrogram -o - | feh --class floating -
diff --git a/home/dot_local/share/bin/executable_subrename b/home/dot_local/share/bin/executable_subrename
new file mode 100644
index 0000000..16d913f
--- /dev/null
+++ b/home/dot_local/share/bin/executable_subrename
@@ -0,0 +1,54 @@
+#!/bin/sh
+file_extension=".srt"
+season=1
+episode=1
+
+PROGNAME="$(basename "$0")"
+USAGE="$( cat << EOF
+usage: $PROGNAME [-h] [-s season] [-e episode] [-x extension] file1 [file2 ...]
+
+rename files to s01e01.srt, s01e02.srt, etc.
+
+options:
+ -s set season number (default: $season)
+ -e set episode number of first file (default: $episode)
+ -x set file extension for output files (default: $file_extension)
+ -h show help
+
+example:
+ subrename -x .ja.srt *.srt
+EOF
+)"
+usage() {
+ echo "$USAGE"
+ exit 0
+}
+stupid() {
+ echo "use $PROGNAME -h for help"
+ exit 1
+}
+
+ARGC=0
+while getopts e:s:x:h OPT; do
+ [ $OPTIND -gt $ARGC ] && ARGC=$OPTIND
+ case "$OPT" in
+ e) episode="$OPTARG" ;;
+ h) usage ;;
+ s) season="$OPTARG" ;;
+ x) file_extension="$OPTARG" ;;
+ \?|*) stupid ;;
+ esac
+done
+shift "$(( $OPTIND - 1 ))"
+
+if [ $# -eq 0 ] ; then
+ echo "error: no files provided"
+ stupid
+fi
+
+for file in "$@" ; do
+ new_filename="$(printf 's%02de%02d%s\n' "$season" "$episode" "$file_extension")"
+ mv --verbose "$file" "$new_filename"
+ episode=$(( $episode + 1 ))
+done
+
diff --git a/home/dot_local/share/bin/executable_time2tsv b/home/dot_local/share/bin/executable_time2tsv
new file mode 100644
index 0000000..4cc369d
--- /dev/null
+++ b/home/dot_local/share/bin/executable_time2tsv
@@ -0,0 +1,107 @@
+#!/bin/awk -f
+
+# ignore empty or comment lines
+/^\s*#/ { next }
+/^\s*$/ { next }
+
+{
+ owner = ""
+ date = ""
+ duration = 0
+ description = ""
+}
+
+function max(a, b) {
+ return a > b ? a : b
+}
+
+function duration2time(duration) {
+ temp = 0
+ num = 0
+ multiplier = 60
+
+ split(duration, char, "")
+ for (i=1; i <= length(duration); i++) {
+ if (char[i] == "h") {
+ temp += num * 60 * 60
+ multiplier = 60
+ num = 0
+ continue
+ }
+ if (char[i] == "m") {
+ temp += num * 60
+ multiplier = 1
+ num = 0
+ continue
+ }
+ if (char[i] == "s") {
+ temp += num
+ multiplier = 0
+ num = 0
+ continue
+ }
+
+ num *= 10
+ num += char[i]
+ }
+ if (num > 0) {
+ temp += num * multiplier
+ }
+
+ return temp
+}
+
+function stripnotes(desc) {
+ out = ""
+ nestlevel = 0
+
+ split(desc, char, "")
+ for (i=1; i <= length(desc); i++) {
+ if (char[i] == "(") {
+ nestlevel += 1
+ continue
+ }
+
+ if (char[i] == ")") {
+ nestlevel = max(0, nestlevel - 1)
+ continue
+ }
+
+ if (nestlevel > 0) continue
+ out = out char[i]
+ }
+
+ return out
+}
+
+# strip leading whitespace
+/^\s+/ { gsub(/^\s+/, "", $0) }
+
+# match owner
+match($0, /^[[:alpha:]]+/) {
+ owner = substr($0, RSTART, RLENGTH)
+ gsub(/^[[:alpha:]]+:?\s*/, "", $0)
+}
+
+# match date
+match($0, /^[0-9-]{10}/) {
+ date = substr($0, RSTART, RLENGTH)
+ gsub(/^[0-9-]{10}:?\s*/, "", $0)
+}
+
+# match time
+match($0, /^\<([0-9]+h)?([0-9]{1,2}m)?([0-9]{1,2}s)?\>/) {
+ duration = duration2time(substr($0, RSTART, RLENGTH))
+ gsub(/^\<([0-9]+h)?([0-9]{1,2}m)?([0-9]{1,2}s)?\>:?\s*/, "", $0)
+}
+
+# description
+{
+ description = stripnotes($0)
+}
+
+# output
+{
+ printf("%s\t%s\t%s\t%s\n", owner, date, duration, description)
+}
+
diff --git a/home/dot_local/share/bin/executable_timefmt b/home/dot_local/share/bin/executable_timefmt
new file mode 100644
index 0000000..c78fb95
--- /dev/null
+++ b/home/dot_local/share/bin/executable_timefmt
@@ -0,0 +1,24 @@
+#!/bin/sh
+[ $# -eq 0 ] && sum="$(cat)" || sum="$1"
+sum="$(echo "$sum" | tr -dc '[:digit:]')"
+if [ -z "$sum" ] ; then
+ echo "error: no input number"
+ exit 1
+fi
+
+fmt() {
+ # printf '%d:%02d:%02d\n' $@ | sed -e 's/^0\{2,\}//'
+ printf '%02dh%02dm%02ds\n' $@ | sed -e 's/00s$//' -e 's/^\(00.\)\+//' -e 's/^0\+//'
+}
+
+fmt $(bc <<EOF
+sum = $sum
+seconds = sum % 60
+sum = (sum - seconds) / 60
+minutes = sum % 60
+sum = (sum - minutes) / 60
+hours = sum
+print hours," ",minutes," ",seconds
+EOF
+)
+
diff --git a/home/dot_local/share/bin/executable_timerep b/home/dot_local/share/bin/executable_timerep
new file mode 100644
index 0000000..e09d6c1
--- /dev/null
+++ b/home/dot_local/share/bin/executable_timerep
@@ -0,0 +1,82 @@
+#!/bin/sh
+TAB="$(printf '\t')"
+time2tsv "$@" | sort -t"$TAB" -k4 | awk -F"$TAB" '
+{
+ gsub(/^\s+/, "", $4)
+ gsub(/\s+$/, "", $4)
+ desc = $4
+ if (desc != last_desc && last_desc != "") {
+ printf("%s\t%d\n", last_desc, sum)
+ sum = 0
+ }
+ sum += $3
+ last_desc = desc
+}
+END {
+ printf("%s\t%d\n", last_desc, sum)
+}
+' | awk -F"$TAB" '
+BEGIN {
+ split("", last_path) # define empty array
+}
+
+function strip(string) {
+ gsub(/^\s+/, "", string)
+ gsub(/\s+$/, "", string)
+ return string
+}
+
+function repeat(str, count, i) {
+ out = ""
+ for (i = 0; i < count; i++) {
+ out = str out
+ }
+ return out
+}
+function indent(depth, i) {
+ return repeat(" ", depth)
+}
+
+function printpath(new_path, new, i) {
+ new = 0
+ for (i = 1; i <= length(new_path); i++) {
+ if (last_path[i] != new_path[i]) new = 1
+ if (new == 0) continue
+ printf("%s%s\n", indent(i-1), new_path[i])
+ last_path[i] = new_path[i]
+ }
+}
+
+function timefmt(time, fmt) {
+ cmd = sprintf("timefmt %s", time)
+ cmd | getline fmt
+ close(cmd)
+ return fmt
+}
+
+{
+ len = split($1, path, "::")
+ for (i = 1; i <= len; i++)
+ path[i] = strip(path[i])
+
+ task = path[len]
+ delete path[len]
+ depth = len - 1
+ sum += $2
+ duration = timefmt($2)
+
+ printpath(path)
+ printf("%-67s %10s\n", indent(depth) task, duration)
+}
+
+BEGIN {
+ printf("\033[4m%-67s\033[0m \033[4m%10s\033[0m\n", "Description", "Total")
+}
+
+END {
+ "timefmt "sum | getline duration
+ printf("%67s \033[4m%10s\033[0m\n", "", "")
+ printf("%67s %10s\n", "", duration)
+}
+'
+
diff --git a/home/dot_local/share/bin/executable_timesum b/home/dot_local/share/bin/executable_timesum
new file mode 100644
index 0000000..6284ca4
--- /dev/null
+++ b/home/dot_local/share/bin/executable_timesum
@@ -0,0 +1,4 @@
+#!/bin/sh
+TAB="$(printf '\t')"
+time2tsv "$@" | cut -d"$TAB" -f3 | paste -sd+ - | bc | timefmt
+
diff --git a/home/dot_local/share/bin/executable_toetsrooster2ical b/home/dot_local/share/bin/executable_toetsrooster2ical
new file mode 100644
index 0000000..5de58cb
--- /dev/null
+++ b/home/dot_local/share/bin/executable_toetsrooster2ical
@@ -0,0 +1,38 @@
+#!/bin/python3
+
+import sys
+import xlrd
+from datetime import datetime
+import json
+from icalendar import Calendar, Event
+from uuid import uuid4 as uuid
+import pytz
+
+workbook = xlrd.open_workbook(sys.argv[1])
+sheet = workbook.sheet_by_index(0)
+cal = Calendar()
+
+cal.add('prodid', 'toetsrooster2ical')
+cal.add('version', '2.0')
+
+def time_to_tuple(timestr):
+ return (int(timestr[0:2]), int(timestr[3:5]))
+
+for toets in range(8, sheet.nrows):
+ toetsdata = sheet.row_values(toets)
+ event = Event()
+
+ date = xlrd.xldate_as_tuple(toetsdata[10], workbook.datemode)
+ times = toetsdata[11].split(" - ")
+
+ event.add('summary', toetsdata[4])
+ event.add('dtstart', datetime(*date[0:3], *time_to_tuple(times[0])))
+ event.add('dtend', datetime(*date[0:3], *time_to_tuple(times[1])))
+ event.add('location', toetsdata[14])
+
+ cal.add_component(event)
+
+f = open('out.ics', 'wb')
+f.write(cal.to_ical())
+f.close()
+
diff --git a/home/dot_local/share/bin/executable_vdirsyncer b/home/dot_local/share/bin/executable_vdirsyncer
new file mode 100644
index 0000000..7869f19
--- /dev/null
+++ b/home/dot_local/share/bin/executable_vdirsyncer
@@ -0,0 +1,6 @@
+#!/bin/sh
+CFG_TMP="$XDG_CONFIG_HOME/vdirsyncer/config"
+mkfifo --mode 700 "$CFG_TMP"
+"$XDG_CONFIG_HOME/vdirsyncer/config_gen" > "$CFG_TMP" &
+/usr/bin/vdirsyncer --config "$CFG_TMP" "$@"
+rm -f "$CFG_TMP"
diff --git a/home/dot_local/share/bin/executable_venvgen b/home/dot_local/share/bin/executable_venvgen
new file mode 100644
index 0000000..25f2c78
--- /dev/null
+++ b/home/dot_local/share/bin/executable_venvgen
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# check if the input is valid
+for arg in "$@" ; do
+ case "$arg" in
+ *=*) ;;
+ *)
+ echo "error: missing assignment operator in argument ($arg)" >&2
+ exit 1
+ ;;
+ esac
+done
+
+# shebang
+printf '#!/bin/sh\n'
+
+# save old variables
+for arg in "$@" ; do
+ name="${arg%%=*}"
+ eval "hasval=\${$name+x}"
+ [ -n "$hasval" ] && printf '_%s="${%s}"\n' "$name" "$name"
+done
+
+# set new variables
+for arg in "$@" ; do
+ name="${arg%%=*}"
+ value="${arg#*=}"
+ printf 'export %s=%q\n' "$name" "$value"
+done
+
+# deactivate function
+printf 'deactivate() {\n'
+for arg in "$@" ; do
+ name="${arg%%=*}"
+ eval "hasval=\${$name+x}"
+ if [ -n "$hasval" ] ; then
+ printf '\t%s="${_%s}"\n' "$name" "$name"
+ printf '\tunset -v _%s\n' "$name"
+ else
+ printf '\tunset -v %s\n' "$name"
+ fi
+done
+printf '\thash -r 2>/dev/null\n'
+printf '\tunset -f deactivate\n'
+printf '}\n'
+printf 'hash -r 2>/dev/null\n'
+
diff --git a/home/dot_local/share/bin/executable_vodchat b/home/dot_local/share/bin/executable_vodchat
new file mode 100644
index 0000000..f233348
--- /dev/null
+++ b/home/dot_local/share/bin/executable_vodchat
@@ -0,0 +1,3 @@
+#!/bin/sh
+input_file="$1"
+jq --raw-output '.replayChatItemAction.actions[].addChatItemAction.item.liveChatTextMessageRenderer | "[" + (.timestampUsec | tonumber / 1e6 | todateiso8601) + "] " + .authorName.simpleText + ": " + .message.runs[].text' "$input_file" 2>/dev/null
diff --git a/home/dot_local/share/bin/executable_wacommode b/home/dot_local/share/bin/executable_wacommode
new file mode 100644
index 0000000..2563895
--- /dev/null
+++ b/home/dot_local/share/bin/executable_wacommode
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+defaults () {
+ # smoothing
+ setwacom Suppress 2
+ setwacom RawSample 5
+
+ # full pen area
+ setwacom Area 0 0 15200 9500
+
+ setwacom Rotate none
+}
+
+notify() {
+ notify-send \
+ --replace-id=99999 \
+ --icon=/dev/null \
+ --expire-time=1000 \
+ -- \
+ 'ワコム' "$*"
+}
+
+SCREEN_1_GEOMETRY="$(xrandr -q | awk '$2 == "connected" && $3 == "primary" { print $4 }')"
+SCREEN_2_GEOMETRY="$(xrandr -q | awk '$2 == "connected" && $3 != "primary" { print $3 }')"
+ALL_GEOMETRY="$(xrandr -q | awk '$1 == "Screen" { print ; exit }' | grep -o '\<current\>[^,]\+' | sed -e 's/^current//' -e 's/ //g' -e 's/$/+0+0/')"
+
+topleft() {
+ notify "画面1、横"
+
+ setwacom MapToOutput "$SCREEN_1_GEOMETRY"
+}
+
+bottomleft() {
+ notify "画面2、縦"
+
+ setwacom Rotate ccw
+ setwacom MapToOutput "$SCREEN_2_GEOMETRY"
+}
+
+topright() {
+ notify "画面1、横、低遅延"
+
+ setwacom Suppress 0
+ setwacom RawSample 1
+
+ setwacom Area 0 1623 7600 5898
+ setwacom MapToOutput "$SCREEN_1_GEOMETRY"
+}
+
+bottomright() {
+ notify "全ての画面、横"
+
+ setwacom Area 0 0 11875 7600
+ setwacom MapToOutput "$ALL_GEOMETRY"
+}
+
+defaults
+$1
diff --git a/home/dot_local/share/bin/executable_wacomshortcuts b/home/dot_local/share/bin/executable_wacomshortcuts
new file mode 100644
index 0000000..911e7ff
--- /dev/null
+++ b/home/dot_local/share/bin/executable_wacomshortcuts
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# tablet buttons
+xsetwacom set "Wacom Intuos PT S 2 Pad pad" Button 3 "key +super +alt +ctrl 1 -super -alt -ctrl"
+xsetwacom set "Wacom Intuos PT S 2 Pad pad" Button 1 "key +super +alt +ctrl 2 -super -alt -ctrl"
+xsetwacom set "Wacom Intuos PT S 2 Pad pad" Button 9 "key +super +alt +ctrl 3 -super -alt -ctrl"
+xsetwacom set "Wacom Intuos PT S 2 Pad pad" Button 8 "key +super +alt +ctrl 4 -super -alt -ctrl"
+
+# pen buttons
+setwacom Button 2 pan
+setwacom PanScrollThreshold 200
+
diff --git a/home/dot_local/share/bin/executable_wacomtouch b/home/dot_local/share/bin/executable_wacomtouch
new file mode 100644
index 0000000..6c1e51a
--- /dev/null
+++ b/home/dot_local/share/bin/executable_wacomtouch
@@ -0,0 +1,14 @@
+#!/bin/sh
+# print if wacom tablet has touch on or off
+bye() {
+ echo $1
+ exit
+}
+
+[ ! -e /dev/input/by-id/usb-Wacom_Co._Ltd._Intuos_PTS-if01-event-mouse ] && bye
+
+if evtest --query /dev/input/by-id/usb-Wacom_Co._Ltd._Intuos_PTS-if01-event-mouse EV_SW SW_MUTE_DEVICE; then
+ bye "touch on"
+else
+ bye "touch off"
+fi
diff --git a/home/dot_local/share/bin/executable_xbindkeys b/home/dot_local/share/bin/executable_xbindkeys
new file mode 100644
index 0000000..03a2c37
--- /dev/null
+++ b/home/dot_local/share/bin/executable_xbindkeys
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec /usr/bin/xbindkeys --file "$XDG_CONFIG_HOME/xbindkeys/main" "$@"
diff --git a/home/dot_local/share/bin/executable_yt-vod b/home/dot_local/share/bin/executable_yt-vod
new file mode 100644
index 0000000..0eb424d
--- /dev/null
+++ b/home/dot_local/share/bin/executable_yt-vod
@@ -0,0 +1,17 @@
+#!/bin/sh
+vid="$1"
+if [ -z "$vid" ] ; then
+ echo "usage: $0 <stream ID>"
+ exit 1
+fi
+
+url="https://youtube.com/watch?v=$vid"
+
+# download chat
+screen -d -m -S "yt-$vid-chat" -- pause yt-dlp --live-from-start --write-sub --no-download "$url"
+
+# download stream
+screen -d -m -S "yt-$vid-vod" -- pause yt-dlp --live-from-start -S ext "$url"
+
+echo "started recording! (use screen -r yt-$vid-<tab> to stop)"
+
diff --git a/home/dot_local/share/bin/symlink_mode b/home/dot_local/share/bin/symlink_mode
new file mode 100644
index 0000000..da230d2
--- /dev/null
+++ b/home/dot_local/share/bin/symlink_mode
@@ -0,0 +1 @@
+../mode/mode
diff --git a/home/dot_local/share/bin/symlink_sh b/home/dot_local/share/bin/symlink_sh
new file mode 100644
index 0000000..ff99e34
--- /dev/null
+++ b/home/dot_local/share/bin/symlink_sh
@@ -0,0 +1 @@
+/usr/bin/dash
diff --git a/home/dot_local/share/fcitx5/themes/mode/base.conf b/home/dot_local/share/fcitx5/themes/mode/base.conf
new file mode 100644
index 0000000..e329a4f
--- /dev/null
+++ b/home/dot_local/share/fcitx5/themes/mode/base.conf
@@ -0,0 +1,42 @@
+# vim:ft=dosini
+[Metadata]
+Name=mode
+Version=0.1
+Author=lonkaars
+Description=theme generated by mode
+ScaleWithDPI=True
+
+[InputPanel]
+Font=sans-serif 12
+
+[InputPanel/Background/Margin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/Background/Margin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/ContentMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/Highlight/Margin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+[Menu/TextMargin]
+Left=0
+Right=0
+Top=0
+Bottom=0
+
+
diff --git a/home/dot_local/share/mode/executable_mode b/home/dot_local/share/mode/executable_mode
new file mode 100644
index 0000000..dc188e9
--- /dev/null
+++ b/home/dot_local/share/mode/executable_mode
@@ -0,0 +1,148 @@
+#!/usr/bin/env sh
+progname="$(basename "$0")"
+data="$(dirname "$(readlink -f "$0")")"
+export data # path to directory containing reload.d, switch.d, etc.
+
+run_switch=1
+run_reload=1
+no_cfg=0
+theme="" # absolute path to theme
+
+# print error message and exit with error
+stupid() {
+ echo "$@" >&2
+ echo "run \`$progname --help\` for options" >&2
+ exit 1
+}
+
+usage() {
+ cat << EOF
+$progname -- switch system themes
+
+usage:
+ $progname [-chr] action|theme
+
+options:
+ -s, --no-switch disable running switch.d hooks
+ -c, --no-cfggen disable generation of templated configuration files
+ -h, --help display this help text
+ -r, --no-reload disable reloading of applications after applying theme
+
+actions:
+ restore switch to last set theme ($XDG_CACHE_HOME/mode/state/theme)
+ reload do not update configuration files, only reload applications
+ help same as --help option
+ list list all themes
+
+examples:
+ mode dark switch to dark mode and reload applications
+ mode restore --no-reload make sure all configuration files are up-to-date
+ mode reload only reload applications
+
+EOF
+}
+
+# run a module file
+run_mod() {
+ mod_name="$1"
+
+ # modules must be executable
+ ! [ -x "$mod_name" ] && return
+
+ # parse interpreter from shebang
+ interpreter="$(basename "$(command -v $(head -n1 "$mod_name" | sed -n 's/^#!\(.*\)/\1/p'))")"
+ if [ "$interpreter" = "sh" ] ; then
+ # source module if interpreter is POSIX sh (makes plugin functions available)
+ ( . "$mod_name" )
+ else
+ # else, just run them
+ "$mod_name"
+ fi
+}
+
+# generate config files from theme file using scripts in switch.d
+switch() {
+ [ -z "$theme" ] && stupid "error: no theme selected"
+ [ ! -e "$theme" ] && stupid "error: theme not found"
+ export theme
+
+ theme_name="$(basename "$theme")"
+ echo "setting theme to $theme_name..."
+
+ # clean up environment
+ unset accent accent_text
+ unset mode
+
+ # load theme colors + aux variables
+ . "$theme"
+
+ # load plugins (TODO: plugins aren't loaded when only reloading)
+ for plugin in "$data"/plug.d/* ; do . "$plugin" ; done
+
+ # generate new config files / snippets (in parallel)
+ for switch_function in "$data"/switch.d/* ; do
+ run_mod "$switch_function" &
+ done
+
+ # join all processes started above
+ wait $(jobs -p)
+}
+
+# reload programs using scripts in reload.d
+reload() {
+ echo "reloading programs..."
+
+ for reload_function in "$data"/reload.d/* ; do
+ run_mod "$reload_function" &
+ done
+
+ wait $(jobs -p)
+}
+
+# main program argument parser (later argument always take priority)
+for arg in "$@" ; do
+ case "$arg" in
+ # stop parsing arguments after --
+ --) break ;;
+ # help
+ -h|--help|help) usage && exit 0 ;;
+ # only run reload scripts
+ reload) run_reload=1 run_switch=0 ;;
+ # prevent reload.d scripts from running
+ -r|--no-reload) run_reload=0 ;;
+ # prevent switch.d scripts from running
+ -s|--no-switch) run_switch=0 ;;
+ # prevent switch.d scripts from running
+ -c|--no-cfggen) no_cfg=1 ;;
+ # restore previous theme stored as symlink (see switch.d/mode)
+ restore)
+ theme="$(readlink -f "$XDG_CACHE_HOME/mode/state/theme")"
+ [ ! -e "$theme" ] && stupid "error: could not locate previous theme"
+ ;;
+ # list themes in themes folder
+ list)
+ find "$data/themes" -type f,l | while read -r theme ; do
+ printf '%s' "$(basename "$theme")"
+ link="$(readlink "$theme")" && printf ' (%s)' "$link"
+ printf '\n'
+ done
+ exit 0
+ ;;
+ *)
+ # check if unknown argument is a theme name
+ if [ -e "$data/themes/$arg" ] ; then
+ theme="$(readlink -f "$data/themes/$arg")"
+ continue
+ fi
+ # else throw error
+ stupid "error: unknown argument or theme: $arg"
+ ;;
+ esac
+done
+
+export no_cfg
+
+# main
+[ $run_switch -eq 1 ] && switch
+[ $run_reload -eq 1 ] && reload
+
diff --git a/home/dot_local/share/mode/plug.d/10_lib b/home/dot_local/share/mode/plug.d/10_lib
new file mode 100644
index 0000000..b3a0276
--- /dev/null
+++ b/home/dot_local/share/mode/plug.d/10_lib
@@ -0,0 +1,46 @@
+#!/bin/sh
+# utility library functions
+hex_to_rgb_array() { pastel format rgb "$1" | cut -c4- | tr '()' '[]' ; }
+
+mix_rgb() { pastel mix --colorspace=RGB --fraction="$3" "$1" "$2" | pastel format hex ; }
+
+getvar() {
+ key="$1"
+ eval "printf '%s' \"\$$key\""
+}
+
+setvar() {
+ key="$1"
+ value="$2"
+ eval "$key='$(printf '%s' "$value")'"
+}
+
+themevar() {
+ key="$1"
+ if [ $# -eq 1 ] ; then
+ value="$(getvar "$key")"
+ else
+ value="$2"
+ setvar "$key" "$value"
+ fi
+
+ vars="$vars
+$(printf "export %s='%s'" "$key" "$value")"
+ eval "export $key"
+}
+
+mkcd() {
+ mkdir -p "$1"
+ cd "$1"
+}
+
+respawn_daemon() {
+ killall -q "$1" && fork "$@"
+}
+
+silent_fail_if_no_commmand() {
+ for name in "$@" ; do
+ [ -z "$(command -v "$name")" ] && exit
+ done
+}
+
diff --git a/home/dot_local/share/mode/plug.d/20_export_colors b/home/dot_local/share/mode/plug.d/20_export_colors
new file mode 100644
index 0000000..0f53d1f
--- /dev/null
+++ b/home/dot_local/share/mode/plug.d/20_export_colors
@@ -0,0 +1,17 @@
+#!/bin/sh
+# colors must be #RRGGBB
+check_color() {
+ (
+ eval "color=\"\${$1}\""
+ exit "$(echo "$color" | sed -n '/^#[0-9a-fA-F]\{6\}$/p' | wc -l)"
+ )
+ if [ $? -ne 1 ] ; then
+ echo "error: color $1 is not properly formatted (#RRGGBB)"
+ stupid && exit 1
+ fi
+ themevar "$1"
+}
+for color in $(seq 0 15 | sed 's/^/color/') bg fg ; do
+ check_color $color
+done
+
diff --git a/home/dot_local/share/mode/plug.d/20_export_mode b/home/dot_local/share/mode/plug.d/20_export_mode
new file mode 100644
index 0000000..c82c4e1
--- /dev/null
+++ b/home/dot_local/share/mode/plug.d/20_export_mode
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $mode = "light" | "dark"
+if [ "$mode" != 'dark' ] && [ "$mode" != 'light' ] ; then
+ pastel format hsl-lightness "$bg" | awk '{ exit($1 > 0.5) }'
+ [ $? -eq 0 ] && mode=dark || mode=light
+ echo "warn: theme $theme did not define \$mode as \"light\" or \"dark\", guessed $mode" >&2
+fi
+themevar mode
+
diff --git a/home/dot_local/share/mode/plug.d/20_export_vim_theme b/home/dot_local/share/mode/plug.d/20_export_vim_theme
new file mode 100644
index 0000000..12304f3
--- /dev/null
+++ b/home/dot_local/share/mode/plug.d/20_export_vim_theme
@@ -0,0 +1,6 @@
+#!/bin/sh
+# warn if the vim theme is not installed
+if [ "$(find "$XDG_CONFIG_HOME/nvim" -name "$vim_theme_name.vim" | wc -l)" -eq 0 ] ; then
+ echo "warn: vim theme $vim_theme_name does not appear to be installed" >&2
+fi
+themevar vim_theme_name
diff --git a/home/dot_local/share/mode/plug.d/50_accent b/home/dot_local/share/mode/plug.d/50_accent
new file mode 100644
index 0000000..ceb3209
--- /dev/null
+++ b/home/dot_local/share/mode/plug.d/50_accent
@@ -0,0 +1,15 @@
+#!/bin/sh
+# create accent color differently for dark/light mode
+
+# do not generate accent color if already explicitly defined by theme
+[ -n "$accent" ] && return
+
+if [ "$mode" = "light" ] ; then
+ themevar accent "$color15"
+ themevar accent_text "$color0"
+fi
+if [ "$mode" = "dark" ] ; then
+ themevar accent "$(mix_rgb $bg $color0 0.5)"
+ themevar accent_text "$fg"
+fi
+
diff --git a/home/dot_local/share/mode/reload.d/brave b/home/dot_local/share/mode/reload.d/brave
new file mode 100644
index 0000000..6f6caeb
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/brave
@@ -0,0 +1,80 @@
+#!/bin/sh
+# WIP
+browser='brave'
+driver='chromedriver'
+devtools_addr='localhost:9222'
+url_base='http://localhost:9515'
+
+command -v "$browser" > /dev/null && command -v "$driver" > /dev/null
+[ $? -ne 0 ] && exit 0
+
+get() { curl -s -o - -X GET "$@" ; }
+post() { curl -s -o - -X POST -H 'Content-Type: application/json' -d @- "$@" ; }
+delete() { curl -s -X DELETE "$@" > /dev/null ; }
+
+$driver --silent > /dev/null &
+sleep 0.1 # (wait for chromedriver to start server)
+
+create_session() {
+ args="$(jq --raw-input --slurp 'split("\n") | map(select(. != ""))' << EOF
+new-window
+headless=new
+EOF
+ )"
+ jq -nc \
+ --arg name "$browser" \
+ --arg debugger "$devtools_addr" \
+ --argjson args "$args" \
+ '{
+ desiredCapabilities: {
+ "browserName": $name,
+ "goog:chromeOptions": {
+ binary: $name,
+ args: $args,
+ debuggerAddress: $debugger
+ },
+ }
+ }' |\
+ post "$url_base/session" |\
+ jq --raw-output '.sessionId'
+}
+
+navigate() {
+ jq -nc --arg url "$1" '{"url": $url}' |\
+ post "$url_base/url" > /dev/null
+}
+
+script() {
+ jq -nc --arg script "$1" '{"script": $script, args: []}' |\
+ post "$url_base/execute/sync" > /dev/null
+}
+
+create_tab() {
+ handle="$(jq -nc '{"type": "tab"}' |\
+ post "$url_base/window/new" |\
+ jq --raw-output '.value.handle')"
+ jq -nc --arg handle "$handle" '{"name": $handle}' |\
+ post "$url_base/window" > /dev/null
+}
+
+# create session
+session_id="$(create_session)"
+url_base="$url_base/session/$session_id"
+create_tab
+
+# set chrome theme
+navigate 'brave://settings'
+script "chrome.send(\"setBraveThemeType\", [$([ "$mode" = "light" ] && echo "2" || echo "1")])"
+
+# todo: reload theme extension
+# navigate 'brave://extensions'
+# - run `chrome.developerPrivate.loadUnpacked()` (TODO: how to handle inputting file path non-interactively)
+# TODO: how to use chromedriver from script (preferably without nodejs+npm or python3+pip dependencies?)
+
+# cleanup
+delete "$url_base/window"
+delete "$url_base"
+kill $(jobs -p)
+wait $(jobs -p)
+
+# reference: https://w3c.github.io/webdriver/
diff --git a/home/dot_local/share/mode/reload.d/executable_dunst b/home/dot_local/share/mode/reload.d/executable_dunst
new file mode 100644
index 0000000..430320c
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/executable_dunst
@@ -0,0 +1,3 @@
+#!/bin/sh
+respawn_daemon dunst
+
diff --git a/home/dot_local/share/mode/reload.d/executable_fcitx5 b/home/dot_local/share/mode/reload.d/executable_fcitx5
new file mode 100644
index 0000000..cd27698
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/executable_fcitx5
@@ -0,0 +1,3 @@
+#!/bin/sh
+fork fcitx5 -rd
+
diff --git a/home/dot_local/share/mode/reload.d/executable_i3 b/home/dot_local/share/mode/reload.d/executable_i3
new file mode 100644
index 0000000..96212cf
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/executable_i3
@@ -0,0 +1,2 @@
+#!/bin/sh
+fork i3-msg reload
diff --git a/home/dot_local/share/mode/reload.d/executable_nvim b/home/dot_local/share/mode/reload.d/executable_nvim
new file mode 100644
index 0000000..cfabcc7
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/executable_nvim
@@ -0,0 +1,6 @@
+#!/bin/sh
+silent_fail_if_no_commmand nvr
+nvr --serverlist | while read -r nvim_socket ; do
+ fork nvr --nostart --servername "$nvim_socket" -c 'source $XDG_CONFIG_HOME/nvim/mode.vim'
+done
+
diff --git a/home/dot_local/share/mode/reload.d/executable_polybar b/home/dot_local/share/mode/reload.d/executable_polybar
new file mode 100644
index 0000000..1976811
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/executable_polybar
@@ -0,0 +1,3 @@
+#!/bin/sh
+fork polybar-msg cmd restart
+
diff --git a/home/dot_local/share/mode/reload.d/executable_term b/home/dot_local/share/mode/reload.d/executable_term
new file mode 100644
index 0000000..b711d56
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/executable_term
@@ -0,0 +1,30 @@
+#!/bin/sh
+escape_msgs="$(cat << EOF | tr -d '\n'
+\033]11;$bg\007
+\033]10;$fg\007
+\033]12;$fg\007
+\033]14;$bg\007
+\033]13;$fg\007
+\033]17;$color8\007
+\033]708;$bg\007
+\033]4;0;$color0\007
+\033]4;1;$color1\007
+\033]4;2;$color2\007
+\033]4;3;$color3\007
+\033]4;4;$color4\007
+\033]4;5;$color5\007
+\033]4;6;$color6\007
+\033]4;7;$color7\007
+\033]4;8;$color8\007
+\033]4;9;$color9\007
+\033]4;10;$color10\007
+\033]4;11;$color11\007
+\033]4;12;$color12\007
+\033]4;13;$color13\007
+\033]4;14;$color14\007
+\033]4;15;$color15\007
+EOF
+)"
+
+find /dev/pts -exec sh -c "printf '$escape_msgs' > {}" \; 2> /dev/null
+
diff --git a/home/dot_local/share/mode/reload.d/gtk b/home/dot_local/share/mode/reload.d/gtk
new file mode 100644
index 0000000..767969d
--- /dev/null
+++ b/home/dot_local/share/mode/reload.d/gtk
@@ -0,0 +1,8 @@
+#!/bin/sh
+# this is max jank but xfsettingsd does other things besides live gtk theme
+# reloading, and i don't like having it running constantly because it fucks
+# up fcitx5 and xbindkeys
+fork xfsettingsd --replace
+sleep 1
+killall -q xfsettingsd
+
diff --git a/home/dot_local/share/mode/switch.d/executable_anki b/home/dot_local/share/mode/switch.d/executable_anki
new file mode 100644
index 0000000..7572b00
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_anki
@@ -0,0 +1,120 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+# this generates theme files compatible with Anki-redesign:
+# <https://ankiweb.net/shared/info/308574457>
+# <https://github.com/shirajuki/anki-redesign>
+ANKI_REDESIGN="$XDG_DATA_HOME/Anki2/addons21/308574457"
+
+# ensure folders exist
+mkdir -p "$ANKI_REDESIGN/user_files/themes"
+
+# ensure theme is set to mode
+CONFIG="$ANKI_REDESIGN/config.json"
+[ -e "$CONFIG" ] && jq '.theme = "mode"' "$CONFIG" | sponge "$CONFIG"
+
+name() {
+ key="$1"
+ value="$2"
+ key_json="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]' | tr -c '[:alnum:]' '_')"
+ key_css="--$(printf '%s' "$key" | tr '[:upper:]' '[:lower:]' | tr -c '[:alnum:]' '-')"
+ echo "\"$key_json\": [ \"\", \"\", \"$value\", \"$value\", \"$key_css\" ]"
+}
+
+unused="#ff00ff"
+surface_0=$(mix_rgb $bg '#000000' 0.7)
+surface_1=$(mix_rgb $color0 $bg 0.40)
+surface_2=$(mix_rgb $color0 $bg 0.60)
+
+cat << EOF > "$ANKI_REDESIGN/user_files/themes/mode.json"
+{
+ "colors": {
+ $(name accent-card "$color4"),
+ $(name accent-danger "$color1"),
+ $(name accent-note "$color2"),
+ $(name border "$bg"),
+ $(name border-focus "#3b82f6"),
+ $(name border-strong "#020202"),
+ $(name border-subtle "$bg"),
+ $(name buried-fg "#777733"),
+ $(name button-bg "$surface_1"),
+ $(name button-disabled "$bg"),
+ $(name button-focus-bg "#0093d0"),
+ $(name button-gradient-end "$surface_2"),
+ $(name button-gradient-start "$surface_2"),
+ $(name button-hover-border "$accent"),
+ $(name button-primary-bg "$accent"),
+ $(name button-primary-disabled "#4484ed"),
+ $(name button-primary-gradient-end "$accent"),
+ $(name button-primary-gradient-start "$accent"),
+ $(name canvas "$bg"),
+ $(name canvas-code "$surface_0"),
+ $(name canvas-elevated "$bg"),
+ $(name canvas-inset "$surface_1"),
+ $(name canvas-overlay "$bg"),
+ $(name current-deck "$unused"),
+ $(name disabled "#777"),
+ $(name faint-border "#29292b"),
+ $(name fg "$fg"),
+ $(name fg-disabled "#737373"),
+ $(name fg-faint "$color0"),
+ $(name fg-link "#bfdbfe"),
+ $(name fg-subtle "#858585"),
+ $(name flag1-bg "#aa5555"),
+ $(name flag1-fg "#ff7b7b"),
+ $(name flag2-bg "#ac653a"),
+ $(name flag2-fg "#f5aa41"),
+ $(name flag3-bg "#559238"),
+ $(name flag3-fg "#86ce5d"),
+ $(name flag4-bg "#506aa3"),
+ $(name flag4-fg "#6f9dff"),
+ $(name flag5-bg "#975d8f"),
+ $(name flag5-fg "#f097e4"),
+ $(name flag6-bg "#399185"),
+ $(name flag6-fg "#5ccfca"),
+ $(name flag7-bg "#624b77"),
+ $(name flag7-fg "#9f63d3"),
+ $(name flag-1 "$color9"),
+ $(name flag-2 "$color11"),
+ $(name flag-3 "$color10"),
+ $(name flag-4 "$color12"),
+ $(name flag-5 "$color13"),
+ $(name flag-6 "$color14"),
+ $(name flag-7 "$color5"),
+ $(name focus-shadow "#0093d0"),
+ $(name frame-bg "$surface_1"),
+ $(name highlight-bg "$accent"),
+ $(name highlight-fg "$accent_text"),
+ $(name learn-count "#ff935b"),
+ $(name link "#77ccff"),
+ $(name marked-bg "#77c"),
+ $(name medium-border "#444"),
+ $(name new-count "#77ccff"),
+ $(name review-count "#5ccc00"),
+ $(name scrollbar-bg "$surface_1"),
+ $(name scrollbar-bg-active "$surface_2"),
+ $(name scrollbar-bg-hover "$surface_2"),
+ $(name selected-bg "rgba(147, 197, 253, 0.5)"),
+ $(name selected-fg "$fg"),
+ $(name shadow "#141414"),
+ $(name shadow-focus "#6366f1"),
+ $(name shadow-inset "#202020"),
+ $(name shadow-subtle "#363636"),
+ $(name slightly-grey-text "#ccc"),
+ $(name state-buried "#92400e"),
+ $(name state-learn "$color1"),
+ $(name state-marked "#a855f7"),
+ $(name state-new "$color4"),
+ $(name state-review "$color2"),
+ $(name state-suspended "#fef9c3"),
+ $(name suspended-bg "#aaaa33"),
+ $(name suspended-fg "#ffffb2"),
+ $(name text-fg "$fg"),
+ $(name tooltip-bg "$surface_1"),
+ $(name window-bg "$bg"),
+ $(name zero-count "#444")
+ },
+ "version": { "major": -1, "minor": -1 }
+}
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_chromium b/home/dot_local/share/mode/switch.d/executable_chromium
new file mode 100644
index 0000000..0ea2caa
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_chromium
@@ -0,0 +1,48 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CACHE_HOME/mode/chromium"
+
+rm -f 'Cached Theme.pak'
+
+magick -size 100x100 "xc:$bg" 'bg.png'
+bg_alt=$(mix_rgb $bg $color0 0.65)
+fg_alt=$(mix_rgb $fg $color15 0.35)
+
+bg="$(hex_to_rgb_array "$bg")"
+fg="$(hex_to_rgb_array "$fg")"
+bg_alt="$(hex_to_rgb_array "$bg_alt")"
+fg_alt="$(hex_to_rgb_array "$fg_alt")"
+
+cat << EOF > 'manifest.json'
+{
+ "description": "colorscheme generated by mode",
+ "manifest_version": 2,
+ "name": "mode theme",
+ "theme": {
+ "images": { "theme_frame": "bg.png" },
+ "colors": {
+ "frame": $bg_alt,
+ "button_background": $fg,
+ "ntp_background": $bg,
+ "ntp_text": $bg_alt,
+ "toolbar": $bg,
+ "toolbar_button_icon": $fg,
+ "tab_background_text": $fg_alt,
+ "tab_background_text_inactive": $fg_alt,
+ "tab_background_text_incognito": $fg_alt,
+ "tab_background_text_incognito_inactive": $fg_alt,
+ "bookmark_text": $fg,
+ "tab_text": $fg
+ },
+ "tints": {
+ "buttons": [ -1, -1, -1 ],
+ "frame_inactive": [ -1, -1, -1 ],
+ "frame_incognito": [ -1, -1, -1 ],
+ "frame_incognito_inactive": [ -1, -1, -1 ]
+ }
+ },
+ "version": "2"
+}
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_discord b/home/dot_local/share/mode/switch.d/executable_discord
new file mode 100644
index 0000000..dd7e5e3
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_discord
@@ -0,0 +1,34 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CONFIG_HOME/BetterDiscord/themes"
+cat << EOF > 'mode.theme.css'
+/**
+ * @name mode
+ * @author mode
+ * @version 0
+*/
+
+/* AUTOMATICALLY GENERATED, DO NOT EDIT */
+
+.theme-dark, .theme-light {
+ --background-primary: $bg;
+ --background-secondary: $bg;
+ --background-secondary-alt: $bg;
+ --text-primary: $fg;
+ --text-secondary: $color15;
+ --accent: $color4;
+ --accent-alt: $color12;
+ --error: $color1;
+ --error-alt: $color9;
+}
+
+.theme-dark {
+ --background-tertiary: $(mix_rgb $bg '#000000' 0.7);
+}
+
+.theme-light {
+ --background-tertiary: $bg;
+}
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_dunst b/home/dot_local/share/mode/switch.d/executable_dunst
new file mode 100644
index 0000000..d7d9a2b
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_dunst
@@ -0,0 +1,24 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CONFIG_HOME/dunst"
+cat 'base' - << EOF > 'dunstrc'
+frame_color = "$accent"
+
+[urgency_low]
+background = "$bg"
+foreground = "$fg"
+timeout = 10
+
+[urgency_normal]
+background = "$bg"
+foreground = "$fg"
+timeout = 10
+
+[urgency_critical]
+background = "$color1"
+foreground = "$bg"
+frame_color = "$color1"
+timeout = 0
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_fcitx5 b/home/dot_local/share/mode/switch.d/executable_fcitx5
new file mode 100644
index 0000000..2cc6ccb
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_fcitx5
@@ -0,0 +1,67 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_DATA_HOME/fcitx5/themes/mode"
+rounding=6
+size=$(( 2 * $rounding + 4 ))
+margin_h=6
+margin_v=4
+
+bg='#000000'
+fg='#ffffff'
+accent='#404040'
+accent_text=$fg
+sel_bg=$(mix_rgb $color12 $bg 0.4)
+sel_fg=$fg
+
+magick \
+ -size ${size}x${size} xc:transparent \
+ -fill xc:"$accent" \
+ -draw "roundrectangle 0,0 $(( $size - 1 )),$(( $size - 1 )) $rounding,$rounding" \
+ highlight.png
+
+cat base.conf - << EOF > theme.conf
+[InputPanel]
+NormalColor=$fg
+HighlightCandidateColor=$accent_text
+HighlightColor=$sel_fg
+HighlightBackgroundColor=$sel_bg
+
+[InputPanel/Background]
+Color=$bg
+
+[InputPanel/Highlight]
+Image=highlight.png
+
+[InputPanel/Highlight/Margin]
+Left=$rounding
+Right=$rounding
+Top=$rounding
+Bottom=$rounding
+
+[InputPanel/ContentMargin]
+Left=$(( 2 + $rounding - $margin_h ))
+Right=$(( 2 + $rounding - $margin_h ))
+Top=$(( 2 + $rounding - $margin_v ))
+Bottom=$(( 2 + $rounding - $margin_v ))
+
+[InputPanel/TextMargin]
+Left=$margin_h
+Right=$margin_h
+Top=$margin_v
+Bottom=$margin_v
+
+[Menu]
+NormalColor=$fg
+
+[Menu/Background]
+Color=$bg
+
+[Menu/Highlight]
+Color=$accent
+
+[Menu/Separator]
+Color=$color7
+
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_gtk b/home/dot_local/share/mode/switch.d/executable_gtk
new file mode 100644
index 0000000..95d3e53
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_gtk
@@ -0,0 +1,11 @@
+#!/bin/sh
+GTK_3_SETTINGS_INI="$XDG_CONFIG_HOME/gtk-3.0/settings.ini"
+if [ "$mode" = "light" ]; then
+ sed -e 's/-Dark/-Light/' -e 's/-dark/-light/' -i "$GTK_3_SETTINGS_INI"
+ sed "s/gtk-application-prefer-dark-theme.*/gtk-application-prefer-dark-theme=false/" -i "$GTK_3_SETTINGS_INI"
+else
+ sed -e 's/-Dark/-Light/' -e 's/-dark/-light/' -i "$GTK_3_SETTINGS_INI"
+ sed "s/gtk-application-prefer-dark-theme.*/gtk-application-prefer-dark-theme=true/" -i "$GTK_3_SETTINGS_INI"
+fi
+grep gtk-theme-name "$GTK_3_SETTINGS_INI" | cut -f2 -d= | xargs xfconf-query -c xsettings -p /Net/ThemeName -s
+
diff --git a/home/dot_local/share/mode/switch.d/executable_i3 b/home/dot_local/share/mode/switch.d/executable_i3
new file mode 100644
index 0000000..713869e
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_i3
@@ -0,0 +1,14 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+indicator="$color0"
+mkcd "$XDG_CONFIG_HOME/i3"
+cat << EOF > 'color.conf'
+client.focused $fg $bg $fg $indicator $bg
+client.focused_inactive $bg $bg $fg $indicator $bg
+client.unfocused $bg $bg $fg $indicator $bg
+client.urgent $bg $bg $fg $indicator $bg
+client.placeholder $bg $bg $fg $indicator $bg
+client.background $bg
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_kitty b/home/dot_local/share/mode/switch.d/executable_kitty
new file mode 100644
index 0000000..eeb81d0
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_kitty
@@ -0,0 +1,27 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CONFIG_HOME/kitty"
+
+cat << EOF > 'color.conf'
+background $bg
+foreground $fg
+
+color0 $color0
+color1 $color1
+color2 $color2
+color3 $color3
+color4 $color4
+color5 $color5
+color6 $color6
+color7 $color7
+color8 $color8
+color9 $color9
+color10 $color10
+color11 $color11
+color12 $color12
+color13 $color13
+color14 $color14
+color15 $color15
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_mode b/home/dot_local/share/mode/switch.d/executable_mode
new file mode 100644
index 0000000..8866486
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_mode
@@ -0,0 +1,10 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CACHE_HOME/mode/state"
+
+echo "$mode" > mode
+rm theme
+ln -sf "$theme" theme
+echo "#!/bin/sh$vars" > vars
+
diff --git a/home/dot_local/share/mode/switch.d/executable_polybar b/home/dot_local/share/mode/switch.d/executable_polybar
new file mode 100644
index 0000000..7087735
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_polybar
@@ -0,0 +1,16 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CONFIG_HOME/polybar"
+cat << EOF > 'colors.ini'
+[color]
+bg = \${xrdb:background:$bg}
+fg = \${xrdb:foreground:$fg}
+fg-alt = \${xrdb:background:$bg}
+fg-half = \${xrdb:color8:$color8}
+
+alpha = #00000000
+
+; vim:ft=dosini
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_vim b/home/dot_local/share/mode/switch.d/executable_vim
new file mode 100644
index 0000000..2220b1a
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_vim
@@ -0,0 +1,59 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CONFIG_HOME/nvim/mode"
+
+# lightline
+cat << EOF > 'lightline.vim'
+let s:bg = [ '$bg', 'NONE' ]
+let s:fg = [ '$fg', 'NONE' ]
+let s:mode = [ '$color0', 'NONE' ]
+let s:faint = [ '$color8', 'NONE' ]
+let s:none = [ 'NONE', 'NONE' ]
+let s:test = [ '#ff00ff', 'NONE' ]
+
+let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}}
+let s:p.normal.left = [ [ s:fg, s:mode ], [ s:faint, s:bg ] ]
+let s:p.normal.right = [ [ s:faint, s:bg ] ]
+let s:p.normal.middle = [ [ s:bg, s:bg ] ]
+let s:p.normal.error = [ [ s:test, s:test ] ]
+let s:p.normal.warning = [ [ s:test, s:test ] ]
+let s:p.inactive.left = copy(s:p.normal.left)
+let s:p.inactive.right = copy(s:p.normal.right)
+let s:p.inactive.middle = copy(s:p.normal.middle)
+let s:p.insert.left = copy(s:p.normal.left)
+let s:p.replace.left = copy(s:p.insert.left)
+let s:p.visual.left = copy(s:p.insert.left)
+let s:p.tabline.left = copy(s:p.normal.right)
+let s:p.tabline.tabsel = [ [ s:fg, s:mode ] ]
+let s:p.tabline.middle = copy(s:p.normal.right)
+let s:p.tabline.right = copy(s:p.normal.right)
+
+let g:lightline#colorscheme#auto#palette = lightline#colorscheme#flatten(s:p)
+EOF
+
+# terminal colors
+cat << EOF > 'termcolors.vim'
+let g:terminal_color_0 = '$color0'
+let g:terminal_color_1 = '$color1'
+let g:terminal_color_2 = '$color2'
+let g:terminal_color_3 = '$color3'
+let g:terminal_color_4 = '$color4'
+let g:terminal_color_5 = '$color5'
+let g:terminal_color_6 = '$color6'
+let g:terminal_color_7 = '$color7'
+let g:terminal_color_8 = '$color8'
+let g:terminal_color_9 = '$color9'
+let g:terminal_color_10 = '$color10'
+let g:terminal_color_11 = '$color11'
+let g:terminal_color_12 = '$color12'
+let g:terminal_color_13 = '$color13'
+let g:terminal_color_14 = '$color14'
+let g:terminal_color_15 = '$color15'
+EOF
+
+# color scheme
+cat << EOF > 'colorscheme.vim'
+colorscheme $vim_theme_name
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_wall b/home/dot_local/share/mode/switch.d/executable_wall
new file mode 100644
index 0000000..c5ced92
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_wall
@@ -0,0 +1,2 @@
+#!/bin/sh
+bgcol "$bg"
diff --git a/home/dot_local/share/mode/switch.d/executable_xrdb b/home/dot_local/share/mode/switch.d/executable_xrdb
new file mode 100644
index 0000000..591a530
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_xrdb
@@ -0,0 +1,22 @@
+#!/bin/sh
+cat << EOF | xrdb -override
+*.color0: $color0
+*.color1: $color1
+*.color2: $color2
+*.color3: $color3
+*.color4: $color4
+*.color5: $color5
+*.color6: $color6
+*.color7: $color7
+*.color8: $color8
+*.color9: $color9
+*.color10: $color10
+*.color11: $color11
+*.color12: $color12
+*.color13: $color13
+*.color14: $color14
+*.color15: $color15
+*.foreground: $fg
+*.background: $bg
+EOF
+
diff --git a/home/dot_local/share/mode/switch.d/executable_zathura b/home/dot_local/share/mode/switch.d/executable_zathura
new file mode 100644
index 0000000..8d7e311
--- /dev/null
+++ b/home/dot_local/share/mode/switch.d/executable_zathura
@@ -0,0 +1,27 @@
+#!/bin/sh
+[ $no_cfg -eq 1 ] && return
+
+mkcd "$XDG_CONFIG_HOME/zathura"
+cat << EOF > 'colors'
+set completion-bg "$bg"
+set completion-fg "$fg"
+set completion-highlight-bg "$accent"
+set completion-highlight-fg "$accent_text"
+set default-bg "$bg"
+set default-fg "$fg"
+set highlight-active-color "$(echo "$accent" | pastel set alpha 0.5 | pastel format rgb)"
+set highlight-color "$(echo "$accent_text" | pastel set alpha 0.5 | pastel format rgb)"
+set inputbar-bg "$bg"
+set inputbar-fg "$fg"
+set notification-bg "$bg"
+set notification-error-bg "$color9"
+set notification-error-fg "$bg"
+set notification-fg "$fg"
+set notification-warning-bg "$color9"
+set notification-warning-fg "$bg"
+set recolor-darkcolor "$fg"
+set recolor-lightcolor "$bg"
+set statusbar-bg "$bg"
+set statusbar-fg "$fg"
+EOF
+
diff --git a/home/dot_local/share/mode/themes/github-black b/home/dot_local/share/mode/themes/github-black
new file mode 100644
index 0000000..34b507c
--- /dev/null
+++ b/home/dot_local/share/mode/themes/github-black
@@ -0,0 +1,25 @@
+#!/bin/sh
+mode=dark
+
+color0='#484f58'
+color1='#ffa198'
+color2='#56d364'
+color3='#e3b341'
+color4='#79c0ff'
+color5='#d2a8ff'
+color6='#56d4dd'
+color7='#b1bac4'
+color8='#6e7681'
+color9='#ff7b72'
+color10='#3fb950'
+color11='#d29922'
+color12='#58a6ff'
+color13='#bc8cff'
+color14='#39c5cf'
+color15='#ffffff'
+
+bg='#000000'
+fg='#e6edf3'
+
+vim_theme_name='ghdark'
+
diff --git a/home/dot_local/share/mode/themes/github-dark b/home/dot_local/share/mode/themes/github-dark
new file mode 100644
index 0000000..577106c
--- /dev/null
+++ b/home/dot_local/share/mode/themes/github-dark
@@ -0,0 +1,25 @@
+#!/bin/sh
+mode=dark
+
+color0='#484f58'
+color1='#ffa198'
+color2='#56d364'
+color3='#e3b341'
+color4='#79c0ff'
+color5='#d2a8ff'
+color6='#56d4dd'
+color7='#b1bac4'
+color8='#6e7681'
+color9='#ff7b72'
+color10='#3fb950'
+color11='#d29922'
+color12='#58a6ff'
+color13='#bc8cff'
+color14='#39c5cf'
+color15='#ffffff'
+
+bg='#0d1117'
+fg='#e6edf3'
+
+vim_theme_name='ghdark'
+
diff --git a/home/dot_local/share/mode/themes/github-light b/home/dot_local/share/mode/themes/github-light
new file mode 100644
index 0000000..d0162f8
--- /dev/null
+++ b/home/dot_local/share/mode/themes/github-light
@@ -0,0 +1,25 @@
+#!/bin/sh
+mode=light
+
+color0='#d1d5da'
+color1='#cb2431'
+color2='#22863a'
+color3='#b08800'
+color4='#005cc5'
+color5='#5a32a3'
+color6='#3192aa'
+color7='#6a737d'
+color8='#959da5'
+color9='#d73a49'
+color10='#28a745'
+color11='#dbab09'
+color12='#0366d6'
+color13='#5a32a3'
+color14='#1b7c83'
+color15='#24292e'
+
+bg='#ffffff'
+fg='#24292e'
+
+vim_theme_name='github-light'
+
diff --git a/home/dot_local/share/mode/themes/rose-pine-dawn b/home/dot_local/share/mode/themes/rose-pine-dawn
new file mode 100644
index 0000000..dfed420
--- /dev/null
+++ b/home/dot_local/share/mode/themes/rose-pine-dawn
@@ -0,0 +1,28 @@
+#!/bin/sh
+mode=light
+
+color0='#c4bdc3'
+color1='#b4637a'
+color2='#286983'
+color3='#ea9d34'
+color4='#56949f'
+color5='#907aa9'
+color6='#d7827e'
+color7='#575279'
+color8='#797593'
+color9='#b4637a'
+color10='#286983'
+color11='#ea9d34'
+color12='#56949f'
+color13='#907aa9'
+color14='#d7827e'
+color15='#575279'
+
+bg='#faf4ed'
+fg='#575279'
+
+accent='#d7827e'
+accent_text='#f4ede8'
+
+vim_theme_name='rose-pine-dawn'
+
diff --git a/home/dot_local/share/mode/themes/symlink_dark b/home/dot_local/share/mode/themes/symlink_dark
new file mode 100644
index 0000000..b5d11f8
--- /dev/null
+++ b/home/dot_local/share/mode/themes/symlink_dark
@@ -0,0 +1 @@
+github-dark
diff --git a/home/dot_local/share/mode/themes/symlink_light b/home/dot_local/share/mode/themes/symlink_light
new file mode 100644
index 0000000..2c27e1d
--- /dev/null
+++ b/home/dot_local/share/mode/themes/symlink_light
@@ -0,0 +1 @@
+github-light
diff --git a/home/dot_local/share/mode/themes/xcode-dark b/home/dot_local/share/mode/themes/xcode-dark
new file mode 100644
index 0000000..eb75b80
--- /dev/null
+++ b/home/dot_local/share/mode/themes/xcode-dark
@@ -0,0 +1,24 @@
+#!/bin/sh
+mode=dark
+
+color0='#43454b'
+color1='#ff8a7a'
+color2='#83c9bc'
+color3='#d9c668'
+color4='#4ec4e6'
+color5='#ff85b8'
+color6='#cda1ff'
+color7='#ffffff'
+color8='#838991'
+color9='#ff8a7a'
+color10='#b1faeb'
+color11='#ffa14f'
+color12='#6bdfff'
+color13='#ff85b8'
+color14='#e5cfff'
+color15='#ffffff'
+
+bg='#1f1f24'
+fg='#e6edf3'
+
+vim_theme_name='xcodedarkhc'
diff --git a/home/dot_local/share/oh-my-zsh/completions/_fork b/home/dot_local/share/oh-my-zsh/completions/_fork
new file mode 100644
index 0000000..7b76938
--- /dev/null
+++ b/home/dot_local/share/oh-my-zsh/completions/_fork
@@ -0,0 +1,2 @@
+#compdef fork
+_precommand "$@"
diff --git a/home/dot_local/share/oh-my-zsh/themes/loek.zsh-theme b/home/dot_local/share/oh-my-zsh/themes/loek.zsh-theme
new file mode 100644
index 0000000..5231234
--- /dev/null
+++ b/home/dot_local/share/oh-my-zsh/themes/loek.zsh-theme
@@ -0,0 +1,17 @@
+INFO_COLOR=$'%{\e[90m%}' # bright gray
+SEPARATOR_COLOR=$'%{\e[30m%}' # normal gray
+RESET_COLOR=$'%{\e[0m%}'
+
+SEPARATOR="$SEPARATOR_COLOR -> "
+
+PROMPT=""
+# only display hostname in prompt if connected over SSH
+[ -n "$SSH_CLIENT" ] && PROMPT+="$INFO_COLOR%m$SEPARATOR"
+PROMPT+="$INFO_COLOR%c$SEPARATOR" # working directory
+PROMPT+="$INFO_COLOR\$(git_prompt_info)" # git info (if in repo)
+PROMPT+="$RESET_COLOR"
+
+ZSH_THEME_GIT_PROMPT_PREFIX="${INFO_COLOR}git "
+ZSH_THEME_GIT_PROMPT_SUFFIX="$SEPARATOR"
+
+# vim:ft=zsh
diff --git a/home/dot_local/share/pass-extensions/executable_directory.bash b/home/dot_local/share/pass-extensions/executable_directory.bash
new file mode 100644
index 0000000..84db500
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/executable_directory.bash
@@ -0,0 +1,12 @@
+#!/bin/bash
+# print the initialized password store directory as a fully qualified path.
+# exits with code 1 if the password store is not initialized.
+dir="${PASSWORD_STORE_DIR-$HOME/.password-store}"
+dir="$(realpath "$dir")"
+if [ -e "$dir/.gpg-id" ] ; then
+ echo "$dir"
+else
+ echo "error: password store is not initialized" >&2
+ exit 1
+fi
+
diff --git a/home/dot_local/share/pass-extensions/executable_duplicates.bash b/home/dot_local/share/pass-extensions/executable_duplicates.bash
new file mode 100644
index 0000000..3ba47aa
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/executable_duplicates.bash
@@ -0,0 +1,45 @@
+#!/bin/bash
+declare -A dupe_tally dupe_map
+
+pass_names="$(pass names -l)"
+[ $? -ne 0 ] && exit 1
+
+pass_count="$(echo "$pass_names" | wc -l)"
+pass_index=1
+
+while read pass_name ; do
+ hash="$(pass show "$pass_name" | head -n1 | sha1sum | cut -c1-40)"
+
+ dupe_map["$pass_name"]="$hash"
+ dupe_tally["$hash"]=$(( ${dupe_tally["$hash"]} + 1 ))
+
+ printf '\rhashing... (%d/%d)' "$pass_index" "$pass_count" >&2
+ pass_index=$(( $pass_index + 1 ))
+done < <(echo "$pass_names")
+printf '\r\e[2K' >&2
+
+unique_duplicates=0
+total_shared=0
+
+for talley_key in "${!dupe_tally[@]}" ; do
+ [ "${dupe_tally["$talley_key"]}" -le 1 ] && continue;
+ unique_duplicates=$(( $unique_duplicates + 1 ))
+
+ echo "same password:"
+ for pass_name in "${!dupe_map[@]}" ; do
+ [ "${dupe_map["$pass_name"]}" != "$talley_key" ] && continue;
+ echo "- $pass_name"
+ total_shared=$(( $total_shared + 1 ))
+ done
+ echo
+done
+
+echo "summary:"
+if [ $unique_duplicates -eq 0 ] ; then
+ echo "- no duplicates"
+else
+ cat << EOF
+- found $unique_duplicates password(s) that were used more than once
+- you should change all $total_shared passwords listed above
+EOF
+fi
diff --git a/home/dot_local/share/pass-extensions/executable_exit.bash b/home/dot_local/share/pass-extensions/executable_exit.bash
new file mode 100644
index 0000000..06bd986
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/executable_exit.bash
@@ -0,0 +1,2 @@
+#!/bin/bash
+exit 0
diff --git a/home/dot_local/share/pass-extensions/executable_g.bash b/home/dot_local/share/pass-extensions/executable_g.bash
new file mode 100644
index 0000000..4ab3ace
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/executable_g.bash
@@ -0,0 +1,2 @@
+#!/bin/bash
+exec pass git "$@"
diff --git a/home/dot_local/share/pass-extensions/executable_names.bash b/home/dot_local/share/pass-extensions/executable_names.bash
new file mode 100644
index 0000000..aa42ebf
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/executable_names.bash
@@ -0,0 +1,46 @@
+#!/bin/bash
+# list all passwords in store
+
+pass_dir="$(pass directory)"
+[ $? -ne 0 ] && exit 1
+cd "$pass_dir"
+
+usage() {
+ cat << EOF
+usage:
+ pass names [-hl]
+
+options:
+ -l ignore symbolic links in password store
+ -h show this help
+EOF
+ exit $1
+}
+
+ARGC=0
+while getopts lh OPT; do
+ [ $OPTIND -gt $ARGC ] && ARGC=$OPTIND
+ case $OPT in
+ l)
+ opt_ignore_symlinks=y
+ ;;
+ h) usage 0 ;;
+ \?|*) usage 1 ;;
+ esac
+done
+
+find_args=()
+
+if [ -n "$opt_ignore_symlinks" ] ; then
+ find_args+=(-P) # ignore symbolic links
+else
+ find_args+=(-L) # follow symbolic links
+fi
+find_args+=(.)
+find_args+=(-type d -name .git -prune) # skip .git directory
+find_args+=(-o -type d -name .extensions -prune) # skip .extensions directory
+find_args+=(-o -type f -name '*.gpg') # only .gpg files
+find_args+=(-print)
+
+find "${find_args[@]}" | cut -c3- | rev | cut -c5- | rev
+
diff --git a/home/dot_local/share/pass-extensions/executable_treasure.bash b/home/dot_local/share/pass-extensions/executable_treasure.bash
new file mode 100644
index 0000000..e79ec24
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/executable_treasure.bash
@@ -0,0 +1,47 @@
+#!/bin/bash
+TAB="$(printf '\t')"
+
+# TODO: add options:
+# --help to display some help
+# --list to list all the versions of a password
+
+# print error if fzf is not found
+command -v fzf > /dev/null || exec bash -c fzf || exit 1
+
+# load pass source code for accessing internals
+exit() { true ; } # disable exit command
+. "$(command -v pass)" exit # source pass source (bash)
+exit() { command exit ; } # restore exit command
+
+cd "$(pass directory)"
+
+set_git "$PWD/"
+if [ -z "$INNER_GIT_DIR" ] ; then
+ cat << "EOF" >&2
+pass-treasure only works when the password store is tracked under version
+control using git!
+EOF
+fi
+
+# create a list of all files that ever existed in the password store
+# repository, then filter empty lines (created by git log), only show file
+# names ending in .gpg, and sort the list
+repo_files_all="$(\
+ cmd_git log --all --pretty="format:" --name-only --diff-filter=A |\
+ sed '/^$/d' | sed -n '/\.gpg$/p' |\
+ sort)"
+
+IFS="$TAB" read -r date file hash < <(
+ while read -u 3 -r file ; do
+ while IFS="$TAB" read -u 4 -r hash date ; do
+ printf '%s\t%s\t%s\n' "$date" "$file" "$hash"
+ done 4< <(
+ cmd_git log --no-patch --diff-filter=ABCMRTUX --format="format:%H$TAB%ad" \
+ -- "$file"
+ echo
+ )
+ done 3< <( echo "$repo_files_all" ) | fzf --tabstop=4
+)
+
+cmd_git cat-file -p "$hash:$file" | $GPG -d "${GPG_OPTS[@]}" -
+
diff --git a/home/dot_local/share/pass-extensions/symlink_dir.bash b/home/dot_local/share/pass-extensions/symlink_dir.bash
new file mode 100644
index 0000000..cb34588
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/symlink_dir.bash
@@ -0,0 +1 @@
+directory.bash
diff --git a/home/dot_local/share/pass-extensions/symlink_dupes.bash b/home/dot_local/share/pass-extensions/symlink_dupes.bash
new file mode 100644
index 0000000..59c3653
--- /dev/null
+++ b/home/dot_local/share/pass-extensions/symlink_dupes.bash
@@ -0,0 +1 @@
+duplicates.bash
diff --git a/home/dot_local/share/private_gnupg/private_gpg-agent.conf b/home/dot_local/share/private_gnupg/private_gpg-agent.conf
new file mode 100644
index 0000000..4e3bb5d
--- /dev/null
+++ b/home/dot_local/share/private_gnupg/private_gpg-agent.conf
@@ -0,0 +1,3 @@
+allow-preset-passphrase
+max-cache-ttl 604800
+pinentry-program /usr/bin/pinentry-gtk