I've been using toybox vi as a makeshift "less" lately. This patch
contains all the fixes I've made...

$ should go to the last character before the newline, not the newline.

Fix ^b and ^f, and ^e and ^y (which was mistakenly ^u before, which is
also a movement key, but half of ^d/^u, neither of which we actually
implement, and neither of which I've ever used myself --- I might have
large hands, but they're not _that_ large).

Fix the display of lines longer than 1024 characters.

Fix the display of the "~"s after the end of the file, and use VT100 dim
to make it a bit more obvious that they're not actually part of the
file. Also be a bit more consistent about \033 which is the most common
way to write \x1b in toybox.

Don't show the status while in ex mode.

Make what the status is showing a little less unclear by adding a "C"
for the byte offset and file size, and add a percentage (albeit one
based on bytes rather than lines).

Fix the flickering seen on updates with the usual stupid trick of
setting a large buffer.

Handle SIGWINCH.

Add support for Home/End/PageUp/PageDown.

Remove a bit of duplication around calls to draw_page().
---
 toys/pending/vi.c | 147 +++++++++++++++++++++++++++++-----------------
 1 file changed, 92 insertions(+), 55 deletions(-)
From 1aad5797a385982f3d246588e7c37321901cba5d Mon Sep 17 00:00:00 2001
From: Elliott Hughes <[email protected]>
Date: Tue, 16 Mar 2021 22:26:52 -0700
Subject: [PATCH] vi: various fixes.

I've been using toybox vi as a makeshift "less" lately. This patch
contains all the fixes I've made...

$ should go to the last character before the newline, not the newline.

Fix ^b and ^f, and ^e and ^y (which was mistakenly ^u before, which is
also a movement key, but half of ^d/^u, neither of which we actually
implement, and neither of which I've ever used myself --- I might have
large hands, but they're not _that_ large).

Fix the display of lines longer than 1024 characters.

Fix the display of the "~"s after the end of the file, and use VT100 dim
to make it a bit more obvious that they're not actually part of the
file. Also be a bit more consistent about \033 which is the most common
way to write \x1b in toybox.

Don't show the status while in ex mode.

Make what the status is showing a little less unclear by adding a "C"
for the byte offset and file size, and add a percentage (albeit one
based on bytes rather than lines).

Fix the flickering seen on updates with the usual stupid trick of
setting a large buffer.

Handle SIGWINCH.

Add support for Home/End/PageUp/PageDown.

Remove a bit of duplication around calls to draw_page().
---
 toys/pending/vi.c | 147 +++++++++++++++++++++++++++++-----------------
 1 file changed, 92 insertions(+), 55 deletions(-)

diff --git a/toys/pending/vi.c b/toys/pending/vi.c
index 18ce8e6a..da43d5d5 100644
--- a/toys/pending/vi.c
+++ b/toys/pending/vi.c
@@ -949,13 +949,57 @@ static int vi_zero(int count0, int count1, char *unused)
   return 1;
 }
 
-static int vi_eol(int count0, int count1, char *unused)
+static int vi_dollar(int count0, int count1, char *unused)
+{
+  size_t new = text_strchr(TT.cursor, '\n');
+
+  if (new != TT.cursor) {
+    TT.cursor = new - 1;
+    TT.vi_mov_flag |= 2;
+    check_cursor_bounds();
+  }
+  return 1;
+}
+
+static void vi_eol()
 {
-  //forward find /n
   TT.cursor = text_strchr(TT.cursor, '\n');
-  TT.vi_mov_flag |= 2;
   check_cursor_bounds();
-  return 1;
+}
+
+static void ctrl_b()
+{
+  int i;
+
+  for (i=0; i<TT.screen_height-2; ++i) {
+    TT.screen = text_psol(TT.screen);
+    // TODO: retain x offset.
+    TT.cursor = text_psol(TT.screen);
+  }
+}
+
+static void ctrl_f()
+{
+  int i;
+
+  for (i=0; i<TT.screen_height-2; ++i) TT.screen = text_nsol(TT.screen);
+  // TODO: real vi keeps the x position.
+  if (TT.screen > TT.cursor) TT.cursor = TT.screen;
+}
+
+static void ctrl_e()
+{
+  TT.screen = text_nsol(TT.screen);
+  // TODO: real vi keeps the x position.
+  if (TT.screen > TT.cursor) TT.cursor = TT.screen;
+}
+
+static void ctrl_y()
+{
+  TT.screen = text_psol(TT.screen);
+  // TODO: only if we're on the bottom line
+  TT.cursor = text_psol(TT.cursor);
+  // TODO: real vi keeps the x position.
 }
 
 //TODO check register where to push from
@@ -1040,7 +1084,7 @@ static int vi_D(char reg, int count0, int count1)
 {
   size_t pos = TT.cursor;
   if (!count0) return 1;
-  vi_eol(1, 1, 0);
+  vi_eol();
   vi_delete(reg, pos, 0);
   if (--count0) vi_dd(reg, count0, 1);
 
@@ -1133,7 +1177,7 @@ struct vi_mov_param vi_movs[] =
   {"l", 0, &cur_right},
   {"M", 0, &vi_M},
   {"w", 0, &vi_movw},
-  {"$", 0, &vi_eol},
+  {"$", 0, &vi_dollar},
   {"f", 1, &vi_find_c},
   {"F", 1, &vi_find_cb},
 };
@@ -1346,14 +1390,14 @@ static void draw_page()
   tty_jump(0, y);
   tty_esc("2K");
   //find cursor position
-  aw = crunch_nstr(&end, 1024, bytes, 0, "\t\n", vi_crunch);
+  aw = crunch_nstr(&end, INT_MAX, bytes, 0, "\t\n", vi_crunch);
 
   //if we need to render text that is not inserted to buffer yet
   if (TT.vi_mode == 2 && TT.il->len) {
     char* iend = TT.il->data; //input end
     x = 0;
     //find insert end position
-    iw = crunch_str(&iend, 1024, 0, "\t\n", vi_crunch);
+    iw = crunch_str(&iend, INT_MAX, 0, "\t\n", vi_crunch);
     clip = (aw+iw) - TT.screen_width+margin;
 
     //if clipped area is bigger than text before insert
@@ -1411,17 +1455,12 @@ static void draw_page()
 
     tty_jump(0, y);
     if (draw_line) {
-
       tty_esc("2K");
-      if (line) {
-        if (draw_line && line && strlen(line)) {
-
-          aw = crunch_nstr(&line, clip, bytes, 0, "\t\n", vi_crunch);
-          crunch_str(&line, TT.screen_width-1, stdout, "\t\n", vi_crunch);
-          if ( *line ) printf("@");
-
-        }
-      } else if (draw_line) printf("~");
+      if (line && strlen(line)) {
+        aw = crunch_nstr(&line, clip, bytes, 0, "\t\n", vi_crunch);
+        crunch_str(&line, TT.screen_width-1, stdout, "\t\n", vi_crunch);
+        if ( *line ) printf("@");
+      } else printf("\033[2m~\033[m");
     }
     if (SSOL+bytes < TT.filesize)  {
       line = toybuf;
@@ -1432,20 +1471,21 @@ static void draw_page()
 
   TT.drawn_row = TT.scr_row, TT.drawn_col = clip;
 
-  //finished updating visual area
+  // Finished updating visual area, show status line.
   tty_jump(0, TT.screen_height);
   tty_esc("2K");
-  if (TT.vi_mode == 2) printf("\x1b[1m-- INSERT --\x1b[m");
+  if (TT.vi_mode == 2) printf("\033[1m-- INSERT --\033[m");
   if (!TT.vi_mode) {
-    cx_scr = printf("%s",TT.il->data);
+    cx_scr = printf("%s", TT.il->data);
     cy_scr = TT.screen_height;
+    *toybuf = 0;
+  } else {
+    // TODO: the row,col display doesn't show the cursor column
+    // TODO: real vi shows the percentage by lines, not bytes
+    sprintf(toybuf, "%zu/%zuC  %zu%%  %d,%d", TT.cursor, TT.filesize,
+      (100*TT.cursor)/TT.filesize, TT.cur_row+1, TT.cur_col+1);
+    if (TT.cur_col != cx_scr) sprintf(toybuf+strlen(toybuf),"-%d", cx_scr+1);
   }
-
-  sprintf(toybuf, "%zu / %zu,%d,%d", TT.cursor, TT.filesize,
-    TT.cur_row+1, TT.cur_col+1);
-
-  if (TT.cur_col != cx_scr) sprintf(toybuf+strlen(toybuf),"-%d", cx_scr+1);
-
   tty_jump(TT.screen_width-strlen(toybuf), TT.screen_height);
   printf("%s", toybuf);
 
@@ -1455,12 +1495,12 @@ static void draw_page()
 
 void vi_main(void)
 {
+  char stdout_buf[BUFSIZ];
   char keybuf[16] = {0};
   char vi_buf[16] = {0};
   char utf8_code[8] = {0};
-  int utf8_dec_p = 0, vi_buf_pos = 0, i;
-  FILE *script = 0;
-  if (FLAG(s)) script = fopen(TT.s, "r");
+  int utf8_dec_p = 0, vi_buf_pos = 0;
+  FILE *script = FLAG(s) ? xfopen(TT.s, "r") : 0;
 
   TT.il = xzalloc(sizeof(struct str_line));
   TT.il->data = xzalloc(80);
@@ -1478,17 +1518,19 @@ void vi_main(void)
   terminal_size(&TT.screen_width, &TT.screen_height);
   TT.screen_height -= 1;
 
+  // Avoid flicker.
+  setbuf(stdout, stdout_buf);
+
+  xsignal(SIGWINCH, generic_signal);
   set_terminal(0, 1, 0, 0);
   //writes stdout into different xterm buffer so when we exit
   //we dont get scroll log full of junk
   tty_esc("?1049h");
-  tty_esc("H");
-  xflush(1);
-
 
-  draw_page();
   for (;;) {
     int key = 0;
+
+    draw_page();
     if (script) {
       key = fgetc(script);
       if (key == EOF) {
@@ -1499,9 +1541,12 @@ void vi_main(void)
     } else key = scan_key(keybuf, -1);
 
     if (key == -1) goto cleanup_vi;
-
-    terminal_size(&TT.screen_width, &TT.screen_height);
-    TT.screen_height -= 1; //TODO this is hack fix visual alignment
+    else if (key == -3) {
+      toys.signal = 0;
+      terminal_size(&TT.screen_width, &TT.screen_height);
+      TT.screen_height -= 1; //TODO this is hack fix visual alignment
+      continue;
+    }
 
     // TODO: support cursor keys in ex mode too.
     if (TT.vi_mode && key>=256) {
@@ -1510,7 +1555,10 @@ void vi_main(void)
       else if (key==KEY_DOWN) cur_down(1, 1, 0);
       else if (key==KEY_LEFT) cur_left(1, 1, 0);
       else if (key==KEY_RIGHT) cur_right(1, 1, 0);
-      draw_page();
+      else if (key==KEY_HOME) vi_zero(1, 1, 0);
+      else if (key==KEY_END) vi_dollar(1, 1, 0);
+      else if (key==KEY_PGDN) ctrl_f();
+      else if (key==KEY_PGUP) ctrl_b();
       continue;
     }
 
@@ -1524,7 +1572,7 @@ void vi_main(void)
           TT.il->len++;
           break;
         case 'A':
-          vi_eol(1, 1, 0);
+          vi_eol();
           TT.vi_mode = 2;
           break;
         case 'a':
@@ -1534,23 +1582,16 @@ void vi_main(void)
           TT.vi_mode = 2;
           break;
         case 'B'-'@':
-          for (i=0; i<TT.screen_height-2; ++i) TT.screen = text_psol(TT.screen);
-          // TODO: if we're on the bottom visible line, move the cursor up.
-          if (TT.screen > TT.cursor) TT.cursor = TT.screen;
+          ctrl_b();
           break;
         case 'E'-'@':
-          TT.screen = text_nsol(TT.screen);
-          // TODO: real vi keeps the x position.
-          if (TT.screen > TT.cursor) TT.cursor = TT.screen;
+          ctrl_e();
           break;
         case 'F'-'@':
-          for (i=0; i<TT.screen_height-2; ++i) TT.screen = text_nsol(TT.screen);
-          // TODO: real vi keeps the x position.
-          if (TT.screen > TT.cursor) TT.cursor = TT.screen;
+          ctrl_f();
           break;
-        case 'U'-'@':
-          TT.screen = text_psol(TT.screen);
-          // TODO: if we're on the bottom visible line, move the cursor up.
+        case 'Y'-'@':
+          ctrl_y();
           break;
         case 27:
           vi_buf[0] = 0;
@@ -1650,9 +1691,6 @@ void vi_main(void)
           break;
       }
     }
-
-    draw_page();
-
   }
 cleanup_vi:
   linelist_unload();
@@ -1660,4 +1698,3 @@ cleanup_vi:
   tty_reset();
   tty_esc("?1049l");
 }
-
-- 
2.31.0.rc2.261.g7f71774620-goog

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to