Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Absolute pathnames similar to expand-cmd-path



On Thu, 27 Jan 2011 19:53:09 -0800
Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> The following seems to work for me, though sometimes it doesn't leave
> the cursor where I expect:
> 
>     autoload -uZ modify-current-argument
>     current-argument-absolute-path() {
>       modify-current-argument '$ARG:a'
>     }
>     zle -N current-argument-absolute-path

Ah, it's magic you want.

The following changes the logic so that if the cursor was on the last
character or after the end of the original argument it is on the last
character or after the end of the new argument, and even more magically
if the characters from the original cursor position to the end are the
same characters at the end of the new string then the cursor is
positioned relative to the end of the new string.

This tickles cursor positioning annyonances in undo.

It will have to wait until Sourceforge resolve the problems.

--- ../zsh-git/zsh/Functions/Zle/modify-current-argument	2010-03-25 21:01:19.000000000 +0000
+++ Functions/Zle/modify-current-argument	2011-01-28 22:09:28.000000000 +0000
@@ -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-
 # 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]}"
+local left="${(j..)reply[1,REPLY-1]}${repl}"
+local right="${(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 ))
+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

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author