549 lines
17 KiB
Bash
549 lines
17 KiB
Bash
setup_terminal() {
|
||
# Make ctrl-q and ctrl-s available to terminal applications.
|
||
stty start undef stop undef
|
||
}
|
||
|
||
setup_aliases() {
|
||
# ls: make `ls` group directories first if supported.
|
||
# lsc: force `ls` to use color output (e.g. for piping into `less`).
|
||
|
||
# Precendence of program to back the `ls` alias:
|
||
# 1. `eza`, if installed.
|
||
# 2. GNU ls
|
||
# 3. BSD ls (e.g. macOS)
|
||
if type -p eza >/dev/null; then
|
||
alias ls="eza --classify --group-directories-first --group --links --smart-group"
|
||
alias la="ls --all"
|
||
alias lt="ls --long --tree --ignore-glob='.git'"
|
||
alias lta="lt --all"
|
||
alias lsc="ls --color=always"
|
||
alias ltc="lt --color=always"
|
||
elif ls --group-directories-first --color=auto >/dev/null 2>&1; then
|
||
alias ls="ls --classify --human-readable --group-directories-first --color=auto"
|
||
alias la="ls --almost-all"
|
||
alias lt="tree --dirsfirst -FI '.git|Spotlight-V100|.fseventsd'"
|
||
alias lsc="ls --color=always"
|
||
alias ltc="tree -C --dirsfirst -FI '.git'"
|
||
else
|
||
alias ls="ls -hF -G"
|
||
alias la="ls -A"
|
||
alias lt="tree --dirsfirst -FI '.git|Spotlight-V100|.fseventsd'"
|
||
alias lsc="/usr/bin/env CLICOLOR_FORCE=1 ls"
|
||
alias ltc="tree -C --dirsfirst -FI '.git'"
|
||
fi
|
||
|
||
alias ll="ls -l"
|
||
alias lla="la -l"
|
||
alias ltl="lt -L"
|
||
|
||
alias dots="cd ~/.dotfiles"
|
||
|
||
alias grep="grep --color=auto"
|
||
alias egrep="egrep --color=auto"
|
||
alias fgrep="fgrep --color=auto"
|
||
|
||
if type -p nvim >/dev/null; then
|
||
alias v="nvim"
|
||
alias vi="nvim"
|
||
alias vim="nvim"
|
||
alias vimdiff="nvim -d"
|
||
fi
|
||
}
|
||
|
||
# source "$ZDOTDIR/completion.zsh"
|
||
setup_completion() {
|
||
# Enable additional completions from packages in `/usr/local`.
|
||
local vendor="/usr/local/share/zsh/vendor-completions"
|
||
[ -d "$vendor" ] && fpath=("$vendor" $fpath)
|
||
|
||
zmodload zsh/complist
|
||
autoload -Uz compinit
|
||
compinit -d "$XDG_CACHE_HOME/zsh/.zcompdump"
|
||
|
||
# Include hidden files when completing.
|
||
_comp_options+=(globdots)
|
||
|
||
# Completion context pattern:
|
||
# :completion:<function>:<completer>:<command>:<argument>:<tag>
|
||
|
||
# Which completion functions to use.
|
||
zstyle ':completion:*' completer _extensions _complete
|
||
|
||
# Match case-insensitively and on partial words.
|
||
zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}'
|
||
|
||
# Activate caching for completions that may use it.
|
||
zstyle ':completion:*' use-cache true
|
||
zstyle ':completion:*' cache-path "$XDG_CACHE_HOME/zsh/.zcompcache"
|
||
|
||
# List files in a format similar to `ls -l`.
|
||
zmodload zsh/stat # required for `file-list all`
|
||
disable stat # don't shadow external `stat` executable
|
||
zstyle ':completion:*' file-list all
|
||
|
||
# Don't complete on all path components, which would complete /u/b/z to /usr/bin/zsh.
|
||
zstyle ':completion:*' path-completion false
|
||
|
||
# Use tags as the group names.
|
||
zstyle ':completion:*' group-name ''
|
||
|
||
# Custom order for words in the command position.
|
||
zstyle ':completion:*:*:-command-:*:*' group-order builtins aliases functions commands
|
||
|
||
# Colors!
|
||
zstyle ':completion:*:*:*:*:descriptions' format '%F{green}❯❯ %d%f'
|
||
zstyle ':completion:*:*:*:*:corrections' format '%F{yellow}❯❯ %d%f'
|
||
zstyle ':completion:*:*:*:*:original' format '%F{yellow}❯❯ %d%f'
|
||
zstyle ':completion:*:*:*:*:messages' format '%F{cyan}❯❯ %d%f'
|
||
zstyle ':completion:*:*:*:*:warnings' format '%F{red}❯❯ no matches%f'
|
||
zstyle ':completion:*:*:*:*:default' list-colors true
|
||
|
||
##################
|
||
# Menu selection #
|
||
##################
|
||
zstyle ':completion:*' menu select
|
||
zstyle ':completion:*:*:*:*:default' select-prompt '%K{yellow}%F{black}%l (%p)%f%k'
|
||
|
||
# Navigate the list with `hjkl`.
|
||
bindkey -M menuselect 'h' vi-backward-char
|
||
bindkey -M menuselect 'j' vi-down-line-or-history
|
||
bindkey -M menuselect 'k' vi-up-line-or-history
|
||
bindkey -M menuselect 'l' vi-forward-char
|
||
|
||
# Accept selected match and keep menu open.
|
||
bindkey -M menuselect 'p' accept-and-hold
|
||
|
||
# Accept selected match and restart completion (allows drilling down directories).
|
||
bindkey -M menuselect '\t' accept-and-infer-next-history
|
||
|
||
# Remove previously inserted matches.
|
||
bindkey -M menuselect 'u' undo
|
||
|
||
# Jump to first/last line.
|
||
bindkey -M menuselect 'g' beginning-of-history
|
||
bindkey -M menuselect 'G' end-of-history
|
||
|
||
# Page down/up.
|
||
bindkey -M menuselect 'f' vi-forward-word
|
||
bindkey -M menuselect 'b' vi-backward-word
|
||
}
|
||
|
||
setup_history() {
|
||
setopt APPEND_HISTORY # Append history rather than overwrite.
|
||
setopt EXTENDED_HISTORY # Save beginning timestamp and duration.
|
||
setopt INC_APPEND_HISTORY # Don't wait until shell exits to save history.
|
||
setopt HIST_IGNORE_ALL_DUPS # Don't add duplicates to history.
|
||
|
||
HISTFILE="${XDG_DATA_HOME:-$HOME/.local/share}/zsh/history"
|
||
HISTSIZE=1000000
|
||
SAVEHIST=1000000
|
||
}
|
||
|
||
setup_zle() {
|
||
bindkey -v # Use vi mode for line editing.
|
||
export KEYTIMEOUT=1 # 10ms delay for <esc> to switch to command mode.
|
||
|
||
#############################
|
||
# ZLE Widgets
|
||
#############################
|
||
fs-set-cursor-shape() {
|
||
local block='\e[1 q' # blinking block
|
||
local underline='\e[3 q' # blinking underline, 4 for steady
|
||
local bar='\e[5 q' # blinkind bar, 6 for steady
|
||
if [[ -n "$ITERM_SESSION_ID" && -z "$TMUX" ]] {
|
||
block='\e]1337;CursorShape=0\a'
|
||
bar='\e]1337;CursorShape=1\a'
|
||
underline='\e]1337;CursorShape=2\a'
|
||
}
|
||
|
||
case "$1" in
|
||
block) echo -n $block ;;
|
||
bar) echo -n $bar ;;
|
||
underline) echo -n $underline ;;
|
||
esac
|
||
}
|
||
|
||
autoload -Uz add-zle-hook-widget
|
||
|
||
# Start new prompts with bar shaped cursor.
|
||
add-zle-hook-widget line-init fs-zle-line-init
|
||
fs-zle-line-init() {
|
||
fs-set-cursor-shape bar
|
||
}
|
||
|
||
# Switch cursor shape depending on editing mode.
|
||
add-zle-hook-widget keymap-select fs-zle-keymap-select
|
||
fs-zle-keymap-select() {
|
||
case $KEYMAP in
|
||
vicmd) fs-set-cursor-shape block ;;
|
||
viins|main) fs-set-cursor-shape bar ;;
|
||
esac
|
||
}
|
||
|
||
# Clear completion menus and other status line text.
|
||
zle -N fs-zle-clear-status-line
|
||
fs-zle-clear-status-line() { zle -R -c; }
|
||
|
||
# Change root directory of the current git repository, if in one.
|
||
zle -N fs-zle-cd-git-root
|
||
fs-zle-cd-git-root() {
|
||
local top_level="$(git rev-parse --show-toplevel 2>/dev/null)"
|
||
[[ -z "$top_level" ]] && return 1
|
||
zle push-line
|
||
BUFFER="builtin cd -- ${(q)top_level}"
|
||
zle accept-line
|
||
}
|
||
|
||
autoload edit-command-line && zle -N edit-command-line # from zshcontrib
|
||
|
||
#############################
|
||
# Key mappings
|
||
#############################
|
||
|
||
# -------------- CTRL -------------------------------
|
||
bindkey -M viins '^a' vi-beginning-of-line
|
||
bindkey -M viins '^e' vi-end-of-line
|
||
bindkey -M viins '^g' fs-zle-cd-git-root
|
||
bindkey -M viins '^j' history-beginning-search-forward
|
||
bindkey -M viins '^k' history-beginning-search-backward
|
||
bindkey -M viins '^l' clear-screen
|
||
bindkey -M viins '^q' fs-zle-clear-status-line
|
||
# ^r history search using fzf
|
||
# ^t paste file/directory using fzf
|
||
bindkey -M viins '^u' kill-whole-line
|
||
bindkey -s '^v' '^unvim\r'
|
||
bindkey -M viins '^x^e' edit-command-line
|
||
bindkey -M viins '^y' yank
|
||
|
||
# -------------- ALT -------------------------------
|
||
bindkey -M viins '^[.' insert-last-word
|
||
bindkey -M viins '^[b' vi-backward-word
|
||
# ^[c cd using fzf
|
||
bindkey -M viins '^[f' vi-forward-word
|
||
|
||
# --------- Command mode -------------------------------
|
||
bindkey -M vicmd ' ' edit-command-line
|
||
|
||
#############################
|
||
# fzf
|
||
#############################
|
||
if type -p fzf >/dev/null; then
|
||
setup_zle_fzf
|
||
else
|
||
# Fall back to incremental search
|
||
bindkey -M viins '^r' history-incremental-search-backward
|
||
bindkey -M isearch '^j' history-incremental-search-forward
|
||
bindkey -M isearch '^k' history-incremental-search-backward
|
||
bindkey -M isearch '^y' accept-search
|
||
fi
|
||
}
|
||
|
||
setup_zle_fzf() {
|
||
local fzf_config="$ZDOTDIR/fzf/key-bindings.zsh"
|
||
[ -r "$fzf_config" ] || return
|
||
|
||
fzf_find() {
|
||
local excluded_dirs=("-name '.*'") # Exclude hidden directories.
|
||
if [ "$(uname -s)" = "Darwin" ] && [ "$(pwd)" = "$HOME" ]; then
|
||
# These macOS directories would make the find command unusable (too slow).
|
||
excluded_dirs+=(
|
||
"-name Library"
|
||
"-name Movies"
|
||
"-name Music"
|
||
"-name Pictures"
|
||
)
|
||
fi
|
||
|
||
local excluded_filesystems=(
|
||
"-fstype devfs"
|
||
"-fstype devtmpfs"
|
||
"-fstype proc"
|
||
"-fstype sysfs"
|
||
)
|
||
|
||
local excluded_items=(
|
||
"-type d \\( ${(j: -o :)excluded_dirs} \\)"
|
||
"${(j: -o :)excluded_filesystems}"
|
||
)
|
||
|
||
local excluded="\\( ${(j: -o :)excluded_items} \\) -prune"
|
||
local included="\\( ${(j: -o :)@} \\) -print"
|
||
eval "command find -L . -mindepth 1 $excluded -o $included 2>/dev/null | cut -c3-"
|
||
}
|
||
|
||
fzf_find_files() {
|
||
fzf_find "-type d" "-type f"
|
||
}
|
||
|
||
fzf_find_dirs() {
|
||
fzf_find "-type d"
|
||
}
|
||
|
||
source "$fzf_config"
|
||
export FZF_CTRL_T_COMMAND=fzf_find_files
|
||
export FZF_ALT_C_COMMAND=fzf_find_dirs
|
||
export FZF_CTRL_T_OPTS=--border-label='" Select file(s) "'
|
||
export FZF_CTRL_R_OPTS=--border-label='" History search "'
|
||
export FZF_ALT_C_OPTS=--border-label='" Change directory "'
|
||
}
|
||
|
||
# Colorful man pages.
|
||
setup_man_pages() {
|
||
# Foreground colors
|
||
typeset -A fg
|
||
fg[black]='\e[30m'
|
||
fg[red]='\e[31m'
|
||
fg[green]='\e[32m'
|
||
fg[yellow]='\e[33m'
|
||
fg[blue]='\e[34m'
|
||
fg[magenta]='\e[35m'
|
||
fg[cyan]='\e[36m'
|
||
fg[white]='\e[37m'
|
||
fg[br_black]='\e[90m'
|
||
fg[br_red]='\e[91m'
|
||
fg[br_green]='\e[92m'
|
||
fg[br_yellow]='\e[93m'
|
||
fg[br_blue]='\e[94m'
|
||
fg[br_magenta]='\e[95m'
|
||
fg[br_cyan]='\e[96m'
|
||
fg[br_white]='\e[97m'
|
||
|
||
# Background colors
|
||
typeset -A bg
|
||
bg[black]='\e[40m'
|
||
bg[red]='\e[41m'
|
||
bg[green]='\e[42m'
|
||
bg[yellow]='\e[43m'
|
||
bg[blue]='\e[44m'
|
||
bg[magenta]='\e[45m'
|
||
bg[cyan]='\e[46m'
|
||
bg[white]='\e[47m'
|
||
bg[br_black]='\e[100m'
|
||
bg[br_red]='\e[101m'
|
||
bg[br_green]='\e[102m'
|
||
bg[br_yellow]='\e[103m'
|
||
bg[br_blue]='\e[104m'
|
||
bg[br_magenta]='\e[105m'
|
||
bg[br_cyan]='\e[106m'
|
||
bg[br_white]='\e[107m'
|
||
|
||
# Other modifiers
|
||
local reset='\e[0m'
|
||
local bold='\e[1m'
|
||
local faint='\e[2m'
|
||
local italic='\e[3m'
|
||
local underline='\e[4m'
|
||
|
||
#######################
|
||
# Customize man pages #
|
||
#######################
|
||
|
||
# bold (md) and blink (mb)
|
||
export LESS_TERMCAP_md="$(printf %b $fg[blue])"
|
||
export LESS_TERMCAP_mb="$LESS_TERMCAP_md"
|
||
export LESS_TERMCAP_me="$(printf %b $reset)"
|
||
|
||
# underline
|
||
export LESS_TERMCAP_us="$(printf %b $fg[br_blue] $italic $underline)"
|
||
export LESS_TERMCAP_ue="$(printf %b $reset)"
|
||
|
||
# search
|
||
export LESS_TERMCAP_so="$(printf %b $fg[black] $bg[yellow] $bold)"
|
||
export LESS_TERMCAP_se="$(printf %b $reset)"
|
||
|
||
# Tell `groff` to not emit SGR sequences, since we are telling `less` to
|
||
# generate them as per the configurations above.
|
||
export GROFF_NO_SGR=1
|
||
}
|
||
|
||
setup_prompt() {
|
||
source "$ZDOTDIR/prompt.zsh"
|
||
}
|
||
|
||
setup_eza() {
|
||
type -p eza >/dev/null || return
|
||
|
||
local black=30
|
||
local red=31
|
||
local green=32
|
||
local yellow=33
|
||
local blue=34
|
||
local magenta=35
|
||
local cyan=36
|
||
local white=37
|
||
|
||
local br_black=90
|
||
local br_red=91
|
||
local br_green=92
|
||
local br_yellow=93
|
||
local br_blue=94
|
||
local br_magenta=95
|
||
local br_cyan=96
|
||
local br_white=97
|
||
|
||
local colors=(
|
||
di=$blue # directories
|
||
ex=$green # executable files
|
||
# fi # regular files
|
||
# pi # named pipes
|
||
# so # sockets
|
||
# bd # block devices
|
||
# cd # character devices
|
||
# ln # symlinks
|
||
# or # symlinks with no target
|
||
# oc # the permissions displayed as octal
|
||
ur=$yellow # the user-read permission bit
|
||
uw=$red # the user-write permission bit
|
||
ux=$green # the user-execute permission bit for regular files
|
||
ue=$green # the user-execute for other file kinds
|
||
# gr # the group-read permission bit
|
||
# gw # the group-write permission bit
|
||
# gx # the group-execute permission bit
|
||
# tr # the others-read permission bit
|
||
# tw # the others-write permission bit
|
||
# tx # the others-execute permission bit
|
||
# su # setuid, setgid, and sticky permission bits for files
|
||
# sf # setuid, setgid, and sticky for other file kinds
|
||
# xa # the extended attribute indicator
|
||
# sn # the numbers of a file’s size (sets nb, nk, nm, ng and nt)
|
||
# nb # the numbers of a file’s size if it is lower than 1 KB/Kib
|
||
nk=$green # the numbers of a file’s size if it is between 1 KB/KiB and 1 MB/MiB
|
||
# nm # the numbers of a file’s size if it is between 1 MB/MiB and 1 GB/GiB
|
||
# ng # the numbers of a file’s size if it is between 1 GB/GiB and 1 TB/TiB
|
||
# nt # the numbers of a file’s size if it is 1 TB/TiB or higher
|
||
# sb # the units of a file’s size (sets ub, uk, um, ug and ut)
|
||
# ub # the units of a file’s size if it is lower than 1 KB/Kib
|
||
# uk # the units of a file’s size if it is between 1 KB/KiB and 1 MB/MiB
|
||
# um # the units of a file’s size if it is between 1 MB/MiB and 1 GB/GiB
|
||
# ug # the units of a file’s size if it is between 1 GB/GiB and 1 TB/TiB
|
||
# ut # the units of a file’s size if it is 1 TB/TiB or higher
|
||
# df # a device’s major ID
|
||
# ds # a device’s minor ID
|
||
uu=$br_black # a user that’s you
|
||
uR=$red # a user that’s root
|
||
un=$yellow # a user that’s someone else
|
||
gu=$br_black # a group that you belong to
|
||
gR=$red # a group related to root
|
||
gn=$yellow # a group you aren’t a member of
|
||
lc=$red # a number of hard links
|
||
# lm # a number of hard links for a regular file with at least two
|
||
# ga # a new flag in Git
|
||
# gm # a modified flag in Git
|
||
# gd # a deleted flag in Git
|
||
# gv # a renamed flag in Git
|
||
# gt # a modified metadata flag in Git
|
||
# gi # an ignored flag in Git
|
||
# gc # a conflicted flag in Git
|
||
# Gm # main branch of repo
|
||
# Go # other branch of repo
|
||
# Gc # clean branch of repo
|
||
# Gd # dirty branch of repo
|
||
# xx # “punctuation”, including many background UI elements
|
||
# da # a file’s date
|
||
# in # a file’s inode number
|
||
# bl # a file’s number of blocks
|
||
# hd # the header row of a table
|
||
# lp # the path of a symlink
|
||
# cc # an escaped character in a filename
|
||
# bO # the overlay style for broken symlink paths
|
||
# sp # special (not file, dir, mount, exec, pipe, socket, block device, char device, or link)
|
||
# mp # a mount point
|
||
# im # a regular file that is an image
|
||
# vi # a regular file that is a video
|
||
# mu # a regular file that is lossy music
|
||
# lo # a regular file that is lossless music
|
||
# cr # a regular file that is related to cryptography (ex: key or certificate)
|
||
# do # a regular file that is a document (ex: office suite document or PDF)
|
||
# co # a regular file that is compressed
|
||
# tm # a regular file that is temporary (ex: a text editor’s backup file)
|
||
# cm # a regular file that is a compilation artifact (ex: Java class file)
|
||
bu=$yellow # a regular file that is used to build a project (ex: Makefile)
|
||
sc=$yellow # a regular file that is source code
|
||
# Sn # No security context on a file
|
||
# Su # SELinux user
|
||
# Sr # SELinux role
|
||
# St # SELinux type
|
||
# Sl # SELinux level
|
||
# ff # BSD file flags
|
||
)
|
||
|
||
export EZA_COLORS="${(pj.:.)colors}"
|
||
}
|
||
|
||
setup_fzf() {
|
||
type -p fzf >/dev/null || return
|
||
|
||
local colors=(
|
||
fg:bright-black
|
||
fg+:bright-white:bold
|
||
bg+:-1
|
||
hl:yellow:regular
|
||
hl+:bright-yellow:bold
|
||
query:bright-white:regular
|
||
info:blue:regular
|
||
border:bright-black
|
||
scrollbar:white
|
||
separator:bright-black
|
||
label:yellow:bold
|
||
prompt:blue
|
||
pointer:red:bold
|
||
marker:green
|
||
spinner:yellow
|
||
)
|
||
|
||
local bindings=(
|
||
ctrl-f:page-down
|
||
ctrl-b:page-up
|
||
ctrl-o:toggle-up
|
||
ctrl-t:toggle-all
|
||
ctrl-x:deselect-all
|
||
)
|
||
|
||
local defaults=(
|
||
--reverse
|
||
--border=rounded
|
||
--scrollbar=┃
|
||
--prompt='"❯ "'
|
||
--pointer='" "'
|
||
--marker='" "'
|
||
--color="${(pj/,/)colors}"
|
||
--bind="${(pj/,/)bindings}"
|
||
)
|
||
|
||
export FZF_DEFAULT_OPTS="${(pj/ /)defaults}"
|
||
}
|
||
|
||
# Set up autoload for custom functions.
|
||
setup_functions() {
|
||
fpath=("$ZDOTDIR/functions" $fpath)
|
||
local filepath
|
||
for filepath in $ZDOTDIR/functions/*; do
|
||
autoload "${filepath##*/}"
|
||
done
|
||
}
|
||
|
||
# Load additional local configuration if present.
|
||
setup_local_config() {
|
||
local config="$HOME/.local/etc/zsh/zshrc"
|
||
[ -r "$config" ] && source "$config" || true
|
||
}
|
||
|
||
# Set up zsh for interactive use (options, prompt, aliases, etc.)
|
||
setup_zsh_interactive() {
|
||
setopt INTERACTIVE_COMMENTS # Allow comments in interactive use.
|
||
setup_terminal
|
||
setup_aliases
|
||
setup_completion
|
||
setup_history
|
||
setup_zle
|
||
setup_man_pages
|
||
setup_prompt
|
||
setup_functions
|
||
setup_eza
|
||
setup_fzf
|
||
setup_local_config
|
||
}
|
||
|
||
# zmodload zsh/zprof
|
||
setup_zsh_interactive
|
||
# zprof
|