diff options
Diffstat (limited to 'Functions/Zle')
-rw-r--r-- | Functions/Zle/.distfiles | 1 | ||||
-rw-r--r-- | Functions/Zle/modify-current-argument | 44 | ||||
-rw-r--r-- | Functions/Zle/send-invisible | 85 | ||||
-rw-r--r-- | Functions/Zle/split-shell-arguments | 2 |
4 files changed, 121 insertions, 11 deletions
diff --git a/Functions/Zle/.distfiles b/Functions/Zle/.distfiles index 2ec4adc22..22eef1e6e 100644 --- a/Functions/Zle/.distfiles +++ b/Functions/Zle/.distfiles @@ -33,6 +33,7 @@ read-from-minibuffer replace-string replace-string-again select-word-style +send-invisible smart-insert-last-word split-shell-arguments transpose-lines diff --git a/Functions/Zle/modify-current-argument b/Functions/Zle/modify-current-argument index 92ca7bdab..92851d600 100644 --- a/Functions/Zle/modify-current-argument +++ b/Functions/Zle/modify-current-argument @@ -14,7 +14,7 @@ setopt localoptions noksharrays multibyte local -a reply -integer REPLY REPLY2 +integer REPLY REPLY2 fromend endoffset autoload -Uz split-shell-arguments split-shell-arguments @@ -30,6 +30,13 @@ if (( REPLY & 1 )); then (( REPLY2 = ${#reply[REPLY]} + 1 )) fi +# Work out offset from end of string +(( fromend = $REPLY2 - ${#reply[REPLY]} - 1 )) +if (( fromend >= -1 )); then + # Cursor is near the end of the word, we'll try to keep it there. + endoffset=1 +fi + # Length of all characters before current. # Force use of character (not index) counting and join without IFS. integer wordoff="${(cj..)#reply[1,REPLY-1]}" @@ -37,15 +44,32 @@ integer wordoff="${(cj..)#reply[1,REPLY-1]}" # Replacement for current word. This could do anything to ${reply[REPLY]}. local ARG="${reply[REPLY]}" repl eval repl=\"$1\" + +if (( !endoffset )) && [[ ${repl[fromend,-1]} = ${ARG[fromend,-1]} ]]; then + # If the part of the string from here to the end hasn't changed, + # leave the cursor this distance from the end instead of the beginning. + endoffset=1 +fi + # New line: all words before and after current word, with # no additional spaces since we've already got the whitespace # and the replacement word in the middle. -BUFFER="${(j..)reply[1,REPLY-1]}${repl}${(j..)reply[REPLY+1,-1]}" - -# Keep cursor at same position in replaced word. -# Redundant here, but useful if $repl changes the length. -# Limit to the next position after the end of the word. -integer repmax=$(( ${#repl} + 1 )) -# Remember CURSOR starts from offset 0 for some reason, so -# subtract 1 from positions. -(( CURSOR = wordoff + (REPLY2 > repmax ? repmax : REPLY2) - 1 )) +local left="${(j..)reply[1,REPLY-1]}${repl}" +local right="${(j..)reply[REPLY+1,-1]}" + +if [[ endoffset -ne 0 && ${#repl} -ne 0 ]]; then + # Place cursor relative to end. + LBUFFER="$left" + RBUFFER="$right" + (( CURSOR += fromend )) +else + BUFFER="$left$right" + + # Keep cursor at same position in replaced word. + # Redundant here, but useful if $repl changes the length. + # Limit to the next position after the end of the word. + integer repmax=$(( ${#repl} + 1 )) + # Remember CURSOR starts from offset 0 for some reason, so + # subtract 1 from positions. + (( CURSOR = wordoff + (REPLY2 > repmax ? repmax : REPLY2) - 1 )) +fi diff --git a/Functions/Zle/send-invisible b/Functions/Zle/send-invisible new file mode 100644 index 000000000..d31fc76ae --- /dev/null +++ b/Functions/Zle/send-invisible @@ -0,0 +1,85 @@ +#autoload + +# send-invisible reads a line from the terminal, displaying an +# asterisk for each character typed. It stores the line in the +# global variable INVISIBLE, and when finished reading, inserts +# the string ${INVISIBLE} into the original command buffer. + +# If one argument is given, it is the prompt. The default is +# "Non-echoed text: " + +# If two or three arguments are given, they form the prefix and +# suffix of the inserted INVISIBLE. Defaults are '${' and '}' +# but these can be replaced, for example with '"${' and '}"' to +# enclose the whole word in double quotes, or '${(z)' and '}' to +# split the value of $INVISIBLE like the shell parser. + +# To use: +# autoload -Uz send-invisible +# zle -N send-invisible +# bindkey '^X ' send-invisible +# Or more elaborately: +# hidden-command() { send-invisible '% ' '${(z)' '}' } +# zle -N hidden-command +# bindkey '^X%' hidden-command + +# Shamelessly cribbed from read-from-minibuffer. + +emulate -L zsh + +# Hide the value of INVISIBLE in any output of set and typeset +typeset -g -H INVISIBLE= + +local pretext="$PREDISPLAY$LBUFFER$RBUFFER$POSTDISPLAY"$'\n' + +# Can't directly make these locals because send-invisible is +# called as a widget, so these special variables are already +# local at the current level and wouldn't get restored +local save_lbuffer=$LBUFFER +local save_rbuffer=$RBUFFER +local save_predisplay=$PREDISPLAY +local save_postdisplay=$POSTDISPLAY +local -a save_region_highlight +save_region_highlight=("${region_highlight[@]}") + +{ + local lb rb opn=${2:-'${'} cls=${3:-'}'} + LBUFFER= + RBUFFER= + PREDISPLAY="$pretext${1:-Non-echoed text: }" + POSTDISPLAY= + region_highlight=("P${(m)#pretext} ${(m)#PREDISPLAY} bold") + + while zle -R && zle .read-command + do + # There are probably more commands that should go into + # the first clause here to harmlessly beep, because ... + case $REPLY in + (send-invisible|run-help|undefined-key|where-is|which-command) + zle .beep;; + (push-*|send-break) INVISIBLE=;& + (accept-*) break;; + (*) + LBUFFER=$lb + RBUFFER=$rb + zle $REPLY # ... this could expose something + lb=$LBUFFER + rb=$RBUFFER + INVISIBLE=$BUFFER + LBUFFER=${(l:$#LBUFFER::*:):-} + RBUFFER=${(l:$#RBUFFER::*:):-} + ;; + esac + done +} always { + LBUFFER=$save_lbuffer + RBUFFER=$save_rbuffer + PREDISPLAY=$save_predisplay + POSTDISPLAY=$save_postdisplay + region_highlight=("${save_region_highlight[@]}") + zle -R + + # Now that the highlight has been restored with all the old + # text and cursor positioning, insert the new text. + LBUFFER+=${INVISIBLE:+${opn}INVISIBLE${cls}} +} diff --git a/Functions/Zle/split-shell-arguments b/Functions/Zle/split-shell-arguments index ee737a067..32b04fcb5 100644 --- a/Functions/Zle/split-shell-arguments +++ b/Functions/Zle/split-shell-arguments @@ -15,7 +15,7 @@ local -a bufwords lbufwords local word integer pos=1 cpos=$((CURSOR+1)) opos iword ichar -bufwords=(${(z)BUFFER}) +bufwords=(${(Z+n+)BUFFER}) reply=() while [[ ${BUFFER[pos]} = [[:space:]] ]]; do |