zsh-workers
 help / color / mirror / code / Atom feed
* This widget implementation feels a bit clunky (edit-quoted-word)
@ 2015-06-20  9:16 Mikael Magnusson
  2015-06-20 17:06 ` Peter Stephenson
  2015-06-20 17:21 ` This widget implementation feels a bit clunky (edit-quoted-word) Bart Schaefer
  0 siblings, 2 replies; 19+ messages in thread
From: Mikael Magnusson @ 2015-06-20  9:16 UTC (permalink / raw)
  To: zsh workers

autoload -U narrow-to-region
function _narrow_to_region_marked()
{ #I had this function since before
  local right
  local left
  local OLDMARK=MARK
  local wasregion=1
  if ((REGION_ACTIVE == 0)); then
    MARK=CURSOR
    wasregion=0
  fi
  REGION_ACTIVE=0
  if ((MARK < CURSOR)); then
    left="$LBUFFER[0,$((MARK-CURSOR-1))]"
    right="$RBUFFER"
  else
    left="$LBUFFER"
    right="$BUFFER[$((MARK+1)),-1]"
  fi
  narrow-to-region -p "$left>>|" -P "|<<$right"
  _line_redraw #update highlight stuff doesn't happen here otherwise
  MARK=OLDMARK
  if ((wasregion)); then
    REGION_ACTIVE=1
  fi
}

function _edit_quoted_word()
{
  local -a reply
  local REPLY REPLY2 len
  _split_shell_arguments_intuitive
  local STARTPOS ENDPOS
  local OLDCURSOR=$CURSOR OLDMARK=$MARK wasregion=$REGION_ACTIVE
  STARTPOS=${#${(j::)reply[1,REPLY-1]}}
  reply[REPLY]=${(Q)reply[REPLY]}
  ENDPOS=${#${(j::)reply[1,REPLY]}}
  CURSOR=$STARTPOS
  MARK=$ENDPOS
  REGION_ACTIVE=1
  BUFFER=${(j::)reply}
  len=$#BUFFER
  _narrow_to_region_marked
  CURSOR=$STARTPOS
  MARK=$((ENDPOS+$#BUFFER-len))
  zle quote-region
  #the following line is also my quote-unquote-word widget
  modify-current-argument '${(q-)${(Q)ARG}}'
  CURSOR=$OLDCURSOR
  MARK=$OLDMARK
  REGION_ACTIVE=$wasregion
}
zle -N edit-quoted-word _edit_quoted_word
bindkey '^_q' edit-quoted-word

autoload -U modify-current-argument
autoload -U split-shell-arguments

function _split_shell_arguments_intuitive()
{ #Had this since before too
  split-shell-arguments
  #have to duplicate some of modify-current-argument to get the word
  #_under_ the cursor, not after.
  setopt localoptions noksharrays multibyte
  if (( REPLY > 1 )); then
    if (( REPLY & 1 )); then
      (( REPLY-- ))
    fi
  fi
}

I'm not exactly sure how often I would use this, but I had the thought
and set off on an adventure. This lets you be on a thing like
% echo I\''d (like) to "have\" some better example?'
turns into
% echo >>|I'd (like) to "have\" some better example?|<<
which is then somewhat easier to edit, then you maybe type this instead
% echo >>|I'd (like) to "have\" '${(q-)${(Q)ARG}}' some better example?|<<
after pressing enter, it turns back into
% echo I\''d (like) to "have\" ''${(q-)${(Q)ARG}}'' some better example?'

I feel like it's unnecessarily hard to get the resulting text from a
narrow-to-region session.
It would be nice if quote-region let you specify the type of quoting.
Urk?

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: This widget implementation feels a bit clunky (edit-quoted-word)
  2015-06-20  9:16 This widget implementation feels a bit clunky (edit-quoted-word) Mikael Magnusson
@ 2015-06-20 17:06 ` Peter Stephenson
  2015-06-21  7:09   ` Mikael Magnusson
  2015-06-20 17:21 ` This widget implementation feels a bit clunky (edit-quoted-word) Bart Schaefer
  1 sibling, 1 reply; 19+ messages in thread
From: Peter Stephenson @ 2015-06-20 17:06 UTC (permalink / raw)
  To: zsh workers

On Sat, 20 Jun 2015 11:16:20 +0200
Mikael Magnusson <mikachu@gmail.com> wrote:
> I feel like it's unnecessarily hard to get the resulting text from a
> narrow-to-region session.

Would you want something like this?

diff --git a/Functions/Zle/narrow-to-region b/Functions/Zle/narrow-to-region
index 86fd7ac..d449540 100644
--- a/Functions/Zle/narrow-to-region
+++ b/Functions/Zle/narrow-to-region
@@ -11,6 +11,8 @@
 # Either or both may be empty.
 #   -n           Only replace the text before or after the region with
 #                the -p or -P options if the text was not empty.
+#   -l lbufvar   ) $lbufvar and $rbufvar will contain the value of $LBUFFER and
+#   -r rbufvar   ) $RBUFFER resulting from any recursive edit (i.e. not with -S or -R)
 #   -S statevar
 #   -R statevar
 # Save or restore the state in/from the parameter named statevar.  In
@@ -28,16 +30,20 @@ integer _ntr_start _ntr_end _ntr_swap _ntr_cursor=$CURSOR _ntr_mark=$MARK
 integer _ntr_stat
 
 local _ntr_opt _ntr_pretext _ntr_posttext _ntr_usepretext _ntr_useposttext
-local _ntr_nonempty _ntr_save _ntr_restore
+local _ntr_nonempty _ntr_save _ntr_restore _ntr_lbuffer _ntr_rbuffer
 
-while getopts "np:P:R:S:" _ntr_opt; do
+while getopts "l:np:P:r:R:S:" _ntr_opt; do
   case $_ntr_opt in
+    (l) _ntr_lbuffer=$OPTARG
+	;;
     (n) _ntr_nonempty=1
 	;;
     (p) _ntr_pretext=$OPTARG _ntr_usepretext=1
 	;;
     (P) _ntr_posttext=$OPTARG _ntr_useposttext=1
 	;;
+    (r) _ntr_rbuffer=$OPTARG
+	;;
     (R) _ntr_restore=$OPTARG
         ;;
     (S)	_ntr_save=$OPTARG
@@ -101,6 +107,9 @@ fi
 if [[ -z $_ntr_save && -z $_ntr_restore ]]; then
   zle recursive-edit
   _ntr_stat=$?
+
+  [[ -n $_ntr_lbuffer ]] && eval "${_ntr_lbuffer}=\${LBUFFER}"
+  [[ -n $_ntr_rbuffer ]] && eval "${_ntr_rbuffer}=\${RBUFFER}"
 fi
 
 if [[ -n $_ntr_restore || -z $_ntr_save ]]; then


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: This widget implementation feels a bit clunky (edit-quoted-word)
  2015-06-20  9:16 This widget implementation feels a bit clunky (edit-quoted-word) Mikael Magnusson
  2015-06-20 17:06 ` Peter Stephenson
@ 2015-06-20 17:21 ` Bart Schaefer
  2015-07-18 23:42   ` PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky) Bart Schaefer
  1 sibling, 1 reply; 19+ messages in thread
From: Bart Schaefer @ 2015-06-20 17:21 UTC (permalink / raw)
  To: zsh workers

On Jun 20, 11:16am, Mikael Magnusson wrote:
}
} I feel like it's unnecessarily hard to get the resulting text from a
} narrow-to-region session.

Hmm.  If you used "narrow-to-region -S state ..." then I think the
resulting text would be $BUFFER between the exit from recursive-edit
and the call to "narrow-to-region -R state" ?

Except that I'm having a little trouble with -S / -R.  The value of
$MARK never seems to be correctly restored.  Is it supposed to be?

} It would be nice if quote-region let you specify the type of quoting.
} Urk?

The difficulty there is that it's a widget so there's no direct way to
pass the type of quote.  I suppose you could use $NUMERIC.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: This widget implementation feels a bit clunky (edit-quoted-word)
  2015-06-20 17:06 ` Peter Stephenson
@ 2015-06-21  7:09   ` Mikael Magnusson
  2015-06-21 17:17     ` Peter Stephenson
  2015-06-22  0:18     ` PATCH: Document narrow-to-region -l and -r Mikael Magnusson
  0 siblings, 2 replies; 19+ messages in thread
