diff --git a/.bashrc b/.bashrc index ea300b2..40da8c4 100644 --- a/.bashrc +++ b/.bashrc @@ -64,6 +64,7 @@ if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then fi +# Align `bash` and `zsh` for prompts (see `$PS1` in ~/.zshrc) PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' diff --git a/.config/shell/aliases b/.config/shell/aliases index d809363..7ac4938 100644 --- a/.config/shell/aliases +++ b/.config/shell/aliases @@ -12,9 +12,19 @@ forget() { # the current history and restore $HISTFILE from disk if [ -n "$BASH_VERSION" ]; then history -c history -r + elif [ -n "$ZSH_VERSION" ]; then + _histsize=$HISTSIZE + HISTSIZE=0 # because shrinking the list to 0 discards all entries + HISTSIZE=$_histsize + unset _histsize + fc -R "$HISTFILE" fi } +if [ -n "$ZSH_VERSION" ]; then + alias forget=' forget' # Leading space => The invocation itself is forgotten because of `setopt HIST_IGNORE_SPACE` +fi + alias path='echo $PATH | tr ":" "\n"' diff --git a/.config/zsh/.zlogout b/.config/zsh/.zlogout new file mode 100644 index 0000000..4582375 --- /dev/null +++ b/.config/zsh/.zlogout @@ -0,0 +1,8 @@ +#!/bin/zsh + +# Failsafe: Dispatch to the real `zsh` logout file in ~/ +# +# See ~/.config/zsh/.zshrc for the details + + +[ -f "$HOME/.zlogout" ] && . "$HOME/.zlogout" diff --git a/.config/zsh/.zshenv b/.config/zsh/.zshenv new file mode 100644 index 0000000..355cd16 --- /dev/null +++ b/.config/zsh/.zshenv @@ -0,0 +1,11 @@ +#!/bin/zsh + +# Failsafe: Dispatch to the real `zsh` env file in ~/ +# +# See ~/.config/zsh/.zshrc for the details +# +# Without this, a set `$ZDOTDIR` would silently skip ~/.zshenv +# and lose `skip_global_compinit=1` + + +[ -f "$HOME/.zshenv" ] && . "$HOME/.zshenv" diff --git a/.config/zsh/.zshrc b/.config/zsh/.zshrc new file mode 100644 index 0000000..e9a08e4 --- /dev/null +++ b/.config/zsh/.zshrc @@ -0,0 +1,12 @@ +#!/bin/zsh + +# Failsafe: Dispatch to the real `zsh` config file in ~/ +# +# `zsh` itself only reads `$ZDOTDIR`, which defaults to ~/, +# and never looks into ~/.config/zsh on its own +# => This file is dead code unless something sets `$ZDOTDIR` +# to this folder (e.g., a future Debian default; +# see Debian bug #1036290 for such a proposal) + + +[ -f "$HOME/.zshrc" ] && . "$HOME/.zshrc" diff --git a/.config/zsh/README.md b/.config/zsh/README.md new file mode 100644 index 0000000..8946d8a --- /dev/null +++ b/.config/zsh/README.md @@ -0,0 +1,8 @@ +# `zsh`-related Configurations + +This folder is NOT read by `zsh` by default: + `zsh` only reads `$ZDOTDIR`, which defaults to ~/. + +The files here are failsafes: + Should some machine or future distribution set `$ZDOTDIR` to this folder, + they dispatch back to the real config files in ~/. diff --git a/.local/state/zsh/.gitkeep b/.local/state/zsh/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.profile b/.profile index cee3613..28cd9a4 100644 --- a/.profile +++ b/.profile @@ -85,3 +85,7 @@ _prepend_to_path "$HOME/.local/bin" if [ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi + + +# `zsh`-specific configurations are automatically sourced from ~/.zshrc, +# which then also ensures that this file is sourced diff --git a/.zlogout b/.zlogout new file mode 100644 index 0000000..7431006 --- /dev/null +++ b/.zlogout @@ -0,0 +1,4 @@ +#!/bin/zsh + +_logout="${XDG_CONFIG_HOME:-$HOME/.config}/shell/logout" +[ -f "$_logout" ] && . "$_logout" diff --git a/.zshenv b/.zshenv new file mode 100644 index 0000000..880a8ff --- /dev/null +++ b/.zshenv @@ -0,0 +1,10 @@ +#!/bin/zsh + +# Sourced by `zsh` before /etc/zsh/zshrc, +# and thus the only place where the following can be set in time + +# On Ubuntu (not Debian), /etc/zsh/zshrc calls `compinit` without arguments +# unless this flag is set, which would create a second ~/.zcompdump +# next to the XDG one set in ~/.zshrc +# => Harmless no-op on Debian, needed on Ubuntu and derivatives +skip_global_compinit=1 diff --git a/.zshrc b/.zshrc index 3a46429..e2b2f24 100644 --- a/.zshrc +++ b/.zshrc @@ -3,5 +3,146 @@ # `zsh`-specific configurations +# Remove built-in aliases because we use our own, sourced via ~/.profile +unalias -a + + # Load configuration files common to all kinds of shells [ -f "$HOME/.profile" ] && . "$HOME/.profile" + + +# Ensure `zsh` is running interactively +[[ -o interactive ]] || return + + +# Make `zsh` show `chroot`s in the prompt +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + + +# Align `bash` and `zsh` for prompts (see `$PS1` in ~/.bashrc) +PS1="${debian_chroot:+($debian_chroot)}%n@%m:%~%(!.#.\$) " + + +# Configure the `history` + +# Set these environment variables here +# to avoid conflict/overlap with `bash` + +export HISTFILE="$XDG_STATE_HOME/zsh/history" + +export HISTSIZE=999999 # Number of lines kept in memory +export SAVEHIST=999999 # Number of lines kept in the `$HISTFILE` + +setopt APPEND_HISTORY # Do not overwrite the `$HISTFILE` +setopt HIST_REDUCE_BLANKS # Remove superfluous blanks from the `history` +setopt HIST_IGNORE_DUPS # Ignore commands entered identically just before +setopt HIST_IGNORE_SPACE # Ignore commands prefixed with a space +setopt HIST_VERIFY # Show expanded `history` before executing + + +# Make `zsh` feel even nicer + +setopt AUTO_CD # Just type the directory to `cd` into it + +setopt CORRECT # Correct spelling of commands + +setopt CHECK_JOBS # Show number of running jobs when exiting `zsh` + +setopt EXTENDED_GLOB # Advanced globbing patterns +setopt NOMATCH # Fail loudly if patterns have no matches + +setopt INTERACTIVE_COMMENTS # Allow `#` comments in the interactive shell + +setopt NOBEEP # Silence `zsh` + + +stty -ixon # Prevent s from freezing `zsh` + + +# Enable (tab) completions + +# "-u" disables the ownership check on completion dirs, which is safe since only we write to them +autoload -Uz compinit && compinit -u -d "${XDG_STATE_HOME:-$HOME/.local/state}/zsh/zcompdump" + +# Complete the `--force` flag of the `dotfiles` utilities in ~/.local/bin +compdef '_arguments "--force[skip safety checks / reinstall]"' dotfiles-install dotfiles-update + +# Enable match highlighting and scrolling through long lists, +# and provide a different style of menu completion +zmodload zsh/complist + +# Include hidden files in tab completion +_comp_options+=(GLOB_DOTS) + +# Make selecting completions nicer with a visual menu +zstyle ':completion:*' menu select + +# Make new executables completable right away +zstyle ':completion:*' rehash true + +# Match case-insensitively if the exact casing does not match +zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z}' + +# Group completion results and label them with bold headers +zstyle ':completion:*:descriptions' format '%B%d%b' +zstyle ':completion:*:messages' format '%d' +zstyle ':completion:*:warnings' format 'No matches for: %d' +zstyle ':completion:*' group-name '' + + +# Jump to frequently used directories with `z ` +if _command_exists zoxide; then + eval "$(zoxide init zsh)" +fi + + +# Suggest the `apt` package providing an unknown command +if [ -r /etc/zsh_command_not_found ]; then + . /etc/zsh_command_not_found +fi + + +# Configure key bindings + +# `vi` mode +bindkey -v + +# Use `vi` keys to navigate the completions in the menu +bindkey -M menuselect 'h' vi-backward-char +bindkey -M menuselect 'k' vi-up-line-or-history +bindkey -M menuselect 'l' vi-forward-char +bindkey -M menuselect 'j' vi-down-line-or-history + +# Enable Ctrl-R for reverse history search +bindkey "^R" history-incremental-search-backward + + +# Fuzzy finding for +# - `history`: r +# - files: t +# - `cd`: c +if [ -r /usr/share/doc/fzf/examples/key-bindings.zsh ]; then + . /usr/share/doc/fzf/examples/key-bindings.zsh +fi + +# Fuzzy completion with the `**` trigger +# (e.g., `vi **`, `ssh **`) +if [ -r /usr/share/doc/fzf/examples/completion.zsh ]; then + . /usr/share/doc/fzf/examples/completion.zsh +fi + + +# Suggest the most recent matching `history` entry as gray ghost text +if [ -r /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh ]; then + . /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh + bindkey "^ " autosuggest-accept # Space + right arrow works by default +fi + + +# Highlight the command line while typing (valid=green, invalid=red) +# (Important: Must be sourced at the very end of this file) +if [ -r /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]; then + . /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh +fi