1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-01-01 05:16:05 +01:00

users/17608: use function to modify currrent command line argument

This commit is contained in:
Peter Stephenson 2013-01-24 20:28:20 +00:00
parent 44757a653c
commit 6265394d6b
3 changed files with 51 additions and 17 deletions

View file

@ -1,3 +1,9 @@
2013-01-24 Peter Stephenson <p.w.stephenson@ntlworld.com>
* users/17608: Doc/Zsh/contrib.yo,
Functions/Zle/modify-current-argument: use function to modify
current command line argument.
2013-01-22 Peter Stephenson <p.stephenson@samsung.com>
* 30993: Src/subst.c, Test/D04parameter.ztst: parameter
@ -461,5 +467,5 @@
*****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL
* $Revision: 1.5788 $
* $Revision: 1.5789 $
*****************************************************

View file

@ -2477,15 +2477,22 @@ See the function tt(modify-current-argument), described below, for
an example of how to call this function.
)
tindex(modify-current-argument)
item(tt(modify-current-argument) var(expr-using-)tt($ARG))(
item(tt(modify-current-argument) [ var(expr-using-)tt($ARG) | var(func) ])(
This function provides a simple method of allowing user-defined widgets
to modify the command line argument under the cursor (or immediately to the
left of the cursor if the cursor is between arguments). The argument
should be an expression which when evaluated operates on the shell
left of the cursor if the cursor is between arguments).
The argument can be an expression which when evaluated operates on the shell
parameter tt(ARG), which will have been set to the command line argument
under the cursor. The expression should be suitably quoted to prevent
it being evaluated too early.
Alternatively, if the argument does not contain the string tt(ARG), it
is assumed to be a shell function, to which the current command line
argument is passed as the only argument. The function should set the
variable tt(REPLY) to the new value for the command line argument.
If the function returns non-zero status, so does the calling function.
For example, a user-defined widget containing the following code
converts the characters in the argument under the cursor into all upper
case:
@ -2497,6 +2504,18 @@ or one of the styles of quotes), and replaces it with single quoting
throughout:
example(modify-current-argument '${(qq)${(Q)ARG}}')
The following performs directory expansion on the command line
argument and replaces it by the absolute path:
example(expand-dir() {
REPLY=${~1}
REPLY=${REPLY:a}
}
modify-current-argument expand-dir)
In practice the function tt(expand-dir) would probably not be defined
within the widget where tt(modify-current-argument) is called.
)
enditem()

View file

@ -14,24 +14,27 @@
setopt localoptions noksharrays multibyte
local -a reply
integer REPLY REPLY2 fromend endoffset
integer posword poschar fromend endoffset
local REPLY REPLY2
autoload -Uz split-shell-arguments
split-shell-arguments
(( posword = REPLY, poschar = REPLY2 ))
# Can't do this unless there's some text under or left of us.
(( REPLY < 2 )) && return 1
(( posword < 2 )) && return 1
# Get the index of the word we want.
if (( REPLY & 1 )); then
if (( posword & 1 )); then
# Odd position; need previous word.
(( REPLY-- ))
(( posword-- ))
# Pretend position was just after the end of it.
(( REPLY2 = ${#reply[REPLY]} + 1 ))
(( poschar = ${#reply[posword]} + 1 ))
fi
# Work out offset from end of string
(( fromend = $REPLY2 - ${#reply[REPLY]} - 1 ))
(( fromend = $poschar - ${#reply[posword]} - 1 ))
if (( fromend >= -1 )); then
# Cursor is near the end of the word, we'll try to keep it there.
endoffset=1
@ -39,11 +42,17 @@ 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]}"
integer wordoff="${(cj..)#reply[1,posword-1]}"
# Replacement for current word. This could do anything to ${reply[REPLY]}.
local ARG="${reply[REPLY]}" repl
eval repl=\"$1\"
# Replacement for current word. This could do anything to ${reply[posword]}.
local ARG="${reply[posword]}" repl
if [[ $1 != *ARG* ]]; then
REPLY=
$1 $ARG || return 1
repl=$REPLY
else
eval repl=\"$1\"
fi
if (( !endoffset )) && [[ ${repl[fromend,-1]} = ${ARG[fromend,-1]} ]]; then
# If the part of the string from here to the end hasn't changed,
@ -54,8 +63,8 @@ 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.
local left="${(j..)reply[1,REPLY-1]}${repl}"
local right="${(j..)reply[REPLY+1,-1]}"
local left="${(j..)reply[1,posword-1]}${repl}"
local right="${(j..)reply[posword+1,-1]}"
if [[ endoffset -ne 0 && ${#repl} -ne 0 ]]; then
# Place cursor relative to end.
@ -71,5 +80,5 @@ else
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 ))
(( CURSOR = wordoff + (poschar > repmax ? repmax : poschar) - 1 ))
fi