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