From: Mikael Magnusson @ 2015-06-21  7:09 UTC (permalink / raw)
  To: Peter Stephenson, Bart Schaefer; +Cc: zsh workers

On Sat, Jun 20, 2015 at 7:06 PM, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
> On Sat, 20 Jun 2015 11:16:20 +0200
> Mikael Magnusson <mikachu@gmail.com> wrote:
>> I feel like it's unnecessarily hard to get the resulting text from a
>> narrow-to-region session.
>
> Would you want something like this?

That does look very promising, yeah. :)
I suppose I should volunteer for writing the doc patch for this.

On Sat, Jun 20, 2015 at 7:21 PM, Bart Schaefer
<schaefer@brasslantern.com> wrote:
> On Jun 20, 11:16am, Mikael Magnusson wrote:
> }
> } I feel like it's unnecessarily hard to get the resulting text from a
> } narrow-to-region session.
>
> Hmm.  If you used "narrow-to-region -S state ..." then I think the
> resulting text would be $BUFFER between the exit from recursive-edit
> and the call to "narrow-to-region -R state" ?
>
> Except that I'm having a little trouble with -S / -R.  The value of
> $MARK never seems to be correctly restored.  Is it supposed to be?

I'll admit I didn't actually look at the impl of the widget, only the
documentation.

> } It would be nice if quote-region let you specify the type of quoting.
> } Urk?
>
> The difficulty there is that it's a widget so there's no direct way to
> pass the type of quote.  I suppose you could use $NUMERIC.

I thought widgets can take an arbitrary amount of arguments, although
it is true that almost none do. The newly added bracketed-paste takes
an argument that names the parameter to store pasted text in for
example. If you mean that you can't do it directly via bindkey then
yeah, that's true, you'd still need a wrapper widget. For my use-case
I could put the argument right in with the zle call though. (But with
PWS' suggested change, I can just insert (q-)LBUFFER/RBUFFER directly,
I think).

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: This widget implementation feels a bit clunky (edit-quoted-word)
  2015-06-21  7:09   ` Mikael Magnusson
@ 2015-06-21 17:17     ` Peter Stephenson
  2015-06-22  2:26       ` Mikael Magnusson
  2015-06-22  0:18     ` PATCH: Document narrow-to-region -l and -r Mikael Magnusson
  1 sibling, 1 reply; 19+ messages in thread
From: Peter Stephenson @ 2015-06-21 17:17 UTC (permalink / raw)
  To: zsh workers

On Sun, 21 Jun 2015 09:09:29 +0200
Mikael Magnusson <mikachu@gmail.com> wrote:
> On Sat, Jun 20, 2015 at 7:06 PM, Peter Stephenson
> <p.w.stephenson@ntlworld.com> wrote:
> > On Sat, 20 Jun 2015 11:16:20 +0200
> > Mikael Magnusson <mikachu@gmail.com> wrote:
> >> I feel like it's unnecessarily hard to get the resulting text from a
> >> narrow-to-region session.
> >
> > Would you want something like this?
> 
> That does look very promising, yeah. :)
> I suppose I should volunteer for writing the doc patch for this.

I've remembered to commit it on the master branch.

pws


^ permalink raw reply	[flat|nested] 19+ messages in thread

* PATCH: Document narrow-to-region -l and -r.
  2015-06-21  7:09   ` Mikael Magnusson
  2015-06-21 17:17     ` Peter Stephenson
@ 2015-06-22  0:18     ` Mikael Magnusson
  1 sibling, 0 replies; 19+ messages in thread
From: Mikael Magnusson @ 2015-06-22  0:18 UTC (permalink / raw)
  To: zsh-workers

---
 Doc/Zsh/contrib.yo | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 323bf0f..09ac5c8 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -2272,7 +2272,8 @@ tindex(narrow-to-region)
 tindex(narrow-to-region-invisible)
 redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ ))ifnztexi(                 )))
 xitem(tt(narrow-to-region )[ tt(-p) var(pre) ] [ tt(-P) var(post) ])
-xitem(SPACES()[ tt(-S) var(statepm) | tt(-R) var(statepm) ] [ tt(-n) ] [ var(start) var(end) ])
+xitem(SPACES()[ tt(-S) var(statepm) | tt(-R) var(statepm) | [ tt(-l) var(lbufvar) ] [ tt(-r) var(rbufvar) ] ])
+xitem(SPACES()[ tt(-n) ] [ var(start) var(end) ])
 item(tt(narrow-to-region-invisible))(
 Narrow the editable portion of the buffer to the region between the cursor
 and the mark, which may be in either order.  The region may not be empty.
@@ -2308,9 +2309,15 @@ parameter, except that parameters beginning with the prefix tt(_ntr_) are
 reserved for use within tt(narrow-to-region).  Typically the parameter will
 be local to the calling function.
 
+The options tt(-l) var(lbufvar) and tt(-r) var(rbufvar) may be used to
+specify parameters where the widget will store the resulting text from
+the operation.  The parameter var(lbufvar) will contain var(LBUFFER)
+and var(rbufvar) will contain var(RBUFFER).  Neither of these two options
+may be used with tt(-S) or tt(-R).
+
 tt(narrow-to-region-invisible) is a simple widget which calls
 tt(narrow-to-region) with arguments which replace any text outside the
-region with `tt(...)'.
+region with `tt(...)'.  It does not take any arguments.
 
 The display is restored (and the widget returns) upon any zle command
 which would usually cause the line to be accepted or aborted.  Hence an
-- 
2.4.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: This widget implementation feels a bit clunky (edit-quoted-word)
  2015-06-21 17:17     ` Peter Stephenson
@ 2015-06-22  2:26       ` Mikael Magnusson
  0 siblings, 0 replies; 19+ messages in thread
From: Mikael Magnusson @ 2015-06-22  2:26 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh workers

On Sun, Jun 21, 2015 at 7:17 PM, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
> On Sun, 21 Jun 2015 09:09:29 +0200
> Mikael Magnusson <mikachu@gmail.com> wrote:
>> On Sat, Jun 20, 2015 at 7:06 PM, Peter Stephenson
>> <p.w.stephenson@ntlworld.com> wrote:
>> > On Sat, 20 Jun 2015 11:16:20 +0200
>> > Mikael Magnusson <mikachu@gmail.com> wrote:
>> >> I feel like it's unnecessarily hard to get the resulting text from a
>> >> narrow-to-region session.
>> >
>> > Would you want something like this?
>>
>> That does look very promising, yeah. :)
>> I suppose I should volunteer for writing the doc patch for this.
>
> I've remembered to commit it on the master branch.

This feels more reasonable now (some of the improvements might be
applied to the previous version too, so not an entirely fair
comparison), (the business with the :+ is because if you delete the
whole string, ${(q-)lbuf} when lbuf is empty results in '', and so
does rbuf, thus concatenated to '''' which with rc_quotes enabled
leaves a single ' that should not be there).

function _edit_quoted_word()
{
  local -a reply
  local REPLY REPLY2 len left right lbuf rbuf
  _split_shell_arguments_intuitive
  left=${(j::)reply[1,REPLY-1]}
  right=${(j::)reply[REPLY+1,-1]}
  (( CURSOR-=$#left ))
  BUFFER=${(Q)reply[REPLY]}
  REGION_ACTIVE=0
  narrow-to-region -l lbuf -r rbuf -p "$left>>|" -P "|<<$right" 0 $#BUFFER
  LBUFFER=$left${lbuf:+${(q-)lbuf}}
  RBUFFER=${rbuf:+${(q-)rbuf}}$right
}
zle -N _edit_quoted_word
bindkey '^_q' _edit_quoted_word

autoload -U split-shell-arguments

function _split_shell_arguments_intuitive()
{
  split-shell-arguments
  # borrowed logic from modify-current-argument to get word under cursor
  (( REPLY > 1 && REPLY & 1 )) && (( REPLY-- ))
}

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 19+ messages in thread

* PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky)
  2015-06-20 17:21 ` This widget implementation feels a bit clunky (edit-quoted-word) Bart Schaefer
@ 2015-07-18 23:42   ` Bart Schaefer
  2015-07-19  3:55     ` Oliver Kiddle
  0 siblings, 1 reply; 19+ messages in thread
