discuss@mandoc.bsd.lv
 help / color / Atom feed
* tbl(7) output in -Tlocale
@ 2014-10-14 10:10 Anthony J. Bentley
  2014-10-14 13:56 ` Ingo Schwarze
  2018-11-28  5:11 ` Ingo Schwarze
  0 siblings, 2 replies; 3+ messages in thread
From: Anthony J. Bentley @ 2014-10-14 10:10 UTC (permalink / raw)
  To: discuss

Hi,

In a UTF-8 locale, groff will output tables with box-drawing characters.
This provides a noticeable increase in readability in terminals.

Rather than the ASCII characters +, |, and - for borders, it uses the
Unicode range U+2500 to U+256C or so.

For example, this table:

.TS
l
l.
Header
_
Data 1
Data 2
.TE

uses U+2500 BOX DRAWINGS LIGHT HORIZONTAL for the horizontal line.

This table:

.TS
tab(:) box;
c5 c5 c5.
1:2:3
4:5:6
.TE

uses U+2500 and U+2502 for the sides, and U+250C, U+2510, U+2514, and
U+2518 for the corners.

.TS
tab(:) doublebox;
c5 c5 c5.
1:2:3
4:5:6
.TE

This is an example where Groff's output is not very good: it renders as
'box' does but duplicating the top and bottom lines. Nicer would be to
use U+2550/U+2551 for the sides and U+2554, U+2557, U+255A, and U+255D
for the corners. (Even in ASCII mode it would make more sense to use =
instead of doubling up on -, since they don't make a pretense of doubling
the vertical sides anyway.)

The 'allbox' option uses everything that 'box' does plus U+251C, U+2524,
U+252C, U+2534, and U+253C. Of course, allbox isn't implemented in mandoc
anyway.

-- 
Anthony J. Bentley
--
 To unsubscribe send an email to discuss+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: tbl(7) output in -Tlocale
  2014-10-14 10:10 tbl(7) output in -Tlocale Anthony J. Bentley
@ 2014-10-14 13:56 ` Ingo Schwarze
  2018-11-28  5:11 ` Ingo Schwarze
  1 sibling, 0 replies; 3+ messages in thread
From: Ingo Schwarze @ 2014-10-14 13:56 UTC (permalink / raw)
  To: Anthony J. Bentley; +Cc: discuss

Hi Anthony,

Anthony J. Bentley wrote on Tue, Oct 14, 2014 at 04:10:55AM -0600:

> In a UTF-8 locale, groff will output tables with box-drawing characters.
> This provides a noticeable increase in readability in terminals.

Makes sense to me, i added an entry to the TODO file.

Actually, this is probably not too difficult to implement if anybody
is looking for a project, but i'm not doing it myself right now...

Yours,
  Ingo
--
 To unsubscribe send an email to discuss+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: tbl(7) output in -Tlocale
  2014-10-14 10:10 tbl(7) output in -Tlocale Anthony J. Bentley
  2014-10-14 13:56 ` Ingo Schwarze
@ 2018-11-28  5:11 ` Ingo Schwarze
  1 sibling, 0 replies; 3+ messages in thread
From: Ingo Schwarze @ 2018-11-28  5:11 UTC (permalink / raw)
  To: Anthony J. Bentley; +Cc: discuss

Hi Anthony,

i'm using the opportunity to reply to an email that is four years old.

Anthony J. Bentley wrote on Tue, Oct 14, 2014 at 04:10:55AM -0600:

> In a UTF-8 locale, groff will output tables with box-drawing characters.
> This provides a noticeable increase in readability in terminals.

Now implemented in mandoc with the commit below.

> .TS
> tab(:) doublebox;
> c5 c5 c5.
> 1:2:3
> 4:5:6
> .TE

> This is an example where Groff's output is not very good: it renders as
> 'box' does but duplicating the top and bottom lines. Nicer would be to
> use U+2550/U+2551 for the sides and U+2554, U+2557, U+255A, and U+255D
> for the corners.

Mandoc does that now, except that i chose to use the "heavy" rather
than the "double" variants.  Maybe we should do that in HTML, too,
it generally looks better.

> (Even in ASCII mode it would make more sense to use =
> instead of doubling up on -, since they don't make a pretense of
> doubling the vertical sides anyway.)

