From: Ken Hornstein Date: Sat, 4 Jan 2014 05:59:38 +0000 (-0500) Subject: Support for sending color escape sequences retrieved from terminfo(5). X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/7086ee95576e95aec1b54ad73c6fa6ead9186a3d?hp=6125f5f8e7f544ccdcecb3d216c9c1035d693b4e Support for sending color escape sequences retrieved from terminfo(5). --- diff --git a/etc/scan.curses b/etc/scan.curses index 67518ac9..913f2c01 100644 --- a/etc/scan.curses +++ b/etc/scan.curses @@ -9,14 +9,15 @@ %; %; %; First, test to see if this is the current message. If it is, then -%; output the bold sequence for this terminal. We use %(zputlit) so the +%; output the standout sequence for this terminal (or the color red). +%; We use %(zputlit) so the %; characters we output don't count against the terminal width. %; -%<(cur)%(zputlit(bold))%>\ +%<(cur)%<(hascolor)%(zputlit(fgcolor red))%|%(zputlit(standout))%>%>\ %; -%; If it's unseen, mark it with an underline +%; If it's unseen, mark it with bold (or the color green) %; -%<(unseen)%(zputlit(underline))%>\ +%<(unseen)%<(hascolor)%(zputlit(fgcolor green))%|%(zputlit(bold))%>%>\ %; %; Next, output the message number. We print it out using 4 digits, right- %; justified, padding with spaces. diff --git a/man/mh-format.man b/man/mh-format.man index 6c8938a5..38d31389 100644 --- a/man/mh-format.man +++ b/man/mh-format.man @@ -298,6 +298,13 @@ putnumf expr print \fInum\fR in a fixed width putlit expr print \fIstr\fR without space compression zputlit expr print \fIstr\fR without space compression; \fIstr\fR must occupy no width on display +bold string set terminal bold mode +underline string set terminal underlined mode +standout string set terminal standout mode +resetterm string reset all terminal attributes +hascolor boolean terminal supports color +fgcolor literal string set terminal foreground color +bgcolor literal string set terminal background color formataddr expr append \fIarg\fR to \fIstr\fR as a (comma separated) address list concataddr expr append \fIarg\fR to \fIstr\fR as a @@ -433,8 +440,29 @@ the str register, but requires that those contents not occupy any output width. It can therefore be used for outputting terminal escape sequences. .PP +There are a limited number of function escapes to output terminal escape +sequences. These sequences are retrieved from the +.IR terminfo (5) +database according to the current terminal setting. The (\fIbold\fR\^), +(\fIunderline\fR\^), and (\fIstandout\fR\^) escapes set bold mode, +underline mode, and standout mode respectively. +.PP +(\fIhascolor\fR\^) +can be used to determine if the current terminal supports color. +(\fIfgcolor\fR\^) and (\fIbgcolor\fR\^) set the foreground and +background colors respectively. Both of these escapes take one literal +argument, the color name, which can be one of: black, red, green, yellow, +blue, magenta, cyan, white. (\fIresetterm\fR\^) resets all terminal +attributes back to their default setting. +.PP +All of these terminal escape should be used in conjunction with +(\fIzputlit\fR\^) (preferred) or (\fIputlit\fR\^), as the normal +(\fputstr\fR\^) function will strip out control characters. +.PP The available output width is kept in an internal register; any output -past this width will be truncated. +past this width will be truncated. The one exception to this is +(\fIzputlit\fR\^) functions will still be executed in case a terminal reset +code is being placed at the end of the line. .SS Special Handling A few functions have different behavior depending on what command they are being invoked from. diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 2e1a0ff5..75adc08e 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -87,6 +87,8 @@ extern struct mailname fmt_mnull; #define TF_STNDOUT 14 /* special - enter underline mode */ #define TF_RESET 15 /* special - reset terminal modes */ #define TF_HASCLR 16 /* special - terminal have color? */ +#define TF_FGCOLR 17 /* special - foreground term color */ +#define TF_BGCOLR 18 /* special - background term color */ /* ftable->flags */ /* NB that TFL_PUTS is also used to decide whether the test @@ -105,7 +107,9 @@ extern struct mailname fmt_mnull; * what maps a particular function name into a format instruction. * type - The type of argument this function expects. Those types are * listed above (with the TF_ prefix). This affects what gets - * placed in the format instruction (the f_un union). + * placed in the format instruction (the f_un union). Also, + * instructions that require special handling are distinguished + * here (TF_MYMBOX is one example). * f_type - The instruction corresponding to this function (from the list * in fmt_compile.h). * extra - Used by some functions to provide extra data to the compiler. @@ -225,10 +229,40 @@ static struct ftable functable[] = { { "standout", TF_STNDOUT,FT_LS_LIT, 0, TFL_PUTS }, { "resetterm", TF_RESET, FT_LS_LIT, 0, TFL_PUTS }, { "hascolor", TF_HASCLR, FT_LV_LIT, 0, 0 }, + { "fgcolor", TF_FGCOLR, FT_LS_LIT, 0, TFL_PUTS }, + { "bgcolor", TF_BGCOLR, FT_LS_LIT, 0, TFL_PUTS }, { NULL, 0, 0, 0, 0 } }; +/* + * A mapping of color names to terminfo color numbers. + * + * There are two sets of terminal-setting codes: 'setaf/setab' (ANSI) and + * 'setf/setb'. Different terminals support different capabilities, so + * we provide a mapping for both. I'm not crazy about putting numbers + * directly in here, but it seems these are well defined by terminfo + * so it should be okay. + */ + +struct colormap { + char *colorname; /* Name of color */ + int ansinum; /* The ANSI escape color number */ + int nonansinum; /* The non-ANSI escape color number */ +}; + +static struct colormap colortable[] = { + { "black", 0, 0 }, + { "red", 1, 4 }, + { "green", 2, 2 }, + { "yellow", 3, 6 }, + { "blue", 4, 1 }, + { "magenta", 5, 5 }, + { "cyan", 6, 3 }, + { "white", 7, 7 }, + { NULL, 0, 0 } +}; + /* * Hash function for component name. The function should be * case independent and probably shouldn't involve a routine @@ -662,6 +696,42 @@ do_func(char *sp) LV(t->f_type, get_term_numcap("colors") > 1); break; + case TF_FGCOLR: + case TF_BGCOLR: { + struct colormap *cmap = colortable; + char *code; + + sp = cp - 1; + while (c && c != ')') + c = *cp++; + cp[-1] = '\0'; + + while (cmap->colorname != NULL) { + if (strcasecmp(sp, cmap->colorname) == 0) + break; + cmap++; + } + + if (cmap->colorname == NULL) { + CERROR("Unknown color name"); + break; + } + + code = get_term_stringparm(t->type == TF_FGCOLR ? "setaf" : "setab", + cmap->ansinum, 0); + + /* + * If this doesn't have anything, try falling back to setf/setb + */ + + if (! code) + code = get_term_stringparm(t->type == TF_FGCOLR ? "setf" : "setb", + cmap->nonansinum, 0); + + LS(t->f_type, code); + break; + } + case TF_NOW: LV(t->f_type, time((time_t *) 0)); break; diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 4460c628..fe2a0044 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -1079,7 +1079,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, there isn't enough room in the buffer for the entire string, skip it completely. Need room for null terminator, and maybe trailing newline (added below). */ - if (cp - scanl + strlen (str) + 1 < max) { + if (str && (cp - scanl + strlen (str) + 1 < max)) { for (sp = str; *sp; *cp++ = *sp++) continue; } if (callbacks && callbacks->trace_func)