]> diplodocus.org Git - nmh/commitdiff
Support for sending color escape sequences retrieved from terminfo(5).
authorKen Hornstein <kenh@pobox.com>
Sat, 4 Jan 2014 05:59:38 +0000 (00:59 -0500)
committerKen Hornstein <kenh@pobox.com>
Sat, 4 Jan 2014 05:59:38 +0000 (00:59 -0500)
etc/scan.curses
man/mh-format.man
sbr/fmt_compile.c
sbr/fmt_scan.c

index 67518ac91401ab6f50d0e52a1df8c7f9f6db6949..913f2c010fbcfcb26fab1127a41c98c2826d3e6f 100644 (file)
@@ -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.
index 6c8938a56b62dee75b08152d21fd85558b7cdd21..38d313897e1836cf1ef34649eb9894f185fb6e7e 100644 (file)
@@ -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.
index 2e1a0ff5a03168e0968a7ac8acfce3f73fb5e8df..75adc08e2816f2286c41ebf6360ce025686304bc 100644 (file)
@@ -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;
index 4460c62800def628d1578934c8e5f3fd0c30a41f..fe2a00449410c709eb36b7300d4a41f6bacea648 100644 (file)
@@ -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)