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

Re: zle: vi mode: wrong undo handling on fresh lines



I wrote:
> How about we instead add a split-undo zle
> widget? It is then easy for someone to add that before completion or
> other widgets like backward-delete-word.

I've attached a patch for this split-undo widget to demonstrate. As
you can see, it is very much based on Jun's changes.
If you want undo from vi command mode to stop at the start of a
completion, you would do:
  undo-complete-word() {
    zle split-undo
    zle complete-word
  }
  zle -N undo-complete-word
  bindkey '^I' undo-complete-word

That's not as simple as you might ideally like but it is at least
configurable. If we want to make this way default for completion, then
someone wanting to configure it needs to be able to reset the vi undo
start position.

split-undo can also be used in the middle of a user-defined zle widget if for
whatever reason you want to allow undos to stop half-way through the
actions of that widget.

> I can't quite work out what the emacs-mode behaviour change is.

That was because I had the second patch applied. Only the first patch is
not good because it combines more than just inserted characters.

Oliver

diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index 4372fe3..a9791ed 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -102,6 +102,7 @@
 "self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
 "send-break", sendbreak, 0
 "set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
+"split-undo", splitundo, ZLE_KEEPSUFFIX
 "spell-word", spellword, 0
 "set-local-history", setlocalhistory, 0
 "transpose-chars", transposechars, 0
@@ -125,7 +126,7 @@
 "vi-change", vichange, 0
 "vi-change-eol", vichangeeol, 0
 "vi-change-whole-line", vichangewholeline, 0
-"vi-cmd-mode", vicmdmode, 0
+"vi-cmd-mode", vicmdmode, ZLE_KEEPSUFFIX
 "vi-delete", videlete, ZLE_KILL | ZLE_KEEPSUFFIX
 "vi-delete-char", videletechar, ZLE_KEEPSUFFIX
 "vi-digit-or-beginning-of-line", vidigitorbeginningofline, 0
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index f5aec84..ed8577b 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1189,7 +1189,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
     zlereadflags = flags;
     zlecontext = context;
     histline = curhist;
-    vistartchange = 0;
+    vistartchange = -1;
     zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE);
     *zleline = ZWC('\0');
     virangeflag = lastcmd = done = zlecs = zlell = mark = 0;
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 61ae85c..68d27f8 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -1632,6 +1632,32 @@ viundochange(char **args)
 	return undo(args);
 }
 
+/**/
+int
+splitundo(char **args)
+{
+    if (vistartchange >= 0) {
+	mergeundo();
+	vistartchange = (curchange && curchange->prev) ?
+	    curchange->prev->changeno : 0;
+    }
+    handleundo();
+    return 0;
+}
+
+/**/
+void
+mergeundo(void)
+{
+    struct change *current = curchange->prev;
+    while (current && current->changeno > vistartchange+1) {
+	current->flags |= CH_PREV;
+	current = current->prev;
+	if (!current) break;
+	current->flags |= CH_NEXT;
+    }
+}
+
 /*
  * Call a ZLE hook: a user-defined widget called at a specific point
  * within the line editor.
@@ -1658,7 +1684,6 @@ zlecallhook(char *name, char *arg)
     args[1] = NULL;
     execzlefunc(thingy, args, 1);
     unrefthingy(thingy);
-
     errflag = saverrflag;
     retflag = savretflag;
 }
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index 9e9cc2f..79b8cb9 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -584,13 +584,7 @@ vicmdmode(UNUSED(char **args))
 {
     if (invicmdmode() || selectkeymap("vicmd", 0))
 	return 1;
-    struct change *current = curchange->prev;
-    while (current && current->changeno > vistartchange+1) {
-	current->flags |= CH_PREV;
-	current = current->prev;
-	if (!current) break;
-	current->flags |= CH_NEXT;
-    }
+    mergeundo();
     vichgflag = 0;
     if (zlecs != findbol())
 	DECCS();



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