From: Bart Schaefer @ 2015-07-18 23:42 UTC (permalink / raw)
  To: zsh workers

On Jun 20, 10:21am, Bart Schaefer wrote:
} 
} [...]  If you used "narrow-to-region -S state ..." then I think the
} resulting text would be $BUFFER between the exit from recursive-edit
} and the call to "narrow-to-region -R state" ?
} 
} Except that I'm having a little trouble with -S / -R.  The value of
} $MARK never seems to be correctly restored.  Is it supposed to be?

What was happening:

In order to narrow the editable buffer to just the current region, the
lesser of MARK and CURSOR is calculated and assigned to _ntr_start.
Then the leading $_ntr_start characters are removed from BUFFER and
MARK and CURSOR are shifted to correspond, so one or the other of them
always ends up being set to 0.

Upon exit from recursive-edit (or calling "narrow-to-region -R state")
the values of LBUFFER and RBUFFER are reset, which automatically moves
CURSOR to the beginning of the new RBUFFER, but does not change MARK.
This guarantees that MARK will be wrong, because it will either be left
as zero, or at a now-irrelevant position in the middle of the buffer,
possibly even past the end of it.

So this patch:

- cleans up white space in the documentary comment

- checks that the -l and -r buffer variables also don't use _ntr_

- consistently uses "zle -M ... >&2" even though I don't know why

- does away with a bunch of unnecessary "eval"s

- declares the -l -r and -S variables with "typeset -g"

- forces MARK and CURSOR to point to opposite ends of the region after
  the function returns, which is really the point of all this


diff --git a/Functions/Zle/narrow-to-region b/Functions/Zle/narrow-to-region
index 8b88da4..293f89b 100644
--- a/Functions/Zle/narrow-to-region
+++ b/Functions/Zle/narrow-to-region
@@ -5,21 +5,26 @@
 # Optionally accepts exactly two arguments, which are used instead of
 # $CURSOR and $MARK as limits to the range.
 #
+# Upon exit, $MARK is always the start of the edited range and $CURSOR
+# the end of the range, even if they began in the opposite order.
+#
 # Other options:
-#   -p pretext   show `pretext' instead of the buffer text before the region.
-#   -P posttext  show  `posttext' instead of the buffer text after the region.
-# Either or both may be empty.
+#   -p pretext   show "pretext" instead of the buffer text before the region.
+#   -P posttext  show "posttext" instead of the buffer text after the region.
+#                Either or both may be empty.
 #   -n           Only replace the text before or after the region with
 #                the -p or -P options if the text was not empty.
-#   -l lbufvar   ) $lbufvar and $rbufvar will contain the value of $LBUFFER and
-#   -r rbufvar   ) $RBUFFER resulting from any recursive edit (i.e. not with -S or -R)
+#   -l lbufvar   $lbufvar is assigned the value of $LBUFFER and
+#   -r rbufvar   $rbufvar is assigned the value of $RBUFFER
+#                from any recursive edit (i.e. not with -S or -R).  Neither
+#                lbufvar nor rbufvar may begin with the prefix "_ntr_".
 #   -S statevar
 #   -R statevar
-# Save or restore the state in/from the parameter named statevar.  In
-# either case no recursive editing takes place; this will typically be
-# done within the calling function between calls with -S and -R.  The
-# statevar may not begin with the prefix _ntr_ which is reserved for
-# parameters within narrow-to-region.
+#      Save or restore the state in/from the parameter named statevar.  In
+#      either case no recursive editing takes place; this will typically be
+#      done within the calling function between calls with -S and -R.  The
+#      statevar may not begin with the prefix "_ntr_" which is reserved for
+#      parameters within narrow-to-region.
 
 emulate -L zsh
 setopt extendedglob
@@ -55,7 +60,8 @@ while getopts "l:np:P:r:R:S:" _ntr_opt; do
 done
 (( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
-if [[ $_ntr_restore = _ntr_* || $_ntr_save = _ntr_* ]]; then
+if [[ $_ntr_restore = _ntr_* || $_ntr_save = _ntr_* ||
+      $_ntr_lbuf_return = _ntr_* || $ntr_rbuf_return = _ntr_* ]]; then
   zle -M "$0: _ntr_ prefix is reserved" >&2
   return 1
 fi
@@ -64,7 +70,7 @@ if [[ -n $_ntr_save || -z $_ntr_restore ]]; then
 
   if (( $# )); then
     if (( $# != 2 )); then
-      zle -M "$0: supply zero or two arguments"
+      zle -M "$0: supply zero or two arguments" >&2
       return 1
     fi
     _ntr_start=$1
@@ -94,39 +100,44 @@ if [[ -n $_ntr_save || -z $_ntr_restore ]]; then
   fi
   PREDISPLAY="$_ntr_predisplay$_ntr_pretext"
   POSTDISPLAY="$_ntr_posttext$_ntr_postdisplay"
-  BUFFER=${BUFFER[_ntr_start+1,_ntr_end-1]}
-  CURSOR=$_ntr_cursor
-  MARK=$_ntr_mark
 
   if [[ -n $_ntr_save ]]; then
-    eval "$_ntr_save=(${(qq)_ntr_predisplay} ${(qq)_ntr_postdisplay}
-${(qq)_ntr_lbuffer} ${(qq)_ntr_rbuffer})" || return 1
+    builtin typeset -ga $_ntr_save
+    set -A $_ntr_save "${_ntr_predisplay}" "${_ntr_postdisplay}" \
+	"${_ntr_lbuffer}" "${_ntr_rbuffer}" || return 1
   fi
+
+  BUFFER=${BUFFER[_ntr_start+1,_ntr_end-1]}
+  CURSOR=$_ntr_cursor
+  MARK=$_ntr_mark
 fi
 
 if [[ -z $_ntr_save && -z $_ntr_restore ]]; then
   zle recursive-edit
   _ntr_stat=$?
 
-  [[ -n $_ntr_lbuf_return ]] && eval "${_ntr_lbuf_return}=\${LBUFFER}"
-  [[ -n $_ntr_rbuf_return ]] && eval "${_ntr_rbuf_return}=\${RBUFFER}"
+  [[ -n $_ntr_lbuf_return ]] &&
+    builtin typeset -g ${_ntr_lbuf_return}="${LBUFFER}"
+  [[ -n $_ntr_rbuf_return ]] &&
+    builtin typeset -g ${_ntr_rbuf_return}="${RBUFFER}"
 fi
 
 if [[ -n $_ntr_restore || -z $_ntr_save ]]; then
   if [[ -n $_ntr_restore ]]; then
-    if ! eval "_ntr_predisplay=\${${_ntr_restore}[1]}
-_ntr_postdisplay=\${${_ntr_restore}[2]}
-_ntr_lbuffer=\${${_ntr_restore}[3]}
-_ntr_rbuffer=\${${_ntr_restore}[4]}"; then
-      zle -M Failed.
+    if ! { _ntr_predisplay="${${(@P)_ntr_restore}[1]}"
+           _ntr_postdisplay="${${(@P)_ntr_restore}[2]}"
+           _ntr_lbuffer="${${(@P)_ntr_restore}[3]}"
+           _ntr_rbuffer="${${(@P)_ntr_restore}[4]}" }; then
+      zle -M Failed. >&2
       return 1
     fi
   fi
 
   PREDISPLAY=$_ntr_predisplay
   POSTDISPLAY=$_ntr_postdisplay
-  LBUFFER="$_ntr_lbuffer$LBUFFER"
-  RBUFFER="$RBUFFER$_ntr_rbuffer"
+  LBUFFER="$_ntr_lbuffer$BUFFER"
+  RBUFFER="$_ntr_rbuffer"
+  MARK=${#_ntr_lbuffer}
 fi
 
 return $_ntr_stat


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky)
  2015-07-18 23:42   ` PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky) Bart Schaefer
@ 2015-07-19  3:55     ` Oliver Kiddle
  2015-07-19  8:23       ` Bart Schaefer
  0 siblings, 1 reply; 19+ messages in thread
From: Oliver Kiddle @ 2015-07-19  3:55 UTC (permalink / raw)
  To: zsh workers

>  emulate -L zsh
>  setopt extendedglob

These lines (not introduced by Bart's patch) have the effect of
resetting lots of options when inside the recursive-edit. That 
affects the behaviour of some things such as completion.

How much of emulate zsh is actually needed by narrow-to-region itself?
Can we get by with just setopt localoptions and a few extras? Or use an
anonymous function around everything but recursive-edit?

It'd also be good for the function to use the new undo limit features.

Oliver


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky)
  2015-07-19  3:55     ` Oliver Kiddle
@ 2015-07-19  8:23       ` Bart Schaefer
  2015-07-20  9:19         ` Oliver Kiddle
  0 siblings, 1 reply; 19+ messages in thread
From: Bart Schaefer @ 2015-07-19  8:23 UTC (permalink / raw)
  To: zsh workers

On Jul 19,  5:55am, Oliver Kiddle wrote:
}
} How much of emulate zsh is actually needed by narrow-to-region itself?

It uses a bunch of unquoted variable references without braces so it
clearly expects no-shwordsplit and no-ksharrays.  I don't see any need
for extendedglob, on another quick read-through.

} It'd also be good for the function to use the new undo limit features.

I was going to send a follow-up message about undo-ing and whether a call
to split-undo is needed before (and/or after) the recursive-edit.

Related, should -S / -R implicitly set undo points?


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky)
  2015-07-19  8:23       ` Bart Schaefer
@ 2015-07-20  9:19         ` Oliver Kiddle
  2015-07-20 16:29           ` Bart Schaefer
  2015-07-23  5:41           ` Undo and narrow-to-region (was Re: PATCH: narrow-to-region (was ...)) Bart Schaefer
  0 siblings, 2 replies; 19+ messages in thread
From: Oliver Kiddle @ 2015-07-20  9:19 UTC (permalink / raw)
  To: zsh workers

Bart wrote:
> } It'd also be good for the function to use the new undo limit features.
> 
> I was going to send a follow-up message about undo-ing and whether a call
> to split-undo is needed before (and/or after) the recursive-edit.

