summary refs log tree commit diff
path: root/.config
diff options
context:
space:
mode:
Diffstat (limited to '.config')
-rw-r--r--.config/aerc/aerc.conf2
-rw-r--r--.config/aerc/binds.conf2
-rw-r--r--.config/autowt/config.toml15
-rw-r--r--.config/darkman/config.yaml8
-rw-r--r--.config/fuzzel/fuzzel.ini9
-rw-r--r--.config/git/config18
-rw-r--r--.config/git/ignore3
-rw-r--r--.config/git/url.cfg14
-rw-r--r--.config/mako/config5
-rw-r--r--.config/mimeapps.list19
-rw-r--r--.config/mpv/config40
-rw-r--r--.config/mpv/input.conf39
-rw-r--r--.config/mpv/mvi/input.conf27
-rw-r--r--.config/mpv/script-opts/subs2srs.conf22
-rw-r--r--.config/mpv/script-opts/thumbfast.conf4
-rw-r--r--.config/msmtp/config28
-rw-r--r--.config/nvim/after/ftplugin/gitrebase.lua19
-rw-r--r--.config/nvim/after/ftplugin/go.lua32
-rw-r--r--.config/nvim/after/ftplugin/help.lua2
-rw-r--r--.config/nvim/after/ftplugin/janet.lua3
-rw-r--r--.config/nvim/after/ftplugin/markdown.lua9
-rw-r--r--.config/nvim/after/ftplugin/todotxt.lua13
-rw-r--r--.config/nvim/after/ftplugin/vala.lua1
-rw-r--r--.config/nvim/after/lsp/gopls.lua1
-rw-r--r--.config/nvim/after/lsp/harper_ls.lua11
-rw-r--r--.config/nvim/after/lsp/pylsp.lua3
-rw-r--r--.config/nvim/after/luasnippets/gitcommit.lua24
-rw-r--r--.config/nvim/after/luasnippets/zig.lua14
-rw-r--r--.config/nvim/init.lua13
-rw-r--r--.config/nvim/lazy-lock.json44
-rw-r--r--.config/nvim/lua/config/autoall.lua35
-rw-r--r--.config/nvim/lua/config/keymaps.lua16
-rw-r--r--.config/nvim/lua/config/lsp.lua5
-rw-r--r--.config/nvim/lua/config/options.lua7
-rw-r--r--.config/nvim/lua/config/snippets.lua84
-rw-r--r--.config/nvim/lua/config/templates.lua53
-rw-r--r--.config/nvim/lua/mod/gh.lua86
-rw-r--r--.config/nvim/lua/mod/git.lua23
-rw-r--r--.config/nvim/lua/mod/jobs.lua68
-rw-r--r--.config/nvim/lua/mod/termopen.lua102
-rw-r--r--.config/nvim/lua/mod/utils.lua15
-rw-r--r--.config/nvim/lua/mod/win.lua110
-rw-r--r--.config/nvim/lua/plugins/blink.lua23
-rw-r--r--.config/nvim/lua/plugins/calcium.lua1
-rw-r--r--.config/nvim/lua/plugins/colorizer.lua5
-rw-r--r--.config/nvim/lua/plugins/colors.lua12
-rw-r--r--.config/nvim/lua/plugins/diff.lua47
-rw-r--r--.config/nvim/lua/plugins/fzf.lua98
-rw-r--r--.config/nvim/lua/plugins/gentoo.lua1
-rw-r--r--.config/nvim/lua/plugins/git.lua7
-rw-r--r--.config/nvim/lua/plugins/haunt.lua47
-rw-r--r--.config/nvim/lua/plugins/icons.lua1
-rw-r--r--.config/nvim/lua/plugins/indent.lua1
-rw-r--r--.config/nvim/lua/plugins/lsp.lua29
-rw-r--r--.config/nvim/lua/plugins/markdown.lua2
-rw-r--r--.config/nvim/lua/plugins/mini.lua4
-rw-r--r--.config/nvim/lua/plugins/minimap.lua13
-rw-r--r--.config/nvim/lua/plugins/oil.lua1
-rw-r--r--.config/nvim/lua/plugins/snippets.lua1
-rw-r--r--.config/nvim/lua/plugins/treesitter.lua5
-rw-r--r--.config/nvim/lua/plugins/whichkey.lua10
-rw-r--r--.config/nvim/plugin/mod.lua25
-rw-r--r--.config/pimsync/pimsync.conf18
-rw-r--r--.config/rc/conf.d/podman1
-rwxr-xr-x.config/rc/init.d/secretsd18
-rwxr-xr-x.config/rc/init.d/syncthing7
-rwxr-xr-x.config/rc/init.d/xdg-desktop-portal13
l---------.config/rc/runlevels/desktop/fcitx51
l---------.config/rc/runlevels/desktop/secretsd1
l---------[-rwxr-xr-x].config/river/init144
-rwxr-xr-x.config/river/init3148
-rw-r--r--.config/starship.toml7
-rw-r--r--.config/tridactyl/themes/r.css4
-rw-r--r--.config/tridactyl/tridactylrc9
-rw-r--r--.config/tridactyl/tridactylrc.default2
-rw-r--r--.config/waybar/config.jsonc140
-rw-r--r--.config/waybar/menu-network.xml10
-rwxr-xr-x.config/waybar/module-calendar.sh11
-rwxr-xr-x.config/waybar/module-tailscale.sh7
-rw-r--r--.config/waybar/style-dark.css3
-rw-r--r--.config/waybar/style-light.css5
-rw-r--r--.config/waybar/style.css35
-rw-r--r--.config/yt-dlp.conf1
83 files changed, 1539 insertions, 427 deletions
diff --git a/.config/aerc/aerc.conf b/.config/aerc/aerc.conf
index 2dd82e2..cd944c2 100644
--- a/.config/aerc/aerc.conf
+++ b/.config/aerc/aerc.conf
@@ -36,7 +36,7 @@ file-picker-cmd=porta filechooser
 X-GitHub-Recipient,robertgzr=github-review-fix | colorize
 
 # keep defaults around
-text/html=html | colorize
+text/html=!html
 text/plain=wrap | colorize
 text/calendar=calendar
 message/delivery-status=colorize
diff --git a/.config/aerc/binds.conf b/.config/aerc/binds.conf
index 3540547..426c80f 100644
--- a/.config/aerc/binds.conf
+++ b/.config/aerc/binds.conf
@@ -1,6 +1,7 @@
 <C-h> = :prev-tab<cr>
 <C-l> = :next-tab<cr>
 <C-t> = :term<cr>
+<C-z> = :term<cr>
 ? = :help keys<cr>
 
 
@@ -120,6 +121,7 @@ Rq = :reply -q<cr>
 
 H = :toggle-headers<cr>
 <C-w> = :open-link<space>
+<C-o> = <esc>M<cr>
 
 ym = :pipe -sd k2 fmt -body | wl-copy -nf<cr>
 yf = :pipe -sd k2 fmt -headers=from | awk '{print $2}' | wl-copy -nf<cr>
diff --git a/.config/autowt/config.toml b/.config/autowt/config.toml
new file mode 100644
index 0000000..eee6257
--- /dev/null
+++ b/.config/autowt/config.toml
@@ -0,0 +1,15 @@
+[cleanup]
+default_mode = "interactive"
+
+[terminal]
+mode = "inplace"
+
+[worktree]
+auto_fetch = true
+directory_pattern = "../worktrees/{repo_name}@{branch}"
+flatten_worktree_directories = true
+
+[scripts.custom.fuzz]
+branch_name = "git-fuzzy worktrees $1"
+[scripts.custom.z]
+branch_name = "git-fuzzy worktrees $1"
diff --git a/.config/darkman/config.yaml b/.config/darkman/config.yaml
index 6271b4b..e55c77d 100644
--- a/.config/darkman/config.yaml
+++ b/.config/darkman/config.yaml
@@ -1,7 +1,7 @@
 ## berlin
-# lat: 52.52
-# lng: 13.40
+lat: 52.52
+lng: 13.40
 # tokyo
-lat: 35.68
-lng: 139.76
+# lat: 35.68
+# lng: 139.76
 portal: true
diff --git a/.config/fuzzel/fuzzel.ini b/.config/fuzzel/fuzzel.ini
index a6befa0..39f17e9 100644
--- a/.config/fuzzel/fuzzel.ini
+++ b/.config/fuzzel/fuzzel.ini
@@ -9,12 +9,12 @@ width=40
 vertical-pad=4
 horizontal-pad=8
 inner-pad=4
-keyboard-focus=on-demand
-exit-on-keyboard-focus-loss=yes
+# keyboard-focus=on-demand
+exit-on-keyboard-focus-loss=no
 use-bold=no
 hide-prompt=no
 prompt="󰈲 "
-terminal=foot -a '{cmd}' -T '{cmd}' {cmd}
+terminal=foot --app-id '{cmd}' --title '{cmd}' -e {cmd}
 dpi-aware=no
 # gamma-correct=yes
 match-counter=yes
@@ -24,3 +24,6 @@ scaling-filter=lanczos3
 [border]
 width=2
 radius=0
+
+[key-bindings]
+cancel=Escape
diff --git a/.config/git/config b/.config/git/config
index 458280d..8c7f26e 100644
--- a/.config/git/config
+++ b/.config/git/config
@@ -27,7 +27,7 @@
     helper = !sh -c 'rbw get f94a873d-9d72-412e-a46d-53e4cd19a291 | xargs printf password=%s\\n'
 
 [core]
-    excludesfile = $HOME/.config/git/ignore
+    excludesfile = ~/.config/git/ignore
     filemode = false
     pager = less -F
 
@@ -65,7 +65,7 @@
     fix = "!f() { local c=${1:-$(git fuzzy commits || :)}; test -n \"$c\" && git fixup $c && git ri $c^; }; f"
     fixup = "!f() { local c=${1:-$(git fuzzy commits || :)}; test -n \"$c\" && git commit --fixup=$c; }; f"
     grep = grep --break --heading --line-number
-    l = !tig
+    l = nvlog
     ls = log --graph --decorate --stat
     mt = mergetool
     pushf = push --force-with-lease
@@ -175,17 +175,7 @@
 
 [includeIf "gitdir:~/src/unikraft/**"]
     path = ~/src/unikraft/.gitconfig
-
-
-# url rewrites
-; [url "git@github.com:"]
-;     insteadOf = "https://github.com/"
-[url "git@git.sr.ht:"]
-    insteadOf = "https://git.sr.ht/"
-; [url "git@bitbucket.org:"]
-;     insteadOf = "https://bitbucket.org/"
-; [url "git@gitlab.com:"]
-;     insteadOf = "https://gitlab.com/"
-
+[includeIf "gitdir:~/src/**"]
+    path = ~/.config/git/url.cfg
 
 ; vim: expandtab shiftwidth=4
diff --git a/.config/git/ignore b/.config/git/ignore
index 33b0186..56516aa 100644
--- a/.config/git/ignore
+++ b/.config/git/ignore
@@ -47,6 +47,9 @@ bower_components
 # personal stuff
 .todo.md
 .org.md
+todo.txt
+.nvim.lua
+.autowt.toml
 
 # clangd
 .cache/
diff --git a/.config/git/url.cfg b/.config/git/url.cfg
new file mode 100644
index 0000000..1631797
--- /dev/null
+++ b/.config/git/url.cfg
@@ -0,0 +1,14 @@
+# url rewrites
+
+[url "git@git.sr.ht:"]
+	insteadOf = "https://git.sr.ht/"
+
+[url "git@codeberg.org:"]
+	insteadOf = "https://codeberg.org/"
+
+[url "git@github.com:"]
+	insteadOf = "https://github.com/"
+
+[url "git@gitlab.com:"]
+	insteadOf = "https://gitlab.com/"
+
diff --git a/.config/mako/config b/.config/mako/config
index 0329579..759616f 100644
--- a/.config/mako/config
+++ b/.config/mako/config
@@ -33,3 +33,8 @@ padding=6
 #
 # [mode=dnd]
 # invisible=1
+
+[app-name=tim]
+anchor=center
+text-alignment=center
+layer=overlay
diff --git a/.config/mimeapps.list b/.config/mimeapps.list
index 013ffc9..1397681 100644
--- a/.config/mimeapps.list
+++ b/.config/mimeapps.list
@@ -1,7 +1,22 @@
 [Default Applications]
-x-scheme-handler/https=urlopen.desktop
-x-scheme-handler/http=urlopen.desktop
+x-scheme-handler/https=urlopen.desktop;
+x-scheme-handler/http=urlopen.desktop;
 application/pdf=org.gnome.Papers.desktop;
+inode/directory=thunar.desktop;
+x-scheme-handler/rpi-imager=com.raspberrypi.rpi-imager-uri-handler.desktop
 
 [Added Associations]
 application/rss+xml=nvim.desktop;
+audio/x-opus+ogg=io.mpv-mpa.desktop;
+application/json=nvim.desktop;
+application/pdf=librewolf.desktop;org.gimp.GIMP.desktop;
+video/webm=mpv.desktop;
+image/gif=io.mpv-mvi.desktop;
+audio/x-mpegurl=nvim.desktop;
+image/png=io.mpv-mvi.desktop;org.gimp.GIMP.desktop;
+video/mp4=mpv.desktop;urlopen.desktop;
+application/zip=org.gnome.Papers.desktop;
+application/vnd.openxmlformats-officedocument.wordprocessingml.document=org.gnome.Papers.desktop;
+application/x-zerosize=nvim.desktop;
+image/jxl=org.gnome.Loupe.desktop;
+audio/x-matroska=mpv.desktop;
diff --git a/.config/mpv/config b/.config/mpv/config
index 41b10cb..746839f 100644
--- a/.config/mpv/config
+++ b/.config/mpv/config
@@ -1,10 +1,20 @@
-vo = gpu-next
-hwdec = auto
+# https://github.com/mpv-player/mpv/discussions/13909
+# vo=gpu-next
+# gpu-api=vulkan
+# hwdec=vulkan
 
-screenshot-directory = ~/pictures/screenshots/mpv
-screenshot-template = '%tY%tm%td-%tH%tM%tS-%F-%p'
-screenshot-format = png
-screenshot-png-compression = 9
+autofit-larger=90%x80%
+
+screenshot-directory=~/pictures/screenshots/mpv
+screenshot-template='%tY%tm%td-%tH%tM%tS-%F-%p'
+screenshot-format=png
+screenshot-png-compression=9
+
+sub-font=Rosario
+sub-ass-override=scale
+sub-file-paths=subs:Subs:subtitles:sub:~/desktop/subs
+
+save-watch-history=yes
 
 #
 # profiles
@@ -13,6 +23,9 @@ screenshot-png-compression = 9
 [fullscreen]
 vo=dmabuf-wayland
 
+[anon]
+save-watch-history=no
+
 [protocol.http]
 profile-desc="Optimized for streaming video"
 glsl-shaders-clr
@@ -34,14 +47,15 @@ osc=yes
 osd-bar=yes
 
 [bigcache]
-demuxer-readahead-secs=20
-demuxer-max-bytes=512M
+cache=yes
+demuxer-readahead-secs=120
+demuxer-max-bytes=1G
 demuxer-max-back-bytes=512M
 
-[gpuhq]
-profile-desc="Optimized for HQ rendering"
-profile-cond=height <= 1440
-profile=gpu-hq
+# [gpuhq]
+# profile-desc="Optimized for HQ rendering"
+# profile-cond=height <= 1440
+# profile=gpu-hq
 
 [scale]
 profile-desc="Use fancy scaling algorithms"
@@ -118,7 +132,7 @@ title="${?media-title:${media-title}}${!media-title:No file}"
 video-aspect-override=no
 loop-file=inf
 image-display-duration=inf
-input-conf=~~/mvi/input.conf
+input-commands-add=load-input-conf '~~/mvi/input.conf'
 input-commands-add=load-script '~~/mvi/scripts/ruler.lua'
 input-commands-add=load-script '~~/mvi/scripts/detect-image.lua'
 input-commands-add=load-script '~~/mvi/scripts/freeze-window.lua'
