#!/usr/bin/env zsh # abbreviation management for zsh, inspired by fish shell and enhanced # https://github.com/olets/zsh-abbr # v6.4.0 # Copyright (c) 2019-present Henry Bley-Vroman # CONFIGURATION # ------------- # Should `abbr-load` run before every `abbr` command? (default true) typeset -gi ABBR_AUTOLOAD=${ABBR_AUTOLOAD:-1} # Log debugging messages? typeset -gi ABBR_DEBUG=${ABBR_DEBUG:-0} # Whether to add default bindings (expand on SPACE, expand and accept on ENTER, # add CTRL for normal SPACE/ENTER; in incremental search mode expand on CTRL+SPACE) # (default true) typeset -gi ABBR_DEFAULT_BINDINGS=${ABBR_DEFAULT_BINDINGS:-1} # Behave as if `--dry-run` was passed? (default false) typeset -gi ABBR_DRY_RUN=${ABBR_DRY_RUN:-0} # See ABBR_SET_LINE_CURSOR typeset -g ABBR_LINE_CURSOR_MARKER=${ABBR_LINE_CURSOR_MARKER:-%} # See ABBR_SET_EXPANSION_CURSOR typeset -g ABBR_EXPANSION_CURSOR_MARKER=${ABBR_EXPANSION_CURSOR_MARKER:-$ABBR_LINE_CURSOR_MARKER} # Behave as if `--force` was passed? (default false) typeset -gi ABBR_FORCE=${ABBR_FORCE:-0} # Check whether you could have used an abbreviation? (default false) # See also ABBR_LOG_AVAILABLE_ABBREVIATION typeset -gi ABBR_GET_AVAILABLE_ABBREVIATION=${ABBR_GET_AVAILABLE_ABBREVIATION:-0} # Log anything found by ABBR_GET_AVAILABLE_ABBREVIATION? (default false) typeset -gi ABBR_LOG_AVAILABLE_ABBREVIATION=${ABBR_LOG_AVAILABLE_ABBREVIATION:-0} # If ABBR_LOG_AVAILABLE_ABBREVIATION is non-zero, should # it log come _after_ the command output? (default false) typeset -gi ABBR_LOG_AVAILABLE_ABBREVIATION_AFTER=${ABBR_LOG_AVAILABLE_ABBREVIATION_AFTER:-0} # Should abbr-expand-and-accept push the unexpanded line to the shell history? (default false) # If true, if abbr-expand-and-accept expands an abbreviation there will be two history entries: # the first is line with the abbreviation, the second is what was run (with the expansion). # With this caveat: if ABBR_EXPAND_PUSH_ABBREVIATION_TO_HISTORY is true, abbr-expand-and-accept # will only push the line with the abbreviation to history if it's different from what abbr-expand # pushed to history. That is, if you # % abbr a=b # % a[Enter] # the history will be # abbr a=b # a # b # not # abbr a=b # a # a # b typeset -gi ABBR_EXPAND_AND_ACCEPT_PUSH_ABBREVIATED_LINE_TO_HISTORY=${ABBR_EXPAND_AND_ACCEPT_PUSH_ABBREVIATED_LINE_TO_HISTORY:-0} # Should abbr-expand push the abbreviation to the shell history? (default false) typeset -gi ABBR_EXPAND_PUSH_ABBREVIATION_TO_HISTORY=${ABBR_EXPAND_PUSH_ABBREVIATION_TO_HISTORY:-0} # Regular abbreviations expand when in command position, even if not at start of line # Experimental. Currently teats all `;`, `&`, `|`, and all reduplications (e.g. `&&`, `||`) as command delimiters. # # 0 to disable (default) # 1 to enable, with warning on shell startup # 2 to enable without warning typeset -gi ABBR_EXPERIMENTAL_COMMAND_POSITION_REGULAR_ABBREVIATIONS=${ABBR_EXPERIMENTAL_COMMAND_POSITION_REGULAR_ABBREVIATIONS:-0} if (( ABBR_EXPERIMENTAL_COMMAND_POSITION_REGULAR_ABBREVIATIONS == 1 )); then 'builtin' 'print' "abbr: You have set ABBR_EXPERIMENTAL_COMMAND_POSITION_REGULAR_ABBREVIATIONS=1. This feature is *experimental* and may have unexpected or undesired results. If it graduates from experimental, the variable name will change.\nYou can suppress this message while still enabling the feature by setting\n\n ABBR_EXPERIMENTAL_COMMAND_POSITION_REGULAR_ABBREVIATIONS=2\n" fi # Limitation: doesn't support the user changing their hist_ignore_space setting interactively typeset -gi _abbr_hist_ignore_space _abbr_hist_ignore_space=$options[hist_ignore_space] # Behave as if `--quiet` was passed? (default false) typeset -gi ABBR_QUIET=${ABBR_QUIET:-0} # Behave as if `--quieter` was passed? (default false) typeset -gi ABBR_QUIETER=${ABBR_QUIETER:-0} # In expansions, replace the first instance of ABBR_LINE_CURSOR_MARKER with the cursor typeset -gi ABBR_SET_LINE_CURSOR=${ABBR_SET_LINE_CURSOR:-0} # In expansions, replace the first instance of ABBR_EXPANSION_CURSOR_MARKER with the cursor typeset -gi ABBR_SET_EXPANSION_CURSOR=${ABBR_SET_EXPANSION_CURSOR:-0} # Function for splitting strings into abbreviation candidates # Default: split into words with shell grammar. # NB in my testing on zsh 5.9 (x86_64-apple-darwin21.3.0), # [[ ${${(k)functions}[(Ie)ABBR_SPLIT_FN]} == 0 ]] # can be significantly more performant than # (( ${${(k)functions}[(Ie)ABBR_SPLIT_FN]} == 0 )) if [[ ${${(k)functions}[(Ie)ABBR_SPLIT_FN]} == 0 ]]; then function ABBR_SPLIT_FN() { REPLY=( ${(z)*} ) } fi # The directory temp files are stored in typeset -g _abbr_tmpdir=${${ABBR_TMPDIR:-${${TMPDIR:-/tmp}%/}/zsh-abbr}%/}/ if [[ ${(%):-%#} == '#' ]]; then _abbr_tmpdir=${${ABBR_TMPDIR:-${${TMPDIR:-/tmp}%/}/zsh-abbr-privileged-users}%/}/ fi # The file abbreviations are stored in typeset -g ABBR_USER_ABBREVIATIONS_FILE=$ABBR_USER_ABBREVIATIONS_FILE if [[ -z $ABBR_USER_ABBREVIATIONS_FILE ]]; then # Legacy support for the zsh-abbr < v5.0.0 default ABBR_USER_ABBREVIATIONS_FILE=${XDG_CONFIG_HOME:-$HOME/.config}/zsh/abbreviations if [[ ! -f $ABBR_USER_ABBREVIATIONS_FILE ]]; then ABBR_USER_ABBREVIATIONS_FILE=${XDG_CONFIG_HOME:-$HOME/.config}/zsh-abbr/user-abbreviations fi fi if [[ ${(t)ABBR_REGULAR_ABBREVIATION_SCALAR_PREFIXES} == ${${(t)ABBR_REGULAR_ABBREVIATION_SCALAR_PREFIXES}#array} ]]; then typeset -ga ABBR_REGULAR_ABBREVIATION_SCALAR_PREFIXES=( 'sudo ' ) fi if [[ ${(t)ABBR_REGULAR_ABBREVIATION_GLOB_PREFIXES} == ${${(t)ABBR_REGULAR_ABBREVIATION_GLOB_PREFIXES}#array} ]]; then typeset -ga ABBR_REGULAR_ABBREVIATION_GLOB_PREFIXES=( ' ' ) fi # FUNCTIONS # --------- abbr() { emulate -LR zsh _abbr_debugger { local action local -a args local asterisk local -i dry_run local error_color local -i force local -i has_error local job_id local logs_silent_when_quiet local logs_silent_when_quieter local opt local output local -i quiet local -i quieter local release_date local REPLY local scope local -i should_exit local success_color local type local version local warn_color asterisk=$* dry_run=$ABBR_DRY_RUN force=$ABBR_FORCE quiet=$ABBR_QUIET quiet=$(( ABBR_QUIETER || ABBR_QUIET )) quieter=$ABBR_QUIETER release_date="November 27 2025" version="zsh-abbr version 6.4.0" # Deprecation notices for values that could be meaningfully set after initialization # Example form: # (( ${+DEPRECATED_VAL} )) && _abbr_warn_deprecation DEPRECATED_VAL VAL # VAL=$DEPRECATED_VAL if (( ABBR_LOADING_USER_ABBREVIATIONS )); then quiet=1 quieter=1 elif ! _abbr_no_color; then error_color="$fg[red]" success_color="$fg[green]" # @DUPE (nearly) abbr, _abbr_log_available_abbreviation, _abbr_warn_deprecation warn_color="$fg[yellow]" fi _abbr:add() { _abbr_debugger local abbreviation local expansion if [[ $# > 1 ]]; then _abbr:util_error "abbr add: Expected one argument, got $#: $*" return fi abbreviation=${1%%=*} expansion=${1#*=} if ! (( ABBR_LOADING_USER_ABBREVIATIONS )); then abbreviation=${(q)abbreviation} expansion=${(q)expansion} fi if [[ -z $abbreviation || -z $expansion || $abbreviation == $1 ]]; then _abbr:util_error "abbr add: Requires abbreviation and expansion" return fi _abbr:util_add $abbreviation $expansion } _abbr:git() { _abbr_debugger local abbreviation local expansion local type_saved if [[ $# > 1 ]]; then _abbr:util_error "abbr add: Expected one argument, got $#: $*" return fi abbreviation=${1%%=*} expansion=${1#*=} type_saved=$type type='regular' _abbr:add ${abbreviation}="git $expansion" type='global' _abbr:add "git ${abbreviation}"="git $expansion" type=$type_saved } _abbr:clear_session() { _abbr_debugger if [[ $# > 0 ]]; then _abbr:util_error "abbr clear-session: Unexpected argument" return fi ABBR_REGULAR_SESSION_ABBREVIATIONS=( ) ABBR_GLOBAL_SESSION_ABBREVIATIONS=( ) } _abbr:erase() { _abbr_debugger local abbreviation local abbreviations_set local -a abbreviations_sets local message local verb_phrase local REPLY if [[ $# > 1 ]]; then _abbr:util_error "abbr erase: Expected one argument" return elif [[ $# < 1 ]]; then _abbr:util_error "abbr erase: Erase must be passed an abbreviation" return fi abbreviation=$1 if [[ $scope != 'user' ]]; then if [[ $type != 'regular' ]]; then if (( ${+ABBR_GLOBAL_SESSION_ABBREVIATIONS[${(qqq)${(Q)abbreviation}}]} )); then (( ABBR_DEBUG )) && 'builtin' 'echo' " Found a global session abbreviation" abbreviations_sets+=( ABBR_GLOBAL_SESSION_ABBREVIATIONS ) fi fi if [[ $type != 'global' ]]; then if (( ${+ABBR_REGULAR_SESSION_ABBREVIATIONS[${(qqq)${(Q)abbreviation}}]} )); then (( ABBR_DEBUG )) && 'builtin' 'echo' " Found a regular session abbreviation" abbreviations_sets+=( ABBR_REGULAR_SESSION_ABBREVIATIONS ) fi fi fi if [[ $scope != 'session' ]]; then if [[ $type != 'regular' ]]; then if ! (( ABBR_LOADING_USER_ABBREVIATIONS )); then source ${_abbr_tmpdir}global-user-abbreviations fi if (( ${+ABBR_GLOBAL_USER_ABBREVIATIONS[${(qqq)${(Q)abbreviation}}]} )); then (( ABBR_DEBUG )) && 'builtin' 'echo' " Found a global user abbreviation" abbreviations_sets+=( ABBR_GLOBAL_USER_ABBREVIATIONS ) fi fi if [[ $type != 'global' ]]; then if ! (( ABBR_LOADING_USER_ABBREVIATIONS )); then source ${_abbr_tmpdir}regular-user-abbreviations fi if (( ${+ABBR_REGULAR_USER_ABBREVIATIONS[${(qqq)${(Q)abbreviation}}]} )); then (( ABBR_DEBUG )) && 'builtin' 'echo' " Found a regular user abbreviation" abbreviations_sets+=( ABBR_REGULAR_USER_ABBREVIATIONS ) fi fi fi if ! (( ${#abbreviations_sets} )); then _abbr:util_error "abbr erase: No${type:+ $type}${scope:+ $scope} abbreviation \`${(Q)abbreviation}\` found" elif (( ${#abbreviations_sets} == 1 )); then verb_phrase="Would erase" if ! (( dry_run )); then verb_phrase="Erased" unset "${abbreviations_sets}[${(qqq)${(Q)abbreviation}}]" # quotation marks required if [[ $abbreviations_sets =~ USER ]]; then _abbr:util_sync_user fi fi _abbr:util_set_to_typed_scope $abbreviations_sets _abbr:util_log_unless_quiet "$success_color$verb_phrase$reset_color $REPLY \`${(Q)abbreviation}\`" else verb_phrase="Did not erase" (( dry_run )) && verb_phrase="Would not erase" message="$error_color$verb_phrase$reset_color abbreviation \`${(Q)abbreviation}\`. Please specify one of\\n" for abbreviations_set in $abbreviations_sets; do _abbr:util_set_to_typed_scope $abbreviations_set message+=" $REPLY\\n" done _abbr:util_error $message fi } _abbr:expand() { _abbr_debugger local expansion if ! (( $# )); then _abbr:util_error "abbr expand: requires an argument" return fi expansion=$(_abbr:expansion $*) if [[ -z $expansion ]]; then return 1 fi _abbr:util_print $expansion } _abbr:expansion() { _abbr_debugger local abbreviation local expansion if ! (( $# )); then _abbr:util_error "_abbr:expansion requires an argument" return fi abbreviation=$* expansion=$(_abbr_regular_expansion "$abbreviation") if [[ ! "$expansion" ]]; then expansion=$(_abbr_global_expansion "$abbreviation" 1) fi if [[ ! "$expansion" ]]; then _abbr_create_files source ${_abbr_tmpdir}global-user-abbreviations expansion=$(_abbr_global_expansion "$abbreviation" 0) fi 'builtin' 'echo' - $expansion } _abbr:export_aliases() { _abbr_debugger local type_saved type_saved=$type if [[ $# > 0 ]]; then _abbr:util_error "abbr export-aliases: Unexpected argument" return fi include_expansion=1 session_prefix="alias" user_prefix="alias" _abbr:util_list $include_expansion $session_prefix $user_prefix } _abbr:import_aliases() { _abbr_debugger local alias_to_import local abbreviation local expansion local saved_type typeset -a aliases_to_import saved_type=$type if [[ $# > 0 ]]; then _abbr:util_error "abbr import-aliases: Unexpected argument" return fi if [[ $saved_type != 'global' ]]; then aliases_to_import=( ${(f)"$('builtin' 'alias' -r)"} ) # this quotation mark to fix syntax highlighting " for alias_to_import in $aliases_to_import; do _abbr:util_import_alias $alias_to_import done fi if [[ $saved_type != 'regular' ]]; then type='global' aliases_to_import=( ${(f)"$('builtin' 'alias' -g)"} ) # this quotation mark to fix syntax highlighting " for alias_to_import in $aliases_to_import; do _abbr:util_import_alias $alias_to_import done fi type=$saved_type } _abbr:import_fish() { _abbr_debugger local abbreviation local abbreviations local expansion local input_file if [[ $# != 1 ]]; then _abbr:util_error "abbr import-fish: requires exactly one argument" return fi input_file=$1 abbreviations=( ${(f)"$(<$input_file)"} ) # this quotation mark to fix syntax highlighting " for abbreviation in $abbreviations; do def=${line#* -- } abbreviation=${def%% *} expansion=${def#* } _abbr:util_add $abbreviation $expansion done } _abbr:import_git_aliases() { _abbr_debugger local config_file local git_alias local prefix local -a git_aliases while (( $# )); do case $1 in "--file") if [[ -z $2 ]]; then _abbr:util_error "abbr import-git-aliases: --file requires a file path" return fi config_file=$2 shift 2 ;; "--prefix") if [[ -z $2 ]]; then _abbr:util_error "abbr import-git-aliases: --prefix requires a prefix string" return fi prefix=$2 shift 2 ;; *) _abbr:util_error "abbr import-git-aliases: Unexpected argument" return esac done if [[ -n $config_file ]]; then if [[ ! -f $config_file ]]; then _abbr:util_error "abbr import-git-aliases: Config file not found" return fi git_aliases=( ${(ps|\nalias.|)"$(git config --file $config_file --get-regexp '^alias\.')"} ) else git_aliases=( ${(ps|\nalias.|)"$(git config --get-regexp '^alias\.')"} ) fi for git_alias in $git_aliases; do key=${${git_alias%% *}#alias.} value=${git_alias#* } if [[ ${value[1]} == '!' ]]; then verb_phrase="Did not" ((dry_run)) && verb_phrase="Would not" _abbr:util_warn "$verb_phrase import the Git alias \`$key\` because its expansion is a function" else if ! (( ABBR_LOADING_USER_ABBREVIATIONS )); then key=${(q)key} value=${(q)value} fi _abbr:util_add "$prefix$key" "git $value" fi done } _abbr:list() { _abbr_debugger local -i include_expansion if [[ $# > 0 ]]; then _abbr:util_error "abbr list definitions: Unexpected argument" return fi include_expansion=1 _abbr:util_list $include_expansion } _abbr:list_abbreviations() { _abbr_debugger if [[ $# > 0 ]]; then _abbr:util_error "abbr list: Unexpected argument" return fi _abbr:util_list } _abbr:list_commands() { _abbr_debugger local -i include_expansion local session_prefix local user_prefix if [[ $# > 0 ]]; then _abbr:util_error "abbr list commands: Unexpected argument" return fi include_expansion=1 session_prefix="abbr -S" user_prefix=abbr _abbr:util_list $include_expansion $session_prefix $user_prefix } _abbr:print_version() { _abbr_debugger if [[ $# > 0 ]]; then _abbr:util_error "abbr version: Unexpected argument" return fi _abbr:util_print $version } _abbr:profile() { _abbr_debugger local zsh_version if [[ $# > 0 ]]; then _abbr:util_error "abbr version: Unexpected argument" return fi zsh_version=$(zsh --version) _abbr:util_print $version _abbr:util_print $zsh_version _abbr:util_print "OSTYPE $OSTYPE" } _abbr:rename() { _abbr_debugger local err local expansion local new local old if [[ $# != 2 ]]; then _abbr:util_error "abbr rename: Requires exactly two arguments" return fi current_abbreviation=$1 new_abbreviation=$2 job_group='_abbr:rename' expansion=$(_abbr:expansion $current_abbreviation) if [[ -n $expansion ]]; then _abbr:util_add $new_abbreviation $expansion if (( $? )); then _abbr:util_error "abbr rename: ${type:+$type }${scope:+$scope }abbreviation \`${(Q)current_abbreviation}\` left untouched" return 1 fi _abbr:erase $current_abbreviation else _abbr:util_error "abbr rename: No${type:+ $type}${scope:+ $scope} abbreviation \`${(Q)current_abbreviation}\` exists" fi } _abbr:util_add() { _abbr_debugger local abbreviation local abbreviations_set local cmd local expansion local existing_expansion local job_group local -a success local typed_scope local verb_phrase local REPLY abbreviation=$1 expansion=$2 success=0 verb_phrase="Added" (( dry_run )) && verb_phrase="Would add" if [[ ${abbreviation%=*} != $abbreviation ]]; then _abbr:util_error "abbr add: ABBREVIATION (\`${(Q)abbreviation}\`) may not contain an equals sign" # this quotation mark to fix syntax highlighting " return 1 fi if [[ $scope == 'session' ]]; then if [[ $type == 'global' ]]; then abbreviations_set=ABBR_GLOBAL_SESSION_ABBREVIATIONS else abbreviations_set=ABBR_REGULAR_SESSION_ABBREVIATIONS fi else if [[ $type == 'global' ]]; then abbreviations_set=ABBR_GLOBAL_USER_ABBREVIATIONS if ! (( ABBR_LOADING_USER_ABBREVIATIONS )); then source ${_abbr_tmpdir}global-user-abbreviations fi else abbreviations_set=ABBR_REGULAR_USER_ABBREVIATIONS if ! (( ABBR_LOADING_USER_ABBREVIATIONS )); then source ${_abbr_tmpdir}regular-user-abbreviations fi fi fi _abbr:util_set_to_typed_scope $abbreviations_set typed_scope=$REPLY existing_expansion=${${(P)abbreviations_set}[${(qqq)${(Q)abbreviation}}]} if [[ -n $existing_expansion ]]; then if (( ! force )); then verb_phrase="Did not add" (( dry_run )) && verb_phrase="Would not add" _abbr:util_error "$verb_phrase the $typed_scope \`${(Q)abbreviation}\`. It already has an expansion" # this quotation mark to fix syntax highlighting " return 2 fi verb_phrase="Redefined" (( dry_run )) && verb_phrase="Would redefine" fi _abbr:util_check_command $abbreviation || return 3 if ! (( dry_run )); then eval $abbreviations_set'[${(qqq)${(Q)abbreviation}}]=${(qqq)${(Q)expansion}}' fi if [[ $scope != 'session' ]]; then _abbr:util_sync_user fi _abbr:util_log_unless_quiet "$success_color$verb_phrase$reset_color the $typed_scope \`${(Q)abbreviation}\`" # this quotation mark to fix syntax highlighting " } _abbr:util_alias() { _abbr_debugger local abbreviation local abbreviations_set local expansion abbreviations_set=$1 for abbreviation in ${(iko)${(P)abbreviations_set}}; do expansion=${${(P)abbreviations_set}[$abbreviation]} alias_definition="alias " if [[ $type == 'global' ]]; then alias_definition+="-g " fi alias_definition+="$abbreviation='$expansion'" 'builtin' 'print' "$alias_definition" done } _abbr:util_bad_options() { _abbr_debugger _abbr:util_error "abbr: Illegal combination of options" } _abbr:util_error() { _abbr_debugger has_error=1 logs_silent_when_quiet+="${logs_silent_when_quiet:+\\n}$error_color$@$reset_color" should_exit=1 } _abbr:util_import_alias() { local abbreviation local expansion abbreviation=${1%%=*} expansion=${1#*=} _abbr:util_add $abbreviation "$('builtin' 'echo' $expansion)" } _abbr:util_check_command() { _abbr_debugger local abbreviation abbreviation=$1 (( ABBR_LOADING_USER_ABBREVIATIONS )) && return 0 (( force && quieter )) && return 0 # Warn if abbreviation would interfere with system command use, e.g. `cp="git cherry-pick"` # To add regardless, use --force if (( $+commands[$abbreviation] && ! $+aliases[$abbreviation] )); then if (( force )); then verb_phrase="will now expand" (( dry_run )) && verb_phrase="would now expand" _abbr:util_log_unless_quieter "\`${(Q)abbreviation}\` $verb_phrase as an abbreviation" # this quotation mark to fix syntax highlighting " else verb_phrase="Did not" (( dry_run )) && verb_phrase="Would not" _abbr:util_warn "$verb_phrase add the abbreviation \`${(Q)abbreviation}\` because a command with the same name exists" # this quotation mark to fix syntax highlighting " return 1 fi fi } _abbr:util_list() { _abbr_debugger local abbreviation local abbreviation_set local -a abbreviations_sets local expansion local -i include_expansion local session_prefix local user_prefix include_expansion=$1 session_prefix=$2 user_prefix=$3 # DUPE (nearly) completions/_abbr's __abbr_describe_abbreviations, zsh-abbr.zsh's _abbr:util_list if [[ $scope != 'session' ]]; then if [[ $type != 'regular' ]]; then abbreviations_sets+=( ABBR_GLOBAL_USER_ABBREVIATIONS ) fi if [[ $type != 'global' ]]; then abbreviations_sets+=( ABBR_REGULAR_USER_ABBREVIATIONS ) fi fi if [[ $scope != 'user' ]]; then if [[ $type != 'regular' ]]; then abbreviations_sets+=( ABBR_GLOBAL_SESSION_ABBREVIATIONS ) fi if [[ $type != 'global' ]]; then abbreviations_sets+=( ABBR_REGULAR_SESSION_ABBREVIATIONS ) fi fi for abbreviation_set in $abbreviations_sets; do for abbreviation in ${(iko)${(P)abbreviation_set}}; do (( include_expansion )) && expansion=${${(P)abbreviation_set}[$abbreviation]} _abbr:util_list_item $abbreviation $expansion ${user_prefix:+$user_prefix -g} done done # DUPE end } _abbr:util_list_item() { _abbr_debugger local abbreviation local expansion local prefix abbreviation=$1 expansion=$2 prefix=$3 result=$abbreviation if [[ $expansion ]]; then result+="=${(qqq)${(Q)expansion}}" fi if [[ $prefix ]]; then result="$prefix $result" fi _abbr:util_print $result } _abbr:util_log_unless_quiet() { _abbr_debugger logs_silent_when_quiet+="${logs_silent_when_quiet:+\\n}$1" } _abbr:util_log_unless_quieter() { _abbr_debugger logs_silent_when_quieter+="${logs_silent_when_quieter:+\\n}$1" } _abbr:util_print() { _abbr_debugger output+="${output:+\\n}$1" } _abbr:util_set_once() { _abbr_debugger local option local value option=$1 value=$2 if [[ "${(P)option}" ]]; then # quoted for syntax highlighting return 1 fi eval $option=$value } _abbr:util_sync_user() { _abbr_debugger (( ABBR_LOADING_USER_ABBREVIATIONS )) && return local abbreviation local expansion local user_updated user_updated=$(mktemp ${_abbr_tmpdir}regular-user-abbreviations_updated.XXXXXX) typeset -p ABBR_GLOBAL_USER_ABBREVIATIONS > ${_abbr_tmpdir}global-user-abbreviations for abbreviation in ${(iko)ABBR_GLOBAL_USER_ABBREVIATIONS}; do expansion=${ABBR_GLOBAL_USER_ABBREVIATIONS[$abbreviation]} 'builtin' 'echo' "abbr -g $abbreviation=$expansion" >> "$user_updated" done typeset -p ABBR_REGULAR_USER_ABBREVIATIONS > ${_abbr_tmpdir}regular-user-abbreviations for abbreviation in ${(iko)ABBR_REGULAR_USER_ABBREVIATIONS}; do expansion=${ABBR_REGULAR_USER_ABBREVIATIONS[$abbreviation]} 'builtin' 'echo' "abbr $abbreviation=$expansion" >> $user_updated done 'command' 'mv' $user_updated $ABBR_USER_ABBREVIATIONS_FILE } _abbr:util_set_to_typed_scope() { _abbr_debugger local abbreviations_set abbreviations_set=$1 REPLY=${${${${abbreviations_set:l}%s}#abbr_}//_/ } } _abbr:util_usage() { _abbr_debugger 'command' 'man' abbr 2>/dev/null || 'command' 'man' ${ABBR_SOURCE_PATH}/man/man1/abbr.1 } _abbr:util_warn() { _abbr_debugger logs_silent_when_quiet+="${logs_silent_when_quiet:+\\n}$warn_color$@$reset_color" } for opt in "$@"; do if (( should_exit )); then return fi case $opt in "add"|\ "a") _abbr:util_set_once action add || args+=( $opt ) shift ;; "git"|\ "g") _abbr:util_set_once action git || args+=( $opt ) shift ;; "clear-session"|\ "c") _abbr:util_set_once action clear_session || args+=( $opt ) shift ;; "--dry-run") dry_run=1 shift ;; "erase"|\ "e") _abbr:util_set_once action erase || args+=( $opt ) shift ;; "expand"|\ "x") _abbr:util_set_once action expand || args+=( $opt ) shift ;; "export-aliases") _abbr:util_set_once action export_aliases || args+=( $opt ) shift ;; "--force"|\ "-f") force=1 shift ;; "--global"|\ "-g") _abbr:util_set_once type global || args+=( $opt ) shift ;; "help"|\ "--help") _abbr:util_usage should_exit=1 shift ;; "import-aliases") _abbr:util_set_once action import_aliases || args+=( $opt ) shift ;; "import-fish") _abbr:util_set_once action import_fish || args+=( $opt ) shift ;; "import-git-aliases") _abbr:util_set_once action import_git_aliases || args+=( $opt ) shift ;; "list") _abbr:util_set_once action list || args+=( $opt ) shift ;; "list-abbreviations"|\ "l") _abbr:util_set_once action list_abbreviations || args+=( $opt ) shift ;; "list-commands"|\ "L"|\ "-L") # -L option is to match the builtin alias's `-L` _abbr:util_set_once action list_commands || args+=( $opt ) shift ;; "load") _abbr_load_user_abbreviations should_exit=1 shift ;; "profile") _abbr:util_set_once action profile || args+=( $opt ) shift ;; "--quiet"|\ "-q") quiet=1 shift ;; "--quieter"|\ "-qq") quiet=1 quieter=1 shift ;; "--regular"|\ "-r") _abbr:util_set_once type regular || args+=( $opt ) shift ;; "rename"|\ "R") _abbr:util_set_once action rename || args+=( $opt ) shift ;; "--session"|\ "-S") _abbr:util_set_once scope session || args+=( $opt ) shift ;; "--user"|\ "-U") _abbr:util_set_once scope user || args+=( $opt ) shift ;; "version"|\ "--version"|\ "-v") _abbr:util_set_once action print_version || args+=( $opt ) shift ;; "--") shift args+=( $@ ) break ;; *) args+=( $opt ) shift ;; esac done if ! (( should_exit )); then if [[ -z $action ]]; then if (( ${#args} )); then action=add else action=list fi fi if ! (( ABBR_LOADING_USER_ABBREVIATIONS )) && [[ $scope != 'session' ]]; then job-queue__zsh-abbr push zsh-abbr $action job_id=$REPLY if (( ABBR_AUTOLOAD )); then _abbr_load_user_abbreviations fi fi _abbr:${action} $args has_error=$? fi if ! (( ABBR_LOADING_USER_ABBREVIATIONS )); then job-queue__zsh-abbr pop zsh-abbr $job_id fi if ! (( quiet )); then if [[ -n $logs_silent_when_quiet ]]; then output=$logs_silent_when_quiet${output:+\\n$output} fi fi if ! (( quieter )); then if [[ -n $logs_silent_when_quieter ]]; then output=$logs_silent_when_quieter${output:+\\n$output} fi fi if (( has_error )); then [[ -n $output ]] && 'builtin' 'print' $output >&2 return 1 else if (( dry_run && ! ABBR_TESTING )); then output+="\\n${warn_color}Dry run. Changes not saved.$reset_color" fi [[ -n $output ]] && 'builtin' 'print' $output >&1 return 0 fi } } _abbr_no_color() { local -a shell_vars local -i found shell_vars=( ${(k)parameters} ) found=$(( ! $shell_vars[(Ie)NO_COLOR] )) return $found } _abbr_regular_expansion() { { emulate -LR zsh # cannot support debug message local -a REPLY local abbreviation local expansion _abbr_regular_expansion:get_expansion() { { # cannot support debug message _abbr_regular_expansion:get_expansion:get_prefixed_expansion() { # cannot support debug message local abbreviation local abbreviation_sans_prefix local prefix_match local prefix_pattern local -a prefixes local -i use_globbing abbreviation=$1 use_globbing=$2 # setopt extended_glob prefixes=( $ABBR_REGULAR_ABBREVIATION_SCALAR_PREFIXES ) (( use_globbing )) && prefixes=( $ABBR_REGULAR_ABBREVIATION_GLOB_PREFIXES ) while [[ ! $expansion ]] && (( #prefixes )); do prefix_pattern=$prefixes[1] shift prefixes abbreviation_sans_prefix="${abbreviation#$prefix_pattern}" if (( use_globbing )); then # Trim $prefix_pattern, _as a glob_ (`$~globparam` vs `$stringparam`)_, from $abbreviation abbreviation_sans_prefix=${abbreviation#$~prefix_pattern} fi prefix_match=${abbreviation%$abbreviation_sans_prefix} # $abbreviation_sans_prefix is now the full $abbreviation if $abbreviation doesn't start with a prefix, # or a $abbreviation with the prefix trimmed if $abbreviation does start with a prefix if (( session )); then expansion=$ABBR_REGULAR_SESSION_ABBREVIATIONS[${(qqq)abbreviation_sans_prefix}] else expansion=$ABBR_REGULAR_USER_ABBREVIATIONS[${(qqq)abbreviation_sans_prefix}] fi if [[ -n $prefix_match ]]; then if [[ ! $expansion ]]; then expansion=$(_abbr_regular_expansion:get_expansion:get_prefixed_expansion $abbreviation_sans_prefix 1) fi if [[ ! $expansion ]]; then expansion=$(_abbr_regular_expansion:get_expansion:get_prefixed_expansion $abbreviation_sans_prefix 0) fi fi if [[ ! $expansion ]]; then continue fi # Re-prepend anything trimmed off during the prefix check expansion="${(qqq)prefix_match}$expansion" # this quotation mark to fix syntax highlighting " done 'builtin' 'echo' - $expansion } # this quotation mark to fix syntax highlighting " local abbreviation local expansion local -i session abbreviation=$1 session=$2 if (( session )); then expansion=$ABBR_REGULAR_SESSION_ABBREVIATIONS[${(qqq)abbreviation}] # this bracket to fix syntax highlighting } else expansion=$ABBR_REGULAR_USER_ABBREVIATIONS[${(qqq)abbreviation}] # this bracket to fix syntax highlighting } fi if [[ ! $expansion ]]; then expansion=$(_abbr_regular_expansion:get_expansion:get_prefixed_expansion $abbreviation 1) fi if [[ ! $expansion ]]; then expansion=$(_abbr_regular_expansion:get_expansion:get_prefixed_expansion $abbreviation 0) fi 'builtin' 'echo' - $expansion } always { unfunction -m _abbr_regular_expansion:get_expansion:get_prefixed_expansion } } abbreviation=$1 # DUPE _abbr_global_expansion, _abbr_regular_expansion # do not expand empty string or all-whitespace string ABBR_SPLIT_FN $abbreviation [[ -n $REPLY ]] || return expansion=$(_abbr_regular_expansion:get_expansion $abbreviation 1) if [[ ! $expansion ]]; then _abbr_create_files source ${_abbr_tmpdir}regular-user-abbreviations expansion=$(_abbr_regular_expansion:get_expansion $abbreviation 0) fi 'builtin' 'echo' - ${(Q)expansion} } always { unfunction -m _abbr_regular_expansion:get_expansion } } _abbr_create_files() { emulate -LR zsh # cannot support debug message [[ -d $_abbr_tmpdir ]] || mkdir -p $_abbr_tmpdir [[ -f ${_abbr_tmpdir}regular-user-abbreviations ]] || touch ${_abbr_tmpdir}regular-user-abbreviations [[ -f ${_abbr_tmpdir}global-user-abbreviations ]] || touch ${_abbr_tmpdir}global-user-abbreviations } _abbr_debugger() { emulate -LR zsh # user abbreviations are loaded on every git subcommand, making noise (( ABBR_LOADING_USER_ABBREVIATIONS && ! ABBR_INITIALIZING )) && return (( ABBR_DEBUG )) && 'builtin' 'echo' - $funcstack[2] } _abbr_global_expansion() { emulate -LR zsh # cannot support debug message # `_abbr_global_expansion … 0` must always be preceded by creating and sourcing files # search this file for examples local -a REPLY local abbreviation local expansion local -i session abbreviation=$1 session=$2 # DUPE _abbr_global_expansion, _abbr_regular_expansion # do not expand empty string or all-whitespace string ABBR_SPLIT_FN $abbreviation [[ -n $REPLY ]] || return if (( session )); then expansion=${ABBR_GLOBAL_SESSION_ABBREVIATIONS[${(qqq)abbreviation}]} else expansion=${ABBR_GLOBAL_USER_ABBREVIATIONS[${(qqq)abbreviation}]} fi 'builtin' 'echo' - ${(Q)expansion} } _abbr_load_user_abbreviations() { emulate -LR zsh { _abbr_debugger function _abbr_load_user_abbreviations:setup() { _abbr_debugger ABBR_REGULAR_USER_ABBREVIATIONS=( ) ABBR_GLOBAL_USER_ABBREVIATIONS=( ) _abbr_create_files } function _abbr_load_user_abbreviations:load() { _abbr_debugger local cmd local -a cmds local -i shwordsplit_on local -a words typeset -gi ABBR_LOADING_USER_ABBREVIATIONS shwordsplit_on=0 if [[ $options[shwordsplit] = on ]]; then shwordsplit_on=1 fi # Load saved user abbreviations if [[ -f $ABBR_USER_ABBREVIATIONS_FILE ]]; then unsetopt shwordsplit cmds=( ${(f)"$(<$ABBR_USER_ABBREVIATIONS_FILE)"} ) for cmd in $cmds; do words=( ${(z)cmd} ) # this bracket for syntax highlighting } # Only execute abbr commands if (( ${#words} > 1 )) && [[ ${words[1]} == abbr ]]; then abbr ${words:1} fi done if (( shwordsplit_on )); then setopt shwordsplit fi unset shwordsplit_on else mkdir -p ${ABBR_USER_ABBREVIATIONS_FILE:A:h} touch $ABBR_USER_ABBREVIATIONS_FILE fi typeset -p ABBR_REGULAR_USER_ABBREVIATIONS > ${_abbr_tmpdir}regular-user-abbreviations typeset -p ABBR_GLOBAL_USER_ABBREVIATIONS > ${_abbr_tmpdir}global-user-abbreviations } ABBR_LOADING_USER_ABBREVIATIONS=1 _abbr_load_user_abbreviations:setup _abbr_load_user_abbreviations:load unset ABBR_LOADING_USER_ABBREVIATIONS return } always { unfunction -m _abbr_load_user_abbreviations:setup unfunction -m _abbr_load_user_abbreviations:load } } _abbr_get_available_abbreviation() { { _abbr_get_available_abbreviation:regular() { { # cannot support debug message _abbr_get_available_abbreviation:regular:prefixed() { # cannot support debug message local expansion local expansion_sans_prefix local prefix_match local prefix_pattern local -a prefixes local -i use_globbing expansion=$1 use_globbing=$2 prefixes=( $ABBR_REGULAR_ABBREVIATION_SCALAR_PREFIXES ) (( use_globbing )) && prefixes=( $ABBR_REGULAR_ABBREVIATION_GLOB_PREFIXES ) while [[ ! $ABBR_UNUSED_ABBREVIATION ]] && (( #prefixes )); do prefix_pattern=$prefixes[1] shift prefixes expansion_sans_prefix="${expansion#$prefix_pattern}" if (( use_globbing )); then # Trim $prefix_pattern, _as a glob_ (`$~globparam` vs `$stringparam`)_, from $expansion expansion_sans_prefix=${expansion#$~prefix_pattern} fi prefix_match=${expansion%$expansion_sans_prefix} # $expansion_sans_prefix is now the full $expansion if $expansion doesn't start with a prefix, # or a $expansion with the prefix trimmed if $expansion does start with a prefix if (( session )); then ABBR_UNUSED_ABBREVIATION=${(Q)${(k)ABBR_REGULAR_SESSION_ABBREVIATIONS[(re)${(qqq)expansion_sans_prefix}]}} else ABBR_UNUSED_ABBREVIATION=${(Q)${(k)ABBR_REGULAR_USER_ABBREVIATIONS[(re)${(qqq)expansion_sans_prefix}]}} fi if [[ -n $prefix_match ]]; then ABBR_UNUSED_ABBREVIATION_PREFIX+=$prefix_match if [[ ! $ABBR_UNUSED_ABBREVIATION ]]; then _abbr_get_available_abbreviation:regular:prefixed $expansion_sans_prefix 1 fi if [[ ! $ABBR_UNUSED_ABBREVIATION ]]; then _abbr_get_available_abbreviation:regular:prefixed $expansion_sans_prefix 0 fi fi done } local expansion local -i session expansion=$1 session=$2 if (( session )); then ABBR_UNUSED_ABBREVIATION=${(Q)${(k)ABBR_REGULAR_SESSION_ABBREVIATIONS[(re)${(qqq)expansion}]}} else ABBR_UNUSED_ABBREVIATION=${(Q)${(k)ABBR_REGULAR_USER_ABBREVIATIONS[(re)${(qqq)expansion}]}} fi if [[ -z $ABBR_UNUSED_ABBREVIATION ]]; then ABBR_UNUSED_ABBREVIATION_PREFIX= _abbr_get_available_abbreviation:regular:prefixed $expansion 1 fi if [[ -z $ABBR_UNUSED_ABBREVIATION ]]; then ABBR_UNUSED_ABBREVIATION_PREFIX= _abbr_get_available_abbreviation:regular:prefixed $expansion 0 fi if [[ -n $ABBR_UNUSED_ABBREVIATION ]]; then return fi ABBR_UNUSED_ABBREVIATION_PREFIX= } always { unfunction -m _abbr_get_available_abbreviation:regular:prefixed } } local expansion local -i i local -a REPLY local -a words expansion=$LBUFFER # Look for regular session abbreviation _abbr_get_available_abbreviation:regular $expansion 1 if [[ -n $ABBR_UNUSED_ABBREVIATION ]]; then ABBR_UNUSED_ABBREVIATION_EXPANSION=$expansion ABBR_UNUSED_ABBREVIATION_SCOPE=session ABBR_UNUSED_ABBREVIATION_TYPE=regular return fi # Look for regular user abbreviation _abbr_get_available_abbreviation:regular $expansion 0 if [[ -n $ABBR_UNUSED_ABBREVIATION ]]; then ABBR_UNUSED_ABBREVIATION_EXPANSION=$expansion ABBR_UNUSED_ABBREVIATION_SCOPE=user ABBR_UNUSED_ABBREVIATION_TYPE=regular return fi ABBR_SPLIT_FN $LBUFFER words=( $REPLY ) # Look for global session abbreviation while [[ -z $ABBR_UNUSED_ABBREVIATION ]] && (( i < ${#words} )); do expansion=${words:$i} ABBR_UNUSED_ABBREVIATION=${(Q)${(k)ABBR_GLOBAL_SESSION_ABBREVIATIONS[(re)${(qqq)expansion}]}} (( i++ )) done if [[ -n $ABBR_UNUSED_ABBREVIATION ]]; then ABBR_UNUSED_ABBREVIATION_EXPANSION=$expansion ABBR_UNUSED_ABBREVIATION_SCOPE=session ABBR_UNUSED_ABBREVIATION_TYPE=global return fi # Look for global user abbreviation i=0 while [[ -z $ABBR_UNUSED_ABBREVIATION ]] && (( i < ${#words} )); do expansion=${words:$i} ABBR_UNUSED_ABBREVIATION=${(Q)${(k)ABBR_GLOBAL_USER_ABBREVIATIONS[(re)${(qqq)expansion}]}} (( i++ )) done if [[ -n $ABBR_UNUSED_ABBREVIATION ]]; then ABBR_UNUSED_ABBREVIATION_EXPANSION=$expansion ABBR_UNUSED_ABBREVIATION_SCOPE=user ABBR_UNUSED_ABBREVIATION_TYPE=global fi } always { unfunction -m _abbr_get_available_abbreviation:regular } } _abbr_log_available_abbreviation() { [[ -z $ABBR_UNUSED_ABBREVIATION || -z $ABBR_UNUSED_ABBREVIATION_EXPANSION ]] && \ return local message # @DUPE (nearly) abbr, _abbr_log_available_abbreviation, _abbr_warn_deprecation local warn_color if ! _abbr_no_color; then warn_color="$fg[yellow]" fi message="abbr: \`$ABBR_UNUSED_ABBREVIATION\`${ABBR_UNUSED_ABBREVIATION_PREFIX:+, prefixed with \`$ABBR_UNUSED_ABBREVIATION_PREFIX\`,} is your $ABBR_UNUSED_ABBREVIATION_TYPE $ABBR_UNUSED_ABBREVIATION_SCOPE abbreviation for \`$ABBR_UNUSED_ABBREVIATION_EXPANSION\`" if ! _abbr_no_color; then message="$warn_color$message$reset_color" fi 'builtin' 'print' $message } # WIDGETS # ------- # returns 1 if the cursor wasn't placed and the entire buffer expanded, # 2 if the entire buffer expanded and the cursor was placed # 3 if only part of the buffer expanded and the cursor was placed # 0 otherwise abbr-expand() { emulate -LR zsh local -a REPLY local abbreviation local -a cmds local expansion local -i i local -i j local -i k local -i matched_full_buffer local -i ret local -a subcmds local -a words ABBR_UNUSED_ABBREVIATION= ABBR_UNUSED_ABBREVIATION_EXPANSION= ABBR_UNUSED_ABBREVIATION_PREFIX= ABBR_UNUSED_ABBREVIATION_SCOPE= ABBR_UNUSED_ABBREVIATION_TYPE= # Check for regular expansion # Supports <=v6.3.x "from the start of the line" sense of regular # (match against entire LBUFFER) and (roughly) "command-position" # sense (matching against righ-most command in LBUFFER). cmds=( $LBUFFER ) if (( ABBR_EXPERIMENTAL_COMMAND_POSITION_REGULAR_ABBREVIATIONS )); then # Treat all `;`, `&`, `|`, and all reduplications (e.g. `&&`, `||`) as command delimiters subcmds=( ${(s.;.)LBUFFER//[&|]/;} ) if (( ${#subcmds} > 1 )); then cmds+=( ${subcmds[-1]} ) fi fi while [[ -z $expansion ]] && (( k < ${#cmds} )); do abbreviation=${cmds[-1]} expansion=$(_abbr_regular_expansion "$abbreviation") (( k++ )) done if [[ -n $expansion ]]; then # BEGIN DUPE abbr-expand 2x with differences # if it expanded and this widget can push to history (( ABBR_EXPAND_PUSH_ABBREVIATION_TO_HISTORY )) && print -s $abbreviation LBUFFER=${LBUFFER%%$abbreviation} if (( ABBR_SET_EXPANSION_CURSOR )) && [[ $expansion != ${expansion/$ABBR_EXPANSION_CURSOR_MARKER} ]]; then LBUFFER=${expansion%%$ABBR_EXPANSION_CURSOR_MARKER*} RBUFFER=${expansion#*$ABBR_EXPANSION_CURSOR_MARKER}$RBUFFER ret=2 # DUPE difference else LBUFFER+=$expansion ret=1 # DUPE difference fi return $ret # END DUPE abbr-expand 2x with differences fi ABBR_SPLIT_FN $LBUFFER words=( $REPLY ) # Check for global session expansion # first check the full LBUFFER, then trim words off the front while [[ -z $expansion ]] && (( i < ${#words} )); do abbreviation=${words:$i} expansion=$(_abbr_global_expansion "$abbreviation" 1) (( i++ )) done if [[ -z $expansion ]]; then # Check for global user expansion i=0 _abbr_create_files source ${_abbr_tmpdir}global-user-abbreviations # first check the full LBUFFER, then trim words off the front while [[ -z $expansion ]] && (( i < ${#words} )); do abbreviation=${words:$i} expansion=$(_abbr_global_expansion "$abbreviation" 0) (( i++ )) done fi if [[ -z $expansion ]]; then # No expansion found. See if one was available (( ABBR_GET_AVAILABLE_ABBREVIATION )) && _abbr_get_available_abbreviation return $ret fi # BEGIN DUPE abbr-expand 2x with differences # if it expanded and this widget can push to history (( ABBR_EXPAND_PUSH_ABBREVIATION_TO_HISTORY )) && print -s $abbreviation LBUFFER=${LBUFFER%%$abbreviation} if (( ABBR_SET_EXPANSION_CURSOR )) && [[ $expansion != ${expansion/$ABBR_EXPANSION_CURSOR_MARKER} ]]; then LBUFFER+=${expansion%%$ABBR_EXPANSION_CURSOR_MARKER*} RBUFFER=${expansion#*$ABBR_EXPANSION_CURSOR_MARKER}$RBUFFER ret=3 # DUPE difference else LBUFFER+=$expansion fi return $ret # END DUPE abbr-expand 2x with differences } abbr-expand-and-accept() { emulate -LR zsh # do not support debug message local -i entire_buffer_expanded local -i hist_ignore local buffer local trailing_space trailing_space=${LBUFFER##*[^[:IFSSPACE:]]} if [[ $_abbr_hist_ignore_space == on ]] && [[ $BUFFER[1] == ' ' ]]; then hist_ignore=1 fi if [[ -z $trailing_space ]]; then buffer=$BUFFER abbr-expand # If changing this, abbr-expand may need to change (( $? == 1 || $? == 2 )) && entire_buffer_expanded=1 # if it expanded and this widget can push to history if (( ! hist_ignore )) && [[ $BUFFER != $buffer ]] && (( ABBR_EXPAND_AND_ACCEPT_PUSH_ABBREVIATED_LINE_TO_HISTORY )); then # if abbr-expand didn't already push the abbreviated line to history if (( ABBR_EXPAND_PUSH_ABBREVIATION_TO_HISTORY )); then (( ! entire_buffer_expanded )) && print -s $buffer else print -s $buffer fi fi fi _abbr_accept-line } abbr-expand-and-insert() { emulate -LR zsh local buffer local -i cursor_was_placed abbr-expand # If changing this, abbr-expand may need to change (( $? == 2 || $? == 3 )) && cursor_was_placed=1 (( cursor_was_placed )) && return if (( ABBR_SET_LINE_CURSOR )) && [[ $BUFFER != ${BUFFER/$ABBR_LINE_CURSOR_MARKER} ]]; then buffer=$BUFFER LBUFFER=${buffer%%$ABBR_LINE_CURSOR_MARKER*} RBUFFER=${buffer#*$ABBR_LINE_CURSOR_MARKER} return fi zle self-insert } # DEPRECATION # ----------- _abbr_warn_deprecation() { emulate -LR zsh _abbr_debugger local callstack local deprecated local message local replacement # @DUPE (nearly) abbr, _abbr_log_available_abbreviation, _abbr_warn_deprecation local warn_color if ! _abbr_no_color; then warn_color="$fg[yellow]" fi deprecated=$1 replacement=$2 callstack=$3 message="$deprecated is deprecated.${replacement:+ Please use $replacement instead.}" if [[ -n $callstack ]]; then message+="\\n${warn_color}Called by \`$callstack\`$reset_color" fi 'builtin' 'print' $message } # INITIALIZATION # -------------- _abbr_init() { emulate -LR zsh local job_id { local log_available_abbreviation_hook local REPLY log_available_abbreviation_hook=preexec (( ABBR_LOG_AVAILABLE_ABBREVIATION_AFTER )) && log_available_abbreviation_hook=precmd typeset -g ABBR_UNUSED_ABBREVIATION typeset -g ABBR_UNUSED_ABBREVIATION_EXPANSION typeset -g ABBR_UNUSED_ABBREVIATION_PREFIX typeset -g ABBR_UNUSED_ABBREVIATION_SCOPE typeset -g ABBR_UNUSED_ABBREVIATION_TYPE typeset -gA ABBR_GLOBAL_SESSION_ABBREVIATIONS typeset -gA ABBR_GLOBAL_USER_ABBREVIATIONS typeset -gi ABBR_INITIALIZING typeset -gA ABBR_REGULAR_SESSION_ABBREVIATIONS typeset -gA ABBR_REGULAR_USER_ABBREVIATIONS ABBR_INITIALIZING=1 ABBR_REGULAR_SESSION_ABBREVIATIONS=( ) ABBR_GLOBAL_SESSION_ABBREVIATIONS=( ) _abbr_init:dependencies() { emulate -LR zsh _abbr_debugger # if installed with Homebrew, will not have .gitmodules if [[ -f ${ABBR_SOURCE_PATH}/.gitmodules && ! -f ${ABBR_SOURCE_PATH}/zsh-job-queue/zsh-job-queue.zsh ]]; then 'builtin' 'print' abbr: Finishing installing dependencies 'command' 'git' submodule update --init --recursive &>/dev/null fi if ! [[ -f ${ABBR_SOURCE_PATH}/zsh-job-queue/zsh-job-queue.zsh ]]; then 'builtin' 'print' abbr: There was a problem finishing installing dependencies return 1 fi source ${ABBR_SOURCE_PATH}/zsh-job-queue/zsh-job-queue.zsh __zsh-abbr } _abbr_init:add_widgets() { emulate -LR zsh _abbr_debugger # _abbr_accept-line is called by abbr-expand-and-accept # h/t https://github.com/ohmyzsh/ohmyzsh/pull/9466/commits/11c1f96155055719e42c3bac7d10c6ef4168a04f if (( ! ${+functions[_abbr_accept-line]} )); then case "$widgets[accept-line]" in # If the accept-line widget was already redefined before zsh-abbr's initialization, # use the user-defined accept-line widget user:*) zle -N _abbr_accept-line_user_defined "${widgets[accept-line]#user:}" _abbr_accept-line() { zle _abbr_accept-line_user_defined -- "$@" } ;; # Otherwise use the standard widget builtin) _abbr_accept-line() { zle .accept-line } ;; esac fi zle -N abbr-expand zle -N accept-line abbr-expand-and-accept zle -N abbr-expand-and-insert } _abbr_init:bind_widgets() { emulate -LR zsh _abbr_debugger # spacebar expands abbreviations bindkey " " abbr-expand-and-insert # control-spacebar is a normal space bindkey "^ " magic-space # when running an incremental search, # spacebar behaves normally and control-space expands abbreviations bindkey -M isearch "^ " abbr-expand-and-insert bindkey -M isearch " " magic-space } _abbr_init:deprecations() { { emulate -LR zsh _abbr_debugger local -A deprecated_widgets deprecated_widgets=( ) # START Deprecation notices for values that could not be meaningfully set after initialization # Example form: # (( ${+DEPRECATED_VAL} )) && _abbr_warn_deprecation DEPRECATED_VAL VAL # VAL=$DEPRECATED_VAL # END Deprecation notices for values that could not be meaningfully set after initialization # START Deprecation notices for functions # Example form: # deprecated_fn() { # _abbr_warn_deprecation deprecated_fn fn # fn # } # END Deprecation notices for functions # Deprecation notices for zle widgets _abbr_init:deprecations:widgets() { # cannot support debug message local bindkey_declaration local bindkey_declarations local replacement local deprecated bindkey_declarations=$(bindkey) # deprecated_widgets is defined in _abbr_init:deprecations for deprecated replacement in ${(kv)deprecated_widgets}; do bindkey_declaration=$('builtin' 'echo' $bindkey_declarations | grep $deprecated) zle -N $deprecated if [[ -n $bindkey_declaration ]]; then _abbr_warn_deprecation $deprecated $replacement "bindkey $bindkey_declaration" fi done } (( ${#deprecated_widgets} )) && { _abbr_init:deprecations:widgets } } always { unfunction -m _abbr_init:deprecations:widgets } } if ! _abbr_no_color; then 'builtin' 'autoload' -U colors && colors fi _abbr_debugger _abbr_init:dependencies || return job-queue__zsh-abbr push zsh-abbr initialization job_id=$REPLY (( ABBR_LOG_AVAILABLE_ABBREVIATION && ABBR_GET_AVAILABLE_ABBREVIATION )) && { 'builtin' 'autoload' -Uz add-zsh-hook 'add-zsh-hook' $log_available_abbreviation_hook _abbr_log_available_abbreviation } _abbr_load_user_abbreviations _abbr_init:add_widgets _abbr_init:deprecations (( ABBR_DEFAULT_BINDINGS )) && _abbr_init:bind_widgets job-queue__zsh-abbr pop zsh-abbr $job_id unset ABBR_INITIALIZING } always { unfunction -m _abbr_init:add_widgets unfunction -m _abbr_init:bind_widgets unfunction -m _abbr_init:dependencies unfunction -m _abbr_init:deprecations } } # _abbr_init should remain the last function defined in this file typeset -g ABBR_SOURCE_PATH ABBR_SOURCE_PATH=${0:A:h} _abbr_init # can't unset # unset _abbr_tmpdir # can't unfunction # _abbr_accept-line # _abbr_create_files # _abbr_debugger # _abbr_get_available_abbreviation # _abbr_global_expansion # _abbr_load_user_abbreviations # _abbr_log_available_abbreviation # _abbr_no_color # _abbr_regular_expansion unfunction -m _abbr unfunction -m _abbr_init unfunction -m _abbr_warn_deprecation unfunction -m _abbr:add unfunction -m _abbr:clear_session unfunction -m _abbr:erase unfunction -m _abbr:expand unfunction -m _abbr:expansion unfunction -m _abbr:export_aliases unfunction -m _abbr:git unfunction -m _abbr:import_aliases unfunction -m _abbr:import_fish unfunction -m _abbr:import_git_aliases unfunction -m _abbr:list unfunction -m _abbr:list_abbreviations unfunction -m _abbr:list_commands unfunction -m _abbr:print_version unfunction -m _abbr:profile unfunction -m _abbr:rename unfunction -m _abbr:util_add unfunction -m _abbr:util_alias unfunction -m _abbr:util_bad_options unfunction -m _abbr:util_check_command unfunction -m _abbr:util_error unfunction -m _abbr:util_import_alias unfunction -m _abbr:util_list unfunction -m _abbr:util_list_item unfunction -m _abbr:util_log_unless_quiet unfunction -m _abbr:util_log_unless_quieter unfunction -m _abbr:util_print unfunction -m _abbr:util_set_once unfunction -m _abbr:util_set_to_typed_scope unfunction -m _abbr:util_sync_user unfunction -m _abbr:util_usage unfunction -m _abbr:util_warn