#!/bin/zsh # http://zsh.sourceforge.net/Doc/Release/Options.html # ============================================================================= # History # ============================================================================= # If this is set, zsh sessions will append their history list to the history # file, rather than replace it. setopt APPEND_HISTORY # Save each command’s beginning timestamp and the duration to the history file. setopt EXTENDED_HISTORY # When searching for history entries in the line editor, do not display # duplicates of a line previously found. setopt HIST_FIND_NO_DUPS # Remove command lines from the history list when the first character on the # line is a space, or when one of the expanded aliases contains a leading space. setopt HIST_IGNORE_SPACE # Number of lines of history kept within the shell. HISTSIZE=10000 # Number of lines of history to save to $HISTFILE. SAVEHIST=10000 # File where history is saved. HISTFILE=~/.histfile # ============================================================================= # Input/Output # ============================================================================= # Allow comments even in interactive shells. setopt INTERACTIVE_COMMENTS # Don't beep on error. setopt NO_BEEP # ============================================================================= # Changing Directories # ============================================================================= # If a command is issued that can’t be executed as a normal command, and the # command is the name of a directory, perform the cd command to that directory. setopt AUTO_CD # Make cd push the old directory onto the directory stack (cd -). setopt AUTO_PUSHD # Don’t push multiple copies of the same directory onto the directory stack. setopt PUSHD_IGNORE_DUPS # Global aliases for fast directory navigation. Global aliases are substituted # anywhere on a line. alias ...='../..' alias ....='../../..' alias .....='../../../..' # ============================================================================= # Environment # ============================================================================= # Add ~/.local/bin to $PATH. export PATH="${HOME}/.local/bin:${PATH}" # Automatically remove duplicates from these arrays. typeset -U path PATH cdpath CDPATH fpath FPATH manpath MANPATH # ============================================================================= # Job Control # ============================================================================= # Report the status of background jobs immediately, rather than waiting until # just before printing a prompt. setopt NOTIFY # Print job notifications in the long format (show e.g. PIDs) by default. setopt LONG_LIST_JOBS # Don't send SIGHUP to background processes when the shell exits. setopt NO_HUP # ============================================================================= # Colours # ============================================================================= # Inside tmux TERM must be "screen", "tmux", or "tmux-256color". # See https://github.com/tmux/tmux/wiki/FAQ and https://github.com/tmux/tmux/issues/625. if [[ -v TMUX ]]; then export TERM="tmux-256color" else export TERM="xterm-256color" fi # Evaluate dircolors to populate $LS_COLORS eval "$(dircolors)" # Add colour to common applications using aliases. # https://wiki.archlinux.org/index.php/Color_output_in_console alias diff='diff --color=auto' alias grep='grep --color=auto' alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias ip='ip --color=auto' # Add source code highlighting to less. # https://www.gnu.org/software/src-highlite/source-highlight.html#Using-source_002dhighlight-with-less if [[ -x "$(command -v source-highlight-esc.sh)" ]]; then # debian export LESSOPEN="| source-highlight-esc.sh %s --tab=4" export LESS=' -R ' elif [[ -x "$(command -v /usr/share/source-highlight/source-highlight-esc.sh)" ]]; then # ubuntu export LESSOPEN="| /usr/share/source-highlight/source-highlight-esc.sh %s --tab=4" export LESS=' -R ' else print -P '%F{8}Warning: source-highlight package missing.' fi # ============================================================================= # Aliases # ============================================================================= # Better ls alias ls='ls --color=auto --classify --group-directories-first -v' alias ll='ls -lh' alias lla='ll -a' # Nice-to-have aliases for (in)frequently used or hard-to-remember commands. alias upgrade='sudo apt update && sudo apt upgrade && sudo apt autoremove' alias rcheck='rhash --check --recursive --percents .' alias rsynca='rsync --archive --compress --partial --human-readable --progress' alias serve='python3 -m http.server' function speedtest() { function f() { echo "================================= $1 =================================" curl --max-time 10 --output /dev/null $2 } f "Datapacket" http://fra.download.datapacket.com/10000mb.bin f "Cachefly" http://cachefly.cachefly.net/100mb.test f "OVH" http://www.ovh.net/files/1Gio.dat f "Digital Ocean" http://speedtest-ams3.digitalocean.com/100mb.test f "Linode" http://speedtest.frankfurt.linode.com/100MB-frankfurt.bin f "Online.net" http://ping.online.net/10000Mo.dat f "Hetzner" https://speed.hetzner.de/1GB.bin f "Vultr" https://fra-de-ping.vultr.com/vultr.com.1000MB.bin f "LeaseWeb" https://mirror.de.leaseweb.net/speedtest/1000mb.bin f "Ramnode" http://lg.nl.ramnode.com/static/1000MB.test f "OVH GRA" http://gra.proof.ovh.net/files/1Gio.dat } # ============================================================================= # Keybinds # ============================================================================= # Enable searching through history for commands matching everything up to the # current cursor position. (https://coderwall.com/p/jpj_6q/zsh-better-history-searching-with-arrow-keys). autoload -U up-line-or-beginning-search autoload -U down-line-or-beginning-search zle -N up-line-or-beginning-search zle -N down-line-or-beginning-search # Use Emacs-style keybinds. bindkey -e # Bind keys as one would expect them to be bound. # Use 'cat -v' to character sequences. bindkey "$terminfo[kbs]" backward-delete-char # BackSpace bindkey "$terminfo[khome]" beginning-of-line # Home bindkey "$terminfo[kend]" end-of-line # End bindkey "$terminfo[kich1]" overwrite-mode # Insert bindkey "$terminfo[kdch1]" delete-char # Delete bindkey "$terminfo[kcuu1]" up-line-or-beginning-search # Up bindkey "$terminfo[kcud1]" down-line-or-beginning-search # Down bindkey "$terminfo[kcub1]" backward-char # Left bindkey "$terminfo[kcuf1]" forward-char # Right #bindkey "$terminfo[kpp]" x # PageUp #bindkey "$terminfo[knp]" x # PageDown bindkey "^[[1;5D" backward-word # Ctrl+Left bindkey "^[[1;5C" forward-word # Ctrl+Right bindkey "^H" backward-delete-word # Ctrl+Backspace bindkey "^[[3;5~" delete-word # Ctrl+Delete bindkey "^[[Z" reverse-menu-complete # Shift+Tab # Additional keybinds. bindkey "^[?" run-help # Alt+? bindkey "^[+" run-help # Alt++ (simpler on Danish keyboards) # Remove '/' from WORDCHARS, making Ctrl+{Right,Left,Backspace} work correctly # on path segments instead of operating on the entire path at once. WORDCHARS=${WORDCHARS:s@/@} # ============================================================================= # Completion # ============================================================================= autoload -Uz compinit compinit # # Options # # If a completion is performed with the cursor within a word, and a full # completion is inserted, the cursor is moved to the end of the word. setopt ALWAYS_TO_END # Automatically list choices on an ambiguous completion. setopt AUTO_LIST # Automatically use menu completion after the second consecutive request for # completion, for example by pressing the tab key repeatedly. setopt AUTO_MENU # If unset, the cursor is set to the end of the word if completion is started. # Otherwise it stays there and completion is done from both ends. setopt COMPLETE_IN_WORD # If a parameter is completed whose content is the name of a directory, then # add a trailing slash instead of a space. setopt AUTO_PARAM_SLASH # On an ambiguous completion, list possibilities instead of inserting the first # match immediately. setopt NO_MENU_COMPLETE # # Styles # # Group matches and describe. zstyle ':completion:*:*:*:*:*' menu select zstyle ':completion:*:matches' group 'yes' zstyle ':completion:*:options' description 'yes' zstyle ':completion:*:options' auto-description 'specify: %d' zstyle ':completion:*:corrections' format ' %F{green}-- %d (errors: %e) --%f' zstyle ':completion:*:descriptions' format ' %F{yellow}-- %d --%f' zstyle ':completion:*:messages' format ' %F{purple} -- %d --%f' zstyle ':completion:*:warnings' format ' %F{red}-- no matches found --%f' zstyle ':completion:*:default' list-prompt '%S%M matches%s' zstyle ':completion:*' format ' %F{yellow}-- %d --%f' zstyle ':completion:*' group-name '' zstyle ':completion:*' verbose yes # Try smart-case completion, then case-insensitive, then partial-word, and then # substring completion. # See http://zsh.sourceforge.net/Doc/Release/Completion-Widgets.html#Completion-Matching-Control. zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Z}{a-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*' # Use the same colors as 'ls' in completion zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS} # Keep directories and files separated zstyle ':completion:*' list-dirs-first true # The value of this style is used in completion listing to separate the string # to complete from a description when completing options. zstyle ':completion:*:options' list-separator \| # This makes it so that the option descriptions are gray instead of the same # colour as the options themselves to avoid confusion. This code itself, # however, is very confusing and I have no idea how it works. zstyle ':completion:*:options' list-colors \ "=(#b)(-##)([^ ]#) #(\\|)(*)=0=38;5;23=${color[bold]}=38;5;237=38;5;242" \ "=(#b)(-##)([^ ]#)(*)=0=38;5;23=${color[bold]}" \ "=(#b) #(\\|)(*)=0=38;5;237=38;5;242" # Enable completion for '../' zstyle ':completion:*' special-dirs true # Behave as if there were a ‘*’ between sequences of slashes in filename paths. # E.g., foo//bar will be treated as foo/*/bar. zstyle ':completion:*' squeeze-slashes false # Make completions for apt etc. usable by activating completion caching layer. zstyle ':completion::complete:*' use-cache on # Don't complete hosts from /etc/hosts zstyle -e ':completion:*' hosts 'reply=()' # Provide more processes in completion of programs like kill and killall zstyle ':completion:*:*:*:*:processes' command 'ps -u $LOGNAME -o pid,user,command -w' zstyle ':completion:*:processes-names' command "ps -eo cmd= | sed 's:\([^ ]*\).*:\1:;s:\(/[^ ]*/\)::;/^\[/d'" zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;36=0=01' zstyle ':completion:*:*:kill:*' menu yes select zstyle ':completion:*:*:kill:*' force-list always zstyle ':completion:*:*:kill:*' insert-ids single # Man zstyle ':completion:*:manuals' separate-sections true zstyle ':completion:*:manuals.(^1*)' insert-sections true zstyle ':completion:*:man:*' menu yes select # Pasting with tabs doesn't perform completion zstyle ':completion:*' insert-tab pending # SSH/SCP/RSYNC tag order zstyle ':completion:*:(scp|rsync):*' tag-order 'hosts:-host:host hosts:-domain:domain hosts:-ipaddr:ip\ address *' zstyle ':completion:*:(scp|rsync):*' group-order users files all-files hosts-domain hosts-host hosts-ipaddr zstyle ':completion:*:ssh:*' tag-order 'hosts:-host:host hosts:-domain:domain hosts:-ipaddr:ip\ address *' zstyle ':completion:*:ssh:*' group-order users hosts-domain hosts-host users hosts-ipaddr zstyle ':completion:*:(ssh|scp|rsync):*:hosts-host' ignored-patterns '*(.|:)*' loopback ip6-loopback localhost ip6-localhost broadcasthost zstyle ':completion:*:(ssh|scp|rsync):*:hosts-domain' ignored-patterns '<->.<->.<->.<->' '^[-[:alnum:]]##(.[-[:alnum:]]##)##' '*@*' zstyle ':completion:*:(ssh|scp|rsync):*:hosts-ipaddr' ignored-patterns '^(<->.<->.<->.<->|(|::)([[:xdigit:].]##:(#c,2))##(|%*))' '127.0.0.<->' '255.255.255.255' '::1' 'fe80::*' # Ignore internal shell functions zstyle ':completion:*:functions' ignored-patterns '_*' # ============================================================================= # Prompting # ============================================================================= # Prompt expansion 101: (http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html) # %F => color dict (https://wiki.archlinux.org/index.php/Zsh#Colors) # %f => reset color # %~ => current path # %n => username # %m => shortname host # %(?..) => prompt conditional - %(condition.true.false) # vcs_info: # %b => current branch # %a => current action (rebase/merge) # # Options # # Enable command substitution and arithmetic expansion in prompts using '$()'. setopt PROMPT_SUBST # Disallow virtual envirnments from updating the prompt. export VIRTUAL_ENV_DISABLE_PROMPT=1 # # Git # http://zsh.sourceforge.net/Doc/Release/User-Contributions.html # # Load vcs_info git module autoload -Uz vcs_info zstyle ':vcs_info:*' enable git # Only export the one 'vcs_info_msg_0_' message variable. zstyle ':vcs_info:*' max-exports 1 # Set formats zstyle ':vcs_info:git*' formats '@%F{yellow}%b%f' # actionformats is used if there is a special action going on in the current # repository; like an interactive rebase or a merge conflict. zstyle ':vcs_info:git*' actionformats '@%F{yellow}%b%f|%F{magenta}%a%f' # # Prompt # # Define the precmd hook function, which is executed before each prompt. precmd () { vcs_info # makes sure we have up-to-date vcs info } PROMPT='' # Show '(venv)' in gray if in virtual environment. PROMPT+='$([[ -v VIRTUAL_ENV ]] && print "%F{8}(`basename $VIRTUAL_ENV`)%f ")' # Show 'hostname:' if logged in through SSH. Only checked once since it cannot # change mid-session, unlike a virtual environment, like configured above. # https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg if [[ -v SSH_CONNECTION ]]; then PROMPT+='%F{010}%m%f:' fi # Add the current working directory. PROMPT+='%F{12}%~%f' # Add version control info PROMPT+='${vcs_info_msg_0_}' # Make the prompt character green if last command successful, otherwise red. PROMPT+='%(?.%F{green}.%F{red})' # Add the actual prompt character: '#' if running with privileges, '❯' if not. PROMPT+='%(!.#.❯)%f ' # ============================================================================= # Xterm Title # ============================================================================= autoload -Uz add-zsh-hook function xterm_title_precmd () { print -Pn '\e]2;%n@%m %1~\a' } function xterm_title_preexec () { print -Pn '\e]2;%n@%m %1~ %# ' print -n "${(q)1}\a" } if [[ "$TERM" == (screen*|xterm*|rxvt*) ]]; then add-zsh-hook -Uz precmd xterm_title_precmd add-zsh-hook -Uz preexec xterm_title_preexec fi # ============================================================================= # Plugins -- Must be loaded last # ============================================================================= # # zsh syntax highlighting: Fish shell like syntax highlighting for Zsh # https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters.md # if [[ -e /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]]; then source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern cursor) ## Main ## Pattern ZSH_HIGHLIGHT_PATTERNS+=('sudo rm' 'fg=white,bold,bg=red') ZSH_HIGHLIGHT_PATTERNS+=('sudo dd' 'fg=white,bold,bg=red') ## Cursor ZSH_HIGHLIGHT_STYLES[cursor]='underline' else print -P '%F{8}Warning: zsh-syntax-highlighting package missing.' fi # # zsh auto-suggestions # if [[ -e /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh ]]; then source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh ZSH_AUTOSUGGEST_STRATEGY=(match_prev_cmd completion) #ZSH_AUTOSUGGEST_COMPLETION_IGNORE="(|sudo )apt install *" else print -P '%F{8}Warning: zsh-autosuggestions package missing.' fi