diff --git a/.config/mpv/input.conf b/.config/mpv/input.conf
index b67dab7..54e3755 100644
--- a/.config/mpv/input.conf
+++ b/.config/mpv/input.conf
@@ -29,11 +29,11 @@ HOME    seek 0 absolute-percent
 END     seek 100 absolute-percent
 $ seek 100 absolute-percent
 
-Shift+RIGHT     playlist-next
-n playlist-next  #! controls > playlist next
-Shift+LEFT      playlist-prev
-p playlist-prev  #! controls > playlist prev
-Alt+Shift+s playlist-shuffle  #! controls > playlist shuffle
+Shift+RIGHT     playlist-next  #! controls > playlist next
+Shift+LEFT      playlist-prev  #! controls > playlist prev
+Alt+Shift+s playlist-shuffle   #! controls > playlist shuffle
+n script-binding uosc/next     #! controls > next
+p script-binding uosc/prev     #! controls > prev
 
 #Alt+RIGHT       frame-step
 #Alt+LEFT        frame-back-step
@@ -53,12 +53,12 @@ PGUP        add chapter 1
 PGDWN       add chapter -1
 
 a cycle audio
-A script-binding uosc/audio #! select > audio
+A ignore
 D cycle deinterlace
-v script-binding uosc/video #! select > video
+V ignore
 
 s cycle sub
-S script-binding uosc/subtitles           #! select > sub
+S ignore
 Ctrl+s script-binding uosc/load-subtitles #! select > load sub...
 e add sub-scale +0.1                      #! sub > scale up
 w add sub-scale -0.1                      #! sub > scale down
@@ -72,8 +72,8 @@ X add audio-delay +0.1                    #! delay > audio +0.1
 Ctrl+z sub-step -1                        #! delay > sub-step -1
 Ctrl+x sub-step 1                         #! delay > sub-step +1
 
-U cycle-values sub-ass-override "scale" "force" "strip" "no"  #! sub > ass override
-V cycle sub-visibility  #! sub > visibility
+U cycle-values sub-ass-override "force" "no" "yes" "scale" "strip"  #! sub > ass override
+v cycle sub-visibility  #! sub > visibility
 # Meta+s cycle sub-ass-force-margins
 
 # PLAYER BINDINGS
@@ -126,13 +126,11 @@ Ctrl+SPACE script-binding uosc/toggle-ui
 MBTN_MID script-binding uosc/menu
 : script-binding uosc/menu
 Enter script-binding uosc/menu
-P script-binding uosc/items     #! select > playlist
-C script-binding uosc/chapters  #! select > chapters
+P ignore
+C ignore
 o script-binding uosc/open-file #! select > file...
 Ctrl+o script-binding openuri/openuri #! select > uri...
 Ctrl+Shift+o script-binding openuri/pasteuri #! select > paste
-Ctrl+n script-binding uosc/next-file
-Ctrl+p script-binding uosc/prev-file
 
 # various
 Alt+w script-binding webm/display-webm-encoder   #! utils > webm encoder
@@ -145,7 +143,15 @@ Alt+b script-binding blur/toggle-blur            #! utils > blur
 
 # gallery
 g ignore
-Shift+g script-message playlist-view-toggle  #! utils > playlist/gallery view
+g-SPACE script-binding uosc/menu
+g-a script-binding uosc/audio #! select > audio
+g-v script-binding uosc/video #! select > video
+g-c script-binding uosc/chapters  #! select > chapters
+g-s script-binding uosc/subtitles #! select > sub
+g-p script-binding uosc/items #! select > playlist
+
+g-g script-message playlist-view-toggle  #! utils > gallery
+Shift+g script-message playlist-view-toggle  #! utils > gallery
 
 # yanktime
 y-y script_binding yanky/yanktime  #! utils > yank > time
@@ -180,7 +186,6 @@ Ctrl+n  script-binding mpvacious-export-note #! mpvacious > export note
 I apply-profile interpolate   #! profiles > interpolate
 
 Ctrl+Shift+0 apply-profile reset         #! profiles > reset
-Ctrl+Shift+1 apply-profile interpolate   #! profiles > interpolate
-Ctrl+Shift+2 apply-profile cache         #! profiles > cache
+Ctrl+Shift+2 apply-profile bigcache      #! profiles > bigcache
 Ctrl+Shift+3 apply-profile scale         #! profiles > scale
 Ctrl+Shift+4 apply-profile compressor    #! profiles > compressor
diff --git a/.config/mpv/mvi/input.conf b/.config/mpv/mvi/input.conf
index 1d5b989..ccf35d2 100644
--- a/.config/mpv/mvi/input.conf
+++ b/.config/mpv/mvi/input.conf
@@ -4,28 +4,6 @@
 4 change-list script-opts append ruler-scale=25
 5 change-list script-opts append ruler-max_size=20,20
 
-SPACE repeatable playlist-next
-alt+SPACE repeatable playlist-prev
-
-# familiar binds
-n playlist-next
-p playlist-prev
-
-UP ignore
-DOWN ignore
-LEFT repeatable playlist-prev
-RIGHT repeatable playlist-next
-
-# simple reminder of default bindings
-#1 add contrast -1
-#2 add contrast 1
-#3 add brightness -1
-#4 add brightness 1
-#5 add gamma -1
-#6 add gamma 1
-#7 add saturation -1
-#8 add saturation 1
-
 # mouse-centric bindings
 MBTN_RIGHT script-binding drag-to-pan
 MBTN_LEFT  script-binding pan-follows-cursor
@@ -92,9 +70,6 @@ d script-message ruler
 # Toggling between pixel-exact reproduction and interpolation
 a cycle-values scale nearest ewa_lanczossharp
 
-# Toggle color management on or off
-c cycle icc-profile-auto
-
 # Screenshot of the window output
 S screenshot window
 
@@ -105,5 +80,5 @@ P script-message force-print-filename
 
 # ADVANCED: you can define bindings that belong to a "section" (named "image-viewer" here) like so:
 #alt+SPACE {image-viewer} repeatable playlist-prev
-#SPACE     {image-viewer} repeatable playlist-next
+SPACE     {image-viewer} repeatable playlist-next
 # to load them conditionally with a command. See scripts-opts/image_viewer.conf for how you can do this
diff --git a/.config/mpv/script-opts/subs2srs.conf b/.config/mpv/script-opts/subs2srs.conf
index 09e2af4..600bb63 100644
--- a/.config/mpv/script-opts/subs2srs.conf
+++ b/.config/mpv/script-opts/subs2srs.conf
@@ -1,13 +1,25 @@
-autoclip=yes
+check_for_updates=no
+reload_config_before_card_creation=yes
 
-deck_name=subs2srs
+autoclip=no
+
+allow_duplicates=no
+deck_name=AJT Mining::Mpvacious
 model_name=Japanese sentences
 sentence_field=SentKanji
 secondary_field=SentEng
 audio_field=SentAudio
 image_field=Image
-note_tag=subs2srs
+note_tag=mpvacious
+vocab_field=VocabKanji
+vocab_audio_field=VocabAudio
+miscinfo_enable=yes
+miscinfo_field=Notes
+miscinfo_format=%n (%t)
 
 use_ffmpeg=yes
-snapshot_format=webp
-opus_container=webm
+opus_container=ogg
+snapshot_format=avif
+snapshot_quality=50
+
+preview_audio=yes
diff --git a/.config/mpv/script-opts/thumbfast.conf b/.config/mpv/script-opts/thumbfast.conf
index 5f5a2a6..5be2221 100644
--- a/.config/mpv/script-opts/thumbfast.conf
+++ b/.config/mpv/script-opts/thumbfast.conf
@@ -6,10 +6,10 @@ tone_mapping=no
 network=no
 
 # Enable hardware decoding
-hwdec=yes
+hwdec=no
 
 # Spawn thumbnailer earlier for faster loads
-spawn_first=yes
+spawn_first=no
 
 # Make smaller thumbnails
 max_height=150
diff --git a/.config/msmtp/config b/.config/msmtp/config
new file mode 100644
index 0000000..1f108b1
--- /dev/null
+++ b/.config/msmtp/config
@@ -0,0 +1,28 @@
+# Set default values for all following accounts.
+defaults
+auth           on
+tls            on
+logfile        ~/.local/state/msmtp.log
+
+set_from_header auto
+set_date_header auto
+
+# gnzler
+account        gnzler
+host           smtp.mailfence.com
+port           465
+tls_starttls   off
+user           robertgzr
+passwordeval   rbw get 68b0ea26-733a-43cd-b8f8-e8ecc98de072
+from           robert@gnzler.de
+from_full_name Robert Günzler
+
+# gnzler alias 1
+account        gnzler.de : gnzler
+
+# gnzler alias 2
+account        gnzler.io : gnzler
+from           robert@gnzler.io
+
+# Default account
+account        default : gnzler.de
diff --git a/.config/nvim/after/ftplugin/gitrebase.lua b/.config/nvim/after/ftplugin/gitrebase.lua
index f85d3b9..fb64534 100644
--- a/.config/nvim/after/ftplugin/gitrebase.lua
+++ b/.config/nvim/after/ftplugin/gitrebase.lua
@@ -1,4 +1,19 @@
 vim.keymap.set('n', 'K', function()
-  -- local cword = vim.fn.expand('<cword>')
-  -- require('gitsigns').show_commit(cword, 'aboveleft split')
+  local commit = vim.fn.expand('<cword>')
+
+  local content = nil
+  require('mod.jobs').start({
+    cmd = { 'git', 'show', '--patch', '--stat', commit },
+    stdout_buffered = true,
+    on_stdout = function(_, stdout)
+      content = stdout
+    end,
+    on_exit = function()
+      require('mod.win').popup(
+        'git-show: ' .. commit,
+        content,
+        { buf = { filetype = 'gitcommit' } }
+      )
+    end,
+  })
 end, { desc = 'Lookup commit hash', buffer = 0 })
diff --git a/.config/nvim/after/ftplugin/go.lua b/.config/nvim/after/ftplugin/go.lua
new file mode 100644
index 0000000..ad5c56e
--- /dev/null
+++ b/.config/nvim/after/ftplugin/go.lua
@@ -0,0 +1,32 @@
+vim.api.nvim_create_autocmd({ 'LspAttach' }, {
+  pattern = '*.go',
+  group = vim.api.nvim_create_augroup('lspattach.go', {}),
+  callback = function(args)
+    local client = vim.lsp.get_client_by_id(args.data.client_id)
+    if not client:supports_method('workspace/executeCommand') then
+      return
+    end
+
+    vim.keymap.set('n', '<leader>i', function()
+      local p = vim
+        .system({
+          'sh',
+          '-c',
+          [[go mod graph | awk '{print $2}' | cut -d@ -f1 | sort -u]],
+        })
+        :wait()
+      local opts = vim.split(p.stdout, '\n')
+      vim.ui.select(opts, {}, function(choice)
+        client:exec_cmd({
+          command = 'gopls.add_import',
+          arguments = {
+            {
+              ['ImportPath'] = choice,
+              ['URI'] = vim.uri_from_bufnr(0),
+            },
+          },
+        })
+      end)
+    end, { desc = 'gopls: add import' })
+  end,
+})
diff --git a/.config/nvim/after/ftplugin/help.lua b/.config/nvim/after/ftplugin/help.lua
new file mode 100644
index 0000000..f41256a
--- /dev/null
+++ b/.config/nvim/after/ftplugin/help.lua
@@ -0,0 +1,2 @@
+-- open help in new tab
+vim.cmd.wincmd "T"
diff --git a/.config/nvim/after/ftplugin/janet.lua b/.config/nvim/after/ftplugin/janet.lua
new file mode 100644
index 0000000..a81b2f0
--- /dev/null
+++ b/.config/nvim/after/ftplugin/janet.lua
@@ -0,0 +1,3 @@
+vim.o.expandtab = true
+vim.o.shiftwidth = 2
+vim.o.commentstring = '# %s'
diff --git a/.config/nvim/after/ftplugin/markdown.lua b/.config/nvim/after/ftplugin/markdown.lua
new file mode 100644
index 0000000..538a6da
--- /dev/null
+++ b/.config/nvim/after/ftplugin/markdown.lua
@@ -0,0 +1,9 @@
+vim.opt_local.makeprg =
+  'pandoc -s -f markdown+wikilinks_title_after_pipe+autolink_bare_uris -t html -o /tmp/%.html %'
+
+vim.api.nvim_buf_create_user_command(0, 'OpenWeb', function()
+  local name = vim.fn.expand('%')
+  vim.system({ 'xdg-open', '/tmp/' .. name .. '.html' })
+end, { desc = 'markdown: open pdf' })
+
+vim.keymap.set('n', '<leader>o', '<cmd>OpenWeb<cr>', { desc = 'markdown: open web', buffer = 0 })
diff --git a/.config/nvim/after/ftplugin/todotxt.lua b/.config/nvim/after/ftplugin/todotxt.lua
index 526f29c..d5091b3 100644
--- a/.config/nvim/after/ftplugin/todotxt.lua
+++ b/.config/nvim/after/ftplugin/todotxt.lua
@@ -1 +1,14 @@
 vim.opt_local.textwidth = 0
