mg: allow to change the tab width
authorop <op@openbsd.org>
Fri, 21 Apr 2023 13:39:36 +0000 (13:39 +0000)
committerop <op@openbsd.org>
Fri, 21 Apr 2023 13:39:36 +0000 (13:39 +0000)
This makes the tab width customizable per-buffer.  The new function
`set-tab-width' changes it for the current buffer or the default value
for new buffers if called with a prefix argument (or from the startup
file.)

The default tab width is still 8 column.

Together with the newly resurrected no-tab-mode, allows to use mg for a
variety of programming languages and coding styles.

Note that it's not possible to call set-tab-width with auto-execute in
the startup file due to limitations in how auto-execute and the parser
work.

ok tb@

usr.bin/mg/basic.c
usr.bin/mg/buffer.c
usr.bin/mg/cmode.c
usr.bin/mg/def.h
usr.bin/mg/display.c
usr.bin/mg/funmap.c
usr.bin/mg/match.c
usr.bin/mg/mg.1
usr.bin/mg/paragraph.c
usr.bin/mg/util.c

index ed7d475..d5f8ecb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: basic.c,v 1.53 2023/04/17 09:49:04 op Exp $   */
+/*     $OpenBSD: basic.c,v 1.54 2023/04/21 13:39:36 op Exp $   */
 
 /* This file is in the public domain */
 
@@ -277,8 +277,7 @@ getgoal(struct line *dlp)
        for (i = 0; i < llength(dlp); i++) {
                c = lgetc(dlp, i);
                if (c == '\t') {
-                       col |= 0x07;
-                       col++;
+                       col = ntabstop(col, curbp->b_tabw);
                } else if (ISCTRL(c) != FALSE) {
                        col += 2;
                } else if (isprint(c))
index e660500..8c8aab4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: buffer.c,v 1.113 2023/03/08 04:43:11 guenther Exp $ */
+/* $OpenBSD: buffer.c,v 1.114 2023/04/21 13:39:36 op Exp $ */
 
 /* This file is in the public domain. */
 
@@ -26,9 +26,42 @@ static struct buffer *bnew(const char *);
 
 static int usebufname(const char *);
 
+/* Default tab width */
+int     defb_tabw = 8;
+
 /* Flag for global working dir */
 extern int globalwd;
 
+/*
+ * Set the tab width for the current buffer, or the default for new
+ * buffers if called with a prefix argument.
+ */
+int
+settabw(int f, int n)
+{
+       char    buf[8], *bufp;
+       const char *errstr;
+
+       if (f & FFARG) {
+               if (n <= 0 || n > 16)
+                       return (FALSE);
+               defb_tabw = n;
+               return (TRUE);
+       }
+
+       if ((bufp = eread("Tab Width: ", buf, sizeof(buf),
+           EFNUL | EFNEW | EFCR)) == NULL)
+               return (ABORT);
+       if (bufp[0] == '\0')
+               return (ABORT);
+       n = strtonum(buf, 1, 16, &errstr);
+       if (errstr)
+               return (dobeep_msgs("Tab width", errstr));
+       curbp->b_tabw = n;
+       curwp->w_rflag |= WFFRAME;
+       return (TRUE);
+}
+
 int
 togglereadonlyall(int f, int n)
 {
@@ -588,6 +621,7 @@ bnew(const char *bname)
        bp->b_lines = 1;
        bp->b_nlseq = "\n";             /* use unix default */
        bp->b_nlchr = bp->b_nlseq;
+       bp->b_tabw = defb_tabw;
        if ((bp->b_bname = strdup(bname)) == NULL) {
                dobeep();
                ewprintf("Can't get %d bytes", strlen(bname) + 1);
index e5442a2..2a2a109 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmode.c,v 1.21 2023/04/17 09:49:04 op Exp $ */
+/* $OpenBSD: cmode.c,v 1.22 2023/04/21 13:39:37 op Exp $ */
 /*
  * This file is in the public domain.
  *
@@ -245,10 +245,10 @@ getindent(const struct line *lp, int *curi)
        for (lo = 0; lo < llength(lp); lo++) {
                if (!isspace(c = lgetc(lp, lo)))
                        break;
-               if (c == '\t') {
-                       nicol |= 0x07;
-               }
-               nicol++;
+               if (c == '\t')
+                       nicol = ntabstop(nicol, curbp->b_tabw);
+               else
+                       nicol++;
        }
 
        /* If last line was blank, choose 0 */
@@ -411,8 +411,7 @@ findcolpos(const struct buffer *bp, const struct line *lp, int lo)
        for (i = 0; i < lo; ++i) {
                c = lgetc(lp, i);
                if (c == '\t') {
-                       col |= 0x07;
-                       col++;
+                       col = ntabstop(col, curbp->b_tabw);
                } else if (ISCTRL(c) != FALSE)
                        col += 2;
                else if (isprint(c)) {
index 8cfaada..65ae2b4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: def.h,v 1.179 2023/04/17 09:49:04 op Exp $    */
+/*     $OpenBSD: def.h,v 1.180 2023/04/21 13:39:37 op Exp $    */
 
 /* This file is in the public domain. */
 
@@ -269,6 +269,7 @@ struct buffer {
        char             b_cwd[NFILEN]; /* working directory             */
        char            *b_nlseq;       /* Newline sequence of chars     */
        char            *b_nlchr;       /* 1st newline character         */
+       int              b_tabw;        /* Width of a tab character      */
        struct fileinfo  b_fi;          /* File attributes               */
        struct undoq     b_undo;        /* Undo actions list             */
        struct undo_rec *b_undoptr;
@@ -430,6 +431,7 @@ int          shrinkwind(int, int);
 int             delwind(int, int);
 
 /* buffer.c */
+int             settabw(int, int);
 int             togglereadonly(int, int);
 int             togglereadonlyall(int, int);
 struct buffer   *bfind(const char *, int);
@@ -542,6 +544,7 @@ int          gotoline(int, int);
 int             setlineno(int);
 
 /* util.c X */
+int             ntabstop(int, int);
 int             showcpos(int, int);
 int             getcolpos(struct mgwin *);
 int             twiddle(int, int);
index 3814a0b..ab923d4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: display.c,v 1.51 2023/04/17 09:49:04 op Exp $ */
+/*     $OpenBSD: display.c,v 1.52 2023/04/21 13:39:37 op Exp $ */
 
 /* This file is in the public domain. */
 
@@ -52,9 +52,9 @@ struct score {
 };
 
 void   vtmove(int, int);
-void   vtputc(int);
-void   vtpute(int);
-int    vtputs(const char *);
+void   vtputc(int, struct mgwin *);
+void   vtpute(int, struct mgwin *);
+int    vtputs(const char *, struct mgwin *);
 void   vteeol(void);
 void   updext(int, int);
 void   modeline(struct mgwin *, int);
@@ -308,9 +308,10 @@ vtmove(int row, int col)
  * Three guesses how we found this.
  */
 void
-vtputc(int c)
+vtputc(int c, struct mgwin *wp)
 {
        struct video    *vp;
+       int              target;
 
        c &= 0xff;
 
@@ -318,19 +319,20 @@ vtputc(int c)
        if (vtcol >= ncol)
                vp->v_text[ncol - 1] = '$';
        else if (c == '\t') {
+               target = ntabstop(vtcol, wp->w_bufp->b_tabw);
                do {
-                       vtputc(' ');
-               } while (vtcol < ncol && (vtcol & 0x07) != 0);
+                       vtputc(' ', wp);
+               } while (vtcol < ncol && vtcol < target);
        } else if (ISCTRL(c)) {
-               vtputc('^');
-               vtputc(CCHR(c));
+               vtputc('^', wp);
+               vtputc(CCHR(c), wp);
        } else if (isprint(c))
                vp->v_text[vtcol++] = c;
        else {
                char bf[5];
 
                snprintf(bf, sizeof(bf), "\\%o", c);
-               vtputs(bf);
+               vtputs(bf, wp);
        }
 }
 
@@ -340,9 +342,10 @@ vtputc(int c)
  * margin.
  */
 void
-vtpute(int c)
+vtpute(int c, struct mgwin *wp)
 {
        struct video *vp;
+       int target;
 
        c &= 0xff;
 
@@ -350,12 +353,13 @@ vtpute(int c)
        if (vtcol >= ncol)
                vp->v_text[ncol - 1] = '$';
        else if (c == '\t') {
+               target = ntabstop(vtcol + lbound, wp->w_bufp->b_tabw);
                do {
-                       vtpute(' ');
-               } while (((vtcol + lbound) & 0x07) != 0 && vtcol < ncol);
+                       vtpute(' ', wp);
+               } while (((vtcol + lbound) < target) && vtcol < ncol);
        } else if (ISCTRL(c) != FALSE) {
-               vtpute('^');
-               vtpute(CCHR(c));
+               vtpute('^', wp);
+               vtpute(CCHR(c), wp);
        } else if (isprint(c)) {
                if (vtcol >= 0)
                        vp->v_text[vtcol] = c;
@@ -365,7 +369,7 @@ vtpute(int c)
 
                snprintf(bf, sizeof(bf), "\\%o", c);
                for (cp = bf; *cp != '\0'; cp++)
-                       vtpute(*cp);
+                       vtpute(*cp, wp);
        }
 }
 
@@ -476,7 +480,7 @@ update(int modelinecolor)
                        vscreen[i]->v_flag |= (VFCHG | VFHBAD);
                        vtmove(i, 0);
                        for (j = 0; j < llength(lp); ++j)
-                               vtputc(lgetc(lp, j));
+                               vtputc(lgetc(lp, j), wp);
                        vteeol();
                } else if ((wp->w_rflag & (WFEDIT | WFFULL)) != 0) {
                        hflag = TRUE;
@@ -486,7 +490,7 @@ update(int modelinecolor)
                                vtmove(i, 0);
                                if (lp != wp->w_bufp->b_headp) {
                                        for (j = 0; j < llength(lp); ++j)
-                                               vtputc(lgetc(lp, j));
+                                               vtputc(lgetc(lp, j), wp);
                                        lp = lforw(lp);
                                }
                                vteeol();
@@ -509,8 +513,7 @@ update(int modelinecolor)
        while (i < curwp->w_doto) {
                c = lgetc(lp, i++);
                if (c == '\t') {
-                       curcol |= 0x07;
-                       curcol++;
+                       curcol = ntabstop(curcol, curwp->w_bufp->b_tabw);
                } else if (ISCTRL(c) != FALSE)
                        curcol += 2;
                else if (isprint(c))
@@ -545,7 +548,7 @@ update(int modelinecolor)
                                    (curcol < ncol - 1)) {
                                        vtmove(i, 0);
                                        for (j = 0; j < llength(lp); ++j)
-                                               vtputc(lgetc(lp, j));
+                                               vtputc(lgetc(lp, j), wp);
                                        vteeol();
                                        /* this line no longer is extended */
                                        vscreen[i]->v_flag &= ~VFEXT;
@@ -677,7 +680,7 @@ updext(int currow, int curcol)
        vtmove(currow, -lbound);                /* start scanning offscreen */
        lp = curwp->w_dotp;                     /* line to output */
        for (j = 0; j < llength(lp); ++j)       /* until the end-of-line */
-               vtpute(lgetc(lp, j));
+               vtpute(lgetc(lp, j), curwp);
        vteeol();                               /* truncate the virtual line */
        vscreen[currow]->v_text[0] = '$';       /* and put a '$' in column 1 */
 }
@@ -793,45 +796,45 @@ modeline(struct mgwin *wp, int modelinecolor)
        vscreen[n]->v_flag |= (VFCHG | VFHBAD); /* Recompute, display.   */
        vtmove(n, 0);                           /* Seek to right line.   */
        bp = wp->w_bufp;
-       vtputc('-');
-       vtputc('-');
+       vtputc('-', wp);
+       vtputc('-', wp);
        if ((bp->b_flag & BFREADONLY) != 0) {
-               vtputc('%');
+               vtputc('%', wp);
                if ((bp->b_flag & BFCHG) != 0)
-                       vtputc('*');
+                       vtputc('*', wp);
                else
-                       vtputc('%');
+                       vtputc('%', wp);
        } else if ((bp->b_flag & BFCHG) != 0) { /* "*" if changed.       */
-               vtputc('*');
-               vtputc('*');
+               vtputc('*', wp);
+               vtputc('*', wp);
        } else {
-               vtputc('-');
-               vtputc('-');
+               vtputc('-', wp);
+               vtputc('-', wp);
        }
-       vtputc('-');
+       vtputc('-', wp);
        n = 5;
-       n += vtputs("Mg: ");
+       n += vtputs("Mg: ", wp);
        if (bp->b_bname[0] != '\0')
-               n += vtputs(&(bp->b_bname[0]));
+               n += vtputs(&(bp->b_bname[0]), wp);
        while (n < 42) {                        /* Pad out with blanks.  */
-               vtputc(' ');
+               vtputc(' ', wp);
                ++n;
        }
-       vtputc('(');
+       vtputc('(', wp);
        ++n;
        for (md = 0; ; ) {
-               n += vtputs(bp->b_modes[md]->p_name);
+               n += vtputs(bp->b_modes[md]->p_name, wp);
                if (++md > bp->b_nmodes)
                        break;
-               vtputc('-');
+               vtputc('-', wp);
                ++n;
        }
        /* XXX These should eventually move to a real mode */
        if (macrodef == TRUE)
-               n += vtputs("-def");
+               n += vtputs("-def", wp);
        if (globalwd == TRUE)
-               n += vtputs("-gwd");
-       vtputc(')');
+               n += vtputs("-gwd", wp);
+       vtputc(')', wp);
        ++n;
 
        if (linenos && colnos)
@@ -842,10 +845,10 @@ modeline(struct mgwin *wp, int modelinecolor)
        else if (colnos)
                len = snprintf(sl, sizeof(sl), "--C%d", getcolpos(wp));
        if ((linenos || colnos) && len < sizeof(sl) && len != -1)
-               n += vtputs(sl);
+               n += vtputs(sl, wp);
 
        while (n < ncol) {                      /* Pad out.              */
-               vtputc('-');
+               vtputc('-', wp);
                ++n;
        }
 }
@@ -854,12 +857,12 @@ modeline(struct mgwin *wp, int modelinecolor)
  * Output a string to the mode line, report how long it was.
  */
 int
-vtputs(const char *s)
+vtputs(const char *s, struct mgwin *wp)
 {
        int n = 0;
 
        while (*s != '\0') {
-               vtputc(*s++);
+               vtputc(*s++, wp);
                ++n;
        }
        return (n);
index fbf4121..ae1c455 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: funmap.c,v 1.66 2023/04/17 09:49:04 op Exp $  */
+/*     $OpenBSD: funmap.c,v 1.67 2023/04/21 13:39:37 op Exp $  */
 
 /* This file is in the public domain */
 
@@ -199,6 +199,7 @@ static struct funmap functnames[] = {
        {ask_selfinsert, "self-insert-char", 1},
        {selfinsert, "self-insert-command", 1},         /* startup only */
        {sentencespace, "sentence-end-double-space", 0},
+       {settabw, "set-tab-width", 1},
 #ifdef REGEX
        {setcasefold, "set-case-fold-search", 0},
 #endif /* REGEX */
index acb814e..9481985 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: match.c,v 1.24 2023/04/17 15:18:25 op Exp $   */
+/*     $OpenBSD: match.c,v 1.25 2023/04/21 13:39:37 op Exp $   */
 
 /* This file is in the public domain. */
 
@@ -136,6 +136,7 @@ displaymatch(struct line *clp, int cbo)
        int      cp;
        int      bufo;
        int      c;
+       int      col;
        int      inwindow;
        char     buf[NLINE];
 
@@ -181,9 +182,9 @@ displaymatch(struct line *clp, int cbo)
                                } else
                                        buf[bufo++] = c;
                        } else {
-                               do {
+                               col = ntabstop(bufo, curbp->b_tabw);
+                               while (bufo < col && bufo < sizeof(buf) - 1)
                                        buf[bufo++] = ' ';
-                               } while ((bufo & 7) && bufo < sizeof(buf) - 1);
                        }
                }
                buf[bufo++] = '\0';
index d2edd28..0b677e9 100644 (file)
@@ -1,7 +1,7 @@
-.\"    $OpenBSD: mg.1,v 1.129 2023/04/17 09:49:04 op Exp $
+.\"    $OpenBSD: mg.1,v 1.130 2023/04/21 13:39:37 op Exp $
 .\" This file is in the public domain.
 .\"
-.Dd $Mdocdate: April 17 2023 $
+.Dd $Mdocdate: April 21 2023 $
 .Dt MG 1
 .Os
 .Sh NAME
@@ -896,6 +896,9 @@ Used by auto-fill-mode.
 Sets the mark in the current window to the current dot location.
 .It set-prefix-string
 Sets the prefix string to be used by the 'prefix-region' command.
+.It set-tab-width
+Set the tab width for the current buffer, or the default for new buffers
+if called with a prefix argument or from the startup file.
 .It shell-command
 Execute external command from mini-buffer.
 .It shell-command-on-region
index 1455295..4e35770 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: paragraph.c,v 1.48 2023/04/17 09:49:04 op Exp $       */
+/*     $OpenBSD: paragraph.c,v 1.49 2023/04/21 13:39:37 op Exp $       */
 
 /* This file is in the public domain. */
 
@@ -413,7 +413,7 @@ fillword(int f, int n)
                        return selfinsert(f, n);
                c = lgetc(curwp->w_dotp, i);
                if (c == '\t')
-                       col |= 0x07;
+                       col = ntabstop(col, curwp->w_bufp->b_tabw);
                else if (ISCTRL(c) != FALSE)
                        ++col;
        }
index 05fd84f..6168f51 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: util.c,v 1.47 2023/04/17 09:53:08 op Exp $    */
+/*     $OpenBSD: util.c,v 1.48 2023/04/21 13:39:37 op Exp $    */
 
 /* This file is in the public domain. */
 
 
 int    doindent(int);
 
+/*
+ * Compute next tab stop, with `col' being the a column number and
+ * `tabw' the tab width.
+ */
+int
+ntabstop(int col, int tabw)
+{
+       return (((col + tabw) / tabw) * tabw);
+}
+
 /*
  * Display a bunch of useful information about the current location of dot.
  * The character under the cursor (in octal), the current line, row, and
@@ -103,8 +113,7 @@ getcolpos(struct mgwin *wp)
        for (i = 0; i < wp->w_doto; ++i) {
                c = lgetc(wp->w_dotp, i);
                if (c == '\t') {
-                       col |= 0x07;
-                       col++;
+                       col = ntabstop(col, wp->w_bufp->b_tabw);
                } else if (ISCTRL(c) != FALSE)
                        col += 2;
                else if (isprint(c)) {
@@ -377,8 +386,9 @@ lfindent(int f, int n)
                        if (c != ' ' && c != '\t')
                                break;
                        if (c == '\t')
-                               nicol |= 0x07;
-                       ++nicol;
+                               nicol = ntabstop(nicol, curwp->w_bufp->b_tabw);
+                       else
+                               ++nicol;
                }
                (void)delwhite(FFRAND, 1);
 
@@ -472,11 +482,17 @@ backdel(int f, int n)
 int
 space_to_tabstop(int f, int n)
 {
+       int     c;
+
        if (n < 0)
                return (FALSE);
        if (n == 0)
                return (TRUE);
-       return (linsert((n << 3) - (curwp->w_doto & 7), ' '));
+
+       c = curwp->w_doto;
+       while (n-- > 0)
+               c = ntabstop(c, curbp->b_tabw);
+       return (linsert(c - curwp->w_doto, ' '));
 }
 
 /*