From: op Date: Fri, 21 Apr 2023 13:39:36 +0000 (+0000) Subject: mg: allow to change the tab width X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=fb3e194e711287806a7a4018d6be7df2a14e1cab;p=openbsd mg: allow to change the tab width 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@ --- diff --git a/usr.bin/mg/basic.c b/usr.bin/mg/basic.c index ed7d475c494..d5f8ecb1796 100644 --- a/usr.bin/mg/basic.c +++ b/usr.bin/mg/basic.c @@ -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)) diff --git a/usr.bin/mg/buffer.c b/usr.bin/mg/buffer.c index e6605000475..8c8aab40a86 100644 --- a/usr.bin/mg/buffer.c +++ b/usr.bin/mg/buffer.c @@ -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); diff --git a/usr.bin/mg/cmode.c b/usr.bin/mg/cmode.c index e5442a2b6ed..2a2a1090003 100644 --- a/usr.bin/mg/cmode.c +++ b/usr.bin/mg/cmode.c @@ -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)) { diff --git a/usr.bin/mg/def.h b/usr.bin/mg/def.h index 8cfaada0300..65ae2b43c06 100644 --- a/usr.bin/mg/def.h +++ b/usr.bin/mg/def.h @@ -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); diff --git a/usr.bin/mg/display.c b/usr.bin/mg/display.c index 3814a0bd29b..ab923d4fb9d 100644 --- a/usr.bin/mg/display.c +++ b/usr.bin/mg/display.c @@ -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); diff --git a/usr.bin/mg/funmap.c b/usr.bin/mg/funmap.c index fbf41217328..ae1c455edff 100644 --- a/usr.bin/mg/funmap.c +++ b/usr.bin/mg/funmap.c @@ -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 */ diff --git a/usr.bin/mg/match.c b/usr.bin/mg/match.c index acb814e3b9d..9481985ee57 100644 --- a/usr.bin/mg/match.c +++ b/usr.bin/mg/match.c @@ -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'; diff --git a/usr.bin/mg/mg.1 b/usr.bin/mg/mg.1 index d2edd289cc5..0b677e9c4ca 100644 --- a/usr.bin/mg/mg.1 +++ b/usr.bin/mg/mg.1 @@ -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 diff --git a/usr.bin/mg/paragraph.c b/usr.bin/mg/paragraph.c index 1455295f90d..4e35770e65f 100644 --- a/usr.bin/mg/paragraph.c +++ b/usr.bin/mg/paragraph.c @@ -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; } diff --git a/usr.bin/mg/util.c b/usr.bin/mg/util.c index 05fd84f91c8..6168f51144b 100644 --- a/usr.bin/mg/util.c +++ b/usr.bin/mg/util.c @@ -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. */ @@ -18,6 +18,16 @@ 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, ' ')); } /*