It is needed immediately after you've setup PREDISPLAY and emptied
BUFFER.

I would have been fairly sure of that answer but my own attempts to make
it work had failed so I went back to see again first. I now realise that
the problem I had is elsewhere. I've attached a very rudimentary patch to
narrow-to-region.

My main use of narrow-to-region is to retrieve history lines into the
middle of the current line. And it is just this situation that is
breaking it. When doing:
  zle undo $_ntr_changeno
it is falling foul of the first line of unapplychange which is:
  if(ch->hist != histline) {
and not undoing enough changes.

This is a consequence of the fix in 10328. If I comment out the two
lines of undo() which do else break; it appears to work fine and the
problem that 10328 targetted doesn't seem to come back. But it is hard
to know how that was failing at the time.

> Related, should -S / -R implicitly set undo points?

I've never used those two options and am not sure I quite understand
what they're for. At least not without digging in the archives. With the
patch below, it is fairly obviously broken for them because
_ntr_changeno is set in a different block from the one which does zle
undo to revert to it.

Oliver

diff --git a/Functions/Zle/narrow-to-region b/Functions/Zle/narrow-to-region
index 293f89b..ae4addd 100644
--- a/Functions/Zle/narrow-to-region
+++ b/Functions/Zle/narrow-to-region
@@ -29,8 +29,9 @@
 emulate -L zsh
 setopt extendedglob
 
-local _ntr_lbuf_return _ntr_rbuf_return
+local _ntr_new_lbuf _ntr_newrbuf _ntr_lbuf_return _ntr_rbuf_return
 local _ntr_predisplay=$PREDISPLAY _ntr_postdisplay=$POSTDISPLAY
+integer _ntr_savelim=$UNDO_LIMIT_NO _ntr_changeno
 integer _ntr_start _ntr_end _ntr_swap _ntr_cursor=$CURSOR _ntr_mark=$MARK
 integer _ntr_stat
 
@@ -98,6 +99,7 @@ if [[ -n $_ntr_save || -z $_ntr_restore ]]; then
   then
     _ntr_posttext=$_ntr_rbuffer
   fi
+  _ntr_changeno=$UNDO_CHANGE_NO
   PREDISPLAY="$_ntr_predisplay$_ntr_pretext"
   POSTDISPLAY="$_ntr_posttext$_ntr_postdisplay"
 
@@ -110,16 +112,25 @@ if [[ -n $_ntr_save || -z $_ntr_restore ]]; then
   BUFFER=${BUFFER[_ntr_start+1,_ntr_end-1]}
   CURSOR=$_ntr_cursor
   MARK=$_ntr_mark
+  zle split-undo
 fi
 
 if [[ -z $_ntr_save && -z $_ntr_restore ]]; then
-  zle recursive-edit
-  _ntr_stat=$?
-
-  [[ -n $_ntr_lbuf_return ]] &&
-    builtin typeset -g ${_ntr_lbuf_return}="${LBUFFER}"
-  [[ -n $_ntr_rbuf_return ]] &&
-    builtin typeset -g ${_ntr_rbuf_return}="${RBUFFER}"
+  {
+    UNDO_LIMIT_NO=$UNDO_CHANGE_NO
+    zle recursive-edit
+    _ntr_stat=$?
+    _ntr_newlbuf="$LBUFFER"
+    _ntr_newrbuf="$RBUFFER"
+
+    [[ -n $_ntr_lbuf_return ]] &&
+      builtin typeset -g ${_ntr_lbuf_return}="${LBUFFER}"
+    [[ -n $_ntr_rbuf_return ]] &&
+      builtin typeset -g ${_ntr_rbuf_return}="${RBUFFER}"
+  } always {
+    zle undo $_ntr_changeno
+    UNDO_LIMIT_NO=_ntr_savelim
+  }
 fi
 
 if [[ -n $_ntr_restore || -z $_ntr_save ]]; then
@@ -135,8 +146,8 @@ if [[ -n $_ntr_restore || -z $_ntr_save ]]; then
 
   PREDISPLAY=$_ntr_predisplay
   POSTDISPLAY=$_ntr_postdisplay
-  LBUFFER="$_ntr_lbuffer$BUFFER"
-  RBUFFER="$_ntr_rbuffer"
+  LBUFFER="$_ntr_lbuffer$_ntr_newlbuf"
+  RBUFFER="$_ntr_newrbuf$_ntr_rbuffer"
   MARK=${#_ntr_lbuffer}
 fi
 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky)
  2015-07-20  9:19         ` Oliver Kiddle
@ 2015-07-20 16:29           ` Bart Schaefer
  2015-07-23  5:41           ` Undo and narrow-to-region (was Re: PATCH: narrow-to-region (was ...)) Bart Schaefer
  1 sibling, 0 replies; 19+ messages in thread
From: Bart Schaefer @ 2015-07-20 16:29 UTC (permalink / raw)
  To: zsh workers

On Jul 20, 11:19am, Oliver Kiddle wrote:
} Subject: Re: PATCH: narrow-to-region (was Re: This widget implementation f
}
} Bart wrote:
} > } It'd also be good for the function to use the new undo limit features.
} > 
} > I was going to send a follow-up message about undo-ing and whether a call
} > to split-undo is needed before (and/or after) the recursive-edit.
} 
} It is needed immediately after you've setup PREDISPLAY and emptied
} BUFFER.

The sourceforge outage is getting a bit annoying with respect to passing
these patches back and forth.

} > Related, should -S / -R implicitly set undo points?
} 
} I've never used those two options and am not sure I quite understand
} what they're for. At least not without digging in the archives. With the
} patch below, it is fairly obviously broken for them because
} _ntr_changeno is set in a different block from the one which does zle
} undo to revert to it.

The -S and -R options are basically a hack to because there's no good way
to do a callback mechansim.  What you'd like is to replace recursive-edit
with a call back into the invoking scope, but you can't do that without
real closures or at least real namerefs, so "narrow-to-region -S" does
everything up to recursive-edit and then saves state, followed by -R
which restores state and picks up where -S left off.

If you introduce new variables _ntr_savelim and _ntr_changeno those are
going to have to be added to the state save/restore, or else they have
to be localized to the part where recursive-edit is called and NOT the
parts where state is saved/restored.

Also this --

}    PREDISPLAY=$_ntr_predisplay
}    POSTDISPLAY=$_ntr_postdisplay
} -  LBUFFER="$_ntr_lbuffer$BUFFER"
} -  RBUFFER="$_ntr_rbuffer"
} +  LBUFFER="$_ntr_lbuffer$_ntr_newlbuf"
} +  RBUFFER="$_ntr_newrbuf$_ntr_rbuffer"
}    MARK=${#_ntr_lbuffer}

-- breaks MARK and CURSOR again, you need

LBUFFER="$_ntr_lbuffer$_ntr_newlbuf$_ntr_newrbuf"
RBUFFER="$_ntr_rbuffer"

to get CURSOR in the right place.  Which means you may as well not save
the left and right buffers separately to begin with.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Undo and narrow-to-region (was Re: PATCH: narrow-to-region (was ...))
  2015-07-20  9:19         ` Oliver Kiddle
  2015-07-20 16:29           ` Bart Schaefer
@ 2015-07-23  5:41           ` Bart Schaefer
  2015-07-27 15:44             ` Oliver Kiddle
  1 sibling, 1 reply; 19+ messages in thread
From: Bart Schaefer @ 2015-07-23  5:41 UTC (permalink / raw)
  To: zsh workers

On Jul 20, 11:19am, Oliver Kiddle wrote:
} Subject: Re: PATCH: narrow-to-region (was Re: This widget implementation f
}
} My main use of narrow-to-region is to retrieve history lines into the
} middle of the current line. And it is just this situation that is
} breaking it. When doing:
}   zle undo $_ntr_changeno
} it is falling foul of the first line of unapplychange which is:
}   if(ch->hist != histline) {
} and not undoing enough changes.
} 
} This is a consequence of the fix in 10328. If I comment out the two
} lines of undo() which do else break; it appears to work fine and the
} problem that 10328 targetted doesn't seem to come back. But it is hard
} to know how that was failing at the time.

So you mean that part of undo becomes

        if (unapplychange(prev))
            curchange = prev;
    } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));

??

What must be happening is that unapplychange() alters the history line,
returns zero, and then is called again with exactly the same struct,
which now succeeds on the adjusted history line.  Pre-10328, the call
to unapplychange() would fail but curchange was moved to ->prev either
way, skipping over the change that failed.

So the "else break;" looks like paranoia to prevent an infinite loop in
the event that unapplychange() fails every time.  Which could happen if
quietgethist() is a no-op?  Perhaps when a line has fallen out of the
history because of HISTSIZE?

Anyway modulo infinite-loop-prevention, it looks to me as if removing
that else-clause is the right thing to do, and similarly in redo() a
bit further along.  I'll let Oliver do the patch if we all agree.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Undo and narrow-to-region (was Re: PATCH: narrow-to-region (was ...))
  2015-07-23  5:41           ` Undo and narrow-to-region (was Re: PATCH: narrow-to-region (was ...)) Bart Schaefer
@ 2015-07-27 15:44             ` Oliver Kiddle
  2015-08-12 17:00               ` PATCH: Re: Undo and narrow-to-region (was ...) Oliver Kiddle
  0 siblings, 1 reply; 19+ messages in thread
From: Oliver Kiddle @ 2015-07-27 15:44 UTC (permalink / raw)
  To: zsh workers

On 22 Jul, Bart wrote:
> So you mean that part of undo becomes
> 
>         if (unapplychange(prev))
>             curchange = prev;
>     } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));
> 
> ??
> 
> What must be happening is that unapplychange() alters the history line,
> returns zero, and then is called again with exactly the same struct,