Indeed; but for -T ascii, i value compatibility with groff, so that
would require writing a patch for groff/src/preproc/tbl/*.cpp,
which i didn't do yet.  I dimly remember briefly looking at that code
years ago and didn't enjoy it.  It is even more complicated than
mandoc/tbl_term.c.

> The 'allbox' option uses everything that 'box' does plus U+251C, U+2524,
> U+252C, U+2534, and U+253C. Of course, allbox isn't implemented in mandoc
> anyway.

That got implemented at some other time during those four years.  :-)

Yours,
  Ingo


Log Message:
-----------
In -T utf8 output mode, render tbl(7) borders with the Unicode
box drawing characters, U+2500 to U+257F.

Originally suggested by bentley@ four years ago,
reminded this summer by Pali Rohar.

Binary and decimal arithmetics are boring,
so let's use some ternary arithmetics for a change.

That said, some other aspects are too complicated for my liking,
so this could use some polishing in the future.

Modified Files:
--------------
    mandoc:
        TODO
        tbl_term.c

Revision Data
-------------
Index: tbl_term.c
===================================================================
RCS file: /home/cvs/mandoc/mandoc/tbl_term.c,v
retrieving revision 1.61
retrieving revision 1.62
diff -Ltbl_term.c -Ltbl_term.c -u -p -r1.61 -r1.62
--- tbl_term.c
+++ tbl_term.c
@@ -32,23 +32,114 @@
 #define	IS_HORIZ(cp)	((cp)->pos == TBL_CELL_HORIZ || \
 			 (cp)->pos == TBL_CELL_DHORIZ)
 
+/* Flags for tbl_hrule(). */
+#define	HRULE_DBOX	(1 << 0)  /* Top and bottom, ASCII mode only. */
+#define	HRULE_DATA	(1 << 1)  /* In the middle of the table. */
+#define	HRULE_DOWN	(1 << 2)  /* Allow downward branches. */
+#define	HRULE_UP	(1 << 3)  /* Allow upward branches. */
+#define	HRULE_ENDS	(1 << 4)  /* Also generate left and right ends. */
+
+
 static	size_t	term_tbl_len(size_t, void *);
 static	size_t	term_tbl_strlen(const char *, void *);
 static	size_t	term_tbl_sulen(const struct roffsu *, void *);
-static	void	tbl_char(struct termp *, char, size_t);
 static	void	tbl_data(struct termp *, const struct tbl_opts *,
 			const struct tbl_cell *,
 			const struct tbl_dat *,
 			const struct roffcol *);
+static	void	tbl_direct_border(struct termp *, int, size_t);
+static	void	tbl_fill_border(struct termp *, int, size_t);
+static	void	tbl_fill_char(struct termp *, char, size_t);
+static	void	tbl_fill_string(struct termp *, const char *, size_t);
+static	void	tbl_hrule(struct termp *, const struct tbl_span *, int);
 static	void	tbl_literal(struct termp *, const struct tbl_dat *,
 			const struct roffcol *);
 static	void	tbl_number(struct termp *, const struct tbl_opts *,
 			const struct tbl_dat *,
 			const struct roffcol *);
-static	void	tbl_hrule(struct termp *, const struct tbl_span *, int);
 static	void	tbl_word(struct termp *, const struct tbl_dat *);
 
 
