fs_setup_terminal() { # Make ctrl-q and ctrl-s available to terminal applications. stty start undef stop undef } fs_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" fs_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::::: # 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 } fs_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 } fs_setup_zle() { bindkey -v # Use vi mode for line editing. export KEYTIMEOUT=1 # 10ms delay for 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 } # Open nvim, preserving the current command line. zle -N fs_zle_open_nvim fs_zle_open_nvim() { zle push-line BUFFER="nvim" 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 -M viins '^v' fs_zle_open_nvim 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 fs_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 } fs_setup_zle_fzf() { local fzf_config="$ZDOTDIR/fzf/key-bindings.zsh" [ -r "$fzf_config" ] || return fs_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-" } fs_fzf_find_files() { fs_fzf_find "-type d" "-type f" } fs_fzf_find_dirs() { fs_fzf_find "-type d" } source "$fzf_config" export FZF_CTRL_T_COMMAND=fs_fzf_find_files export FZF_ALT_C_COMMAND=fs_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. fs_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 } fs_setup_prompt() { source "$ZDOTDIR/prompt.zsh" } fs_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}" } fs_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. fs_setup_functions() { fpath=("$ZDOTDIR/functions" $fpath) local filepath for filepath in $ZDOTDIR/functions/*; do autoload "${filepath##*/}" done } # Load additional local configuration if present. fs_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.) fs_setup_zsh_interactive() { setopt INTERACTIVE_COMMENTS # Allow comments in interactive use. fs_setup_terminal fs_setup_aliases fs_setup_completion fs_setup_history fs_setup_zle fs_setup_man_pages fs_setup_prompt fs_setup_functions fs_setup_eza fs_setup_fzf fs_setup_local_config } # zmodload zsh/zprof fs_setup_zsh_interactive # zprof