Yes. Changes to the history number are not collected up as change events
in nextchanges. This means that several history line changes are undone
in a single go.

It also has the, perhaps less desirable, effect that you can't use redo
to revert a change to the history line. Is that worth fixing?

> So the "else break;" looks like paranoia to prevent an infinite loop in
> the event that unapplychange() fails every time.  Which could happen if
> quietgethist() is a no-op?  Perhaps when a line has fallen out of the
> history because of HISTSIZE?

I tried to find a way to induce such an infinite loop and couldn't. Even
so, how about the following patch which checks histline had changed to
detect a failure to set the history line.

> Anyway modulo infinite-loop-prevention, it looks to me as if removing
> that else-clause is the right thing to do, and similarly in redo() a
> bit further along.  I'll let Oliver do the patch if we all agree.

Not sure it's necessary for redo because there's no option to redo more
than one change.

Oliver

diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 8b55403..d512c7a 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -1590,8 +1590,8 @@ undo(char **args)
 	    return 1;
 	if (unapplychange(prev))
 	    curchange = prev;
-	else
-	    break;
+	else if (histline != prev->hist)
+	    break; /* avoid infinite loop if history line unchanged */
     } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));
     setlastline();
     return 0;


^ permalink raw reply	[flat|nested] 19+ messages in thread

