aboutsummaryrefslogtreecommitdiff
path: root/.config/shell/zsh-abbr
diff options
context:
space:
mode:
authorkj_sh6042025-12-25 21:33:50 -0500
committerkj_sh6042025-12-25 21:33:50 -0500
commitec1c2263aa8b60b7645f33a22b3881727be335c0 (patch)
treebf74f4efa2e585cc670a66240524da610a475bba /.config/shell/zsh-abbr
parent698f33c146248930aa70cb7c0c836112e3215633 (diff)
feat: zsh-abbr
Diffstat (limited to '.config/shell/zsh-abbr')
-rw-r--r--.config/shell/zsh-abbr/zsh-abbr.plugin.zsh2
-rw-r--r--.config/shell/zsh-abbr/zsh-abbr.zsh2040
-rwxr-xr-x.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.plugin.zsh2
-rwxr-xr-x.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.zsh279
4 files changed, 2323 insertions, 0 deletions
diff --git a/.config/shell/zsh-abbr/zsh-abbr.plugin.zsh b/.config/shell/zsh-abbr/zsh-abbr.plugin.zsh
new file mode 100644
index 0000000..1c915ff
--- /dev/null
+++ b/.config/shell/zsh-abbr/zsh-abbr.plugin.zsh
@@ -0,0 +1,2 @@
+fpath+=${0:A:h}/completions
+source ${0:A:h}/zsh-abbr.zsh
diff --git a/.config/shell/zsh-abbr/zsh-abbr.zsh b/.config/shell/zsh-abbr/zsh-abbr.zsh
new file mode 100644
index 0000000..89e342b
--- /dev/null
+++ b/.config/shell/zsh-abbr/zsh-abbr.zsh
@@ -0,0 +1,2040 @@
+#!/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
diff --git a/.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.plugin.zsh b/.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.plugin.zsh
new file mode 100755
index 0000000..6e5ba79
--- /dev/null
+++ b/.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.plugin.zsh
@@ -0,0 +1,2 @@
+fpath+=${0:A:h}/completions
+source ${0:A:h}/zsh-job-queue.zsh
diff --git a/.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.zsh b/.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.zsh
new file mode 100755
index 0000000..5774e78
--- /dev/null
+++ b/.config/shell/zsh-abbr/zsh-job-queue/zsh-job-queue.zsh
@@ -0,0 +1,279 @@
+#!/usr/bin/env zsh
+
+# Cross-session job queues manager for zsh
+# https://zsh-job-queue.olets.dev
+# v3.0.0
+# Copyright (c) 2024 Henry Bley-Vroman
+#
+# Usage:
+#
+# ```
+# id=$(job-queue push <scope> [<job-description> [<support-ticket-url>]])
+# # waits for its turn in the <scope> queue
+# # do some work
+# job-queue pop $id
+# ```
+#
+# Optionally include a suffix argument when sourcing this file
+# source path/to/zsh-job-queue.zsh <suffix>
+# The suffix is appended to the names of the file's exported functions.
+# This can be used, for instance, to distinguish multiple copies
+# of zsh-job-queue.
+#
+# In .zshrc:
+# source path/to/zsh-job-queue/zsh-job-queue.zsh
+# In a plugin which bundles its own (e.g. Git submodule or subtree) copy:
+# source ./zsh-job-queue/zsh-job-queue.zsh __my-plugin
+#
+# Refer to zsh-abbr for an example of the latter
+
+function _job_queue:init"${1:-}"() { # this quotation mark to fix syntax highlighting "
+ zmodload zsh/datetime
+
+ # Log debugging messages?
+ typeset -gi JOB_QUEUE_DEBUG=${JOB_QUEUE_DEBUG:-0}
+
+ # How old does a job have to be to be considered timed out?
+ typeset -gi JOB_QUEUE_TIMEOUT_AGE_SECONDS=${JOB_QUEUE_TIMEOUT_AGE_SECONDS:-30}
+
+ # Temp dir
+ typeset -g JOB_QUEUE_TMPDIR=${${JOB_QUEUE_TMPDIR:-${${TMPDIR:-/tmp}%/}/zsh-job-queue}%/}/
+ typeset -g JOB_QUEUE_PRIVILEGED_TEMPDIR=${${JOB_QUEUE_PRIVILEGED_TEMPDIR:-${JOB_QUEUE_TMPDIR:-${${TMPDIR:-/tmp}%/}/zsh-job-queue-privileged-users}}%/}/
+
+ typeset -g _job_queue_tmpdir=$JOB_QUEUE_TMPDIR
+
+ # Temp dir for privileged users
+ if [[ ${(%):-%#} == '#' ]]; then
+ _job_queue_tmpdir=$JOB_QUEUE_PRIVILEGED_TEMPDIR
+ fi
+}
+
+function job-queue"${1:-}"() { # this quotation mark to fix syntax highlighting "
+ emulate -LR zsh
+
+ {
+ # _job_queue:clear
+ # gets unfunction'd
+ #
+ # @param {string} scope
+ function _job_queue:clear() {
+ emulate -LR zsh
+
+ _job_queue:debugger
+
+ local scope
+ scope=$1
+
+ rm -rf $_job_queue_tmpdir${scope}
+ }
+
+ # gets unfunction'd
+ function _job_queue:debugger() {
+ emulate -LR zsh
+
+ (( JOB_QUEUE_DEBUG )) && 'builtin' 'echo' - $funcstack[2]
+ }
+
+ # gets unfunction'd
+ function _job_queue:help() {
+ emulate -LR zsh
+
+ 'command' 'man' job-queue 2>/dev/null || 'command' 'man' ${0:A:h}/man/man1/job-queue.1
+ }
+
+ # _job_queue:pop
+ # gets unfunction'd
+ #
+ # @param {string} scope
+ # @param {string} job_id
+ function _job_queue:pop() {
+ emulate -LR zsh
+
+ _job_queue:debugger
+
+ local scope
+ local job_id
+
+ scope=$1
+ job_id=$2
+
+ 'command' 'rm' $_job_queue_tmpdir${scope}/$job_id &>/dev/null
+ }
+
+ # _job_queue:push
+ # gets unfunction'd
+ #
+ # @param {string} scope
+ # @param {string} job_id
+ # @param {string} job_description
+ # @param {string} support_ticket_url
+ function _job_queue:push() {
+ emulate -LR zsh
+
+ {
+ _job_queue:debugger
+
+ local front_of_queue_job_age
+ local front_of_queue_job_id
+ local front_of_queue_job_path
+ local job_description
+ local job_id
+ local scope
+ local support_ticket_url
+
+ _job_queue:generate-id # sets REPLY variable
+ job_id=$REPLY
+
+ scope=$1
+ job_description=$2
+ support_ticket_url=$3
+
+ # gets unfunction'd
+ function _job_queue:push:add_job() {
+ _job_queue:debugger
+
+ if ! [[ -d $_job_queue_tmpdir${scope} ]]; then
+ 'command' 'mkdir' -p $_job_queue_tmpdir${scope}
+ fi
+
+ 'builtin' 'echo' $job_description > $_job_queue_tmpdir${scope}/$job_id
+ 'builtin' 'echo' $support_ticket_url >> $_job_queue_tmpdir${scope}/$job_id
+ }
+
+ # gets unfunction'd
+ function _job_queue:push:get_front_of_queue_job_id() {
+ # cannot support debug message
+
+ 'command' 'ls' -t $_job_queue_tmpdir${scope} | 'command' 'tail' -1
+ }
+
+ # gets unfunction'd
+ function _job_queue:push:handle_timeout() {
+ _job_queue:debugger
+
+ local msg
+ local -a msg_data
+ local msg_description
+ local msg_url
+
+ front_of_queue_job_path=$_job_queue_tmpdir${scope}/$front_of_queue_job_id
+
+ msg_data=( ${(f)"$('command' 'cat' $front_of_queue_job_path)"} ) # this quotation mark to improve syntax highlighting "
+ msg_description=$msg_data[1]
+ msg_url=$msg_data[2]
+
+ 'builtin' 'echo' "job-queue: A job added at $(strftime '%T %b %d %Y' ${${front_of_queue_job_id%%-*}%%.*}) has timed out."
+
+ msg="The job was related to \`$scope\`"
+
+ if [[ -n $msg_description ]]; then
+ msg+="'s \`$msg_description\`"
+ fi
+
+ msg+="."
+
+ 'builtin' 'echo' $msg
+ 'builtin' 'echo' "This could be the result of manually terminating an activity in \`$scope\`."
+
+ if [[ -n $msg_url ]]; then
+ 'builtin' 'echo' "If you believe it reflects bug in \`$scope\`, please report it at $msg_url"
+ fi
+
+ 'builtin' 'echo'
+
+ 'command' 'rm' $front_of_queue_job_path &>/dev/null
+ }
+
+ # gets unfunction'd
+ function _job_queue:push:wait_turn() {
+ front_of_queue_job_id=$(_job_queue:push:get_front_of_queue_job_id)
+
+ while [[ $front_of_queue_job_id != $job_id ]]; do
+ front_of_queue_job_id=$(_job_queue:push:get_front_of_queue_job_id)
+
+ front_of_queue_job_age=$(( $EPOCHREALTIME - ${front_of_queue_job_id%%-*} ))
+
+ if (( $front_of_queue_job_age > $JOB_QUEUE_TIMEOUT_AGE_SECONDS )); then
+ _job_queue:push:handle_timeout
+ fi
+
+ 'command' 'sleep' 0.01
+ done
+ }
+
+ _job_queue:push:add_job
+ _job_queue:push:wait_turn
+ } always {
+ unfunction -m _job_queue:push:add_job
+ unfunction -m _job_queue:push:get_front_of_queue_job_id
+ unfunction -m _job_queue:push:handle_timeout
+ unfunction -m _job_queue:push:wait_turn
+ }
+ }
+
+ # gets unfunction'd
+ function _job_queue:generate-id() {
+ emulate -LR zsh
+
+ # cannot support debug message
+
+ local uuid
+
+ uuid=$('command' 'uuidgen' 2>/dev/null || 'command' 'cat' /dev/urandom | 'command' 'base64' | 'command' 'tr' -dc '0-9a-zA-Z' | 'command' 'head' -c36)
+
+ REPLY="$EPOCHREALTIME--$uuid"
+ }
+
+ # gets unfunction'd
+ function _job_queue:version() {
+ emulate -LR zsh
+
+ 'builtin' 'printf' "zsh-job-queue version %s\n" 3.0.0
+ }
+
+ for opt in "$@"; do
+ case $opt in
+ clear)
+ shift
+ _job_queue:clear $@
+ return
+ ;;
+ "--help"|\
+ help)
+ _job_queue:help
+ return
+ ;;
+ "--version"|\
+ "-v")
+ _job_queue:version
+ return
+ ;;
+ pop)
+ shift
+ _job_queue:pop $@
+ return
+ ;;
+ push)
+ shift
+ _job_queue:push $@
+ return
+ ;;
+ *)
+ 'builtin' 'echo' "job-queue: Invalid option $opt"
+ return 1
+ ;;
+ esac
+ done
+ } always {
+ unfunction -m _job_queue:clear
+ unfunction -m _job_queue:debugger
+ unfunction -m _job_queue:help
+ unfunction -m _job_queue:pop
+ unfunction -m _job_queue:push
+ unfunction -m _job_queue:generate-id
+ unfunction -m _job_queue:version
+ }
+}
+
+_job_queue:init${1:-}
+unfunction -m _job_queue:init${1:-}