+
+vim.keymap.set('n', '<m-x>', function()
+  require('mod.utils').edit_current_line(function(lines)
+    -- will only run for the current line
+    return vim.tbl_map(function(ln)
+      if string.sub(ln, 1, 2) == 'x ' then
+        return string.sub(ln, 3, -1)
+      else
+        return 'x ' .. ln
+      end
+    end, lines)
+  end)
+end, { desc = 'Check todo', buffer = 0 })
diff --git a/.config/nvim/after/ftplugin/vala.lua b/.config/nvim/after/ftplugin/vala.lua
new file mode 100644
index 0000000..3cbb257
--- /dev/null
+++ b/.config/nvim/after/ftplugin/vala.lua
@@ -0,0 +1 @@
+vim.o.commentstring = '// %s'
diff --git a/.config/nvim/after/lsp/gopls.lua b/.config/nvim/after/lsp/gopls.lua
index 5262a45..88ad048 100644
--- a/.config/nvim/after/lsp/gopls.lua
+++ b/.config/nvim/after/lsp/gopls.lua
@@ -1,4 +1,5 @@
 return {
+  filetypes = { 'go', 'gomod', 'gowork', 'gotmpl', 'templ' },
   settings = {
     gopls = {
       hints = {
diff --git a/.config/nvim/after/lsp/harper_ls.lua b/.config/nvim/after/lsp/harper_ls.lua
new file mode 100644
index 0000000..3298e30
--- /dev/null
+++ b/.config/nvim/after/lsp/harper_ls.lua
@@ -0,0 +1,11 @@
+return {
+  settings = {
+    ["harper-ls"] = {
+      userDictPath = "~/.config/dict.txt",
+      linters = {
+        SentenceCapitalization = false,
+        -- SpellCheck = false,
+      },
+    },
+  },
+}
diff --git a/.config/nvim/after/lsp/pylsp.lua b/.config/nvim/after/lsp/pylsp.lua
new file mode 100644
index 0000000..6f05ad8
--- /dev/null
+++ b/.config/nvim/after/lsp/pylsp.lua
@@ -0,0 +1,3 @@
+return {
+  -- settings = {},
+}
diff --git a/.config/nvim/after/luasnippets/gitcommit.lua b/.config/nvim/after/luasnippets/gitcommit.lua
new file mode 100644
index 0000000..91c686b
--- /dev/null
+++ b/.config/nvim/after/luasnippets/gitcommit.lua
@@ -0,0 +1,24 @@
+---@diagnostic disable: undefined-global
+return {
+  s({ trig = 'cz', descr = 'conventional commit' }, {
+    c(1, {
+      t('feat'),
+      t('fix'),
+      t('docs'),
+      t('style'),
+      t('refactor'),
+      t('perf'),
+      t('test'),
+      t('chore'),
+    }),
+    c(2, {
+      t(''),
+      sn(nil, {
+        t('('),
+        i(1, 'scope'),
+        t(')'),
+      }),
+    }),
+    t(': '),
+  }),
+}
diff --git a/.config/nvim/after/luasnippets/zig.lua b/.config/nvim/after/luasnippets/zig.lua
new file mode 100644
index 0000000..ab80e82
--- /dev/null
+++ b/.config/nvim/after/luasnippets/zig.lua
@@ -0,0 +1,14 @@
+---@diagnostic disable: undefined-global
+return {
+  s({trig = 'str'}, t("[]const u8")),
+  s({trig = 'test'}, {
+    c(1, {
+      t('a'),
+      t('b'),
+    }),
+    c(2, {
+      t('c'),
+      t('d'),
+    }),
+  }),
+}
diff --git a/.config/nvim/init.lua b/.config/nvim/init.lua
index 5dee508..4f4a22e 100644
--- a/.config/nvim/init.lua
+++ b/.config/nvim/init.lua
@@ -2,6 +2,9 @@ _G.feedkeys = function(keys)
   vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(keys, true, false, true), 'n', true)
 end
 
+-- enable experimental ui2
+require('vim._core.ui2').enable()
+
 require('config.lazy')
 require('config.filetypes')
 require('config.diagnostics')
@@ -11,3 +14,13 @@ require('config.options')
 require('config.statuscolumn')
 require('config.statusline')
 require('config.undo')
+require('config.templates')
+
+-- overwrite ui.open
+vim.ui.open = function(path, opt)
+  if opt and opt.cmd then
+    vim.uv.spawn(cmd, { args = { path } })
+  else
+    vim.uv.spawn('porta', { args = { 'open-uri', path, 'ask' } })
+  end
+end
diff --git a/.config/nvim/lazy-lock.json b/.config/nvim/lazy-lock.json
index 16e407a..f1f7047 100644
--- a/.config/nvim/lazy-lock.json
+++ b/.config/nvim/lazy-lock.json
@@ -1,32 +1,36 @@
 {
   "LuaSnip": { "branch": "master", "commit": "642b0c595e11608b4c18219e93b88d7637af27bc" },
   "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" },
+  "blink.indent": { "branch": "main", "commit": "2e9c9768affeaf3a48b2dc329eb59763012f79f6" },
   "calcium.nvim": { "branch": "main", "commit": "7a7d3740083fa5669e1a0f25d133705624a23f0d" },
-  "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" },
-  "fzf-lua": { "branch": "main", "commit": "9f0432fdd7825ab163520045831a40b6df82ea28" },
+  "diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" },
+  "fishbone.nvim": { "branch": "main", "commit": "0ea8e0f92330a1f57a0a2e66e66223e7ff1f087f" },
+  "friendly-snippets": { "branch": "main", "commit": "b4d01b0fdf3c9a549961c2f9ffe8dc09be166219" },
+  "fzf-lua": { "branch": "main", "commit": "13bb178a299f7493dd64427a58e61904c4b58ecb" },
   "gentoo-syntax": { "branch": "master", "commit": "1b3a81ec62e5c843245dc431be0fe072add7eca8" },
-  "git-dev.nvim": { "branch": "master", "commit": "90c1395ca37a38228e287d0a843835a5a39ce553" },
+  "git-dev.nvim": { "branch": "master", "commit": "727c9526a7fcbf980aa1bb2caf2383c74a543093" },
   "gitgraph.nvim": { "branch": "main", "commit": "c16daa7d7dd597caf9085644c009cfa80b75db8e" },
-  "gitlinker.nvim": { "branch": "master", "commit": "d7adb5e4ba5bab4fd443a3f4c46af3f4c864685d" },
-  "gitsigns.nvim": { "branch": "main", "commit": "0d797daee85366bc242580e352a4f62d67557b84" },
+  "gitlinker.nvim": { "branch": "master", "commit": "a1b74070bbd5e50128190c85b09f1431ea5fbd83" },
+  "gitsigns.nvim": { "branch": "main", "commit": "070a5d7b985546cc57e1fc61e5bc507fecac6045" },
   "guess-indent.nvim": { "branch": "main", "commit": "84a4987ff36798c2fc1169cbaff67960aed9776f" },
-  "haunt.nvim": { "branch": "main", "commit": "666d83868bac8b38f1dc765d9da6eca4d92c826f" },
-  "indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" },
-  "koda.nvim": { "branch": "main", "commit": "a560a332ccc1eb2caacb280a390213bb9f37b3cb" },
+  "haunt.nvim": { "branch": "main", "commit": "c973175dda88236ecda342fd3654b5dc4f6b7764" },
+  "indent-blankline.nvim": { "branch": "master", "commit": "f1e186e44d3b7f9ae918008e2c28ce37c6023d2d" },
+  "koda.nvim": { "branch": "main", "commit": "25a5c98ca2f6bb0b69f5e2654a78f0d7c7e0721d" },
   "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
   "markdown.nvim": { "branch": "master", "commit": "093be911d90de03877f3009de36081c1a6242d51" },
-  "mini.ai": { "branch": "main", "commit": "43eb2074843950a3a25aae56a5f41362ec043bfa" },
-  "mini.align": { "branch": "main", "commit": "6f3c69cd57134ad8fbf1e85dcdc90cb37a8c75c8" },
-  "mini.icons": { "branch": "main", "commit": "7fdae2443a0e2910015ca39ad74b50524ee682d3" },
-  "mini.operators": { "branch": "main", "commit": "fccb5e3ef0cc319b217ed9c7db1a4672dd6b766c" },
-  "mini.surround": { "branch": "main", "commit": "2715e04bea3ec9244f15b421dc5b18c0fe326210" },
+  "mini.ai": { "branch": "main", "commit": "6c39ae7b11abe479fbe1bc81bf00ac6bca7afa07" },
+  "mini.align": { "branch": "main", "commit": "77d7446b9f2452193f13ced9fb73a8b3aa4a4f4d" },
+  "mini.icons": { "branch": "main", "commit": "f642e3ba8c12afbc8f32f6d77ef6597eac56786f" },
+  "mini.operators": { "branch": "main", "commit": "9e0aa164b097c6cb45e59b9371c9347ac06eb822" },
+  "mini.surround": { "branch": "main", "commit": "33a2ebe5df8eb4751828fcba133e18ed0fbbdfab" },
   "none-ls-shellcheck.nvim": { "branch": "main", "commit": "0f84461241e76e376a95fb7391deac82dc3efdbf" },
-  "none-ls.nvim": { "branch": "main", "commit": "7f9301e416533b5d74e2fb3b1ce5059eeaed748b" },
-  "nvim-colorizer.lua": { "branch": "master", "commit": "c8c2c19436d33165ec34fa90c975bc0a739fe3fb" },
-  "nvim-lspconfig": { "branch": "master", "commit": "0203a9608d63eda57679b01e69f33a7b4c34b0d1" },
-  "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" },
-  "oil.nvim": { "branch": "master", "commit": "0fcc83805ad11cf714a949c98c605ed717e0b83e" },
-  "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
-  "render-markdown": { "branch": "main", "commit": "4ae2f2e8e8c66d070f33cfb57cb6f867e3baf5d9" },
+  "none-ls.nvim": { "branch": "main", "commit": "c4b82bb63b13856ba4d6b971b7aad3bb38fc6fe2" },
+  "nvim-colorizer.lua": { "branch": "master", "commit": "72a05f62c52241bc7441c820eb53946f92b2e6a4" },
+  "nvim-lspconfig": { "branch": "master", "commit": "4d363f93c3581b9212a24f7a830d7590b3f050af" },
+  "nvim-treesitter": { "branch": "main", "commit": "f603a2f4da48728f80257fb5fbb90145fd1dc173" },
+  "oil.nvim": { "branch": "master", "commit": "b73018b75affd13fa38e2fc94ef753b465f770d7" },
+  "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" },
+  "render-markdown": { "branch": "main", "commit": "640a3ec6d538bad17c328be373c7cad0293d9589" },
+  "satellite.nvim": { "branch": "main", "commit": "87843c9c8f28b54332497302de380a6d94c9e82b" },
   "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
 }
diff --git a/.config/nvim/lua/config/autoall.lua b/.config/nvim/lua/config/autoall.lua
new file mode 100644
index 0000000..6f36182
--- /dev/null
+++ b/.config/nvim/lua/config/autoall.lua
@@ -0,0 +1,35 @@
+-- Autocommands for all files opened in nvim
+local autocmd = vim.api.nvim_create_autocmd
+local autogrp = vim.api.nvim_create_augroup
+
+-- check if the current buffer is empty
+local bufempty = function(bufnr)
+  bufnr = bufnr or 0
+  if vim.api.nvim_buf_get_offset(bufnr, 0) <= 0 then
+    local handle = io.open(vim.api.nvim_buf_get_name(bufnr))
+    if handle == nil then
+      return true
+    end
+    local eof = handle:read(0)
+    handle:close()
+    if eof == nil then
+      return true
+    end
+  end
+  return false
+end
+
+local expand_template = function(name)
+  require('luasnip').snip_expand(require('config.templates')[name])
+  require('luasnip').unlink_current()
+end
+
+autocmd({ 'BufEnter', 'BufNewFile' }, {
+  pattern = 'deb/DEBIAN/changelog_blobs/*.txt',
+  group = autogrp('DebianChangelogTemplate', { clear = true }),
+  callback = function(opt)
+    if bufempty() then
+      return expand_template('debian-changelog')
+    end
+  end,
+})
diff --git a/.config/nvim/lua/config/keymaps.lua b/.config/nvim/lua/config/keymaps.lua
index a93b8fd..3c51041 100644
--- a/.config/nvim/lua/config/keymaps.lua
+++ b/.config/nvim/lua/config/keymaps.lua
@@ -1,7 +1,12 @@
 local map = vim.keymap.set
 
-map('n', 'gb', '<cmd>bnext<cr>', { desc = 'Buffer next' })
-map('n', 'gB', '<cmd>bprevious<cr>', { desc = 'Buffer prev' })
+map('n', 'gb', '<cmd>bnext<cr>', { desc = 'Buf next' })
+map('n', 'gB', '<cmd>bprevious<cr>', { desc = 'Buf prev' })
+
+map('n', '<c-h>', '<cmd>tabprev<cr>', { desc = 'Tab prev' })
+map('n', '<c-j>', '<cmd>bprev<cr>', { desc = 'Buf prev' })
+map('n', '<c-k>', '<cmd>bnext<cr>', { desc = 'Buf next' })
+map('n', '<c-l>', '<cmd>tabnext<cr>', { desc = 'Tab next' })
 
 map('n', '<a-j>', '<cmd>cnext<cr>', { desc = 'Quickfix next' })
 map('n', '<a-k>', '<cmd>cprev<cr>', { desc = 'Quickfix prev' })
@@ -21,8 +26,11 @@ map(
 vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWinEnter' }, {
   group = vim.api.nvim_create_augroup('bufclose', {}),
   callback = function()
-    if vim.list_contains({ 'help', 'nofile', 'quickfix' }, vim.bo.buftype) then
-      map('', 'q', '<cmd>close<cr>', { desc = 'Close buffer', buffer = 0 })
+    if
+      (vim.fn.maparg('q', 'n') == '')
+      and vim.list_contains({ 'help', 'nofile', 'nowrite', 'quickfix' }, vim.bo.buftype)
+    then
+      map('n', 'q', '<cmd>close<cr>', { desc = 'Close buffer', buffer = 0 })
     end
   end,
 })
