This implements the vim option expandtab in BusyBox vi.  From
vim help:

  In Insert mode: Use the appropriate number of spaces to insert a
  <Tab>.  Spaces are used in indents with the '>' and '<' commands and
  when 'autoindent' is on.  To insert a real tab when 'expandtab' is
  on, use CTRL-V<Tab>.

This implementation doesn't change how BusyBox vi handles autoindent:
it continues to copy the indentation from a neighbouring line.  If
that line has tabs in its indentation so too will the new line.

function                                             old     new   delta
char_insert                                          563     679    +116
next_column                                            -      48     +48
.rodata                                           105211  105236     +25
colon                                               3844    3855     +11
refresh                                             1000     982     -18
move_to_col                                           83      59     -24
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/2 up/down: 200/-42)           Total: 158 bytes
---
 editors/vi.c | 64 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 47 insertions(+), 17 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 6dd951421..4967ff5ec 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -289,11 +289,13 @@ struct globals {
 #if ENABLE_FEATURE_VI_SETOPTS
        smallint vi_setops;     // set by setops()
 #define VI_AUTOINDENT (1 << 0)
-#define VI_ERR_METHOD (1 << 1)
-#define VI_IGNORECASE (1 << 2)
-#define VI_SHOWMATCH  (1 << 3)
-#define VI_TABSTOP    (1 << 4)
+#define VI_EXPANDTAB  (1 << 1)
+#define VI_ERR_METHOD (1 << 2)
+#define VI_IGNORECASE (1 << 3)
+#define VI_SHOWMATCH  (1 << 4)
+#define VI_TABSTOP    (1 << 5)
 #define autoindent (vi_setops & VI_AUTOINDENT)
+#define expandtab  (vi_setops & VI_EXPANDTAB )
 #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or 
flash
 #define ignorecase (vi_setops & VI_IGNORECASE)
 #define showmatch  (vi_setops & VI_SHOWMATCH )
@@ -301,6 +303,7 @@ struct globals {
 // order of constants and strings must match
 #define OPTS_STR \
                "ai\0""autoindent\0" \
+               "et\0""expandtab\0" \
                "fl\0""flash\0" \
                "ic\0""ignorecase\0" \
                "sm\0""showmatch\0" \
@@ -309,6 +312,7 @@ struct globals {
 #define clear_openabove() (vi_setops &= ~VI_TABSTOP)
 #else
 #define autoindent (0)
+#define expandtab  (0)
 #define err_method (0)
 #define openabove  (0)
 #define set_openabove() ((void)0)
@@ -758,6 +762,27 @@ static int next_tabstop(int col)
        return col + ((tabstop - 1) - (col % tabstop));
 }
 
+static int next_column(char c, int co)
+{
+       if (c == '\t')
+               co = next_tabstop(co);
+       else if ((unsigned char)c < ' ' || c == 0x7f)
+               co++; // display as ^X, use 2 columns
+       return co + 1;
+}
+
+#if ENABLE_FEATURE_VI_SETOPTS
+static int get_column(char *p)
+{
+       const char *r;
+       int co = 0;
+
+       for (r = begin_line(p); r < p; r++)
+               co = next_column(*r, co);
+       return co;
+}
+#endif
+
 //----- Erase the Screen[] memory ------------------------------
 static void screen_erase(void)
 {
@@ -837,11 +862,7 @@ static void sync_cursor(char *d, int *row, int *col)
        do { // drive "co" to correct column
                if (*tp == '\n') //vda || *tp == '\0')
                        break;
-               if (*tp == '\t') {
-                       co = next_tabstop(co);
-               } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) {
-                       co++; // display as ^X, use 2 columns
-               }
+               co = next_column(*tp, co) - 1;
                // inserting text before a tab, don't include its position
                if (cmd_mode && tp == d - 1 && *d == '\t') {
                        co++;
@@ -1806,12 +1827,8 @@ static char *move_to_col(char *p, int l)
        do {
                if (*p == '\n') //vda || *p == '\0')
                        break;
-               if (*p == '\t') {
-                       co = next_tabstop(co);
-               } else if (*p < ' ' || *p == 127) {
-                       co++; // display as ^X, use 2 columns
-               }
-       } while (++co <= l && p++ < end);
+               co = next_column(*p, co);
+       } while (co <= l && p++ < end);
        return p;
 }
 
@@ -2103,6 +2120,17 @@ static char *char_insert(char *p, char c, int undo) // 
insert the char c at 'p'
                        p--;
                        p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED);
                }
+       } else if (c == '\t' && expandtab) {    // expand tab
+               int col = get_column(p);
+               col = next_tabstop(col) - col + 1;
+               while (col--) {
+#if ENABLE_FEATURE_VI_UNDO
+                       undo_push_insert(p, 1, undo);
+#else
+                       modified_count++;
+#endif
+                       p += 1 + stupid_insert(p, ' ');
+               }
 #endif
        } else if (c == term_orig.c_cc[VERASE] || c == 8 || c == 127) { // Is 
this a BS
                if (p > text) {
@@ -2870,11 +2898,13 @@ static void colon(char *buf)
 #  if ENABLE_FEATURE_VI_SETOPTS
                        status_line_bold(
                                "%sautoindent "
+                               "%sexpandtab "
                                "%sflash "
                                "%signorecase "
                                "%sshowmatch "
                                "tabstop=%u",
                                autoindent ? "" : "no",
+                               expandtab ? "" : "no",
                                err_method ? "" : "no",
                                ignorecase ? "" : "no",
                                showmatch ? "" : "no",
@@ -3752,7 +3782,7 @@ static void do_cmd(int c)
                i = count_lines(p, q);  // # of lines we are shifting
                for ( ; i > 0; i--, p = next_line(p)) {
                        if (c == '<') {
-                               // shift left- remove tab or 8 spaces
+                               // shift left- remove tab or tabstop spaces
                                if (*p == '\t') {
                                        // shrink buffer 1 char
                                        text_hole_delete(p, p, allow_undo);
@@ -3766,7 +3796,7 @@ static void do_cmd(int c)
                                        }
                                }
                        } else /* if (c == '>') */ {
-                               // shift right -- add tab or 8 spaces
+                               // shift right -- add tab or tabstop spaces
                                char_insert(p, '\t', allow_undo);
                        }
 #if ENABLE_FEATURE_VI_UNDO
-- 
2.30.2

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to