feat: migrate from Zsh to Fish shell with comprehensive configuration

Major shell migration replacing Zsh/Oh-My-Zsh with Fish shell:

- Remove all Zsh configurations (dot_zshrc.tmpl, dot_p10k.zsh)
- Remove Oh-My-Zsh external dependencies from .chezmoiexternal.toml
- Add complete Fish shell setup with config.fish.tmpl and abbr.fish.tmpl
- Implement Fish-native functions for lazy-loading tools (mise, pyenv, zoxide, etc.)
- Create commonrc.fish.tmpl for cross-shell compatibility
- Add Fish plugin management via Fisher (tide prompt, fzf.fish)
- Update documentation (CLAUDE.md, TODO.md, ONBOARDING.md) to reflect Fish
- Add .fish.tmpl file association to VS Code settings
- Enhance PowerShell profile with lsd aliases
- Configure git delta pager and zdiff3 merge conflict style
- Update WSL keychain integration for Fish shell

This migration maintains all existing tool integrations while improving
startup performance through lazy-loading and Fish's native features.
This commit is contained in:
2025-10-27 13:37:00 -05:00
parent 4095b2d242
commit 4d914f1e2f
34 changed files with 501 additions and 1864 deletions

View File

@@ -0,0 +1,12 @@
# Defer hishtory initialization to first prompt
# This runs after startup but before user interaction
function __init_hishtory --on-event fish_prompt
# Remove this function after first run
functions --erase __init_hishtory
# Only initialize if hishtory config exists
if test -f $HOME/.hishtory/config.fish
set -gx HISHTORY_SERVER "https://hsh.{{ dopplerProjectJson.PRIVATE_DOMAIN }}"
source $HOME/.hishtory/config.fish
end
end

View File

@@ -0,0 +1,18 @@
# Lazy-load chatgpt completions on first use
function chatgpt --wraps chatgpt
# Initialize chatgpt completions only once
if not set -q __chatgpt_initialized
set -g __chatgpt_initialized 1
# Generate and source completions
if command -q chatgpt
command chatgpt --set-completions fish | source
else
echo "chatgpt is not installed" >&2
return 1
end
end
# Execute the actual chatgpt command
command chatgpt $argv
end

View File

@@ -0,0 +1,24 @@
function chcode --description "Edit chezmoi files in VS Code"
set -gx EDITOR "code --wait"
# Check if --watch is in arguments
set -l has_watch false
set -l has_file false
for arg in $argv
if test "$arg" = "--watch"
set has_watch true
else if not string match -q -- '-*' $arg
set has_file true
end
end
# If --watch is provided but no file, show error
if test $has_watch = true -a $has_file = false
echo "--watch requires a file to be provided, directories aren't supported with watch mode"
return 1
end
# Execute chezmoi edit with all arguments
chezmoi edit $argv
end

View File

@@ -0,0 +1,12 @@
function chfix --description "chmod +x the last command (if it's a file)"
# Get the last command from Fish history
set -l last_command (history --max 1 | string trim)
if test -f "$last_command"
chmod +x "$last_command"
echo "Made executable: $last_command"
else
echo "Error: $last_command is not a valid file"
return 1
end
end

View File

@@ -0,0 +1,6 @@
function chshow --description "Show rendered chezmoi template via fzf"
set -l target (find {{ .chezmoi.sourceDir | quote }} -name "*.tmpl" -type f | fzf)
if test -n "$target"
cat $target | chezmoi execute-template
end
end

View File

@@ -0,0 +1,19 @@
# Lazy-load thefuck on first use
function fuck --description "Correct your previous console command"
# Initialize thefuck only once
if not set -q __thefuck_initialized
set -g __thefuck_initialized 1
# Run thefuck alias generation
if command -q thefuck
thefuck --alias | source
else
echo "thefuck is not installed" >&2
return 1
end
end
# Execute the fuck command (which thefuck creates)
# After initialization, the actual fuck function will be defined
fuck $argv
end

View File

@@ -0,0 +1,3 @@
function gi --description "Generate .gitignore from gitignore.io"
curl -sL https://www.toptal.com/developers/gitignore/api/$argv
end

View File

@@ -0,0 +1,3 @@
function glf --description "Git log find by commit message"
git log --all --grep="$argv"
end

View File

@@ -0,0 +1,18 @@
# Lazy-load just completions on first use
function just --wraps just
# Initialize just completions only once
if not set -q __just_initialized
set -g __just_initialized 1
# Generate and source completions
if command -q just
command just --completions fish | source
else
echo "just is not installed" >&2
return 1
end
end
# Execute the actual just command
command just $argv
end

View File

@@ -0,0 +1,7 @@
function lastRuns --description "Show last N GitHub Actions runs"
set -l runs 10
if test (count $argv) -gt 0
set runs $argv[1]
end
gh run list -L $runs --json name,url | jq -c '.[] | [.name, .url] | join(" ")' -r
end

View File

@@ -0,0 +1,11 @@
# Lazy-load mise on first use
function mise --wraps mise
# Initialize mise only once
if not set -q __mise_initialized
set -g __mise_initialized 1
command mise activate fish | source
end
# Execute the actual mise command
command mise $argv
end

View File

@@ -0,0 +1,4 @@
function mktouch --description "Touch a file while creating parent directories"
mkdir -p (dirname $argv[1])
touch $argv[1]
end

View File

@@ -0,0 +1,23 @@
# Lazy-load pyenv on first use
function pyenv --wraps pyenv
# Initialize pyenv only once
if not set -q __pyenv_initialized
set -g __pyenv_initialized 1
# Add to PATH if not already there
if test -d $PYENV_ROOT/bin; and not contains $PYENV_ROOT/bin $PATH
set -gx PATH $PYENV_ROOT/bin $PATH
end
# Run pyenv init
command pyenv init - fish | source
# pyenv-virtualenv if available
if command -q pyenv-virtualenv-init
command pyenv virtualenv-init - fish | source
end
end
# Execute the actual pyenv command
command pyenv $argv
end

View File

@@ -0,0 +1,13 @@
function tempCode --description "Create a temporary file and open in VS Code"
if test (count $argv) -eq 0
echo "Must provide filetype argument (ex: py, .xml, html)"
return 1
end
# Remove preceding dot, then re-add to support both '.py' and 'py' as arguments
set -l extension (string replace -r '^\.' '' $argv[1])
set -l temp_file (mktemp /tmp/XXXXXXXXXXXX_(uuidgen).$extension)
echo "Temporary $argv[1] file created at $temp_file"
code --file-uri "file://$temp_file"
end

View File

@@ -0,0 +1,18 @@
# Lazy-load zoxide on first use of z command
function z --description "zoxide smart cd"
# Initialize zoxide only once
if not set -q __zoxide_initialized
set -g __zoxide_initialized 1
# Run zoxide init
if command -q zoxide
zoxide init fish | source
else
echo "zoxide is not installed" >&2
return 1
end
end
# Execute the actual z command (defined by zoxide init)
__zoxide_z $argv
end

View File

@@ -0,0 +1,18 @@
# Lazy-load zoxide on first use of zi command
function zi --description "zoxide interactive smart cd"
# Initialize zoxide only once (shared flag with z.fish)
if not set -q __zoxide_initialized
set -g __zoxide_initialized 1
# Run zoxide init
if command -q zoxide
zoxide init fish | source
else
echo "zoxide is not installed" >&2
return 1
end
end
# Execute the actual zi command (defined by zoxide init)
__zoxide_zi $argv
end