summaryrefslogtreecommitdiff
path: root/fish
diff options
context:
space:
mode:
Diffstat (limited to 'fish')
-rw-r--r--fish/conf.d/.gitignore1
-rw-r--r--fish/conf.d/ai.fish30
-rw-r--r--fish/conf.d/alternatives.fish20
-rw-r--r--fish/conf.d/config.fish31
-rw-r--r--fish/conf.d/dotfiles.fish48
-rw-r--r--fish/conf.d/editor.fish44
-rw-r--r--fish/conf.d/fuzzy.fish5
-rw-r--r--fish/conf.d/games.fish15
-rw-r--r--fish/conf.d/gos.fish6
-rw-r--r--fish/conf.d/java.fish6
-rw-r--r--fish/conf.d/k8s.fish76
-rw-r--r--fish/conf.d/quickedit.fish118
-rw-r--r--fish/conf.d/supersync.fish125
-rw-r--r--fish/conf.d/taskwarrior.fish143
-rw-r--r--fish/conf.d/timr.fish26
-rw-r--r--fish/conf.d/tmputils.fish63
-rw-r--r--fish/conf.d/tmux.fish94
-rw-r--r--fish/conf.d/update.fish75
-rw-r--r--fish/conf.d/utils.fish155
-rw-r--r--fish/conf.d/worktime.fish122
-rw-r--r--fish/conf.d/zoxide.fish5
-rw-r--r--fish/conf.d/zsh.fish6
22 files changed, 1214 insertions, 0 deletions
diff --git a/fish/conf.d/.gitignore b/fish/conf.d/.gitignore
new file mode 100644
index 0000000..70a0a68
--- /dev/null
+++ b/fish/conf.d/.gitignore
@@ -0,0 +1 @@
+omf.fish
diff --git a/fish/conf.d/ai.fish b/fish/conf.d/ai.fish
new file mode 100644
index 0000000..01993c4
--- /dev/null
+++ b/fish/conf.d/ai.fish
@@ -0,0 +1,30 @@
+# set -gx HEXAI_PROVIDER copilot
+
+function ai::cursor_agent
+ set last_updated_file ~/.cursor_agent_last_updated
+ if not test -e $last_updated_file
+ cursor-agent update
+ touch $last_updated_file
+ else
+ set current_time (date +%s)
+ if test (uname) = Darwin
+ set file_time (stat -f %m $last_updated_file 2>/dev/null)
+ else
+ set file_time (stat -c %Y $last_updated_file 2>/dev/null)
+ end
+ set time_diff (math "$current_time - $file_time")
+ if test $time_diff -gt 86400
+ cursor-agent update
+ touch $last_updated_file
+ end
+ end
+ touch ~/.nofish
+ cursor-agent
+end
+
+function a
+ ai::cursor_agent
+end
+
+abbr -a suggest hexai
+abbr -a explain 'hexai explain'
diff --git a/fish/conf.d/alternatives.fish b/fish/conf.d/alternatives.fish
new file mode 100644
index 0000000..75c6e05
--- /dev/null
+++ b/fish/conf.d/alternatives.fish
@@ -0,0 +1,20 @@
+if type -q bat
+ alias Cat=/usr/bin/cat
+ alias cat=bat
+end
+if type -q see
+ alias ca=see
+end
+if type -q bit
+ alias Git=/usr/bin/git
+ alias git=bit
+end
+if type -q procs
+ alias p='procs'
+end
+if type -q carl
+ alias cal='carl'
+end
+
+# To change my habits
+alias tig=lazygit
diff --git a/fish/conf.d/config.fish b/fish/conf.d/config.fish
new file mode 100644
index 0000000..670ca86
--- /dev/null
+++ b/fish/conf.d/config.fish
@@ -0,0 +1,31 @@
+fish_vi_key_bindings
+
+# Add paths to PATH
+set -U fish_user_paths ~/bin ~/scripts ~/go/bin ~/.cargo/bin $fish_user_paths
+
+if command -q -v doas >/dev/null
+ abbr -a s doas
+else
+ abbr -a s sudo
+end
+
+abbr -a g 'grep -E -i'
+abbr -a no 'grep -E -i -v'
+abbr -a not 'grep -E -i -v'
+abbr -a gl 'git log --pretty=oneline --graph --decorate --all'
+abbr -a gp 'begin; git commit -a; and git pull; and git push; end'
+
+for dir in ~/.config/fish/conf.d.work ~/.config/fish/conf.d.local
+ if test -d $dir
+ for file in $dir/*.fish
+ source $file
+ end
+ end
+end
+
+if test -d /home/linuxbrew/.linuxbrew
+ if status is-interactive
+ # Commands to run in interactive sessions can go here
+ end
+ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
+end
diff --git a/fish/conf.d/dotfiles.fish b/fish/conf.d/dotfiles.fish
new file mode 100644
index 0000000..cf944a1
--- /dev/null
+++ b/fish/conf.d/dotfiles.fish
@@ -0,0 +1,48 @@
+set -gx DOTFILES_DIR ~/git/conf/dotfiles
+
+function dotfiles::update
+ set -l prev_pwd (pwd)
+ cd $DOTFILES_DIR
+ rex home
+ cd "$prev_pwd"
+end
+
+function dotfiles::update::git
+ set -l prev_pwd (pwd)
+ cd $DOTFILES_DIR
+ git pull
+ git commit -a
+ git push
+ rex home
+ cd "$prev_pwd"
+end
+
+function dotfiles::fuzzy::edit
+ set -l prev_pwd (pwd)
+ cd $DOTFILES_DIR
+ set -l dotfile (find . -type f -not -path '*/.git/*' | fzf)
+ $EDITOR "$dotfile"
+ if echo "$dotfile" | grep -F -q .fish
+ echo "Sourcing $dotfile"
+ source "$dotfile"
+ end
+ cd "$prev_pwd"
+end
+
+function dotfiles::rexify
+ cd $DOTFILES_DIR
+ rex home
+ cd -
+end
+
+function dotfiles::random::edit
+ $EDITOR (find $DOTFILES_DIR -type f -not -path '*/.git/*' | shuf -n 1)
+end
+
+abbr -a .u 'dotfiles::update'
+abbr -a .ug 'dotfiles::update::git'
+abbr -a .e 'dotfiles::fuzzy::edit'
+abbr -a .rex 'dotfiles::rexify'
+abbr -a .re 'dotfiles::random::edit'
+abbr -a cdconf "cd $HOME/git/conf"
+abbr -a cdotfiles "cd $HOME/git/conf/dotfiles"
diff --git a/fish/conf.d/editor.fish b/fish/conf.d/editor.fish
new file mode 100644
index 0000000..bda4644
--- /dev/null
+++ b/fish/conf.d/editor.fish
@@ -0,0 +1,44 @@
+set -gx EDITOR hx
+set -gx VISUAL $EDITOR
+set -gx GIT_EDITOR $EDITOR
+set -gx HELIX_CONFIG_DIR $HOME/.config/helix
+
+function editor::helix::open_with_lock
+ set -l file $argv[1]
+ set -l lock "$file.lock"
+ if test -f "$lock"
+ echo "File lock $lock exists! Another instance is editing it?"
+ return 2
+ end
+ touch $lock
+ hx $file $argv[2..-1]
+ rm $lock
+end
+
+function editor::helix::open_with_lock::force
+ set -l file $argv[1]
+ set -l lock "$file.lock"
+ if test -f "$lock"
+ echo "File lock $lock exists! Force deleting it and terminating all $EDITOR instances?"
+ rm -f $lock
+ pkill -f $EDITOR
+ end
+ touch $lock
+ hx $file $argv[2..-1]
+ rm $lock
+end
+
+function editor::helix::edit::remote
+ set -l local_path $argv[1]
+ set -l remote_uri $argv[2]
+ scp $local_path $remote_uri; or return 1
+ echo "LOCAL_PATH=$local_path; REMOTE_URI=$remote_uri" >~/.hx.remote.source
+ hx $local_path
+end
+
+abbr -a lhx 'editor::helix::open_with_lock'
+abbr -a hxl 'editor::helix::open_with_lock'
+abbr -a hxlf 'editor::helix::open_with_lock::force'
+abbr -a lhxf 'editor::helix::open_with_lock::force'
+abbr -a rhx 'editor::helix::edit::remote'
+abbr -a x hx
diff --git a/fish/conf.d/fuzzy.fish b/fish/conf.d/fuzzy.fish
new file mode 100644
index 0000000..7683a0e
--- /dev/null
+++ b/fish/conf.d/fuzzy.fish
@@ -0,0 +1,5 @@
+function __tv_git
+ tv git-repos
+end
+
+bind \cg __tv_git
diff --git a/fish/conf.d/games.fish b/fish/conf.d/games.fish
new file mode 100644
index 0000000..291a798
--- /dev/null
+++ b/fish/conf.d/games.fish
@@ -0,0 +1,15 @@
+function games::colorscript
+ if test -e ~/git/shell-color-scripts
+ cd ~/git/shell-color-scripts
+ set -x DEV 1
+ ./colorscript.sh --random
+ cd -
+ else
+ echo 'No colorscripts installed. Go to:'
+ echo ' https://gitlab.com/dwt1/shell-color-scripts'
+ end
+end
+
+if not test -f ~/.colorscript.disable
+ games::colorscript
+end
diff --git a/fish/conf.d/gos.fish b/fish/conf.d/gos.fish
new file mode 100644
index 0000000..a23d7a7
--- /dev/null
+++ b/fish/conf.d/gos.fish
@@ -0,0 +1,6 @@
+set -x GOS_BIN ~/go/bin/gos
+set -x GOS_DIR ~/.gosdir
+
+if test -f $GOS_BIN
+ alias cdgos "cd $GOS_DIR"
+end
diff --git a/fish/conf.d/java.fish b/fish/conf.d/java.fish
new file mode 100644
index 0000000..5a4968c
--- /dev/null
+++ b/fish/conf.d/java.fish
@@ -0,0 +1,6 @@
+if test (uname) = Linux
+ set -gx JAVA_HOME /usr/lib/jvm/java-latest-openjdk
+ if not test -d $JAVA_HOME
+ echo "Warning: JAVA_HOME path '$JAVA_HOME' does not exist."
+ end
+end
diff --git a/fish/conf.d/k8s.fish b/fish/conf.d/k8s.fish
new file mode 100644
index 0000000..ee1584b
--- /dev/null
+++ b/fish/conf.d/k8s.fish
@@ -0,0 +1,76 @@
+function kcompletions
+ if command -q -v kubectl >/dev/null
+ kubectl completion fish | source
+ end
+end
+
+# Check if the directory $HOME/.krew exists and update PATH
+if test -d $HOME/.krew
+ set -x PATH (set -q KREW_ROOT; and echo $KREW_ROOT; or echo $HOME/.krew)/bin $PATH
+end
+
+function kpod
+ set pattern "."
+ if test -n "$argv[1]"
+ set pattern "$argv[1]"
+ end
+ set -gx POD (kubectl get pods | grep "$pattern" | sort -R | head -n 1 | cut -d' ' -f1)
+ echo "Pod is $POD"
+end
+
+function klogsf
+ if test -z "$POD" -o -n "$argv[1]"
+ kpod $argv
+ end
+ kubectl logs -f $POD
+end
+
+function klogs
+ if test -z "$POD" -o -n "$argv[1]"
+ kpod $argv
+ end
+ kubectl logs $POD
+end
+
+function kbash
+ if test -z "$POD" -o -n "$argv[1]"
+ kpod $argv
+ end
+ kubectl exec -it $POD -- /bin/bash
+end
+
+function kshell
+ if test -z "$POD" -o -n "$argv[1]"
+ kpod $argv
+ end
+ kubectl exec -it $POD -- /bin/sh
+end
+
+function kdesc
+ if test -z "$POD" -o -n "$argv[1]"
+ kpod $argv
+ end
+ kubectl describe pod $POD
+end
+
+function kedit
+ if test -z "$POD" -o -n "$argv[1]"
+ kpod $argv
+ end
+ kubectl edit pod $POD
+end
+
+function k8s::kubectl::config::contexts
+ kubectl config get-contexts | sed '1d; /\*/d' | awk '{ print $1 }' | sort
+end
+alias kcontexts="k8s::kubectl::config::contexts"
+
+function k8s::kubectl::config::use_context
+ kubectl config use-context (kubectl config get-contexts | sed '1d; /\*/d' | awk '{ print $1 }' | sort | fzf)
+end
+alias kcontext="k8s::kubectl::config::use_context"
+
+function k8s::kubectl::config::set_namespace
+ kubectl config set-context --current --namespace=(kubectl get ns | sed 1d | awk '{ print $1 }' | sort | fzf)
+end
+alias knamespace="k8s::kubectl::config::set_namespace"
diff --git a/fish/conf.d/quickedit.fish b/fish/conf.d/quickedit.fish
new file mode 100644
index 0000000..f1c0f15
--- /dev/null
+++ b/fish/conf.d/quickedit.fish
@@ -0,0 +1,118 @@
+set -gx QUICKEDIT_DIR ~/QuickEdit
+
+function quickedit::postaction
+ set -l file_path $argv[1]
+ set -l make_run 0
+
+ if test -f Makefile
+ make
+ set make_run 1
+ end
+
+ # Go to git toplevel dir (if exists)
+ cd (dirname $file_path)
+ set -l git_dir (git rev-parse --show-toplevel 2>/dev/null)
+ if test $status -eq 0
+ cd $git_dir
+ end
+ if not test $make_run -eq 1
+ if test -f Makefile
+ make
+ end
+ end
+ if test -d .git
+ git commit -a -m Update
+ git pull
+ git push
+ end
+end
+
+function quickedit::current_dir
+ set -l grep_pattern .
+
+ if test (count $argv) -gt 0
+ set grep_pattern $argv[1]
+ end
+
+ set files (find -L . -type f -not -path '*/.*' | grep -E "$grep_pattern")
+
+ switch (count $files)
+ case 0
+ echo No result found
+ return
+ case 1
+ set file_path $files[1]
+ case '*'
+ set file_path (printf '%s\n' $files | fzf)
+ end
+
+ if editor::helix::open_with_lock $file_path
+ quickedit::postaction $file_path
+ end
+end
+
+function quickedit
+ set -l prev_dir (pwd)
+
+ cd $QUICKEDIT_DIR
+ if test (count $argv) -gt 0
+ quickedit::current_dir $argv[1]
+ else
+ quickedit::current_dir
+ end
+
+ cd $prev_dir
+end
+
+function quickedit::snippets
+ set -l prev_dir (pwd)
+
+ cd ~/Notes/snippets
+ if test (count $argv) -gt 0
+ set grep_pattern $argv[1]
+ quickedit::current_dir $argv[1]
+ else
+ quickedit::current_dir
+ end
+
+ cd $prev_dir
+end
+
+function quickedit::direct
+ set -l dir $argv[1]
+ set -l file $argv[2]
+ cd $dir
+
+ if editor::helix::open_with_lock $file
+ quickedit::postaction $file
+ end
+
+ cd -
+end
+
+function quickedit::scratchpad
+ quickedit::direct ~/Notes Scratchpad.md
+end
+
+function quickedit::quicknote
+ quickedit::direct ~/Notes QuickNote.md
+end
+
+function quickedit::performance
+ quickedit::direct ~/Notes Performance.md
+end
+
+abbr -a e quickedit
+abbr -a scratch quickedit::scratchpad
+abbr -a S quickedit::scratchpad
+abbr -a quicknote quickedit::quicknote
+abbr -a perf quickedit::performance
+abbr -a performance quickedit::performance
+abbr -a goals quickedit::performance
+abbr -a er "ranger $QUICKEDIT_DIR"
+abbr -a cdquickedit "cd $QUICKEDIT_DIR"
+abbr -a cdnotes 'cd ~/Notes'
+abbr -a cdfish 'cd ~/.config/fish/conf.d'
+abbr -a cddocs 'cd ~/Documents'
+abbr -a cdocs 'cd ~/Documents'
+abbr -a snippets quickedit::snippets
diff --git a/fish/conf.d/supersync.fish b/fish/conf.d/supersync.fish
new file mode 100644
index 0000000..320afcd
--- /dev/null
+++ b/fish/conf.d/supersync.fish
@@ -0,0 +1,125 @@
+set -x SUPERSYNC_STAMP_FILE ~/.supersync.last
+
+# Only sync the HabitsAndQuotes when it's asked for via function parameter
+function supersync::worktime
+ set -l worktime_dir ~/git/worktime
+
+ if not test -d $worktime_dir
+ echo "Warning: Directory $worktime_dir does not exist"
+ return 1
+ end
+ cd $worktime_dir
+
+ if test (count $argv) -gt 0 -a $argv[1] = sync_quotes
+ if test -d ~/Notes/HabitsAndQuotes
+ echo "" >work-wisdoms.md.tmp
+ for notes in ~/Notes/HabitsAndQuotes/{Productivity,Mentoring}.md
+ grep '^\* ' $notes >>work-wisdoms.md.tmp
+ end
+ sort -u work-wisdoms.md.tmp >work-wisdoms.md
+ rm work-wisdoms.md.tmp
+ git add work-wisdoms.md
+ grep '^\* ' ~/Notes/HabitsAndQuotes/Exercise.md >exercises.md
+ git add exercises.md
+ end
+ end
+
+ find . -name '*.txt' -exec git add {} \;
+ find . -name '*.json' -exec git add {} \;
+ find . -name '*.csv' -exec git add {} \;
+ git commit -a -m sync
+
+ git pull origin master
+ git push origin master
+
+ cd -
+end
+
+function supersync::uprecords
+ set -l uprecords_dir ~/git/uprecords
+ set -l uprecords_repo git@codeberg.org:snonux/uprecords.git
+
+ if not test -d $uprecords_dir
+ git clone $uprecords_repo $uprecords_dir
+ cd $uprecords_dir
+ else
+ cd $uprecords_dir
+ git pull
+ end
+
+ make update
+ git commit -a -m Update
+ git push
+ cd -
+end
+
+function supersync::taskwarrior
+ if test -f ~/scripts/taskwarriorfeeder.rb
+ ruby ~/scripts/taskwarriorfeeder.rb
+ end
+
+ taskwarrior::export
+ taskwarrior::export::gos
+ taskwarrior::export::bd
+ taskwarrior::import
+ taskwarrior::db::prune
+end
+
+function supersync::gitsyncer
+ set enable_file ~/.gitsyncer_enable
+ set now (date +%s)
+ set weekly_interval (math 7 \* 24 \* 60 \* 60)
+
+ if not test -f $enable_file
+ # echo Gitsyncer is not enabled
+ return
+ end
+
+ set last_run (cat $enable_file)
+ if test (math $now - $last_run) -lt $weekly_interval
+ return
+ end
+
+ if test -f ~/go/bin/gitsyncer
+ ~/go/bin/gitsyncer sync bidirectional --auto-create-releases --create-repos --throttle && ~/go/bin/gitsyncer showcase
+ end
+ if test $status -eq 0
+ echo $now >$enable_file
+ end
+end
+
+function supersync
+ if test -f ~/.supersync_disable
+ echo Supersync is disabled
+ return
+ end
+
+ supersync::worktime sync_quotes
+ supersync::taskwarrior
+ supersync::worktime no_sync_quotes
+ supersync::uprecords
+
+ if test -f ~/.gos_enable
+ gos
+ end
+
+ supersync::gitsyncer
+ update::tools
+
+ date +%s >$SUPERSYNC_STAMP_FILE.tmp
+ mv $SUPERSYNC_STAMP_FILE.tmp $SUPERSYNC_STAMP_FILE
+end
+
+function supersync::is_it_time_to_sync
+ set -l max_age 86400
+ set -l now (date +%s)
+ if test -f $SUPERSYNC_STAMP_FILE
+ set -l diff (math $now - (cat $SUPERSYNC_STAMP_FILE))
+ if test $diff -lt $max_age
+ return 0
+ end
+ end
+ read -P "It's time to run supersync! Run it? (y/n) " answer; and test "$answer" = y; and supersync
+end
+
+abbr -a supersynct 'supersync; track'
diff --git a/fish/conf.d/taskwarrior.fish b/fish/conf.d/taskwarrior.fish
new file mode 100644
index 0000000..17240a3
--- /dev/null
+++ b/fish/conf.d/taskwarrior.fish
@@ -0,0 +1,143 @@
+function taskwarrior::fuzzy::_select
+ sed -n '/^[0-9]/p' | sort -rn | fzf | cut -d' ' -f1
+end
+
+function taskwarrior::fuzzy::find
+ set -g TASK_ID (task ready | taskwarrior::fuzzy::_select)
+end
+
+function taskwarrior::select
+ set -l task_id "$argv[1]"
+ if test -n "$task_id"
+ set -g TASK_ID "$task_id"
+ end
+ if test "$TASK_ID" = - -o -z "$TASK_ID"
+ taskwarrior::fuzzy::find
+ end
+end
+
+function taskwarrior::due::count
+ set -l due_count (task status:pending due.before:now count)
+
+ if test $due_count -gt 0
+ echo "There are $due_count tasks due!"
+ end
+end
+
+function taskwarrior::add::track
+ if test (count $argv) -gt 0
+ task add priority:L +personal +track $argv
+ else
+ tasksamurai +track
+ end
+end
+
+function taskwarrior::add::standup
+ if test (count $argv) -gt 0
+ task add priority:L +work +standup +sre +nosched $argv
+ task add priority:L +work +standup +storage +nosched $argv
+
+ if test -f ~/git/helpers/jira/jira.rb
+ echo "Do you want to raise a Jira ticket? (y/n)"
+ read -l user_input
+ if test "$user_input" = y
+ ruby ~/git/helpers/jira/jira.rb --raise "$argv"
+ end
+ end
+
+ else
+ tasksamurai +standup
+ end
+end
+
+function taskwarrior::add::standup::editor
+ set -l tmpfile (mktemp /tmp/standup.XXXXXX.txt)
+ $EDITOR $tmpfile
+ taskwarrior::add::standup (cat $tmpfile)
+end
+
+function _taskwarrior::set_import_export_tags
+ if test (uname) = Darwin
+ set -gx TASK_IMPORT_TAG work
+ set -gx TASK_EXPORT_TAG personal
+ else
+ set -gx TASK_IMPORT_TAG personal
+ set -gx TASK_EXPORT_TAG work
+ end
+end
+
+function taskwarrior::export::bd
+ if test -d ~/Notes/Bulgarian
+ # Export bulgarian dumi
+ set -l outfile ~/Notes/Bulgarian/bd-(date +%s).txt
+ task +bd status:pending export | jq -r '.[].description' >$outfile
+ yes | task +bd status:pending delete
+ cat ~/Notes/Bulgarian/bd-*.txt | sort -u >~/Notes/Bulgarian/compact-(date +%s).tmp && rm ~/Notes/Bulgarian/bd-*.txt
+ sort -u ~/Notes/Bulgarian/compact-*.tmp >~/Notes/Bulgarian/bd-compacted.txt && rm ~/Notes/Bulgarian/compact-*.tmp
+ end
+end
+
+function taskwarrior::export::gos
+ task +share status:pending export >"$WORKTIME_DIR/tw-gos-export-$(date +%s).json"
+ yes | task +share status:pending delete
+end
+
+function taskwarrior::export
+ _taskwarrior::set_import_export_tags
+ set -l count (task +$TASK_EXPORT_TAG status:pending count)
+
+ if test $count -eq 0
+ return
+ end
+
+ echo "Exporting $count tasks to $TASK_EXPORT_TAG"
+ task +$TASK_EXPORT_TAG status:pending export >"$WORKTIME_DIR/tw-$TASK_EXPORT_TAG-export-$(date +%s).json"
+ yes | task +$TASK_EXPORT_TAG status:pending delete
+end
+
+function taskwarrior::import
+ _taskwarrior::set_import_export_tags
+
+ find $WORKTIME_DIR -name "tw-$TASK_IMPORT_TAG-export-*.json" | while read -l import
+ task import $import
+ rm $import
+ end
+
+ find $WORKTIME_DIR -name "tw-(hostname)-export-*.json" | while read -l import
+ task import $import
+ rm $import
+ end
+end
+
+function taskwarrior::db::prune
+ yes | task +random status:completed delete
+end
+
+function taskwarrior::invoke
+ if test -f ~/scripts/taskwarriorfeeder.rb
+ ruby ~/scripts/taskwarriorfeeder.rb
+ end
+ tasksamurai
+end
+
+abbr -a t task
+abbr -a L 'task add +log'
+abbr -a tlog 'task add +log'
+abbr -a log 'task add +log'
+abbr -a tdue 'tasksamurai status:pending due.before:now'
+abbr -a thome 'tasksamurai +home'
+abbr -a tasks 'tasksamurai -track'
+abbr -a tread 'tasksamurai +read'
+abbr -a track 'taskwarrior::add::track'
+abbr -a tra 'taskwarrior::add::track'
+abbr -a trat 'timr track'
+abbr -a tfind 'taskwarrior::fuzzy::find'
+abbr -a ts 'taskwarrior::invoke'
+
+# Virtual standup abbrs
+abbr -a V 'taskwarrior::add::standup'
+abbr -a Vstorage 'tasksamurai +standup +storage'
+abbr -a Vsre 'tasksamurai +standup +sre'
+abbr -a Ved 'taskwarrior::add::standup::editor'
+
+taskwarrior::due::count
diff --git a/fish/conf.d/timr.fish b/fish/conf.d/timr.fish
new file mode 100644
index 0000000..8c92462
--- /dev/null
+++ b/fish/conf.d/timr.fish
@@ -0,0 +1,26 @@
+function timr_prompt -d "Display timr timr_status in the prompt"
+ if command -v timr >/dev/null
+ set -l timr_status (timr prompt)
+ if test -n "$timr_status"
+ set -l icon (string sub -l 1 -- "$timr_status")
+ set -l time (string sub -s 2 -- "$timr_status")
+ if test "$icon" = "▶"
+ set_color green
+ else
+ set_color yellow
+ end
+ printf '%s' "$icon"
+ set_color normal
+ printf ' %s' "$time"
+ end
+ end
+end
+
+complete -c timr -n __fish_use_subcommand -a start -d "Start the timer"
+complete -c timr -n __fish_use_subcommand -a stop -d "Stop the timer"
+complete -c timr -n __fish_use_subcommand -a pause -d "Pause the timer"
+complete -c timr -n __fish_use_subcommand -a status -d "Show the timer status"
+complete -c timr -n __fish_use_subcommand -a reset -d "Reset the timer"
+complete -c timr -n __fish_use_subcommand -a live -d "Show the live timer"
+complete -c timr -n __fish_use_subcommand -a prompt -d "Show the prompt status"
+
diff --git a/fish/conf.d/tmputils.fish b/fish/conf.d/tmputils.fish
new file mode 100644
index 0000000..87d8bde
--- /dev/null
+++ b/fish/conf.d/tmputils.fish
@@ -0,0 +1,63 @@
+set -gx TMPUTILS_DIR ~/data/tmp
+set -gx TMPUTILS_TMPFILE ~/.tmpfile
+
+function tmpdir
+ set -l name $argv[1]
+ set -l dir "$TMPUTILS_DIR/$name"
+ if not test -d $dir
+ mkdir -p $dir
+ end
+ cd $dir
+end
+
+function tmpls
+ if not test -d $TMPUTILS_DIR
+ return
+ end
+ ls $TMPUTILS_DIR
+end
+
+function tmptee
+ set -l name $argv[1]
+ if test -z "$name"
+ set name (date +%s)
+ else
+ set -e argv[1]
+ end
+ set -l file "$TMPUTILS_DIR/$name"
+ if not test -d $TMPUTILS_DIR
+ mkdir -p $TMPUTILS_DIR
+ end
+ tee $argv $file
+ echo $file >$TMPUTILS_TMPFILE
+end
+
+function tmpcat
+ set -l name $argv[1]
+ if test -z "$name"
+ cat (tmpfile)
+ return
+ end
+ cat "$TMPUTILS_DIR/$name"
+end
+
+function tmpedit
+ set -l name $argv[1]
+ if test -z "$name"
+ $EDITOR (tmpfile)
+ return
+ end
+ $EDITOR "$TMPUTILS_DIR/$name"
+end
+
+function tmpgrep
+ set -l name $argv[1]
+ set -e argv[1]
+ tmcpat $name | grep $argv
+end
+
+function tmpfile
+ cat $TMPUTILS_TMPFILE
+end
+
+abbr -a cdtmp "cd $TMPUTILS_DIR"
diff --git a/fish/conf.d/tmux.fish b/fish/conf.d/tmux.fish
new file mode 100644
index 0000000..e65960e
--- /dev/null
+++ b/fish/conf.d/tmux.fish
@@ -0,0 +1,94 @@
+function _tmux::cleanup_default
+ tmux list-sessions | string match -r '^T.*: ' | string match -v -r attached | string split ':' | while read -l s
+ echo "Killing $s"
+ tmux kill-session -t "$s"
+ end
+end
+
+function _tmux::connect_command
+ set -l server_or_pod $argv[1]
+ if test -z "$TMUX_KEXEC"
+ echo "ssh -A -t $server_or_pod"
+ else
+ echo "kubectl exec -it $server_or_pod -- /bin/bash"
+ end
+end
+
+function tmux::new
+ set -l session $argv[1]
+ _tmux::cleanup_default
+ if test -z "$session"
+ tmux::new (string join "" T (date +%s))
+ else
+ tmux new-session -d -s $session
+ tmux -2 attach-session -t $session || tmux -2 switch-client -t $session
+ end
+end
+
+function tmux::attach
+ set -l session $argv[1]
+ if test -z "$session"
+ tmux attach-session || tmux::new
+ else
+ tmux attach-session -t $session || tmux::new $session
+ end
+end
+
+function tmux::remote
+ set -l server $argv[1]
+ tmux new -s $server "ssh -A -t $server 'tmux attach-session || tmux'" || tmux attach-session -d -t $server
+end
+
+function tmux::search
+ set -l session (tmux list-sessions | fzf | cut -d: -f1)
+ if test -z "$TMUX"
+ tmux attach-session -t $session
+ else
+ tmux switch -t $session
+ end
+end
+
+function tmux::cluster_ssh
+ if test -f "$argv[1]"
+ tmux::tssh_from_file $argv[1]
+ return
+ end
+ tmux::tssh_from_argument $argv
+end
+
+function tmux::tssh_from_argument
+ set -l session $argv[1]
+ set first_server_or_container $argv[2]
+ set remaining_servers $argv[3..-1]
+ if test -z "$first_server_or_container"
+ set first_server_or_container $session
+ end
+
+ tmux new-session -d -s $session (_tmux::connect_command "$first_server_or_container")
+ if not tmux list-session | grep "^$session:"
+ echo "Could not create session $session"
+ return 2
+ end
+ for server_or_container in $remaining_servers
+ tmux split-window -t $session "tmux select-layout tiled; $(_tmux::connect_command "$server_or_container")"
+ end
+ tmux setw -t $session synchronize-panes on
+ tmux -2 attach-session -t $session || tmux -2 switch-client -t $session
+end
+
+function tmux::tssh_from_file
+ set -l serverlist $argv[1]
+ set -l session (basename $serverlist | cut -d. -f1)
+ tmux::tssh_from_argument $session (awk '{ print $1 }' $serverlist | sed 's/.lan./.lan/g')
+end
+
+alias tn 'tmux::new'
+alias ta 'tmux::attach'
+alias tx 'tmux::remote'
+alias ts 'tmux::search'
+alias tssh 'tmux::cluster_ssh'
+alias tm tmux
+alias tl 'tmux list-sessions'
+alias foo 'tmux::new foo'
+alias bar 'tmux::new bar'
+alias baz 'tmux::new baz'
diff --git a/fish/conf.d/update.fish b/fish/conf.d/update.fish
new file mode 100644
index 0000000..abe9da0
--- /dev/null
+++ b/fish/conf.d/update.fish
@@ -0,0 +1,75 @@
+function update::tools
+ set pids
+
+ echo "Installing/updating gofumpt"
+ go install mvdan.cc/gofumpt@latest &
+ set -a pids $last_pid
+
+ echo "Installing/updating mage"
+ go install github.com/magefile/mage@latest &
+ set -a pids $last_pid
+
+ echo "Installing/updating golangci-lint"
+ go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest &
+ set -a pids $last_pid
+
+ echo "Installing/updating goimports"
+ go install golang.org/x/tools/cmd/goimports@latest &
+ set -a pids $last_pid
+
+ for prog in hexai hexai-lsp hexai-tmux-action
+ echo "Installing/updating $prog from codeberg.org/snonux/hexai/cmd/$prog@latest"
+ go install codeberg.org/snonux/hexai/cmd/$prog@latest &
+ set -a pids $last_pid
+ end
+
+ for prog in tasksamurai timr perc
+ echo "Installing/updating $prog from codeberg.org/snonux/$prog/cmd/$prog@latest"
+ go install codeberg.org/snonux/$prog/cmd/$prog@latest &
+ set -a pids $last_pid
+ end
+
+ if test (uname) = Darwin
+ echo 'Updating cursor-agent on macOS'
+ cursor-agent update &
+ end
+ set -a pids $last_pid
+
+ echo 'Updating claude'
+ claude update &
+ set -a pids $last_pid
+
+ if test (uname) = Linux
+ echo "Installing/updating tgpt"
+ go install github.com/aandrew-me/tgpt/v2@latest &
+ set -a pids $last_pid
+
+ for prog in gos gitsyncer yoga totalrecall
+ echo "Installing/updating $prog from codeberg.org/snonux/$prog/cmd/$prog@latest"
+ go install codeberg.org/snonux/$prog/cmd/$prog@latest
+ end
+
+ # doas npm uninstall -g @qwen-code/qwen-code@latest
+ # doas npm install -g @qwen-code/qwen-code@latest
+
+ echo "Installing/updating @openai/codex globally via npm"
+ doas npm uninstall -g @openai/codex
+ doas npm install -g @openai/codex
+
+ echo "Installing/updating @google/gemini-cli globally via npm"
+ doas npm uninstall -g @google/gemini-cli
+ doas npm install -g @google/gemini-cli
+
+ echo "Installing/updating @sourcegraph/amp globally via npm"
+ doas npm uninstall -g @sourcegraph/amp
+ doas npm install -g @sourcegraph/amp
+
+ echo "Installing/updating opencode-ai globally via npm"
+ doas npm uninstall -g opencode-ai
+ doas npm install -g opencode-ai
+ end
+
+ for pid in $pids
+ wait $pid
+ end
+end
diff --git a/fish/conf.d/utils.fish b/fish/conf.d/utils.fish
new file mode 100644
index 0000000..33854a5
--- /dev/null
+++ b/fish/conf.d/utils.fish
@@ -0,0 +1,155 @@
+function fullest_i
+ df -i | sort -n -k 5
+end
+
+function fullest_h
+ df -h | sort -n -k 5
+end
+
+function usortn
+ sort | uniq -c | sort -n
+end
+
+function asum
+ awk '{ sum += $1 } END { print sum }'
+end
+
+function stop
+ set -l service $argv[1]
+ sudo service $service stop $argv
+end
+
+function start
+ set -l service $argv[1]
+ sudo service $service start $argv
+end
+
+function restart
+ set -l service $argv[1]
+ sudo service $service restart $argv
+end
+
+function statuss
+ set -l service $argv[1]
+ sudo service $service status $argv
+end
+
+function loop
+ set -l sleep 10
+ if set -q SLEEP
+ set sleep $SLEEP
+ end
+ echo "sleep is $sleep" 1>&2
+ while true
+ $argv
+ sleep $sleep
+ end
+end
+
+function f
+ find . -iname "*$argv*"
+end
+
+function random
+ set -l upto $argv[1]
+ set -l random (math $RANDOM % $upto)
+ echo "Sleeping $random seconds"
+ sleep $random
+end
+
+function dedup
+ set -l file $argv[1]
+ if test -z $file
+ awk '{ if (line[$0] != 42) { print $0 }; line[$0] = 42; }'
+ else
+ awk '{ if (line[$0] != 42) { print $0 }; line[$0] = 42; }' $file | sudo tee $file.dedup >/dev/null
+ if test ! -f $file.dedupbak
+ sudo mv $file $file.dedupbak
+ end
+ sudo mv $file.dedup $file
+ wc -l $file $file.dedupbak
+ sudo gzip --best $file.dedupbak &
+ end
+end
+
+function dedup_no_bak
+ set -l file $argv[1]
+ if test -z $file
+ awk '{ if (line[$0] != 42) { print $0 }; line[$0] = 42; }'
+ else
+ awk '{ if (line[$0] != 42) { print $0 }; line[$0] = 42; }' $file | sudo tee $file.dedup >/dev/null
+ if test ! -f $file.dedupbak
+ sudo mv $file $file.dedupbak
+ end
+ sudo mv $file.dedup $file
+ wc -l $file $file.dedupbak
+ sudo rm -v $file.dedupbak &
+ end
+end
+
+function drop_caches
+ echo 3 | sudo tee /proc/sys/vm/drop_caches
+end
+
+function ssl_connect
+ set -l address $argv[1]
+ openssl s_client -connect $address
+end
+
+function ssl_dates
+ ssl_connect $argv | openssl x509 -noout -dates
+end
+
+function lastu
+ last | grep -E -v '(root|cron|nagios)'
+end
+
+function lastl
+ lastu | less
+end
+
+abbr wetter 'curl http://wttr.in'
+
+abbr tf terraform
+
+function touchtype
+ tt --noskip --noreport --showwpm --bold --theme (tt -list themes | sort -R | head -n1) $argv
+end
+
+function touchtype::quote
+ while true
+ touchtype -quotes en
+ sleep 0.2
+ end
+end
+
+function touchtype::scifi
+ find ~/git/scifi/summaries/ -type f -name \*.md | sort -R | head -n 1 | xargs cat | touchtype
+end
+
+function checkcert
+ set host $argv[1]
+ set port $argv[2]
+ openssl s_client \
+ -connect $host:$port \
+ -servername $host \
+ -showcerts </dev/null 2>/dev/null | openssl x509 -noout -dates -subject
+end
+
+abbr typing 'touchtype::quote'
+
+function sway_config_view
+ less /etc/sway/config
+end
+
+function ssh::force
+ set -l server $argv[1]
+ ssh-keygen -R $server
+ ssh -A $server
+end
+
+if test -f ~/git/geheim/geheim.rb
+ function geheim
+ ruby ~/git/geheim/geheim.rb $argv
+ end
+end
diff --git a/fish/conf.d/worktime.fish b/fish/conf.d/worktime.fish
new file mode 100644
index 0000000..2dfbe6b
--- /dev/null
+++ b/fish/conf.d/worktime.fish
@@ -0,0 +1,122 @@
+set -gx WORKTIME_DIR ~/git/worktime
+
+if test (uname) = Darwin -a ! -f ~/.wtloggedin
+ echo "Warn: Not logged in, run wtlogin"
+end
+
+function worktime
+ ruby $WORKTIME_DIR/worktime.rb $argv
+end
+
+function worktime::sync
+ cd $WORKTIME_DIR
+ git commit -a -m sync
+ git pull
+ git push
+ cd -
+end
+
+function worktime::wisdom_reminder
+ if test -f $WORKTIME_DIR/work-wisdoms.md
+ sed -n '/^\* / { s/\* //; p; }' $WORKTIME_DIR/work-wisdoms.md | sort -R | head -n 1
+ end
+end
+
+function worktime::report
+ if test -f ~/.wtloggedin
+ if test -f ~/.wtmaster
+ worktime --report | tee $WORKTIME_DIR/report.txt
+ else
+ worktime --report
+ end
+ worktime::wisdom_reminder
+ end
+end
+
+function worktime::add
+ set -l seconds $argv[1]
+ set -l what $argv[2]
+ set -l descr $argv[3]
+ set -l epoch (date +%s)
+
+ if test -z "$what"
+ set what work
+ end
+
+ if test -z "$descr"
+ worktime --add $seconds --epoch $epoch --what $what
+ else
+ worktime --add $seconds --epoch $epoch --what $what --descr "$descr"
+ end
+
+ worktime::report
+end
+
+function worktime::log
+ set -l seconds $argv[1]
+ set -l what $argv[2]
+ set -l epoch (date +%s)
+
+ if test -z "$what"
+ set what work
+ end
+
+ worktime --log --epoch $epoch --what $what
+ worktime::report
+end
+
+function worktime::login
+ set -l what $argv[1]
+ if test -z "$what"
+ set what work
+ end
+ touch ~/.wtloggedin
+ worktime --login --what $what
+ worktime::wisdom_reminder
+end
+
+function worktime::logout
+ set -l what $argv[1]
+
+ if test -z "$what"
+ set what work
+ end
+
+ if test -f ~/.wtloggedin
+ rm ~/.wtloggedin
+ end
+
+ worktime --logout --what $what
+ worktime::report
+end
+
+function worktime::status
+ worktime::report
+
+ if test -f ~/.wtloggedin
+ echo "You are logged in"
+ set -l num_worklog (ls $WORKTIME_DIR | grep wl- | wc -l)
+ if test $num_worklog -gt 0
+ echo "$num_worklog entries in the worklog in $WORKTIME_DIR/wl-*"
+ end
+ else
+ echo "You are not logged in"
+ end
+end
+
+abbr -a cdworktime "cd $WORKTIME_DIR"
+abbr -a wt worktime
+abbr -a wtedit 'worktime --edit'
+abbr -a wtreport 'worktime --report'
+abbr -a wtadd 'worktime::add'
+abbr -a wtlog 'worktime::log'
+abbr -a wtlogin 'worktime::login'
+abbr -a wtlogout 'worktime::logout'
+abbr -a wtstatus 'worktime::status'
+abbr -a wtsync 'worktime::sync'
+abbr -a wtf 'worktime --report'
+abbr -a random_exercise "sort -R $WORKTIME_DIR/exercises.md | head -n 1"
+abbr -a random_exercises "sort -R $WORKTIME_DIR/exercises.md | head -n 10"
+abbr -a wl 'task add +work'
+abbr -a ql 'task add +personal'
+abbr -a pl 'task add +personal'
diff --git a/fish/conf.d/zoxide.fish b/fish/conf.d/zoxide.fish
new file mode 100644
index 0000000..4005ebb
--- /dev/null
+++ b/fish/conf.d/zoxide.fish
@@ -0,0 +1,5 @@
+if type -q zoxide
+ zoxide init fish | source
+else
+ echo "zoxide not installed?"
+end
diff --git a/fish/conf.d/zsh.fish b/fish/conf.d/zsh.fish
new file mode 100644
index 0000000..4cbc597
--- /dev/null
+++ b/fish/conf.d/zsh.fish
@@ -0,0 +1,6 @@
+# To run a ZSH function in fish, you can use the following function.
+function Z
+ touch ~/.nofish
+ zsh -i -c "$argv"
+ rm ~/.nofish
+end