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; }