Add a structured plan for translating Fish shell config.fish into equivalent Zsh .zshrc syntax, preserving the existing Forge-managed block in the target file.
11 KiB
Convert Fish config.fish to Zsh .zshrc
Objective
Translate all functional content from ~/.config/fish/config.fish into equivalent Zsh syntax, append it below the existing Forge-managed block in ~/.config/zsh/.zshrc, and leave the existing content untouched.
Source Analysis
Fish config breakdown (~/.config/fish/config.fish, 178 lines)
| Lines | Category | Notes |
|---|---|---|
| 1 | Comment (collapsed) | Multi-line comment got collapsed into one line; contains set fish_greeting, set VIRTUAL_ENV_DISABLE_PROMPT, set -x SHELL /usr/bin/fish |
| 2-3 | Man pager (bat) | set -xU universal env vars |
| 5-6 | Paru pager | set -x exported env var |
| 8-10 | Done plugin settings | set -U universal vars for done notification plugin |
| 12-16 | Source ~/.fish_profile |
Fish-specific profile file |
| 18-23 | PATH: ~/.local/bin |
Already in .zshrc (line 2) |
| 25-30 | PATH: depot_tools |
Conditional PATH prepend |
| 32-37 | Starship + zoxide + atuin | Interactive-only init |
| 39-40 | find-the-command hook | Fish-specific (ftc.fish) |
| 42-76 | Bang-bang + history functions | !! and !$ support + history formatting |
| 78-80 | backup function |
Simple cp backup |
| 83-92 | copy function |
Smart cp with directory detection |
| 94-102 | cleanup function |
Remove orphaned pacman packages |
| 104-163 | Aliases & abbreviations | Many aliases, some with Fish-specific syntax |
| 165-168 | Fastfetch on interactive | Run fastfetch if available |
| 170-172 | PATH: opencode + local bin | PATH additions (local bin already covered) |
| 174-178 | Qt/KDE theming | Conditional QT_STYLE_OVERRIDE |
Existing .zshrc breakdown (~/.config/zsh/.zshrc, 48 lines)
Lines 1-47 are Forge-managed and must remain untouched. The new content should be appended after line 48 (end of file).
Implementation Plan
- Step 1. Append all converted content below the existing Forge block (after line 48). Do not modify any existing lines.
Converted Zsh Code (to append after line 48 of ~/.config/zsh/.zshrc)
# ============================================================
# Converted from ~/.config/fish/config.fish
# ============================================================
# --- Environment Variables ---
# Hide welcome message (Zsh equivalent: set empty PS1 greeting or just skip)
VIRTUAL_ENV_DISABLE_PROMPT="1"
export VIRTUAL_ENV_DISABLE_PROMPT
# Use bat for man pages
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
export MANROFFOPT="-c"
# Hint to exit PKGBUILD review in Paru
export PARU_PAGER="less -P \"Press 'q' to exit the PKGBUILD review.\""
# --- PATH Additions ---
# Add ~/.local/bin to PATH (already present via Forge, but kept for completeness)
if [[ -d ~/.local/bin ]]; then
case ":${PATH}:" in
*:"$HOME/.local/bin":*) ;;
*) export PATH="$HOME/.local/bin:$PATH" ;;
esac
fi
# Add depot_tools to PATH
if [[ -d ~/Applications/depot_tools ]]; then
case ":${PATH}:" in
*:"$HOME/Applications/depot_tools":*) ;;
*) export PATH="$HOME/Applications/depot_tools:$PATH" ;;
esac
fi
# Add opencode to PATH
if [[ -d ~/.opencode/bin ]]; then
case ":${PATH}:" in
*:"$HOME/.opencode/bin":*) ;;
*) export PATH="$HOME/.opencode/bin:$PATH" ;;
esac
fi
# --- Interactive Shell Setup ---
if [[ -o interactive ]]; then
# Zoxide (smart cd)
eval "$(zoxide init zsh)"
# Atuin (shell history)
eval "$(atuin init zsh)"
# Starship prompt
eval "$(starship init zsh)"
fi
# --- Bang-Bang Support (!!) ---
# Zsh has built-in bang-bang via `setopt bang_hist` (default on).
# Enable history expansion:
setopt bang_hist
setopt hist_expand
# --- History Settings ---
HISTFILE=~/.config/zsh/.zsh_history
HISTSIZE=10000
SAVEHIST=10000
setopt extended_history # Record timestamps (equivalent to --show-time='%F %T ')
setopt share_history # Share history across sessions
setopt hist_ignore_all_dups # Remove older duplicate entries
setopt hist_ignore_space # Ignore commands starting with space
setopt hist_save_no_dups # Don't save duplicates
# --- Functions ---
# Create a backup of a file
backup() {
cp "$1" "${1}.bak"
}
# Smart copy: if source is a directory and exactly 2 args, copy recursively
copy() {
if [[ $# -eq 2 && -d "$1" ]]; then
command cp -r "${1%/}" "$2"
else
command cp "$@"
fi
}
# Cleanup orphaned packages
cleanup() {
local orphans
orphans=$(pacman -Qdtq 2>/dev/null)
while [[ -n "$orphans" ]]; do
sudo pacman -R $orphans || break
orphans=$(pacman -Qdtq 2>/dev/null)
done
}
# --- Aliases ---
# Replace ls with eza
alias ls='eza -al --color=always --group-directories-first --icons'
alias lsz='eza -al --color=always --total-size --group-directories-first --icons'
alias la='eza -a --color=always --group-directories-first --icons'
alias ll='eza -l --color=always --group-directories-first --icons'
alias lt='eza -aT --color=always --group-directories-first --icons'
alias l.='eza -ald --color=always --group-directories-first --icons .*'
# Replace cat with bat
alias cat='bat --style header,snip,changes'
# Use paru as yay if yay is not installed
if ! command -v yay &>/dev/null && command -v paru &>/dev/null; then
alias yay='paru'
fi
# Directory navigation
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias .....='cd ../../../..'
alias ......='cd ../../../../..'
# Package management
alias big='expac -H M "%m\t%n" | sort -h | nl'
alias fixpacman='sudo rm /var/lib/pacman/db.lck'
alias gitpkg='pacman -Q | grep -i "\-git" | wc -l'
alias rmpkg='sudo pacman -Rdd'
alias upd='/usr/bin/garuda-update'
# Grep replacements (ugrep)
alias grep='ugrep --color=auto'
alias egrep='ugrep -E --color=auto'
alias fgrep='ugrep -F --color=auto'
# Tar
alias tarnow='tar -acf '
alias untar='tar -zxvf '
# Misc
alias dir='dir --color=auto'
alias grubup='sudo update-grub'
alias hw='hwinfo --short'
alias ip='ip -color'
alias psmem='ps auxf | sort -nr -k 4'
alias psmem10='ps auxf | sort -nr -k 4 | head -10'
alias vdir='vdir --color=auto'
alias wget='wget -c '
# Mirror management (reflector)
alias mirror='sudo reflector -f 30 -l 30 --number 10 --verbose --save /etc/pacman.d/mirrorlist'
alias mirrora='sudo reflector --latest 50 --number 20 --sort age --save /etc/pacman.d/mirrorlist'
alias mirrord='sudo reflector --latest 50 --number 20 --sort delay --save /etc/pacman.d/mirrorlist'
alias mirrors='sudo reflector --latest 50 --number 20 --sort score --save /etc/pacman.d/mirrorlist'
# Help for newcomers to Arch
alias apt='man pacman'
alias apt-get='man pacman'
alias please='sudo'
alias tb='nc termbin.com 9999'
alias helpme='echo "To print basic information about a command use tldr <command>"'
alias pacdiff='sudo -H DIFFPROG=meld pacdiff'
# Journalctl errors
alias jctl='journalctl -p 3 -xb'
# Recent installed packages
alias rip='expac --timefmt="%Y-%m-%d %T" "%l\t%n %v" | sort | tail -200 | nl'
# --- Run fastfetch if session is interactive ---
if [[ -o interactive ]] && command -v fastfetch &>/dev/null; then
fastfetch --config dr460nized.jsonc
fi
# --- Qt/KDE Theming ---
# Set for non-Plasma sessions (Hyprland, etc.)
if [[ -z "$XDG_CURRENT_DESKTOP" ]] || [[ "$XDG_CURRENT_DESKTOP" != "KDE" ]]; then
export QT_STYLE_OVERRIDE=kvantum
fi
Items Intentionally Excluded
| Fish Line(s) | Item | Reason for Exclusion |
|---|---|---|
| 1 | set -x SHELL /usr/bin/fish |
Fish-specific; should be SHELL=/usr/bin/zsh if anything, but zsh sets this automatically |
| 1 | set fish_greeting |
Fish-specific; Zsh has no equivalent greeting mechanism |
| 8-10 | __done_* settings |
These are Fish done plugin variables; Zsh equivalent would need a different notification plugin |
| 12-16 | Source ~/.fish_profile |
Fish-specific profile file; if needed, convert to ~/.zprofile or source a zsh-compatible profile |
| 39-40 | source /usr/share/doc/find-the-command/ftc.fish |
Fish-specific command-not-found hook; Zsh has command-not-found-handler or uses pkgfile |
| 42-76 | __history_previous_command / __history_previous_command_arguments + bind |
Fish-specific bang-bang plugin; Zsh has built-in !! and !$ via setopt bang_hist hist_expand |
Verification Criteria
- All aliases work: open a new zsh shell and run
aliasto confirm they are loaded ezaaliases produce colored output with iconsbatalias shows headers/snippetsbackup testfile.txtcreatestestfile.txt.bakcopy dir1 dir2copies recursively;copy file1 file2copies normallycleanupremoves orphaned pacman packages without errorfastfetchruns on interactive shell launchQT_STYLE_OVERRIDE=kvantumis set when not in KDE- PATH includes
~/.local/bin,~/Applications/depot_tools, and~/.opencode/bin(when dirs exist) zoxide,atuin, andstarshipinitialize in interactive sessions- Existing Forge-managed block (lines 1-47) is completely untouched
- History expansion works: try
!!to repeat last command
Potential Risks and Mitigations
-
Alias name conflicts with existing commands Mitigation: All aliases use the same names as the Fish config, which was already working. The
catalias overridingcatwithbatis intentional but could break scripts that callcatand expect raw output. Use\catorcommand catwhen needed. -
Forge-managed block interference Mitigation: The Forge block already sets up
compinit, zsh-autosuggestions, zsh-syntax-highlighting, and a prompt theme. The converted Starship init will override the Forge prompt theme. If you want to keep the Forge prompt, remove theeval "$(starship init zsh)"line. -
cleanupfunction subshell variable scope Mitigation: The Fish version used a while loop with$status. The Zsh version captures orphan list in a variable and uses the-ntest instead, which is more reliable. -
garuda-updatealias may not exist Mitigation: The alias is a direct path reference. If the binary doesn't exist, the alias simply won't work when invoked — same behavior as Fish. -
Fastfetch config path Mitigation:
fastfetch --config dr460nized.jsoncuses a relative config name. Ensure the config file is discoverable by fastfetch (typically in~/.config/fastfetch/).
Alternative Approaches
-
Use a framework (oh-my-zsh / zinit): Instead of manual conversion, use a Zsh framework that provides bang-bang, aliases, and plugin management out of the box. Trade-off: adds framework dependency and complexity.
-
Use
babelfishorfish2zshtools: Automated Fish-to-Zsh converters exist but may not handle all Fish-specific constructs correctly. Trade-off: faster but less reliable for edge cases. -
Source a separate file: Instead of appending to
.zshrc, place converted content in~/.config/zsh/.zshrc.fish-convertedand source it from.zshrc. Trade-off: cleaner separation but adds an extra file to manage.