* PATCH: Re: Undo and narrow-to-region (was ...)
  2015-07-27 15:44             ` Oliver Kiddle
@ 2015-08-12 17:00               ` Oliver Kiddle
  2015-08-17 21:15                 ` Daniel Hahler
  0 siblings, 1 reply; 19+ messages in thread
From: Oliver Kiddle @ 2015-08-12 17:00 UTC (permalink / raw)
  To: zsh workers

Here is the narrow-to-region with support for undo limits along with
a related change to the undo mechanism.

It'd be good if this gets some wider testing because I only use
narrow-to-region in limited ways. This is showing up issues with
$UNDO_CHANGE_NO and zle undo to undo multiple changes.

The change to zle_utils.c here is for $UNDO_CHANGE_NO. 
If you consider this function:
  undostuff() {
    LBUFFER+='a'
    LBUFFER+='b'
    zle split-undo
    LBUFFER+='c'
    _undo_here=$UNDO_CHANGE_NO
    LBUFFER+='d'
  }

A subsequent zle undo $_undo_here should take you back to 'abc' while a
default undo should skip straight to 'ab' without stopping at 'abc'.

The following adds a call to mkundoent() when $UNDO_CHANGE_NO is
referenced so you get a clear change number marking the current
state. I think the result is simpler than the current tricks with
undo_set_by_variable.

This is still not perfect with history changes. I'm not really happy
with the way history line changes are managed in the undo system in
general. The old fix in 10328 seems rather ugly. It might be better to
create full undo entries for history changes though that would need
hacks to ensure that multiple history changes are undone in a single
step.

This patch also replaces 35935.

Oliver

diff --git a/Functions/Zle/narrow-to-region b/Functions/Zle/narrow-to-region
index 293f89b..0ef28a8 100644
--- a/Functions/Zle/narrow-to-region
+++ b/Functions/Zle/narrow-to-region
@@ -26,11 +26,13 @@
 #      statevar may not begin with the prefix "_ntr_" which is reserved for
 #      parameters within narrow-to-region.
 
-emulate -L zsh
-setopt extendedglob
+# set the minimum of options to avoid changing behaviour away from
+# user preferences from within recursive-edit
+setopt localoptions noshwordsplit noksharrays
 
-local _ntr_lbuf_return _ntr_rbuf_return
+local _ntr_newbuf _ntr_lbuf_return _ntr_rbuf_return
 local _ntr_predisplay=$PREDISPLAY _ntr_postdisplay=$POSTDISPLAY
+integer _ntr_savelim=UNDO_LIMIT_NO _ntr_changeno
 integer _ntr_start _ntr_end _ntr_swap _ntr_cursor=$CURSOR _ntr_mark=$MARK
 integer _ntr_stat
 
@@ -61,7 +63,7 @@ done
 (( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
 if [[ $_ntr_restore = _ntr_* || $_ntr_save = _ntr_* ||
-      $_ntr_lbuf_return = _ntr_* || $ntr_rbuf_return = _ntr_* ]]; then
+      $_ntr_lbuf_return = _ntr_* || $_ntr_rbuf_return = _ntr_* ]]; then
   zle -M "$0: _ntr_ prefix is reserved" >&2
   return 1
 fi
@@ -86,30 +88,34 @@ if [[ -n $_ntr_save || -z $_ntr_restore ]]; then
     _ntr_end=_ntr_swap
   fi
 
-  (( _ntr_end++, _ntr_cursor -= _ntr_start, _ntr_mark -= _ntr_start ))
+  (( _ntr_cursor -= _ntr_start, _ntr_mark -= _ntr_start ))
   
   _ntr_lbuffer=${BUFFER[1,_ntr_start]}
   if [[ -z $_ntr_usepretext || ( -n $_ntr_nonempty && -z $_ntr_lbuffer ) ]]
   then
     _ntr_pretext=$_ntr_lbuffer
   fi
-  _ntr_rbuffer=${BUFFER[_ntr_end,-1]}
+  _ntr_rbuffer=${BUFFER[_ntr_end+1,-1]}
   if [[ -z $_ntr_useposttext || ( -n $_ntr_nonempty && -z $_ntr_rbuffer ) ]]
   then
     _ntr_posttext=$_ntr_rbuffer
   fi
+  _ntr_changeno=$UNDO_CHANGE_NO
   PREDISPLAY="$_ntr_predisplay$_ntr_pretext"
   POSTDISPLAY="$_ntr_posttext$_ntr_postdisplay"
 
   if [[ -n $_ntr_save ]]; then
     builtin typeset -ga $_ntr_save
     set -A $_ntr_save "${_ntr_predisplay}" "${_ntr_postdisplay}" \
-	"${_ntr_lbuffer}" "${_ntr_rbuffer}" || return 1
+	"${_ntr_savelim}" "${_ntr_changeno}" \
+	"${_ntr_start}" "${_ntr_end}" || return 1
   fi
 
-  BUFFER=${BUFFER[_ntr_start+1,_ntr_end-1]}
+  BUFFER=${BUFFER[_ntr_start+1,_ntr_end]}
   CURSOR=$_ntr_cursor
   MARK=$_ntr_mark
+  zle split-undo
+  UNDO_LIMIT_NO=$UNDO_CHANGE_NO
 fi
 
 if [[ -z $_ntr_save && -z $_ntr_restore ]]; then
@@ -126,18 +132,22 @@ if [[ -n $_ntr_restore || -z $_ntr_save ]]; then
   if [[ -n $_ntr_restore ]]; then
     if ! { _ntr_predisplay="${${(@P)_ntr_restore}[1]}"
            _ntr_postdisplay="${${(@P)_ntr_restore}[2]}"
-           _ntr_lbuffer="${${(@P)_ntr_restore}[3]}"
-           _ntr_rbuffer="${${(@P)_ntr_restore}[4]}" }; then
+	   _ntr_savelim="${${(@P)_ntr_restore}[3]}"
+	   _ntr_changeno="${${(@P)_ntr_restore}[4]}"
+	   _ntr_start="${${(@P)_ntr_restore}[5]}"
+	   _ntr_end="${${(@P)_ntr_restore}[6]}" }; then
       zle -M Failed. >&2
       return 1
     fi
   fi
 
+  _ntr_newbuf="$BUFFER"
+  zle undo $_ntr_changeno
   PREDISPLAY=$_ntr_predisplay
   POSTDISPLAY=$_ntr_postdisplay
-  LBUFFER="$_ntr_lbuffer$BUFFER"
-  RBUFFER="$_ntr_rbuffer"
-  MARK=${#_ntr_lbuffer}
+  BUFFER[_ntr_start+1,_ntr_end]="$_ntr_newbuf"
+  (( MARK = _ntr_start, CURSOR = _ntr_start + ${#_ntr_newbuf} ))
+  UNDO_LIMIT_NO=_ntr_savelim
 fi
 
 return $_ntr_stat
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 8b55403..d1d3206 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -1409,10 +1409,6 @@ zlong undo_changeno;
 
 zlong undo_limitno;
 
-/* If non-zero, the last increment to undo_changeno was for the variable */
-
-static int undo_set_by_variable;
-
 /**/
 void
 initundo(void)
@@ -1423,7 +1419,6 @@ initundo(void)
     curchange->del = curchange->ins = NULL;
     curchange->dell = curchange->insl = 0;
     curchange->changeno = undo_changeno = undo_limitno = 0;
-    undo_set_by_variable = 0;
     lastline = zalloc((lastlinesz = linesz) * ZLE_CHAR_SIZE);
     ZS_memcpy(lastline, zleline, (lastll = zlell));
     lastcs = zlecs;
@@ -1549,7 +1544,6 @@ mkundoent(void)
 	ch->prev = NULL;
     }
     ch->changeno = ++undo_changeno;
-    undo_set_by_variable = 0;
     endnextchanges = ch;
 }
 
@@ -1584,14 +1578,13 @@ undo(char **args)
 	struct change *prev = curchange->prev;
 	if(!prev)
 	    return 1;
-	if (prev->changeno < last_change)
+	if (prev->changeno <= last_change)
 	    break;
-	if (prev->changeno < undo_limitno && !*args)
+	if (prev->changeno <= undo_limitno && !*args)
 	    return 1;
-	if (unapplychange(prev))
-	    curchange = prev;
-	else
-	    break;
+	if (!unapplychange(prev) && last_change >= 0)
+	    unapplychange(prev);
+	curchange = prev;
     } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));
     setlastline();
     return 0;
@@ -1741,18 +1734,10 @@ zlecallhook(char *name, char *arg)
 zlong
 get_undo_current_change(UNUSED(Param pm))
 {
-    if (undo_set_by_variable) {
-	/* We were the last to increment this, doesn't need another one. */
-	return undo_changeno;
-    }
-    undo_set_by_variable = 1;
-    /*
-     * Increment the number in case a change is in progress;
-     * we don't want to back off what's already been done when
-     * we return to this change number.  This eliminates any
-     * problem about the point where a change is numbered
-     */
-    return ++undo_changeno;
+    /* add entry for any pending changes */
+    mkundoent();
+    setlastline();
+    return undo_changeno;
 }
 
 /**/


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: Re: Undo and narrow-to-region (was ...)
  2015-08-12 17:00               ` PATCH: Re: Undo and narrow-to-region (was ...) Oliver Kiddle
