On Thu, 02 Apr 2020 16:21:47 -0600, "Todd C. Miller" wrote:

> In vim, the expandtab option expands tabs to spaces in insert mode
> as well as when shifting and indenting/outdenting.  This is very
> useful when working on a code-base where the style dictates using
> spaces instead of tabs for indentation.
>
> NetBSD added an implementation of expandtab to their vi some time
> ago, but theirs doesn't convert tabs to spaces in insert mode.  I've
> adapted the NetBSD patch and added support for expanding tabs in
> insert mode, unless escaped via ^V.
>
> The option is off by default (of course).
>
> Comments?  Please, no tabs vs spaces flame wars.

Ping?  It would be nice for this to make 6.7.

 - todd

Index: usr.bin/vi/common/options.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/common/options.c,v
retrieving revision 1.27
diff -u -p -u -r1.27 options.c
--- usr.bin/vi/common/options.c 21 May 2019 09:24:58 -0000      1.27
+++ usr.bin/vi/common/options.c 2 Apr 2020 20:43:14 -0000
@@ -69,6 +69,8 @@ OPTLIST const optlist[] = {
        {"escapetime",  NULL,           OPT_NUM,        0},
 /* O_ERRORBELLS            4BSD */
        {"errorbells",  NULL,           OPT_0BOOL,      0},
+/* O_EXPANDTAB     NetBSD 5.0 */
+       {"expandtab",   NULL,           OPT_0BOOL,      0},
 /* O_EXRC      System V (undocumented) */
        {"exrc",        NULL,           OPT_0BOOL,      0},
 /* O_EXTENDED    4.4BSD */
@@ -207,6 +209,7 @@ static OABBREV const abbrev[] = {
        {"co",          O_COLUMNS},             /*   4.4BSD */
        {"eb",          O_ERRORBELLS},          /*     4BSD */
        {"ed",          O_EDCOMPATIBLE},        /*     4BSD */
+       {"et",          O_EXPANDTAB},           /* NetBSD 5.0 */
        {"ex",          O_EXRC},                /* System V (undocumented) */
        {"ht",          O_HARDTABS},            /*     4BSD */
        {"ic",          O_IGNORECASE},          /*     4BSD */
Index: usr.bin/vi/docs/USD.doc/vi.man/vi.1
===================================================================
RCS file: /cvs/src/usr.bin/vi/docs/USD.doc/vi.man/vi.1,v
retrieving revision 1.77
diff -u -p -u -r1.77 vi.1
--- usr.bin/vi/docs/USD.doc/vi.man/vi.1 4 Oct 2019 20:12:01 -0000       1.77
+++ usr.bin/vi/docs/USD.doc/vi.man/vi.1 2 Apr 2020 22:05:31 -0000
@@ -1606,6 +1606,11 @@ and
 characters to move forward to the next
 .Ar shiftwidth
 column boundary.
+If the
+.Cm expandtab
+option is set, only insert
+.Aq space
+characters.
 .Pp
 .It Aq Cm erase
 .It Aq Cm control-H
@@ -2343,6 +2348,16 @@ key mapping.
 .Nm ex
 only.
 Announce error messages with a bell.
+.It Cm expandtab , et Bq off
+Expand
+.Aq tab
+characters to
+.Aq space
+when inserting, replacing or shifting text, autoindenting,
+indenting with
+.Aq Ic control-T ,
+or outdenting with
+.Aq Ic control-D .
 .It Cm exrc , ex Bq off
 Read the startup files in the local directory.
 .It Cm extended Bq off
Index: usr.bin/vi/docs/USD.doc/vi.ref/set.opt.roff
===================================================================
RCS file: /cvs/src/usr.bin/vi/docs/USD.doc/vi.ref/set.opt.roff,v
retrieving revision 1.12
diff -u -p -u -r1.12 set.opt.roff
--- usr.bin/vi/docs/USD.doc/vi.ref/set.opt.roff 8 Aug 2016 15:09:33 -0000       
1.12
+++ usr.bin/vi/docs/USD.doc/vi.ref/set.opt.roff 2 Apr 2020 22:05:27 -0000
@@ -96,7 +96,9 @@ the first nonblank character of the line
 Lines are indented using tab characters to the extent possible (based on
 the value of the
 .OP tabstop
-option) and then using space characters as necessary.
+option, and if
+.OP expandtab
+is not set) and then using space characters as necessary.
 For commands inserting text into the middle of a line, any blank characters
 to the right of the cursor are discarded, and the first nonblank character
 to the right of the cursor is aligned as described above.
@@ -400,6 +402,17 @@ only.
 error messages are normally presented in inverse video.
 If that is not possible for the terminal, setting this option causes
 error messages to be announced by ringing the terminal bell.
+.KY expandtab
+.IP "expandtab, et [off]"
+Expand
+.LI <tab>
+characters to
+.LI <space>
+when inserting, replacing or shifting text, autoindenting,
+indenting with
+.CO <control-T>,
+or outdenting with
+.CO <control-D>.
 .KY exrc
 .IP "exrc, ex [off]"
 If this option is turned on in the EXINIT environment variables,
Index: usr.bin/vi/ex/ex_shift.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/ex/ex_shift.c,v
retrieving revision 1.8
diff -u -p -u -r1.8 ex_shift.c
--- usr.bin/vi/ex/ex_shift.c    6 Jan 2016 22:28:52 -0000       1.8
+++ usr.bin/vi/ex/ex_shift.c    2 Apr 2020 20:53:16 -0000
@@ -127,10 +127,13 @@ shift(SCR *sp, EXCMD *cmdp, enum which r
                 * Build a new indent string and count the number of
                 * characters it uses.
                 */
-               for (tbp = bp, newidx = 0;
-                   newcol >= O_VAL(sp, O_TABSTOP); ++newidx) {
-                       *tbp++ = '\t';
-                       newcol -= O_VAL(sp, O_TABSTOP);
+               tbp = bp;
+               newidx = 0;
+               if (!O_ISSET(sp, O_EXPANDTAB)) {
+                       for (; newcol >= O_VAL(sp, O_TABSTOP); ++newidx) {
+                               *tbp++ = '\t';
+                               newcol -= O_VAL(sp, O_TABSTOP);
+                       }
                }
                for (; newcol > 0; --newcol, ++newidx)
                        *tbp++ = ' ';
Index: usr.bin/vi/ex/ex_txt.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/ex/ex_txt.c,v
retrieving revision 1.16
diff -u -p -u -r1.16 ex_txt.c
--- usr.bin/vi/ex/ex_txt.c      27 May 2016 09:18:12 -0000      1.16
+++ usr.bin/vi/ex/ex_txt.c      2 Apr 2020 20:53:58 -0000
@@ -400,8 +400,12 @@ txt_dent(SCR *sp, TEXT *tp)
         *
         * Count up spaces/tabs needed to get to the target.
         */
-       for (cno = 0, tabs = 0; cno + COL_OFF(cno, ts) <= scno; ++tabs)
-               cno += COL_OFF(cno, ts);
+       cno = 0;
+       tabs = 0;
+       if (!O_ISSET(sp, O_EXPANDTAB)) {
+               for (; cno + COL_OFF(cno, ts) <= scno; ++tabs)
+                       cno += COL_OFF(cno, ts);
+       }
        spaces = scno - cno;
 
        /* Make sure there's enough room. */
Index: usr.bin/vi/vi/v_txt.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/vi/v_txt.c,v
retrieving revision 1.33
diff -u -p -u -r1.33 v_txt.c
--- usr.bin/vi/vi/v_txt.c       27 May 2016 09:18:12 -0000      1.33
+++ usr.bin/vi/vi/v_txt.c       2 Apr 2020 22:13:09 -0000
@@ -32,7 +32,7 @@
 static int      txt_abbrev(SCR *, TEXT *, CHAR_T *, int, int *, int *);
 static void     txt_ai_resolve(SCR *, TEXT *, int *);
 static TEXT    *txt_backup(SCR *, TEXTH *, TEXT *, u_int32_t *);
-static int      txt_dent(SCR *, TEXT *, int);
+static int      txt_dent(SCR *, TEXT *, int, int);
 static int      txt_emark(SCR *, TEXT *, size_t);
 static void     txt_err(SCR *, TEXTH *);
 static int      txt_fc(SCR *, TEXT *, int *);
@@ -968,7 +968,7 @@ leftmargin:         tp->lb[tp->cno - 1] = ' ';
                        if (tp->ai == 0 || tp->cno > tp->ai + tp->offset)
                                goto ins_ch;
 
-                       (void)txt_dent(sp, tp, 0);
+                       (void)txt_dent(sp, tp, O_SHIFTWIDTH, 0);
                        break;
                default:
                        abort();
@@ -1184,7 +1184,7 @@ leftmargin:               tp->lb[tp->cno - 1] = ' ';
        case K_CNTRLT:                  /* Add autoindent characters. */
                if (!LF_ISSET(TXT_CNTRLT))
                        goto ins_ch;
-               if (txt_dent(sp, tp, 1))
+               if (txt_dent(sp, tp, O_SHIFTWIDTH, 1))
                        goto err;
                goto ebuf_chk;
        case K_RIGHTBRACE:
@@ -1213,6 +1213,13 @@ leftmargin:              tp->lb[tp->cno - 1] = ' ';
        case K_HEXCHAR:
                hexcnt = 1;
                goto insq_ch;
+       case K_TAB:
+               if (quote != Q_VTHIS && O_ISSET(sp, O_EXPANDTAB)) {
+                       if (txt_dent(sp, tp, O_TABSTOP, 1))
+                               goto err;
+                       goto ebuf_chk;
+               }
+               goto insq_ch;
        default:                        /* Insert the character. */
 ins_ch:                /*
                 * Historically, vi eliminated nul's out of hand.  If the
@@ -1683,13 +1690,19 @@ txt_ai_resolve(SCR *sp, TEXT *tp, int *c
        /*
         * If there are no spaces, or no tabs after spaces and less than
         * ts spaces, it's already minimal.
+        * Keep analysing if expandtab is set.
         */
-       if (!spaces || (!tab_after_sp && spaces < ts))
+       if ((!spaces || (!tab_after_sp && spaces < ts)) &&
+           !O_ISSET(sp, O_EXPANDTAB))
                return;
 
        /* Count up spaces/tabs needed to get to the target. */
-       for (cno = 0, tabs = 0; cno + COL_OFF(cno, ts) <= scno; ++tabs)
-               cno += COL_OFF(cno, ts);
+       cno = 0;
+       tabs = 0;
+       if (!O_ISSET(sp, O_EXPANDTAB)) {
+               for (; cno + COL_OFF(cno, ts) <= scno; ++tabs)
+                       cno += COL_OFF(cno, ts);
+       }
        spaces = scno - cno;
 
        /*
@@ -1846,7 +1859,7 @@ txt_backup(SCR *sp, TEXTH *tiqh, TEXT *t
  * changes.
  */
 static int
-txt_dent(SCR *sp, TEXT *tp, int isindent)
+txt_dent(SCR *sp, TEXT *tp, int swopt, int isindent)
 {
        CHAR_T ch;
        u_long sw, ts;
@@ -1854,7 +1867,7 @@ txt_dent(SCR *sp, TEXT *tp, int isindent
        int ai_reset;
 
        ts = O_VAL(sp, O_TABSTOP);
-       sw = O_VAL(sp, O_SHIFTWIDTH);
+       sw = O_VAL(sp, swopt);
 
        /*
         * Since we don't know what precedes the character(s) being inserted
@@ -1921,9 +1934,12 @@ txt_dent(SCR *sp, TEXT *tp, int isindent
        if (current >= target)
                spaces = tabs = 0;
        else {
-               for (cno = current,
-                   tabs = 0; cno + COL_OFF(cno, ts) <= target; ++tabs)
-                       cno += COL_OFF(cno, ts);
+               cno = current;
+               tabs = 0;
+               if (!O_ISSET(sp, O_EXPANDTAB)) {
+                       for (; cno + COL_OFF(cno, ts) <= target; ++tabs)
+                               cno += COL_OFF(cno, ts);
+                       }
                spaces = target - cno;
        }
 

Reply via email to