+/*
+ * The following border-character tables are indexed
+ * by ternary (3-based) numbers, as opposed to binary or decimal.
+ * Each ternary digit describes the line width in one direction:
+ * 0 means no line, 1 single or light line, 2 double or heavy line.
+ */
+
+/* Positional values of the four directions. */
+#define	BRIGHT	1
+#define	BDOWN	3
+#define	BLEFT	(3 * 3)
+#define	BUP	(3 * 3 * 3)
+#define	BHORIZ	(BLEFT + BRIGHT)
+
+/* Code points to use for each combination of widths. */
+static  const int borders_utf8[81] = {
+	0x0020, 0x2576, 0x257a,  /* 000 right */
+	0x2577, 0x250c, 0x250d,  /* 001 down */
+	0x257b, 0x250e, 0x250f,  /* 002 */
+	0x2574, 0x2500, 0x257c,  /* 010 left */
+	0x2510, 0x252c, 0x252e,  /* 011 left down */
+	0x2512, 0x2530, 0x2532,  /* 012 */
+	0x2578, 0x257e, 0x2501,  /* 020 left */
+	0x2511, 0x252d, 0x252f,  /* 021 left down */
+	0x2513, 0x2531, 0x2533,  /* 022 */
+	0x2575, 0x2514, 0x2515,  /* 100 up */
+	0x2502, 0x251c, 0x251d,  /* 101 up down */
+	0x257d, 0x251f, 0x2522,  /* 102 */
+	0x2518, 0x2534, 0x2536,  /* 110 up left */
+	0x2524, 0x253c, 0x253e,  /* 111 all */
+	0x2527, 0x2541, 0x2546,  /* 112 */
+	0x2519, 0x2535, 0x2537,  /* 120 up left */
+	0x2525, 0x253d, 0x253f,  /* 121 all */
+	0x252a, 0x2545, 0x2548,  /* 122 */
+	0x2579, 0x2516, 0x2517,  /* 200 up */
+	0x257f, 0x251e, 0x2521,  /* 201 up down */
+	0x2503, 0x2520, 0x2523,  /* 202 */
+	0x251a, 0x2538, 0x253a,  /* 210 up left */
+	0x2526, 0x2540, 0x2544,  /* 211 all */
+	0x2528, 0x2542, 0x254a,  /* 212 */
+	0x251b, 0x2539, 0x253b,  /* 220 up left */
+	0x2529, 0x2543, 0x2547,  /* 221 all */
+	0x252b, 0x2549, 0x254b,  /* 222 */
+};
+
+/* ASCII approximations for these code points, compatible with groff. */
+static  const int borders_ascii[81] = {
+	' ', '-', '=',  /* 000 right */
+	'|', '+', '+',  /* 001 down */
+	'|', '+', '+',  /* 002 */
+	'-', '-', '=',  /* 010 left */
+	'+', '+', '+',  /* 011 left down */
+	'+', '+', '+',  /* 012 */
+	'=', '=', '=',  /* 020 left */
+	'+', '+', '+',  /* 021 left down */
+	'+', '+', '+',  /* 022 */
+	'|', '+', '+',  /* 100 up */
+	'|', '+', '+',  /* 101 up down */
+	'|', '+', '+',  /* 102 */
+	'+', '+', '+',  /* 110 up left */
+	'+', '+', '+',  /* 111 all */
+	'+', '+', '+',  /* 112 */
+	'+', '+', '+',  /* 120 up left */
+	'+', '+', '+',  /* 121 all */
+	'+', '+', '+',  /* 122 */
+	'|', '+', '+',  /* 200 up */
+	'|', '+', '+',  /* 201 up down */
+	'|', '+', '+',  /* 202 */
+	'+', '+', '+',  /* 210 up left */
+	'+', '+', '+',  /* 211 all */
+	'+', '+', '+',  /* 212 */
+	'+', '+', '+',  /* 220 up left */
+	'+', '+', '+',  /* 221 all */
+	'+', '+', '+',  /* 222 */
+};
+
+/* Either of the above according to the selected output encoding. */
+static	const int *borders_locale;
+
+
 static size_t
 term_tbl_sulen(const struct roffsu *su, void *arg)
 {
@@ -70,15 +161,16 @@ term_tbl_len(size_t sz, void *arg)
 	return term_len((const struct termp *)arg, sz);
 }
 
