Expand aliases when point is on word

The self-insertion character has to be empty for that to work

This is usually the case when pressing enter
This commit is contained in:
tsi 2025-12-25 18:24:57 +01:00
parent 94f8211b87
commit fb37d2b89e
No known key found for this signature in database

View file

@ -10,6 +10,8 @@
# WARNING 1: This plugin creates and overwrites various readline bindings.
# Therefore, it might interfere with other plugins/custom bindings.
# Some bindings may be changed (e.g. \e\C-a...) while others should not (e.g. \C-m)
# WARNING 2: This plugin needs and enables extended globbing.
shopt -s extglob
# Regexes for heuristically determining whether we're abbreviating the first word.
# Construction put into functions to prevent global namespace pollution
@ -82,18 +84,28 @@ _try_abbrev_internal () {
# Recursively perform abbrevation on the line defined by $1, taking $2 as the point and $3 as the mark.
# Set the vars defined by $4, $5 and $6 to the updated values (line, point and mark).
# $7 is the character/string to self-insert.
declare -r line=$1 point=$2 mark=$3 new_line=$4 new_point=$5 new_mark=$6 \
declare -r line=$1 mark=$3 new_line=$4 new_point=$5 new_mark=$6 \
level=${#FUNCNAME[@]}
declare point=$2
declare self_insertion=$7
# `level` is needed to keep track of the recursion, because we don't have a return value but rather
# set a variable defined in the calling context. This level is just appended to the identifier to make it unique
# across all the recursive calls.
declare -r line_until_point=${line::point}
# If the self-insertion character is null (i.e. when pressing enter/accepting a line),
# then we also want to expand aliases if the cursor/point is *on* the word instead of just *after* the word.
if [[ -z $self_insertion ]]; then
line_from_point=${line:point}
line_from_point_without_partial_word=${line_from_point##*([^<>&;()|[:space:]])} # extglob must be enabled!
# Move point forward to right after the word. Keep mark where it is.
point=${#line}-${#line_from_point_without_partial_word}
fi
declare -r point line_until_point=${line::point}
if
# Check if the character at point is a shell metacharacter or EOL
[[ $point -eq ${#line} || "${line:point:1}" = [\<\>\&\;\(\)\|[:space:]] ]] &&
# [[ $point -eq ${#line} || "${line:point:1}" = [\<\>\&\;\(\)\|[:space:]] ]] &&
# NOTE: Above line commented out, it's actually not that useful.
# Determine word to complete
# Uses the same word separators as bash (| & ; ( ) space tab newline) (aka "shell metacharacters")
@ -141,7 +153,7 @@ _try_abbrev_internal () {
declare tmp=" $replacement"
[[ $tmp =~ ^([[:space:]]*$is_first_word_prefix) ]] && tmp=${tmp#"${BASH_REMATCH[1]}"}
declare -r word_to_expand=${tmp%%[<>&;()|[:space:]]*}
if [[ ! ${_expanded_aliases[$word_to_expand]-} ]]; then
if [[ -z ${_expanded_aliases[$word_to_expand]-} ]]; then
declare -r point_for_replacement=$((${#BASH_REMATCH[1]}+${#word_to_expand}))
declare -g "ret_$level"
declare -n recursively_expanded_replacement="ret_$level"
@ -149,7 +161,7 @@ _try_abbrev_internal () {
replacement=${recursively_expanded_replacement# }
fi
# Eval if it has a trailing exclamation point and strip trailing \n and \r
[[ $eval_expansion = true ]] && replacement=$(eval "${replacement%!}")
"$eval_expansion" && replacement=$(eval "${replacement%!}")
# Calculate point and mark offset.
declare -ir offset=${#replacement}-${#word_at_point}+${#self_insertion}
@ -164,8 +176,8 @@ _try_abbrev_internal () {
eval "$new_line"'=${line_until_point}${self_insertion}${line:point}'
fi
# Advance mark if it's right of (or on) the point.
[[ $mark && $mark -ge "$point" ]] && eval "$new_mark"'=$((mark+offset))'
# Advance mark if it's set and right of (or on) the point.
[[ $mark && mark -ge point ]] && eval "$new_mark"'=$((mark+offset))'
# Advance point.
eval "$new_point"'=$((point+offset))'