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

PATCH: visual line mode



This adds a linewise visual mode.

This uses a value of 2 for region_active which is exposed to the shell
function widgets via REGION_ACTIVE.

A visual-line-mode widget is added. We might need another one to just
set region_active to 0 which would be bound to escape in the visual
keymap.

There are also a few widgets: vichangeeol, viindent and viunindent that
should work linewise even for a character-wise selection.

There's an existing old bug with blank lines: dd on a blank line doesn't
work. It works in 3.0.8 but not in 4.2.1.

Oliver

diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index f5ff0a4..1dc0c9a 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -179,7 +179,8 @@
 "vi-yank", viyank, ZLE_LASTCOL
 "vi-yank-eol", viyankeol, 0
 "vi-yank-whole-line", viyankwholeline, 0
-"visual-mode", visualmode, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
+"visual-line-mode", visuallinemode, ZLE_MENUCMP | ZLE_LASTCOL
+"visual-mode", visualmode, ZLE_MENUCMP | ZLE_LASTCOL
 "what-cursor-position", whatcursorposition, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
 "where-is", whereis, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
 "which-command", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index d1bd5a1..5ee9f5a 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -440,12 +440,44 @@ killline(char **args)
 }
 
 /**/
+void
+regionlines(int *start, int *end)
+{
+    int origcs = zlecs;
+
+    UNMETACHECK();
+    if (zlecs < mark) {
+	*start = findbol();
+        zlecs = (mark > zlell) ? zlell : mark;
+	*end = findeol();
+    } else {
+	*end = findeol();
+        zlecs = mark;
+	*start = findbol();
+    }
+    zlecs = origcs;
+}
+
+/**/
 int
 killregion(UNUSED(char **args))
 {
     if (mark > zlell)
 	mark = zlell;
-    if (mark > zlecs)
+    if (region_active == 2) {
+	int a, b;
+	regionlines(&a, &b);
+	zlecs = a;
+	region_active = 0;
+	cut(zlecs, b - zlecs, CUT_RAW);
+	shiftchars(zlecs, b - zlecs);
+	if (zlell) {
+	    if (zlecs == zlell)
+		DECCS();
+	    foredel(1, 0);
+	    vifirstnonblank(zlenoargs);
+	}
+    } else if (mark > zlecs)
 	forekill(mark - zlecs + invicmdmode(), CUT_RAW);
     else {
 	if (invicmdmode())
@@ -958,15 +990,22 @@ quoteregion(UNUSED(char **args))
 {
     ZLE_STRING_T str;
     size_t len;
+    int extra = invicmdmode();
 
     if (mark > zlell)
 	mark = zlell;
-    if (mark < zlecs) {
+    if (region_active == 2) {
+	int a, b;
+	regionlines(&a, &b);
+	zlecs = a;
+	mark = b;
+	extra = 0;
+    } else if (mark < zlecs) {
 	int tmp = mark;
 	mark = zlecs;
 	zlecs = tmp;
     }
-    str = (ZLE_STRING_T)hcalloc((len = mark - zlecs + invicmdmode()) *
+    str = (ZLE_STRING_T)hcalloc((len = mark - zlecs + extra) *
 	ZLE_CHAR_SIZE);
     ZS_memcpy(str, zleline + zlecs, len);
     foredel(len, CUT_RAW);
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index 7b6420c..fad6b0a 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -527,6 +527,25 @@ visualmode(UNUSED(char **args))
 
 /**/
 int
+visuallinemode(UNUSED(char **args))
+{
+    switch (region_active) {
+    case 2:
+	region_active = 0;
+	break;
+    case 0:
+	mark = zlecs;
+	/* fall through */
+    case 1:
+	region_active = 2;
+	break;
+    }
+    return 0;
+}
+
+
+/**/
+int
 vigotocolumn(UNUSED(char **args))
 {
     int x, y, n = zmult;
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index ebc6b49..f0351ad 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -1039,6 +1039,14 @@ zrefresh(void)
 	}
 	if (invicmdmode())
 	    INCPOS(region_highlights[0].end);
+	if (region_active == 2) {
+	    int origcs = zlecs;
+	    zlecs = region_highlights[0].end;
+	    region_highlights[0].end = findeol();
+	    zlecs = region_highlights[0].start;
+	    region_highlights[0].start = findbol();
+	    zlecs = origcs;
+	}
     } else {
 	region_highlights[0].start = region_highlights[0].end = -1;
     }
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index ba13de3..a07ed61 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -162,12 +162,14 @@ static int
 getvirange(int wf)
 {
     int pos = zlecs, mpos = mark, ret = 0;
-    int visual = region_active; /* don't trust movement cmd not to change it */
+    int visual = region_active; /* movement command might set it */
     int mult1 = zmult, hist1 = histline;
     Thingy k2;
 
     if (visual) {
 	pos = mark;
+	vilinerange = (visual == 2);
+	region_active = 0;
     } else {
 
     virangeflag = 1;
@@ -262,10 +264,8 @@ getvirange(int wf)
 	pos = tmp;
     }
 
-    if (visual && invicmdmode()) {
-	region_active = 0;
+    if (visual && invicmdmode())
 	INCPOS(pos);
-    }
 
     /* Was it a line-oriented move?  If so, the command will have set *
      * the vilinerange flag.  In this case, entire lines are taken,   *
@@ -469,7 +469,15 @@ visubstitute(UNUSED(char **args))
 int
 vichangeeol(UNUSED(char **args))
 {
-    forekill(findeol() - zlecs, CUT_RAW);
+    int a, b;
+    if (region_active) {
+	regionlines(&a, &b);
+	zlecs = a;
+	region_active = 0;
+	cut(zlecs, b - zlecs, CUT_RAW);
+	shiftchars(zlecs, b - zlecs);
+    } else
+	forekill(findeol() - zlecs, CUT_RAW);
     startvitext(1);
     return 0;
 }
@@ -727,8 +735,11 @@ viindent(UNUSED(char **args))
 {
     int oldcs = zlecs, c2;
 
-    /* get the range */
     startvichange(1);
+    /* force line range */
+    if (region_active == 1)
+	region_active = 2;
+    /* get the range */
     if ((c2 = getvirange(0)) == -1) {
 	vichgflag = 0;
 	return 1;
@@ -758,8 +769,11 @@ viunindent(UNUSED(char **args))
 {
     int oldcs = zlecs, c2;
 
-    /* get the range */
     startvichange(1);
+    /* force line range */
+    if (region_active == 1)
+	region_active = 2;
+    /* get the range */
     if ((c2 = getvirange(0)) == -1) {
 	vichgflag = 0;
 	return 1;



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