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

Vim special marks - Re: PATCH: highlight pasted text



Bart wrote:
> } Apart from using a bindkey -s sequence that finishes with a widget that
> } has ZLE_YANK set.
> 
> It could be enabled by poking into region_highlight if the yankb / yanke
> internal variables were exposed via zsh/zleparam.

Vim has special marks for jumping to the start and end of the most
recent change: `[ and `]. There's also `. which is similar. In effect,
this is much the same as yankb and yanke after a paste. I think it'd
be better to make something more general like that available. It's
a feature I use quite a bit in vim. Is there anything in emacs like
yankb/yanke?

The following is an implementation that works by digging in the undo
information. This has the advantage of keeping the code related to this
feature contained within vigotomark rather than having to sprinkle code
everywhere to update the special marks. There's one very unfortunate
effect of this design choice, however: if the start of some inserted
text looks the same as what was there before, the undo mechanism will
identify the later characters as having been inserted rather than the
earlier ones.

Any ideas: stick with this and ignore that bug, hack in some way of
hinting to undo where it should look for changes, add global variables
that are updated everywhere or something else?

Oliver

diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index d751c43..1b6177b 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -876,24 +876,81 @@ int
 vigotomark(UNUSED(char **args))
 {
     ZLE_INT_T ch;
+    int *markcs, *markhist = 0;
     int oldcs = zlecs;
     int oldline = histline;
+    struct change *current;
+    int tmpcs, tmphist, found = 0;
 
     ch = getfullchar(0);
-    if (ch == ZWC('\'') || ch == ZWC('`'))
-	ch = 26;
-    else {
-	if (ch < ZWC('a') || ch > ZWC('z'))
+    if (ch == ZWC('\'') || ch == ZWC('`')) {
+	markhist = vimarkline + 26;
+	markcs = vimarkcs + 26;
+    } else if (ch == ZWC('[')) {
+	current = curchange->prev;
+	tmpcs = zlell;
+	tmphist = histline;
+	/* find lowest change offset in current undo change */
+	for (; current; current = current->prev) {
+	    if (current->hist != tmphist && found)
+		break;
+            if (current->off < tmpcs || current->hist != tmphist)
+		tmpcs = current->off;
+		tmphist = current->hist;
+	    if (!found && (current->insl || current->dell))
+		found = 1;
+	    if (!(current->flags & CH_PREV))
+		break;
+	}
+	if (!found)
 	    return 1;
-	ch -= ZWC('a');
-    }
-    if (!vimarkline[ch])
-	return 1;
-    if (curhist != vimarkline[ch] && !zle_goto_hist(vimarkline[ch], 0, 0)) {
-	vimarkline[ch] = 0;
+	markcs = &tmpcs;
+	markhist = &tmphist;
+    } else if (ch == ZWC(']')) {
+	for (current = curchange->prev;current && current->flags & CH_PREV;
+		current = current->prev) {}
+	if (!current)
+	    return 1;
+	tmpcs = current->off + current->insl;
+	tmphist = histline;
+	/* highest offset after insert in current undo change */
+        for (;current != curchange;current = current->next) {
+	    if (!found && (current->insl || current->dell))
+		found = 1;
+	    if (current->off + current->insl >= tmpcs ||
+		    current->hist != tmphist) {
+		tmpcs = current->off;
+		tmphist = current->hist;
+	        if (current->insl)
+		    tmpcs += current->insl - 1;
+	    } else /* adjust tmpcs following this change */
+		tmpcs += current->insl - current->dell;
+	}
+	if (!found)
+	    return 1;
+	markcs = &tmpcs;
+	markhist = &tmphist;
+    } else if (ch == ZWC('.') && curchange->prev) {
+	/* position cursor where it was after the last change. not exactly
+	 * what vim does but close enough */
+	tmpcs = curchange->prev->new_cs;
+	tmphist = curchange->prev->hist;
+	markcs = &tmpcs;
+	markhist = &tmphist;
+    } else if (ch >= ZWC('a') && ch <= ZWC('z')) {
+	markhist = vimarkline + (ch - ZWC('a'));
+	markcs = vimarkcs + (ch - ZWC('a'));
+    } else
 	return 1;
+    if (markhist) {
+	if (!*markhist)
+	    return 1;
+	if (histline != *markhist && !zle_goto_hist(*markhist, 0, 0)) {
+	    *markhist = 0;
+	    return 1;
+	}
     }
-    zlecs = vimarkcs[ch];
+    zlecs = *markcs;
     vimarkcs[26] = oldcs;
     vimarkline[26] = oldline;
     if (zlecs > zlell)
diff --git a/Test/X02zlevi.ztst b/Test/X02zlevi.ztst
index 14bc02e..21d22b1 100644
--- a/Test/X02zlevi.ztst
+++ b/Test/X02zlevi.ztst
@@ -289,6 +289,22 @@
 >BUFFER: one wo
 >CURSOR: 2
 
+  zletest $'one two three\e`[~wcenew\e`[~$p`[~$rO`['
+0:move to start of change with `[
+>BUFFER: One New threeTwO
+>CURSOR: 15
+
+  zletest $'one\eyyPj`.~``cetwo\e0`.'
+0:return to position after last change
+>BUFFER: One
+>two
+>CURSOR: 6
+
+  zletest $'one two three\e0`]~bbcenew\e0`]~0P`]~0rO`]'
+0:move to end of change with `]
+>BUFFER: OwOone neW threE
+>CURSOR: 0
+
   zletest $'keepnot\eo  unwanted\ekhhcvj '
 0:force character-wise change to join lines
 >BUFFER: keep wanted



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