about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Doc/Zsh/contrib.yo25
-rw-r--r--Functions/Zle/modify-current-argument35
3 files changed, 51 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index e984c0288..1e1bab72d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 $
 *****************************************************
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 8dbc095fd..00f70a2bf 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -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()
 
diff --git a/Functions/Zle/modify-current-argument b/Functions/Zle/modify-current-argument
index 92851d600..941eb80af 100644
--- a/Functions/Zle/modify-current-argument
+++ b/Functions/Zle/modify-current-argument
@@ -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