mirror of
https://github.com/gaschz/dotfiles.git
synced 2025-12-04 22:34:27 +01:00
- Standardize capability usage with the terminfo database for portability. POSIX tput does declare only the basic options such as 'init', 'reset' and 'clear', leaving the rest unspecified, that is not ideal but hard coding escape sequences is way worse. - Set colorization options based on number of colors the terminal supports and not the TERM variable when possible. This is incomplete, terminal emulators may support or adapt more than it is advertised, but involves using DECRQSS queries and delays, as an example, 'resize' utility from XTerm uses 3 seconds as delay, this is worrisome. - Term with only '-direct' variants without ending with 256 means it only supports direct-color indexing, therefore 'tmux-direct' cannot be used, but the non-multiplexer terminal 'xterm-direct256' can.
502 lines
14 KiB
Bash
502 lines
14 KiB
Bash
#!/usr/bin/env zsh
|
|
|
|
## SPDX-FileCopyrightText: 2004 - 2022 Tim Pope <https://tpo.pe>
|
|
## SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
|
|
##
|
|
## SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
## Credits: https://github.com/tpope/dotfiles/blob/master/.zshrc
|
|
|
|
## {{{ Requirements
|
|
## If not running interactively, return.
|
|
case $- in
|
|
*i*) ;;
|
|
*) return;;
|
|
esac
|
|
|
|
## Source default files.
|
|
# shellcheck disable=SC1090
|
|
source "$HOME/.zprofile"
|
|
source "$ENV"
|
|
## }}}
|
|
## {{{ Options
|
|
PROMPT_EOL_MARK='%b%B%S%#%s%b'
|
|
## - Quiet
|
|
setopt no_beep
|
|
## - Words
|
|
setopt interactive_comments
|
|
## - History
|
|
SAVEHIST="$HISTSIZE"
|
|
setopt no_extended_history
|
|
setopt hist_expire_dups_first # purge dups first
|
|
setopt hist_ignore_dups # ignore dups in history list
|
|
setopt hist_verify # if command has hist expansion, show it before executing
|
|
setopt inc_append_history # append command to history as soon as it runs
|
|
## - Expansion
|
|
setopt auto_cd
|
|
setopt no_nomatch # if a pattern has no matches print an error
|
|
setopt numeric_glob_sort # sort file names numerically when relevant
|
|
setopt magic_equal_subst # filename expansion for opt=arg
|
|
setopt no_equals # don't interpret =string as a command
|
|
## - Prompt
|
|
setopt prompt_subst
|
|
setopt transient_rprompt
|
|
setopt print_exit_value
|
|
|
|
if test "${color_prompt-}" = "yes"; then
|
|
set zle_bracketed_paste
|
|
autoload -Uz bracketed-paste-magic
|
|
zle -N bracketed-paste bracketed-paste-magic
|
|
autoload -Uz url-quote-magic
|
|
zle -N self-insert url-quote-magic
|
|
|
|
pasteinit() {
|
|
OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]}
|
|
zle -N self-insert url-quote-magic
|
|
}
|
|
pastefinish() {
|
|
zle -N self-insert $OLD_SELF_INSERT
|
|
}
|
|
zstyle :bracketed-paste-magic paste-init pasteinit
|
|
zstyle :bracketed-paste-magic paste-finish pastefinish
|
|
else
|
|
unset zle_bracketed_paste
|
|
fi
|
|
|
|
## }}}
|
|
## {{{ Alias
|
|
alias reload="exec zsh"
|
|
## }}}
|
|
## {{{ Prompt
|
|
|
|
newline=$'\n'
|
|
if test "${color_prompt-}" = "yes"; then
|
|
autoload -U colors && colors
|
|
[[ "${COLORTERM-}" == (24bit|truecolor) ||
|
|
"${terminfo[colors]}" -eq '16777216' ]] || zmodload zsh/nearcolor
|
|
|
|
PS1="\$(resize-terminal)%F{magenta}[%{${usercolor}%}%n@%m%F{reset_color%}"
|
|
PS1="${PS1} %{$dircolor%}%50<...<%~%<<%F{reset_color%}\$(_git_prompt_info)"
|
|
PS1="${PS1}%F{magenta}]%F{reset_color}${newline-}${ps1_symbol} "
|
|
RPS1="%(?..(%F{red%}%?%F{reset_color%}%)%<<)"
|
|
else
|
|
PS1="\$(resize-terminal)[%n@%M %~\$(_git_prompt_info)]${newline}"
|
|
PS1="${PS1}${ps1_symbol} "
|
|
RPS1="%(?..(%?%)%<<)"
|
|
fi
|
|
|
|
## Set window title
|
|
_set_title() {
|
|
case "${1:-}" in
|
|
*install*)
|
|
hash -r ;;
|
|
esac
|
|
print -Pn '\033]1;%l@%m${1+*}\a'
|
|
print -Pn '\033]2;%n@%m:%~'
|
|
if test -n "${1:-}"; then
|
|
print -Pnr ' (%24>..>$1%>>)' | tr '\0-\037' '?'
|
|
fi
|
|
print -Pn " [%l]\a"
|
|
}
|
|
|
|
case "${TERM-}" in
|
|
screen*|tmux*)
|
|
precmd() {
|
|
_set_title "$@"
|
|
if [ "${STY:-}" -o "${TMUX:-}" ]; then
|
|
print -Pn '\033k@\033\\'
|
|
else
|
|
print -Pn '\033k@%m\033\\'
|
|
fi
|
|
}
|
|
preexec() {
|
|
_set_title "$@"
|
|
return 0
|
|
#print -Pnr '%10>..>$1' | tr '\0-\037' '?'
|
|
#if [ "${STY:-}" -o "${TMUX:-}" ]; then
|
|
# print -Pn '\033k@\033\\'
|
|
#else
|
|
# print -Pn '\033k@%m\033\\'
|
|
#fi
|
|
}
|
|
;;
|
|
|
|
*?-direct*|xterm*|rxvt*|Eterm*|kterm*|putty*|dtterm*|ansi*|cygwin*)
|
|
precmd () { _set_title "$@" }
|
|
preexec() { _set_title "$@" }
|
|
;;
|
|
|
|
""|dumb|linux*|vt220*|vt100*) ;;
|
|
|
|
*)
|
|
PS1="%n@%m:%~%# "
|
|
RPS1="%(?..(%?%)%<<)"
|
|
;;
|
|
esac
|
|
|
|
unset hostcolor hostletter hostcode dircolor usercolor usercode newline \
|
|
ps1_symbol
|
|
## }}}
|
|
## {{{ Completions
|
|
|
|
## Enable completion.
|
|
zstyle ':completion:*' use-cache on
|
|
zstyle ':completion:*' cache-path \
|
|
"${XDG_CACHE_HOME:-$HOME/.cache}"/zsh/zcompcache
|
|
zstyle ':completion:*' auto-description 'Specify: %d'
|
|
zstyle ':completion:*' completer _expand _complete _ignored _approximate
|
|
zstyle ':completion:*' expand prefix suffix
|
|
zstyle ':completion:*' file-sort name
|
|
zstyle ':completion:*' group-name ''
|
|
zstyle ':completion:*' ignore-parents parent pwd ..
|
|
zstyle ':completion:*' insert-unambiguous true
|
|
zstyle ':completion:*' list-prompt \
|
|
%SAt %p: Hit TAB for more, or the character to insert%s
|
|
zstyle ':completion:*' list-suffixes true
|
|
zstyle ':completion:*' matcher-list '' \
|
|
'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' \
|
|
'r:|[._-]=** r:|=**' 'l:|=* r:|=*'
|
|
zstyle ':completion:*' menu select=1
|
|
zstyle ':completion:*' original true
|
|
zstyle ':completion:*' preserve-prefix '//[^/]##/'
|
|
zstyle ':completion:*' select-prompt \
|
|
%SScrolling active: current selection at %p%s
|
|
zstyle ':completion:*' special-dirs true
|
|
zstyle ':completion:*' squeeze-slashes true
|
|
zstyle ':completion:*' use-compctl true
|
|
zstyle ':completion:*' verbose true
|
|
zstyle ':completion:*:*:-command-:*:*' file-patterns \
|
|
'*(#q-*):executables:Executables *(-/):directories:Directories'
|
|
zstyle -e ':completion:*:*:-command-:*:*' tag-order '
|
|
reply=("
|
|
executables:Executables:Executables
|
|
builtins:Builtins:Builtins
|
|
commands:Commands:Commands
|
|
aliases:Aliases:Aliases
|
|
functions:Functions:Functions
|
|
parameters:Variables:Variables
|
|
reserved-words:Keywords:Keywords
|
|
directories:Directories
|
|
" -
|
|
)'
|
|
|
|
## Completion per utility.
|
|
zstyle ':completion:*:sudo::' environ \
|
|
HOME="/root" \
|
|
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
zstyle ':completion:*:doas::' environ \
|
|
HOME="/root" \
|
|
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
|
## Colored completions.
|
|
# zstyle ':completion:*' format 'Completing %d'
|
|
if test "${color_prompt-}" = "yes"; then
|
|
zstyle ':completion:*:*:*:*:descriptions' format '%B%F{blue}-- %d --%b%f'
|
|
zstyle ':completion:*:messages' format ' %B%F{purple} -- %d --%f%b'
|
|
zstyle ':completion:*:warnings' format ' %B%F{red}-- no matches --%f%b'
|
|
|
|
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
|
|
zstyle ':completion:*:*:kill:*' list-colors \
|
|
'=(#b) #([0-9]#)*( *[a-z])*=94=91=93'
|
|
else
|
|
zstyle ':completion:*:*:*:*:descriptions' format '-- %d --%b%f'
|
|
zstyle ':completion:*:messages' format ' -- %d --%f%b'
|
|
zstyle ':completion:*:warnings' format ' -- no matches --%f%b'
|
|
|
|
zstyle ':completion:*:default' list-colors ''
|
|
zstyle ':completion:*:*:kill:*' list-colors ''
|
|
fi
|
|
|
|
## Load completions.
|
|
autoload -Uz compinit
|
|
zmodload zsh/complist
|
|
mkdir -p -- "$XDG_CACHE_HOME/zsh"
|
|
compinit -u -d "$XDG_CACHE_HOME/zsh/zcompdump"
|
|
# _comp_options+=(globdots)
|
|
! has zoxide || eval "$(zoxide init zsh)"
|
|
! has gitlint || eval "$(_GITLINT_COMPLETE=zsh_source gitlint)"
|
|
## }}}
|
|
## {{{ Plugins
|
|
source_readable /usr/share/doc/fzf/examples/key-bindings.zsh
|
|
source_readable /usr/share/doc/fzf/examples/completion.zsh
|
|
|
|
if test "${color_prompt-}" = "yes"; then
|
|
## Enable auto-suggestions based on the history
|
|
if test -f /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh; then
|
|
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=30
|
|
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="standout"
|
|
typeset -a ZSH_AUTOSUGGEST_CLEAR_WIDGETS
|
|
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
|
|
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste accept-line)
|
|
source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh
|
|
fi
|
|
## Highlight commands as you type
|
|
if test -f /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
|
|
then
|
|
## https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters
|
|
ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern regexp)
|
|
typeset -A ZSH_HIGHLIGHT_STYLES
|
|
ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=red'
|
|
ZSH_HIGHLIGHT_STYLES[alias]='fg=cyan'
|
|
ZSH_HIGHLIGHT_STYLES[function]='fg=cyan'
|
|
ZSH_HIGHLIGHT_STYLES[builtin]='fg=green'
|
|
ZSH_HIGHLIGHT_STYLES[command]='fg=green'
|
|
ZSH_HIGHLIGHT_STYLES[precommand]='fg=green'
|
|
ZSH_HIGHLIGHT_STYLES[comment]='fg=black,bold'
|
|
ZSH_HIGHLIGHT_STYLES[globbing]='fg=cyan'
|
|
typeset -A ZSH_HIGHLIGHT_REGEXP
|
|
ZSH_HIGHLIGHT_REGEXP+=('^sudo' 'fg=magenta')
|
|
ZSH_HIGHLIGHT_REGEXP+=('^doas' 'fg=magenta')
|
|
source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
|
|
fi
|
|
fi
|
|
## }}}
|
|
## {{{ Bindkeys
|
|
|
|
## Widgets
|
|
##
|
|
function bindkey-multi () {
|
|
## Usage: bindkey-multi mode Nmode -- bind nbind terminfoname -- widgetname
|
|
local i j widget nomap
|
|
local -a maps sequences
|
|
|
|
test "$1" = "--" && nomap=1
|
|
|
|
while [[ "$1" != "--" ]]; do
|
|
maps+=( "$1" )
|
|
shift
|
|
done
|
|
shift
|
|
|
|
while [[ "$1" != "--" ]]; do
|
|
sequences+=( "$1" )
|
|
shift
|
|
done
|
|
shift
|
|
|
|
widget="$1"
|
|
test -z "$widget" && return 1
|
|
|
|
if test -n "$nomap"; then
|
|
for j in "${sequences[@]}"; do
|
|
test "$j" || continue
|
|
bindkey -- "$j" "$widget"
|
|
done
|
|
return 0
|
|
fi
|
|
|
|
for i in "${maps[@]}"; do
|
|
test "$i" || continue
|
|
for j in "${sequences[@]}"; do
|
|
test "$j" || continue
|
|
bindkey -M "$i" -- "$j" "$widget"
|
|
done
|
|
done
|
|
return 0
|
|
}
|
|
|
|
function clear-screen-and-scrollback() {
|
|
case "${TERM-}" in
|
|
""|dumb|linux*|vt100*|vt220*) return;;
|
|
esac
|
|
test -n "${TTY-}" || return
|
|
echoti civis >"${TTY-}"
|
|
printf '%b' "\033[H\033[2J" >"${TTY-}"
|
|
zle .reset-prompt
|
|
zle -R
|
|
printf '%b' "\033[3J" >"${TTY-}"
|
|
echoti cnorm >"${TTY-}"
|
|
}
|
|
zle -N clear-screen-and-scrollback
|
|
|
|
fg-widget() {
|
|
if [[ $#BUFFER -eq 0 ]]; then
|
|
if jobs %- >/dev/null 2>&1; then
|
|
BUFFER='fg %-'
|
|
else
|
|
BUFFER='fg'
|
|
fi
|
|
zle accept-line
|
|
else
|
|
zle push-input
|
|
zle clear-screen
|
|
fi
|
|
}
|
|
zle -N fg-widget
|
|
|
|
change-first-word(){
|
|
zle beginning-of-line -N
|
|
zle kill-word
|
|
}
|
|
zle -N change-first-word
|
|
|
|
new-screen() {
|
|
test -z "${STY-}" || screen < "${TTY-}"
|
|
test -z "${TMUX-}" || tmux new-window
|
|
}
|
|
zle -N new-screen
|
|
|
|
case "${TERM-}" in
|
|
""|dumb|linux*|vt100*|vt220*) ;;
|
|
*)
|
|
zle-keymap-select zle-line-init() {
|
|
case "${KEYMAP:-}" in
|
|
vicmd) print -n -- "\033[2 q";;
|
|
viins|main) print -n -- "\033[5 q";;
|
|
esac
|
|
|
|
zle reset-prompt
|
|
zle -R
|
|
}
|
|
|
|
zle-line-finish() {
|
|
print -n -- "\033[2 q"
|
|
}
|
|
|
|
zle -N zle-line-init
|
|
zle -N zle-line-finish
|
|
zle -N zle-keymap-select
|
|
;;
|
|
esac
|
|
|
|
set-keymap-vi(){
|
|
export KEYTIMEOUT=1
|
|
bindkey -v
|
|
}
|
|
|
|
set-keymap-emacs(){
|
|
bindkey -e
|
|
bindkey -r "^Q"
|
|
}
|
|
|
|
## Keymap mode
|
|
set-keymap-emacs
|
|
|
|
autoload -Uz select-word-style
|
|
select-word-style bash
|
|
|
|
## Viins
|
|
bindkey -M viins "^A" beginning-of-line
|
|
bindkey -M viins "^B" backward-char
|
|
bindkey -M viins "^D" delete-char-or-list
|
|
bindkey -M viins "^E" end-of-line
|
|
bindkey -M viins "^F" forward-char
|
|
bindkey-multi emacs viins vicmd -- "^G" -- which-command
|
|
bindkey -M viins "^J" accept-search
|
|
bindkey -M viins "^K" kill-line
|
|
bindkey -M viins "^L" clear-screen-and-scrollback
|
|
bindkey -M viins "^M" accept-line
|
|
bindkey -M viins "^N" down-line-or-history
|
|
bindkey -M viins "^P" up-line-or-history
|
|
bindkey -M viins "^R" history-incremental-search-backward
|
|
bindkey -M viins "^S" history-incremental-search-forward
|
|
bindkey -M viins "^T" transpose-chars
|
|
bindkey-multi emacs viins -- "^W" -- vi-backward-kill-word
|
|
bindkey -M viins "^U" backward-kill-line
|
|
bindkey -M emacs "^U" backward-kill-line
|
|
bindkey -M viins "^Y" yank
|
|
bindkey-multi emacs viins vicmd -- "^Z" -- fg-widget
|
|
bindkey -M viins "^_" undo
|
|
bindkey -M viins "^@" redo
|
|
bindkey -M viins " " magic-space
|
|
bindkey -M emacs " " magic-space
|
|
bindkey -M emacs "^X^[" vi-cmd-mode
|
|
## Viins alt
|
|
bindkey -M viins "^[u" undo
|
|
bindkey -M viins "^[r" redo
|
|
bindkey -M viins "^[m" copy-prev-shell-word
|
|
|
|
## Misc
|
|
bindkey -M isearch "^J" accept-search 2>/dev/null
|
|
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
|
|
bindkey -M menuselect "^C" send-break
|
|
bindkey -M menuselect "^J" accept-and-infer-next-history # accept-search
|
|
bindkey -M menuselect "^M" accept-line
|
|
|
|
## Keys for multiple modes and multiple bindings.
|
|
## https://invisible-island.net/xterm/xterm-function-keys.html
|
|
##
|
|
## Shit+Tab
|
|
bindkey-multi emacs viins menuselect -- "\033[Z" "${terminfo[kcbt]}" \
|
|
-- reverse-menu-complete
|
|
## Backspace
|
|
bindkey-multi emacs viins vicmd menuselect -- "^H" "^?" "${terminfo[kbs]}" \
|
|
-- backward-delete-char
|
|
## Home
|
|
bindkey-multi emacs viins vicmd -- "\033[1~" "\033[7~" "\033[H" "\033OH" \
|
|
"${terminfo[khome]}" \
|
|
-- beginning-of-line
|
|
## Insert
|
|
bindkey-multi emacs viins vicmd -- "\033[2~" "\033[L" "${terminfo[kich1]}" \
|
|
-- overwrite-mode
|
|
## Delete
|
|
bindkey-multi emacs viins vicmd -- "\033[3~" "\033[P" "\033OP" \
|
|
"${terminfo[kdch1]}" \
|
|
-- vi-delete-char
|
|
## End
|
|
bindkey-multi emacs viins vicmd -- "\033[4~" "\033[8~" "\033[F" "\033OF" \
|
|
"${terminfo[kend]}" \
|
|
-- end-of-line
|
|
## PgUp
|
|
bindkey-multi emacs viins -- "\033[5~" "\033[I" "${terminfo[kpp]}" \
|
|
-- beginning-of-buffer-or-history
|
|
## PgDown
|
|
bindkey-multi emacs viins -- "\033[6~" "\033[G" "${terminfo[knp]}" \
|
|
-- end-of-buffer-or-history
|
|
## Up arrow
|
|
bindkey-multi emacs viins vicmd -- "\033[A" "\033OA" "${terminfo[kcuu1]}" \
|
|
-- up-line-or-history
|
|
## Down arrow
|
|
bindkey-multi emacs viins vicmd -- "\033[B" "\033OB" "${terminfo[kcud1]}" \
|
|
-- down-line-or-history
|
|
## Right arrow
|
|
bindkey-multi emacs viins vicmd -- "\033[1C" "\033[C" "\033OC" \
|
|
"${terminfo[kcuf1]}" \
|
|
-- forward-char
|
|
## Left arrow
|
|
bindkey-multi emacs viins vicmd -- "\033[D" "\033OD" "${terminfo[kcub1]}" \
|
|
-- backward-char
|
|
## Ctrl-Delete
|
|
bindkey-multi emacs viins vicmd -- "\033[3;5~" "\033[3\^" "${terminfo[kDC5]}" \
|
|
-- kill-word
|
|
## Ctrl-RightArrow
|
|
bindkey-multi emacs viins vicmd -- "\033[1;5C" "\0330c" "${terminfo[kRIT5]}" \
|
|
-- forward-word
|
|
## Ctrl-LeftArrow
|
|
bindkey-multi emacs viins vicmd -- "\033[1;5D" "\0330d" "${terminfo[kLFT5]}" \
|
|
-- backward-word
|
|
## F11
|
|
bindkey-multi emacs viins -- "\033[23~" "${terminfo[kf11]}" -- new-screen
|
|
|
|
autoload -Uz edit-command-line
|
|
zle -N edit-command-line
|
|
bindkey -M emacs "^[e" edit-command-line
|
|
bindkey -M emacs "^X^E" edit-command-line
|
|
bindkey -M vicmd "^E" edit-command-line
|
|
|
|
bindkey -M emacs "\033a" change-first-word
|
|
bindkey -M emacs "^XD" describe-key-briefly
|
|
|
|
for binding in ${(f)$(bindkey -M emacs|grep -e '^"\^X')}; do
|
|
bindkey -M viins "${(@Qz)binding}"
|
|
done
|
|
unset binding
|
|
|
|
## Make sure the terminal is in application mode, when zle is active.
|
|
## Only then are the values from $terminfo valid.
|
|
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
|
|
## }}}
|
|
## {{{ End
|
|
## Source local zsh configuration.
|
|
source_readable "$HOME/.zshrc.local"
|
|
## }}}
|