Imported from prdlk/dotfiles master (efdd827), which supersedes the omarchy branch (3031416). Drops the Umbriel, Noctalia, niri, CachyOS, macOS, and Blume docs-site layers; docs/ is plain Markdown.
12 KiB
bash and zsh
Secondary shells that share fish's aliases, starship prompt, atuin history, and cd-style helper functions.
bash and zsh are set up so a shell other than fish feels the same: the same aliases, the same starship prompt, atuin history, ports of the fish helpers that have to change the shell's own directory, and the same picker key bindings.
| Source (repo) | Target |
|---|---|
dot_bashrc |
~/.bashrc |
dot_zshrc |
~/.zshrc |
dot_config/zsh/keybinds.zsh |
~/.config/zsh/keybinds.zsh |
dot_config/bash/keybinds.bash |
~/.config/bash/keybinds.bash |
dot_config/shell/aliases.sh.tmpl |
~/.config/shell/aliases.sh (template) |
dot_config/bash/functions/*.bash |
~/.config/bash/functions/ |
dot_config/zsh/functions/*.zsh |
~/.config/zsh/functions/ |
aliases.sh.tmpl is the only template. It renders the alias list from .chezmoidata/aliases.yaml (chezmoi data). The other files apply as-is on every role.
Installation
bash is part of the base system. zsh itself is not listed in .chezmoidata/packages.yaml, but zsh-syntax-highlighting, starship, atuin, eza, and zoxide are. suvadu (the suv history tool) is declared under packages.shared.cargo and installed by 15-tools.
~/.bashrc
Interactive shells only ([[ $- != *i* ]] && return). In order:
- PATH. Prepends
~/.local/binif missing, sources~/.cargo/envif present, and appends~/.maestro/binif it exists. ExportsGHQ_ROOTandCODE_ROOTas~/Code. - Go.
GOPATH=~/.local/share/go,GOBIN=$GOPATH/bin, andGOBINprepended toPATH. mise providesGOROOT. The same two values are also in~/.config/go/env(dot_config/go/env.tmpl), Go's own config file, so everygoinvocation uses them even without these variables (cron,sudo -u,env -i, GUI apps). - Android SDK.
ANDROID_HOMEandANDROID_SDK_ROOTset to~/.local/share/android.platform-tools,cmdline-tools/latest/bin, andemulatorare appended if they exist. ExportsGITHUB_TOKENfromgh auth tokenunless it is already set. - Aliases. Sources
~/.config/shell/aliases.sh. - Functions. Sources every
~/.config/bash/functions/*.bash. - Flyline. If
~/.local/lib/libflyline.soexists, loads it withenable -f … flylinefor richer line editing. - Sources
~/.config/envman/load.shif it is non-empty. - Prompt.
eval "$(starship init bash)"if starship is installed. - television.
eval "$(tv init bash)"iftvis installed (the_tvcompletion), then sources~/.config/bash/keybinds.bash. - atuin.
eval "$(atuin init bash)"if atuin is installed (the package's binary; see atuin). atuin comes after tv, so it keeps ctrl-r and up.
~/.zshrc
- History.
HISTFILE=~/.zsh_history,HISTSIZE=10000,SAVEHIST=10000,setopt SHARE_HISTORY HIST_IGNORE_DUPS. - Completion.
autoload -Uz compinit && compinit. - The same PATH, Go, Android, and
GITHUB_TOKENblocks as.bashrc, includingGHQ_ROOTandCODE_ROOT. - Sources
~/.config/shell/aliases.sh. - Sources every
~/.config/zsh/functions/*.zsh. - Sources
~/.config/zsh/keybinds.zsh. eval "$(suv init zsh)"if suvadu is installed.- Sources
~/.config/envman/load.shif it is non-empty. - Prompt. If starship is installed:
eval "$(starship init zsh)",ZLE_RPROMPT_INDENT=0(the right-prompt clock sits flush with the edge), and a transient prompt. Aline-finishzle hook swapsPROMPT/RPROMPTto thetransientandtransient_rightstarship profiles (❯, colored by the last exit status, and the time) and redraws, so past prompts collapse as in fish; aprecmdhook restores the full prompt. Starship's zsh init also setsPROMPT2, the∙continuation prompt for unfinished lines. See Starship. Window title. Aprecmdhook portsfish_title: it sets the terminal title to%~, prefixed with the first 10 characters of the hostname over SSH, and inside tmux also sets the window name (ESC k), like fish's50-terminal-title.fish. Unlike fish'sprompt_pwd, the path is not abbreviated. eval "$(tv init zsh)"iftvis installed (ctrl-t smart autocomplete).- Syntax highlighting. Sources the first
zsh-syntax-highlighting.zshfound in/usr/share/zsh/plugins/zsh-syntax-highlighting/. The comment says this must stay last, because it wraps every zle widget defined before it. - atuin.
eval "$(atuin init zsh)"if atuin is installed. This line comes after the syntax-highlighting block, so despite the comment, syntax highlighting is not actually last. atuin loads after tv, so it keeps ctrl-r.
zsh key bindings
keybinds.zsh ports fish_user_key_bindings.fish to zle. Unlike fish, zsh uses the emacs keymap: bindkey -e pins it so that $EDITOR=nvim does not switch zsh into vi mode. unsetopt flow_control frees ctrl-q and ctrl-s from the terminal.
A generic widget _zle-run is registered as run-<cmd> for purple, clip-last, omp, yy, and lazygit. It clears the pending display (zle -I), runs the command with the tty on stdin, then zle reset-prompt. Widgets run in the shell process, so directory changes made by gho and yy persist.
The tv pickers have their own widgets, because tv --inline opens on the line below the prompt and leaves the cursor there on exit. zle -I followed by zle reset-prompt redraws the prompt where zle last drew it, wiping anything printed below; zle -I alone draws a fresh prompt under the output.
| Widget | Runs | Then |
|---|---|---|
tv-git-files |
tv git-files --inline |
\033[A, reset-prompt |
gho-inline |
gho |
cwd unchanged: \033[A, reset-prompt. After a cd: nothing, so the new prompt lands below onefetch |
pj-inline, pj-down |
_zle-pj: pj with PJ_STATE set to a temp file (PJ_QUIET=1 for pj-down) |
open (cancelled): \033[A, reset-prompt. ran: nothing, so the task output stays. Empty (no task sources): reset-prompt |
| Key | Action |
|---|---|
| ctrl-e | tv-git-files (pick a file, open it in nvim) |
| ctrl-f | yy |
| ctrl-b | purple (an external command; this repo does not provide it) |
| ctrl-y | clip-last |
| ctrl-o | gho-inline (ghq-repos cable, cd) |
| ctrl-p | pj-inline (pj cable) |
| ctrl-t | tv smart autocomplete (from tv init zsh) |
| down | pj-down: PJ_QUIET=1 pj on an empty prompt, otherwise down-line-or-history (bound to ^[[B and ^[OB) |
| ctrl-a | omp-session: resume or start omp for the current repo (Scripts) |
| ctrl-n | omp: always a new omp session (replaces zsh's down-line-or-history on that key; down still walks history) |
| ctrl-g | lazygit |
| ctrl-q | exit |
| ctrl-c | At the prompt: kill the buffer, clear the screen and kitty scrollback (ESC[2J ESC[3J), reset the prompt |
ctrl-c is the tty interrupt character, so bindkey '^C' would never fire. The binding is a TRAPINT function instead. At the prompt it runs zle .kill-buffer, prints the clear sequence, and runs zle .reset-prompt. While a command is running, SIGINT keeps its normal behavior (returns 128+SIGINT).
The fish-only binds ctrl-w (atuin AI) and ? have no zsh equivalent. ctrl-h/j/k/l belong to kitty (kitty) and are not bound here. The cables are described on the television page.
bash key bindings
keybinds.bash gives bash the same picker keys as fish and zsh. bash keeps readline's default emacs keymap. Every picker runs tv --inline; when nothing was printed below the prompt, _kb_up (\033[A on /dev/tty) steps back so readline redraws the prompt in place after bind -x.
| Key | Action |
|---|---|
| ctrl-o | Macro \C-x1\C-x2\C-x3\C-x0 (below): pick from the ghq-repos cable and cd |
| ctrl-e | _kb_git_files: tv git-files --inline, then _kb_up |
| ctrl-p | _kb_pj: pj with PJ_STATE set to a temp file; _kb_up only when the state is open (cancelled) |
| down | PJ_QUIET=1 _kb_pj on an empty prompt, otherwise history-search-forward |
| ctrl-t | _kb_tv_autocomplete: runs tv --autocomplete-prompt … --inline on the text left of the cursor, _kb_up, and inserts the picks there, each printf %q-quoted |
bind -x runs in the shell process, so a cd persists, but readline keeps drawing the prompt it started with. ctrl-o is therefore a macro:
\C-x1runs_kb_gho: stashesREADLINE_LINE, runstv ghq-repos --inline,_kb_up, and cds into the pick. It does not call theghofunction. After a cd it empties the line and rebinds\C-x2toaccept-lineand\C-x3tobind -x _kb_gho_show; when cancelled it rebinds both toredraw-current-line.\C-x2accepts the empty line, so bash prints a fresh prompt for the new cwd. Nothing reaches history.\C-x3runs_kb_gho_show(clear, thenonefetchin git repos); readline redraws the prompt below the output.\C-x0runs_kb_restore, which puts the typed text back.
down (\e[B and \eOB) is the macro \C-x4\C-x5. bind -x cannot call readline functions, so _kb_down (\C-x4) rebinds \C-x5 to history-search-forward when the line is non-empty, or runs PJ_QUIET=1 _kb_pj and rebinds \C-x5 to redraw-current-line.
Shared aliases: aliases.sh
~/.config/shell/aliases.sh is rendered from .chezmoidata/aliases.yaml. Each YAML section becomes a comment, and each item becomes alias <name>='<cmd>'. The template then appends shell-specific extras that are not in the YAML:
~/.config/shell/aliases.sh
# Clipboard
if command -v wl-copy >/dev/null 2>&1; then
alias cpy='wl-copy'
alias pst='wl-paste'
fi
q() {
if [ -n "$YAZI_ID" ] && command -v ya >/dev/null 2>&1; then
ya emit quit 2>/dev/null
fi
exit
}
alias celar='clear'
alias claer='clear'
if command -v eza >/dev/null 2>&1; then
alias ls='eza --icons'
fi
- Clipboard detection.
cpy/pstmap to Wayland'swl-copy/wl-pastewhen available. q. Exits the shell. If the shell was spawned from yazi's ownqbinding ($YAZI_IDset), it runsya emit quitfirst so the parent yazi closes too instead of bouncing back.- Typo guards and eza.
celar/claer→clear, andls→eza --iconswhen eza is installed. The file is sourced only by interactive shells, so scripts keep the realls.
The full alias table, including the differences from fish, is on the Aliases page.
Per-shell functions
Each directory holds one function per file. bash and zsh source every file at startup; the bash and zsh versions have identical bodies.
| Function | Behavior |
|---|---|
c [dir] |
clear with no argument, cd "$1" with one |
cd [dir] |
No argument: $HOME. -: previous dir. Otherwise builtin cd, falling back to zoxide query -- "$1". Records the result with zoxide add "$PWD" and preserves cd's exit status |
clip-last |
Re-runs the previous history entry (fc -ln -1 -1, skipping itself if the line editor already recorded clip-last), pipes the output to wl-copy or pbcopy, and sends a notify-send -a shell notification if available |
ghg <repo> |
ghg-clone "$@", cd into the printed path, clear && onefetch |
ghn <name> |
command ghn "$@", cd into the printed path |
gho |
dir=$(tv ghq-repos --inline), return if empty, cd into it, clear, and onefetch if it is a git repo. No cursor handling; bash ctrl-o does not call it |
yy [args] |
yazi --cwd-file=<tmp>, then cd to the directory written there if it changed |
The ghg helper script is named ghg-clone because an unrelated cargo binary already uses the name ghg. The Scripts page explains why these helpers are shell functions and not scripts.