@ 2015-08-17 21:15                 ` Daniel Hahler
  2015-08-17 21:58                   ` Bart Schaefer
  2015-08-18  7:05                   ` Bart Schaefer
  0 siblings, 2 replies; 19+ messages in thread
From: Daniel Hahler @ 2015-08-17 21:15 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: Zsh Hackers' List, Christian Neukirchen

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Oliver,

this patch breaks the following widget I am using (via http://chneukirchen.org/blog/archive/2013/03/10-fresh-zsh-tricks-you-may-not-know.html):

autoload -Uz narrow-to-region
function _history-incremental-preserving-pattern-search-backward
{
  local state
  MARK=CURSOR  # magick, else multiple ^R don't work
  narrow-to-region -p "$LBUFFER${BUFFER:+>>}" -P "${BUFFER:+<<}$RBUFFER" -S state
  zle end-of-history
  zle history-incremental-pattern-search-backward
  narrow-to-region -R state
}
zle -N _history-incremental-preserving-pattern-search-backward
bindkey "^R" _history-incremental-preserving-pattern-search-backward
bindkey -M isearch "^R" history-incremental-pattern-search-backward
bindkey "^S" history-incremental-pattern-search-forward


After ^R, pressing Enter will add the same line to the end again.
This also happens when pressing a cursor key etc.

TEST CASE:
% echo foo
foo
% ^Rfoo^M
fooecho foo

Commit: 832130c57dedc532191512045096180657a049f3


Regards,
Daniel.

On 12.08.2015 19:00, Oliver Kiddle wrote:
> Here is the narrow-to-region with support for undo limits along with
> a related change to the undo mechanism.
> 
> It'd be good if this gets some wider testing because I only use
> narrow-to-region in limited ways. This is showing up issues with
> $UNDO_CHANGE_NO and zle undo to undo multiple changes.
> 
> The change to zle_utils.c here is for $UNDO_CHANGE_NO. 
> If you consider this function:
>   undostuff() {
>     LBUFFER+='a'
>     LBUFFER+='b'
>     zle split-undo
>     LBUFFER+='c'
>     _undo_here=$UNDO_CHANGE_NO
>     LBUFFER+='d'
>   }
> 
> A subsequent zle undo $_undo_here should take you back to 'abc' while a
> default undo should skip straight to 'ab' without stopping at 'abc'.
> 
> The following adds a call to mkundoent() when $UNDO_CHANGE_NO is
> referenced so you get a clear change number marking the current
> state. I think the result is simpler than the current tricks with
> undo_set_by_variable.
> 
> This is still not perfect with history changes. I'm not really happy
> with the way history line changes are managed in the undo system in
> general. The old fix in 10328 seems rather ugly. It might be better to
> create full undo entries for history changes though that would need
> hacks to ensure that multiple history changes are undone in a single
> step.
> 
> This patch also replaces 35935.
> 
> Oliver
> 
> diff --git a/Functions/Zle/narrow-to-region b/Functions/Zle/narrow-to-region
> index 293f89b..0ef28a8 100644
> --- a/Functions/Zle/narrow-to-region
> +++ b/Functions/Zle/narrow-to-region
> @@ -26,11 +26,13 @@
>  #      statevar may not begin with the prefix "_ntr_" which is reserved for
>  #      parameters within narrow-to-region.
>  
> -emulate -L zsh
> -setopt extendedglob
> +# set the minimum of options to avoid changing behaviour away from
> +# user preferences from within recursive-edit
> +setopt localoptions noshwordsplit noksharrays
>  
> -local _ntr_lbuf_return _ntr_rbuf_return
> +local _ntr_newbuf _ntr_lbuf_return _ntr_rbuf_return
>  local _ntr_predisplay=$PREDISPLAY _ntr_postdisplay=$POSTDISPLAY
> +integer _ntr_savelim=UNDO_LIMIT_NO _ntr_changeno
>  integer _ntr_start _ntr_end _ntr_swap _ntr_cursor=$CURSOR _ntr_mark=$MARK
>  integer _ntr_stat
>  
> @@ -61,7 +63,7 @@ done
>  (( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
>  
>  if [[ $_ntr_restore = _ntr_* || $_ntr_save = _ntr_* ||
> -      $_ntr_lbuf_return = _ntr_* || $ntr_rbuf_return = _ntr_* ]]; then
> +      $_ntr_lbuf_return = _ntr_* || $_ntr_rbuf_return = _ntr_* ]]; then
>    zle -M "$0: _ntr_ prefix is reserved" >&2
>    return 1
>  fi
> @@ -86,30 +88,34 @@ if [[ -n $_ntr_save || -z $_ntr_restore ]]; then
>      _ntr_end=_ntr_swap
>    fi
>  
> -  (( _ntr_end++, _ntr_cursor -= _ntr_start, _ntr_mark -= _ntr_start ))
> +  (( _ntr_cursor -= _ntr_start, _ntr_mark -= _ntr_start ))
>    
>    _ntr_lbuffer=${BUFFER[1,_ntr_start]}
>    if [[ -z $_ntr_usepretext || ( -n $_ntr_nonempty && -z $_ntr_lbuffer ) ]]
>    then
>      _ntr_pretext=$_ntr_lbuffer
>    fi
> -  _ntr_rbuffer=${BUFFER[_ntr_end,-1]}
> +  _ntr_rbuffer=${BUFFER[_ntr_end+1,-1]}
>    if [[ -z $_ntr_useposttext || ( -n $_ntr_nonempty && -z $_ntr_rbuffer ) ]]
>    then
>      _ntr_posttext=$_ntr_rbuffer
>    fi
> +  _ntr_changeno=$UNDO_CHANGE_NO
>    PREDISPLAY="$_ntr_predisplay$_ntr_pretext"
>    POSTDISPLAY="$_ntr_posttext$_ntr_postdisplay"
>  
>    if [[ -n $_ntr_save ]]; then
>      builtin typeset -ga $_ntr_save
>      set -A $_ntr_save "${_ntr_predisplay}" "${_ntr_postdisplay}" \
> -	"${_ntr_lbuffer}" "${_ntr_rbuffer}" || return 1
> +	"${_ntr_savelim}" "${_ntr_changeno}" \
> +	"${_ntr_start}" "${_ntr_end}" || return 1
>    fi
>  
> -  BUFFER=${BUFFER[_ntr_start+1,_ntr_end-1]}
> +  BUFFER=${BUFFER[_ntr_start+1,_ntr_end]}
>    CURSOR=$_ntr_cursor
>    MARK=$_ntr_mark
> +  zle split-undo
> +  UNDO_LIMIT_NO=$UNDO_CHANGE_NO
>  fi
>  
>  if [[ -z $_ntr_save && -z $_ntr_restore ]]; then
> @@ -126,18 +132,22 @@ if [[ -n $_ntr_restore || -z $_ntr_save ]]; then
>    if [[ -n $_ntr_restore ]]; then
>      if ! { _ntr_predisplay="${${(@P)_ntr_restore}[1]}"
>             _ntr_postdisplay="${${(@P)_ntr_restore}[2]}"
> -           _ntr_lbuffer="${${(@P)_ntr_restore}[3]}"
> -           _ntr_rbuffer="${${(@P)_ntr_restore}[4]}" }; then
> +	   _ntr_savelim="${${(@P)_ntr_restore}[3]}"
> +	   _ntr_changeno="${${(@P)_ntr_restore}[4]}"
> +	   _ntr_start="${${(@P)_ntr_restore}[5]}"
> +	   _ntr_end="${${(@P)_ntr_restore}[6]}" }; then
>        zle -M Failed. >&2
>        return 1
>      fi
>    fi
>  
> +  _ntr_newbuf="$BUFFER"
> +  zle undo $_ntr_changeno
>    PREDISPLAY=$_ntr_predisplay
>    POSTDISPLAY=$_ntr_postdisplay
> -  LBUFFER="$_ntr_lbuffer$BUFFER"
> -  RBUFFER="$_ntr_rbuffer"
> -  MARK=${#_ntr_lbuffer}
> +  BUFFER[_ntr_start+1,_ntr_end]="$_ntr_newbuf"
> +  (( MARK = _ntr_start, CURSOR = _ntr_start + ${#_ntr_newbuf} ))
> +  UNDO_LIMIT_NO=_ntr_savelim
>  fi
>  
>  return $_ntr_stat
> diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
> index 8b55403..d1d3206 100644
> --- a/Src/Zle/zle_utils.c
> +++ b/Src/Zle/zle_utils.c
> @@ -1409,10 +1409,6 @@ zlong undo_changeno;
>  
>  zlong undo_limitno;
>  
> -/* If non-zero, the last increment to undo_changeno was for the variable */
> -
> -static int undo_set_by_variable;
> -
>  /**/
>  void
>  initundo(void)
> @@ -1423,7 +1419,6 @@ initundo(void)
>      curchange->del = curchange->ins = NULL;
>      curchange->dell = curchange->insl = 0;
>      curchange->changeno = undo_changeno = undo_limitno = 0;
> -    undo_set_by_variable = 0;
>      lastline = zalloc((lastlinesz = linesz) * ZLE_CHAR_SIZE);
>      ZS_memcpy(lastline, zleline, (lastll = zlell));
>      lastcs = zlecs;
> @@ -1549,7 +1544,6 @@ mkundoent(void)
>  	ch->prev = NULL;
>      }
>      ch->changeno = ++undo_changeno;
> -    undo_set_by_variable = 0;
>      endnextchanges = ch;
>  }
>  
> @@ -1584,14 +1578,13 @@ undo(char **args)
>  	struct change *prev = curchange->prev;
>  	if(!prev)
>  	    return 1;
> -	if (prev->changeno < last_change)
> +	if (prev->changeno <= last_change)
>  	    break;
> -	if (prev->changeno < undo_limitno && !*args)
> +	if (prev->changeno <= undo_limitno && !*args)
>  	    return 1;
> -	if (unapplychange(prev))
> -	    curchange = prev;
> -	else
> -	    break;
> +	if (!unapplychange(prev) && last_change >= 0)
> +	    unapplychange(prev);
> +	curchange = prev;
>      } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));
>      setlastline();
>      return 0;
> @@ -1741,18 +1734,10 @@ zlecallhook(char *name, char *arg)
>  zlong
>  get_undo_current_change(UNUSED(Param pm))
>  {
> -    if (undo_set_by_variable) {
> -	/* We were the last to increment this, doesn't need another one. */
> -	return undo_changeno;
> -    }
> -    undo_set_by_variable = 1;
> -    /*
> -     * Increment the number in case a change is in progress;
> -     * we don't want to back off what's already been done when
> -     * we return to this change number.  This eliminates any
> -     * problem about the point where a change is numbered
> -     */
> -    return ++undo_changeno;
> +    /* add entry for any pending changes */
> +    mkundoent();
> +    setlastline();
> +    return undo_changeno;
>  }
>  
>  /**/
> 
-----BEGIN PGP SIGNATURE-----

iEYEARECAAYFAlXSTt8ACgkQfAK/hT/mPgBQFwCfbI+trLonGkP6845YlVrNZPoF
XM4AoKynpdr5Yf7wTReGSog4HMTdjAOl
=bq0S
-----END PGP SIGNATURE-----


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: Re: Undo and narrow-to-region (was ...)
  2015-08-17 21:15                 ` Daniel Hahler
