Эх сурвалжийг харах

同步至 https://github.com/mirror/busybox/commit/ac04eb3657f99f6952971d8ceb8a82d73b783de8

Meco Man 4 жил өмнө
parent
commit
4761b2258d
1 өөрчлөгдсөн 148 нэмэгдсэн , 76 устгасан
  1. 148 76
      vi.c

+ 148 - 76
vi.c

@@ -134,7 +134,6 @@ struct globals {
 #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash
 #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash
 #define ignorecase (vi_setops & VI_IGNORECASE)
 #define ignorecase (vi_setops & VI_IGNORECASE)
 #define showmatch  (vi_setops & VI_SHOWMATCH )
 #define showmatch  (vi_setops & VI_SHOWMATCH )
-#define openabove  (vi_setops & VI_TABSTOP   )
 // order of constants and strings must match
 // order of constants and strings must match
 #define OPTS_STR \
 #define OPTS_STR \
         "ai\0""autoindent\0" \
         "ai\0""autoindent\0" \
@@ -143,15 +142,10 @@ struct globals {
         "ic\0""ignorecase\0" \
         "ic\0""ignorecase\0" \
         "sm\0""showmatch\0" \
         "sm\0""showmatch\0" \
         "ts\0""tabstop\0"
         "ts\0""tabstop\0"
-#define set_openabove() (vi_setops |= VI_TABSTOP)
-#define clear_openabove() (vi_setops &= ~VI_TABSTOP)
 #else
 #else
 #define autoindent (0)
 #define autoindent (0)
 #define expandtab  (0)
 #define expandtab  (0)
 #define err_method (0)
 #define err_method (0)
-#define openabove  (0)
-#define set_openabove() ((void)0)
-#define clear_openabove() ((void)0)
 #endif
 #endif
 
 
 #if ENABLE_FEATURE_VI_READONLY
 #if ENABLE_FEATURE_VI_READONLY
@@ -207,6 +201,10 @@ struct globals {
 #if ENABLE_FEATURE_VI_SEARCH
 #if ENABLE_FEATURE_VI_SEARCH
     char *last_search_pattern; // last pattern from a '/' or '?' search
     char *last_search_pattern; // last pattern from a '/' or '?' search
 #endif
 #endif
+#if ENABLE_FEATURE_VI_SETOPTS
+    int indentcol;      // column of recently autoindent, 0 or -1
+#endif
+    smallint cmd_error;
 
 
     /* former statics */
     /* former statics */
 #if ENABLE_FEATURE_VI_YANKMARK
 #if ENABLE_FEATURE_VI_YANKMARK
@@ -331,6 +329,8 @@ struct globals {
 #define ioq_start               (G.ioq_start          )
 #define ioq_start               (G.ioq_start          )
 #define dotcnt                  (G.dotcnt             )
 #define dotcnt                  (G.dotcnt             )
 #define last_search_pattern     (G.last_search_pattern)
 #define last_search_pattern     (G.last_search_pattern)
+#define indentcol               (G.indentcol          )
+#define cmd_error               (G.cmd_error          )
 
 
 #define edit_file__cur_line     (G.edit_file__cur_line)
 #define edit_file__cur_line     (G.edit_file__cur_line)
 #define refresh__old_offset     (G.refresh__old_offset)
 #define refresh__old_offset     (G.refresh__old_offset)
@@ -367,6 +367,7 @@ struct globals {
     last_modified_count = -1; \
     last_modified_count = -1; \
     /* "" but has space for 2 chars: */ \
     /* "" but has space for 2 chars: */ \
     IF_FEATURE_VI_SEARCH(last_search_pattern = vi_zalloc(2);) \
     IF_FEATURE_VI_SEARCH(last_search_pattern = vi_zalloc(2);) \
+    tabstop = 8; \
 } while (0)
 } while (0)
 
 
 static void edit_file(char *);  // edit one file
 static void edit_file(char *);  // edit one file
@@ -547,7 +548,11 @@ static int vi_main(int argc, char **argv)
     }
     }
 #endif
 #endif
     optparse_init(&options, argv); // RT-Thread team added
     optparse_init(&options, argv); // RT-Thread team added
-    while ((c = optparse(&options, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) {
+    while ((c = optparse(&options,
+#if ENABLE_FEATURE_VI_CRASHME
+            "C"
+#endif
+            "RHh" IF_FEATURE_VI_COLON("c:"))) != -1) {
         switch (c) {
         switch (c) {
 #if ENABLE_FEATURE_VI_CRASHME
 #if ENABLE_FEATURE_VI_CRASHME
         case 'C':
         case 'C':
@@ -749,7 +754,6 @@ static void edit_file(char *fn)
 
 
     cmd_mode = 0;       // 0=command  1=insert  2='R'eplace
     cmd_mode = 0;       // 0=command  1=insert  2='R'eplace
     cmdcnt = 0;
     cmdcnt = 0;
-    tabstop = 4;
     offset = 0;         // no horizontal offset
     offset = 0;         // no horizontal offset
     c = '\0';
     c = '\0';
 #if ENABLE_FEATURE_VI_DOT_CMD
 #if ENABLE_FEATURE_VI_DOT_CMD
@@ -991,7 +995,6 @@ static void setops(char *args, int flg_no)
     index = 1 << (index >> 1); // convert to VI_bit
     index = 1 << (index >> 1); // convert to VI_bit
 
 
     if (index & VI_TABSTOP) {
     if (index & VI_TABSTOP) {
-        // don't set this bit in vi_setops, it's reused as 'openabove'
         int t;
         int t;
         if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
         if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
             goto bad;
             goto bad;
@@ -1367,12 +1370,10 @@ static void colon(char *buf)
             status_line_bold("No current filename");
             status_line_bold("No current filename");
             goto ret;
             goto ret;
         }
         }
-        if (e < 0) {    // no addr given- read after current line
-            q = begin_line(dot);
-        } else if (e == 0) {    // user said ":0r foo"
+        if (e == 0) {   // user said ":0r foo"
             q = text;
             q = text;
-        } else {    // addr given- read after that line
-            q = next_line(find_line(e));
+        } else {    // read after given line or current line if none given
+            q = next_line(e > 0 ? find_line(e) : dot);
             // read after last line
             // read after last line
             if (q == end-1)
             if (q == end-1)
                 ++q;
                 ++q;
@@ -1592,11 +1593,11 @@ static void colon(char *buf)
                     editing = 0;
                     editing = 0;
                 } else if (cmd[0] == 'x' || cmd[1] == 'q') {
                 } else if (cmd[0] == 'x' || cmd[1] == 'q') {
                     // are there other files to edit?
                     // are there other files to edit?
-                    int n = cmdline_filecnt - optind - 1;
+                    int n = cmdline_filecnt - options.optind - 1;
                     if (n > 0) {
                     if (n > 0) {
                         if (useforce) {
                         if (useforce) {
                             // force end of argv list
                             // force end of argv list
-                            optind = cmdline_filecnt;
+                            options.optind = cmdline_filecnt;
                         } else {
                         } else {
                             status_line_bold("%u more file(s) to edit", n);
                             status_line_bold("%u more file(s) to edit", n);
                             goto ret;
                             goto ret;
@@ -1653,7 +1654,7 @@ static int next_tabstop(int col)
 
 
 static int prev_tabstop(int col)
 static int prev_tabstop(int col)
 {
 {
-    return col - ((col % tabstop) ?: tabstop);
+    return col - ((col % tabstop) ? (col % tabstop) : tabstop);
 }
 }
 
 
 static int next_column(char c, int co)
 static int next_column(char c, int co)
@@ -2131,12 +2132,27 @@ static char *char_search(char *p, const char *pat, int dir_and_range)
 
 
 #endif /* FEATURE_VI_SEARCH */
 #endif /* FEATURE_VI_SEARCH */
 
 
+// find number of characters in indent, p must be at beginning of line
+static size_t indent_len(char *p)
+{
+    char *r = p;
+
+    while (r < (end - 1) && isblank(*r))
+        r++;
+    return r - p;
+}
+
+
+#if !ENABLE_FEATURE_VI_UNDO
+#define char_insert(a,b,c) char_insert(a,b)
+#endif
 static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
 static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
 {
 {
 #if ENABLE_FEATURE_VI_SETOPTS
 #if ENABLE_FEATURE_VI_SETOPTS
-    char *q;
     size_t len;
     size_t len;
+    int col, ntab, nspc;
 #endif
 #endif
+    char *bol = begin_line(p);
 
 
     if (c == 22) {      // Is this an ctrl-V?
     if (c == 22) {      // Is this an ctrl-V?
         p += stupid_insert(p, '^'); // use ^ to indicate literal next
         p += stupid_insert(p, '^'); // use ^ to indicate literal next
@@ -2158,25 +2174,36 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
         if ((p[-1] != '\n') && (dot > text)) {
         if ((p[-1] != '\n') && (dot > text)) {
             p--;
             p--;
         }
         }
-    } else if (c == 4) {    // ctrl-D reduces indentation
-        int prev;
-        char *r, *bol;
-        bol = begin_line(p);
-        for (r = bol; r < end_line(p); ++r) {
-            if (!isblank(*r))
-                break;
+#if ENABLE_FEATURE_VI_SETOPTS
+        if (autoindent) {
+            len = indent_len(bol);
+            if (len && get_column(bol + len) == indentcol && bol[len] == '\n') {
+                // remove autoindent from otherwise empty line
+                text_hole_delete(bol, bol + len - 1, undo);
+                p = bol;
+            }
         }
         }
-
-        prev = prev_tabstop(get_column(r));
+#endif
+    } else if (c == 4) {    // ctrl-D reduces indentation
+        char *r = bol + indent_len(bol);
+        int prev = prev_tabstop(get_column(r));
         while (r > bol && get_column(r) > prev) {
         while (r > bol && get_column(r) > prev) {
             if (p > bol)
             if (p > bol)
                 p--;
                 p--;
             r--;
             r--;
             r = text_hole_delete(r, r, ALLOW_UNDO_QUEUED);
             r = text_hole_delete(r, r, ALLOW_UNDO_QUEUED);
         }
         }
+
+#if ENABLE_FEATURE_VI_SETOPTS
+        if (autoindent && indentcol && r == end_line(p)) {
+            // record changed size of autoindent
+            indentcol = get_column(p);
+            return p;
+        }
+#endif
 #if ENABLE_FEATURE_VI_SETOPTS
 #if ENABLE_FEATURE_VI_SETOPTS
     } else if (c == '\t' && expandtab) {    // expand tab
     } else if (c == '\t' && expandtab) {    // expand tab
-        int col = get_column(p);
+        col = get_column(p);
         col = next_tabstop(col) - col + 1;
         col = next_tabstop(col) - col + 1;
         while (col--) {
         while (col--) {
 # if ENABLE_FEATURE_VI_UNDO
 # if ENABLE_FEATURE_VI_UNDO
@@ -2215,27 +2242,46 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
             showmatching(p - 1);
             showmatching(p - 1);
         }
         }
         if (autoindent && c == '\n') {  // auto indent the new line
         if (autoindent && c == '\n') {  // auto indent the new line
-            // use current/previous line as template
-            q = openabove ? p : prev_line(p);
-            len = strspn(q, " \t"); // space or tab
-            if (openabove) {
-                p--;        // this replaces dot_prev() in do_cmd()
-                q += len;   // template will be shifted by text_hole_make()
+            // use indent of current/previous line
+            bol = indentcol < 0 ? p : prev_line(p);
+            len = indent_len(bol);
+            col = get_column(bol + len);
+
+            if (len && col == indentcol) {
+                // previous line was empty except for autoindent
+                // move the indent to the current line
+                memmove(bol + 1, bol, len);
+                *bol = '\n';
+                return p;
             }
             }
+
+            if (indentcol < 0)
+                p--;    // open above, indent before newly inserted NL
+
             if (len) {
             if (len) {
-                uintptr_t bias;
-                bias = text_hole_make(p, len);
-                p += bias;
-                q += bias;
+                indentcol = col;
+                if (expandtab) {
+                    ntab = 0;
+                    nspc = col;
+                } else {
+                    ntab = col / tabstop;
+                    nspc = col % tabstop;
+                }
+                p += text_hole_make(p, ntab + nspc);
 #if ENABLE_FEATURE_VI_UNDO
 #if ENABLE_FEATURE_VI_UNDO
-                undo_push_insert(p, len, undo);
+                undo_push_insert(p, ntab + nspc, undo);
 #endif
 #endif
-                rt_memcpy(p, q, len);
-                p += len;
+                memset(p, '\t', ntab);
+                p += ntab;
+                memset(p, ' ', nspc);
+                return p + nspc;
             }
             }
         }
         }
 #endif
 #endif
     }
     }
+#if ENABLE_FEATURE_VI_SETOPTS
+    indentcol = 0;
+#endif
     return p;
     return p;
 }
 }
 
 
@@ -2280,14 +2326,19 @@ static int find_range(char **start, char **stop, int cmd)
 #endif
 #endif
         // these cmds operate on whole lines
         // these cmds operate on whole lines
         buftype = WHOLE;
         buftype = WHOLE;
-        if (--cmdcnt > 0)
+        if (--cmdcnt > 0) {
             do_cmd('j');
             do_cmd('j');
+            if (cmd_error)
+                buftype = -1;
+        }
     } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) {
     } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) {
         // Most operate on char positions within a line.  Of those that
         // Most operate on char positions within a line.  Of those that
         // don't '%' needs no special treatment, search commands are
         // don't '%' needs no special treatment, search commands are
         // marked as MULTI and  "{}" are handled below.
         // marked as MULTI and  "{}" are handled below.
         buftype = strchr("nN/?", c) ? MULTI : PARTIAL;
         buftype = strchr("nN/?", c) ? MULTI : PARTIAL;
         do_cmd(c);      // execute movement cmd
         do_cmd(c);      // execute movement cmd
+        if (cmd_error)
+            buftype = -1;
         if (p == dot)   // no movement is an error
         if (p == dot)   // no movement is an error
             buftype = -1;
             buftype = -1;
     } else if (strchr("wW", c)) {
     } else if (strchr("wW", c)) {
@@ -2829,7 +2880,7 @@ static void show_help(void)
 static void start_new_cmd_q(char c)
 static void start_new_cmd_q(char c)
 {
 {
     // get buffer for new cmd
     // get buffer for new cmd
-    dotcnt = cmdcnt ?: 1;
+    dotcnt = cmdcnt ? cmdcnt : 1;
     last_modifying_cmd[0] = c;
     last_modifying_cmd[0] = c;
     lmc_len = 1;
     lmc_len = 1;
     adding2q = 1;
     adding2q = 1;
@@ -3085,7 +3136,7 @@ static int get_motion_char(void)
             // get any non-zero motion count
             // get any non-zero motion count
             for (cnt = 0; isdigit(c); c = get_one_char())
             for (cnt = 0; isdigit(c); c = get_one_char())
                 cnt = cnt * 10 + (c - '0');
                 cnt = cnt * 10 + (c - '0');
-            cmdcnt = (cmdcnt ?: 1) * cnt;
+            cmdcnt = (cmdcnt ? cmdcnt : 1) * cnt;
         } else {
         } else {
             // ensure standalone '0' works
             // ensure standalone '0' works
             cmdcnt = 0;
             cmdcnt = 0;
@@ -3291,6 +3342,7 @@ static void indicate_error(void)
     if (crashme > 0)
     if (crashme > 0)
         return;
         return;
 #endif
 #endif
+    cmd_error = TRUE;
     if (!err_method) {
     if (!err_method) {
         write1(ESC_BELL);
         write1(ESC_BELL);
     } else {
     } else {
@@ -3697,6 +3749,7 @@ static void do_cmd(int c)
 //  p = q = save_dot = buf; // quiet the compiler
 //  p = q = save_dot = buf; // quiet the compiler
     rt_memset(buf, '\0', sizeof(buf));
     rt_memset(buf, '\0', sizeof(buf));
     keep_index = FALSE;
     keep_index = FALSE;
+    cmd_error = FALSE;
 
 
     show_status_line();
     show_status_line();
 
 
@@ -3817,24 +3870,30 @@ static void do_cmd(int c)
     case 10:            // Newline ^J
     case 10:            // Newline ^J
     case 'j':           // j- goto next line, same col
     case 'j':           // j- goto next line, same col
     case KEYCODE_DOWN:  // cursor key Down
     case KEYCODE_DOWN:  // cursor key Down
+    case 13:            // Carriage Return ^M
+    case '+':           // +- goto next line
+        q = dot;
         do {
         do {
-            dot_next();     // go to next B-o-l
+            p = next_line(q);
+            if (p == end_line(q)) {
+                indicate_error();
+                goto dc1;
+            }
+            q = p;
         } while (--cmdcnt > 0);
         } while (--cmdcnt > 0);
-        // try to stay in saved column
-        dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex);
-        keep_index = TRUE;
+        dot = q;
+        if (c == 13 || c == '+') {
+            dot_skip_over_ws();
+        } else {
+            // try to stay in saved column
+            dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex);
+            keep_index = TRUE;
+        }
         break;
         break;
     case 12:            // ctrl-L  force redraw whole screen
     case 12:            // ctrl-L  force redraw whole screen
     case 18:            // ctrl-R  force redraw
     case 18:            // ctrl-R  force redraw
         redraw(TRUE);   // this will redraw the entire display
         redraw(TRUE);   // this will redraw the entire display
         break;
         break;
-    case 13:            // Carriage Return ^M
-    case '+':           // +- goto next line
-        do {
-            dot_next();
-        } while (--cmdcnt > 0);
-        dot_skip_over_ws();
-        break;
     case 21:            // ctrl-U  scroll up half screen
     case 21:            // ctrl-U  scroll up half screen
         dot_scroll((rows - 2) / 2, -1);
         dot_scroll((rows - 2) / 2, -1);
         break;
         break;
@@ -3875,6 +3934,8 @@ static void do_cmd(int c)
                 dot = q;
                 dot = q;
                 dot_begin();    // go to B-o-l
                 dot_begin();    // go to B-o-l
                 dot_skip_over_ws();
                 dot_skip_over_ws();
+            } else {
+                indicate_error();
             }
             }
         } else if (c1 == '\'') {    // goto previous context
         } else if (c1 == '\'') {    // goto previous context
             dot = swap_context(dot);    // swap current and previous context
             dot = swap_context(dot);    // swap current and previous context
@@ -3908,7 +3969,7 @@ static void do_cmd(int c)
             break;
             break;
         }
         }
         cnt = 0;
         cnt = 0;
-        i = cmdcnt ?: 1;
+        i = cmdcnt ? cmdcnt : 1;
         // are we putting whole lines or strings
         // are we putting whole lines or strings
         if (regtype[YDreg] == WHOLE) {
         if (regtype[YDreg] == WHOLE) {
             if (c == 'P') {
             if (c == 'P') {
@@ -3937,6 +3998,7 @@ static void do_cmd(int c)
 # endif
 # endif
         } while (--cmdcnt > 0);
         } while (--cmdcnt > 0);
         dot += cnt;
         dot += cnt;
+        dot_skip_over_ws();
 # if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS
 # if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS
         yank_status("Put", p, i);
         yank_status("Put", p, i);
 # endif
 # endif
@@ -3999,12 +4061,6 @@ static void do_cmd(int c)
     case ',':           // ,- repeat latest search in opposite direction
     case ',':           // ,- repeat latest search in opposite direction
         dot_to_char(c != ',' ? last_search_cmd : last_search_cmd ^ 0x20);
         dot_to_char(c != ',' ? last_search_cmd : last_search_cmd ^ 0x20);
         break;
         break;
-    case '-':           // -- goto prev line
-        do {
-            dot_prev();
-        } while (--cmdcnt > 0);
-        dot_skip_over_ws();
-        break;
 #if ENABLE_FEATURE_VI_DOT_CMD
 #if ENABLE_FEATURE_VI_DOT_CMD
     case '.':           // .- repeat the last modifying command
     case '.':           // .- repeat the last modifying command
         // Stuff the last_modifying_cmd back into stdin
         // Stuff the last_modifying_cmd back into stdin
@@ -4021,7 +4077,6 @@ static void do_cmd(int c)
     case 'N':           // N- backward search for last pattern
     case 'N':           // N- backward search for last pattern
         dir = last_search_pattern[0] == '/' ? BACK : FORWARD;
         dir = last_search_pattern[0] == '/' ? BACK : FORWARD;
         goto dc4;       // now search for pattern
         goto dc4;       // now search for pattern
-        break;
     case '?':           // ?- backward search for a pattern
     case '?':           // ?- backward search for a pattern
     case '/':           // /- forward search for a pattern
     case '/':           // /- forward search for a pattern
         buf[0] = c;
         buf[0] = c;
@@ -4209,9 +4264,10 @@ static void do_cmd(int c)
         if (cmdcnt > (rows - 1)) {
         if (cmdcnt > (rows - 1)) {
             cmdcnt = (rows - 1);
             cmdcnt = (rows - 1);
         }
         }
-        if (--cmdcnt > 0) {
-            do_cmd('+');
+        while (--cmdcnt > 0) {
+            dot_next();
         }
         }
+        dot_begin();
         dot_skip_over_ws();
         dot_skip_over_ws();
         break;
         break;
     case 'I':           // I- insert before first non-blank
     case 'I':           // I- insert before first non-blank
@@ -4248,8 +4304,8 @@ static void do_cmd(int c)
         if (cmdcnt > (rows - 1)) {
         if (cmdcnt > (rows - 1)) {
             cmdcnt = (rows - 1);
             cmdcnt = (rows - 1);
         }
         }
-        if (--cmdcnt > 0) {
-            do_cmd('-');
+        while (--cmdcnt > 0) {
+            dot_prev();
         }
         }
         dot_begin();
         dot_begin();
         dot_skip_over_ws();
         dot_skip_over_ws();
@@ -4262,17 +4318,18 @@ static void do_cmd(int c)
         break;
         break;
     case 'O':           // O- open an empty line above
     case 'O':           // O- open an empty line above
         dot_begin();
         dot_begin();
-        set_openabove();
+#if ENABLE_FEATURE_VI_SETOPTS
+        indentcol = -1;
+#endif
         goto dc3;
         goto dc3;
     case 'o':           // o- open an empty line below
     case 'o':           // o- open an empty line below
         dot_end();
         dot_end();
  dc3:
  dc3:
         dot = char_insert(dot, '\n', ALLOW_UNDO);
         dot = char_insert(dot, '\n', ALLOW_UNDO);
         if (c == 'O' && !autoindent) {
         if (c == 'O' && !autoindent) {
-            // done in char_insert() for openabove+autoindent
+            // done in char_insert() for 'O'+autoindent
             dot_prev();
             dot_prev();
         }
         }
-        clear_openabove();
         goto dc_i;
         goto dc_i;
     case 'R':           // R- continuous Replace char
     case 'R':           // R- continuous Replace char
  dc5:
  dc5:
@@ -4326,7 +4383,7 @@ static void do_cmd(int c)
             editing = 0;
             editing = 0;
         }
         }
         // are there other files to edit?
         // are there other files to edit?
-        j = cmdline_filecnt - optind - 1;
+        j = cmdline_filecnt - options.optind - 1;
         if (editing == 0 && j > 0) {
         if (editing == 0 && j > 0) {
             editing = 1;
             editing = 1;
             modified_count = 0;
             modified_count = 0;
@@ -4390,6 +4447,9 @@ static void do_cmd(int c)
                 if (dot != (end-1)) {
                 if (dot != (end-1)) {
                     dot_prev();
                     dot_prev();
                 }
                 }
+            } else if (c == 'd') {
+                dot_begin();
+                dot_skip_over_ws();
             } else {
             } else {
                 dot = save_dot;
                 dot = save_dot;
             }
             }
@@ -4409,17 +4469,29 @@ static void do_cmd(int c)
     }
     }
     case 'k':           // k- goto prev line, same col
     case 'k':           // k- goto prev line, same col
     case KEYCODE_UP:        // cursor key Up
     case KEYCODE_UP:        // cursor key Up
+    case '-':           // -- goto prev line
+        q = dot;
         do {
         do {
-            dot_prev();
+            p = prev_line(q);
+            if (p == begin_line(q)) {
+                indicate_error();
+                goto dc1;
+            }
+            q = p;
         } while (--cmdcnt > 0);
         } while (--cmdcnt > 0);
-        // try to stay in saved column
-        dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex);
-        keep_index = TRUE;
+        dot = q;
+        if (c == '-') {
+            dot_skip_over_ws();
+        } else {
+            // try to stay in saved column
+            dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex);
+            keep_index = TRUE;
+        }
         break;
         break;
     case 'r':           // r- replace the current char with user input
     case 'r':           // r- replace the current char with user input
         c1 = get_one_char();    // get the replacement char
         c1 = get_one_char();    // get the replacement char
         if (c1 != 27) {
         if (c1 != 27) {
-            if (end_line(dot) - dot < (cmdcnt ?: 1)) {
+            if (end_line(dot) - dot < (cmdcnt ? cmdcnt : 1)) {
                 indicate_error();
                 indicate_error();
                 goto dc6;
                 goto dc6;
             }
             }