+
 void
 term_tbl(struct termp *tp, const struct tbl_span *sp)
 {
-	const struct tbl_cell	*cp, *cpn, *cpp;
+	const struct tbl_cell	*cp, *cpn, *cpp, *cps;
 	const struct tbl_dat	*dp;
 	static size_t		 offset;
 	size_t			 coloff, tsz;
-	int			 ic, horiz, hspans, vert, more;
-	char			 fc;
+	int			 hspans, ic, more;
+	int			 dvert, fc, horiz, line, uvert;
 
 	/* Inhibit printing of spaces: we do padding ourselves. */
 
@@ -90,6 +182,9 @@ term_tbl(struct termp *tp, const struct 
 	 */
 
 	if (tp->tbl.cols == NULL) {
+		borders_locale = tp->enc == TERMENC_UTF8 ?
+		    borders_utf8 : borders_ascii;
+
 		tp->tbl.len = term_tbl_len;
 		tp->tbl.slen = term_tbl_strlen;
 		tp->tbl.sulen = term_tbl_sulen;
@@ -127,10 +222,11 @@ term_tbl(struct termp *tp, const struct 
 
 		/* Horizontal frame at the start of boxed tables. */
 
-		if (sp->opts->opts & TBL_OPT_DBOX)
-			tbl_hrule(tp, sp, 3);
+		if (tp->enc == TERMENC_ASCII &&
+		    sp->opts->opts & TBL_OPT_DBOX)
+			tbl_hrule(tp, sp, HRULE_DBOX | HRULE_ENDS);
 		if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
-			tbl_hrule(tp, sp, 2);
+			tbl_hrule(tp, sp, HRULE_DOWN | HRULE_ENDS);
 	}
 
 	/* Set up the columns. */
@@ -219,30 +315,34 @@ term_tbl(struct termp *tp, const struct 
 		/* Print the vertical frame at the start of each row. */
 
 		tp->tcol = tp->tcols;
-		fc = '\0';
-		if (sp->layout->vert ||
-		    (sp->next != NULL && sp->next->layout->vert &&
-		     sp->next->pos == TBL_SPAN_DATA) ||
-		    (sp->prev != NULL && sp->prev->layout->vert &&
-		     (horiz || (IS_HORIZ(sp->layout->first) &&
-		       !IS_HORIZ(sp->prev->layout->first)))) ||
-		    sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
-			fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|';
-		else if (horiz && sp->opts->lvert)
-			fc = '-';
-		if (fc != '\0') {
+		uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 :
+		    sp->opts->opts & TBL_OPT_BOX ? 1 : 0;
+		if (sp->pos == TBL_SPAN_DATA && uvert < sp->layout->vert)
+			uvert = dvert = sp->layout->vert;
+		if (sp->next != NULL && sp->next->pos == TBL_SPAN_DATA &&
+		    dvert < sp->next->layout->vert)
+			dvert = sp->next->layout->vert;
+		if (sp->prev != NULL && uvert < sp->prev->layout->vert &&
+		    (horiz || (IS_HORIZ(sp->layout->first) &&
+		      !IS_HORIZ(sp->prev->layout->first))))
+			uvert = sp->prev->layout->vert;
+		line = sp->pos == TBL_SPAN_DHORIZ ||
+		    sp->layout->first->pos == TBL_CELL_DHORIZ ? 2 :
+		    sp->pos == TBL_SPAN_HORIZ ||
+		    sp->layout->first->pos == TBL_CELL_HORIZ ? 1 : 0;
+		fc = BUP * uvert + BDOWN * dvert + BRIGHT * line;
+		if (uvert > 0 || dvert > 0 || (horiz && sp->opts->lvert)) {
 			(*tp->advance)(tp, tp->tcols->offset);
-			(*tp->letter)(tp, fc);
-			tp->viscol = tp->tcol->offset + 1;
+			tp->viscol = tp->tcol->offset;
+			tbl_direct_border(tp, fc, 1);
 		}
 
 		/* Print the data cells. */
 
 		more = 0;
-		if (horiz) {
-			tbl_hrule(tp, sp, 0);
-			term_flushln(tp);
-		} else {
+		if (horiz)
+			tbl_hrule(tp, sp, HRULE_DATA | HRULE_DOWN | HRULE_UP);
+		else {
 			cp = sp->layout->first;
 			cpn = sp->next == NULL ? NULL :
 			    sp->next->layout->first;
@@ -258,25 +358,27 @@ term_tbl(struct termp *tp, const struct 
 				 * and advance to next layout cell.
 				 */
 
+				uvert = dvert = fc = 0;
 				if (cp != NULL) {
-					vert = cp->vert;
+					cps = cp;
+					while (cps->next != NULL &&
+					    cps->next->pos == TBL_CELL_SPAN)
+						cps = cps->next;
+					if (sp->pos == TBL_SPAN_DATA)
+						uvert = dvert = cps->vert;
 					switch (cp->pos) {
 					case TBL_CELL_HORIZ:
-						fc = '-';
+						fc = BHORIZ;
 						break;
 					case TBL_CELL_DHORIZ:
-						fc = '=';
+						fc = BHORIZ * 2;
 						break;
 					default:
-						fc = ' ';
 						break;
 					}
-				} else {
-					vert = 0;
-					fc = ' ';
 				}
 				if (cpp != NULL) {
-					if (vert == 0 &&
+					if (uvert < cpp->vert &&
 					    cp != NULL &&
 					    ((IS_HORIZ(cp) &&
 					      !IS_HORIZ(cpp)) ||
@@ -284,19 +386,22 @@ term_tbl(struct termp *tp, const struct 
 					      cpp->next != NULL &&
 					      IS_HORIZ(cp->next) &&
 					      !IS_HORIZ(cpp->next))))
-						vert = cpp->vert;
+						uvert = cpp->vert;
 					cpp = cpp->next;
 				}
-				if (vert == 0 &&
-				    sp->opts->opts & TBL_OPT_ALLBOX)
-					vert = 1;
+				if (sp->opts->opts & TBL_OPT_ALLBOX) {
+					if (uvert == 0)
+						uvert = 1;
+					if (dvert == 0)
+						dvert = 1;
+				}
 				if (cpn != NULL) {
-					if (vert == 0)
-						vert = cpn->vert;
+					if (dvert == 0 ||
+					    (dvert < cpn->vert &&
+					     tp->enc == TERMENC_UTF8))
+						dvert = cpn->vert;
 					cpn = cpn->next;
 				}
-				if (cp != NULL)
-					cp = cp->next;
 
 				/*
 				 * Skip later cells in a span,
@@ -306,6 +411,7 @@ term_tbl(struct termp *tp, const struct 
 
 				if (hspans) {
 					hspans--;
+					cp = cp->next;
 					continue;
 				}
 				if (dp != NULL) {
@@ -331,10 +437,13 @@ term_tbl(struct termp *tp, const struct 
 				 * but not after the last column.
 				 */
 
-				if (fc == ' ' && ((vert == 0 &&
-				     (cp == NULL || !IS_HORIZ(cp))) ||
-				    tp->tcol + 1 == tp->tcols + tp->lasttcol))
+				if (fc == 0 && ((uvert == 0 && dvert == 0 &&
+				     (cp->next == NULL ||
+				      !IS_HORIZ(cp->next))) ||
+				    tp->tcol + 1 == tp->tcols + tp->lasttcol)) {
+					cp = cp->next;
 					continue;
+				}
 
 				if (tp->viscol < tp->tcol->rmargin) {
 					(*tp->advance)(tp, tp->tcol->rmargin
@@ -342,69 +451,89 @@ term_tbl(struct termp *tp, const struct 
 					tp->viscol = tp->tcol->rmargin;
 				}
 				while (tp->viscol < tp->tcol->rmargin +
-				    tp->tbl.cols[ic].spacing / 2) {
-					(*tp->letter)(tp, fc);
-					tp->viscol++;
-				}
+				    tp->tbl.cols[ic].spacing / 2)
+					tbl_direct_border(tp, fc, 1);
 
 				if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
 					continue;
 
-				if (fc == ' ' && cp != NULL) {
+				if (cp != NULL) {
 					switch (cp->pos) {
 					case TBL_CELL_HORIZ:
-						fc = '-';
+						fc = BLEFT;
 						break;
 					case TBL_CELL_DHORIZ:
-						fc = '=';
+						fc = BLEFT * 2;
 						break;
 					default:
+						fc = 0;
 						break;
 					}
+					cp = cp->next;
 				}
-				if (tp->tbl.cols[ic].spacing) {
-					(*tp->letter)(tp, fc == ' ' ? '|' :
-					    vert ? '+' : fc);
-					tp->viscol++;
+				if (cp != NULL) {
+					switch (cp->pos) {
+					case TBL_CELL_HORIZ:
+						fc += BRIGHT;
+						break;
+					case TBL_CELL_DHORIZ:
+						fc += BRIGHT * 2;
+						break;
+					default:
+						break;
+					}
 				}
+				if (tp->tbl.cols[ic].spacing)
+					tbl_direct_border(tp, fc +
+					    BUP * uvert + BDOWN * dvert, 1);
+
+				if (tp->enc == TERMENC_UTF8)
+					uvert = dvert = 0;
 
-				if (fc != ' ') {
+				if (fc != 0) {
 					if (cp != NULL &&
 					    cp->pos == TBL_CELL_HORIZ)
-						fc = '-';
+						fc = BHORIZ;
 					else if (cp != NULL &&
 					    cp->pos == TBL_CELL_DHORIZ)
-						fc = '=';
+						fc = BHORIZ * 2;
 					else
-						fc = ' ';
+						fc = 0;
 				}
 				if (tp->tbl.cols[ic].spacing > 2 &&
-				    (vert > 1 || fc != ' ')) {
-					(*tp->letter)(tp, fc == ' ' ? '|' :
-					    vert > 1 ? '+' : fc);
-					tp->viscol++;
-				}
+				    (uvert > 1 || dvert > 1 || fc != 0))
+					tbl_direct_border(tp, fc +
+					    BUP * (uvert > 1) +
+					    BDOWN * (dvert > 1), 1);
 			}
 		}
 
 		/* Print the vertical frame at the end of each row. */
 
-		fc = '\0';
-		if ((sp->layout->last->vert &&
-		     sp->layout->last->col + 1 == sp->opts->cols) ||
-		    (sp->next != NULL &&
-		     sp->next->layout->last->vert &&
-		     sp->next->layout->last->col + 1 == sp->opts->cols) ||
-		    (sp->prev != NULL &&
-		     sp->prev->layout->last->vert &&
-		     sp->prev->layout->last->col + 1 == sp->opts->cols &&
-		     (horiz || (IS_HORIZ(sp->layout->last) &&
-		      !IS_HORIZ(sp->prev->layout->last)))) ||
-		    (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
-			fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|';
-		else if (horiz && sp->opts->rvert)
-			fc = '-';
-		if (fc != '\0') {
+		uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 :
+		    sp->opts->opts & TBL_OPT_BOX ? 1 : 0;
+		if (sp->pos == TBL_SPAN_DATA &&
+		    uvert < sp->layout->last->vert &&
+		    sp->layout->last->col + 1 == sp->opts->cols)
+			uvert = dvert = sp->layout->last->vert;
+		if (sp->next != NULL &&
+		    dvert < sp->next->layout->last->vert &&
+		    sp->next->layout->last->col + 1 == sp->opts->cols)
+			dvert = sp->next->layout->last->vert;
+		if (sp->prev != NULL &&
+		    uvert < sp->prev->layout->last->vert &&
+		    sp->prev->layout->last->col + 1 == sp->opts->cols &&
+		    (horiz || (IS_HORIZ(sp->layout->last) &&
+		     !IS_HORIZ(sp->prev->layout->last))))
+			uvert = sp->prev->layout->last->vert;
+		line = sp->pos == TBL_SPAN_DHORIZ ||
+		    (sp->layout->last->pos == TBL_CELL_DHORIZ &&
+		     sp->layout->last->col + 1 == sp->opts->cols) ? 2 :
+		    sp->pos == TBL_SPAN_HORIZ ||
+		    (sp->layout->last->pos == TBL_CELL_HORIZ &&
+		     sp->layout->last->col + 1 == sp->opts->cols) ? 1 : 0;
+		fc = BUP * uvert + BDOWN * dvert + BLEFT * line;
+		if (uvert > 0 || dvert > 0 || (horiz && sp->opts->rvert)) {
 			if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
 			    sp->layout->last->col + 1 < sp->opts->cols)) {
 				tp->tcol++;
@@ -412,7 +541,7 @@ term_tbl(struct termp *tp, const struct 
 				    tp->tcol->offset > tp->viscol ?
 				    tp->tcol->offset - tp->viscol : 1);
 			}
-			(*tp->letter)(tp, fc);
+			tbl_direct_border(tp, fc, 1);
 		}
 		(*tp->endline)(tp);
 		tp->viscol = 0;
@@ -429,11 +558,12 @@ term_tbl(struct termp *tp, const struct 
 	tp->tcol->rmargin = tp->maxrmargin;
 	if (sp->next == NULL) {
 		if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
-			tbl_hrule(tp, sp, 2);
+			tbl_hrule(tp, sp, HRULE_UP | HRULE_ENDS);
 			tp->skipvsp = 1;
 		}
-		if (sp->opts->opts & TBL_OPT_DBOX) {
-			tbl_hrule(tp, sp, 3);
+		if (tp->enc == TERMENC_ASCII &&
+		    sp->opts->opts & TBL_OPT_DBOX) {
+			tbl_hrule(tp, sp, HRULE_DBOX | HRULE_ENDS);
 			tp->skipvsp = 2;
 		}
 		assert(tp->tbl.cols);
@@ -443,80 +573,87 @@ term_tbl(struct termp *tp, const struct 
 	} else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX &&
 	    (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA ||
 	     sp->next->next != NULL))
-		tbl_hrule(tp, sp, 1);
+		tbl_hrule(tp, sp,
+		    HRULE_DATA | HRULE_DOWN | HRULE_UP | HRULE_ENDS);
 
 	tp->flags &= ~TERMP_NONOSPACE;
 }
 
-/*
- * Kinds of horizontal rulers:
- * 0: inside the table (single or double line with crossings)
- * 1: inside the table (single or double line with crossings and ends)
- * 2: inner frame (single line with crossings and ends)
- * 3: outer frame (single line without crossings with ends)
- */
 static void
-tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
+tbl_hrule(struct termp *tp, const struct tbl_span *sp, int flags)
 {
 	const struct tbl_cell *cp, *cpn, *cpp;
 	const struct roffcol *col;
-	int	 vert;
-	char	 cross, line, stdcross, stdline;
-
-	stdline = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
-	stdcross = (kind < 3) ? '+' : '-';
+	int cross, dvert, line, linewidth, uvert;
 
 	cp = sp->layout->first;
-	cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first;
-	if (cpp == cp)
-		cpp = NULL;
-	cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first;
-	if (cpn == cp)
-		cpn = NULL;
-	if (kind)
-		term_word(tp,
-		    cpn == NULL || cpn->pos != TBL_CELL_DOWN ? "+" : "|");
+	cpn = cpp = NULL;
+	if (flags & HRULE_DATA) {
+		linewidth = sp->pos == TBL_SPAN_DHORIZ ? 2 : 1;
+		cpn = sp->next == NULL ? NULL : sp->next->layout->first;
+		if (cpn == cp)
+			cpn = NULL;
+	} else
+		linewidth = tp->enc == TERMENC_UTF8 &&
+		    sp->opts->opts & TBL_OPT_DBOX ? 2 : 1;
+	if (tp->viscol == 0) {
+		(*tp->advance)(tp, tp->tcols->offset);
+		tp->viscol = tp->tcols->offset;
+	}
+	if (flags & HRULE_ENDS)
+		tbl_direct_border(tp, linewidth * (BRIGHT +
+		    (flags & (HRULE_UP | HRULE_DBOX) ? BUP : 0) +
+		    (flags & (HRULE_DOWN | HRULE_DBOX) ? BDOWN : 0)), 1);
+	else {
+		cpp = sp->prev == NULL ? NULL : sp->prev->layout->first;
+		if (cpp == cp)
+			cpp = NULL;
+	}
 	for (;;) {
 		col = tp->tbl.cols + cp->col;
-		if (cpn == NULL || cpn->pos != TBL_CELL_DOWN) {
-			line = stdline;
-			cross = stdcross;
-		} else {
-			line = ' ';
-			cross = (kind < 3) ? '|' : ' ';
-		}
-		tbl_char(tp, line, col->width + col->spacing / 2);
-		vert = cp->vert;
+		line = cpn == NULL || cpn->pos != TBL_CELL_DOWN ?
+		    BHORIZ * linewidth : 0;
+		tbl_direct_border(tp, line, col->width + col->spacing / 2);
+		uvert = dvert = 0;
+		if (flags & HRULE_UP &&
+		    (tp->enc == TERMENC_ASCII || sp->pos == TBL_SPAN_DATA ||
+		     (sp->prev != NULL && sp->prev->layout == sp->layout)))
+			uvert = cp->vert;
+		if (flags & HRULE_DOWN)
+			dvert = cp->vert;
 		if ((cp = cp->next) == NULL)
-			 break;
+			break;
 		if (cpp != NULL) {
-			if (vert < cpp->vert)
-				vert = cpp->vert;
+			if (uvert < cpp->vert)
+				uvert = cpp->vert;
 			cpp = cpp->next;
 		}
 		if (cpn != NULL) {
-			if (vert < cpn->vert)
-				vert = cpn->vert;
+			if (dvert < cpn->vert)
+				dvert = cpn->vert;
 			cpn = cpn->next;
 		}
-		if (cpn == NULL || cpn->pos != TBL_CELL_DOWN) {
-			line = stdline;
-			cross = stdcross;
-		} else
-			line = ' ';
-		if (sp->opts->opts & TBL_OPT_ALLBOX && !vert)
-			vert = 1;
+		if (sp->opts->opts & TBL_OPT_ALLBOX) {
+			if (flags & HRULE_UP && uvert == 0)
+				uvert = 1;
+			if (flags & HRULE_DOWN && dvert == 0)
+				dvert = 1;
+		}
+		cross = BHORIZ * linewidth + BUP * uvert + BDOWN * dvert;
 		if (col->spacing)
-			tbl_char(tp, vert ? cross : line, 1);
+			tbl_direct_border(tp, cross, 1);
 		if (col->spacing > 2)
-			tbl_char(tp, vert > 1 ? cross : line, 1);
+			tbl_direct_border(tp, tp->enc == TERMENC_ASCII &&
+			    (uvert > 1 || dvert > 1) ? cross : line, 1);
 		if (col->spacing > 4)
-			tbl_char(tp, line, (col->spacing - 3) / 2);
+			tbl_direct_border(tp, line, (col->spacing - 3) / 2);
 	}
-	if (kind) {
-		term_word(tp,
-		    cpn == NULL || cpn->pos != TBL_CELL_DOWN ? "+" : "|");
-		term_flushln(tp);
+	if (flags & HRULE_ENDS) {
+		tbl_direct_border(tp, linewidth * (BLEFT +
+		    (flags & (HRULE_UP | HRULE_DBOX) ? BUP : 0) +
+		    (flags & (HRULE_DOWN | HRULE_DBOX) ? BDOWN : 0)), 1);
+		(*tp->endline)(tp);
+		tp->viscol = 0;
 	}
 }
 
@@ -527,10 +664,10 @@ tbl_data(struct termp *tp, const struct 
 {
 	switch (cp->pos) {
 	case TBL_CELL_HORIZ:
-		tbl_char(tp, '-', col->width);
+		tbl_fill_border(tp, BHORIZ, col->width);
 		return;
 	case TBL_CELL_DHORIZ:
-		tbl_char(tp, '=', col->width);
+		tbl_fill_border(tp, BHORIZ * 2, col->width);
 		return;
 	default:
 		break;
@@ -544,11 +681,11 @@ tbl_data(struct termp *tp, const struct 
 		return;
 	case TBL_DATA_HORIZ:
 	case TBL_DATA_NHORIZ:
-		tbl_char(tp, '-', col->width);
+		tbl_fill_border(tp, BHORIZ, col->width);
 		return;
 	case TBL_DATA_NDHORIZ:
 	case TBL_DATA_DHORIZ:
-		tbl_char(tp, '=', col->width);
+		tbl_fill_border(tp, BHORIZ * 2, col->width);
 		return;
 	default:
 		break;
@@ -573,18 +710,48 @@ tbl_data(struct termp *tp, const struct 
 }
 
 static void
-tbl_char(struct termp *tp, char c, size_t len)
+tbl_fill_string(struct termp *tp, const char *cp, size_t len)
+{
+	size_t	 i, sz;
+
+	sz = term_strlen(tp, cp);
+	for (i = 0; i < len; i += sz)
+		term_word(tp, cp);
+}
+
+static void
+tbl_fill_char(struct termp *tp, char c, size_t len)
 {
-	size_t		i, sz;
-	char		cp[2];
+	char	 cp[2];
 
 	cp[0] = c;
 	cp[1] = '\0';
+	tbl_fill_string(tp, cp, len);
+}
 
-	sz = term_strlen(tp, cp);
+static void
+tbl_fill_border(struct termp *tp, int c, size_t len)
+{
+	char	 buf[12];
 
-	for (i = 0; i < len; i += sz)
-		term_word(tp, cp);
+	if ((c = borders_locale[c]) > 127) {
+		(void)snprintf(buf, sizeof(buf), "\\[u%04x]", c);
+		tbl_fill_string(tp, buf, len);
+	} else
+		tbl_fill_char(tp, c, len);
+}
+
+static void
+tbl_direct_border(struct termp *tp, int c, size_t len)
+{
+	size_t	 i, sz;
+
+	c = borders_locale[c];
+	sz = (*tp->width)(tp, c);
+	for (i = 0; i < len; i += sz) {
+		(*tp->letter)(tp, c);
+		tp->viscol += sz;
+	}
 }
 
 static void
@@ -624,9 +791,9 @@ tbl_literal(struct termp *tp, const stru
 		break;
 	}
 
-	tbl_char(tp, ASCII_NBRSP, padl);
+	tbl_fill_char(tp, ASCII_NBRSP, padl);
 	tbl_word(tp, dp);
-	tbl_char(tp, ASCII_NBRSP, padr);
+	tbl_fill_char(tp, ASCII_NBRSP, padr);
 }
 
 static void
@@ -687,13 +854,13 @@ tbl_number(struct termp *tp, const struc
 	} else if (col->width > totsz)
 		padl = (col->width - totsz) / 2;
 
-	tbl_char(tp, ASCII_NBRSP, padl);
+	tbl_fill_char(tp, ASCII_NBRSP, padl);
 	tbl_word(tp, dp);
 
 	/* Pad right to fill the column.  */
 
 	if (col->width > padl + totsz)
-		tbl_char(tp, ASCII_NBRSP, col->width - padl - totsz);
+		tbl_fill_char(tp, ASCII_NBRSP, col->width - padl - totsz);
 }
 
 static void
Index: TODO
===================================================================
RCS file: /home/cvs/mandoc/mandoc/TODO,v
retrieving revision 1.278
retrieving revision 1.279
diff -LTODO -LTODO -u -p -r1.278 -r1.279
--- TODO
+++ TODO
@@ -190,15 +190,6 @@ are mere guesses, and some may be wrong.
 - look what Joerg Schilling manual pages use
   Thu, 19 Mar 2015 18:31:48 +0100
 
-- use Unicode U+2500 to U+256C for table borders
-  in tbl(7) -Tutf-8 output
-  suggested by bentley@  Tue, 14 Oct 2014 04:10:55 -0600
-  loc *  exist **  algo *  size *  imp **
-
-- implement table borders in HTML output
-  pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
-  loc *  exist *  algo **  size **  imp **
-
 --- missing eqn features -----------------------------------------------
 
 - In a matrix, break the output line after each matrix line.
--
 To unsubscribe send an email to discuss+unsubscribe@mandoc.bsd.lv

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-14 10:10 tbl(7) output in -Tlocale Anthony J. Bentley
2014-10-14 13:56 ` Ingo Schwarze
2018-11-28  5:11 ` Ingo Schwarze

discuss@mandoc.bsd.lv

Archives are clonable: git clone --mirror http://inbox.vuxu.org/mandoc-discuss

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://inbox.vuxu.org/vuxu.archive.mandoc.discuss


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git