]> 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
 %;
 %;
 %; 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.
 %;
 %; 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.
 %;
 %; 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
 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
 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
 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
 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.
 .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_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
 
 /* 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
  *         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.
  * 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 },
      { "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 }
 };
 
 
      { 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
 /* 
  * 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;
 
        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;
     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). */
               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)
                for (sp = str; *sp; *cp++ = *sp++) continue;
            }
            if (callbacks && callbacks->trace_func)