From f408ae894e4e10bbf4358c7c07bb9618ef1353e4 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 7 Feb 2026 23:46:42 +0200 Subject: rename --- README.md | 5 + Rexfile | 291 ++++++++++++++++++ bash/bash_profile | 3 + bash/bashrc | 15 + claude/CLAUDE.md | 2 + cursor/commands/commit-and-push-to-git.md | 3 + cursor/commands/increment-version-and-push.md | 3 + dotfiles/README.md | 5 - dotfiles/Rexfile | 291 ------------------ dotfiles/bash/bash_profile | 3 - dotfiles/bash/bashrc | 15 - dotfiles/claude/CLAUDE.md | 2 - dotfiles/cursor/commands/commit-and-push-to-git.md | 3 - .../cursor/commands/increment-version-and-push.md | 3 - dotfiles/fish/conf.d/.gitignore | 1 - dotfiles/fish/conf.d/ai.fish | 30 -- dotfiles/fish/conf.d/alternatives.fish | 20 -- dotfiles/fish/conf.d/config.fish | 31 -- dotfiles/fish/conf.d/dotfiles.fish | 48 --- dotfiles/fish/conf.d/editor.fish | 44 --- dotfiles/fish/conf.d/fuzzy.fish | 5 - dotfiles/fish/conf.d/games.fish | 15 - dotfiles/fish/conf.d/gos.fish | 6 - dotfiles/fish/conf.d/java.fish | 6 - dotfiles/fish/conf.d/k8s.fish | 76 ----- dotfiles/fish/conf.d/quickedit.fish | 118 -------- dotfiles/fish/conf.d/supersync.fish | 125 -------- dotfiles/fish/conf.d/taskwarrior.fish | 143 --------- dotfiles/fish/conf.d/timr.fish | 26 -- dotfiles/fish/conf.d/tmputils.fish | 63 ---- dotfiles/fish/conf.d/tmux.fish | 94 ------ dotfiles/fish/conf.d/update.fish | 75 ----- dotfiles/fish/conf.d/utils.fish | 155 ---------- dotfiles/fish/conf.d/worktime.fish | 122 -------- dotfiles/fish/conf.d/zoxide.fish | 5 - dotfiles/fish/conf.d/zsh.fish | 6 - dotfiles/ghostty/config | 17 -- dotfiles/gitsyncer/config.json | 33 --- dotfiles/helix/config.toml | 88 ------ dotfiles/helix/languages.toml | 206 ------------- dotfiles/nvim/init.lua | 70 ----- dotfiles/pipewire/pipewire.conf | 257 ---------------- dotfiles/scripts/README.md | 3 - dotfiles/scripts/ai | 7 - dotfiles/scripts/brokenlinkfinder | 73 ----- dotfiles/scripts/gvim | 7 - dotfiles/scripts/hx.aichat-prompt | 9 - dotfiles/scripts/hx.chatgpt-prompt | 3 - dotfiles/scripts/hx.goformatter | 3 - dotfiles/scripts/hx.hexai-prompt | 9 - dotfiles/scripts/hx.nvim-copilot-prompt | 32 -- dotfiles/scripts/hx.prompt | 14 - dotfiles/scripts/randomnote.rb | 30 -- dotfiles/scripts/taskwarriorfeeder.rb | 220 -------------- dotfiles/scripts/tmux-edit-send | 246 ---------------- dotfiles/scripts/wol-f3s | 86 ------ dotfiles/signature | 2 - dotfiles/ssh/config | 26 -- dotfiles/sway/config.d/keyboard.conf | 6 - dotfiles/tmux/tmux.conf | 38 --- dotfiles/tmux/tmux.local.conf | 2 - dotfiles/vale.ini | 6 - dotfiles/waybar/config.jsonc | 194 ------------ dotfiles/waybar/style.css | 326 --------------------- dotfiles/zsh/zshrc | 22 -- fish/conf.d/.gitignore | 1 + fish/conf.d/ai.fish | 30 ++ fish/conf.d/alternatives.fish | 20 ++ fish/conf.d/config.fish | 31 ++ fish/conf.d/dotfiles.fish | 48 +++ fish/conf.d/editor.fish | 44 +++ fish/conf.d/fuzzy.fish | 5 + fish/conf.d/games.fish | 15 + fish/conf.d/gos.fish | 6 + fish/conf.d/java.fish | 6 + fish/conf.d/k8s.fish | 76 +++++ fish/conf.d/quickedit.fish | 118 ++++++++ fish/conf.d/supersync.fish | 125 ++++++++ fish/conf.d/taskwarrior.fish | 143 +++++++++ fish/conf.d/timr.fish | 26 ++ fish/conf.d/tmputils.fish | 63 ++++ fish/conf.d/tmux.fish | 94 ++++++ fish/conf.d/update.fish | 75 +++++ fish/conf.d/utils.fish | 155 ++++++++++ fish/conf.d/worktime.fish | 122 ++++++++ fish/conf.d/zoxide.fish | 5 + fish/conf.d/zsh.fish | 6 + ghostty/config | 17 ++ gitsyncer/config.json | 33 +++ helix/config.toml | 88 ++++++ helix/languages.toml | 206 +++++++++++++ nvim/init.lua | 70 +++++ pipewire/pipewire.conf | 257 ++++++++++++++++ scripts/README.md | 3 + scripts/ai | 7 + scripts/brokenlinkfinder | 73 +++++ scripts/gvim | 7 + scripts/hx.aichat-prompt | 9 + scripts/hx.chatgpt-prompt | 3 + scripts/hx.goformatter | 3 + scripts/hx.hexai-prompt | 9 + scripts/hx.nvim-copilot-prompt | 32 ++ scripts/hx.prompt | 14 + scripts/randomnote.rb | 30 ++ scripts/taskwarriorfeeder.rb | 220 ++++++++++++++ scripts/tmux-edit-send | 246 ++++++++++++++++ scripts/wol-f3s | 86 ++++++ signature | 2 + ssh/config | 26 ++ sway/config.d/keyboard.conf | 6 + tmux/tmux.conf | 38 +++ tmux/tmux.local.conf | 2 + vale.ini | 6 + waybar/config.jsonc | 194 ++++++++++++ waybar/style.css | 326 +++++++++++++++++++++ zsh/zshrc | 22 ++ 116 files changed, 3571 insertions(+), 3571 deletions(-) create mode 100644 README.md create mode 100644 Rexfile create mode 100644 bash/bash_profile create mode 100644 bash/bashrc create mode 100644 claude/CLAUDE.md create mode 100644 cursor/commands/commit-and-push-to-git.md create mode 100644 cursor/commands/increment-version-and-push.md delete mode 100644 dotfiles/README.md delete mode 100644 dotfiles/Rexfile delete mode 100644 dotfiles/bash/bash_profile delete mode 100644 dotfiles/bash/bashrc delete mode 100644 dotfiles/claude/CLAUDE.md delete mode 100644 dotfiles/cursor/commands/commit-and-push-to-git.md delete mode 100644 dotfiles/cursor/commands/increment-version-and-push.md delete mode 100644 dotfiles/fish/conf.d/.gitignore delete mode 100644 dotfiles/fish/conf.d/ai.fish delete mode 100644 dotfiles/fish/conf.d/alternatives.fish delete mode 100644 dotfiles/fish/conf.d/config.fish delete mode 100644 dotfiles/fish/conf.d/dotfiles.fish delete mode 100644 dotfiles/fish/conf.d/editor.fish delete mode 100644 dotfiles/fish/conf.d/fuzzy.fish delete mode 100644 dotfiles/fish/conf.d/games.fish delete mode 100644 dotfiles/fish/conf.d/gos.fish delete mode 100644 dotfiles/fish/conf.d/java.fish delete mode 100644 dotfiles/fish/conf.d/k8s.fish delete mode 100644 dotfiles/fish/conf.d/quickedit.fish delete mode 100644 dotfiles/fish/conf.d/supersync.fish delete mode 100644 dotfiles/fish/conf.d/taskwarrior.fish delete mode 100644 dotfiles/fish/conf.d/timr.fish delete mode 100644 dotfiles/fish/conf.d/tmputils.fish delete mode 100644 dotfiles/fish/conf.d/tmux.fish delete mode 100644 dotfiles/fish/conf.d/update.fish delete mode 100644 dotfiles/fish/conf.d/utils.fish delete mode 100644 dotfiles/fish/conf.d/worktime.fish delete mode 100644 dotfiles/fish/conf.d/zoxide.fish delete mode 100644 dotfiles/fish/conf.d/zsh.fish delete mode 100644 dotfiles/ghostty/config delete mode 100644 dotfiles/gitsyncer/config.json delete mode 100644 dotfiles/helix/config.toml delete mode 100644 dotfiles/helix/languages.toml delete mode 100644 dotfiles/nvim/init.lua delete mode 100644 dotfiles/pipewire/pipewire.conf delete mode 100644 dotfiles/scripts/README.md delete mode 100755 dotfiles/scripts/ai delete mode 100644 dotfiles/scripts/brokenlinkfinder delete mode 100755 dotfiles/scripts/gvim delete mode 100755 dotfiles/scripts/hx.aichat-prompt delete mode 100755 dotfiles/scripts/hx.chatgpt-prompt delete mode 100755 dotfiles/scripts/hx.goformatter delete mode 100755 dotfiles/scripts/hx.hexai-prompt delete mode 100755 dotfiles/scripts/hx.nvim-copilot-prompt delete mode 100755 dotfiles/scripts/hx.prompt delete mode 100644 dotfiles/scripts/randomnote.rb delete mode 100644 dotfiles/scripts/taskwarriorfeeder.rb delete mode 100755 dotfiles/scripts/tmux-edit-send delete mode 100755 dotfiles/scripts/wol-f3s delete mode 100644 dotfiles/signature delete mode 100644 dotfiles/ssh/config delete mode 100644 dotfiles/sway/config.d/keyboard.conf delete mode 100644 dotfiles/tmux/tmux.conf delete mode 100644 dotfiles/tmux/tmux.local.conf delete mode 100644 dotfiles/vale.ini delete mode 100644 dotfiles/waybar/config.jsonc delete mode 100644 dotfiles/waybar/style.css delete mode 100644 dotfiles/zsh/zshrc create mode 100644 fish/conf.d/.gitignore create mode 100644 fish/conf.d/ai.fish create mode 100644 fish/conf.d/alternatives.fish create mode 100644 fish/conf.d/config.fish create mode 100644 fish/conf.d/dotfiles.fish create mode 100644 fish/conf.d/editor.fish create mode 100644 fish/conf.d/fuzzy.fish create mode 100644 fish/conf.d/games.fish create mode 100644 fish/conf.d/gos.fish create mode 100644 fish/conf.d/java.fish create mode 100644 fish/conf.d/k8s.fish create mode 100644 fish/conf.d/quickedit.fish create mode 100644 fish/conf.d/supersync.fish create mode 100644 fish/conf.d/taskwarrior.fish create mode 100644 fish/conf.d/timr.fish create mode 100644 fish/conf.d/tmputils.fish create mode 100644 fish/conf.d/tmux.fish create mode 100644 fish/conf.d/update.fish create mode 100644 fish/conf.d/utils.fish create mode 100644 fish/conf.d/worktime.fish create mode 100644 fish/conf.d/zoxide.fish create mode 100644 fish/conf.d/zsh.fish create mode 100644 ghostty/config create mode 100644 gitsyncer/config.json create mode 100644 helix/config.toml create mode 100644 helix/languages.toml create mode 100644 nvim/init.lua create mode 100644 pipewire/pipewire.conf create mode 100644 scripts/README.md create mode 100755 scripts/ai create mode 100644 scripts/brokenlinkfinder create mode 100755 scripts/gvim create mode 100755 scripts/hx.aichat-prompt create mode 100755 scripts/hx.chatgpt-prompt create mode 100755 scripts/hx.goformatter create mode 100755 scripts/hx.hexai-prompt create mode 100755 scripts/hx.nvim-copilot-prompt create mode 100755 scripts/hx.prompt create mode 100644 scripts/randomnote.rb create mode 100644 scripts/taskwarriorfeeder.rb create mode 100755 scripts/tmux-edit-send create mode 100755 scripts/wol-f3s create mode 100644 signature create mode 100644 ssh/config create mode 100644 sway/config.d/keyboard.conf create mode 100644 tmux/tmux.conf create mode 100644 tmux/tmux.local.conf create mode 100644 vale.ini create mode 100644 waybar/config.jsonc create mode 100644 waybar/style.css create mode 100644 zsh/zshrc diff --git a/README.md b/README.md new file mode 100644 index 0000000..6fdd2c2 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# dotfiles + +These are all my dotfiles. I can install them locally on my laptop and/or workstation as well as remotely on any server. + +For local installation, also have a read through https://blog.ferki.it/2023/08/11/local-management-with-rex/ diff --git a/Rexfile b/Rexfile new file mode 100644 index 0000000..4c1f5b0 --- /dev/null +++ b/Rexfile @@ -0,0 +1,291 @@ +use Rex -feature => [ '1.14', 'exec_autodie' ]; +use Rex::Logger; + +our $HOME = $ENV{HOME}; + +# In a public Git rapository. +our $DOT = "$HOME/git/conf/dotfiles"; + +# In a private Git repository. +our $DOT_PRIVATE = "$HOME/git/conf_private/dotfiles"; + +sub ensure_dir { + my ( $src_glob, $dst_dir, $file_mode ) = @_; + Rex::Logger::info("Ensure dir glob $src_glob"); + + file $dst_dir, + ensure => 'directory', + mode => '0700'; + + file "$dst_dir/" . basename($_), + ensure => 'present', + source => $_, + mode => $file_mode // '0640' + for glob $src_glob; +} + +sub ensure_file { + my ( $src_file, $dst_file, $file_mode ) = @_; + + file $dst_file, + ensure => 'present', + source => $src_file, + mode => $file_mode // '0640'; +} + +sub ensure { + my ( $src, $dst, $mode ) = @_; + ( $dst =~ /\/$/ ? \&ensure_dir : \&ensure_file )->( $src, $dst, $mode ); +} + +desc 'Install packages on Termux'; +task 'pkg_termux', sub { + my @pkgs = qw/ + ack-grep + ctags + fzf + golang + htop + make + nodejs + ripgrep + rsync + ruby + starship + tig + /; + + for my $pkg (@pkgs) { + Rex::Logger::info("Installing package $pkg"); + pkg $pkg, ensure => 'installed'; + } +}; + +desc 'Install packages on FreeBSD'; +task 'pkg_freebsd', sub { + my @pkgs = qw/ + zoxide + dust + lazygit + taskwarrior + bat + ctags + fzf + gmake + go + gron + htop + lynx + node + p5-ack + ripgrep + tig + doas + tmux + /; + + for my $pkg (@pkgs) { + Rex::Logger::info("Installing package $pkg"); + pkg $pkg, ensure => 'installed'; + } +}; + +desc 'Install packages on Fedora Linux'; +task 'pkg_fedora', sub { + my @pkgs = qw/ + opendoas + fd-find + nodejs-bash-language-server + fortune-mod + syncthing + ncdu + ack + fish + bat + ctags + fzf + golang + golang-x-tools-gopls + gpaste + gron + htop + java-latest-openjdk-devel + lynx + make + nodejs + perl-File-Slurp + procs + rakudo + Rex + ripgrep + ruby + strace + task2 + tig + tmux + dialect + chromium + strawberry + gnumeric + sway-config-fedora + sway + waybar + zathura + /; + + for my $pkg (@pkgs) { + Rex::Logger::info("Installing package $pkg"); + pkg $pkg, ensure => 'installed'; + } +}; + +desc 'Install ~/.config/helix'; +task 'home_helix', sub { ensure "$DOT/helix/*" => "$HOME/.config/helix/" }; + +desc 'Install ~/.config/ghostty'; +task 'home_ghostty', sub { ensure "$DOT/ghostty/*" => "$HOME/.config/ghostty/" }; + +desc 'Install ~/.cursor'; +task 'home_cursor', sub { + file "$HOME/.cursor" => ensure => 'directory', mode => '0750'; + ensure "$DOT/cursor/commands/*" => "$HOME/.cursor/commands/", '0750'; +}; + +desc 'Install ~/scripts'; +task 'home_scripts', sub { ensure "$DOT/scripts/*" => "$HOME/scripts/", '0750' }; + +desc 'Install ~/.ssh files'; +task 'home_ssh', sub { ensure "$DOT/ssh/config" => "$HOME/.ssh/config", '0600' }; + +desc 'Install BASH configuration'; +task 'home_bash', sub { + ensure "$DOT/bash/bash_profile" => "$HOME/.bash_profile"; + ensure "$DOT/bash/bashrc" => "$HOME/.bashrc"; +}; + +desc 'Install ZSH configuration'; +task 'home_zsh', sub { + if ( $^O eq 'darwin' ) { + ensure "$DOT/zsh/zshrc" => "$HOME/.zshrc"; + } + else { + Rex::Logger::info( 'Skipping ZSH configuration (not on macOS)', 'warn' ); + } +}; + +desc 'Install fish configuration'; +task 'home_fish', sub { + + # ensure "$DOT/fish/conf.d/*" => "$HOME/.config/fish/conf.d/"; + my $dest_dir = "$HOME/.config/fish/conf.d"; + if ( !-l $dest_dir ) { + if ( -d $dest_dir ) { + rename $dest_dir, "$dest_dir.old" or die "Could not rename $dest_dir: $!"; + } + symlink "$DOT/fish/conf.d" => $dest_dir or die "Could not create symlink: $!"; + } +}; + +desc 'Install gitsyncer configuration'; +task 'home_gitsyncer', sub { + my $dest_dir = "$HOME/.config/gitsyncer"; + symlink "$DOT/gitsyncer/" => $dest_dir or die "Could not create symlink: $!"; +}; + +sub isFileSymlink() { + my $file = shift; + return -l $file && -e $file; +} + +desc 'Vale and proselint'; +task 'home_vale', sub { + ensure "$DOT/vale.ini" => "$HOME/.vale.ini"; + say 'Now you can run "vale sync"'; +}; + +desc 'Install tmux configuration'; +task 'home_tmux', sub { + ensure "$DOT/tmux/*" => "$HOME/.config/tmux/"; +}; + +desc 'Install Sway configuration'; +task 'home_sway', sub { + ensure "$DOT/sway/config.d/*" => "$HOME/.config/sway/config.d/"; + ensure "$DOT/waybar/*" => "$HOME/.config/waybar/"; +}; + +desc 'Install my signature'; +task 'home_signature', sub { + ensure "$DOT/signature" => "$HOME/.signature"; +}; + +desc 'Install my calendar files'; +task 'home_calendar', sub { + unless ( -d $DOT_PRIVATE ) { + Rex::Logger::info( "$DOT_PRIVATE not there, skipping task", 'warn' ); + } + else { + ensure "$DOT_PRIVATE/calendar/*" => "$HOME/.calendar/"; + } +}; + +desc 'Install my Pipewire tuned for High-Res config'; +task 'home_pipewire', sub { + file "$HOME/.config/pipewire" => ensure => 'directory', + mode => '0750'; + ensure + "$DOT/pipewire/pipewire.conf" => "$HOME/.config/pipewire/pipewire.conf", + '0600'; +}; + +desc 'Manage ~/QuickEdit directory and symlinks'; +task 'home_quickedit', sub { + if ( $^O eq 'linux' || $^O eq 'freebsd' ) { + Rex::Logger::info('Setting up ~/QuickEdit'); + + file "$HOME/QuickEdit", + ensure => 'directory', + mode => '0700'; + + my %symlinks = ( + 'data' => "$HOME/data/", + 'Documents' => "$HOME/Documents//", + 'dotfiles' => "$HOME/git/conf/dotfiles/", + 'foo.zone-gemtext' => "$HOME/git/foo.zone-content/gemtext//", + 'Notes' => "$HOME/Notes/", + 'public-snippets' => "$HOME/git/conf/snippets//", + 'worktime' => "$HOME/git/worktime/", + ); + + for my $name ( keys %symlinks ) { + my $link_path = "$HOME/QuickEdit/$name"; + my $target = $symlinks{$name}; + + # Remove existing symlink if it points to a different target + if ( -l $link_path ) { + my $current_target = readlink($link_path); + if ( $current_target ne $target ) { + unlink $link_path or die "Could not remove $link_path: $!"; + symlink $target => $link_path or die "Could not create symlink $link_path: $!"; + } + } + elsif ( -e $link_path ) { + Rex::Logger::info( "$link_path exists but is not a symlink, skipping", 'warn' ); + } + else { + symlink $target => $link_path or die "Could not create symlink $link_path: $!"; + } + } + } + elsif ( $^O eq 'darwin' ) { + Rex::Logger::info('QuickEdit placeholder for macOS (not yet implemented)'); + + # TODO: Implement QuickEdit management for macOS + } +}; + +desc 'Install all my ~ files'; +task 'home', sub { + require Rex::TaskList; + run_task $_ for Rex::TaskList->create()->get_all_tasks('^home_'); +}; diff --git a/bash/bash_profile b/bash/bash_profile new file mode 100644 index 0000000..004a7b3 --- /dev/null +++ b/bash/bash_profile @@ -0,0 +1,3 @@ +if [ -f $HOME/.bashrc ]; then + source $HOME/.bashrc +fi diff --git a/bash/bashrc b/bash/bashrc new file mode 100644 index 0000000..ec2b10c --- /dev/null +++ b/bash/bashrc @@ -0,0 +1,15 @@ +# If shell is interactive +if [[ ! -z "$PS1" && ! -f $HOME/.nofish ]]; then + # Use fish if it's installed + if [ -e /opt/local/bin/fish ]; then + exec /opt/local/bin/fish + elif [ -e /bin/fish ]; then + exec /bin/fish + elif [ -e /usr/bin/fish ]; then + exec /usr/bin/fish + elif [ -e /data/data/com.termux/files/usr/bin/fish ]; then + exec /data/data/com.termux/files/usr/bin/fish + fi + + echo 'I might want to install fish on this host' +fi diff --git a/claude/CLAUDE.md b/claude/CLAUDE.md new file mode 100644 index 0000000..ffda0b7 --- /dev/null +++ b/claude/CLAUDE.md @@ -0,0 +1,2 @@ +- Whenever updating code, also update the comments in the code to reflect the reality and the reasoning. +- When a function reaches 50 lines of code or more, try to refactor it into several functions of about 30 lines each. In case of a go project, when main.go becomes too large, move code into the ./internal package. diff --git a/cursor/commands/commit-and-push-to-git.md b/cursor/commands/commit-and-push-to-git.md new file mode 100644 index 0000000..42132bd --- /dev/null +++ b/cursor/commands/commit-and-push-to-git.md @@ -0,0 +1,3 @@ +# Commit and push to git + +Commit and push to git all changes you made. diff --git a/cursor/commands/increment-version-and-push.md b/cursor/commands/increment-version-and-push.md new file mode 100644 index 0000000..015038b --- /dev/null +++ b/cursor/commands/increment-version-and-push.md @@ -0,0 +1,3 @@ +# Increment version and push + +Increment the version of the project, tag it in git, commit, and push. For Go-based projects, look for the internal/version.go file. For bug fixes, increment only the minor version. We are using semantic versioning, e.g., x.y.z, where z is the minor version. For new features, increment y. Never increment x (the major version) unless specified. diff --git a/dotfiles/README.md b/dotfiles/README.md deleted file mode 100644 index 6fdd2c2..0000000 --- a/dotfiles/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# dotfiles - -These are all my dotfiles. I can install them locally on my laptop and/or workstation as well as remotely on any server. - -For local installation, also have a read through https://blog.ferki.it/2023/08/11/local-management-with-rex/ diff --git a/dotfiles/Rexfile b/dotfiles/Rexfile deleted file mode 100644 index 4c1f5b0..0000000 --- a/dotfiles/Rexfile +++ /dev/null @@ -1,291 +0,0 @@ -use Rex -feature => [ '1.14', 'exec_autodie' ]; -use Rex::Logger; - -our $HOME = $ENV{HOME}; - -# In a public Git rapository. -our $DOT = "$HOME/git/conf/dotfiles"; - -# In a private Git repository. -our $DOT_PRIVATE = "$HOME/git/conf_private/dotfiles"; - -sub ensure_dir { - my ( $src_glob, $dst_dir, $file_mode ) = @_; - Rex::Logger::info("Ensure dir glob $src_glob"); - - file $dst_dir, - ensure => 'directory', - mode => '0700'; - - file "$dst_dir/" . basename($_), - ensure => 'present', - source => $_, - mode => $file_mode // '0640' - for glob $src_glob; -} - -sub ensure_file { - my ( $src_file, $dst_file, $file_mode ) = @_; - - file $dst_file, - ensure => 'present', - source => $src_file, - mode => $file_mode // '0640'; -} - -sub ensure { - my ( $src, $dst, $mode ) = @_; - ( $dst =~ /\/$/ ? \&ensure_dir : \&ensure_file )->( $src, $dst, $mode ); -} - -desc 'Install packages on Termux'; -task 'pkg_termux', sub { - my @pkgs = qw/ - ack-grep - ctags - fzf - golang - htop - make - nodejs - ripgrep - rsync - ruby - starship - tig - /; - - for my $pkg (@pkgs) { - Rex::Logger::info("Installing package $pkg"); - pkg $pkg, ensure => 'installed'; - } -}; - -desc 'Install packages on FreeBSD'; -task 'pkg_freebsd', sub { - my @pkgs = qw/ - zoxide - dust - lazygit - taskwarrior - bat - ctags - fzf - gmake - go - gron - htop - lynx - node - p5-ack - ripgrep - tig - doas - tmux - /; - - for my $pkg (@pkgs) { - Rex::Logger::info("Installing package $pkg"); - pkg $pkg, ensure => 'installed'; - } -}; - -desc 'Install packages on Fedora Linux'; -task 'pkg_fedora', sub { - my @pkgs = qw/ - opendoas - fd-find - nodejs-bash-language-server - fortune-mod - syncthing - ncdu - ack - fish - bat - ctags - fzf - golang - golang-x-tools-gopls - gpaste - gron - htop - java-latest-openjdk-devel - lynx - make - nodejs - perl-File-Slurp - procs - rakudo - Rex - ripgrep - ruby - strace - task2 - tig - tmux - dialect - chromium - strawberry - gnumeric - sway-config-fedora - sway - waybar - zathura - /; - - for my $pkg (@pkgs) { - Rex::Logger::info("Installing package $pkg"); - pkg $pkg, ensure => 'installed'; - } -}; - -desc 'Install ~/.config/helix'; -task 'home_helix', sub { ensure "$DOT/helix/*" => "$HOME/.config/helix/" }; - -desc 'Install ~/.config/ghostty'; -task 'home_ghostty', sub { ensure "$DOT/ghostty/*" => "$HOME/.config/ghostty/" }; - -desc 'Install ~/.cursor'; -task 'home_cursor', sub { - file "$HOME/.cursor" => ensure => 'directory', mode => '0750'; - ensure "$DOT/cursor/commands/*" => "$HOME/.cursor/commands/", '0750'; -}; - -desc 'Install ~/scripts'; -task 'home_scripts', sub { ensure "$DOT/scripts/*" => "$HOME/scripts/", '0750' }; - -desc 'Install ~/.ssh files'; -task 'home_ssh', sub { ensure "$DOT/ssh/config" => "$HOME/.ssh/config", '0600' }; - -desc 'Install BASH configuration'; -task 'home_bash', sub { - ensure "$DOT/bash/bash_profile" => "$HOME/.bash_profile"; - ensure "$DOT/bash/bashrc" => "$HOME/.bashrc"; -}; - -desc 'Install ZSH configuration'; -task 'home_zsh', sub { - if ( $^O eq 'darwin' ) { - ensure "$DOT/zsh/zshrc" => "$HOME/.zshrc"; - } - else { - Rex::Logger::info( 'Skipping ZSH configuration (not on macOS)', 'warn' ); - } -}; - -desc 'Install fish configuration'; -task 'home_fish', sub { - - # ensure "$DOT/fish/conf.d/*" => "$HOME/.config/fish/conf.d/"; - my $dest_dir = "$HOME/.config/fish/conf.d"; - if ( !-l $dest_dir ) { - if ( -d $dest_dir ) { - rename $dest_dir, "$dest_dir.old" or die "Could not rename $dest_dir: $!"; - } - symlink "$DOT/fish/conf.d" => $dest_dir or die "Could not create symlink: $!"; - } -}; - -desc 'Install gitsyncer configuration'; -task 'home_gitsyncer', sub { - my $dest_dir = "$HOME/.config/gitsyncer"; - symlink "$DOT/gitsyncer/" => $dest_dir or die "Could not create symlink: $!"; -}; - -sub isFileSymlink() { - my $file = shift; - return -l $file && -e $file; -} - -desc 'Vale and proselint'; -task 'home_vale', sub { - ensure "$DOT/vale.ini" => "$HOME/.vale.ini"; - say 'Now you can run "vale sync"'; -}; - -desc 'Install tmux configuration'; -task 'home_tmux', sub { - ensure "$DOT/tmux/*" => "$HOME/.config/tmux/"; -}; - -desc 'Install Sway configuration'; -task 'home_sway', sub { - ensure "$DOT/sway/config.d/*" => "$HOME/.config/sway/config.d/"; - ensure "$DOT/waybar/*" => "$HOME/.config/waybar/"; -}; - -desc 'Install my signature'; -task 'home_signature', sub { - ensure "$DOT/signature" => "$HOME/.signature"; -}; - -desc 'Install my calendar files'; -task 'home_calendar', sub { - unless ( -d $DOT_PRIVATE ) { - Rex::Logger::info( "$DOT_PRIVATE not there, skipping task", 'warn' ); - } - else { - ensure "$DOT_PRIVATE/calendar/*" => "$HOME/.calendar/"; - } -}; - -desc 'Install my Pipewire tuned for High-Res config'; -task 'home_pipewire', sub { - file "$HOME/.config/pipewire" => ensure => 'directory', - mode => '0750'; - ensure - "$DOT/pipewire/pipewire.conf" => "$HOME/.config/pipewire/pipewire.conf", - '0600'; -}; - -desc 'Manage ~/QuickEdit directory and symlinks'; -task 'home_quickedit', sub { - if ( $^O eq 'linux' || $^O eq 'freebsd' ) { - Rex::Logger::info('Setting up ~/QuickEdit'); - - file "$HOME/QuickEdit", - ensure => 'directory', - mode => '0700'; - - my %symlinks = ( - 'data' => "$HOME/data/", - 'Documents' => "$HOME/Documents//", - 'dotfiles' => "$HOME/git/conf/dotfiles/", - 'foo.zone-gemtext' => "$HOME/git/foo.zone-content/gemtext//", - 'Notes' => "$HOME/Notes/", - 'public-snippets' => "$HOME/git/conf/snippets//", - 'worktime' => "$HOME/git/worktime/", - ); - - for my $name ( keys %symlinks ) { - my $link_path = "$HOME/QuickEdit/$name"; - my $target = $symlinks{$name}; - - # Remove existing symlink if it points to a different target - if ( -l $link_path ) { - my $current_target = readlink($link_path); - if ( $current_target ne $target ) { - unlink $link_path or die "Could not remove $link_path: $!"; - symlink $target => $link_path or die "Could not create symlink $link_path: $!"; - } - } - elsif ( -e $link_path ) { - Rex::Logger::info( "$link_path exists but is not a symlink, skipping", 'warn' ); - } - else { - symlink $target => $link_path or die "Could not create symlink $link_path: $!"; - } - } - } - elsif ( $^O eq 'darwin' ) { - Rex::Logger::info('QuickEdit placeholder for macOS (not yet implemented)'); - - # TODO: Implement QuickEdit management for macOS - } -}; - -desc 'Install all my ~ files'; -task 'home', sub { - require Rex::TaskList; - run_task $_ for Rex::TaskList->create()->get_all_tasks('^home_'); -}; diff --git a/dotfiles/bash/bash_profile b/dotfiles/bash/bash_profile deleted file mode 100644 index 004a7b3..0000000 --- a/dotfiles/bash/bash_profile +++ /dev/null @@ -1,3 +0,0 @@ -if [ -f $HOME/.bashrc ]; then - source $HOME/.bashrc -fi diff --git a/dotfiles/bash/bashrc b/dotfiles/bash/bashrc deleted file mode 100644 index ec2b10c..0000000 --- a/dotfiles/bash/bashrc +++ /dev/null @@ -1,15 +0,0 @@ -# If shell is interactive -if [[ ! -z "$PS1" && ! -f $HOME/.nofish ]]; then - # Use fish if it's installed - if [ -e /opt/local/bin/fish ]; then - exec /opt/local/bin/fish - elif [ -e /bin/fish ]; then - exec /bin/fish - elif [ -e /usr/bin/fish ]; then - exec /usr/bin/fish - elif [ -e /data/data/com.termux/files/usr/bin/fish ]; then - exec /data/data/com.termux/files/usr/bin/fish - fi - - echo 'I might want to install fish on this host' -fi diff --git a/dotfiles/claude/CLAUDE.md b/dotfiles/claude/CLAUDE.md deleted file mode 100644 index ffda0b7..0000000 --- a/dotfiles/claude/CLAUDE.md +++ /dev/null @@ -1,2 +0,0 @@ -- Whenever updating code, also update the comments in the code to reflect the reality and the reasoning. -- When a function reaches 50 lines of code or more, try to refactor it into several functions of about 30 lines each. In case of a go project, when main.go becomes too large, move code into the ./internal package. diff --git a/dotfiles/cursor/commands/commit-and-push-to-git.md b/dotfiles/cursor/commands/commit-and-push-to-git.md deleted file mode 100644 index 42132bd..0000000 --- a/dotfiles/cursor/commands/commit-and-push-to-git.md +++ /dev/null @@ -1,3 +0,0 @@ -# Commit and push to git - -Commit and push to git all changes you made. diff --git a/dotfiles/cursor/commands/increment-version-and-push.md b/dotfiles/cursor/commands/increment-version-and-push.md deleted file mode 100644 index 015038b..0000000 --- a/dotfiles/cursor/commands/increment-version-and-push.md +++ /dev/null @@ -1,3 +0,0 @@ -# Increment version and push - -Increment the version of the project, tag it in git, commit, and push. For Go-based projects, look for the internal/version.go file. For bug fixes, increment only the minor version. We are using semantic versioning, e.g., x.y.z, where z is the minor version. For new features, increment y. Never increment x (the major version) unless specified. diff --git a/dotfiles/fish/conf.d/.gitignore b/dotfiles/fish/conf.d/.gitignore deleted file mode 100644 index 70a0a68..0000000 --- a/dotfiles/fish/conf.d/.gitignore +++ /dev/null @@ -1 +0,0 @@ -omf.fish diff --git a/dotfiles/fish/conf.d/ai.fish b/dotfiles/fish/conf.d/ai.fish deleted file mode 100644 index 01993c4..0000000 --- a/dotfiles/fish/conf.d/ai.fish +++ /dev/null @@ -1,30 +0,0 @@ -# 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/dotfiles/fish/conf.d/alternatives.fish b/dotfiles/fish/conf.d/alternatives.fish deleted file mode 100644 index 75c6e05..0000000 --- a/dotfiles/fish/conf.d/alternatives.fish +++ /dev/null @@ -1,20 +0,0 @@ -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/dotfiles/fish/conf.d/config.fish b/dotfiles/fish/conf.d/config.fish deleted file mode 100644 index 670ca86..0000000 --- a/dotfiles/fish/conf.d/config.fish +++ /dev/null @@ -1,31 +0,0 @@ -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/dotfiles/fish/conf.d/dotfiles.fish b/dotfiles/fish/conf.d/dotfiles.fish deleted file mode 100644 index cf944a1..0000000 --- a/dotfiles/fish/conf.d/dotfiles.fish +++ /dev/null @@ -1,48 +0,0 @@ -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/dotfiles/fish/conf.d/editor.fish b/dotfiles/fish/conf.d/editor.fish deleted file mode 100644 index bda4644..0000000 --- a/dotfiles/fish/conf.d/editor.fish +++ /dev/null @@ -1,44 +0,0 @@ -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/dotfiles/fish/conf.d/fuzzy.fish b/dotfiles/fish/conf.d/fuzzy.fish deleted file mode 100644 index 7683a0e..0000000 --- a/dotfiles/fish/conf.d/fuzzy.fish +++ /dev/null @@ -1,5 +0,0 @@ -function __tv_git - tv git-repos -end - -bind \cg __tv_git diff --git a/dotfiles/fish/conf.d/games.fish b/dotfiles/fish/conf.d/games.fish deleted file mode 100644 index 291a798..0000000 --- a/dotfiles/fish/conf.d/games.fish +++ /dev/null @@ -1,15 +0,0 @@ -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/dotfiles/fish/conf.d/gos.fish b/dotfiles/fish/conf.d/gos.fish deleted file mode 100644 index a23d7a7..0000000 --- a/dotfiles/fish/conf.d/gos.fish +++ /dev/null @@ -1,6 +0,0 @@ -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/dotfiles/fish/conf.d/java.fish b/dotfiles/fish/conf.d/java.fish deleted file mode 100644 index 5a4968c..0000000 --- a/dotfiles/fish/conf.d/java.fish +++ /dev/null @@ -1,6 +0,0 @@ -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/dotfiles/fish/conf.d/k8s.fish b/dotfiles/fish/conf.d/k8s.fish deleted file mode 100644 index ee1584b..0000000 --- a/dotfiles/fish/conf.d/k8s.fish +++ /dev/null @@ -1,76 +0,0 @@ -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/dotfiles/fish/conf.d/quickedit.fish b/dotfiles/fish/conf.d/quickedit.fish deleted file mode 100644 index f1c0f15..0000000 --- a/dotfiles/fish/conf.d/quickedit.fish +++ /dev/null @@ -1,118 +0,0 @@ -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/dotfiles/fish/conf.d/supersync.fish b/dotfiles/fish/conf.d/supersync.fish deleted file mode 100644 index 320afcd..0000000 --- a/dotfiles/fish/conf.d/supersync.fish +++ /dev/null @@ -1,125 +0,0 @@ -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/dotfiles/fish/conf.d/taskwarrior.fish b/dotfiles/fish/conf.d/taskwarrior.fish deleted file mode 100644 index 17240a3..0000000 --- a/dotfiles/fish/conf.d/taskwarrior.fish +++ /dev/null @@ -1,143 +0,0 @@ -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/dotfiles/fish/conf.d/timr.fish b/dotfiles/fish/conf.d/timr.fish deleted file mode 100644 index 8c92462..0000000 --- a/dotfiles/fish/conf.d/timr.fish +++ /dev/null @@ -1,26 +0,0 @@ -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/dotfiles/fish/conf.d/tmputils.fish b/dotfiles/fish/conf.d/tmputils.fish deleted file mode 100644 index 87d8bde..0000000 --- a/dotfiles/fish/conf.d/tmputils.fish +++ /dev/null @@ -1,63 +0,0 @@ -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/dotfiles/fish/conf.d/tmux.fish b/dotfiles/fish/conf.d/tmux.fish deleted file mode 100644 index e65960e..0000000 --- a/dotfiles/fish/conf.d/tmux.fish +++ /dev/null @@ -1,94 +0,0 @@ -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/dotfiles/fish/conf.d/update.fish b/dotfiles/fish/conf.d/update.fish deleted file mode 100644 index abe9da0..0000000 --- a/dotfiles/fish/conf.d/update.fish +++ /dev/null @@ -1,75 +0,0 @@ -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/dotfiles/fish/conf.d/utils.fish b/dotfiles/fish/conf.d/utils.fish deleted file mode 100644 index 33854a5..0000000 --- a/dotfiles/fish/conf.d/utils.fish +++ /dev/null @@ -1,155 +0,0 @@ -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 | 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/dotfiles/fish/conf.d/worktime.fish b/dotfiles/fish/conf.d/worktime.fish deleted file mode 100644 index 2dfbe6b..0000000 --- a/dotfiles/fish/conf.d/worktime.fish +++ /dev/null @@ -1,122 +0,0 @@ -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/dotfiles/fish/conf.d/zoxide.fish b/dotfiles/fish/conf.d/zoxide.fish deleted file mode 100644 index 4005ebb..0000000 --- a/dotfiles/fish/conf.d/zoxide.fish +++ /dev/null @@ -1,5 +0,0 @@ -if type -q zoxide - zoxide init fish | source -else - echo "zoxide not installed?" -end diff --git a/dotfiles/fish/conf.d/zsh.fish b/dotfiles/fish/conf.d/zsh.fish deleted file mode 100644 index 4cbc597..0000000 --- a/dotfiles/fish/conf.d/zsh.fish +++ /dev/null @@ -1,6 +0,0 @@ -# To run a ZSH function in fish, you can use the following function. -function Z - touch ~/.nofish - zsh -i -c "$argv" - rm ~/.nofish -end diff --git a/dotfiles/ghostty/config b/dotfiles/ghostty/config deleted file mode 100644 index e109583..0000000 --- a/dotfiles/ghostty/config +++ /dev/null @@ -1,17 +0,0 @@ -window-decoration = true -copy-on-select = true -quick-terminal-position = bottom -quick-terminal-screen = mouse -shell-integration = zsh -bold-is-bright = true - -# Toggle window decorations only works on Linux! -keybind = ctrl+shift+d=toggle_window_decorations -keybind = ctrl+shift+f=toggle_fullscreen -keybind = ctrl+shift+g=reload_config -# Toggle quick terminal only supported for MacOS -keybind = global:ctrl+shift+t=toggle_quick_terminal -keybind = ctrl+shift+c=copy_to_clipboard -keybind = ctrl+shift+v=paste_from_clipboard -keybind = ctrl+shift+w=paste_from_selection - diff --git a/dotfiles/gitsyncer/config.json b/dotfiles/gitsyncer/config.json deleted file mode 100644 index a1e8258..0000000 --- a/dotfiles/gitsyncer/config.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "organizations": [ - { - "host": "git@codeberg.org", - "name": "snonux" - }, - { - "host": "git@github.com", - "name": "snonux" - }, - { - "host": "ssh://git@r0:30022/repos", - "backupLocation": true - } - ], - "repositories": [], - "skip_releases": { - "fapi": [ - "0.0.1" - ] - }, - "exclude_from_showcase": [ - "bratwurstmitsenf", - "Adv360-Pro-ZMK", - "katana", - "playground", - "pages", - "nvim" - ], - "exclude_branches": [ - "^codex/" - ] -} \ No newline at end of file diff --git a/dotfiles/helix/config.toml b/dotfiles/helix/config.toml deleted file mode 100644 index cdd64b5..0000000 --- a/dotfiles/helix/config.toml +++ /dev/null @@ -1,88 +0,0 @@ -theme = "adwaita-dark" - -[editor] -bufferline = "always" -rulers = [80, 100, 120, 140] -line-number = "relative" -mouse = true -cursorline = true -cursorcolumn = true -continue-comments = false -completion-timeout = 2000 - -[editor.soft-wrap] -enable = true - -[editor.inline-diagnostics] -# cursor-line = "hint" - -[editor.auto-save] -focus-lost = true -after-delay.timeout = 3000 -after-delay.enable = true - -[editor.statusline] -left = ["version-control", "mode", "spinner", "file-name", "position" ] -center = ["diagnostics"] -right = ["selections", "file-encoding", "file-line-ending", "file-type"] - -[editor.lsp] -display-messages = true -display-inlay-hints = false - -[editor.cursor-shape] -normal = "block" -insert = "underline" -select = "bar" - -[editor.whitespace.render] -space = "none" -tab = "none" -newline = "none" - -[keys.normal] -D = ["ensure_selections_forward", "extend_to_line_end"] -#S conflicts with split_selection, for now comment out -#S = ["ensure_selections_forward", "extend_to_line_start"] -0 = ["select_mode", "extend_to_file_start"] -G = ["ensure_selections_forward", "extend_to_file_end"] -"^" = ["move_prev_word_start", "move_next_word_end", "search_selection", "global_search"] -"ret" = "goto_word" - -C-c = "yank_main_selection_to_clipboard" -C-v = { b = "paste_clipboard_before", a = "paste_clipboard_after", r = ":clipboard-paste-replace" } -A-c = "toggle_comments" # Was originally C-c, so mapped to ALT now - -# Helix related helpers -C-h = { c = ":config-open", r = ":config-reload", C = ":run-shell-command cp -v ~/.config/helix/*.toml ~/git/conf/dotfiles/helix/", l = ":open ~/.config/helix/languages.toml", h = ":open ~/git/worktime/HelixCheat.md", L = ":log-open", d = ":theme default" } - -C-r = [ ":config-reload", ":reload-all" ] - -C-u = [ ":write", ":run-shell-command sh -c 'source ~/.hx.remote.source; scp $LOCAL_PATH $REMOTE_URI && echo Uploaded to $REMOTE_URI || echo Failed uploading to $REMOTE_URI'"] - -# Various helpers -C-s = { e = ":set-option soft-wrap.enable true", d = ":set-option soft-wrap.enable false", s = "save_selection" } - -# Buffer stuff -C-q = ":buffer-close" - -# AI commands are good here. -C-p = { c = ":pipe ai correct this sentence and only print out the corrected text", r = ":pipe ai restructure and reword the input and dont leave information out and only print out the new text", a = ":pipe ai rewrite this in a more casual style", n = ":pipe ai these are book notes of mine. correct the grammar and re-organize the notes. use bullet points for short information and whole paragraphs for longer one. the output must be in Gemini Gemtext format with the star * as the bullet point symbol and not the minus - . dont leave out any content.", p = ":pipe ai" } -# Will replace the above -C-a = ":pipe hexai-tmux-action" - -# Git commands -C-g = { d = ":run-shell-command git diff", p = ":run-shell-command git pull", u = ":run-shell-command git push", t = ":run-shell-command tmux new-window -n hx-git-tig tig", c = ":run-shell-command tmux split-window -v 'git commit -a'" } - -# Build commands -C-l = { m = ":run-shell-command make", d = ":run-shell-command go-task dev", r = ":run-shell-command tmux new-window -n hx-go-task-run 'go-task run'" } - -[keys.normal.space] -B = "file_picker_in_current_buffer_directory" -Q = [ ":cd ~/QuickEdit", "file_picker_in_current_directory" ] - -[keys.select] -"{" = "goto_prev_paragraph" -"}" = "goto_next_paragraph" -n = ["extend_search_next", "merge_selections"] -N = ["extend_search_prev", "merge_selections"] diff --git a/dotfiles/helix/languages.toml b/dotfiles/helix/languages.toml deleted file mode 100644 index 33a3f0d..0000000 --- a/dotfiles/helix/languages.toml +++ /dev/null @@ -1,206 +0,0 @@ -[[language]] -name = "hcl" -scope = "source.hcl" -injection-regex = "(hcl|tf|nomad)" -language-id = "terraform" -file-types = ["hcl", "tf", "nomad"] -comment-token = "#" -block-comment-tokens = { start = "/*", end = "*/" } -indent = { tab-width = 2, unit = " " } -language-servers = [ "terraform-ls", "hexai-lsp" ] -auto-format = true - -[[language]] -name = "go" -auto-format= true -diagnostic-severity = "hint" -formatter = { command = "hx.goformatter" } -language-servers = [ "gopls", "golangci-lint-lsp", "hexai-lsp" ] -[language-server.hexai-lsp] -command = "hexai-lsp" - -[language-server.gopls] -command = "gopls" - -[language-server.gopls.config.hints] -assignVariableTypes = true -compositeLiteralFields = true -constantValues = true -functionTypeParameters = true -parameterNames = true -rangeVariableTypes = true - -# go install github.com/nametake/golangci-lint-langserver@latest │ -[language-server.golangci-lint-lsp] -command = "golangci-lint-langserver" - -[language-server.ltex-ls] -command = "/home/paul/java/ltex-ls/bin/ltex-ls" - -# golangci-lint-langserver depepds/calls golangci-lint -# go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest -[language-server.golangci-lint-lsp.config] -command = ["golangci-lint", "run", "--issues-exit-code=1"] -# command = ["golangci-lint", "run", "--out-format", "json", "--issues-exit-code=1"] - -[[language]] -name = "c" -scope = "source.c" -injection-regex = "c" -file-types = ["c", "h"] -comment-token = "//" -language-servers = [ "clangd", "hexai-lsp" ] -indent = { tab-width = 2, unit = " " } - -[[grammar]] -name = "c" -source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7175a6dd5fc1cee660dce6fe23f6043d75af424a" } - -[language-server.clangd] -command = "clangd" - -[[language]] -name = "perl" -auto-format= true -formatter = { command = "perltidy", args = ["-l=120"] } -scope = "source.perl" -file-types = ["pl", "pm", "t", "psgi", "raku", "rakumod", "rakutest", "rakudoc", "nqp", "p6", "pl6", "pm6", { glob = "Rexfile" }] -shebangs = ["perl"] -comment-token = "#" -language-servers = [ "perlnavigator", "hexai-lsp" ] -indent = { tab-width = 2, unit = " " } - -[[grammar]] -name = "perl" -source = { git = "https://github.com/tree-sitter-perl/tree-sitter-perl", rev = "e99bb5283805db4cb86c964722d709df21b0ac16" } - -[[language]] -name = "pod" -scope = "source.pod" -injection-regex = "pod" -file-types = ["pod"] - -[[grammar]] -name = "pod" -source = { git = "https://github.com/tree-sitter-perl/tree-sitter-pod", rev = "39da859947b94abdee43e431368e1ae975c0a424" } - -[[language]] -name = "ruby" -auto-format = true -scope = "source.ruby" -injection-regex = "ruby" -file-types = [ - "rb", - "rbs", - "rake", - "irb", - "gemspec", - { glob = "Gemfile" }, - { glob = "Rakefile" } -] -shebangs = ["ruby"] -comment-token = "#" -language-servers = [ "ruby-lsp", "solargraph", "rubocop", "hexai-lsp" ] -indent = { tab-width = 2, unit = " " } - -[[grammar]] -name = "ruby" -source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "206c7077164372c596ffa8eaadb9435c28941364" } - -[[language]] -name = "bash" -scope = "source.bash" -injection-regex = "(shell|bash|zsh|sh)" -file-types = [ - "sh", - "bash", - "zsh", - "zshenv", - "zlogin", - "zlogout", - "zprofile", - "zshrc", - "eclass", - "ebuild", - "bazelrc", - "Renviron", - "zsh-theme", - "ksh", - "cshrc", - "tcshrc", - "bashrc_Apple_Terminal", - "zshrc_Apple_Terminal", - { glob = "*zshrc*" }, -] -shebangs = ["sh", "bash", "dash", "zsh"] -comment-token = "#" -language-servers = [ "bash-language-server", "hexai-lsp" ] -indent = { tab-width = 2, unit = " " } - -[[language]] -name = "fish" -# scope = "source.fish" -# injection-regex = "(fish)" -# file-types = [ -# "fish", -# ] -# shebangs = ["fish" ] -# comment-token = "#" -language-servers = [ "fish-lsp", "hexai-lsp" ] -# indent =dth = 4, unit = " " } - -[[grammar]] -name = "bash" -source = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "275effdfc0edce774acf7d481f9ea195c6c403cd" } - -[language-server] -bash-language-server = { command = "bash-language-server", args = ["start"] } -vale-ls = { command = "vale-ls" } -ruby-lsp = { command = "ruby-lsp"} -rubocop = { command = "rubocop", args = ["--lsp"] } - -[[language]] -name = "markdown" -scope = "source.md" -injection-regex = "md|markdown" -file-types = ["md", "markdown", "mkd", "mdwn", "mdown", "markdn", "mdtxt", "mdtext", "workbook", "gmi", "tpl", "txt" ] -roots = [".marksman.toml"] -language-servers = [ "marksman", "markdown-oxide", "vale-ls", "hexai-lsp", "ltex-ls"] -indent = { tab-width = 2, unit = " " } - -[[grammar]] -name = "markdown" -source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown" } - -[[language]] -name = "markdown.inline" -scope = "source.markdown.inline" -injection-regex = "markdown\\.inline" -file-types = [] -grammar = "markdown_inline" - -[[grammar]] -name = "markdown_inline" -source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown-inline" } - -[[language]] -name = "gemini" -scope = "source.gmi" -file-types = ["gmi", "tpl"] - -[[grammar]] -name = "gemini" -source = { git = "https://git.sr.ht/~nbsp/tree-sitter-gemini", rev = "3cc5e4bdf572d5df4277fc2e54d6299bd59a54b3" } - -[[language]] -name = "java" -scope = "source.java" -injection-regex = "java" -file-types = ["java", "jav", "pde"] -roots = ["pom.xml", "build.gradle", "build.gradle.kts"] -language-servers = [ "jdtls", "hexai-lsp" ] -indent = { tab-width = 2, unit = " " } - -[[grammar]] -name = "java" -source = { git = "https://github.com/tree-sitter/tree-sitter-java", rev = "09d650def6cdf7f479f4b78f595e9ef5b58ce31e" } diff --git a/dotfiles/nvim/init.lua b/dotfiles/nvim/init.lua deleted file mode 100644 index c3b8701..0000000 --- a/dotfiles/nvim/init.lua +++ /dev/null @@ -1,70 +0,0 @@ - -require("CopilotChat").setup { - -- See Configuration section for options -} - -local timer = vim.loop.new_timer() -- Initialize the timer - -vim.api.nvim_create_autocmd("BufEnter", { - pattern = "*", - callback = function() - if vim.bo.filetype == "copilot-chat" then - local copilot_chat_buf = vim.api.nvim_get_current_buf() - vim.cmd("wincmd _") -- Maximize height - vim.cmd("wincmd |") -- Maximize width - local file_path = vim.fn.expand("~/.copilot_chat_output.txt") - - -- Start the timer with a 2-second interval - timer:start(1000, 1000, vim.schedule_wrap(function() - if copilot_chat_buf and vim.api.nvim_buf_is_valid(copilot_chat_buf) then - -- Get all lines in the buffer - local lines = vim.api.nvim_buf_get_lines(copilot_chat_buf, 0, -1, false) - - -- Check for the stopping condition - local user_line_count = 0 - for _, line in ipairs(lines) do - if line:find("^## User") then - user_line_count = user_line_count + 1 - if user_line_count >= 2 then - print("Stopping write process: Two '## User' lines detected.") - timer:stop() - -- Write the buffer content to the file - vim.api.nvim_buf_call(copilot_chat_buf, function() - vim.cmd("write! " .. file_path) - end) - vim.cmd("qa!") - return - end - end - end - - -- Write the buffer content to the file - vim.api.nvim_buf_call(copilot_chat_buf, function() - vim.cmd("write! " .. file_path) - end) - end - end)) - end - end, -}) - -vim.api.nvim_create_user_command('CopilotAsk', function(args) - local chat = require("CopilotChat") - local input - if args.args and args.args ~= "" then - input = args.args - else - local input_file = os.getenv("HOME") .. "/.copilot_chat_input.txt" - local file = io.open(input_file, "r") - if file then - input = file:read("*all") - file:close() - else - print("Error: Unable to open input file.") - return - end - end - chat.ask(input) -end, { force = true, range = true, nargs = "?" }) - - diff --git a/dotfiles/pipewire/pipewire.conf b/dotfiles/pipewire/pipewire.conf deleted file mode 100644 index a97c99e..0000000 --- a/dotfiles/pipewire/pipewire.conf +++ /dev/null @@ -1,257 +0,0 @@ -# Daemon config file for PipeWire version "0.3.51" # -# -# Copy and edit this file in /etc/pipewire for system-wide changes -# or in ~/.config/pipewire for local changes. -# -# It is also possible to place a file with an updated section in -# /etc/pipewire/pipewire.conf.d/ for system-wide changes or in -# ~/.config/pipewire/pipewire.conf.d/ for local changes. -# - -context.properties = { - ## Configure properties in the system. - #library.name.system = support/libspa-support - #context.data-loop.library.name.system = support/libspa-support - #support.dbus = true - #link.max-buffers = 64 - link.max-buffers = 16 # version < 3 clients can't handle more - #mem.warn-mlock = false - #mem.allow-mlock = true - #mem.mlock-all = false - #clock.power-of-two-quantum = true - #log.level = 2 - #cpu.zero.denormals = false - - core.daemon = true # listening for socket connections - core.name = pipewire-0 # core name and socket name - - ## Properties for the DSP configuration. - default.clock.rate = 48000 - default.clock.allowed-rates = [ 44100 48000 88200 96000 176400 192000 352800 384000 ] - #default.clock.quantum = 1024 - default.clock.min-quantum = 16 - #default.clock.max-quantum = 2048 - #default.clock.quantum-limit = 8192 - #default.video.width = 640 - #default.video.height = 480 - #default.video.rate.num = 25 - #default.video.rate.denom = 1 - # - #settings.check-quantum = false - #settings.check-rate = false - # - # These overrides are only applied when running in a vm. - vm.overrides = { - default.clock.min-quantum = 1024 - } -} - -context.spa-libs = { - # = - # - # Used to find spa factory names. It maps an spa factory name - # regular expression to a library name that should contain - # that factory. - # - audio.convert.* = audioconvert/libspa-audioconvert - api.alsa.* = alsa/libspa-alsa - api.v4l2.* = v4l2/libspa-v4l2 - api.libcamera.* = libcamera/libspa-libcamera - api.bluez5.* = bluez5/libspa-bluez5 - api.vulkan.* = vulkan/libspa-vulkan - api.jack.* = jack/libspa-jack - support.* = support/libspa-support - #videotestsrc = videotestsrc/libspa-videotestsrc - #audiotestsrc = audiotestsrc/libspa-audiotestsrc -} - -context.modules = [ - #{ name = - # [ args = { = ... } ] - # [ flags = [ [ ifexists ] [ nofail ] ] - #} - # - # Loads a module with the given parameters. - # If ifexists is given, the module is ignored when it is not found. - # If nofail is given, module initialization failures are ignored. - # - - # Uses realtime scheduling to boost the audio thread priorities. This uses - # RTKit if the user doesn't have permission to use regular realtime - # scheduling. - { name = libpipewire-module-rt - args = { - nice.level = -11 - #rt.prio = 88 - #rt.time.soft = -1 - #rt.time.hard = -1 - } - flags = [ ifexists nofail ] - } - - # The native communication protocol. - { name = libpipewire-module-protocol-native } - - # The profile module. Allows application to access profiler - # and performance data. It provides an interface that is used - # by pw-top and pw-profiler. - { name = libpipewire-module-profiler } - - # Allows applications to create metadata objects. It creates - # a factory for Metadata objects. - { name = libpipewire-module-metadata } - - # Creates a factory for making devices that run in the - # context of the PipeWire server. - { name = libpipewire-module-spa-device-factory } - - # Creates a factory for making nodes that run in the - # context of the PipeWire server. - { name = libpipewire-module-spa-node-factory } - - # Allows creating nodes that run in the context of the - # client. Is used by all clients that want to provide - # data to PipeWire. - { name = libpipewire-module-client-node } - - # Allows creating devices that run in the context of the - # client. Is used by the session manager. - { name = libpipewire-module-client-device } - - # The portal module monitors the PID of the portal process - # and tags connections with the same PID as portal - # connections. - { name = libpipewire-module-portal - flags = [ ifexists nofail ] - } - - # The access module can perform access checks and block - # new clients. - { name = libpipewire-module-access - args = { - # access.allowed to list an array of paths of allowed - # apps. - #access.allowed = [ - # /usr/bin/pipewire-media-session - #] - - # An array of rejected paths. - #access.rejected = [ ] - - # An array of paths with restricted access. - #access.restricted = [ ] - - # Anything not in the above lists gets assigned the - # access.force permission. - #access.force = flatpak - } - } - - # Makes a factory for wrapping nodes in an adapter with a - # converter and resampler. - { name = libpipewire-module-adapter } - - # Makes a factory for creating links between ports. - { name = libpipewire-module-link-factory } - - # Provides factories to make session manager objects. - { name = libpipewire-module-session-manager } - - # Use libcanberra to play X11 Bell - #{ name = libpipewire-module-x11-bell - # args = { - # #sink.name = "" - # #sample.name = "bell-window-system" - # #x11.display = null - # #x11.xauthority = null - # } - #} -] - -context.objects = [ - #{ factory = - # [ args = { = ... } ] - # [ flags = [ [ nofail ] ] - #} - # - # Creates an object from a PipeWire factory with the given parameters. - # If nofail is given, errors are ignored (and no object is created). - # - #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } - #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] } - #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } } - #{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } } - #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } } - #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } - - # A default dummy driver. This handles nodes marked with the "node.always-driver" - # property when no other driver is currently active. JACK clients need this. - { factory = spa-node-factory - args = { - factory.name = support.node.driver - node.name = Dummy-Driver - node.group = pipewire.dummy - priority.driver = 20000 - } - } - { factory = spa-node-factory - args = { - factory.name = support.node.driver - node.name = Freewheel-Driver - priority.driver = 19000 - node.group = pipewire.freewheel - node.freewheel = true - } - } - # This creates a new Source node. It will have input ports - # that you can link, to provide audio for this source. - #{ factory = adapter - # args = { - # factory.name = support.null-audio-sink - # node.name = "my-mic" - # node.description = "Microphone" - # media.class = "Audio/Source/Virtual" - # audio.position = "FL,FR" - # } - #} - - # This creates a single PCM source device for the given - # alsa device path hw:0. You can change source to sink - # to make a sink in the same way. - #{ factory = adapter - # args = { - # factory.name = api.alsa.pcm.source - # node.name = "alsa-source" - # node.description = "PCM Source" - # media.class = "Audio/Source" - # api.alsa.path = "hw:0" - # api.alsa.period-size = 1024 - # api.alsa.headroom = 0 - # api.alsa.disable-mmap = false - # api.alsa.disable-batch = false - # audio.format = "S16LE" - # audio.rate = 48000 - # audio.channels = 2 - # audio.position = "FL,FR" - # } - #} -] - -context.exec = [ - #{ path = [ args = "" ] } - # - # Execute the given program with arguments. - # - # You can optionally start the session manager here, - # but it is better to start it as a systemd service. - # Run the session manager with -h for options. - # - #{ path = "/usr/bin/pipewire-media-session" args = "" } - # - # You can optionally start the pulseaudio-server here as well - # but it is better to start it as a systemd service. - # It can be interesting to start another daemon here that listens - # on another address with the -a option (eg. -a tcp:4713). - # - #{ path = "/usr/bin/pipewire" args = "-c pipewire-pulse.conf" } -] diff --git a/dotfiles/scripts/README.md b/dotfiles/scripts/README.md deleted file mode 100644 index ecbc8ec..0000000 --- a/dotfiles/scripts/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Scripts installed to my ~/scripts - -Mostly quick-n-dirty ones! diff --git a/dotfiles/scripts/ai b/dotfiles/scripts/ai deleted file mode 100755 index abcf490..0000000 --- a/dotfiles/scripts/ai +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env zsh - -if [ $(uname) = Darwin ]; then - exec hx.nvim-copilot-prompt "$@" -else - exec hx.hexai-prompt "$@" -fi diff --git a/dotfiles/scripts/brokenlinkfinder b/dotfiles/scripts/brokenlinkfinder deleted file mode 100644 index 7fe1576..0000000 --- a/dotfiles/scripts/brokenlinkfinder +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env ruby - -require 'net/http' -require 'uri' -require 'nokogiri' -require 'set' - -# Method to fetch and parse HTML from a URL -def fetch_html(url) - response = Net::HTTP.get_response(URI(url)) - response.body if response.is_a?(Net::HTTPSuccess) -rescue StandardError => e - puts "Error fetching #{url}: #{e.message}" - nil -end - -# Method to find and check links on a page -def check_links(url, domain) - html = fetch_html(url) - return unless html - - checked = Set.new - broken = Set.new - - document = Nokogiri::HTML(html) - links = document.css('a').map { |link| link['href'] }.compact - - internal_links = links.select do |link| - link.start_with?('/') || link.start_with?('./') || URI(link).host == domain - end - puts "Internal links: #{internal_links}" - - internal_links.uniq.each do |link| - full_url = link.start_with?('/') || link.start_with?('./') ? "#{url}#{link}" : link - full_url.sub!('./', '/') - next if checked.include?(full_url) - - broken << full_url unless check_link(full_url) - checked << full_url - end - - broken -end - -# Method to check if a link is broken -def check_link(url) - uri = URI(url) - response = Net::HTTP.get_response(uri) - - if response.is_a?(Net::HTTPSuccess) - puts "Working link: #{url}" - true - else - puts "Broken link: #{url} (HTTP #{response.code})" - false - end -rescue StandardError => e - puts "Error checking #{url}: #{e.message}" - false -end - -# Main program -if ARGV.length != 1 - puts 'Usage: ruby brokenlinkfinder.rb ' - exit -end - -start_url = ARGV.first -domain = URI(start_url).host - -check_links(start_url, domain).each do |broken| - puts "Broken: #{broken}" -end diff --git a/dotfiles/scripts/gvim b/dotfiles/scripts/gvim deleted file mode 100755 index 5777a7c..0000000 --- a/dotfiles/scripts/gvim +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# Hack so qutebrowser starts an editor (Helix) in a new ghostty terminal. - -declare -r FILE_PATH="$2" -#echo "$@" > /tmp/params.txt - -ghostty -e "hx $FILE_PATH" diff --git a/dotfiles/scripts/hx.aichat-prompt b/dotfiles/scripts/hx.aichat-prompt deleted file mode 100755 index 4cafcf5..0000000 --- a/dotfiles/scripts/hx.aichat-prompt +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env zsh - -declare -xr INSTRUCTIONS='Answer only. If it is code, code only without code-block at the beginning and the end.' - -if [[ $# -eq 0 ]]; then - aichat "$(hx.prompt). $INSTRUCTIONS" -else - aichat "$@. $INSTRUCTIONS" -fi diff --git a/dotfiles/scripts/hx.chatgpt-prompt b/dotfiles/scripts/hx.chatgpt-prompt deleted file mode 100755 index e4b6047..0000000 --- a/dotfiles/scripts/hx.chatgpt-prompt +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env zsh - -chatgpt "$(hx.prompt). Answer only. If it is code, code only without code-block at the beginning and the end." diff --git a/dotfiles/scripts/hx.goformatter b/dotfiles/scripts/hx.goformatter deleted file mode 100755 index 028fbb2..0000000 --- a/dotfiles/scripts/hx.goformatter +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -goimports | gofumpt diff --git a/dotfiles/scripts/hx.hexai-prompt b/dotfiles/scripts/hx.hexai-prompt deleted file mode 100755 index ef413c0..0000000 --- a/dotfiles/scripts/hx.hexai-prompt +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env zsh - -declare -xr INSTRUCTIONS='Answer only. If it is code, code only without code-block at the beginning and the end.' - -if [[ $# -eq 0 ]]; then - hexai "$(hx.prompt). $INSTRUCTIONS" 2>/dev/null -else - hexai "$@. $INSTRUCTIONS" 2>/dev/null -fi diff --git a/dotfiles/scripts/hx.nvim-copilot-prompt b/dotfiles/scripts/hx.nvim-copilot-prompt deleted file mode 100755 index dcb2837..0000000 --- a/dotfiles/scripts/hx.nvim-copilot-prompt +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env zsh - -declare -r STDIN_FILE=~/.copilot_prompt_stdin.txt -declare -r INPUT_FILE=~/.copilot_chat_input.txt -declare -r OUTPUT_FILE=~/.copilot_chat_output.txt -declare INPUT_PROMPT - -if [ -f $OUTPUT_FILE.done ]; then - rm $OUTPUT_FILE.done -fi -cat > $STDIN_FILE &>/dev/null - -if [ $# -eq 0 ]; then - INPUT_PROMPT="$(hx.prompt)" -else - INPUT_PROMPT="$@" -fi - -cat < $INPUT_FILE -$INPUT_PROMPT for the following: - -$(cat $STDIN_FILE) - -If the result is code, print out the code only, don't print the \`\`\`-markers around the code block. -INPUT_FILE - -tmux split-window -v "nvim +':CopilotAsk'; mv $OUTPUT_FILE $OUTPUT_FILE.done" - -while [ ! -f "$OUTPUT_FILE.done" ]; do - sleep 0.2 -done -sed -n '/^## Copilot/,/^## User/ { /^## Copilot/d; /\[file:/d; /^## User/d; p; }' $OUTPUT_FILE.done diff --git a/dotfiles/scripts/hx.prompt b/dotfiles/scripts/hx.prompt deleted file mode 100755 index 8dd14dd..0000000 --- a/dotfiles/scripts/hx.prompt +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env zsh - -declare -r REPLY_FILE=~/.hx-prompt-reply -if [ -f "$REPLY_FILE" ]; then - rm "$REPLY_FILE" -fi - -tmux split-window -v "touch $REPLY_FILE.tmp; hx $REPLY_FILE.tmp; mv $REPLY_FILE.tmp $REPLY_FILE" - -while [ ! -f "$REPLY_FILE" ]; do - sleep 0.2 -done - -cat "$REPLY_FILE" diff --git a/dotfiles/scripts/randomnote.rb b/dotfiles/scripts/randomnote.rb deleted file mode 100644 index b0c1b49..0000000 --- a/dotfiles/scripts/randomnote.rb +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env ruby - -NOTES_DIR = "#{ENV['HOME']}/git/foo.zone-content/gemtext/notes" -BOOK_PATH = "#{ENV['HOME']}/Buecher/Diverse/Search-Inside-Yourself.txt" -MIN_PERCENTAGE = 80 -MIN_LENGTH = 10 - -class String - CLEAN_PATTERN = [ - /\d\d\d-\d\d-\d\d/, /[^A-Za-z0-9!.;,?'" @]/, - /http.?:\/\/\S+/, /\S+\.gmi/, /^\./, /^\d/, - ] - def clean - CLEAN_PATTERN.each {|p| gsub! p, '' } - gsub(/\s+/, ' ').strip - end - def letter_percentage?(threshold) = threshold <= (100 * count("A-Za-z")) / length -end - -begin - srand Random.new_seed - puts File.read((Dir["#{NOTES_DIR}/*.gmi"] + [BOOK_PATH]).shuffle.sample) - .split("\n") - .map(&:clean) - .select{ |l| l.length >= MIN_LENGTH } - .reject{ |l| l.match?(/(Published at|EMail your comments)/) } - .reject{ |l| l.match?(/'|book notes/) } - .select{ |l| l.letter_percentage?(MIN_PERCENTAGE) } - .shuffle.sample -end diff --git a/dotfiles/scripts/taskwarriorfeeder.rb b/dotfiles/scripts/taskwarriorfeeder.rb deleted file mode 100644 index 117ca69..0000000 --- a/dotfiles/scripts/taskwarriorfeeder.rb +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env ruby - -require 'optparse' -require 'digest' -require 'json' -require 'set' - -PERSONAL_TIMESPAN_D = 30 -WORK_TIMESPAN_D = 14 -WORKTIME_DIR = "#{ENV['HOME']}/git/worktime".freeze -GOS_DIR = "#{ENV['HOME']}/.gosdir".freeze -MAX_PENDING_RANDOM_TASKS = 42 - -def maybe? - [true, false].sample -end - -def run_from_personal_device? - `uname`.chomp == 'Linux' -end - -def random_count - MAX_PENDING_RANDOM_TASKS - `task status:pending +random -work count`.to_i -end - -def notes(notes_dirs, prefix, dry) - notes_dirs.each do |notes_dir| - Dir["#{notes_dir}/#{prefix}-*"].each do |notes_file| - match = File.read(notes_file).strip.match(/(?\d+)? *(?[A-Z]?[a-z,-:]+) *(?.*)/m) - next unless match - - tags = match[:tag].split(',') + [prefix] - due = if match[:due].nil? - tags.include?('track') ? 'eow' : "#{rand(0..PERSONAL_TIMESPAN_D)}d" - else - "#{match[:due]}d" - end - yield tags, match[:body], due - File.delete(notes_file) unless dry - end - end -end - -def random_quote(md_file) - tag = File.basename(md_file, '.md').downcase - lines = File.readlines(md_file) - - match = lines.first.match(/\((\d+)\)/) - timespan = run_from_personal_device? ? PERSONAL_TIMESPAN_D : WORK_TIMESPAN_D - timespan = match ? match[1].to_i : timespan - - quote = lines.select { |l| l.start_with? '*' }.map { |l| l.sub(/\* +/, '') }.sample - tags = [tag, 'random'] - tags << 'work' if maybe? and maybe? - yield tags, quote.chomp, "#{rand(0..timespan)}d" -end - -def run!(cmd, dry) - puts cmd - return if dry - - puts `#{cmd}` - raise "Command '#{cmd}' failed with #{$?.exitstatus}" if $?.exitstatus != 0 -rescue StandardError => e - puts "Error running command '#{cmd}': #{e.message}" - exit 1 -end - -def skill_add!(skills_str, dry) - skills_file = "#{WORKTIME_DIR}/skills.txt" - skills_str.split(',').map(&:strip).each { skills[_1.to_s.downcase] = _1 } - - File.foreach(skills_file) do |line| - line.chomp! - skills[line.downcase] = line - end - File.open("#{skills_file}.tmp", 'w') do |file| - skills.each_value { |skill| file.puts(skill) } - end - return if dry - - File.rename("#{skills_file}.tmp", skills_file) -end - -def worklog_add!(tag, quote, due, dry) - file = "#{WORKTIME_DIR}/wl-#{Time.now.to_i}n.txt" - content = "#{due.chomp 'd'} #{tag} #{quote}" - - puts "#{file}: #{content}" - File.write(file, content) unless dry -end - -# Queue to Gos https://codeberg.org/snonux/gos -def gos_queue!(tags, message, dry) - tags.delete('share') - platforms = [] - %w[linkedin li mastodon ma noop no].select { tags.include?(_1) }.each do |platform| - platforms << platform - tags.delete(platform) - end - unless platforms.empty? - platforms = %w[share] + platforms - tags = ["#{platforms.join(':')}"] + tags - end - tags = %w[share] + tags if tags.size == 1 && !tags.first.start_with?('share') - tags_str = tags.join(',') - - message = "#{tags_str.empty? ? '' : "#{tags_str} "}#{message}" - file = "#{GOS_DIR}/#{Digest::MD5.hexdigest(message)}.txt" - puts "Writing #{file} with #{message}" - File.write(file, message) unless dry -end - -def task_add!(tags, quote, due, dry) - if quote.empty? - puts 'Not adding task with empty quote' - return - end - if tags.include?('tr') - tags << 'track' - tags.delete('tr') - end - tags << 'work' if tags.include?('mentoring') || tags.include?('productivity') - tags.uniq! - - if tags.include?('task') - run! "task #{quote}", dry - else - project = tags.find { |t| t =~ /^[A-Z]/ } - project = if project.nil? - '' - else - tags.delete(project) - " project:#{project.downcase}" - end - priority = tags.include?('high') ? 'H' : '' - run! "task add due:#{due} priority:#{priority}#{project} +#{tags.join(' +')} '#{quote.gsub("'", '"')}'", dry - end -end - -def task_schedule!(id, due, dry) - run! "timeout 5s task modify #{id} due:#{due}", dry -end - -def filter_tasks(filter) - lines = `task #{filter} 2>/dev/null`.split("\n").drop(1) - lines.pop - lines.map { |foo| foo.split.first }.each do |id| - yield id if id.to_i.positive? - end -end - -begin - opts = { - random_dir: "#{ENV['HOME']}/Notes/random", - notes_dirs: "#{ENV['HOME']}/Notes,#{ENV['HOME']}/Notes/Quicklogger,#{ENV['HOME']}/git/worktime", - dry_run: false, - no_random: false - } - - opt_parser = OptionParser.new do |o| - o.banner = 'Usage: ruby taskwarriorfeeder.rb [options]' - o.on('-d', '--random-dir DIR', 'The random quotes directory') { |v| opts[:random_dir] = v } - o.on('-n', '--notes-dirs DIR1,DIR2,...', 'The notes directories') { |v| opts[:notes_dirs] = v } - o.on('-D', '--dry-run', 'Dry run mode') { opts[:dry_run] = true } - o.on('-R', '--no-randoms', 'No random entries') { opts[:no_random] = true } - o.on_tail('-h', '--help', 'Show this help message and exit') { puts o and exit } - end - - opt_parser.parse!(ARGV) - - (run_from_personal_device? ? %w[ql pl] : %w[wl]).each do |prefix| - notes(opts[:notes_dirs].split(','), prefix, opts[:dry_run]) do |tags, note, due| - if tags.include?('skill') || tags.include?('skills') - skill_add!(note, opts[:dry_run]) - elsif tags.include? 'work' - worklog_add!(:log, note, due, opts[:dry_run]) - elsif tags.any? { |tag| tag.start_with?('share') } - gos_queue!(tags, note, opts[:dry_run]) - else - task_add!(tags, note, due, opts[:dry_run]) - end - end - end - - unless opts[:no_random] - count = random_count - - Dir["#{opts[:random_dir]}/*.md"].shuffle.each do |md_file| - next unless maybe? - break if count <= 0 - - random_quote(md_file) do |tags, quote, due| - task_add!(tags, quote, due, opts[:dry_run]) - count -= 1 - end - end - end - - if Dir.exist?(GOS_DIR) && !opts[:dry_run] - Dir["#{WORKTIME_DIR}/tw-gos-*.json"].each do |tw_gos| - JSON.parse(File.read(tw_gos)).each do |entry| - gos_queue!(entry['tags'], entry['description'], opts[:dry_run]) - end - File.delete(tw_gos) - rescue StandardError => e - puts e - end - end - - # Schedule track tasks to end of week - filter_tasks('+track due:') do |id| - task_schedule!(id, 'eow', opts[:dry_run]) - end - - # Randomly schedule other unscheduled tasks - filter_tasks('-unsched -nosched -meeting -track due:') do |id| - task_schedule!(id, "#{rand(0..PERSONAL_TIMESPAN_D)}d", opts[:dry_run]) - end -end diff --git a/dotfiles/scripts/tmux-edit-send b/dotfiles/scripts/tmux-edit-send deleted file mode 100755 index 05fe62d..0000000 --- a/dotfiles/scripts/tmux-edit-send +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/env bash -set -u -o pipefail - -LOG_ENABLED=0 -log_file="${TMPDIR:-/tmp}/tmux-edit-send.log" -log() { - if [ "$LOG_ENABLED" -eq 1 ]; then - printf '%s\n' "$*" >> "$log_file" - fi -} - -# Read the target pane id from a temp file created by tmux binding. -read_target_from_file() { - local file_path="$1" - local pane_id - if [ -n "$file_path" ] && [ -f "$file_path" ]; then - pane_id="$(sed -n '1p' "$file_path" | tr -d '[:space:]')" - # Ensure pane ID has % prefix - if [ -n "$pane_id" ] && [[ "$pane_id" != %* ]]; then - pane_id="%${pane_id}" - fi - printf '%s' "$pane_id" - fi -} - -# Read the target pane id from tmux environment if present. -read_target_from_env() { - local env_line pane_id - env_line="$(tmux show-environment -g TMUX_EDIT_TARGET 2>/dev/null || true)" - case "$env_line" in - TMUX_EDIT_TARGET=*) - pane_id="${env_line#TMUX_EDIT_TARGET=}" - # Ensure pane ID has % prefix - if [ -n "$pane_id" ] && [[ "$pane_id" != %* ]] && [[ "$pane_id" =~ ^[0-9]+$ ]]; then - pane_id="%${pane_id}" - fi - printf '%s' "$pane_id" - ;; - esac -} - -# Resolve the target pane id, falling back to the last pane. -resolve_target_pane() { - local candidate="$1" - local current_pane last_pane - - current_pane="$(tmux display-message -p "#{pane_id}" 2>/dev/null || true)" - log "current pane=${current_pane:-}" - - # Ensure candidate has % prefix if it's a pane ID - if [ -n "$candidate" ] && [[ "$candidate" =~ ^[0-9]+$ ]]; then - candidate="%${candidate}" - log "normalized candidate to $candidate" - fi - - if [ -n "$candidate" ] && [[ "$candidate" == *"#{"* ]]; then - log "format target detected, clearing" - candidate="" - fi - if [ -z "$candidate" ]; then - candidate="$(tmux display-message -p "#{last_pane}" 2>/dev/null || true)" - log "using last pane as fallback: $candidate" - elif [ "$candidate" = "$current_pane" ]; then - last_pane="$(tmux display-message -p "#{last_pane}" 2>/dev/null || true)" - if [ -n "$last_pane" ]; then - candidate="$last_pane" - log "candidate was current, using last pane: $candidate" - fi - fi - printf '%s' "$candidate" -} - -# Capture the latest multi-line prompt content from the pane. -capture_prompt_text() { - local target="$1" - tmux capture-pane -p -t "$target" -S -2000 2>/dev/null | awk ' - function trim_box(line) { - sub(/^ *│ ?/, "", line) - sub(/ *│ *$/, "", line) - sub(/[[:space:]]+$/, "", line) - return line - } - /^ *│ *→/ && index($0,"INSERT")==0 && index($0,"Add a follow-up")==0 { - if (text != "") last = text - text = "" - capture = 1 - line = $0 - sub(/^.*→ ?/, "", line) - line = trim_box(line) - if (line != "") text = line - next - } - capture { - if ($0 ~ /^ *└/) { - capture = 0 - if (text != "") last = text - next - } - if ($0 ~ /^ *│/ && index($0,"INSERT")==0 && index($0,"Add a follow-up")==0) { - line = trim_box($0) - if (line != "") { - if (text != "") text = text " " line - else text = line - } - } - } - END { - if (text != "") last = text - if (last != "") print last - } - ' -} - -# Write captured prompt text into the temp file if available. -prefill_tmpfile() { - local tmpfile="$1" - local prompt_text="$2" - if [ -n "$prompt_text" ]; then - printf '%s\n' "$prompt_text" > "$tmpfile" - fi -} - -# Ensure the target pane exists before sending keys. -validate_target_pane() { - local target="$1" - local pane target_found - if [ -z "$target" ]; then - log "error: no target pane determined" - echo "Could not determine target pane." >&2 - return 1 - fi - target_found=0 - log "validate: looking for target='$target' in all panes:" - for pane in $(tmux list-panes -a -F "#{pane_id}" 2>/dev/null || true); do - log "validate: checking pane='$pane'" - if [ "$pane" = "$target" ]; then - target_found=1 - log "validate: MATCH FOUND!" - break - fi - done - if [ "$target_found" -ne 1 ]; then - log "error: target pane not found: $target" - echo "Target pane not found: $target" >&2 - return 1 - fi - log "validate: target pane validated successfully" -} - -# Send temp file contents to the target pane line by line. -send_content() { - local target="$1" - local tmpfile="$2" - local prompt_text="$3" - local first_line=1 - local line - log "send_content: target=$target, prompt_text='$prompt_text'" - while IFS= read -r line || [ -n "$line" ]; do - log "send_content: read line='$line'" - if [ "$first_line" -eq 1 ] && [ -n "$prompt_text" ]; then - if [[ "$line" == "$prompt_text"* ]]; then - local old_line="$line" - line="${line#"$prompt_text"}" - log "send_content: stripped prompt, was='$old_line' now='$line'" - fi - fi - first_line=0 - log "send_content: sending line='$line'" - tmux send-keys -t "$target" -l "$line" - tmux send-keys -t "$target" Enter - done < "$tmpfile" - log "sent content to $target" -} - -# Main entry point. -main() { - local target_file="${1:-}" - local target - local editor="${EDITOR:-vi}" - local tmpfile - local prompt_text - - log "=== tmux-edit-send starting ===" - log "target_file=$target_file" - log "EDITOR=$editor" - - target="$(read_target_from_file "$target_file" || true)" - if [ -n "$target" ]; then - log "file target=${target:-}" - rm -f "$target_file" - fi - if [ -z "$target" ]; then - target="${TMUX_EDIT_TARGET:-}" - fi - log "env target=${target:-}" - if [ -z "$target" ]; then - target="$(read_target_from_env || true)" - fi - log "tmux env target=${target:-}" - target="$(resolve_target_pane "$target")" - log "fallback target=${target:-}" - - tmpfile="$(mktemp)" - log "created tmpfile=$tmpfile" - if [ ! -f "$tmpfile" ]; then - log "ERROR: mktemp failed to create file" - echo "ERROR: mktemp failed" >&2 - exit 1 - fi - mv "$tmpfile" "${tmpfile}.md" 2>&1 | while read -r line; do log "mv output: $line"; done - tmpfile="${tmpfile}.md" - log "renamed to tmpfile=$tmpfile" - if [ ! -f "$tmpfile" ]; then - log "ERROR: tmpfile does not exist after rename" - echo "ERROR: tmpfile rename failed" >&2 - exit 1 - fi - trap 'rm -f "$tmpfile"' EXIT - - log "capturing prompt text from target=$target" - prompt_text="$(capture_prompt_text "$target")" - log "captured prompt_text='$prompt_text'" - prefill_tmpfile "$tmpfile" "$prompt_text" - log "prefilled tmpfile" - - log "launching editor: $editor $tmpfile" - "$editor" "$tmpfile" - local editor_exit=$? - log "editor exited with status $editor_exit" - - if [ ! -s "$tmpfile" ]; then - log "empty file, nothing sent" - exit 0 - fi - - log "tmpfile contents:" - log "$(cat "$tmpfile")" - - log "validating target pane" - validate_target_pane "$target" - log "sending content to target=$target" - send_content "$target" "$tmpfile" "$prompt_text" - log "=== tmux-edit-send completed ===" -} - -main "$@" diff --git a/dotfiles/scripts/wol-f3s b/dotfiles/scripts/wol-f3s deleted file mode 100755 index 263763b..0000000 --- a/dotfiles/scripts/wol-f3s +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# Wake-on-LAN and shutdown script for f3s cluster (f0, f1, f2) -# -# Usage: -# wol-f3s # Wake all three Beelinks -# wol-f3s f0 # Wake only f0 -# wol-f3s f1 # Wake only f1 -# wol-f3s f2 # Wake only f2 -# wol-f3s shutdown # Shutdown all three Beelinks - -# MAC addresses -F0_MAC="e8:ff:1e:d7:1c:ac" # f0 (192.168.1.130) -F1_MAC="e8:ff:1e:d7:1e:44" # f1 (192.168.1.131) -F2_MAC="e8:ff:1e:d7:1c:a0" # f2 (192.168.1.132) - -# IP addresses -F0_IP="192.168.1.130" -F1_IP="192.168.1.131" -F2_IP="192.168.1.132" - -# SSH user -SSH_USER="paul" - -# Broadcast address for your LAN -BROADCAST="192.168.1.255" - -wake() { - local name=$1 - local mac=$2 - - if [[ "$mac" == "XX:XX:XX:XX:XX:XX" ]]; then - echo "⚠️ $name MAC address not configured yet" - return 1 - fi - - echo "Sending WoL packet to $name ($mac)..." - wol -i "$BROADCAST" "$mac" -} - -shutdown_host() { - local name=$1 - local ip=$2 - - echo "Shutting down $name ($ip)..." - ssh -o ConnectTimeout=5 "$SSH_USER@$ip" "doas poweroff" 2>/dev/null && \ - echo " ✓ Shutdown command sent to $name" || \ - echo " ✗ Failed to reach $name (already down?)" -} - -ACTION="${1:-all}" - -case "$ACTION" in - f0) - wake "f0" "$F0_MAC" - ;; - f1) - wake "f1" "$F1_MAC" - ;; - f2) - wake "f2" "$F2_MAC" - ;; - all|"") - wake "f0" "$F0_MAC" - wake "f1" "$F1_MAC" - wake "f2" "$F2_MAC" - ;; - shutdown|poweroff|down) - # This is to mute Gogios alerts for a day - ssh rex@blowfish.buetow.org touch /tmp/f3s_taken_down - ssh rex@fishfinger.buetow.org touch /tmp/f3s_taken_down - shutdown_host "f0" "$F0_IP" - shutdown_host "f1" "$F1_IP" - shutdown_host "f2" "$F2_IP" - echo "" - echo "✓ Shutdown commands sent to all machines." - exit 0 - ;; - *) - echo "Usage: $0 [f0|f1|f2|all|shutdown]" - exit 1 - ;; -esac - -echo "" -echo "✓ WoL packets sent. Machines should boot in a few seconds." -echo " Wait ~30 seconds, then try: ssh paul@192.168.1.130" diff --git a/dotfiles/signature b/dotfiles/signature deleted file mode 100644 index 8031719..0000000 --- a/dotfiles/signature +++ /dev/null @@ -1,2 +0,0 @@ -Paul Buetow -paul.buetow.org diff --git a/dotfiles/ssh/config b/dotfiles/ssh/config deleted file mode 100644 index 5824103..0000000 --- a/dotfiles/ssh/config +++ /dev/null @@ -1,26 +0,0 @@ -#ControlPath ~/.ssh/cp-%C -#ControlMaster auto -#UseKeychain yes -AddKeysToAgent yes -ControlPersist 60m -#StrictHostKeyChecking no - -Host blowfish.buetow.org -User rex -Port 2 - -Host fishfinger.buetow.org -User rex -Port 2 - -Host *.aws.buetow.org -User ec2-user -Port 22 - -Host *.buetow.org -Port 2 - -Host git-server -HostName r0 -Port 30022 -User git diff --git a/dotfiles/sway/config.d/keyboard.conf b/dotfiles/sway/config.d/keyboard.conf deleted file mode 100644 index cf91046..0000000 --- a/dotfiles/sway/config.d/keyboard.conf +++ /dev/null @@ -1,6 +0,0 @@ -input "type:keyboard" { - xkb_layout us,gb,de - xkb_options grp:win_space_toggle -} - -input * xkb_options "caps:escape" diff --git a/dotfiles/tmux/tmux.conf b/dotfiles/tmux/tmux.conf deleted file mode 100644 index 51c20a8..0000000 --- a/dotfiles/tmux/tmux.conf +++ /dev/null @@ -1,38 +0,0 @@ -source ~/.config/tmux/tmux.local.conf - -set-option -g allow-rename off -set-option -g history-limit 100000 -set-option -s escape-time 0 -set-option -g set-titles on - -set-window-option -g mode-keys vi - -bind-key h select-pane -L -bind-key j select-pane -D -bind-key k select-pane -U -bind-key l select-pane -R - -bind-key H resize-pane -L 5 -bind-key J resize-pane -D 5 -bind-key K resize-pane -U 5 -bind-key L resize-pane -R 5 - -bind-key g popup -E -w 95% -h 95% -d '#{pane_current_path}' lazygit -bind-key f popup -E -w 95% -h 95% -d '#{pane_current_path}' ranger -bind-key e run-shell -b "tmux display-message -p '#{pane_id}' > /tmp/tmux-edit-target-#{client_pid} \; tmux popup -E -w 90% -h 35% -x 5% -y 65% -d '#{pane_current_path}' \"~/scripts/tmux-edit-send /tmp/tmux-edit-target-#{client_pid}\"" -bind-key N popup -E -w 95% -h 95% hx ~/Notes -bind-key t popup -E -w 95% -h 95% hx fish - -# bind-key b break-pane -d -bind-key c new-window -c '#{pane_current_path}' -bind-key F new-window -n "session-switcher" "tmux list-sessions | fzf | cut -d: -f1 | xargs tmux switch-client -t" -bind-key p setw synchronize-panes off -bind-key P setw synchronize-panes on -bind-key r source-file ~/.config/tmux/tmux.conf \; display-message "~/.config/tmux/tmux.conf reloaded" -bind-key T choose-tree - -set-option -g pane-active-border-style fg=magenta,bold - -set -g status-right '#{@hexai_status} #[fg=colour8]| %H:%M' -set -g status-right-length 120 -set-environment -g HEXAI_TMUX_STATUS_THEME white-on-purple diff --git a/dotfiles/tmux/tmux.local.conf b/dotfiles/tmux/tmux.local.conf deleted file mode 100644 index adb6294..0000000 --- a/dotfiles/tmux/tmux.local.conf +++ /dev/null @@ -1,2 +0,0 @@ -bind-key -T copy-mode-vi 'v' send -X begin-selection -bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel diff --git a/dotfiles/vale.ini b/dotfiles/vale.ini deleted file mode 100644 index 3b39678..0000000 --- a/dotfiles/vale.ini +++ /dev/null @@ -1,6 +0,0 @@ -StylesPath = styles -MinAlertLevel = suggestion -Packages = Microsoft, proselint - -[*] -BasedOnStyles = Vale, Microsoft, proselint diff --git a/dotfiles/waybar/config.jsonc b/dotfiles/waybar/config.jsonc deleted file mode 100644 index db2aeea..0000000 --- a/dotfiles/waybar/config.jsonc +++ /dev/null @@ -1,194 +0,0 @@ -// -*- mode: jsonc -*- -{ - // "layer": "top", // Waybar at top layer - // "position": "bottom", // Waybar position (top|bottom|left|right) - "height": 20, // Waybar height (to be removed for auto height) - // "width": 1280, // Waybar width - "spacing": 1, // Gaps between modules (4px) - // Choose the order of the modules - "modules-left": [ - "sway/workspaces", - "sway/mode", - "sway/scratchpad" - ], - "modules-center": [ - ], - "modules-right": [ - "idle_inhibitor", - "pulseaudio", - "network", - "power-profiles-daemon", - "temperature", - "sway/language", - "battery", - "clock", - "tray" - ], - // Modules configuration - // "sway/workspaces": { - // "disable-scroll": true, - // "all-outputs": true, - // "warp-on-scroll": false, - // "format": "{name}: {icon}", - // "format-icons": { - // "1": "", - // "2": "", - // "3": "", - // "4": "", - // "5": "", - // "urgent": "", - // "focused": "", - // "default": "" - // } - // }, - "keyboard-state": { - "numlock": true, - "capslock": true, - "format": "{name} {icon}", - "format-icons": { - "locked": "", - "unlocked": "" - } - }, - "sway/mode": { - "format": "{}" - }, - "sway/scratchpad": { - "format": "{icon} {count}", - "show-empty": false, - "format-icons": ["", ""], - "tooltip": true, - "tooltip-format": "{app}: {title}" - }, - "mpd": { - "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {volume}% ", - "format-disconnected": "Disconnected ", - "format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ", - "unknown-tag": "N/A", - "interval": 5, - "consume-icons": { - "on": " " - }, - "random-icons": { - "off": " ", - "on": " " - }, - "repeat-icons": { - "on": " " - }, - "single-icons": { - "on": "1 " - }, - "state-icons": { - "paused": "", - "playing": "" - }, - "tooltip-format": "MPD (connected)", - "tooltip-format-disconnected": "MPD (disconnected)" - }, - "idle_inhibitor": { - "format": "{icon}", - "format-icons": { - "activated": "", - "deactivated": "" - } - }, - "tray": { - // "icon-size": 21, - "spacing": 10 - }, - "clock": { - // "timezone": "America/New_York", - "tooltip-format": "{:%Y %B}\n{calendar}", - "format-alt": "{:%Y-%m-%d}" - }, - "cpu": { - "format": "{usage}% ", - "tooltip": false - }, - "memory": { - "format": "{}% " - }, - "temperature": { - // "thermal-zone": 2, - // "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input", - "critical-threshold": 80, - // "format-critical": "{temperatureC}°C {icon}", - "format": "{temperatureC}°C {icon}", - "format-icons": ["", "", ""] - }, - "backlight": { - // "device": "acpi_video1", - "format": "{percent}% {icon}", - "format-icons": ["🌑", "🌘", "🌗", "🌖", "🌕"] - }, - "battery": { - "states": { - // "good": 95, - "warning": 30, - "critical": 15 - }, - "format": "{capacity}% {icon}", - "format-full": "{capacity}% {icon}", - "format-charging": "{capacity}% ", - "format-plugged": "{capacity}% ", - "format-alt": "{time} {icon}", - // "format-good": "", // An empty format will hide the module - // "format-full": "", - "format-icons": ["", "", "", "", ""] - }, - "battery#bat2": { - "bat": "BAT2" - }, - "power-profiles-daemon": { - "format": "{icon}", - "tooltip-format": "Power profile: {profile}\nDriver: {driver}", - "tooltip": true, - "format-icons": { - "default": "", - "performance": "", - "balanced": "", - "power-saver": "" - } - }, - "network": { - // "interface": "wlp2*", // (Optional) To force the use of this interface - "format-wifi": "{essid} ({signalStrength}%) ", - "format-ethernet": "{ipaddr}/{cidr} ", - "tooltip-format": "{ifname} via {gwaddr} ", - "format-linked": "{ifname} (No IP) ", - "format-disconnected": "Disconnected ⚠", - "format-alt": "{ifname}: {ipaddr}/{cidr}" - }, - "pulseaudio": { - // "scroll-step": 1, // %, can be a float - "format": "{volume}% {icon} {format_source}", - "format-bluetooth": "{volume}% {icon} {format_source}", - "format-bluetooth-muted": " {icon} {format_source}", - "format-muted": " {format_source}", - "format-source": "{volume}% ", - "format-source-muted": "", - "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "", - "phone": "", - "portable": "", - "car": "", - "default": ["", "", ""] - }, - "on-click": "pavucontrol" - }, - "custom/media": { - "format": "{icon} {}", - "return-type": "json", - "max-length": 40, - "format-icons": { - "spotify": "", - "default": "🎜" - }, - "escape": true, - "exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder - // "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name - } -} diff --git a/dotfiles/waybar/style.css b/dotfiles/waybar/style.css deleted file mode 100644 index e031037..0000000 --- a/dotfiles/waybar/style.css +++ /dev/null @@ -1,326 +0,0 @@ -* { - font-family: 'Noto Sans Mono', 'Font Awesome 6 Free', 'Font Awesome 6 Brands', monospace; - font-size: 13px; -} - -window#waybar { - background-color: rgba(43, 48, 59, 0.5); - border-bottom: 3px solid rgba(100, 114, 125, 0.5); - color: #ffffff; - transition-property: background-color; - transition-duration: .5s; -} - -window#waybar.hidden { - opacity: 0.2; -} - -/* -window#waybar.empty { - background-color: transparent; -} -window#waybar.solo { - background-color: #FFFFFF; -} -*/ - -window#waybar.termite { - background-color: #3F3F3F; -} - -window#waybar.chromium { - background-color: #000000; - border: none; -} - -button { - /* Use box-shadow instead of border so the text isn't offset */ - box-shadow: inset 0 -3px transparent; - /* Avoid rounded borders under each button name */ - border: none; - border-radius: 0; -} - -/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ -button:hover { - background: inherit; - box-shadow: inset 0 -3px #ffffff; -} - -/* you can set a style on hover for any module like this */ -#pulseaudio:hover { - background-color: #a37800; -} - -#workspaces button { - padding: 0 5px; - background-color: transparent; - color: #ffffff; -} - -#workspaces button:hover { - background: rgba(0, 0, 0, 0.2); -} - -#workspaces button.focused { - background-color: #64727D; - box-shadow: inset 0 -3px #ffffff; -} - -#workspaces button.urgent { - background-color: #eb4d4b; -} - -#mode { - background-color: #64727D; - box-shadow: inset 0 -3px #ffffff; -} - -#clock, -#battery, -#cpu, -#memory, -#disk, -#temperature, -#backlight, -#network, -#pulseaudio, -#wireplumber, -#custom-media, -#tray, -#mode, -#idle_inhibitor, -#scratchpad, -#power-profiles-daemon, -#mpd { - padding: 0 10px; - color: #ffffff; -} - -#window, -#workspaces { - margin: 0 4px; -} - -/* If workspaces is the leftmost module, omit left margin */ -.modules-left > widget:first-child > #workspaces { - margin-left: 0; -} - -/* If workspaces is the rightmost module, omit right margin */ -.modules-right > widget:last-child > #workspaces { - margin-right: 0; -} - -#clock { - background-color: #64727D; -} - -#battery { - background-color: #ffffff; - color: #000000; -} - -#battery.charging, #battery.plugged { - color: #ffffff; - background-color: #26A65B; -} - -@keyframes blink { - to { - background-color: #ffffff; - color: #000000; - } -} - -/* Using steps() instead of linear as a timing function to limit cpu usage */ -#battery.critical:not(.charging) { - background-color: #f53c3c; - color: #ffffff; - animation-name: blink; - animation-duration: 0.5s; - animation-timing-function: steps(12); - animation-iteration-count: infinite; - animation-direction: alternate; -} - -#power-profiles-daemon { - padding-right: 15px; -} - -#power-profiles-daemon.performance { - background-color: #f53c3c; - color: #ffffff; -} - -#power-profiles-daemon.balanced { - background-color: #2980b9; - color: #ffffff; -} - -#power-profiles-daemon.power-saver { - background-color: #2ecc71; - color: #000000; -} - -label:focus { - background-color: #000000; -} - -#cpu { - background-color: #2ecc71; - color: #000000; -} - -#memory { - background-color: #9b59b6; -} - -#disk { - background-color: #964B00; -} - -#backlight { - background-color: #90b1b1; -} - -#network { - background-color: #2980b9; -} - -#network.disconnected { - background-color: #f53c3c; -} - -#pulseaudio { - background-color: #f1c40f; - color: #000000; -} - -#pulseaudio.muted { - background-color: #90b1b1; - color: #2a5c45; -} - -#wireplumber { - background-color: #fff0f5; - color: #000000; -} - -#wireplumber.muted { - background-color: #f53c3c; -} - -#custom-media { - background-color: #66cc99; - color: #2a5c45; - min-width: 100px; -} - -#custom-media.custom-spotify { - background-color: #66cc99; -} - -#custom-media.custom-vlc { - background-color: #ffa000; -} - -#temperature { - background-color: #f0932b; -} - -#temperature.critical { - background-color: #eb4d4b; -} - -#tray { - background-color: #2980b9; -} - -#tray > .passive { - -gtk-icon-effect: dim; -} - -#tray > .needs-attention { - -gtk-icon-effect: highlight; - background-color: #eb4d4b; -} - -#idle_inhibitor { - background-color: #2d3436; -} - -#idle_inhibitor.activated { - background-color: #ecf0f1; - color: #2d3436; -} - -#mpd { - background-color: #66cc99; - color: #2a5c45; -} - -#mpd.disconnected { - background-color: #f53c3c; -} - -#mpd.stopped { - background-color: #90b1b1; -} - -#mpd.paused { - background-color: #51a37a; -} - -#language { - background: #00b093; - color: #740864; - padding: 0 5px; - margin: 0 5px; - min-width: 16px; -} - -#keyboard-state { - background: #97e1ad; - color: #000000; - padding: 0 0px; - margin: 0 5px; - min-width: 16px; -} - -#keyboard-state > label { - padding: 0 5px; -} - -#keyboard-state > label.locked { - background: rgba(0, 0, 0, 0.2); -} - -#scratchpad { - background: rgba(0, 0, 0, 0.2); -} - -#scratchpad.empty { - background-color: transparent; -} - -#privacy { - padding: 0; -} - -#privacy-item { - padding: 0 5px; - color: white; -} - -#privacy-item.screenshare { - background-color: #cf5700; -} - -#privacy-item.audio-in { - background-color: #1ca000; -} - -#privacy-item.audio-out { - background-color: #0069d4; -} diff --git a/dotfiles/zsh/zshrc b/dotfiles/zsh/zshrc deleted file mode 100644 index fa84d26..0000000 --- a/dotfiles/zsh/zshrc +++ /dev/null @@ -1,22 +0,0 @@ -if [ -f $HOME/.nofish ]; then - current_time=$(date +%s) - file_time=$(stat -f %m $HOME/.nofish) - time_diff=$((current_time - file_time)) - if [ $time_diff -gt 5 ]; then - rm -vf $HOME/.nofish - fi -fi -if [ ! -f $HOME/.nofish ]; then - if [ -e /opt/homebrew/bin/fish ]; then - exec /opt/homebrew/bin/fish - elif [ -e /bin/fish ]; then - exec /bin/fish - elif [ -e /usr/bin/fish ]; then - exec /usr/bin/fish - elif [ -e /data/data/com.termux/files/usr/bin/fish ]; then - exec /data/data/com.termux/files/usr/bin/fish - fi - echo 'I might want to install fish on this host' -fi - -alias f=fish 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 | 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 diff --git a/ghostty/config b/ghostty/config new file mode 100644 index 0000000..e109583 --- /dev/null +++ b/ghostty/config @@ -0,0 +1,17 @@ +window-decoration = true +copy-on-select = true +quick-terminal-position = bottom +quick-terminal-screen = mouse +shell-integration = zsh +bold-is-bright = true + +# Toggle window decorations only works on Linux! +keybind = ctrl+shift+d=toggle_window_decorations +keybind = ctrl+shift+f=toggle_fullscreen +keybind = ctrl+shift+g=reload_config +# Toggle quick terminal only supported for MacOS +keybind = global:ctrl+shift+t=toggle_quick_terminal +keybind = ctrl+shift+c=copy_to_clipboard +keybind = ctrl+shift+v=paste_from_clipboard +keybind = ctrl+shift+w=paste_from_selection + diff --git a/gitsyncer/config.json b/gitsyncer/config.json new file mode 100644 index 0000000..a1e8258 --- /dev/null +++ b/gitsyncer/config.json @@ -0,0 +1,33 @@ +{ + "organizations": [ + { + "host": "git@codeberg.org", + "name": "snonux" + }, + { + "host": "git@github.com", + "name": "snonux" + }, + { + "host": "ssh://git@r0:30022/repos", + "backupLocation": true + } + ], + "repositories": [], + "skip_releases": { + "fapi": [ + "0.0.1" + ] + }, + "exclude_from_showcase": [ + "bratwurstmitsenf", + "Adv360-Pro-ZMK", + "katana", + "playground", + "pages", + "nvim" + ], + "exclude_branches": [ + "^codex/" + ] +} \ No newline at end of file diff --git a/helix/config.toml b/helix/config.toml new file mode 100644 index 0000000..cdd64b5 --- /dev/null +++ b/helix/config.toml @@ -0,0 +1,88 @@ +theme = "adwaita-dark" + +[editor] +bufferline = "always" +rulers = [80, 100, 120, 140] +line-number = "relative" +mouse = true +cursorline = true +cursorcolumn = true +continue-comments = false +completion-timeout = 2000 + +[editor.soft-wrap] +enable = true + +[editor.inline-diagnostics] +# cursor-line = "hint" + +[editor.auto-save] +focus-lost = true +after-delay.timeout = 3000 +after-delay.enable = true + +[editor.statusline] +left = ["version-control", "mode", "spinner", "file-name", "position" ] +center = ["diagnostics"] +right = ["selections", "file-encoding", "file-line-ending", "file-type"] + +[editor.lsp] +display-messages = true +display-inlay-hints = false + +[editor.cursor-shape] +normal = "block" +insert = "underline" +select = "bar" + +[editor.whitespace.render] +space = "none" +tab = "none" +newline = "none" + +[keys.normal] +D = ["ensure_selections_forward", "extend_to_line_end"] +#S conflicts with split_selection, for now comment out +#S = ["ensure_selections_forward", "extend_to_line_start"] +0 = ["select_mode", "extend_to_file_start"] +G = ["ensure_selections_forward", "extend_to_file_end"] +"^" = ["move_prev_word_start", "move_next_word_end", "search_selection", "global_search"] +"ret" = "goto_word" + +C-c = "yank_main_selection_to_clipboard" +C-v = { b = "paste_clipboard_before", a = "paste_clipboard_after", r = ":clipboard-paste-replace" } +A-c = "toggle_comments" # Was originally C-c, so mapped to ALT now + +# Helix related helpers +C-h = { c = ":config-open", r = ":config-reload", C = ":run-shell-command cp -v ~/.config/helix/*.toml ~/git/conf/dotfiles/helix/", l = ":open ~/.config/helix/languages.toml", h = ":open ~/git/worktime/HelixCheat.md", L = ":log-open", d = ":theme default" } + +C-r = [ ":config-reload", ":reload-all" ] + +C-u = [ ":write", ":run-shell-command sh -c 'source ~/.hx.remote.source; scp $LOCAL_PATH $REMOTE_URI && echo Uploaded to $REMOTE_URI || echo Failed uploading to $REMOTE_URI'"] + +# Various helpers +C-s = { e = ":set-option soft-wrap.enable true", d = ":set-option soft-wrap.enable false", s = "save_selection" } + +# Buffer stuff +C-q = ":buffer-close" + +# AI commands are good here. +C-p = { c = ":pipe ai correct this sentence and only print out the corrected text", r = ":pipe ai restructure and reword the input and dont leave information out and only print out the new text", a = ":pipe ai rewrite this in a more casual style", n = ":pipe ai these are book notes of mine. correct the grammar and re-organize the notes. use bullet points for short information and whole paragraphs for longer one. the output must be in Gemini Gemtext format with the star * as the bullet point symbol and not the minus - . dont leave out any content.", p = ":pipe ai" } +# Will replace the above +C-a = ":pipe hexai-tmux-action" + +# Git commands +C-g = { d = ":run-shell-command git diff", p = ":run-shell-command git pull", u = ":run-shell-command git push", t = ":run-shell-command tmux new-window -n hx-git-tig tig", c = ":run-shell-command tmux split-window -v 'git commit -a'" } + +# Build commands +C-l = { m = ":run-shell-command make", d = ":run-shell-command go-task dev", r = ":run-shell-command tmux new-window -n hx-go-task-run 'go-task run'" } + +[keys.normal.space] +B = "file_picker_in_current_buffer_directory" +Q = [ ":cd ~/QuickEdit", "file_picker_in_current_directory" ] + +[keys.select] +"{" = "goto_prev_paragraph" +"}" = "goto_next_paragraph" +n = ["extend_search_next", "merge_selections"] +N = ["extend_search_prev", "merge_selections"] diff --git a/helix/languages.toml b/helix/languages.toml new file mode 100644 index 0000000..33a3f0d --- /dev/null +++ b/helix/languages.toml @@ -0,0 +1,206 @@ +[[language]] +name = "hcl" +scope = "source.hcl" +injection-regex = "(hcl|tf|nomad)" +language-id = "terraform" +file-types = ["hcl", "tf", "nomad"] +comment-token = "#" +block-comment-tokens = { start = "/*", end = "*/" } +indent = { tab-width = 2, unit = " " } +language-servers = [ "terraform-ls", "hexai-lsp" ] +auto-format = true + +[[language]] +name = "go" +auto-format= true +diagnostic-severity = "hint" +formatter = { command = "hx.goformatter" } +language-servers = [ "gopls", "golangci-lint-lsp", "hexai-lsp" ] +[language-server.hexai-lsp] +command = "hexai-lsp" + +[language-server.gopls] +command = "gopls" + +[language-server.gopls.config.hints] +assignVariableTypes = true +compositeLiteralFields = true +constantValues = true +functionTypeParameters = true +parameterNames = true +rangeVariableTypes = true + +# go install github.com/nametake/golangci-lint-langserver@latest │ +[language-server.golangci-lint-lsp] +command = "golangci-lint-langserver" + +[language-server.ltex-ls] +command = "/home/paul/java/ltex-ls/bin/ltex-ls" + +# golangci-lint-langserver depepds/calls golangci-lint +# go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest +[language-server.golangci-lint-lsp.config] +command = ["golangci-lint", "run", "--issues-exit-code=1"] +# command = ["golangci-lint", "run", "--out-format", "json", "--issues-exit-code=1"] + +[[language]] +name = "c" +scope = "source.c" +injection-regex = "c" +file-types = ["c", "h"] +comment-token = "//" +language-servers = [ "clangd", "hexai-lsp" ] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "c" +source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7175a6dd5fc1cee660dce6fe23f6043d75af424a" } + +[language-server.clangd] +command = "clangd" + +[[language]] +name = "perl" +auto-format= true +formatter = { command = "perltidy", args = ["-l=120"] } +scope = "source.perl" +file-types = ["pl", "pm", "t", "psgi", "raku", "rakumod", "rakutest", "rakudoc", "nqp", "p6", "pl6", "pm6", { glob = "Rexfile" }] +shebangs = ["perl"] +comment-token = "#" +language-servers = [ "perlnavigator", "hexai-lsp" ] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "perl" +source = { git = "https://github.com/tree-sitter-perl/tree-sitter-perl", rev = "e99bb5283805db4cb86c964722d709df21b0ac16" } + +[[language]] +name = "pod" +scope = "source.pod" +injection-regex = "pod" +file-types = ["pod"] + +[[grammar]] +name = "pod" +source = { git = "https://github.com/tree-sitter-perl/tree-sitter-pod", rev = "39da859947b94abdee43e431368e1ae975c0a424" } + +[[language]] +name = "ruby" +auto-format = true +scope = "source.ruby" +injection-regex = "ruby" +file-types = [ + "rb", + "rbs", + "rake", + "irb", + "gemspec", + { glob = "Gemfile" }, + { glob = "Rakefile" } +] +shebangs = ["ruby"] +comment-token = "#" +language-servers = [ "ruby-lsp", "solargraph", "rubocop", "hexai-lsp" ] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "ruby" +source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "206c7077164372c596ffa8eaadb9435c28941364" } + +[[language]] +name = "bash" +scope = "source.bash" +injection-regex = "(shell|bash|zsh|sh)" +file-types = [ + "sh", + "bash", + "zsh", + "zshenv", + "zlogin", + "zlogout", + "zprofile", + "zshrc", + "eclass", + "ebuild", + "bazelrc", + "Renviron", + "zsh-theme", + "ksh", + "cshrc", + "tcshrc", + "bashrc_Apple_Terminal", + "zshrc_Apple_Terminal", + { glob = "*zshrc*" }, +] +shebangs = ["sh", "bash", "dash", "zsh"] +comment-token = "#" +language-servers = [ "bash-language-server", "hexai-lsp" ] +indent = { tab-width = 2, unit = " " } + +[[language]] +name = "fish" +# scope = "source.fish" +# injection-regex = "(fish)" +# file-types = [ +# "fish", +# ] +# shebangs = ["fish" ] +# comment-token = "#" +language-servers = [ "fish-lsp", "hexai-lsp" ] +# indent =dth = 4, unit = " " } + +[[grammar]] +name = "bash" +source = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "275effdfc0edce774acf7d481f9ea195c6c403cd" } + +[language-server] +bash-language-server = { command = "bash-language-server", args = ["start"] } +vale-ls = { command = "vale-ls" } +ruby-lsp = { command = "ruby-lsp"} +rubocop = { command = "rubocop", args = ["--lsp"] } + +[[language]] +name = "markdown" +scope = "source.md" +injection-regex = "md|markdown" +file-types = ["md", "markdown", "mkd", "mdwn", "mdown", "markdn", "mdtxt", "mdtext", "workbook", "gmi", "tpl", "txt" ] +roots = [".marksman.toml"] +language-servers = [ "marksman", "markdown-oxide", "vale-ls", "hexai-lsp", "ltex-ls"] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "markdown" +source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown" } + +[[language]] +name = "markdown.inline" +scope = "source.markdown.inline" +injection-regex = "markdown\\.inline" +file-types = [] +grammar = "markdown_inline" + +[[grammar]] +name = "markdown_inline" +source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown-inline" } + +[[language]] +name = "gemini" +scope = "source.gmi" +file-types = ["gmi", "tpl"] + +[[grammar]] +name = "gemini" +source = { git = "https://git.sr.ht/~nbsp/tree-sitter-gemini", rev = "3cc5e4bdf572d5df4277fc2e54d6299bd59a54b3" } + +[[language]] +name = "java" +scope = "source.java" +injection-regex = "java" +file-types = ["java", "jav", "pde"] +roots = ["pom.xml", "build.gradle", "build.gradle.kts"] +language-servers = [ "jdtls", "hexai-lsp" ] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "java" +source = { git = "https://github.com/tree-sitter/tree-sitter-java", rev = "09d650def6cdf7f479f4b78f595e9ef5b58ce31e" } diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..c3b8701 --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,70 @@ + +require("CopilotChat").setup { + -- See Configuration section for options +} + +local timer = vim.loop.new_timer() -- Initialize the timer + +vim.api.nvim_create_autocmd("BufEnter", { + pattern = "*", + callback = function() + if vim.bo.filetype == "copilot-chat" then + local copilot_chat_buf = vim.api.nvim_get_current_buf() + vim.cmd("wincmd _") -- Maximize height + vim.cmd("wincmd |") -- Maximize width + local file_path = vim.fn.expand("~/.copilot_chat_output.txt") + + -- Start the timer with a 2-second interval + timer:start(1000, 1000, vim.schedule_wrap(function() + if copilot_chat_buf and vim.api.nvim_buf_is_valid(copilot_chat_buf) then + -- Get all lines in the buffer + local lines = vim.api.nvim_buf_get_lines(copilot_chat_buf, 0, -1, false) + + -- Check for the stopping condition + local user_line_count = 0 + for _, line in ipairs(lines) do + if line:find("^## User") then + user_line_count = user_line_count + 1 + if user_line_count >= 2 then + print("Stopping write process: Two '## User' lines detected.") + timer:stop() + -- Write the buffer content to the file + vim.api.nvim_buf_call(copilot_chat_buf, function() + vim.cmd("write! " .. file_path) + end) + vim.cmd("qa!") + return + end + end + end + + -- Write the buffer content to the file + vim.api.nvim_buf_call(copilot_chat_buf, function() + vim.cmd("write! " .. file_path) + end) + end + end)) + end + end, +}) + +vim.api.nvim_create_user_command('CopilotAsk', function(args) + local chat = require("CopilotChat") + local input + if args.args and args.args ~= "" then + input = args.args + else + local input_file = os.getenv("HOME") .. "/.copilot_chat_input.txt" + local file = io.open(input_file, "r") + if file then + input = file:read("*all") + file:close() + else + print("Error: Unable to open input file.") + return + end + end + chat.ask(input) +end, { force = true, range = true, nargs = "?" }) + + diff --git a/pipewire/pipewire.conf b/pipewire/pipewire.conf new file mode 100644 index 0000000..a97c99e --- /dev/null +++ b/pipewire/pipewire.conf @@ -0,0 +1,257 @@ +# Daemon config file for PipeWire version "0.3.51" # +# +# Copy and edit this file in /etc/pipewire for system-wide changes +# or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# /etc/pipewire/pipewire.conf.d/ for system-wide changes or in +# ~/.config/pipewire/pipewire.conf.d/ for local changes. +# + +context.properties = { + ## Configure properties in the system. + #library.name.system = support/libspa-support + #context.data-loop.library.name.system = support/libspa-support + #support.dbus = true + #link.max-buffers = 64 + link.max-buffers = 16 # version < 3 clients can't handle more + #mem.warn-mlock = false + #mem.allow-mlock = true + #mem.mlock-all = false + #clock.power-of-two-quantum = true + #log.level = 2 + #cpu.zero.denormals = false + + core.daemon = true # listening for socket connections + core.name = pipewire-0 # core name and socket name + + ## Properties for the DSP configuration. + default.clock.rate = 48000 + default.clock.allowed-rates = [ 44100 48000 88200 96000 176400 192000 352800 384000 ] + #default.clock.quantum = 1024 + default.clock.min-quantum = 16 + #default.clock.max-quantum = 2048 + #default.clock.quantum-limit = 8192 + #default.video.width = 640 + #default.video.height = 480 + #default.video.rate.num = 25 + #default.video.rate.denom = 1 + # + #settings.check-quantum = false + #settings.check-rate = false + # + # These overrides are only applied when running in a vm. + vm.overrides = { + default.clock.min-quantum = 1024 + } +} + +context.spa-libs = { + # = + # + # Used to find spa factory names. It maps an spa factory name + # regular expression to a library name that should contain + # that factory. + # + audio.convert.* = audioconvert/libspa-audioconvert + api.alsa.* = alsa/libspa-alsa + api.v4l2.* = v4l2/libspa-v4l2 + api.libcamera.* = libcamera/libspa-libcamera + api.bluez5.* = bluez5/libspa-bluez5 + api.vulkan.* = vulkan/libspa-vulkan + api.jack.* = jack/libspa-jack + support.* = support/libspa-support + #videotestsrc = videotestsrc/libspa-videotestsrc + #audiotestsrc = audiotestsrc/libspa-audiotestsrc +} + +context.modules = [ + #{ name = + # [ args = { = ... } ] + # [ flags = [ [ ifexists ] [ nofail ] ] + #} + # + # Loads a module with the given parameters. + # If ifexists is given, the module is ignored when it is not found. + # If nofail is given, module initialization failures are ignored. + # + + # Uses realtime scheduling to boost the audio thread priorities. This uses + # RTKit if the user doesn't have permission to use regular realtime + # scheduling. + { name = libpipewire-module-rt + args = { + nice.level = -11 + #rt.prio = 88 + #rt.time.soft = -1 + #rt.time.hard = -1 + } + flags = [ ifexists nofail ] + } + + # The native communication protocol. + { name = libpipewire-module-protocol-native } + + # The profile module. Allows application to access profiler + # and performance data. It provides an interface that is used + # by pw-top and pw-profiler. + { name = libpipewire-module-profiler } + + # Allows applications to create metadata objects. It creates + # a factory for Metadata objects. + { name = libpipewire-module-metadata } + + # Creates a factory for making devices that run in the + # context of the PipeWire server. + { name = libpipewire-module-spa-device-factory } + + # Creates a factory for making nodes that run in the + # context of the PipeWire server. + { name = libpipewire-module-spa-node-factory } + + # Allows creating nodes that run in the context of the + # client. Is used by all clients that want to provide + # data to PipeWire. + { name = libpipewire-module-client-node } + + # Allows creating devices that run in the context of the + # client. Is used by the session manager. + { name = libpipewire-module-client-device } + + # The portal module monitors the PID of the portal process + # and tags connections with the same PID as portal + # connections. + { name = libpipewire-module-portal + flags = [ ifexists nofail ] + } + + # The access module can perform access checks and block + # new clients. + { name = libpipewire-module-access + args = { + # access.allowed to list an array of paths of allowed + # apps. + #access.allowed = [ + # /usr/bin/pipewire-media-session + #] + + # An array of rejected paths. + #access.rejected = [ ] + + # An array of paths with restricted access. + #access.restricted = [ ] + + # Anything not in the above lists gets assigned the + # access.force permission. + #access.force = flatpak + } + } + + # Makes a factory for wrapping nodes in an adapter with a + # converter and resampler. + { name = libpipewire-module-adapter } + + # Makes a factory for creating links between ports. + { name = libpipewire-module-link-factory } + + # Provides factories to make session manager objects. + { name = libpipewire-module-session-manager } + + # Use libcanberra to play X11 Bell + #{ name = libpipewire-module-x11-bell + # args = { + # #sink.name = "" + # #sample.name = "bell-window-system" + # #x11.display = null + # #x11.xauthority = null + # } + #} +] + +context.objects = [ + #{ factory = + # [ args = { = ... } ] + # [ flags = [ [ nofail ] ] + #} + # + # Creates an object from a PipeWire factory with the given parameters. + # If nofail is given, errors are ignored (and no object is created). + # + #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } + #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] } + #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } } + #{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } } + #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } } + #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } + + # A default dummy driver. This handles nodes marked with the "node.always-driver" + # property when no other driver is currently active. JACK clients need this. + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Dummy-Driver + node.group = pipewire.dummy + priority.driver = 20000 + } + } + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Freewheel-Driver + priority.driver = 19000 + node.group = pipewire.freewheel + node.freewheel = true + } + } + # This creates a new Source node. It will have input ports + # that you can link, to provide audio for this source. + #{ factory = adapter + # args = { + # factory.name = support.null-audio-sink + # node.name = "my-mic" + # node.description = "Microphone" + # media.class = "Audio/Source/Virtual" + # audio.position = "FL,FR" + # } + #} + + # This creates a single PCM source device for the given + # alsa device path hw:0. You can change source to sink + # to make a sink in the same way. + #{ factory = adapter + # args = { + # factory.name = api.alsa.pcm.source + # node.name = "alsa-source" + # node.description = "PCM Source" + # media.class = "Audio/Source" + # api.alsa.path = "hw:0" + # api.alsa.period-size = 1024 + # api.alsa.headroom = 0 + # api.alsa.disable-mmap = false + # api.alsa.disable-batch = false + # audio.format = "S16LE" + # audio.rate = 48000 + # audio.channels = 2 + # audio.position = "FL,FR" + # } + #} +] + +context.exec = [ + #{ path = [ args = "" ] } + # + # Execute the given program with arguments. + # + # You can optionally start the session manager here, + # but it is better to start it as a systemd service. + # Run the session manager with -h for options. + # + #{ path = "/usr/bin/pipewire-media-session" args = "" } + # + # You can optionally start the pulseaudio-server here as well + # but it is better to start it as a systemd service. + # It can be interesting to start another daemon here that listens + # on another address with the -a option (eg. -a tcp:4713). + # + #{ path = "/usr/bin/pipewire" args = "-c pipewire-pulse.conf" } +] diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..ecbc8ec --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,3 @@ +# Scripts installed to my ~/scripts + +Mostly quick-n-dirty ones! diff --git a/scripts/ai b/scripts/ai new file mode 100755 index 0000000..abcf490 --- /dev/null +++ b/scripts/ai @@ -0,0 +1,7 @@ +#!/usr/bin/env zsh + +if [ $(uname) = Darwin ]; then + exec hx.nvim-copilot-prompt "$@" +else + exec hx.hexai-prompt "$@" +fi diff --git a/scripts/brokenlinkfinder b/scripts/brokenlinkfinder new file mode 100644 index 0000000..7fe1576 --- /dev/null +++ b/scripts/brokenlinkfinder @@ -0,0 +1,73 @@ +#!/usr/bin/env ruby + +require 'net/http' +require 'uri' +require 'nokogiri' +require 'set' + +# Method to fetch and parse HTML from a URL +def fetch_html(url) + response = Net::HTTP.get_response(URI(url)) + response.body if response.is_a?(Net::HTTPSuccess) +rescue StandardError => e + puts "Error fetching #{url}: #{e.message}" + nil +end + +# Method to find and check links on a page +def check_links(url, domain) + html = fetch_html(url) + return unless html + + checked = Set.new + broken = Set.new + + document = Nokogiri::HTML(html) + links = document.css('a').map { |link| link['href'] }.compact + + internal_links = links.select do |link| + link.start_with?('/') || link.start_with?('./') || URI(link).host == domain + end + puts "Internal links: #{internal_links}" + + internal_links.uniq.each do |link| + full_url = link.start_with?('/') || link.start_with?('./') ? "#{url}#{link}" : link + full_url.sub!('./', '/') + next if checked.include?(full_url) + + broken << full_url unless check_link(full_url) + checked << full_url + end + + broken +end + +# Method to check if a link is broken +def check_link(url) + uri = URI(url) + response = Net::HTTP.get_response(uri) + + if response.is_a?(Net::HTTPSuccess) + puts "Working link: #{url}" + true + else + puts "Broken link: #{url} (HTTP #{response.code})" + false + end +rescue StandardError => e + puts "Error checking #{url}: #{e.message}" + false +end + +# Main program +if ARGV.length != 1 + puts 'Usage: ruby brokenlinkfinder.rb ' + exit +end + +start_url = ARGV.first +domain = URI(start_url).host + +check_links(start_url, domain).each do |broken| + puts "Broken: #{broken}" +end diff --git a/scripts/gvim b/scripts/gvim new file mode 100755 index 0000000..5777a7c --- /dev/null +++ b/scripts/gvim @@ -0,0 +1,7 @@ +#!/bin/bash +# Hack so qutebrowser starts an editor (Helix) in a new ghostty terminal. + +declare -r FILE_PATH="$2" +#echo "$@" > /tmp/params.txt + +ghostty -e "hx $FILE_PATH" diff --git a/scripts/hx.aichat-prompt b/scripts/hx.aichat-prompt new file mode 100755 index 0000000..4cafcf5 --- /dev/null +++ b/scripts/hx.aichat-prompt @@ -0,0 +1,9 @@ +#!/usr/bin/env zsh + +declare -xr INSTRUCTIONS='Answer only. If it is code, code only without code-block at the beginning and the end.' + +if [[ $# -eq 0 ]]; then + aichat "$(hx.prompt). $INSTRUCTIONS" +else + aichat "$@. $INSTRUCTIONS" +fi diff --git a/scripts/hx.chatgpt-prompt b/scripts/hx.chatgpt-prompt new file mode 100755 index 0000000..e4b6047 --- /dev/null +++ b/scripts/hx.chatgpt-prompt @@ -0,0 +1,3 @@ +#!/usr/bin/env zsh + +chatgpt "$(hx.prompt). Answer only. If it is code, code only without code-block at the beginning and the end." diff --git a/scripts/hx.goformatter b/scripts/hx.goformatter new file mode 100755 index 0000000..028fbb2 --- /dev/null +++ b/scripts/hx.goformatter @@ -0,0 +1,3 @@ +#!/bin/sh + +goimports | gofumpt diff --git a/scripts/hx.hexai-prompt b/scripts/hx.hexai-prompt new file mode 100755 index 0000000..ef413c0 --- /dev/null +++ b/scripts/hx.hexai-prompt @@ -0,0 +1,9 @@ +#!/usr/bin/env zsh + +declare -xr INSTRUCTIONS='Answer only. If it is code, code only without code-block at the beginning and the end.' + +if [[ $# -eq 0 ]]; then + hexai "$(hx.prompt). $INSTRUCTIONS" 2>/dev/null +else + hexai "$@. $INSTRUCTIONS" 2>/dev/null +fi diff --git a/scripts/hx.nvim-copilot-prompt b/scripts/hx.nvim-copilot-prompt new file mode 100755 index 0000000..dcb2837 --- /dev/null +++ b/scripts/hx.nvim-copilot-prompt @@ -0,0 +1,32 @@ +#!/usr/bin/env zsh + +declare -r STDIN_FILE=~/.copilot_prompt_stdin.txt +declare -r INPUT_FILE=~/.copilot_chat_input.txt +declare -r OUTPUT_FILE=~/.copilot_chat_output.txt +declare INPUT_PROMPT + +if [ -f $OUTPUT_FILE.done ]; then + rm $OUTPUT_FILE.done +fi +cat > $STDIN_FILE &>/dev/null + +if [ $# -eq 0 ]; then + INPUT_PROMPT="$(hx.prompt)" +else + INPUT_PROMPT="$@" +fi + +cat < $INPUT_FILE +$INPUT_PROMPT for the following: + +$(cat $STDIN_FILE) + +If the result is code, print out the code only, don't print the \`\`\`-markers around the code block. +INPUT_FILE + +tmux split-window -v "nvim +':CopilotAsk'; mv $OUTPUT_FILE $OUTPUT_FILE.done" + +while [ ! -f "$OUTPUT_FILE.done" ]; do + sleep 0.2 +done +sed -n '/^## Copilot/,/^## User/ { /^## Copilot/d; /\[file:/d; /^## User/d; p; }' $OUTPUT_FILE.done diff --git a/scripts/hx.prompt b/scripts/hx.prompt new file mode 100755 index 0000000..8dd14dd --- /dev/null +++ b/scripts/hx.prompt @@ -0,0 +1,14 @@ +#!/usr/bin/env zsh + +declare -r REPLY_FILE=~/.hx-prompt-reply +if [ -f "$REPLY_FILE" ]; then + rm "$REPLY_FILE" +fi + +tmux split-window -v "touch $REPLY_FILE.tmp; hx $REPLY_FILE.tmp; mv $REPLY_FILE.tmp $REPLY_FILE" + +while [ ! -f "$REPLY_FILE" ]; do + sleep 0.2 +done + +cat "$REPLY_FILE" diff --git a/scripts/randomnote.rb b/scripts/randomnote.rb new file mode 100644 index 0000000..b0c1b49 --- /dev/null +++ b/scripts/randomnote.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby + +NOTES_DIR = "#{ENV['HOME']}/git/foo.zone-content/gemtext/notes" +BOOK_PATH = "#{ENV['HOME']}/Buecher/Diverse/Search-Inside-Yourself.txt" +MIN_PERCENTAGE = 80 +MIN_LENGTH = 10 + +class String + CLEAN_PATTERN = [ + /\d\d\d-\d\d-\d\d/, /[^A-Za-z0-9!.;,?'" @]/, + /http.?:\/\/\S+/, /\S+\.gmi/, /^\./, /^\d/, + ] + def clean + CLEAN_PATTERN.each {|p| gsub! p, '' } + gsub(/\s+/, ' ').strip + end + def letter_percentage?(threshold) = threshold <= (100 * count("A-Za-z")) / length +end + +begin + srand Random.new_seed + puts File.read((Dir["#{NOTES_DIR}/*.gmi"] + [BOOK_PATH]).shuffle.sample) + .split("\n") + .map(&:clean) + .select{ |l| l.length >= MIN_LENGTH } + .reject{ |l| l.match?(/(Published at|EMail your comments)/) } + .reject{ |l| l.match?(/'|book notes/) } + .select{ |l| l.letter_percentage?(MIN_PERCENTAGE) } + .shuffle.sample +end diff --git a/scripts/taskwarriorfeeder.rb b/scripts/taskwarriorfeeder.rb new file mode 100644 index 0000000..117ca69 --- /dev/null +++ b/scripts/taskwarriorfeeder.rb @@ -0,0 +1,220 @@ +#!/usr/bin/env ruby + +require 'optparse' +require 'digest' +require 'json' +require 'set' + +PERSONAL_TIMESPAN_D = 30 +WORK_TIMESPAN_D = 14 +WORKTIME_DIR = "#{ENV['HOME']}/git/worktime".freeze +GOS_DIR = "#{ENV['HOME']}/.gosdir".freeze +MAX_PENDING_RANDOM_TASKS = 42 + +def maybe? + [true, false].sample +end + +def run_from_personal_device? + `uname`.chomp == 'Linux' +end + +def random_count + MAX_PENDING_RANDOM_TASKS - `task status:pending +random -work count`.to_i +end + +def notes(notes_dirs, prefix, dry) + notes_dirs.each do |notes_dir| + Dir["#{notes_dir}/#{prefix}-*"].each do |notes_file| + match = File.read(notes_file).strip.match(/(?\d+)? *(?[A-Z]?[a-z,-:]+) *(?.*)/m) + next unless match + + tags = match[:tag].split(',') + [prefix] + due = if match[:due].nil? + tags.include?('track') ? 'eow' : "#{rand(0..PERSONAL_TIMESPAN_D)}d" + else + "#{match[:due]}d" + end + yield tags, match[:body], due + File.delete(notes_file) unless dry + end + end +end + +def random_quote(md_file) + tag = File.basename(md_file, '.md').downcase + lines = File.readlines(md_file) + + match = lines.first.match(/\((\d+)\)/) + timespan = run_from_personal_device? ? PERSONAL_TIMESPAN_D : WORK_TIMESPAN_D + timespan = match ? match[1].to_i : timespan + + quote = lines.select { |l| l.start_with? '*' }.map { |l| l.sub(/\* +/, '') }.sample + tags = [tag, 'random'] + tags << 'work' if maybe? and maybe? + yield tags, quote.chomp, "#{rand(0..timespan)}d" +end + +def run!(cmd, dry) + puts cmd + return if dry + + puts `#{cmd}` + raise "Command '#{cmd}' failed with #{$?.exitstatus}" if $?.exitstatus != 0 +rescue StandardError => e + puts "Error running command '#{cmd}': #{e.message}" + exit 1 +end + +def skill_add!(skills_str, dry) + skills_file = "#{WORKTIME_DIR}/skills.txt" + skills_str.split(',').map(&:strip).each { skills[_1.to_s.downcase] = _1 } + + File.foreach(skills_file) do |line| + line.chomp! + skills[line.downcase] = line + end + File.open("#{skills_file}.tmp", 'w') do |file| + skills.each_value { |skill| file.puts(skill) } + end + return if dry + + File.rename("#{skills_file}.tmp", skills_file) +end + +def worklog_add!(tag, quote, due, dry) + file = "#{WORKTIME_DIR}/wl-#{Time.now.to_i}n.txt" + content = "#{due.chomp 'd'} #{tag} #{quote}" + + puts "#{file}: #{content}" + File.write(file, content) unless dry +end + +# Queue to Gos https://codeberg.org/snonux/gos +def gos_queue!(tags, message, dry) + tags.delete('share') + platforms = [] + %w[linkedin li mastodon ma noop no].select { tags.include?(_1) }.each do |platform| + platforms << platform + tags.delete(platform) + end + unless platforms.empty? + platforms = %w[share] + platforms + tags = ["#{platforms.join(':')}"] + tags + end + tags = %w[share] + tags if tags.size == 1 && !tags.first.start_with?('share') + tags_str = tags.join(',') + + message = "#{tags_str.empty? ? '' : "#{tags_str} "}#{message}" + file = "#{GOS_DIR}/#{Digest::MD5.hexdigest(message)}.txt" + puts "Writing #{file} with #{message}" + File.write(file, message) unless dry +end + +def task_add!(tags, quote, due, dry) + if quote.empty? + puts 'Not adding task with empty quote' + return + end + if tags.include?('tr') + tags << 'track' + tags.delete('tr') + end + tags << 'work' if tags.include?('mentoring') || tags.include?('productivity') + tags.uniq! + + if tags.include?('task') + run! "task #{quote}", dry + else + project = tags.find { |t| t =~ /^[A-Z]/ } + project = if project.nil? + '' + else + tags.delete(project) + " project:#{project.downcase}" + end + priority = tags.include?('high') ? 'H' : '' + run! "task add due:#{due} priority:#{priority}#{project} +#{tags.join(' +')} '#{quote.gsub("'", '"')}'", dry + end +end + +def task_schedule!(id, due, dry) + run! "timeout 5s task modify #{id} due:#{due}", dry +end + +def filter_tasks(filter) + lines = `task #{filter} 2>/dev/null`.split("\n").drop(1) + lines.pop + lines.map { |foo| foo.split.first }.each do |id| + yield id if id.to_i.positive? + end +end + +begin + opts = { + random_dir: "#{ENV['HOME']}/Notes/random", + notes_dirs: "#{ENV['HOME']}/Notes,#{ENV['HOME']}/Notes/Quicklogger,#{ENV['HOME']}/git/worktime", + dry_run: false, + no_random: false + } + + opt_parser = OptionParser.new do |o| + o.banner = 'Usage: ruby taskwarriorfeeder.rb [options]' + o.on('-d', '--random-dir DIR', 'The random quotes directory') { |v| opts[:random_dir] = v } + o.on('-n', '--notes-dirs DIR1,DIR2,...', 'The notes directories') { |v| opts[:notes_dirs] = v } + o.on('-D', '--dry-run', 'Dry run mode') { opts[:dry_run] = true } + o.on('-R', '--no-randoms', 'No random entries') { opts[:no_random] = true } + o.on_tail('-h', '--help', 'Show this help message and exit') { puts o and exit } + end + + opt_parser.parse!(ARGV) + + (run_from_personal_device? ? %w[ql pl] : %w[wl]).each do |prefix| + notes(opts[:notes_dirs].split(','), prefix, opts[:dry_run]) do |tags, note, due| + if tags.include?('skill') || tags.include?('skills') + skill_add!(note, opts[:dry_run]) + elsif tags.include? 'work' + worklog_add!(:log, note, due, opts[:dry_run]) + elsif tags.any? { |tag| tag.start_with?('share') } + gos_queue!(tags, note, opts[:dry_run]) + else + task_add!(tags, note, due, opts[:dry_run]) + end + end + end + + unless opts[:no_random] + count = random_count + + Dir["#{opts[:random_dir]}/*.md"].shuffle.each do |md_file| + next unless maybe? + break if count <= 0 + + random_quote(md_file) do |tags, quote, due| + task_add!(tags, quote, due, opts[:dry_run]) + count -= 1 + end + end + end + + if Dir.exist?(GOS_DIR) && !opts[:dry_run] + Dir["#{WORKTIME_DIR}/tw-gos-*.json"].each do |tw_gos| + JSON.parse(File.read(tw_gos)).each do |entry| + gos_queue!(entry['tags'], entry['description'], opts[:dry_run]) + end + File.delete(tw_gos) + rescue StandardError => e + puts e + end + end + + # Schedule track tasks to end of week + filter_tasks('+track due:') do |id| + task_schedule!(id, 'eow', opts[:dry_run]) + end + + # Randomly schedule other unscheduled tasks + filter_tasks('-unsched -nosched -meeting -track due:') do |id| + task_schedule!(id, "#{rand(0..PERSONAL_TIMESPAN_D)}d", opts[:dry_run]) + end +end diff --git a/scripts/tmux-edit-send b/scripts/tmux-edit-send new file mode 100755 index 0000000..05fe62d --- /dev/null +++ b/scripts/tmux-edit-send @@ -0,0 +1,246 @@ +#!/usr/bin/env bash +set -u -o pipefail + +LOG_ENABLED=0 +log_file="${TMPDIR:-/tmp}/tmux-edit-send.log" +log() { + if [ "$LOG_ENABLED" -eq 1 ]; then + printf '%s\n' "$*" >> "$log_file" + fi +} + +# Read the target pane id from a temp file created by tmux binding. +read_target_from_file() { + local file_path="$1" + local pane_id + if [ -n "$file_path" ] && [ -f "$file_path" ]; then + pane_id="$(sed -n '1p' "$file_path" | tr -d '[:space:]')" + # Ensure pane ID has % prefix + if [ -n "$pane_id" ] && [[ "$pane_id" != %* ]]; then + pane_id="%${pane_id}" + fi + printf '%s' "$pane_id" + fi +} + +# Read the target pane id from tmux environment if present. +read_target_from_env() { + local env_line pane_id + env_line="$(tmux show-environment -g TMUX_EDIT_TARGET 2>/dev/null || true)" + case "$env_line" in + TMUX_EDIT_TARGET=*) + pane_id="${env_line#TMUX_EDIT_TARGET=}" + # Ensure pane ID has % prefix + if [ -n "$pane_id" ] && [[ "$pane_id" != %* ]] && [[ "$pane_id" =~ ^[0-9]+$ ]]; then + pane_id="%${pane_id}" + fi + printf '%s' "$pane_id" + ;; + esac +} + +# Resolve the target pane id, falling back to the last pane. +resolve_target_pane() { + local candidate="$1" + local current_pane last_pane + + current_pane="$(tmux display-message -p "#{pane_id}" 2>/dev/null || true)" + log "current pane=${current_pane:-}" + + # Ensure candidate has % prefix if it's a pane ID + if [ -n "$candidate" ] && [[ "$candidate" =~ ^[0-9]+$ ]]; then + candidate="%${candidate}" + log "normalized candidate to $candidate" + fi + + if [ -n "$candidate" ] && [[ "$candidate" == *"#{"* ]]; then + log "format target detected, clearing" + candidate="" + fi + if [ -z "$candidate" ]; then + candidate="$(tmux display-message -p "#{last_pane}" 2>/dev/null || true)" + log "using last pane as fallback: $candidate" + elif [ "$candidate" = "$current_pane" ]; then + last_pane="$(tmux display-message -p "#{last_pane}" 2>/dev/null || true)" + if [ -n "$last_pane" ]; then + candidate="$last_pane" + log "candidate was current, using last pane: $candidate" + fi + fi + printf '%s' "$candidate" +} + +# Capture the latest multi-line prompt content from the pane. +capture_prompt_text() { + local target="$1" + tmux capture-pane -p -t "$target" -S -2000 2>/dev/null | awk ' + function trim_box(line) { + sub(/^ *│ ?/, "", line) + sub(/ *│ *$/, "", line) + sub(/[[:space:]]+$/, "", line) + return line + } + /^ *│ *→/ && index($0,"INSERT")==0 && index($0,"Add a follow-up")==0 { + if (text != "") last = text + text = "" + capture = 1 + line = $0 + sub(/^.*→ ?/, "", line) + line = trim_box(line) + if (line != "") text = line + next + } + capture { + if ($0 ~ /^ *└/) { + capture = 0 + if (text != "") last = text + next + } + if ($0 ~ /^ *│/ && index($0,"INSERT")==0 && index($0,"Add a follow-up")==0) { + line = trim_box($0) + if (line != "") { + if (text != "") text = text " " line + else text = line + } + } + } + END { + if (text != "") last = text + if (last != "") print last + } + ' +} + +# Write captured prompt text into the temp file if available. +prefill_tmpfile() { + local tmpfile="$1" + local prompt_text="$2" + if [ -n "$prompt_text" ]; then + printf '%s\n' "$prompt_text" > "$tmpfile" + fi +} + +# Ensure the target pane exists before sending keys. +validate_target_pane() { + local target="$1" + local pane target_found + if [ -z "$target" ]; then + log "error: no target pane determined" + echo "Could not determine target pane." >&2 + return 1 + fi + target_found=0 + log "validate: looking for target='$target' in all panes:" + for pane in $(tmux list-panes -a -F "#{pane_id}" 2>/dev/null || true); do + log "validate: checking pane='$pane'" + if [ "$pane" = "$target" ]; then + target_found=1 + log "validate: MATCH FOUND!" + break + fi + done + if [ "$target_found" -ne 1 ]; then + log "error: target pane not found: $target" + echo "Target pane not found: $target" >&2 + return 1 + fi + log "validate: target pane validated successfully" +} + +# Send temp file contents to the target pane line by line. +send_content() { + local target="$1" + local tmpfile="$2" + local prompt_text="$3" + local first_line=1 + local line + log "send_content: target=$target, prompt_text='$prompt_text'" + while IFS= read -r line || [ -n "$line" ]; do + log "send_content: read line='$line'" + if [ "$first_line" -eq 1 ] && [ -n "$prompt_text" ]; then + if [[ "$line" == "$prompt_text"* ]]; then + local old_line="$line" + line="${line#"$prompt_text"}" + log "send_content: stripped prompt, was='$old_line' now='$line'" + fi + fi + first_line=0 + log "send_content: sending line='$line'" + tmux send-keys -t "$target" -l "$line" + tmux send-keys -t "$target" Enter + done < "$tmpfile" + log "sent content to $target" +} + +# Main entry point. +main() { + local target_file="${1:-}" + local target + local editor="${EDITOR:-vi}" + local tmpfile + local prompt_text + + log "=== tmux-edit-send starting ===" + log "target_file=$target_file" + log "EDITOR=$editor" + + target="$(read_target_from_file "$target_file" || true)" + if [ -n "$target" ]; then + log "file target=${target:-}" + rm -f "$target_file" + fi + if [ -z "$target" ]; then + target="${TMUX_EDIT_TARGET:-}" + fi + log "env target=${target:-}" + if [ -z "$target" ]; then + target="$(read_target_from_env || true)" + fi + log "tmux env target=${target:-}" + target="$(resolve_target_pane "$target")" + log "fallback target=${target:-}" + + tmpfile="$(mktemp)" + log "created tmpfile=$tmpfile" + if [ ! -f "$tmpfile" ]; then + log "ERROR: mktemp failed to create file" + echo "ERROR: mktemp failed" >&2 + exit 1 + fi + mv "$tmpfile" "${tmpfile}.md" 2>&1 | while read -r line; do log "mv output: $line"; done + tmpfile="${tmpfile}.md" + log "renamed to tmpfile=$tmpfile" + if [ ! -f "$tmpfile" ]; then + log "ERROR: tmpfile does not exist after rename" + echo "ERROR: tmpfile rename failed" >&2 + exit 1 + fi + trap 'rm -f "$tmpfile"' EXIT + + log "capturing prompt text from target=$target" + prompt_text="$(capture_prompt_text "$target")" + log "captured prompt_text='$prompt_text'" + prefill_tmpfile "$tmpfile" "$prompt_text" + log "prefilled tmpfile" + + log "launching editor: $editor $tmpfile" + "$editor" "$tmpfile" + local editor_exit=$? + log "editor exited with status $editor_exit" + + if [ ! -s "$tmpfile" ]; then + log "empty file, nothing sent" + exit 0 + fi + + log "tmpfile contents:" + log "$(cat "$tmpfile")" + + log "validating target pane" + validate_target_pane "$target" + log "sending content to target=$target" + send_content "$target" "$tmpfile" "$prompt_text" + log "=== tmux-edit-send completed ===" +} + +main "$@" diff --git a/scripts/wol-f3s b/scripts/wol-f3s new file mode 100755 index 0000000..263763b --- /dev/null +++ b/scripts/wol-f3s @@ -0,0 +1,86 @@ +#!/bin/bash +# Wake-on-LAN and shutdown script for f3s cluster (f0, f1, f2) +# +# Usage: +# wol-f3s # Wake all three Beelinks +# wol-f3s f0 # Wake only f0 +# wol-f3s f1 # Wake only f1 +# wol-f3s f2 # Wake only f2 +# wol-f3s shutdown # Shutdown all three Beelinks + +# MAC addresses +F0_MAC="e8:ff:1e:d7:1c:ac" # f0 (192.168.1.130) +F1_MAC="e8:ff:1e:d7:1e:44" # f1 (192.168.1.131) +F2_MAC="e8:ff:1e:d7:1c:a0" # f2 (192.168.1.132) + +# IP addresses +F0_IP="192.168.1.130" +F1_IP="192.168.1.131" +F2_IP="192.168.1.132" + +# SSH user +SSH_USER="paul" + +# Broadcast address for your LAN +BROADCAST="192.168.1.255" + +wake() { + local name=$1 + local mac=$2 + + if [[ "$mac" == "XX:XX:XX:XX:XX:XX" ]]; then + echo "⚠️ $name MAC address not configured yet" + return 1 + fi + + echo "Sending WoL packet to $name ($mac)..." + wol -i "$BROADCAST" "$mac" +} + +shutdown_host() { + local name=$1 + local ip=$2 + + echo "Shutting down $name ($ip)..." + ssh -o ConnectTimeout=5 "$SSH_USER@$ip" "doas poweroff" 2>/dev/null && \ + echo " ✓ Shutdown command sent to $name" || \ + echo " ✗ Failed to reach $name (already down?)" +} + +ACTION="${1:-all}" + +case "$ACTION" in + f0) + wake "f0" "$F0_MAC" + ;; + f1) + wake "f1" "$F1_MAC" + ;; + f2) + wake "f2" "$F2_MAC" + ;; + all|"") + wake "f0" "$F0_MAC" + wake "f1" "$F1_MAC" + wake "f2" "$F2_MAC" + ;; + shutdown|poweroff|down) + # This is to mute Gogios alerts for a day + ssh rex@blowfish.buetow.org touch /tmp/f3s_taken_down + ssh rex@fishfinger.buetow.org touch /tmp/f3s_taken_down + shutdown_host "f0" "$F0_IP" + shutdown_host "f1" "$F1_IP" + shutdown_host "f2" "$F2_IP" + echo "" + echo "✓ Shutdown commands sent to all machines." + exit 0 + ;; + *) + echo "Usage: $0 [f0|f1|f2|all|shutdown]" + exit 1 + ;; +esac + +echo "" +echo "✓ WoL packets sent. Machines should boot in a few seconds." +echo " Wait ~30 seconds, then try: ssh paul@192.168.1.130" diff --git a/signature b/signature new file mode 100644 index 0000000..8031719 --- /dev/null +++ b/signature @@ -0,0 +1,2 @@ +Paul Buetow +paul.buetow.org diff --git a/ssh/config b/ssh/config new file mode 100644 index 0000000..5824103 --- /dev/null +++ b/ssh/config @@ -0,0 +1,26 @@ +#ControlPath ~/.ssh/cp-%C +#ControlMaster auto +#UseKeychain yes +AddKeysToAgent yes +ControlPersist 60m +#StrictHostKeyChecking no + +Host blowfish.buetow.org +User rex +Port 2 + +Host fishfinger.buetow.org +User rex +Port 2 + +Host *.aws.buetow.org +User ec2-user +Port 22 + +Host *.buetow.org +Port 2 + +Host git-server +HostName r0 +Port 30022 +User git diff --git a/sway/config.d/keyboard.conf b/sway/config.d/keyboard.conf new file mode 100644 index 0000000..cf91046 --- /dev/null +++ b/sway/config.d/keyboard.conf @@ -0,0 +1,6 @@ +input "type:keyboard" { + xkb_layout us,gb,de + xkb_options grp:win_space_toggle +} + +input * xkb_options "caps:escape" diff --git a/tmux/tmux.conf b/tmux/tmux.conf new file mode 100644 index 0000000..51c20a8 --- /dev/null +++ b/tmux/tmux.conf @@ -0,0 +1,38 @@ +source ~/.config/tmux/tmux.local.conf + +set-option -g allow-rename off +set-option -g history-limit 100000 +set-option -s escape-time 0 +set-option -g set-titles on + +set-window-option -g mode-keys vi + +bind-key h select-pane -L +bind-key j select-pane -D +bind-key k select-pane -U +bind-key l select-pane -R + +bind-key H resize-pane -L 5 +bind-key J resize-pane -D 5 +bind-key K resize-pane -U 5 +bind-key L resize-pane -R 5 + +bind-key g popup -E -w 95% -h 95% -d '#{pane_current_path}' lazygit +bind-key f popup -E -w 95% -h 95% -d '#{pane_current_path}' ranger +bind-key e run-shell -b "tmux display-message -p '#{pane_id}' > /tmp/tmux-edit-target-#{client_pid} \; tmux popup -E -w 90% -h 35% -x 5% -y 65% -d '#{pane_current_path}' \"~/scripts/tmux-edit-send /tmp/tmux-edit-target-#{client_pid}\"" +bind-key N popup -E -w 95% -h 95% hx ~/Notes +bind-key t popup -E -w 95% -h 95% hx fish + +# bind-key b break-pane -d +bind-key c new-window -c '#{pane_current_path}' +bind-key F new-window -n "session-switcher" "tmux list-sessions | fzf | cut -d: -f1 | xargs tmux switch-client -t" +bind-key p setw synchronize-panes off +bind-key P setw synchronize-panes on +bind-key r source-file ~/.config/tmux/tmux.conf \; display-message "~/.config/tmux/tmux.conf reloaded" +bind-key T choose-tree + +set-option -g pane-active-border-style fg=magenta,bold + +set -g status-right '#{@hexai_status} #[fg=colour8]| %H:%M' +set -g status-right-length 120 +set-environment -g HEXAI_TMUX_STATUS_THEME white-on-purple diff --git a/tmux/tmux.local.conf b/tmux/tmux.local.conf new file mode 100644 index 0000000..adb6294 --- /dev/null +++ b/tmux/tmux.local.conf @@ -0,0 +1,2 @@ +bind-key -T copy-mode-vi 'v' send -X begin-selection +bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel diff --git a/vale.ini b/vale.ini new file mode 100644 index 0000000..3b39678 --- /dev/null +++ b/vale.ini @@ -0,0 +1,6 @@ +StylesPath = styles +MinAlertLevel = suggestion +Packages = Microsoft, proselint + +[*] +BasedOnStyles = Vale, Microsoft, proselint diff --git a/waybar/config.jsonc b/waybar/config.jsonc new file mode 100644 index 0000000..db2aeea --- /dev/null +++ b/waybar/config.jsonc @@ -0,0 +1,194 @@ +// -*- mode: jsonc -*- +{ + // "layer": "top", // Waybar at top layer + // "position": "bottom", // Waybar position (top|bottom|left|right) + "height": 20, // Waybar height (to be removed for auto height) + // "width": 1280, // Waybar width + "spacing": 1, // Gaps between modules (4px) + // Choose the order of the modules + "modules-left": [ + "sway/workspaces", + "sway/mode", + "sway/scratchpad" + ], + "modules-center": [ + ], + "modules-right": [ + "idle_inhibitor", + "pulseaudio", + "network", + "power-profiles-daemon", + "temperature", + "sway/language", + "battery", + "clock", + "tray" + ], + // Modules configuration + // "sway/workspaces": { + // "disable-scroll": true, + // "all-outputs": true, + // "warp-on-scroll": false, + // "format": "{name}: {icon}", + // "format-icons": { + // "1": "", + // "2": "", + // "3": "", + // "4": "", + // "5": "", + // "urgent": "", + // "focused": "", + // "default": "" + // } + // }, + "keyboard-state": { + "numlock": true, + "capslock": true, + "format": "{name} {icon}", + "format-icons": { + "locked": "", + "unlocked": "" + } + }, + "sway/mode": { + "format": "{}" + }, + "sway/scratchpad": { + "format": "{icon} {count}", + "show-empty": false, + "format-icons": ["", ""], + "tooltip": true, + "tooltip-format": "{app}: {title}" + }, + "mpd": { + "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {volume}% ", + "format-disconnected": "Disconnected ", + "format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ", + "unknown-tag": "N/A", + "interval": 5, + "consume-icons": { + "on": " " + }, + "random-icons": { + "off": " ", + "on": " " + }, + "repeat-icons": { + "on": " " + }, + "single-icons": { + "on": "1 " + }, + "state-icons": { + "paused": "", + "playing": "" + }, + "tooltip-format": "MPD (connected)", + "tooltip-format-disconnected": "MPD (disconnected)" + }, + "idle_inhibitor": { + "format": "{icon}", + "format-icons": { + "activated": "", + "deactivated": "" + } + }, + "tray": { + // "icon-size": 21, + "spacing": 10 + }, + "clock": { + // "timezone": "America/New_York", + "tooltip-format": "{:%Y %B}\n{calendar}", + "format-alt": "{:%Y-%m-%d}" + }, + "cpu": { + "format": "{usage}% ", + "tooltip": false + }, + "memory": { + "format": "{}% " + }, + "temperature": { + // "thermal-zone": 2, + // "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input", + "critical-threshold": 80, + // "format-critical": "{temperatureC}°C {icon}", + "format": "{temperatureC}°C {icon}", + "format-icons": ["", "", ""] + }, + "backlight": { + // "device": "acpi_video1", + "format": "{percent}% {icon}", + "format-icons": ["🌑", "🌘", "🌗", "🌖", "🌕"] + }, + "battery": { + "states": { + // "good": 95, + "warning": 30, + "critical": 15 + }, + "format": "{capacity}% {icon}", + "format-full": "{capacity}% {icon}", + "format-charging": "{capacity}% ", + "format-plugged": "{capacity}% ", + "format-alt": "{time} {icon}", + // "format-good": "", // An empty format will hide the module + // "format-full": "", + "format-icons": ["", "", "", "", ""] + }, + "battery#bat2": { + "bat": "BAT2" + }, + "power-profiles-daemon": { + "format": "{icon}", + "tooltip-format": "Power profile: {profile}\nDriver: {driver}", + "tooltip": true, + "format-icons": { + "default": "", + "performance": "", + "balanced": "", + "power-saver": "" + } + }, + "network": { + // "interface": "wlp2*", // (Optional) To force the use of this interface + "format-wifi": "{essid} ({signalStrength}%) ", + "format-ethernet": "{ipaddr}/{cidr} ", + "tooltip-format": "{ifname} via {gwaddr} ", + "format-linked": "{ifname} (No IP) ", + "format-disconnected": "Disconnected ⚠", + "format-alt": "{ifname}: {ipaddr}/{cidr}" + }, + "pulseaudio": { + // "scroll-step": 1, // %, can be a float + "format": "{volume}% {icon} {format_source}", + "format-bluetooth": "{volume}% {icon} {format_source}", + "format-bluetooth-muted": " {icon} {format_source}", + "format-muted": " {format_source}", + "format-source": "{volume}% ", + "format-source-muted": "", + "format-icons": { + "headphone": "", + "hands-free": "", + "headset": "", + "phone": "", + "portable": "", + "car": "", + "default": ["", "", ""] + }, + "on-click": "pavucontrol" + }, + "custom/media": { + "format": "{icon} {}", + "return-type": "json", + "max-length": 40, + "format-icons": { + "spotify": "", + "default": "🎜" + }, + "escape": true, + "exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder + // "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name + } +} diff --git a/waybar/style.css b/waybar/style.css new file mode 100644 index 0000000..e031037 --- /dev/null +++ b/waybar/style.css @@ -0,0 +1,326 @@ +* { + font-family: 'Noto Sans Mono', 'Font Awesome 6 Free', 'Font Awesome 6 Brands', monospace; + font-size: 13px; +} + +window#waybar { + background-color: rgba(43, 48, 59, 0.5); + border-bottom: 3px solid rgba(100, 114, 125, 0.5); + color: #ffffff; + transition-property: background-color; + transition-duration: .5s; +} + +window#waybar.hidden { + opacity: 0.2; +} + +/* +window#waybar.empty { + background-color: transparent; +} +window#waybar.solo { + background-color: #FFFFFF; +} +*/ + +window#waybar.termite { + background-color: #3F3F3F; +} + +window#waybar.chromium { + background-color: #000000; + border: none; +} + +button { + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -3px transparent; + /* Avoid rounded borders under each button name */ + border: none; + border-radius: 0; +} + +/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ +button:hover { + background: inherit; + box-shadow: inset 0 -3px #ffffff; +} + +/* you can set a style on hover for any module like this */ +#pulseaudio:hover { + background-color: #a37800; +} + +#workspaces button { + padding: 0 5px; + background-color: transparent; + color: #ffffff; +} + +#workspaces button:hover { + background: rgba(0, 0, 0, 0.2); +} + +#workspaces button.focused { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; +} + +#workspaces button.urgent { + background-color: #eb4d4b; +} + +#mode { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; +} + +#clock, +#battery, +#cpu, +#memory, +#disk, +#temperature, +#backlight, +#network, +#pulseaudio, +#wireplumber, +#custom-media, +#tray, +#mode, +#idle_inhibitor, +#scratchpad, +#power-profiles-daemon, +#mpd { + padding: 0 10px; + color: #ffffff; +} + +#window, +#workspaces { + margin: 0 4px; +} + +/* If workspaces is the leftmost module, omit left margin */ +.modules-left > widget:first-child > #workspaces { + margin-left: 0; +} + +/* If workspaces is the rightmost module, omit right margin */ +.modules-right > widget:last-child > #workspaces { + margin-right: 0; +} + +#clock { + background-color: #64727D; +} + +#battery { + background-color: #ffffff; + color: #000000; +} + +#battery.charging, #battery.plugged { + color: #ffffff; + background-color: #26A65B; +} + +@keyframes blink { + to { + background-color: #ffffff; + color: #000000; + } +} + +/* Using steps() instead of linear as a timing function to limit cpu usage */ +#battery.critical:not(.charging) { + background-color: #f53c3c; + color: #ffffff; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: steps(12); + animation-iteration-count: infinite; + animation-direction: alternate; +} + +#power-profiles-daemon { + padding-right: 15px; +} + +#power-profiles-daemon.performance { + background-color: #f53c3c; + color: #ffffff; +} + +#power-profiles-daemon.balanced { + background-color: #2980b9; + color: #ffffff; +} + +#power-profiles-daemon.power-saver { + background-color: #2ecc71; + color: #000000; +} + +label:focus { + background-color: #000000; +} + +#cpu { + background-color: #2ecc71; + color: #000000; +} + +#memory { + background-color: #9b59b6; +} + +#disk { + background-color: #964B00; +} + +#backlight { + background-color: #90b1b1; +} + +#network { + background-color: #2980b9; +} + +#network.disconnected { + background-color: #f53c3c; +} + +#pulseaudio { + background-color: #f1c40f; + color: #000000; +} + +#pulseaudio.muted { + background-color: #90b1b1; + color: #2a5c45; +} + +#wireplumber { + background-color: #fff0f5; + color: #000000; +} + +#wireplumber.muted { + background-color: #f53c3c; +} + +#custom-media { + background-color: #66cc99; + color: #2a5c45; + min-width: 100px; +} + +#custom-media.custom-spotify { + background-color: #66cc99; +} + +#custom-media.custom-vlc { + background-color: #ffa000; +} + +#temperature { + background-color: #f0932b; +} + +#temperature.critical { + background-color: #eb4d4b; +} + +#tray { + background-color: #2980b9; +} + +#tray > .passive { + -gtk-icon-effect: dim; +} + +#tray > .needs-attention { + -gtk-icon-effect: highlight; + background-color: #eb4d4b; +} + +#idle_inhibitor { + background-color: #2d3436; +} + +#idle_inhibitor.activated { + background-color: #ecf0f1; + color: #2d3436; +} + +#mpd { + background-color: #66cc99; + color: #2a5c45; +} + +#mpd.disconnected { + background-color: #f53c3c; +} + +#mpd.stopped { + background-color: #90b1b1; +} + +#mpd.paused { + background-color: #51a37a; +} + +#language { + background: #00b093; + color: #740864; + padding: 0 5px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state { + background: #97e1ad; + color: #000000; + padding: 0 0px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state > label { + padding: 0 5px; +} + +#keyboard-state > label.locked { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad.empty { + background-color: transparent; +} + +#privacy { + padding: 0; +} + +#privacy-item { + padding: 0 5px; + color: white; +} + +#privacy-item.screenshare { + background-color: #cf5700; +} + +#privacy-item.audio-in { + background-color: #1ca000; +} + +#privacy-item.audio-out { + background-color: #0069d4; +} diff --git a/zsh/zshrc b/zsh/zshrc new file mode 100644 index 0000000..fa84d26 --- /dev/null +++ b/zsh/zshrc @@ -0,0 +1,22 @@ +if [ -f $HOME/.nofish ]; then + current_time=$(date +%s) + file_time=$(stat -f %m $HOME/.nofish) + time_diff=$((current_time - file_time)) + if [ $time_diff -gt 5 ]; then + rm -vf $HOME/.nofish + fi +fi +if [ ! -f $HOME/.nofish ]; then + if [ -e /opt/homebrew/bin/fish ]; then + exec /opt/homebrew/bin/fish + elif [ -e /bin/fish ]; then + exec /bin/fish + elif [ -e /usr/bin/fish ]; then + exec /usr/bin/fish + elif [ -e /data/data/com.termux/files/usr/bin/fish ]; then + exec /data/data/com.termux/files/usr/bin/fish + fi + echo 'I might want to install fish on this host' +fi + +alias f=fish -- cgit v1.2.3