diff --git a/.config/nvim/lua/config/lsp.lua b/.config/nvim/lua/config/lsp.lua
index b168014..5a2bf79 100644
--- a/.config/nvim/lua/config/lsp.lua
+++ b/.config/nvim/lua/config/lsp.lua
@@ -6,6 +6,8 @@ local lsp = vim.lsp
 
 lsp.enable({
   'bashls',
+  'blueprint_ls',
+  'buf_ls',
   'ccls',
   'clangd',
   'gopls',
@@ -14,6 +16,7 @@ lsp.enable({
   'rust_analyzer',
   'superhtml',
   'tinymist',
+  'vala_ls',
   'zk',
   'zls',
 })
@@ -35,7 +38,7 @@ lsp.config('*', {
 vim.api.nvim_create_autocmd({ 'LspAttach' }, {
   group = vim.api.nvim_create_augroup('lspattach', {}),
   callback = function(args)
-    local client = assert(vim.lsp.get_client_by_id(args.data.client_id))
+    local client = vim.lsp.get_client_by_id(args.data.client_id)
 
     -- TODO: what does this do?
     vim.opt_local.omnifunc = 'v:lua.vim.lsp.omnifunc'
diff --git a/.config/nvim/lua/config/options.lua b/.config/nvim/lua/config/options.lua
index 073835f..07a41a3 100644
--- a/.config/nvim/lua/config/options.lua
+++ b/.config/nvim/lua/config/options.lua
@@ -37,3 +37,10 @@ opt.mousescroll = 'ver:1,hor:6'
 
 -- load local vim config (will as to allow it)
 opt.exrc = true
+
+-- increase the auto-scroll window
+opt.scrolloff = 10
+
+-- use osc2 to set terminal title
+opt.title = true
+opt.titlestring = [[nvim: %t%( %M%)%( (%{expand("%:~:h")})%)%a]]
diff --git a/.config/nvim/lua/config/snippets.lua b/.config/nvim/lua/config/snippets.lua
index e0c260e..9cd0632 100644
--- a/.config/nvim/lua/config/snippets.lua
+++ b/.config/nvim/lua/config/snippets.lua
@@ -6,16 +6,24 @@ ls.config.set_config({
   enable_autosnippets = true,
   history = true,
   updateevents = 'TextChanged,TextChangedI',
-  override_builtin = true,
+  exit_roots = false, -- dont exit when reaching last node
   ext_opts = {
     [types.choiceNode] = {
-      active = {
-        virt_text = { { '◂    󰬊 ', 'NonText' } },
+      passive = {
+        virt_text = { { '󰬊 ', 'Conceal' } },
+        virt_text_pos = 'inline',
       },
     },
     [types.insertNode] = {
-      active = {
-        virt_text = { { '◂    󰬐 ', 'NonText' } },
+      passive = {
+        virt_text = { { '󰬐 ', 'Conceal' } },
+        virt_text_pos = 'inline',
+      },
+    },
+    [types.exitNode] = {
+      passive = {
+        virt_text = { { '$', 'Conceal' } },
+        virt_text_pos = 'inline',
       },
     },
   },
@@ -53,27 +61,6 @@ ls.config.set_config({
 require('luasnip.loaders.from_lua').lazy_load()
 require('luasnip.loaders.from_vscode').lazy_load({ include = {} })
 
--- keymaps
-vim.keymap.set({ 'i', 's' }, '<c-j>', function()
-  return vim.snippet.active({ direction = 1 }) and vim.snippet.jump(1)
-end, { silent = true, desc = 'snippet: jump next' })
-
-vim.keymap.set({ 'i', 's' }, '<c-k>', function()
-  return vim.snippet.active({ direction = -1 }) and vim.snippet.jump(-1)
-end, { silent = true, desc = 'snippet: jump prev' })
-
-vim.keymap.set({ 'i', 's' }, '<c-n>', function()
-  if ls.choice_active() then
-    ls.change_choice(1)
-  end
-end, { silent = true, desc = 'snippet: next choice' })
-
-vim.keymap.set({ 'i', 's' }, '<c-p>', function()
-  if ls.choice_active() then
-    ls.change_choice(-1)
-  end
-end, { silent = true, desc = 'snippet: prev choice' })
-
 -- usercmds
 vim.api.nvim_create_user_command('EditSnippets', require('luasnip.loaders').edit_snippet_files, {})
 
@@ -105,36 +92,23 @@ vim.api.nvim_create_user_command('EditSnippets', require('luasnip.loaders').edit
 vim.api.nvim_create_autocmd('ModeChanged', {
   pattern = '*',
   callback = function()
-    if ((vim.v.event.old_mode == 's' and vim.v.event.new_mode == 'n') or vim.v.event.old_mode == 'i')
-        and ls.session.current_nodes[vim.api.nvim_get_current_buf()]
-        and not ls.session.jump_active
-        and not require("blink.cmp").is_visible()
+    if
+      ((vim.v.event.old_mode == 's' or vim.v.event.old_mode == 'i') and vim.v.event.new_mode == 'n')
+      and ls.session.current_nodes[vim.api.nvim_get_current_buf()]
+      and not ls.session.jump_active
+      and not require('blink.cmp').is_visible()
     then
-      ls.unlink_current()
+      vim.schedule(ls.unlink_current)
     end
-  end
+  end,
 })
 
--- attach to builtin snippet hooks
-vim.snippet.expand = ls.lsp_expand
-vim.snippet.active = function(filter)
-  filter = filter or {}
-  filter.direction = filter.direction or 1
-  if filter.direction == 1 then
-    return ls.expand_or_jumpable()
-  else
-    return ls.jumpable(filter.direction)
-  end
-end
-vim.snippet.jump = function(direction)
-  if direction == 1 then
-    if ls.expandable() then
-      return ls.expand_or_jump()
-    else
-      return ls.jumpable(1) and ls.jump(1)
-    end
-  else
-    return ls.jumpable(-1) and ls.jump(-1)
-  end
-end
-vim.snippet.stop = ls.unlink_current
+-- expand/jump keymaps handled by blink
+
+vim.keymap.set({ 'i', 's' }, '<c-n>', function()
+  return ls.choice_active() and ls.change_choice(1)
+end, { silent = true, desc = 'luasnip: next choice' })
+
+vim.keymap.set({ 'i', 's' }, '<c-p>', function()
+  return ls.choice_active() and ls.change_choice(-1)
+end, { silent = true, desc = 'luasnip: prev choice' })
diff --git a/.config/nvim/lua/config/templates.lua b/.config/nvim/lua/config/templates.lua
new file mode 100644
index 0000000..a01efa1
--- /dev/null
+++ b/.config/nvim/lua/config/templates.lua
@@ -0,0 +1,53 @@
+-- template snippets
+require('luasnip').setup_snip_env()
+local templates = {}
+
+-- check if the current buffer is empty
+local bufempty = function(bufnr)
+  bufnr = bufnr or 0
+  if vim.api.nvim_buf_get_offset(bufnr, 0) <= 0 then
+    local handle = io.open(vim.api.nvim_buf_get_name(bufnr))
+    if handle == nil then
+      return true
+    end
+    local eof = handle:read(0)
+    handle:close()
+    if eof == nil then
+      return true
+    end
+  end
+  return false
+end
+
+local register_template = function(pattern, snip)
+  templates[pattern] = snip
+
+  vim.api.nvim_create_autocmd({ 'BufEnter', 'BufNewFile' }, {
+    pattern = pattern,
+    group = vim.api.nvim_create_augroup('Template' .. pattern, { clear = true }),
+    callback = function(opt)
+      if bufempty() then
+        require('luasnip').snip_expand(templates[pattern])
+        require('luasnip').unlink_current()
+      end
+    end,
+  })
+end
+
+register_template(
+  'deb/DEBIAN/changelog_blobs/*.txt',
+  s(
+    'debian-changelog',
+    fmt(
+      [[
+ukp-agent (${VERSION}) unstable; urgency=medium
+
+  * feat: <>
+]],
+      { i(0) },
+      {
+        delimiters = '<>',
+      }
+    )
+  )
+)
diff --git a/.config/nvim/lua/mod/gh.lua b/.config/nvim/lua/mod/gh.lua
new file mode 100644
index 0000000..1f8a267
--- /dev/null
+++ b/.config/nvim/lua/mod/gh.lua
@@ -0,0 +1,86 @@
+local M = {}
+
+-- gh api \
+--   --method POST \
+--   -H "Accept: application/vnd.github+json" \
+--   -H "X-GitHub-Api-Version: 2022-11-28" \
+--   /repos/OWNER/REPO/pulls/PULL_NUMBER/comments \
+
+function M.pr_comment(repo, pull, commit_id, comment)
+  vim.print(vim.inspect(comment))
+  vim.print(vim.inspect({
+    'gh',
+    'api',
+    '--method',
+    'POST',
+    string.format('/repos/%s/pulls/%d/comments', repo, pull),
+    '-f',
+    'body=' .. comment.body,
+    '-f',
+    'commit_id=' .. commit_id,
+    '-f',
+    'path=' .. comment.path,
+    '-f',
+    'side=RIGHT',
+    '-f',
+    'line=' .. comment.line,
+  }))
+end
+
+function M.pr_view()
+  local p = vim
+    .system({
+      'gh',
+      'pr',
+      'view',
+      '--json',
+      'number,headRepository,headRefOid',
+      '--jq',
+      '{head:.headRefOid,repo:.headRepository.nameWithOwner,pull:.number}',
+    })
+    :wait()
+  return vim.json.decode(p.stdout)
+end
+
+function M.submit_review()
+  local gitroot = vim.fs.root(0, { '.git' })
+  if not gitroot then
+    vim.notify('Not a git repository.', vim.log.levels.WARN)
+    return
+  end
+
+  local review = { comments = {} }
+
+  local marks = require('haunt.api').get_bookmarks()
+  for _, mark in ipairs(marks) do
+    -- nil for bookmarks outside the current repo
+    local path = vim.fs.relpath(gitroot, mark.file)
+    if path then
+      review.comments[#review.comments] = {
+        path = path,
+        line = mark.line,
+        body = mark.note,
+      }
+    end
+  end
+
+  review.pr = M.pr_view()
+
+  vim.print(vim.inspect(review))
+
+  vim.ui.select({
+    'OK',
+    'Cancel',
+  }, {
+    prompt = 'Submit review?',
+  }, function(choice)
+    vim.print(choice)
+    if choice == 'OK' then
+      for _, comment in ipairs(review.comments) do
+        M.pr_comment(pr.repo, pr.pull, pr.head, comment)
+      end
+    end
+  end)
+end
+
+return M
diff --git a/.config/nvim/lua/mod/git.lua b/.config/nvim/lua/mod/git.lua
new file mode 100644
index 0000000..3e36e61
--- /dev/null
+++ b/.config/nvim/lua/mod/git.lua
@@ -0,0 +1,23 @@
+local M = {}
+
+function M.commit()
+  local commit = vim.fn.expand('<cword>') -- XXX: can we do better?
+  vim.cmd.DiffviewOpen(commit .. '^!')
+end
+
+function M.log()
+  local bufnr = vim.api.nvim_create_buf(true, true)
+  assert(bufnr ~= 0, 'Failed to create buffer')
+
+  vim.bo[bufnr].bufhidden = 'wipe'
+  vim.bo[bufnr].modifiable = true
+  vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, content)
+  vim.bo[bufnr].modifiable = false
+
+  vim.keymap.set('n', 'q', '<cmd>quit!<cr>', { silent = true, buffer = bufnr })
+  vim.keymap.set('n', 'K', M.commit, { silent = true, buffer = bufnr })
+
+  vim.api.nvim_win_set_buf(0, bufnr)
+end
+
+return M
diff --git a/.config/nvim/lua/mod/jobs.lua b/.config/nvim/lua/mod/jobs.lua
new file mode 100644
index 0000000..a4dea6f
--- /dev/null
+++ b/.config/nvim/lua/mod/jobs.lua
@@ -0,0 +1,68 @@
+-- this plugin provides an API to register and recall jobs.
+
+local M = {
+  _jobs = {},
+}
+
+local function format_jobcmd(cmd)
+  if type(cmd) == 'table' then
+    return table.concat(cmd, ' ')
+  end
+  return cmd
+end
+
+local function register(id, cmd)
+  table.insert(M._jobs, id, cmd)
+  vim.notify_once(string.format('started job %d (%s)', id, format_jobcmd(M._jobs[id])))
+end
+
+local function deregister(id)
+  local cmd = M._jobs[id]
+  table.insert(M._jobs, id, nil)
+  vim.notify_once(string.format('stopped job %d (%s)', id, format_jobcmd(cmd)))
+end
+
+function M.start(opts)
+  local previous_on_exit = opts.on_exit or function() end
+  opts.on_exit = function(id, exitcode, event)
+    deregister(id)
+    return previous_on_exit(id, exitcode, event)
+  end
+
+  local id = vim.fn.jobstart(opts.cmd, opts)
+
+  register(id, opts.cmd)
+end
+
+function M.select()
+  if #M._jobs == 0 then
+    vim.notify('No running jobs', vim.log.levels.WARN)
+    return
+  end
+
+  local function provider(cb)
+    for id, cmd in pairs(M._jobs) do
+      cb(string.format('[%d] %s', id, format_jobcmd(cmd)))
+    end
+    cb(nil)
+  end
+  local function parse_jobid(entry)
+    return tonumber(string.match(entry, '%[([0-9]*)%]'))
+  end
+
+  require('fzf-lua').fzf_exec(provider, {
+    prompt = 'Jobs❯',
+    actions = {
+      ['ctrl-x'] = {
+        fn = function(selected)
+          for _, entry in pairs(selected) do
+            vim.fn.jobstop(parse_jobid(entry))
+          end
+        end,
+        reload = true,
+      },
+    },
+  })
+end
+
+return M
diff --git a/.config/nvim/lua/mod/termopen.lua b/.config/nvim/lua/mod/termopen.lua
new file mode 100644
index 0000000..f8117f1
--- /dev/null
+++ b/.config/nvim/lua/mod/termopen.lua
@@ -0,0 +1,102 @@
+-- this plugin provides a popup terminal.
+local jobs = require('mod.jobs')
+
+local M = {}
+
+function M.termopen(opts)
+  opts = opts or {}
+
+  -- setup the buffer
+  local buf = vim.api.nvim_create_buf(false, true)
+  vim.api.nvim_set_option_value('bufhidden', 'wipe', { buf = buf })
+  vim.api.nvim_set_option_value('modifiable', false, { buf = buf })
+
+  -- setup keymappings
+  vim.keymap.set('n', 'q', '<cmd>close<cr>', { buffer = buf })
+  vim.keymap.set('n', '<esc>', '<cmd>close<cr>', { buffer = buf })
+
+  -- setup the window
+  -- local w = math.ceil(vim.o.columns * 1.0)
+  -- local h = math.ceil(vim.o.lines * 0.4)
+  local win = vim.api.nvim_open_win(buf, true, {
+    -- style = 'minimal',
+    -- relative = 'editor',
+    -- width = w,
+    -- height = h,
+    -- row = math.ceil(vim.o.lines - h),
+    -- col = vim.o.columns,
+    -- border = { ' ', '─', ' ', ' ', ' ', '─', ' ', ' ' },
+    split = 'below',
+    win = -1,
+  })
+  vim.api.nvim_set_current_win(win)
+
+  -- spawn the command
+  if #opts.cmd == 0 then
+    opts.cmd = { vim.env.SHELL }
+  end
+
+  -- vim.notify('termopen: running ' .. vim.inspect(opts.cmd), vim.log.levels.DEBUG)
+
+  jobs.start(vim.tbl_deep_extend('error', opts, {
+    term = true,
+    env = {
+      -- we need this to avoid opening in the term buffer
+      NVR_PRE_CMD = 'close',
+    },
+    on_exit = function()
+      -- if vim.api.nvim_win_is_valid(win) then
+      --   vim.api.nvim_win_close(win, true)
+      -- end
+    end,
+  }))
+
+  -- put into insert mode
+  vim.cmd.startinsert()
+end
+
+-- wrappers convenience
+
+function M.term(a)
+  local cwd = nil
+  local args = a.fargs
+
+  if #args > 0 then
+    if args[1]:sub(0, 4) == 'cwd=' then
+      cwd = args[1]:sub(5)
+      args = vim.list_slice(args, 2)
+    end
+  end
+
+  for i = 0, #args do
+    if args[i] == '%' then
+      args[i] = vim.fn.expand(args[i])
+    end
+  end
+
+  M.termopen({ cmd = args, cwd = cwd })
+end
+
+function M.make(a)
+  if vim.opt_local.makeprg == nil then
+    vim.ui.input({ prompt = 'Enter makeprg: ' }, function(input)
+      vim.opt_local.makeprg = input
+    end)
+  end
+
+  local makeprg = vim.opt_local.makeprg:get()
+  if string.match(makeprg, [[%$%*]]) == nil then
+    makeprg = makeprg .. ' ' .. a.args
+  end
+
+  local cmd = vim.split(makeprg, ' ')
+  cmd = vim.tbl_map(function(p)
+    p, _ = string.gsub(p, [[%$%*]], a.args)
+    p, _ = vim.fn.expand(p)
+    return p
+  end, cmd)
+
+  M.termopen({ cmd = cmd })
+end
+
+return M
diff --git a/.config/nvim/lua/mod/utils.lua b/.config/nvim/lua/mod/utils.lua
new file mode 100644
index 0000000..1f3cd8b
--- /dev/null
+++ b/.config/nvim/lua/mod/utils.lua
@@ -0,0 +1,15 @@
+local M = {}
+
+function M.buf_edit_lines(buf, start_row, end_row, callback)
+  local lines = {}
+  lines = vim.api.nvim_buf_get_lines(buf, start_row, end_row, true)
+  lines = callback(lines)
+  return vim.api.nvim_buf_set_lines(buf, start_row, end_row, true, lines)
+end
+
+function M.edit_current_line(callback)
+  local row, _ = unpack(vim.api.nvim_win_get_cursor(0))
+  return M.buf_edit_lines(0, row - 1, row, callback)
+end
+
+return M
diff --git a/.config/nvim/lua/mod/win.lua b/.config/nvim/lua/mod/win.lua
new file mode 100644
index 0000000..e5c5f71
--- /dev/null
+++ b/.config/nvim/lua/mod/win.lua
@@ -0,0 +1,110 @@
+local M = {}
+
+function M.open(name, content, opts)
+  if name == '' then
+    return
+  end
+  if #content == 0 then
+    return
+  end
+
+  local opts = opts or {}
+  local autoclose = opts.autoclose or false
+  local buf_opts = opts.buf or { buftype = '' }
+
+  local win_opts = opts.win or false
+  -- profiles
+  if type(win_opts) == 'table' and type(win_opts[1] == 'string') then
+    local profile = win_opts[1]
+    local overwrites = unpack(win_opts, 2)
+    if profile == 'emplace' then
+      win_opts = false
+    elseif profile == 'smallsplit' then
+      win_opts = {
+        split = 'above',
+        win = 0,
+        height = 20,
+      }
+    elseif profile == 'popup' then
+      local winh = vim.api.nvim_win_get_height(0)
+      local winw = vim.api.nvim_win_get_width(0)
+      local winsize = 0.5
+      win_opts = {
+        relative = 'win',
+        height = math.floor(winh * winsize),
+        width = math.floor(winw * winsize),
+        row = math.floor((winh * 0.5) - (0.5 * (winh * winsize))),
+        col = math.floor((winw * 0.5) - (0.5 * (winw * winsize))),
+        style = 'minimal',
+        border = 'single',
+        zindex = 99,
+        title = name,
+      }
+    end
+    if overwrites then
+      for k, v in pairs(overwrites) do
+        win_opts[k] = v
+      end
+    end
+  end
+
+  local bufnr = vim.api.nvim_create_buf(false, true)
+  assert(bufnr ~= 0, 'Failed to create buffer')
+
+  vim.bo[bufnr].modifiable = true
+  vim.api.nvim_buf_set_name(bufnr, name)
+  vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, content)
+  for k, v in pairs(buf_opts) do
+    vim.bo[bufnr][k] = v
+  end
+
+  -- without win_opts (by default) replace current buffer
+  local winid = 0
+  if win_opts then
+    winid = vim.api.nvim_open_win(0, not autoclose, win_opts)
+    assert(winid ~= 0, 'Failed to create window')
+  end
+
+  vim.keymap.set('n', 'q', '<cmd>quit!<cr>', { silent = true, buffer = bufnr })
+
+  if autoclose then
+    local group = 'modwin_' .. vim.base64.encode(vim.uv.random(16))
+    local group_id = vim.api.nvim_create_augroup(group, {})
+
+    vim.api.nvim_create_autocmd('WinClosed', {
+      pattern = tostring(winid),
+      group = group_id,
+      callback = function()
+        vim.api.nvim_create_augroup(group, {})
+        M.winid = nil
+      end,
+    })
+    vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, {
+      group = group_id,
+      callback = function()
+        vim.api.nvim_create_augroup(group, {})
+        pcall(vim.api.nvim_win_close, winid, true)
+      end,
+    })
+  end
+
+  vim.api.nvim_win_set_buf(winid, bufnr)
+  return { bufnr, winid }
+end
+
+function M.popup(name, content, opts)
+  local defaults = {
+    autoclose = true,
+    buf = {
+      bufhidden = 'wipe',
+      buftype = 'nofile',
+      modifiable = false,
+    },
+    win = { 'popup' },
+  }
+  opts = opts or {}
+  opts = vim.tbl_deep_extend('force', defaults, opts)
+  M.open(name, content, opts)
+end
+
+return M
diff --git a/.config/nvim/lua/plugins/blink.lua b/.config/nvim/lua/plugins/blink.lua
index 1122bcc..cefef4a 100644
--- a/.config/nvim/lua/plugins/blink.lua
+++ b/.config/nvim/lua/plugins/blink.lua
@@ -1,6 +1,7 @@
 return {
   {
-    'saghen/blink.cmp',
+    enabled = true,
+    'https://github.com/saghen/blink.cmp.git',
     version = '1.*',
 
     lazy = false,
@@ -25,7 +26,7 @@ return {
       -- TODO:
       -- 'prefer_rust_with_warning', requires nightly rust, due to:
       -- https://github.com/rust-lang/rust/issues/86656
-      fuzzy = { 
+      fuzzy = {
         implementation = 'lua',
         sorts = {
           function(a, b)
@@ -35,11 +36,13 @@ return {
             }
             local a_priority = prio[a.source_id] or 0
             local b_priority = prio[b.source_id] or 0
-            if a_priority ~= b_priority then return a_priority > b_priority end
+            if a_priority ~= b_priority then
+              return a_priority > b_priority
+            end
           end,
           -- defaults
           'score',
-          'sort_text'
+          'sort_text',
         },
       },
 
@@ -74,6 +77,8 @@ return {
         window = { scrollbar = false }, -- BUG: weird artifacts
       },
 
+      snippets = { preset = 'luasnip' },
+
       keymap = {
         ['<C-space>'] = { 'show', 'show_documentation', 'hide_documentation' },
         ['<C-e>'] = { 'cancel', 'fallback' },
@@ -87,8 +92,14 @@ return {
         ['<C-k>'] = { 'snippet_backward', 'fallback' },
         -- ['<C-l>'] = { 'show', 'hide', 'fallback' },
       },
-
-      snippets = { preset = 'luasnip' },
+    },
+  },
+  {
+    'https://github.com/saghen/blink.indent.git',
+    opts = {
+      scope = {
+        highlights = { 'BlinkIndentScope' },
+      },
     },
   },
 }
diff --git a/.config/nvim/lua/plugins/calcium.lua b/.config/nvim/lua/plugins/calcium.lua
index f0ab78c..7ff1ba0 100644
--- a/.config/nvim/lua/plugins/calcium.lua
+++ b/.config/nvim/lua/plugins/calcium.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'necrom4/calcium.nvim',
     cmd = {'Calcium'},
     opts = {
diff --git a/.config/nvim/lua/plugins/colorizer.lua b/.config/nvim/lua/plugins/colorizer.lua
index c949058..0b69d5a 100644
--- a/.config/nvim/lua/plugins/colorizer.lua
+++ b/.config/nvim/lua/plugins/colorizer.lua
@@ -1,8 +1,9 @@
 return {
   {
-    'NvChad/nvim-colorizer.lua',
+    enabled = true,
+    'https://github.com/NvChad/nvim-colorizer.lua.git',
     -- 'norcalli/nvim-colorizer.lua',
-    lazy = false,
+    lazy = true,
     opts = {
       options = {
         display = {
diff --git a/.config/nvim/lua/plugins/colors.lua b/.config/nvim/lua/plugins/colors.lua
new file mode 100644
index 0000000..764abfd
--- /dev/null
+++ b/.config/nvim/lua/plugins/colors.lua
@@ -0,0 +1,12 @@
+return {
+  {
+    enabled = true,
+    'https://github.com/oskarnurm/koda.nvim',
+    lazy = false,
+    priority = 1000,
+    config = function()
+      vim.opt.termguicolors = true
+      vim.cmd('colorscheme koda')
+    end,
+  }
+}
diff --git a/.config/nvim/lua/plugins/diff.lua b/.config/nvim/lua/plugins/diff.lua
new file mode 100644
index 0000000..d758522
--- /dev/null
+++ b/.config/nvim/lua/plugins/diff.lua
@@ -0,0 +1,47 @@
+return {
+  {
+    enabled = true,
+    'https://github.com/sindrets/diffview.nvim',
+    cmd = {
+      'DiffviewOpen',
+      'DiffviewFileHistory',
+    },
+    init = function()
+      vim.keymap.set(
+        'n',
+        '<leader>g-',
+        vim.cmd.DiffviewFileHistory,
+        { desc = 'DiffviewFileHistory' }
+      )
+
+      vim.api.nvim_create_autocmd('Filetype', {
+        pattern = { 'git', 'gitcommit', 'gitrebase' },
+        callback = function()
+          vim.keymap.set('n', 'K', function()
+            vim.cmd.DiffviewOpen(vim.fn.expand('<cword>') .. '^!')
+          end, { buffer = 0, desc = 'DiffviewOpen' })
+        end,
+      })
+    end,
+    config = function()
+      vim.api.nvim_create_autocmd('User', {
+        pattern = { 'DiffviewViewEnter' },
+        callback = function()
+          vim.keymap.set('n', 'q', '<cmd>DiffviewClose<cr>', { buffer = 0 })
+          vim.keymap.set(
+            'n',
+            '<a-j>',
+            require('diffview.actions').select_next_entry,
+            { buffer = 0 }
+          )
+          vim.keymap.set(
+            'n',
+            '<a-k>',
+            require('diffview.actions').select_prev_entry,
+            { buffer = 0 }
+          )
+        end,
+      })
+    end,
+  },
+}
diff --git a/.config/nvim/lua/plugins/fzf.lua b/.config/nvim/lua/plugins/fzf.lua
index 73246a8..1a25c0d 100644
--- a/.config/nvim/lua/plugins/fzf.lua
+++ b/.config/nvim/lua/plugins/fzf.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'ibhagwan/fzf-lua',
     dependencies = {
       'echasnovski/mini.icons',
@@ -13,10 +14,12 @@ return {
         { 'default' },
         -- OPTIONS
         winopts = {
+          backdrop = 0,
           split = 'belowright 20new',
           border = 'none',
           preview = {
             border = 'none',
+            hidden = true,
           },
           -- on_create = function() end,
         },
@@ -27,11 +30,12 @@ return {
             ['ctrl-p'] = 'up',
           },
         },
-        -- actions = {
-        --   files = {
-        --     ['ctrl-q'] = { fn = fzf.actions.file_sel_to_qf },
-        --   },
-        -- },
+        actions = {
+          files = {
+            true,
+            ['ctrl-q'] = { fn = fzf.actions.file_sel_to_qf, prefix = 'select-all' },
+          },
+        },
         fzf_colors = true,
         -- PICKER CONFIG
         files = {
@@ -39,7 +43,7 @@ return {
         },
         marks = {
           marks = '[a-zA-Z]',
-        }
+        },
       })
     end,
     keys = {
@@ -48,11 +52,26 @@ return {
       { mode = 'n', ';b', '<cmd>FzfLua buffers<cr>', desc = 'fzf: buffers' },
       { mode = 'n', ';f', '<cmd>FzfLua files<cr>', desc = 'fzf: find_files' },
       { mode = 'n', ';g', '<cmd>FzfLua live_grep<cr>', desc = 'fzf: live_grep' },
-      { mode = 'n', ';d', '<cmd>FzfLua diagnostics_workspace<cr>', desc = 'fzf: workspace diagnostics' },
-      { mode = 'n', ';D', '<cmd>FzfLua diagnostics_document<cr>', desc = 'fzf: document diagnostics' },
+      {
+        mode = 'n',
+        ';D',
+        '<cmd>FzfLua diagnostics_workspace sort=true<cr>',
+        desc = 'fzf: workspace diagnostics',
+      },
+      {
+        mode = 'n',
+        ';d',
+        '<cmd>FzfLua diagnostics_document sort=true<cr>',
+        desc = 'fzf: document diagnostics',
+      },
       { mode = 'n', ';h', '<cmd>FzfLua helptags<cr>', desc = 'fzf: help' },
       { mode = 'n', ';s', '<cmd>FzfLua lsp_document_symbols<cr>', desc = 'fzf: document symbols' },
-      { mode = 'n', ';w', '<cmd>FzfLua lsp_live_workspace_symbols<cr>', desc = 'fzf: workspace symbols' },
+      {
+        mode = 'n',
+        ';w',
+        '<cmd>FzfLua lsp_live_workspace_symbols<cr>',
+        desc = 'fzf: workspace symbols',
+      },
       { mode = 'n', ';m', '<cmd>FzfLua marks<cr>', desc = 'fzf: marks' },
       {
         mode = 'n',
@@ -62,12 +81,60 @@ return {
         end,
         desc = 'fzf: vim_config',
       },
-      -- {
-      --   mode = 'n',
-      --   ';;t',
-      --   '<cmd>Telescope<cr>',
-      --   desc = 'telescope: select (interactive)',
-      -- },
+      {
+        mode = 'n',
+        ';z',
+        function()
+          -- register one-time autocmd to open changed directory with oil
+          vim.api.nvim_create_autocmd('DirChanged', {
+            pattern = '*',
+            callback = vim.schedule_wrap(function(args)
+              vim.cmd.Oil(args.file)
+            end),
+            once = true,
+          })
+          require('fzf-lua').zoxide()
+        end,
+        desc = 'fzf: zoxide',
+      },
+      {
+        mode = 'n',
+        ';Z',
+        function()
+          require('fzf-lua').live_grep({
+            cwd = vim.env.ZK_NOTEBOOK_DIR,
+            actions = {
+              ['ctrl-c'] = function(selected, opts)
+                local utils = require('fzf-lua.utils')
+
+                local title = opts.last_query
+                local p = vim
+                  .system({ 'zk', 'new', '--dry-run', '--no-input', '--title', title }, { text = true })
+                  :wait()
+                if not p.code == 0 then
+                  return
+                end
+                utils.info(vim.inspect(p.stdout))
+
+                local note_path = vim.trim(p.stderr)
+                local note_body = vim.split(p.stdout, '\n')
+                require('mod.win').open(note_path, note_body, {
+                  buf = { filetype = 'markdown' },
+                })
+              end,
+            },
+          })
+        end,
+        desc = 'fzf: zettelkasten',
+      },
+      {
+        mode = 'n',
+        ';T',
+        function()
+          require('fzf-lua').live_grep({ regex = '(TODO|XXX|NOTE|HACK):' })
+        end,
+        desc = 'fzf: zettelkasten',
+      },
       {
         mode = 'n',
         ';;f',
@@ -78,7 +145,6 @@ return {
           else
             dir = vim.fn.expand('%:p:h')
           end
-          -- require('fzf-lua').files({ cwd = dir })
           _G.feedkeys(':Fzf files cwd=' .. dir)
         end,
         desc = 'fzf: files (interactive)',
diff --git a/.config/nvim/lua/plugins/gentoo.lua b/.config/nvim/lua/plugins/gentoo.lua
index 15ef3aa..9af7571 100644
--- a/.config/nvim/lua/plugins/gentoo.lua
+++ b/.config/nvim/lua/plugins/gentoo.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'https://github.com/gentoo/gentoo-syntax',
     lazy = false,
     init = function()
diff --git a/.config/nvim/lua/plugins/git.lua b/.config/nvim/lua/plugins/git.lua
index d1e3f7b..7f1db6d 100644
--- a/.config/nvim/lua/plugins/git.lua
+++ b/.config/nvim/lua/plugins/git.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'lewis6991/gitsigns.nvim',
     lazy = false,
     opts = {
@@ -46,6 +47,7 @@ return {
   },
 
   {
+    enabled = true,
     'linrongbin16/gitlinker.nvim',
     cmd = { 'GitLink' },
     dependencies = { 'nvim-lua/plenary.nvim' },
@@ -54,6 +56,7 @@ return {
     },
     keys = {
       {
+        mode = { 'n', 'x' },
         '<leader>gl',
         vim.cmd.GitLink,
         desc = 'GitLinker: clipboard',
@@ -62,11 +65,13 @@ return {
   },
 
   {
-    enabled = false,
+    enabled = true,
     'moyiz/git-dev.nvim',
     lazy = true,
     cmd = { 'GitDevOpen', 'GitDevCleanAll' },
     opts = {
+      pickers = { type = 'uiselect' },
+      ephemeral = false,
       read_only = false,
     },
   },
diff --git a/.config/nvim/lua/plugins/haunt.lua b/.config/nvim/lua/plugins/haunt.lua
new file mode 100644
index 0000000..aa24cec
--- /dev/null
+++ b/.config/nvim/lua/plugins/haunt.lua
@@ -0,0 +1,47 @@
+return {
+  {
+    enabled = true,
+    'https://github.com/TheNoeTrevino/haunt.nvim',
+    lazy = true,
+    opts = {
+      sign = '',
+      -- sign_hl = nil,
+      -- line_hl = nil,
+      -- virt_text_hl = nil,
+      data_dir = nil,
+      annotation_prefix = '  ',
+      -- virt_text_pos = 'eol',
+      virt_text_pos = 'above',
+      picker_keys = {
+        delete = { key = 'ctrl-x' },
+        edit_annotation = { key = 'ctrl-e' },
+      },
+    },
+    cmd = {
+      'HauntAnnoate',
+      'HauntDelete',
+      'HauntList',
+      'HauntNext',
+      'HauntPrev',
+      'HauntQfAll',
+    },
+    keys = {
+      { '[h', '<cmd>HauntPrev<cr>', desc = 'haunt: prev annotation', silent = true },
+      { ']h', '<cmd>HauntNext<cr>', desc = 'haunt: next annotation', silent = true },
+      { '<leader>h', '<nop>', desc = 'haunt' },
+      { '<leader>ha', '<cmd>HauntAnnotate<cr>', desc = 'haunt: annotate', silent = true },
+      { '<leader>ha', '<cmd>HauntAnnotate<cr>', desc = 'haunt: annotate', silent = true },
+      { '<leader>hd', '<cmd>HauntDelete<cr>', desc = 'haunt: delete', silent = true },
+      { '<leader>hl', '<cmd>HauntList<cr>', desc = 'haunt: list', silent = true },
+      { '<leader>hf', '<cmd>HauntQfAll<cr>', desc = 'haunt: quickfix', silent = true },
+      {
+        '<leader>ht',
+        function()
+          require('haunt.api').toggle_all_lines()
+        end,
+        desc = 'haunt: toggle all',
+        silent = true,
+      },
+    },
+  },
+}
diff --git a/.config/nvim/lua/plugins/icons.lua b/.config/nvim/lua/plugins/icons.lua
index 9a597ab..339ad12 100644
--- a/.config/nvim/lua/plugins/icons.lua
+++ b/.config/nvim/lua/plugins/icons.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'echasnovski/mini.icons',
     version = false,
     events = { 'VeryLazy' },
diff --git a/.config/nvim/lua/plugins/indent.lua b/.config/nvim/lua/plugins/indent.lua
index e247c5a..d197a43 100644
--- a/.config/nvim/lua/plugins/indent.lua
+++ b/.config/nvim/lua/plugins/indent.lua
@@ -1,6 +1,7 @@
 return {
   -- show indents using virtual text
   {
+    enabled = false,
     'lukas-reineke/indent-blankline.nvim',
     lazy = false,
     main = 'ibl',
diff --git a/.config/nvim/lua/plugins/lsp.lua b/.config/nvim/lua/plugins/lsp.lua
index 311f1bc..306953c 100644
--- a/.config/nvim/lua/plugins/lsp.lua
+++ b/.config/nvim/lua/plugins/lsp.lua
@@ -1,14 +1,22 @@
 return {
   {
+    enabled = true,
     'neovim/nvim-lspconfig',
     version = '^2.0',
   },
   {
+    enabled = true,
     'nvimtools/none-ls.nvim',
     dependencies = {
       'nvim-lua/plenary.nvim',
       'gbprod/none-ls-shellcheck.nvim',
     },
+    ft = {
+      'sh',
+      'bash',
+      'go',
+      'lua',
+    },
     config = function()
       local nls = require('null-ls')
       nls.setup({
@@ -18,10 +26,25 @@ return {
 
           nls.builtins.formatting.stylua,
           nls.builtins.formatting.shfmt,
-          nls.builtins.formatting.buf,
 
-          require("none-ls-shellcheck.diagnostics"),
-          require("none-ls-shellcheck.code_actions"),
+          require('none-ls-shellcheck.diagnostics'),
+          require('none-ls-shellcheck.code_actions'),
+
+          nls.builtins.diagnostics.golangci_lint.with({
+            command = 'task',
+            args = {
+              '--offline',
+              '--silent',
+              '--exit-code',
+              '--failfast',
+              '--output=interleaved',
+              'go:lint',
+              '--',
+              '--show-stats=false',
+              '--output.json.path=stdout',
+              '--path-mode=abs',
+            },
+          }),
         },
       })
     end,
diff --git a/.config/nvim/lua/plugins/markdown.lua b/.config/nvim/lua/plugins/markdown.lua
index efe7019..a02cb67 100644
--- a/.config/nvim/lua/plugins/markdown.lua
+++ b/.config/nvim/lua/plugins/markdown.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     -- handy markdown commands
     'tadmccorkle/markdown.nvim',
     ft = { 'markdown' },
@@ -17,6 +18,7 @@ return {
     },
   },
   {
+    enabled = true,
     -- pretty markdown
     'MeanderingProgrammer/markdown.nvim',
     name = 'render-markdown', -- needed if used together with markdown.nvim above
diff --git a/.config/nvim/lua/plugins/mini.lua b/.config/nvim/lua/plugins/mini.lua
index fb4c9a6..fdf4a0e 100644
--- a/.config/nvim/lua/plugins/mini.lua
+++ b/.config/nvim/lua/plugins/mini.lua
@@ -1,23 +1,27 @@
 return {
   {
+    enabled = true,
     'echasnovski/mini.align',
     version = false,
     lazy = false,
     opts = {},
   },
   {
+    enabled = true,
     'echasnovski/mini.ai',
     version = false,
     lazy = false,
     opts = {},
   },
   {
+    enabled = true,
     'echasnovski/mini.surround',
     version = false,
     lazy = false,
     opts = {},
   },
   {
+    enabled = true,
     'echasnovski/mini.operators',
     version = false,
     lazy = false,
diff --git a/.config/nvim/lua/plugins/minimap.lua b/.config/nvim/lua/plugins/minimap.lua
new file mode 100644
index 0000000..99e9ec7
--- /dev/null
+++ b/.config/nvim/lua/plugins/minimap.lua
@@ -0,0 +1,13 @@
+return {
+  {
+    enabled = false,
+    'alchezar/fishbone.nvim',
+    event = 'VeryLazy',
+    opts = {},
+  },
+  {
+    enabled = false,
+    'https://github.com/lewis6991/satellite.nvim',
+    opts = {},
+  }
+}
diff --git a/.config/nvim/lua/plugins/oil.lua b/.config/nvim/lua/plugins/oil.lua
index 401fe8b..d21b041 100644
--- a/.config/nvim/lua/plugins/oil.lua
+++ b/.config/nvim/lua/plugins/oil.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'stevearc/oil.nvim',
     lazy = false,
     opts = {
diff --git a/.config/nvim/lua/plugins/snippets.lua b/.config/nvim/lua/plugins/snippets.lua
index 71276a0..2a38a1d 100644
--- a/.config/nvim/lua/plugins/snippets.lua
+++ b/.config/nvim/lua/plugins/snippets.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'L3MON4D3/LuaSnip',
     version = 'v2.*',
     build = 'make install_jsregexp',
diff --git a/.config/nvim/lua/plugins/treesitter.lua b/.config/nvim/lua/plugins/treesitter.lua
index 0978eb7..ccacc7a 100644
--- a/.config/nvim/lua/plugins/treesitter.lua
+++ b/.config/nvim/lua/plugins/treesitter.lua
@@ -1,5 +1,6 @@
 return {
   {
+    enabled = true,
     'nvim-treesitter/nvim-treesitter',
     branch = 'main',
     lazy = false,
@@ -36,6 +37,7 @@ return {
         'gotmpl',
         'gowork',
         'html',
+        'janet_simple',
         'javascript',
         'json',
         'lua',
@@ -43,15 +45,18 @@ return {
         'markdown',
         'markdown_inline',
         'ninja',
+        'proto',
         'python',
         'regex',
         'rust',
         'scss',
         'sql',
+        'templ', -- golang html templates
         'todotxt',
         'toml',
         'typescript',
         'typst',
+        'vala',
         'vim',
         'vimdoc',
         'yaml',
diff --git a/.config/nvim/lua/plugins/whichkey.lua b/.config/nvim/lua/plugins/whichkey.lua
index cb89df4..442b43f 100644
--- a/.config/nvim/lua/plugins/whichkey.lua
+++ b/.config/nvim/lua/plugins/whichkey.lua
@@ -1,9 +1,19 @@
 return {
   {
+    enabled = true,
     'folke/which-key.nvim',
     event = 'VeryLazy',
     opts = {
       icons = { separator = '→ ', group = ' +' },
     },
+    keys = {
+      {
+        '<leader>?',
+        function()
+          require('which-key').show({ global = true })
+        end,
+        desc = 'which-key: show buffer local keymaps',
+      },
+    },
   },
 }
diff --git a/.config/nvim/plugin/mod.lua b/.config/nvim/plugin/mod.lua
new file mode 100644
index 0000000..a26bf46
--- /dev/null
+++ b/.config/nvim/plugin/mod.lua
@@ -0,0 +1,25 @@
+-- register keybinds and commands for lua/mod/?.lua here
+
+-- jobs.lua
+vim.api.nvim_create_user_command('Jobs', function(a) require('mod.jobs').select(a) end,
+  { nargs = 0, desc = 'jobs: List running jobs' })
+
+vim.keymap.set('n', ';j', '<cmd>Jobs<cr>', { desc = 'fzf: jobs' })
+
+-- termopen.lua
+vim.api.nvim_create_user_command('Term', function(a) require('mod.termopen').term(a) end,
+  { nargs = '*', desc = 'termopen: Terminal' })
+vim.api.nvim_create_user_command('Make', function(a) require('mod.termopen').make(a) end,
+  { nargs = '*', desc = 'termopen: Make' })
+
+vim.keymap.set('n', '<leader><leader>m', '<cmd>Make<cr>', { desc = 'termopen: make' })
+vim.keymap.set('n', '<leader><leader>t', '<cmd>Termopen<cr>', { desc = 'termopen: shell' })
+vim.keymap.set('n', '<leader><leader>l', function()
+  vim.ui.input({ prompt = 'Launch: ' }, function(input)
+    if input ~= nil and #input > 0 then
+      require('mod.termopen').termopen({ cmd = { vim.env.SHELL, '-c', input } })
+    else
+      vim.notify('termopen: empty arguments', vim.log.levels.WARN)
+    end
+  end)
+end, { desc = 'termopen: Launch' })
diff --git a/.config/pimsync/pimsync.conf b/.config/pimsync/pimsync.conf
index 8fed018..b85c959 100644
--- a/.config/pimsync/pimsync.conf
+++ b/.config/pimsync/pimsync.conf
@@ -4,22 +4,26 @@ status_path "~/.local/state/pimsync/status/"
 # PAIRS
 
 pair calendars_robert {
-	storage_a calendars_robert_local
-	storage_b gzr_robert_calendar_remote
+	storage_a gzr_robert_calendar_remote
+	storage_b calendars_robert_local
 	collections all
+	conflict_resolution cmd nvim -d
 }
 
 pair contacts_robert {
-	storage_a contacts_local
-	storage_b gzr_robert_contacts_remote
+	storage_a gzr_robert_contacts_remote
+	storage_b contacts_local
 	collections all
+	conflict_resolution cmd nvim -d
 }
 
 pair calendars_goro {
-	storage_a calendars_goro_local
-	storage_b gzr_goro_calendar_remote
+	storage_a gzr_goro_calendar_remote
+	storage_b calendars_goro_local
 	# NOTE: only sync events
-	collection events
+	# collection events
+	collections all
+	conflict_resolution cmd nvim -d
 }
 
 # STORAGE LOCAL
diff --git a/.config/rc/conf.d/podman b/.config/rc/conf.d/podman
new file mode 100644
index 0000000..e78ef15
--- /dev/null
+++ b/.config/rc/conf.d/podman
@@ -0,0 +1 @@
+export DOCKER_BUILDKIT=1
diff --git a/.config/rc/init.d/secretsd b/.config/rc/init.d/secretsd
new file mode 100755
index 0000000..8c639a9
--- /dev/null
+++ b/.config/rc/init.d/secretsd
@@ -0,0 +1,18 @@
+#!/sbin/openrc-run
+DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
+SECRETSD_HOME=${XDG_DATA_HOME}/secretsd
+
+description="Lightweight Wayland notification daemon"
+
+command="/usr/bin/secretsd"
+command_args="--no-syslog --db-path=${SECRETSD_HOME}/db --key-location=file:${SECRETSD_HOME}/key"
+supervisor=supervise-daemon
+error_logger="logger -t '${RC_SVCNAME}' -p daemon.error"
+
+depend() {
+	need dbus
+}
+
+start_pre() {
+	checkpath -q -d ${SECRETSD_HOME}
+}
diff --git a/.config/rc/init.d/syncthing b/.config/rc/init.d/syncthing
index 083b092..8a790f8 100755
--- a/.config/rc/init.d/syncthing
+++ b/.config/rc/init.d/syncthing
@@ -12,3 +12,10 @@ browser() {
 	syncthing browser
 	eend $? "Opened syncthing gui in the browser"
 }
+
+start_post() {
+	pkill -RTMIN+3 waybar
+}
+stop_post() {
+	pkill -RTMIN+3 waybar
+}
diff --git a/.config/rc/init.d/xdg-desktop-portal b/.config/rc/init.d/xdg-desktop-portal
index aeacb00..1852935 100755
--- a/.config/rc/init.d/xdg-desktop-portal
+++ b/.config/rc/init.d/xdg-desktop-portal
@@ -1,10 +1,6 @@
 #!/sbin/openrc-run
-DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
-
-supervisor=supervise-daemon
-command="/usr/libexec/xdg-desktop-portal"
-command_args="--replace $command_args"
-error_logger="logger -t '${RC_SVCNAME}' -p daemon.error"
+# Copyright 1999-2025 Gentoo Authors
+# Distributed under the terms of the GNU General Public License, v2 or later
 
 depend() {
 	need dbus \
@@ -12,3 +8,8 @@ depend() {
 		xdg-desktop-portal-wlr \
 		xdg-desktop-portal-darkman
 }
+
+DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
+supervisor=supervise-daemon
+command="/usr/libexec/xdg-desktop-portal"
+error_logger="logger -t '${RC_SVCNAME}' -p daemon.error"
diff --git a/.config/rc/runlevels/desktop/fcitx5 b/.config/rc/runlevels/desktop/fcitx5
deleted file mode 120000
index a7b382d..0000000
--- a/.config/rc/runlevels/desktop/fcitx5
+++ /dev/null
@@ -1 +0,0 @@
-/home/robert/.config/rc/init.d/fcitx5
\ No newline at end of file
diff --git a/.config/rc/runlevels/desktop/secretsd b/.config/rc/runlevels/desktop/secretsd
new file mode 120000
index 0000000..bafe0c8
--- /dev/null
+++ b/.config/rc/runlevels/desktop/secretsd
@@ -0,0 +1 @@
+/home/robert/.config/rc/init.d/secretsd
\ No newline at end of file
diff --git a/.config/river/init b/.config/river/init
index ae976d7..f94bf12 100755..120000
--- a/.config/river/init
+++ b/.config/river/init
@@ -1,143 +1 @@
-#!/bin/sh
-
-# start desktop runlevel
-riverctl spawn 'openrc -U desktop'
-
-# ::start style
-riverctl background-color 0x080808ff
-riverctl border-color-focused 0x70649aff
-riverctl border-color-unfocused 0x080808af
-riverctl border-color-urgent 0xcb1b45ff
-riverctl border-width 3
-# ::end style
-
-# rules
-riverctl rule-add -app-id '*' ssd
-riverctl rule-add -app-id 'librewolf' -title 'Picture-in-Picture' float
-riverctl rule-add -app-id 'workfox' ssd
-riverctl rule-add -app-id 'foot-float' float
-riverctl rule-add -app-id 'mpv' float
-riverctl rule-add -app-id 'nm-connection-editor' float
-
-# keymaps: wm
-riverctl map normal Super+Shift E spawn 'openrc -U default && riverctl exit'
-riverctl map normal Super+Shift Q close
-riverctl map normal Super+Shift Return zoom
-riverctl map normal Super F toggle-fullscreen
-riverctl map normal Super+Shift Space toggle-float
-
-riverctl map normal Super J focus-view next
-riverctl map normal Super K focus-view previous
-riverctl map normal Super L focus-view right
-riverctl map normal Super H focus-view left
-riverctl map normal Super+Shift J swap next
-riverctl map normal Super+Shift K swap previous
-riverctl map normal Super+Shift L swap right
-riverctl map normal Super+Shift H swap left
-riverctl map normal Super Backspace focus-previous-tags
-riverctl map normal Super+Shift Backspace move-previous-tags
-riverctl map normal Super Period focus-output next
-riverctl map normal Super Comma focus-output previous
-riverctl map normal Super+Shift Period send-to-output next
-riverctl map normal Super+Shift Comma send-to-output previous
-all_tags=$(((1 << 32) - 1))
-riverctl map normal Super 0 set-focused-tags $all_tags
-riverctl map normal Super+Shift 0 set-view-tags $all_tags
-for i in $(seq 1 9); do
-	tags=$((1 << (i - 1)))
-	# tag management
-	riverctl map normal Super "$i" set-focused-tags "$tags"
-	riverctl map normal Super+Shift "$i" set-view-tags "$tags"
-	riverctl map normal Super+Control "$i" toggle-focused-tags "$tags"
-	riverctl map normal Super+Shift+Control "$i" toggle-view-tags "$tags"
-done
-riverctl map-pointer normal Super BTN_LEFT move-view
-riverctl map-pointer normal Super BTN_RIGHT resize-view
-
-# keymaps: apps
-riverctl map normal Super Return spawn 'footclient'
-riverctl map normal Super+Control Return spawn 'foot -a foot-float -W 120x40'
-riverctl map normal Super D spawn 'fuzzel'
-riverctl map normal Super Z spawn 'footclient -- sleep .4 && zk e'
-riverctl map normal Super+Shift S spawn '~/bin/grimshot'
-
-# keymaps: cmd mode
-riverctl declare-mode cmd
-riverctl map normal Super Space enter-mode cmd
-riverctl map cmd None Escape enter-mode normal
-riverctl map cmd None Space spawn "riverctl enter-mode normal; menm"
-riverctl map cmd None Backspace spawn "riverctl enter-mode normal; susm"
-riverctl map cmd None A spawn "riverctl enter-mode normal; audm"
-riverctl map cmd None B spawn "riverctl enter-mode normal; blum"
-riverctl map cmd None C spawn "riverctl enter-mode normal; netm"
-riverctl map cmd None D spawn "riverctl enter-mode normal; dskm"
-riverctl map cmd None F spawn "riverctl enter-mode normal; fm"
-riverctl map cmd None K spawn "riverctl enter-mode normal; keym"
-riverctl map cmd None N spawn "riverctl enter-mode normal; ntfm"
-riverctl map cmd None P spawn "riverctl enter-mode normal; pasm"
-riverctl map cmd None R spawn "riverctl enter-mode normal; svcm"
-riverctl map cmd None S spawn "riverctl enter-mode normal; snim"
-riverctl map cmd None T spawn "riverctl enter-mode normal; flatpak run com.odnoyko.valot --compact"
-riverctl map cmd None V spawn "riverctl enter-mode normal; vpnm"
-riverctl map cmd None X spawn "riverctl enter-mode normal; fuzzel --list-executables-in-path"
-riverctl map cmd Shift C spawn "riverctl enter-mode normal; calm"
-
-# keymaps: misc
-# riverctl map-switch normal lid close spawn 'waylock -init-color 0x005469 & playerctl pause'
-riverctl map-switch normal lid close spawn 'fyi todo lock'
-
-riverctl map normal Super B spawn 'pkill -USR1 waybar'
-riverctl map normal Super+Alt K spawn 'mpv ~/pictures/fwkeyboard.jpg'
-
-riverctl map normal Super C spawn 'fyi todo xf86copy'
-riverctl map normal Super X spawn 'fyi todo xf86cut'
-riverctl map normal Super V spawn 'fyi todo xf86paste'
-
-# keymaps: fn/media keys
-riverctl map normal None XF86AudioRaiseVolume spawn 'wpctl set-volume --limit=1.0 @DEFAULT_AUDIO_SINK@ 5%+'
-riverctl map normal None XF86AudioLowerVolume spawn 'wpctl set-volume --limit=1.0 @DEFAULT_AUDIO_SINK@ 5%-'
-riverctl map normal None XF86AudioMute spawn 'wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle'
-riverctl map normal None XF86AudioMicMute spawn 'wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle'
-riverctl map normal None XF86AudioPlay spawn 'playerctl -p playerctld play-pause'
-riverctl map normal None XF86AudioPrev spawn 'playerctl -p playerctld previous'
-riverctl map normal None XF86AudioNext spawn 'playerctl -p playerctld next'
-riverctl map normal None XF86MonBrightnessUp spawn 'brightnessctl set +5%'
-riverctl map normal None XF86MonBrightnessDown spawn 'brightnessctl set 5%-'
-
-# input
-riverctl keyboard-layout -options caps:super,eurosign:5 -variant mac us
-riverctl set-repeat 70 200
-riverctl set-cursor-warp on-output-change
-riverctl focus-follows-cursor normal
-riverctl hide-cursor timeout 0
-riverctl hide-cursor when-typing disabled
-riverctl xcursor-theme Adwaita 16
-
-riverctl input 'pointer-*' natural-scroll enabled
-riverctl input 'pointer-*' pointer-accel 0
-riverctl input 'pointer-*' tap enabled
-riverctl input 'pointer-*' accel-profile adaptive
-riverctl input 'pointer-*' disable-while-typing enabled
-riverctl input '*Kensington_Slimblade_Trackball' natural-scroll disabled
-riverctl input '*Kensington_Slimblade_Trackball' pointer-accel 1
-
-# spawn a terminal
-riverctl spawn foot
-
-# wm
-riverctl default-layout rivercarro
-
-riverctl map normal Super Equal send-layout-cmd rivercarro 'main-ratio +0.02'
-riverctl map normal Super Minus send-layout-cmd rivercarro 'main-ratio -0.02'
-riverctl map normal Super+Alt H send-layout-cmd rivercarro 'main-location left'
-riverctl map normal Super+Alt K send-layout-cmd rivercarro 'main-location top'
-riverctl map normal Super+Alt J send-layout-cmd rivercarro 'main-location bottom'
-riverctl map normal Super+Alt L send-layout-cmd rivercarro 'main-location right'
-riverctl map normal Super+Alt Space send-layout-cmd rivercarro 'main-location monocle'
-
-exec /usr/bin/rivercarro \
-	-inner-gaps 3 \
-	-outer-gaps 3 \
-	-main-location left \
-	-main-ratio 0.6 \
-	-main-count 1
+init3
\ No newline at end of file
diff --git a/.config/river/init3 b/.config/river/init3
new file mode 100755
index 0000000..0c25fc6
--- /dev/null
+++ b/.config/river/init3
@@ -0,0 +1,148 @@
+#!/bin/sh
+
+# start desktop runlevel
+riverctl spawn 'openrc -U desktop'
+
+# ::start style
+riverctl background-color 0x080808ff
+riverctl border-color-focused 0x70649aff
+riverctl border-color-unfocused 0x080808af
+riverctl border-color-urgent 0xcb1b45ff
+riverctl border-width 3
+# ::end style
+
+# rules
+riverctl rule-add -app-id '*' ssd
+riverctl rule-add -app-id 'librewolf' -title 'Picture-in-Picture' float
+riverctl rule-add -app-id 'librewolf' -title 'Extension:*' float
+riverctl rule-add -app-id 'workfox' ssd
+riverctl rule-add -app-id '*+float' float
+riverctl rule-add -app-id 'mpv' float
+riverctl rule-add -app-id 'nm-connection-editor' float
+riverctl rule-add -app-id 'ibus-ui-gtk3' float
+riverctl rule-add -app-id 'thunar' -title 'File Operation Progress' float
+
+# keymaps: wm
+riverctl map normal Super+Shift E spawn 'openrc -U default && riverctl exit'
+riverctl map normal Super+Shift Q close
+riverctl map normal Super+Shift Return zoom
+riverctl map normal Super F toggle-fullscreen
+riverctl map normal Super+Shift Space toggle-float
+
+riverctl map normal Super J focus-view next
+riverctl map normal Super K focus-view previous
+riverctl map normal Super L focus-view right
+riverctl map normal Super H focus-view left
+riverctl map normal Super+Shift J swap next
+riverctl map normal Super+Shift K swap previous
+riverctl map normal Super+Shift L swap right
+riverctl map normal Super+Shift H swap left
+riverctl map normal Super Backspace focus-previous-tags
+riverctl map normal Super+Shift Backspace move-previous-tags
+riverctl map normal Super Period focus-output next
+riverctl map normal Super Comma focus-output previous
+riverctl map normal Super+Shift Period send-to-output next
+riverctl map normal Super+Shift Comma send-to-output previous
+all_tags=$(((1 << 32) - 1))
+riverctl map normal Super 0 set-focused-tags $all_tags
+riverctl map normal Super+Shift 0 set-view-tags $all_tags
+for i in $(seq 1 9); do
+	tags=$((1 << (i - 1)))
+	# tag management
+	riverctl map normal Super "$i" set-focused-tags "$tags"
+	riverctl map normal Super+Shift "$i" set-view-tags "$tags"
+	riverctl map normal Super+Control "$i" toggle-focused-tags "$tags"
+	riverctl map normal Super+Shift+Control "$i" toggle-view-tags "$tags"
+done
+riverctl map-pointer normal Super BTN_LEFT move-view
+riverctl map-pointer normal Super BTN_RIGHT resize-view
+
+# keymaps: apps
+riverctl map normal Super Return spawn 'footclient'
+riverctl map normal Super+Control Return spawn 'foot --app-id foot+float --window-size-chars 120x40'
+# riverctl map normal Super Return spawn 'monstar'
+# riverctl map normal Super+Control Return spawn 'monstar --app-id monstar+float --window-size-chars 120x40'
+riverctl map normal Super D spawn 'fuzzel'
+riverctl map normal Super Z spawn 'footclient -- zk e'
+riverctl map normal Super+Shift S spawn 'grimshot'
+
+# keymaps: cmd mode
+riverctl declare-mode cmd
+riverctl map normal Super Space enter-mode cmd
+riverctl map cmd None Escape enter-mode normal
+riverctl map cmd None Space spawn "riverctl enter-mode normal; menm"
+riverctl map cmd None Backspace spawn "riverctl enter-mode normal; susm"
+riverctl map cmd None A spawn "riverctl enter-mode normal; audm"
+riverctl map cmd None B spawn "riverctl enter-mode normal; blum"
+riverctl map cmd None C spawn "riverctl enter-mode normal; netm"
+riverctl map cmd None D spawn "riverctl enter-mode normal; dskm"
+riverctl map cmd None F spawn "riverctl enter-mode normal; fm"
+riverctl map cmd None K spawn "riverctl enter-mode normal; keym"
+riverctl map cmd None N spawn "riverctl enter-mode normal; ntfm"
+riverctl map cmd None P spawn "riverctl enter-mode normal; pasm"
+riverctl map cmd None R spawn "riverctl enter-mode normal; svcm"
+riverctl map cmd None S spawn "riverctl enter-mode normal; snim"
+riverctl map cmd None T spawn "riverctl enter-mode normal; vpnm"
+riverctl map cmd None X spawn "riverctl enter-mode normal; fuzzel --list-executables-in-path"
+riverctl map cmd Shift C spawn "riverctl enter-mode normal; calm"
+
+# keymaps: misc
+# riverctl map-switch normal lid close spawn 'waylock -init-color 0x005469 & playerctl pause'
+riverctl map-switch normal lid close spawn 'fyi todo lock'
+
+riverctl map normal Super B spawn 'pkill -USR1 waybar'
+riverctl map normal Super+Control K spawn 'mpv ~/pictures/fwkeyboard.jpg'
+riverctl map normal Super O spawn 'ocr'
+
+riverctl map normal Super C spawn 'fyi todo xf86copy'
+riverctl map normal Super X spawn 'fyi todo xf86cut'
+riverctl map normal Super V spawn 'fyi todo xf86paste'
+
+# keymaps: fn/media keys
+riverctl map normal None XF86AudioRaiseVolume spawn 'wpctl set-volume --limit=1.0 @DEFAULT_AUDIO_SINK@ 5%+'
+riverctl map normal None XF86AudioLowerVolume spawn 'wpctl set-volume --limit=1.0 @DEFAULT_AUDIO_SINK@ 5%-'
+riverctl map normal None XF86AudioMute spawn 'wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle'
+riverctl map normal None XF86AudioMicMute spawn 'wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle'
+riverctl map normal None XF86AudioPlay spawn 'playerctl -p playerctld play-pause'
+riverctl map normal None XF86AudioPrev spawn 'playerctl -p playerctld previous'
+riverctl map normal None XF86AudioNext spawn 'playerctl -p playerctld next'
+riverctl map normal None XF86MonBrightnessUp spawn 'brightnessctl set +5%'
+riverctl map normal None XF86MonBrightnessDown spawn 'brightnessctl set 5%-'
+
+# input
+riverctl keyboard-layout -options caps:super,eurosign:5 -variant mac us
+riverctl set-repeat 70 200
+riverctl set-cursor-warp on-output-change
+riverctl focus-follows-cursor normal
+riverctl hide-cursor timeout 5000
+riverctl hide-cursor when-typing enabled
+riverctl xcursor-theme Adwaita 16
+
+riverctl input 'pointer-*' natural-scroll enabled
+riverctl input 'pointer-*' pointer-accel 0
+riverctl input 'pointer-*' tap enabled
+riverctl input 'pointer-*' accel-profile adaptive
+riverctl input 'pointer-*' disable-while-typing enabled
+riverctl input '*Kensington_Slimblade_Trackball' natural-scroll disabled
+riverctl input '*Kensington_Slimblade_Trackball' pointer-accel 1
+
+# spawn a terminal
+riverctl spawn foot
+
+# wm
+riverctl default-layout rivercarro
+
+riverctl map normal Super Equal send-layout-cmd rivercarro 'main-ratio +0.02'
+riverctl map normal Super Minus send-layout-cmd rivercarro 'main-ratio -0.02'
+riverctl map normal Super+Alt H send-layout-cmd rivercarro 'main-location left'
+riverctl map normal Super+Alt K send-layout-cmd rivercarro 'main-location top'
+riverctl map normal Super+Alt J send-layout-cmd rivercarro 'main-location bottom'
+riverctl map normal Super+Alt L send-layout-cmd rivercarro 'main-location right'
+riverctl map normal Super+Alt Space send-layout-cmd rivercarro 'main-location monocle'
+
+exec /usr/bin/rivercarro \
+	-inner-gaps 3 \
+	-outer-gaps 3 \
+	-main-location left \
+	-main-ratio 0.6 \
+	-main-count 1
diff --git a/.config/starship.toml b/.config/starship.toml
index 724526a..710cd66 100644
--- a/.config/starship.toml
+++ b/.config/starship.toml
@@ -2,6 +2,7 @@
 
 format = """
 ⋮ \
+${env_var.ZMX_SESSION}\
 $container\
 $username\
 $hostname\
@@ -27,6 +28,11 @@ $character\
 add_newline = false
 command_timeout = 100
 
+[env_var.ZMX_SESSION]
+symbol = ""
+format = "[\\[$symbol$env_value\\]]($style) "
+style = "bold green"
+
 [container]
 symbol = ' '
 format = '[$symbol\[$name\]]($style) '
@@ -116,3 +122,4 @@ disabled = false
 format = '$symbol '
 success_symbol = '[❯](bold)'
 error_symbol = '[❯](bold red)'
+
diff --git a/.config/tridactyl/themes/r.css b/.config/tridactyl/themes/r.css
index 05b47a6..b2d56a4 100644
--- a/.config/tridactyl/themes/r.css
+++ b/.config/tridactyl/themes/r.css
@@ -21,11 +21,11 @@
     --tridactyl-of-fg: #fce19f;
     --tridactyl-of-bg: var(--tridactyl-bg);
 
-    --tridactyl-hintspan-fg: #f9f9fa;
+    --tridactyl-hintspan-fg: var(--tridactyl-bg);
     --tridactyl-hintspan-bg: rgb(185, 142, 255);
 
     --tridactyl-hint-fg: var(--tridactyl-hintspan-fg);
-    --tridactyl-hint-bg: rgba(185, 142, 255, 0.15);
+    --tridactyl-hint-bg: color-mix(in srgb, var(--tridactyl-hintspan-bg) 33%, transparent);
     --tridactyl-hint-outline: 1px solid var(--tridactyl-hintspan-bg);
 
     --tridactyl-hint-active-fg: var(--tridactyl-hint-fg);
diff --git a/.config/tridactyl/tridactylrc b/.config/tridactyl/tridactylrc
index 526b7eb..d74d7fa 100644
--- a/.config/tridactyl/tridactylrc
+++ b/.config/tridactyl/tridactylrc
@@ -21,19 +21,22 @@ unbind <C-f>
 unbind <C-a>
 unbind --mode=ex <C-a> " select all in cmdline
 unbind --mode=browser <C-,>
+unbind <A-o>
 
 bind n findnext 1
 bind N findnext -1
 
 " hint: mpv/video
-set exaliases.mpvsafe js -p tri.excmds.shellescape(JS_ARG).then(u => tri.excmds.exclaim_quiet(`play-mpv ${u}`))
+set exaliases.mpvsafe js -p tri.excmds.shellescape(JS_ARG).then(u => tri.excmds.exclaim_quiet(`play-mpv '${u}'`))
 bind gv composite get_current_url | mpvsafe
 bind yv composite getclip | mpvsafe
 bind ;v hint -W mpvsafe
 
-"bind ;e hint -hW js -p tri.excmds.exclaim_quiet(`${tri.config.get('editorcmd')} /tmp/tridactl.${document.location.hostname}.txt '+normal!i${JS_ARG}'`)
+alias editor_rm composite editor | jsb -p tri.native.run(`rm -f '${JS_ARG[0]}'`)
+bind --mode=insert <C-i> editor_rm
+bind --mode=input <C-i> editor_rm
 
-set exaliases.imgsafe js -p tri.excmds.shellescape(JS_ARG).then(u => tri.excmds.exclaim_quiet(`fyi 'tridactyl::mvi' ${u} && mvi ${u}`))
+set exaliases.imgsafe mpvsafe
 bind ;i composite hint -Jpipe img | js -p JS_ARG.src | imgsafe
 
 bind gp composite get_current_url | winopen -popup
diff --git a/.config/tridactyl/tridactylrc.default b/.config/tridactyl/tridactylrc.default
index e505eec..7eb10cb 100644
--- a/.config/tridactyl/tridactylrc.default
+++ b/.config/tridactyl/tridactylrc.default
@@ -36,3 +36,5 @@ autocontain -s reddit\.com weeb
 autocontain -s kitsu\.app weeb
 autocontain -s trakt\.tv weeb
 autocontain -s anilist\.co weeb
+
+autocontain -s instagram\.com meta
diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc
index eac00c8..66cc917 100644
--- a/.config/waybar/config.jsonc
+++ b/.config/waybar/config.jsonc
@@ -6,18 +6,32 @@
   // ------------------------------------------------------------------------ //
 
   "modules-left": [
-    "custom/launcher",
+    "custom/home",
+    "river/layout",
     "river/mode",
     "river/tags",
     "river/window",
+    // "custom/argen-context",
+    // "wlr/workspaces",
+    "group/mpris",
   ],
 
-  "custom/launcher": {
-    "format": "",
-    "tooltip": false,
-    "on-click": "riverctl spawn fuzzel",
+  "custom/home": {
+    "format": "{icon}",
+    "format-icons": {
+      "dark": "󰔌",
+      "light": "󰄺",
+    },
+    "tooltip-format": "{alt}",
+    "exec": "~/.config/waybar/module-home.sh",
+    "return-type": "json",
+    "interval": 7200, // 2h
+    "on-click": "pkill -x fuzzel || riverctl spawn fuzzel",
+    "on-click-right": "darkman toggle",
   },
 
+  "river/layout": {},
+
   "river/mode": {},
 
   "river/tags": {
@@ -31,6 +45,47 @@
     "max-length": 50,
   },
 
+  "custom/argen-context": {
+    "exec": "~/src/argen/zig-out/bin/argenctl context list --json | jq -rc '.[]|select(.current)|.name'",
+    "interval": 2
+  },
+
+  "group/mpris": {
+    "orientation": "inherit",
+    "drawer": {
+      "transition-duration": 0,
+      "click-to-reveal": false,
+    },
+    "modules": [
+      "mpris#icon",
+      "mpris#detail",
+    ],
+  },
+
+  "mpris#icon": {
+    "format": "{player_icon}",
+    "player-icons": {
+      "default": "󰲸",
+      "firefox": "",
+      "librewolf": "",
+      "spotify": "󰓇",
+      "mpv": "",
+    },
+    "status-icons": {
+      "paused": "",
+      "playing": "",
+      "stopped": "",
+    }
+  },
+
+  "mpris#detail": {
+    "max-length": 50,
+    "format": "{dynamic}",
+    "format-paused": "<i>{dynamic}</i>",
+    "dynamic-order": ["artist", "title", "length"],
+  },
+
+
   // ------------------------------------------------------------------------ //
 
   "modules-center": [
@@ -40,6 +95,7 @@
     "clock#utc",
     "custom/calendar",
     "custom/timew",
+    "custom/syncthing",
   ],
 
   "privacy": {
@@ -101,20 +157,27 @@
   "custom/calendar": {
     "exec": "~/.config/waybar/module-calendar.sh",
     "return-type": "json",
-    "interval": 10800,
-    "on-click": "calm",
+    "interval": 7200, // 2h
+    "on-click": "riverctl spawn calm",
   },
 
   "custom/timew": {
     "exec": "~/.config/waybar/module-timew.sh",
     "return-type": "json",
-    "interval": 900,
+    "interval": 900, // 15min
+  },
+
+  "custom/syncthing": {
+    "exec": "~/.config/waybar/module-syncthing.sh",
+    "return-type": "json",
+    "interval": 900, // 15min
+    "on-click": "xdg-open http://localhost:8384",
+    "signal": 3,
   },
 
   // ------------------------------------------------------------------------ //
 
   "modules-right": [
-    "mpris",
     "tray",
     "group/tailscale",
     "group/net",
@@ -127,25 +190,6 @@
     "upower",
   ],
 
-  "mpris": {
-    "max-length": 50,
-    "format": "{player_icon} {dynamic}",
-    "format-paused": "{status_icon} <i>{dynamic}</i>",
-    "dynamic-order": ["artist", "title", "length"],
-    "player-icons": {
-      "default": "󰲸",
-      "firefox": "",
-      "librewolf": "",
-      "spotify": "󰓇",
-      "mpv": "",
-    },
-    "status-icons": {
-      "paused": "",
-      "playing": "",
-      "stopped": "",
-    }
-  },
-
   "tray": {
     "icon-size": 13,
     "spacing": 2
@@ -153,10 +197,6 @@
 
   "group/net": {
     "orientation": "inherit",
-    "drawer": {
-      "transition-duration": 0,
-      "click-to-reveal": true,
-    },
     "modules": [
       "network#primary",
       "network#bandwidth",
@@ -164,9 +204,11 @@
   },
 
   "network#primary": {
-    "format-wifi": "󰖩{signalStrength}%",
-    "format-ethernet": "󰈀",
     "format-disconnected": "󰌙",
+    "format-ethernet": "󰈀",
+    "tooltip-format-ethernet": "󰛳 Interface: {ifname}\n󰩟 IP:        {ipaddr}\n󱂇 Gateway:   {gwaddr}/{cidr}",
+    "format-wifi": "󰖩{signalStrength}%",
+    "tooltip-format-wifi": " SSID:      {essid}\n            {bssid}\n󱄙 Signal:    {signaldBm} dBm\n Frequency: {frequency} MHz\n\n󰛳 Interface: {ifname}\n󰩟 IP:        {ipaddr}\n󱂇 Gateway:   {gwaddr}/{cidr}",
     //  SSID:      {essid}
     //             {bssid}
     // 󱄙 Signal:    {signaldBm} dBm
@@ -175,19 +217,19 @@
     // 󰛳 Interface: {ifname}
     // 󰩟 IP:        {ipaddr}
     // 󱂇 Gateway:   {gwaddr}/{cidr}
-    "tooltip-format-wifi": " SSID:      {essid}\n            {bssid}\n󱄙 Signal:    {signaldBm} dBm\n Frequency: {frequency} MHz\n\n󰛳 Interface: {ifname}\n󰩟 IP:        {ipaddr}\n󱂇 Gateway:   {gwaddr}/{cidr}",
-    "tooltip-format-ethernet": "󰛳 Interface: {ifname}\n󰩟 IP:        {ipaddr}\n󱂇 Gateway:   {gwaddr}/{cidr}",
-    "menu": "on-click-right",
     "menu-file": "~/.config/waybar/menu-network.xml",
     "menu-actions": {
       "open-netm": "netm",
-      "airplane-mode": "fyi todo",
+      "airplane-mode": "nmcli radio all off",
+      "copy-ipaddr": "nmcli -g IP4.ADDRESS c show $(nmcli -s -g uuid c show --active | head -1) | wl-copy -n",
+      "copy-gateway": "nmcli -g IP4.GATEWAY c show $(nmcli -s -g uuid c show --active | head -1) | wl-copy -n",
     },
-    "on-click": "netm",
+    "menu": "on-click-right",
   },
 
   "network#bandwidth": {
-    "format": "󱦲{bandwidthUpBytes} 󱦳{bandwidthDownBytes}",
+    "format": "<small>{bandwidthUpBytes}</small><small>{bandwidthDownBytes}</small>",
+    "tooltip-format": "Total: {bandwidthTotalBytes}",
   },
 
   "group/tailscale": {
@@ -204,9 +246,9 @@
     "format-disconnected": "",
     "format-disabled": "",
     "format-linked": "",
-    "tooltip-format": "{ifname}: {bandwidthUpBits} {bandwidthDownBits}",
+    "tooltip-format": "{ifname} / {ipaddr}:\n<small>{bandwidthUpBytes}</small><small>{bandwidthDownBytes}</small>",
     "tooltip-format-disconnected": "disconnected",
-    "on-click": "vpnm",
+    "on-click": "riverctl spawn vpnm",
   },
 
   "custom/tailscale": {
@@ -218,7 +260,7 @@
     "exec": "~/.config/waybar/module-tailscale.sh",
     "return-type": "json",
     "signal": 2,
-    "on-click": "vpnm",
+    "on-click": "riverctl spawn vpnm",
   },
 
   "bluetooth": {
@@ -232,20 +274,20 @@
     "tooltip-format": "{device_enumerate}",
     "tooltip-format-enumerate-connected": "{device_alias} {device_address}",
     "tooltip-format-enumerate-connected-battery": "{device_alias} {device_address} {device_battery_percentage}%",
-    "on-click": "blum"
+    "on-click": "riverctl spawn blum"
   },
 
   "group/sys": {
     "orientation": "inherit",
     "drawer": {
       "transition-duration": 0,
-      "click-to-reveal": true,
+      "click-to-reveal": false,
     },
     "modules": [
       "load",
+      "temperature",
       "cpu",
       "memory",
-      "temperature",
     ],
   },
 
@@ -255,12 +297,12 @@
   },
 
   "cpu": {
-    "format": "cpu:{usage}%",
+    "format": "{icon}{usage}%",
     "format-icons": ["󰍛","󰍛","󰍛","󰍛","󰀦"],
   },
 
   "memory": {
-    "format": "mem:{percentage}%",
+    "format": "{icon}{percentage}%",
     "format-icons": ["󰘚"],
   },
 
@@ -300,7 +342,7 @@
     },
     "reverse-scrolling": true,
     "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
-    "on-click-right": "audm",
+    "on-click-right": "riverctl spawn audm",
   },
 
   "power-profiles-daemon": {
diff --git a/.config/waybar/menu-network.xml b/.config/waybar/menu-network.xml
index 11b78f7..deb56b0 100644
--- a/.config/waybar/menu-network.xml
+++ b/.config/waybar/menu-network.xml
@@ -11,5 +11,15 @@
                 <property name="label">Toggle airplane mode</property>
             </object>
         </child>
+        <child>
+            <object class="GtkMenuItem" id="copy-ipaddr">
+                <property name="label">Copy IP address</property>
+            </object>
+        </child>
+        <child>
+            <object class="GtkMenuItem" id="copy-gateway">
+                <property name="label">Copy gateway address</property>
+            </object>
+        </child>
     </object>
 </interface>
diff --git a/.config/waybar/module-calendar.sh b/.config/waybar/module-calendar.sh
index 6b20e2f..f779a5c 100755
--- a/.config/waybar/module-calendar.sh
+++ b/.config/waybar/module-calendar.sh
@@ -5,15 +5,14 @@ set -eu
 shopt -s extglob
 
 update() {
-	local today tn
+	local events tn
 	local text
 
 	# get events
-	today=$(~/src/calsync/ics2calendartxt ~/calendars/**/**/* 2>/dev/null |
-		grep -I "$(date -I)")
-	[ -z "$today" ] && return
+	events=$(env COLOR=never cdar 2>/dev/null)
+	[ -z "$events" ] && return
 
-	tn=$(wc -l <<<"$today")
+	tn=$(wc -l <<<"$events")
 
 	# 	text="$today"
 	# 	text="${text##"$(date +'%Y-%m-%d w%V %a ')"}"
@@ -22,7 +21,7 @@ update() {
 	text="󰃭 $tn"
 
 	jq -nrc '{text:$text,tooltip:$tip}' \
-		--arg tip "$today" \
+		--arg tip "$events" \
 		--arg text "$text"
 }
 
diff --git a/.config/waybar/module-tailscale.sh b/.config/waybar/module-tailscale.sh
index 53b0409..3a2ce75 100755
--- a/.config/waybar/module-tailscale.sh
+++ b/.config/waybar/module-tailscale.sh
@@ -15,16 +15,19 @@ update() {
 
 	alt="$ts_acct"
 	class="$ts_acct"
+	tip="$ts_ip"
 	# only display account name when not "main"
 	[ "$ts_acct" = "main" ] || text=$ts_acct
 
-	if tailscale exit-node list | grep -q selected; then
+	en_name=$(tailscale exit-node list | grep selected)
+	if test -n "$en_name"; then
 		alt="exit-node"
 		class="exit-node"
+		tip="$(awk '{printf "%s (%s)", $2, $1}' <<<"$en_name")"
 	fi
 
 	jq -nrc '{text:$text,tooltip:$tip,class:$class,alt:$alt}' \
-		--arg tip "${ts_ip:?}" \
+		--arg tip "${tip:?}" \
 		--arg class "${class:?}" \
 		--arg alt "${alt:?}" \
 		--arg text "${text:-}"
diff --git a/.config/waybar/style-dark.css b/.config/waybar/style-dark.css
index 5fd324c..a9f1583 100644
--- a/.config/waybar/style-dark.css
+++ b/.config/waybar/style-dark.css
@@ -5,9 +5,10 @@
 @define-color ur #ff5733;
 @define-color gr #86cd82;
 @define-color ye #d9ba73;
-@define-color bl #5abfb5;
+@define-color bl #458ee6;
 @define-color fg @wh;
 @define-color bg @bk;
 @define-color di shade(@fg, 0.5);
+@define-color bb alpha(@bg, 0.95);
 /* ::end style */
 @import url("style.css");
diff --git a/.config/waybar/style-light.css b/.config/waybar/style-light.css
index be6995d..930dd99 100644
--- a/.config/waybar/style-light.css
+++ b/.config/waybar/style-light.css
@@ -3,12 +3,13 @@
 @define-color wh #faf9f5;
 @define-color ac #70649a;
 @define-color ur #ca0043;
-@define-color gr #86cd82;
-@define-color ye #926200;
+@define-color gr #019833;
+@define-color ye #b07700;
 @define-color bl #007d7d;
 @define-color fg @bk;
 @define-color bg @wh;
 @define-color di shade(@bg, 0.4);
+@define-color bb alpha(@bg, 0.6);
 /* ::end style */
 @import url("style.css");
 #tags button.focused label {
diff --git a/.config/waybar/style.css b/.config/waybar/style.css
index 7e22eb3..d455b23 100644
--- a/.config/waybar/style.css
+++ b/.config/waybar/style.css
@@ -21,15 +21,16 @@
 }
 
 window#waybar {
-  background: alpha(@bg, 0.99);
+  background: @bb;
 }
 
-.module {
+widget .module {
   padding: 0 3px;
-  padding-bottom: 1px;
 }
-label.module {
+label, image {
   color: @di;
+  padding-top: 1px;
+  padding-bottom: 1px;
 }
 
 tooltip, menu {
@@ -57,9 +58,11 @@ menuitem:hover label {
 }
 
 
-#custom-launcher {
-  margin-left: 5px;
+#custom-home {
+  margin: 0;
+  padding: 0 6px;
   color: @fg;
+  background: @bg;
 }
 
 #mode {
@@ -76,6 +79,16 @@ menuitem:hover label {
   opacity: 0;
 }
 
+#layout {
+  box-shadow: inset 0 -1px @ac;
+  color: @fg;
+}
+
+#layout.left {
+  min-width: 0;
+}
+
+
 #tags button {
   min-width: unset;
   padding: 0 3px;
@@ -121,11 +134,17 @@ menuitem:hover label {
   color: @fg;
 }
 
+#mpris.icon {
+  box-shadow: inset 0 -1px @ac;
+  color: @ac;
+}
 #mpris.paused {
   color: shade(@di, 1.5);
   font-style: italic;
 }
 
+#network.bandwidth {
+}
 #network.tailscale {
   color: @fg;
 }
@@ -149,6 +168,7 @@ menuitem:hover label {
 }
 
 #pulseaudio.bluetooth {
+  box-shadow: inset 0 -1px @bl;
   color: @bl;
 }
 #pulseaudio.muted {
@@ -165,11 +185,10 @@ menuitem:hover label {
   background: @ye;
 }
 
-#upower * {
+#upower {
 }
 #upower.charging {
   box-shadow: inset 0 -1px @gr;
-  background: unset;
 }
 #upower.empty {
   background: @ur;
diff --git a/.config/yt-dlp.conf b/.config/yt-dlp.conf
index 457cd5e..1ae8755 100644
--- a/.config/yt-dlp.conf
+++ b/.config/yt-dlp.conf
@@ -1 +1,2 @@
+--no-update
 --embed-metadata