@ 2015-08-17 21:58                   ` Bart Schaefer
  2015-08-18  3:43                     ` Bart Schaefer
  2015-08-18  7:05                   ` Bart Schaefer
  1 sibling, 1 reply; 19+ messages in thread
From: Bart Schaefer @ 2015-08-17 21:58 UTC (permalink / raw)
  To: Zsh Hackers' List; +Cc: Daniel Hahler

On Aug 17, 11:15pm, Daniel Hahler wrote:
} Subject: Re: PATCH: Re: Undo and narrow-to-region (was ...)
}
} this patch breaks the following widget I am using (via
} http://chneukirchen.org/blog/archive/2013/03/10-fresh-zsh-tricks-you-may-not-know.html):

Oliver may not be able to get to this for a while.  Is it possible for
you to try reverting just the change to the narrow-to-region shell code
and see if that fixes things, or if both the shell and C code changes
need to be reverted?

There's been difficulty before with the save/restore state feature of
narrow-to-region.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: Re: Undo and narrow-to-region (was ...)
  2015-08-17 21:58                   ` Bart Schaefer
@ 2015-08-18  3:43                     ` Bart Schaefer
  0 siblings, 0 replies; 19+ messages in thread
From: Bart Schaefer @ 2015-08-18  3:43 UTC (permalink / raw)
  To: Zsh Hackers' List

On Aug 17,  2:58pm, I wrote:
}
} Oliver may not be able to get to this for a while.  Is it possible for
} you to try reverting just the change to the narrow-to-region shell code
} and see if that fixes things, or if both the shell and C code changes
} need to be reverted?

I was able to reproduce the broken behavior with 832130c and then back
that out to determine that Daniel's example works correctly with the
previous version of narrow-to-region.

Oliver said:
> This is still not perfect with history changes.

In fact it's actually horribly broken with respect to history changes,
at least with -R / -S, as far as I can tell ...

In Daniel's example, we start with BUFFER='', record $UNDO_CHANGE_NO,
wander about in the history a bit, then do "zle undo $_ntr_changeno"
with the expectation that will return us to the previous state, that
is, an empty BUFFER.  But it doesn't.

It mostly works as long as BUFFER isn't empty when $UNDO_CHANGE_NO is
saved.  This goes back to Oliver's grumbling that undo decides what to
do based on whether the text on the line matches the text at the undo
point,  In this case there is no text at the undo point, so anything
will match and nothing gets undone.

The following brute-forces the history back to the same line where the
undo point was set before performing the undo.  This works for Daniel's
example but I have no idea what it will do for other cases.  It can't
make things any worse, in theory.


diff --git a/Functions/Zle/narrow-to-region b/Functions/Zle/narrow-to-region
index 0ef28a8..261d821 100644
--- a/Functions/Zle/narrow-to-region
+++ b/Functions/Zle/narrow-to-region
@@ -32,7 +32,7 @@ setopt localoptions noshwordsplit noksharrays
 
 local _ntr_newbuf _ntr_lbuf_return _ntr_rbuf_return
 local _ntr_predisplay=$PREDISPLAY _ntr_postdisplay=$POSTDISPLAY
-integer _ntr_savelim=UNDO_LIMIT_NO _ntr_changeno
+integer _ntr_savelim=UNDO_LIMIT_NO _ntr_changeno _ntr_histno=HISTNO
 integer _ntr_start _ntr_end _ntr_swap _ntr_cursor=$CURSOR _ntr_mark=$MARK
 integer _ntr_stat
 
@@ -108,7 +108,7 @@ if [[ -n $_ntr_save || -z $_ntr_restore ]]; then
     builtin typeset -ga $_ntr_save
     set -A $_ntr_save "${_ntr_predisplay}" "${_ntr_postdisplay}" \
 	"${_ntr_savelim}" "${_ntr_changeno}" \
-	"${_ntr_start}" "${_ntr_end}" || return 1
+	"${_ntr_start}" "${_ntr_end}" "${_ntr_histno}" || return 1
   fi
 
   BUFFER=${BUFFER[_ntr_start+1,_ntr_end]}
@@ -135,13 +135,15 @@ if [[ -n $_ntr_restore || -z $_ntr_save ]]; then
 	   _ntr_savelim="${${(@P)_ntr_restore}[3]}"
 	   _ntr_changeno="${${(@P)_ntr_restore}[4]}"
 	   _ntr_start="${${(@P)_ntr_restore}[5]}"
-	   _ntr_end="${${(@P)_ntr_restore}[6]}" }; then
+	   _ntr_end="${${(@P)_ntr_restore}[6]}"
+	   _ntr_histno="${${(@P)_ntr_restore}[7]}" }; then
       zle -M Failed. >&2
       return 1
     fi
   fi
 
   _ntr_newbuf="$BUFFER"
+  HISTNO=_ntr_histno
   zle undo $_ntr_changeno
   PREDISPLAY=$_ntr_predisplay
   POSTDISPLAY=$_ntr_postdisplay

-- 
Barton E. Schaefer


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: PATCH: Re: Undo and narrow-to-region (was ...)
  2015-08-17 21:15                 ` Daniel Hahler
  2015-08-17 21:58                   ` Bart Schaefer
@ 2015-08-18  7:05                   ` Bart Schaefer
  1 sibling, 0 replies; 19+ messages in thread
From: Bart Schaefer @ 2015-08-18  7:05 UTC (permalink / raw)
  To: Zsh Hackers' List; +Cc: Daniel Hahler

On Aug 17, 11:15pm, Daniel Hahler wrote:
}
} function _history-incremental-preserving-pattern-search-backward
} {
}   local state
}   MARK=CURSOR  # magick, else multiple ^R don't work
}   narrow-to-region -p "$LBUFFER${BUFFER:+>>}" -P "${BUFFER:+<<}$RBUFFER" -S state
}   zle end-of-history
}   zle history-incremental-pattern-search-backward
}   narrow-to-region -R state
} }

Incidentally, the MARK=CURSOR "magick" doesn't seem to be needed any
more with the most recent revision of narrow-to-region.  However, if
you remove that, then the retrieved history will *replace* whatever
text starts out in the region between MARK and CURSOR.   (This is
consistent with what bracketed-paste does, if that matters.)

-- 
Barton E. Schaefer


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2015-08-18  7:05 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-20  9:16 This widget implementation feels a bit clunky (edit-quoted-word) Mikael Magnusson
2015-06-20 17:06 ` Peter Stephenson
2015-06-21  7:09   ` Mikael Magnusson
2015-06-21 17:17     ` Peter Stephenson
2015-06-22  2:26       ` Mikael Magnusson
2015-06-22  0:18     ` PATCH: Document narrow-to-region -l and -r Mikael Magnusson
2015-06-20 17:21 ` This widget implementation feels a bit clunky (edit-quoted-word) Bart Schaefer
2015-07-18 23:42   ` PATCH: narrow-to-region (was Re: This widget implementation feels a bit clunky) Bart Schaefer
2015-07-19  3:55     ` Oliver Kiddle
2015-07-19  8:23       ` Bart Schaefer
2015-07-20  9:19         ` Oliver Kiddle
2015-07-20 16:29           ` Bart Schaefer
2015-07-23  5:41           ` Undo and narrow-to-region (was Re: PATCH: narrow-to-region (was ...)) Bart Schaefer
2015-07-27 15:44             ` Oliver Kiddle
2015-08-12 17:00               ` PATCH: Re: Undo and narrow-to-region (was ...) Oliver Kiddle
2015-08-17 21:15                 ` Daniel Hahler
2015-08-17 21:58                   ` Bart Schaefer
2015-08-18  3:43                     ` Bart Schaefer
2015-08-18  7:05                   ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).