diff options
Diffstat (limited to 'dot_config/zsh')
| -rw-r--r-- | dot_config/zsh/dot_zprofile | 116 | ||||
| -rw-r--r-- | dot_config/zsh/dot_zshrc | 322 |
2 files changed, 438 insertions, 0 deletions
diff --git a/dot_config/zsh/dot_zprofile b/dot_config/zsh/dot_zprofile new file mode 100644 index 0000000..30b5b21 --- /dev/null +++ b/dot_config/zsh/dot_zprofile @@ -0,0 +1,116 @@ +# Login shell configuration — sourced once per session by zsh. +# Sets environment variables, XDG paths, tool config, and host-specific overrides. + +# Guard against double-sourcing (e.g. nested login shells) +[[ -n $__ZPROFILE_SOURCED ]] && return +__ZPROFILE_SOURCED=1 + +# ── PATH ────────────────────────────────────────────────────────────────────── +typeset -U path # deduplicate PATH entries +path=("$HOME/.local/bin" "$HOME/.local/share/nvim/mason/bin" $path) + +# ── XDG Base Directories ───────────────────────────────────────────────────── +export XDG_CONFIG_HOME="$HOME/.config" +export XDG_DATA_HOME="$HOME/.local/share" +export XDG_STATE_HOME="$HOME/.local/state" +export XDG_CACHE_HOME="$HOME/.cache" + +# ── Locale ──────────────────────────────────────────────────────────────────── +export LANG=en_US.UTF-8 + +# ── Terminal ────────────────────────────────────────────────────────────────── +case $TERM in + *256color|*truecolor) export COLORTERM=24bit ;; +esac + +export TERMINAL='ghostty' +export BROWSER='linkhandler' +export OPENER='xdg-open' + +# ── Editors ─────────────────────────────────────────────────────────────────── +export EDITOR='nvim' +export VISUAL='nvim' +export DIFFPROG='nvim -d' +export MANPAGER='nvim +Man!' +export MANWIDTH=999 + +# ── less ────────────────────────────────────────────────────────────────────── +export LESS="-F --RAW-CONTROL-CHARS" +[[ -r /usr/bin/source-highlight-esc.sh ]] && export LESSOPEN="| /usr/bin/source-highlight-esc.sh %s" + +# ── GPG / SSH ───────────────────────────────────────────────────────────────── +unset SSH_AGENT_PID +export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" + +# ── FZF ─────────────────────────────────────────────────────────────────────── +export FZF_DEFAULT_COMMAND="fd --type file --follow --hidden --exclude .git --color=always" +export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" +export FZF_DIRS_COMMAND="fd --type d --follow --hidden --exclude .git --color=always" +export FZF_DEFAULT_OPTS="--ansi --layout=reverse --inline-info --cycle --color=dark --color=fg:-1,bg:-1,hl:#5fff87,fg+:-1,bg+:-1,hl+:#ffaf5f --color=info:#af87ff,prompt:#5fff87,pointer:#ff87d7,marker:#ff87d7,spinner:#ff87d7" +export FZF_CTRL_T_OPTS="--preview 'bat --color=always --style=numbers --line-range=:500 {}' --select-1 --exit-0" +export FZF_CTRL_R_OPTS="--preview 'echo {}' --preview-window down:3:hidden:wrap --bind '?:toggle-preview' --sort --exact" +export FZF_ALT_C_OPTS="--preview 'tree -C {} | head -200'" + +# ── Git prompt ──────────────────────────────────────────────────────────────── +export GIT_PS1_SHOWDIRTYSTATE=1 +export GIT_PS1_SHOWSTASHSTATE=1 +unset GIT_PS1_SHOWUNTRACKEDFILES +export GIT_PS1_SHOWUPSTREAM="verbose" +export GIT_PS1_SHOWCONFLICTSTATE="yes" +export GIT_PS1_DESCRIBE_STYLE="branch" +export GIT_PS1_SHOWCOLORHINTS=1 +export GIT_PS1_HIDE_IF_PWD_IGNORED=1 + +# ── GCC ─────────────────────────────────────────────────────────────────────── +export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + +# ── Java ────────────────────────────────────────────────────────────────────── +# System AA fonts, GTK L&F, XDG prefs dir, GTK2 for compatibility +export _JAVA_OPTIONS="-Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Djava.util.prefs.userRoot=$XDG_CONFIG_HOME/java -Djdk.gtk.version=2" +# Fix for non-reparenting WMs (sway, dwm, etc.) +export _JAVA_AWT_WM_NONREPARENTING=1 + +# ── Miscellaneous ───────────────────────────────────────────────────────────── +export QT_QPA_PLATFORMTHEME=qt6ct +export NO_AT_BRIDGE=1 # suppress GTK accessibility bus warnings +export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock" +export INPUTRC="$XDG_CONFIG_HOME/sh/inputrc" + +# ── Wayland ─────────────────────────────────────────────────────────────────── +export XDG_CURRENT_DESKTOP=sway +export MOZ_ENABLE_WAYLAND=1 + +# ── XDG cleanup: keep $HOME tidy ───────────────────────────────────────────── +# https://wiki.archlinux.org/title/XDG_Base_Directory#Partial +export CARGO_HOME="$XDG_DATA_HOME/cargo" +export CUDA_CACHE_PATH="$XDG_CACHE_HOME/nv" +export GOPATH="$XDG_DATA_HOME/go" +export GRADLE_USER_HOME="$XDG_DATA_HOME/gradle" +export NODE_REPL_HISTORY="$XDG_DATA_HOME/node_repl_history" +export PASSWORD_STORE_DIR="$XDG_DATA_HOME/password-store" +export RUFF_CACHE_DIR="$XDG_CACHE_HOME/ruff" +export RUSTUP_HOME="$XDG_DATA_HOME/rustup" +export WGETRC="$XDG_CONFIG_HOME/wget/wgetrc" +export WINEPREFIX="$XDG_DATA_HOME/wineprefixes/default" + +# ── Host-specific ───────────────────────────────────────────────────────────── +case $(uname -n) in + halley2) + export LIBVA_DRIVER_NAME="iHD" + export MESA_LOADER_DRIVER_OVERRIDE="iris" + export VAAPI_MPEG4_ENABLED=true + ;; + hercules) + export OCL_ICD_VENDORS=nvidia + [[ -r "$XDG_CONFIG_HOME/sh/work-envrc" ]] && source "$XDG_CONFIG_HOME/sh/work-envrc" + ;; +esac + +# ── Secrets (from pass) ────────────────────────────────────────────────────── +(( $+commands[pass] )) && export FIRECRAWL_API_KEY="$(pass show copilot/firecrawl-api-key)" + +# ── Auto-start sway on VT1 ──────────────────────────────────────────────────── +if [[ -z $WAYLAND_DISPLAY && $XDG_VTNR == 1 ]]; then + export XDG_SESSION_TYPE=wayland + exec sway +fi diff --git a/dot_config/zsh/dot_zshrc b/dot_config/zsh/dot_zshrc new file mode 100644 index 0000000..fad4bca --- /dev/null +++ b/dot_config/zsh/dot_zshrc @@ -0,0 +1,322 @@ +# Interactive zsh configuration. + +# ── Terminal ────────────────────────────────────────────────────────────────── +stty -ixon # disable XON/XOFF flow control (frees Ctrl-S/Ctrl-Q) +ttyctl -f # freeze terminal state; programs can't leave it broken + +# ── Options ─────────────────────────────────────────────────────────────────── +# Note: appendhistory, nomatch, notify are zsh defaults — not set here. +setopt autocd # cd by typing directory name +setopt extendedglob # extended glob patterns (#, ~, ^) +setopt interactivecomments # allow # comments in interactive shell +setopt rmstarsilent # don't confirm rm * +setopt prompt_subst # expand variables/functions in prompt +setopt auto_pushd # cd pushes old dir onto stack (cd -<TAB> to browse) +setopt pushd_ignore_dups # don't push duplicate dirs onto stack +unsetopt beep # no terminal bell + +# ── History ─────────────────────────────────────────────────────────────────── +HISTFILE="$XDG_STATE_HOME/zsh/history" +HISTSIZE=50000 +SAVEHIST=50000 +setopt extended_history # save timestamp and duration per entry +setopt share_history # share history across concurrent sessions +setopt hist_ignore_all_dups # remove older duplicate when adding new entry +setopt hist_find_no_dups # skip duplicates when searching history +setopt hist_reduce_blanks # trim superfluous whitespace from entries +setopt hist_ignore_space # commands starting with space are not saved + +# ── Emacs keybindings ───────────────────────────────────────────────────────── +bindkey -e + +# ── Prompt ──────────────────────────────────────────────────────────────────── +autoload -Uz colors && colors +source /usr/share/git/completion/git-prompt.sh +PROMPT='%B%{$fg[green]%}%n%{$reset_color%}@%{$fg[cyan]%}%m%{$reset_color%}:%b%{$fg[yellow]%}%~%{$reset_color%}$(__git_ps1 " (%s)")%(?..[%{$fg[red]%}%?%{$reset_color%}]) %(!.#.>) ' + +# ── Completion ──────────────────────────────────────────────────────────────── +fpath=($XDG_DATA_HOME/zsh/completion $fpath) +autoload -Uz compinit && compinit -d "$XDG_CACHE_HOME/zsh/zcompdump" + +zstyle ':completion:*' menu select # arrow-key driven menu for ambiguous completions +zstyle ':completion:*' completer _expand_alias _complete _ignored _match _approximate +# │ │ │ │ └ fuzzy match (typo tolerance) +# │ │ │ └ try pattern matching +# │ │ └ include normally hidden completions +# │ └ standard completion +# └ expand aliases before completing +zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} # colorize file completions like ls +zstyle ':completion:*' use-cache on # cache completions (speeds up pip, dpkg, etc.) +zstyle ':completion:*' cache-path "$XDG_CACHE_HOME/zsh" +zstyle ':completion:*:match:*' original only # only show original when pattern-matching +zstyle ':completion:*:functions' ignored-patterns '_*' # hide internal completion functions +zstyle ':completion:*:*:kill:*' menu yes select # interactive menu for kill completion +zstyle ':completion:*:kill:*' force-list always # always show process list for kill +zstyle ':completion:*:cd:*' ignore-parents parent pwd # cd never completes . or .. +zstyle ':completion::complete:*' gain-privileges 1 # use doas/sudo for privileged completions +zstyle -e ':completion:*:approximate:*' \ + max-errors 'reply=($((($#PREFIX+$#SUFFIX)/3))numeric)' # allow 1 typo per 3 chars typed + +_comp_options+=(globdots) # include hidden files in completion + +# ── Terminal key setup ───────────────────────────────────────────────────────── +# Application mode ensures terminfo values are valid during line editing. +# Without this, some terminals send wrong sequences for special keys. +if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then + autoload -Uz add-zle-hook-widget + function zle_application_mode_start { echoti smkx } + function zle_application_mode_stop { echoti rmkx } + add-zle-hook-widget -Uz zle-line-init zle_application_mode_start + add-zle-hook-widget -Uz zle-line-finish zle_application_mode_stop +fi + +# Up/Down stored for history-substring-search bindings (set after plugin source) +typeset -g -A key +key[Up]="${terminfo[kcuu1]}" +key[Down]="${terminfo[kcud1]}" + +# ── Custom keybindings ──────────────────────────────────────────────────────── +bindkey \^U backward-kill-line + +# Word navigation (Ctrl-Right also accepts autosuggestion word-by-word — fish-like) +bindkey '^[[1;5C' forward-word # Ctrl-Right +bindkey '^[[1;5D' backward-word # Ctrl-Left +bindkey '^[[1;3C' forward-word # Alt-Right +bindkey '^[[1;3D' backward-word # Alt-Left +bindkey '^H' backward-kill-word # Ctrl-Backspace +bindkey '^[[3;5~' kill-word # Ctrl-Delete + +# Ctrl-Z: toggle foreground/background (no need to type 'fg') +toggle-fg-bg() { + if (( ${#jobstates} )); then + zle .push-input + BUFFER="fg" + zle .accept-line + else + zle .push-input + zle .clear-screen + fi +} +zle -N toggle-fg-bg +bindkey '^Z' toggle-fg-bg + +# Ctrl-D exits even on non-empty line +exit_zsh() { exit } +zle -N exit_zsh +bindkey '^D' exit_zsh + +# Ctrl-X Ctrl-E: edit command in $EDITOR +autoload -Uz edit-command-line +zle -N edit-command-line +bindkey "^X^E" edit-command-line + +# Ctrl-Y: copy current command line to clipboard (OSC 52 — terminal-native) +copy-line-to-clipboard() { printf '\033]52;c;%s\a' "$(echo -n "$BUFFER" | base64)" } +zle -N copy-line-to-clipboard +bindkey '^Y' copy-line-to-clipboard + +# ── Word style ──────────────────────────────────────────────────────────────── +# Ctrl-W/Alt-B/Alt-F use shell quoting rules for word boundaries +autoload -Uz select-word-style +select-word-style shell + +# ── Smart dot expansion ─────────────────────────────────────────────────────── +# Typing .. automatically expands: ... → ../.. , .... → ../../.. , etc. +rationalise-dot() { + if [[ $LBUFFER = *.. ]]; then + LBUFFER+=/.. + else + LBUFFER+=. + fi +} +zle -N rationalise-dot +bindkey . rationalise-dot + +# ── Window title ────────────────────────────────────────────────────────────── +autoload -Uz add-zsh-hook + +xterm_title_precmd() { print -Pn -- '\e]2;%~\a' } +xterm_title_preexec() { print -Pn -- '\e]2;%~ %# ' && print -n -- "${(q)1}\a" } + +if [[ "$TERM" == (xterm-ghostty|st*|screen*|xterm*|rxvt*|tmux*|putty*|konsole*|gnome*) ]]; then + add-zsh-hook -Uz precmd xterm_title_precmd + add-zsh-hook -Uz preexec xterm_title_preexec +fi + +# ── Zellij tab naming (dir:cmd like tmux) ──────────────────────────────────── +if [[ -n "$ZELLIJ" ]]; then + _zellij_dir() { [[ "$PWD" == "$HOME" ]] && echo '~' || echo "${PWD##*/}"; } + _zellij_tab_idx() { echo $(( $(zellij action current-tab-info 2>/dev/null | grep -oP 'position: \K\d+') + 1 )); } + _zellij_tab_precmd() { zellij action rename-tab "$(_zellij_tab_idx):$(_zellij_dir)" 2>/dev/null; } + _zellij_tab_preexec() { zellij action rename-tab "$(_zellij_tab_idx):$(_zellij_dir):${1%% *}" 2>/dev/null; } + add-zsh-hook precmd _zellij_tab_precmd + add-zsh-hook preexec _zellij_tab_preexec +fi + +# ── Recent directories ──────────────────────────────────────────────────────── +autoload -Uz chpwd_recent_dirs cdr +add-zsh-hook chpwd chpwd_recent_dirs +[[ -d ${XDG_STATE_HOME}/zsh ]] || mkdir -p "${XDG_STATE_HOME}/zsh" +zstyle ':chpwd:*' recent-dirs-file "$XDG_STATE_HOME/zsh/chpwd-recent-dirs" +zstyle ':completion:*:*:cdr:*:*' menu selection + +# ── OSC 7 — report CWD to terminal (zellij uses this for new pane/tab CWD) ── +_osc7_chpwd() { + printf '\e]7;file://%s%s\e\\' "${HOST}" "${PWD}" +} +add-zsh-hook chpwd _osc7_chpwd +_osc7_chpwd + +# ── Help system ─────────────────────────────────────────────────────────────── +autoload -Uz run-help run-help-git run-help-ip +(( $+aliases[run-help] )) && unalias run-help +alias help=run-help + +# ── Bracketed paste ─────────────────────────────────────────────────────────── +autoload -Uz bracketed-paste-magic +zle -N bracketed-paste bracketed-paste-magic + +# ── Aliases ─────────────────────────────────────────────────────────────────── +# Files +alias l='lsd -l' +alias la='lsd -lA' +alias lt='lsd --tree' +alias mkdir='mkdir -p' +alias du='du -h' +alias df='df -h' +alias free='free -h' + +# Grep / diff with color +alias grep='grep --color=auto' +alias fgrep='grep -F --color=auto' +alias egrep='grep -E --color=auto' +alias diff='diff --color=auto' +alias dmesg='dmesg --color=auto' +alias dm='dmesg --color=always | less -r' + +# Networking +alias ip="ip -color=auto" +alias lsip="ip -human -color=auto --brief address show" +alias ipa="ip -stats -details -human -color=auto address show" +alias ipecho='curl ipecho.net/plain' +alias ss='doas ss -tupnl' + +# Privilege escalation +alias sudo='doas' +alias sudoedit='doasedit' +alias gimme='doas chown $USER:$(id -gn $USER)' +alias pacdiff='doas pacdiff' + +# Pacman +alias pacopt='comm -13 <(pacman -Qqdt | sort) <(pacman -Qqdtt | sort)' + +# Git +alias g='git' + +# Systemd +alias sys='systemctl' +alias ssys='doas systemctl' +alias sysu='systemctl --user' + +# Navigation +alias c='clear' + +# Yazi: cd-on-exit wrapper +y() { + local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" + command yazi "$@" --cwd-file="$tmp" + IFS= read -r -d '' cwd < "$tmp" + [[ "$cwd" != "$PWD" ]] && [[ -d "$cwd" ]] && builtin cd -- "$cwd" + rm -f -- "$tmp" +} + +# Tools +alias stow='stow -R --no-folding --adopt' +alias curl='curlie' +alias cpr='rsync --archive -hh --partial --info=stats1,progress2 --modify-window=1' +alias mvr='rsync --archive -hh --partial --info=stats1,progress2 --modify-window=1 --remove-source-files' +alias sub='subliminal download -l en' + +# Neovim +alias n='nvim' +alias ndiff='nvim -d' +alias nd='nvim -d' +alias nview='nvim -R' +alias nv='nvim -R' +alias ng='nvim +Neogit' + +# Zellij: smart attach — 0 sessions: create, 1: attach, many: welcome picker +za() { + if [[ -n $ZELLIJ ]]; then + echo "Already inside zellij" >&2 + return 1 + fi + local -a sessions=("${(@f)$(zellij list-sessions -ns 2>/dev/null)}") + sessions=(${sessions:#}) + case ${#sessions} in + 0) zellij ;; + 1) zellij attach "${sessions[1]}" ;; + *) zellij -l welcome ;; + esac +} + +# Just +alias j='just' + +# LLVM / Clang tooling +alias ncmake='cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_FLAGS="$DEV_CFLAGS" -DCMAKE_CXX_FLAGS="$DEV_CFLAGS" -DCMAKE_INSTALL_PREFIX=build/install -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build' +alias ircc='clang -S -emit-llvm -fno-discard-value-names -O0 -Xclang -disable-O0-optnone -o -' +alias irfc='flang -S -emit-llvm -O0 -o -' +alias astcc='clang -Xclang -ast-dump -fsyntax-only' +alias astfc='flang -fc1 -fdebug-dump-parse-tree' +alias symfc='flang -fc1 -fdebug-dump-symbols' +alias gdbr='gdb -ex start --args' + +# GitHub Copilot CLI +alias copilot='gh copilot --autopilot --enable-all-github-mcp-tools --yolo --resume' + +# ── Alias completions ───────────────────────────────────────────────────────── +compdef g=git +compdef j=just +compdef n=nvim ndiff=nvim nd=nvim nview=nvim nv=nvim +compdef sys=systemctl ssys=systemctl sysu=systemctl +compdef l=lsd la=lsd lt=lsd + +# ── GPG agent ───────────────────────────────────────────────────────────────── +# Set GPG_TTY to this shell's actual TTY (not the login console) and tell +# the agent so pinentry prompts appear in the right terminal +export GPG_TTY=$TTY +gpg-connect-agent updatestartuptty /bye &>/dev/null + +# ── Zoxide (smart directory jumping) ────────────────────────────────────────── +# z foo → jump to frecency-ranked dir matching "foo" +# zi → interactive picker with fzf +eval "$(zoxide init zsh)" + +# ── FZF ─────────────────────────────────────────────────────────────────────── +source <(fzf --zsh) + +# Ctrl-X Ctrl-R: search history with fzf and immediately execute +fzf-history-widget-accept() { + fzf-history-widget + zle accept-line +} +zle -N fzf-history-widget-accept +bindkey '^X^R' fzf-history-widget-accept + +_fzf_compgen_path() { fd --hidden --follow --exclude ".git" . "$1" } +_fzf_compgen_dir() { fd --type d --hidden --follow --exclude ".git" . "$1" } + +# ── Plugins (must be sourced last) ──────────────────────────────────────────── +# Highlight config must be set BEFORE sourcing the plugin +ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern) +typeset -A ZSH_HIGHLIGHT_STYLES +ZSH_HIGHLIGHT_STYLES[comment]='fg=yellow' +source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh + +source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh +bindkey '^[[Z' autosuggest-accept # Shift-Tab to accept suggestion + +source /usr/share/zsh/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh +[[ -n "${key[Up]}" ]] && bindkey -- "${key[Up]}" history-substring-search-up +[[ -n "${key[Down]}" ]] && bindkey -- "${key[Down]}" history-substring-search-down |
