Added format support for zputlit function escape. It requires
authorDavid Levine <levinedl@acm.org>
Mon, 5 Nov 2012 02:58:47 +0000 (20:58 -0600)
committerDavid Levine <levinedl@acm.org>
Mon, 5 Nov 2012 02:58:47 +0000 (20:58 -0600)
that the str contents have zero display width, such as for
terminal escape sequences.

Makefile.am
docs/pending-release-notes
etc/scan.highlighted [new file with mode: 0644]
h/fmt_compile.h
man/mh-format.man
man/scan.man
sbr/fmt_compile.c
sbr/fmt_scan.c
test/common.sh.in
test/scan/test-scan
uip/fmtdump.c

index ec21483..f4407a1 100644 (file)
@@ -161,8 +161,8 @@ dist_sysconf_DATA = etc/MailAliases etc/components etc/digestcomps \
                    etc/mhl.format etc/mhl.forward etc/mhl.headers \
                    etc/mhl.reply etc/rcvdistcomps etc/rcvdistcomps.outbox \
                    etc/replcomps etc/replgroupcomps etc/scan.MMDDYY \
-                   etc/scan.YYYYMMDD etc/scan.default etc/scan.mailx \
-                   etc/scan.nomime etc/scan.size etc/scan.time \
+                   etc/scan.YYYYMMDD etc/scan.default etc/scan.highlighted \
+                   etc/scan.mailx etc/scan.nomime etc/scan.size etc/scan.time \
                    etc/scan.timely etc/scan.unseen
 
 ##
index 021c692..fc7728b 100644 (file)
@@ -27,6 +27,8 @@ NEW FEATURES
 - Added -noall/-all switches to sortm(1).  sortm -noall requires
   a messages argument.
 - $PAGER overrides the compiled-in default pager command.
+- Added etc/scan.highlighted format file, as an example of how to
+  highlight/colorize the output of scan(1).
 
 
 ----------------------------
diff --git a/etc/scan.highlighted b/etc/scan.highlighted
new file mode 100644 (file)
index 0000000..134317b
--- /dev/null
@@ -0,0 +1,40 @@
+%; scan.highlighted
+%;
+%; This file shows how to use ANSI escape sequences to highlight a
+%; current message in yellow and any unseen messages in cyan.  It
+%; differs from the default scan format in the two additional lines at
+%; the beginning and the literal sequence at the end.
+%;
+%; To enable use of this format, add "-form scan.highlighted" to your
+%; scan invocation or to your profile (~/.mh_profile), e.g.:
+%;     scan: -form scan.highlighted
+%;
+%; You can optionally copy this file to your MH Path and modify as
+%; desired.
+%;
+%; The mh-sequence(5) man page describes the unseen sequence.
+%;
+%; A more readable approach would add escape sequences to your profile, e.g.:
+%;     normal: \e[m
+%;     bright-black: \e[1;30m
+%;     red: \e[31m
+%;     green: \e[32m
+%;     yellow: \e[33m
+%;     blue: \e[34m
+%;     magenta: \e[35m
+%;     cyan: \e[36m
+%;     bright-white: \e[1;37m
+%;     underlined-white: \e[4;37m
+%; To use them in the format, e.g., at the beginning:
+%;     %<(cur)%(void(profile yellow))%(zputlit)%>\
+%;     %<(unseen)%(void(profile cyan))%(zputlit)%>\
+%; and at the end:
+%;     %(void(profile normal))%(zputlit)
+%;
+%<(cur)%(void(lit \e[33m))%(zputlit)%>\
+%<(unseen)%(void(lit \e[36m))%(zputlit)%>\
+%4(msg)%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\
+%02(mon{date})/%02(mday{date})%<{date} %|*%>\
+%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\
+%<(zero)%17(decode(friendly{from}))%>  \
+%(decode{subject})%<{body}<<%{body}>>%>%(void(lit \e[m))%(zputlit)
index 3cbae02..559f993 100644 (file)
 #define FT_STRF                9       /* "str" as text, filled                   */
 #define FT_STRFW       10      /* "str" as text, filled, width in "value" */
 #define FT_STRLIT      11      /* "str" as text, no space compression     */
-#define FT_PUTADDR     12      /* split and print address line            */
+#define FT_STRLITZ     12      /* literal text with zero display width    */
+#define FT_PUTADDR     13      /* split and print address line            */
 
 /* types that modify the "str" or "value" registers                     */
-#define FT_LS_COMP     13      /* set "str" to component text          */
-#define FT_LS_LIT      14      /* set "str" to literal text            */
-#define FT_LS_GETENV   15      /* set "str" to getenv(text)            */
-#define FT_LS_CFIND    16      /* set "str" to context_find(text)      */
-#define FT_LS_DECODECOMP 17    /* set "str" to decoded component text  */
-#define FT_LS_DECODE   18      /* decode "str" as RFC-2047 header      */
-#define FT_LS_TRIM     19      /* trim trailing white space from "str" */
-#define FT_LV_COMP     20      /* set "value" to comp (as dec. num)    */
-#define FT_LV_COMPFLAG 21      /* set "value" to comp flag word        */
-#define FT_LV_LIT      22      /* set "value" to literal num           */
-#define FT_LV_DAT      23      /* set "value" to dat[n]                */
-#define FT_LV_STRLEN   24      /* set "value" to length of "str"       */
-#define FT_LV_PLUS_L   25      /* set "value" += literal               */
-#define FT_LV_MINUS_L  26      /* set "value" -= literal               */
-#define FT_LV_DIVIDE_L 27      /* set "value" to value / literal       */
-#define FT_LV_MODULO_L 28      /* set "value" to value % literal       */
-#define FT_LV_CHAR_LEFT 29     /* set "value" to char left in output   */
+#define FT_LS_COMP     14      /* set "str" to component text          */
+#define FT_LS_LIT      15      /* set "str" to literal text            */
+#define FT_LS_GETENV   16      /* set "str" to getenv(text)            */
+#define FT_LS_CFIND    17      /* set "str" to context_find(text)      */
+#define FT_LS_DECODECOMP 18    /* set "str" to decoded component text  */
+#define FT_LS_DECODE   19      /* decode "str" as RFC-2047 header      */
+#define FT_LS_TRIM     20      /* trim trailing white space from "str" */
+#define FT_LV_COMP     21      /* set "value" to comp (as dec. num)    */
+#define FT_LV_COMPFLAG 22      /* set "value" to comp flag word        */
+#define FT_LV_LIT      23      /* set "value" to literal num           */
+#define FT_LV_DAT      24      /* set "value" to dat[n]                */
+#define FT_LV_STRLEN   25      /* set "value" to length of "str"       */
+#define FT_LV_PLUS_L   26      /* set "value" += literal               */
+#define FT_LV_MINUS_L  27      /* set "value" -= literal               */
+#define FT_LV_DIVIDE_L 28      /* set "value" to value / literal       */
+#define FT_LV_MODULO_L 29      /* set "value" to value % literal       */
+#define FT_LV_CHAR_LEFT 30     /* set "value" to char left in output   */
 
-#define FT_LS_MONTH    30      /* set "str" to tws month                   */
-#define FT_LS_LMONTH   31      /* set "str" to long tws month              */
-#define FT_LS_ZONE     32      /* set "str" to tws timezone                */
-#define FT_LS_DAY      33      /* set "str" to tws weekday                 */
-#define FT_LS_WEEKDAY  34      /* set "str" to long tws weekday            */
-#define FT_LS_822DATE  35      /* set "str" to 822 date str                */
-#define FT_LS_PRETTY   36      /* set "str" to pretty (?) date str         */
-#define FT_LV_SEC      37      /* set "value" to tws second                */
-#define FT_LV_MIN      38      /* set "value" to tws minute                */
-#define FT_LV_HOUR     39      /* set "value" to tws hour                  */
-#define FT_LV_MDAY     40      /* set "value" to tws day of month          */
-#define FT_LV_MON      41      /* set "value" to tws month                 */
-#define FT_LV_YEAR     42      /* set "value" to tws year                  */
-#define FT_LV_YDAY     43      /* set "value" to tws day of year           */
-#define FT_LV_WDAY     44      /* set "value" to tws weekday               */
-#define FT_LV_ZONE     45      /* set "value" to tws timezone              */
-#define FT_LV_CLOCK    46      /* set "value" to tws clock                 */
-#define FT_LV_RCLOCK   47      /* set "value" to now - tws clock           */
-#define FT_LV_DAYF     48      /* set "value" to tws day flag              */
-#define FT_LV_DST      49      /* set "value" to tws daylight savings flag */
-#define FT_LV_ZONEF    50      /* set "value" to tws timezone flag         */
+#define FT_LS_MONTH    31      /* set "str" to tws month                   */
+#define FT_LS_LMONTH   32      /* set "str" to long tws month              */
+#define FT_LS_ZONE     33      /* set "str" to tws timezone                */
+#define FT_LS_DAY      34      /* set "str" to tws weekday                 */
+#define FT_LS_WEEKDAY  35      /* set "str" to long tws weekday            */
+#define FT_LS_822DATE  36      /* set "str" to 822 date str                */
+#define FT_LS_PRETTY   37      /* set "str" to pretty (?) date str         */
+#define FT_LV_SEC      38      /* set "value" to tws second                */
+#define FT_LV_MIN      39      /* set "value" to tws minute                */
+#define FT_LV_HOUR     40      /* set "value" to tws hour                  */
+#define FT_LV_MDAY     41      /* set "value" to tws day of month          */
+#define FT_LV_MON      42      /* set "value" to tws month                 */
+#define FT_LV_YEAR     43      /* set "value" to tws year                  */
+#define FT_LV_YDAY     44      /* set "value" to tws day of year           */
+#define FT_LV_WDAY     45      /* set "value" to tws weekday               */
+#define FT_LV_ZONE     46      /* set "value" to tws timezone              */
+#define FT_LV_CLOCK    47      /* set "value" to tws clock                 */
+#define FT_LV_RCLOCK   48      /* set "value" to now - tws clock           */
+#define FT_LV_DAYF     49      /* set "value" to tws day flag              */
+#define FT_LV_DST      50      /* set "value" to tws daylight savings flag */
+#define FT_LV_ZONEF    51      /* set "value" to tws timezone flag         */
 
-#define FT_LS_PERS     51      /* set "str" to person part of addr    */
-#define FT_LS_MBOX     52      /* set "str" to mbox part of addr      */
-#define FT_LS_HOST     53      /* set "str" to host part of addr      */
-#define FT_LS_PATH     54      /* set "str" to route part of addr     */
-#define FT_LS_GNAME    55      /* set "str" to group part of addr     */
-#define FT_LS_NOTE     56      /* set "str" to comment part of addr   */
-#define FT_LS_ADDR     57      /* set "str" to mbox@host              */
-#define FT_LS_822ADDR  58      /* set "str" to 822 format addr        */
-#define FT_LS_FRIENDLY 59      /* set "str" to "friendly" format addr */
-#define FT_LV_HOSTTYPE 60      /* set "value" to addr host type       */
-#define FT_LV_INGRPF   61      /* set "value" to addr in-group flag   */
-#define FT_LS_UNQUOTE  62      /* remove RFC 2822 quotes from "str"   */
-#define FT_LV_NOHOSTF  63      /* set "value" to addr no-host flag */
+#define FT_LS_PERS     52      /* set "str" to person part of addr    */
+#define FT_LS_MBOX     53      /* set "str" to mbox part of addr      */
+#define FT_LS_HOST     54      /* set "str" to host part of addr      */
+#define FT_LS_PATH     55      /* set "str" to route part of addr     */
+#define FT_LS_GNAME    56      /* set "str" to group part of addr     */
+#define FT_LS_NOTE     57      /* set "str" to comment part of addr   */
+#define FT_LS_ADDR     58      /* set "str" to mbox@host              */
+#define FT_LS_822ADDR  59      /* set "str" to 822 format addr        */
+#define FT_LS_FRIENDLY 60      /* set "str" to "friendly" format addr */
+#define FT_LV_HOSTTYPE 61      /* set "value" to addr host type       */
+#define FT_LV_INGRPF   62      /* set "value" to addr in-group flag   */
+#define FT_LS_UNQUOTE  63      /* remove RFC 2822 quotes from "str"   */
+#define FT_LV_NOHOSTF  64      /* set "value" to addr no-host flag */
 
 /* Date Coercion */
-#define FT_LOCALDATE   64      /* Coerce date to local timezone */
-#define FT_GMTDATE     65      /* Coerce date to gmt            */
+#define FT_LOCALDATE   65      /* Coerce date to local timezone */
+#define FT_GMTDATE     66      /* Coerce date to gmt            */
 
 /* pre-format processing */
-#define FT_PARSEDATE   66      /* parse comp into a date (tws) struct */
-#define FT_PARSEADDR   67      /* parse comp into a mailaddr struct   */
-#define FT_FORMATADDR  68      /* let external routine format addr    */
-#define FT_CONCATADDR  69      /* formataddr w/out duplicate removal  */
-#define FT_MYMBOX      70      /* do "mymbox" test on comp            */
+#define FT_PARSEDATE   67      /* parse comp into a date (tws) struct */
+#define FT_PARSEADDR   68      /* parse comp into a mailaddr struct   */
+#define FT_FORMATADDR  69      /* let external routine format addr    */
+#define FT_CONCATADDR  70      /* formataddr w/out duplicate removal  */
+#define FT_MYMBOX      71      /* do "mymbox" test on comp            */
 
 /* misc. */            /* ADDTOSEQ only works if you include "options LBL" */
-#define FT_ADDTOSEQ    71      /* add current msg to a sequence       */
+#define FT_ADDTOSEQ    72      /* add current msg to a sequence       */
 
 /* conditionals & control flow (must be last) */
-#define FT_SAVESTR     72      /* save current str reg               */
-#define FT_DONE                73      /* stop formatting                    */
-#define FT_PAUSE       74      /* pause                              */
-#define FT_NOP         75      /* nop                                */
-#define FT_GOTO                76      /* (relative) goto                    */
-#define FT_IF_S_NULL   77      /* test if "str" null                 */
-#define FT_IF_S                78      /* test if "str" non-null             */
-#define FT_IF_V_EQ     79      /* test if "value" = literal          */
-#define FT_IF_V_NE     80      /* test if "value" != literal         */
-#define FT_IF_V_GT     81      /* test if "value" > literal          */
-#define FT_IF_MATCH    82      /* test if "str" contains literal     */
-#define FT_IF_AMATCH   83      /* test if "str" starts with literal  */
-#define FT_S_NULL      84      /* V = 1 if "str" null                */
-#define FT_S_NONNULL   85      /* V = 1 if "str" non-null            */
-#define FT_V_EQ                86      /* V = 1 if "value" = literal         */
-#define FT_V_NE                87      /* V = 1 if "value" != literal        */
-#define FT_V_GT                88      /* V = 1 if "value" > literal         */
-#define FT_V_MATCH     89      /* V = 1 if "str" contains literal    */
-#define FT_V_AMATCH    90      /* V = 1 if "str" starts with literal */
+#define FT_SAVESTR     73      /* save current str reg               */
+#define FT_DONE                74      /* stop formatting                    */
+#define FT_PAUSE       75      /* pause                              */
+#define FT_NOP         76      /* nop                                */
+#define FT_GOTO                77      /* (relative) goto                    */
+#define FT_IF_S_NULL   78      /* test if "str" null                 */
+#define FT_IF_S                79      /* test if "str" non-null             */
+#define FT_IF_V_EQ     80      /* test if "value" = literal          */
+#define FT_IF_V_NE     81      /* test if "value" != literal         */
+#define FT_IF_V_GT     82      /* test if "value" > literal          */
+#define FT_IF_MATCH    83      /* test if "str" contains literal     */
+#define FT_IF_AMATCH   84      /* test if "str" starts with literal  */
+#define FT_S_NULL      85      /* V = 1 if "str" null                */
+#define FT_S_NONNULL   86      /* V = 1 if "str" non-null            */
+#define FT_V_EQ                87      /* V = 1 if "value" = literal         */
+#define FT_V_NE                88      /* V = 1 if "value" != literal        */
+#define FT_V_GT                89      /* V = 1 if "value" > literal         */
+#define FT_V_MATCH     90      /* V = 1 if "str" contains literal    */
+#define FT_V_AMATCH    91      /* V = 1 if "str" starts with literal */
 
 #define IF_FUNCS FT_S_NULL     /* start of "if" functions */
index 7aad129..6d84c97 100644 (file)
@@ -1,4 +1,4 @@
-.TH MH-FORMAT %manext5% "March 24, 2012" "%nmhversion%"
+.TH MH-FORMAT %manext5% "November 4, 2012" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -296,7 +296,8 @@ putnum      expr            print \fInum\fR
 putnumf        expr            print \fInum\fR in a fixed width
 .\" addtoseq literal    add msg to sequence (LBL option)
 putlit expr            print \fIstr\fR without space compression
-nodate string  integer Argument not a date string (0 or 1)
+zputlit        expr            print \fIstr\fR without space compression;
+                       \fIstr\fR must occupy no width on display
 formataddr     expr            append \fIarg\fR to \fIstr\fR as a
                        (comma separated) address list
 concataddr     expr            append \fIarg\fR to \fIstr\fR as a
@@ -424,8 +425,11 @@ the left up to the field width.
 The functions (\fIputnum\fR\^) and
 (\fIputstr\fR\^) are somewhat special: they print their result in the minimum number of characters
 required, and ignore any leading field width argument.  The (\fIputlit\fR\^)
-function outputs the exact contents of str register without any changes
+function outputs the exact contents of the str register without any changes
 such as duplicate space removal or control character conversion.
+The (\fIzputlit\fR\^) similarly outputs the exact contents of the str
+register, but requires that those contents not occupy any output width.
+It can therefore be used for outputting terminal escape sequences.
 .PP
 The available output width is kept in an internal register; any output
 past this width will be truncated.
index 7bca7d2..95cf428 100644 (file)
@@ -1,4 +1,4 @@
-.TH SCAN %manext1% "March 6, 2012" "%nmhversion%"
+.TH SCAN %manext1% "November 4, 2012" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -189,6 +189,12 @@ modification of the message file itself.  This feature is handy for
 scanning a draft folder, as message drafts usually aren't allowed
 to have dates in them.
 .PP
+The
+.B %etcdir%
+directory contains several format files as examples of customized
+.B scan
+output.
+.PP
 .B scan
 will update the
 .B nmh
index ee495f1..1d03b21 100644 (file)
@@ -35,6 +35,8 @@
  *
  * - Add the code in fmt_scan.c to handle your new function.
  *
+ * - Add code to fmtdump.c to display your new function.
+ *
  * - Document the new function in the mh-format(5) man page.
  *
  */
@@ -137,6 +139,7 @@ static struct ftable functable[] = {
      { "putnumf",    TF_EXPR,  FT_NUMF,        0,              0 },
      { "putaddr",    TF_STR,   FT_PUTADDR,     0,              0 },
      { "putlit",     TF_STR,   FT_STRLIT,      0,              0 },
+     { "zputlit",    TF_STR,   FT_STRLITZ,     0,              0 },
      { "void",       TF_NOP,   0,              0,              0 },
 
      { "comp",       TF_COMP,  FT_LS_COMP,     0,              TFL_PUTS },
index 51ba24c..3818b85 100644 (file)
@@ -409,6 +409,25 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat)
            while ((c = *sp++) && cp < ep)
                *cp++ = c;
            break;
+       case FT_STRLITZ: {
+           size_t len = strlen (str);
+
+           /* Don't want to emit part of an escape sequence.  So if
+              there isn't enough room in the buffer for the entire
+              string, skip it completely. */
+           if (cp - scanl + len + 1 < max) {
+               for (sp = str; *sp; *cp++ = *sp++) continue;
+
+               /* This string doesn't count against the width.  So
+                  increase ep the same amount as cp, only if the
+                  scan buffer will always be large enough. */
+               if (ep - scanl + len + 1 < max) {
+                   ep += len;
+               }
+           }
+
+           break;
+       }
        case FT_STRFW:
            adios (NULL, "internal error (FT_STRFW)");
 
@@ -976,6 +995,22 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat)
        fmt++;
     }
 #ifndef JLR
+    /* Emit any trailing sequences of zero display length. */
+    while (fmt->f_type != FT_DONE) {
+       if (fmt->f_type == FT_LS_LIT) {
+           str = fmt->f_text;
+       } else if (fmt->f_type == FT_STRLITZ) {
+           /* Don't want to emit part of an escape sequence.  So if
+              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) {
+               for (sp = str; *sp; *cp++ = *sp++) continue;
+           }
+       }
+       fmt++;
+    }
+
     finished:;
     if (cp > scanl  &&  cp[-1] != '\n') {
        if (cp - scanl < (int) max - 1) {
index a81e156..a25409b 100644 (file)
@@ -193,8 +193,8 @@ EOF
   for f in MailAliases components digestcomps distcomps forwcomps mhl.body \
            mhl.digest mhl.format mhl.forward mhl.headers mhl.reply \
            mhn.defaults rcvdistcomps replcomps replgroupcomps scan.MMDDYY \
-           scan.YYYYMMDD scan.default scan.mailx scan.nomime scan.size \
-           scan.time scan.timely scan.unseen
+           scan.YYYYMMDD scan.default scan.highlighted scan.mailx scan.nomime \
+           scan.size scan.time scan.timely scan.unseen
   do
     cp "${MH_INST_DIR}${sysconfdir}/${f}" "${MH_TEST_DIR}/Mail" || exit 1
   done
index 1c6d949..fb69e29 100755 (executable)
@@ -30,8 +30,30 @@ cat > $expected <<EOF
   10  09/29 Test10             Testing message 10<<This is message number 10 >>
 EOF
 
-scan -width 80 +inbox > $actual || exit 1
+scan +inbox -width 80 > $actual || exit 1
 
 check "$expected" "$actual"
 
+# check highlighting
+cat > $expected <<EOF
+   1  09/29 Test1              Testing message 1<<This is message number 1 >>\e[m
+   2  09/29 Test2              Testing message 2<<This is message number 2 >>\e[m
+   3  09/29 Test3              Testing message 3<<This is message number 3 >>\e[m
+   4  09/29 Test4              Testing message 4<<This is message number 4 >>\e[m
+\e[33m   5+ 09/29 Test5              Testing message 5<<This is message number 5 >>\e[m
+   6  09/29 Test6              Testing message 6<<This is message number 6 >>\e[m
+   7  09/29 Test7              Testing message 7<<This is message number 7 >>\e[m
+   8  09/29 Test8              Testing message 8<<This is message number 8 >>\e[m
+   9  09/29 Test9              Testing message 9<<This is message number 9 >>\e[m
+\e[36m  10  09/29 Test10             Testing message 10<<This is message number 10 >>\e[m
+EOF
+
+printf 'Unseen-Sequence: unseen\n' >> $MH
+mark -sequence cur 5
+mark -sequence unseen 10
+scan -form scan.highlighted -width 80 > $actual || exit 1
+
+check "$expected" "$actual"
+
+
 exit $failed
index 0b3283d..d69fb8c 100644 (file)
@@ -355,6 +355,7 @@ f_typestr(int t)
        case FT_STRFW: return("STRFW");
        case FT_PUTADDR: return("PUTADDR");
        case FT_STRLIT: return("STRLIT");
+       case FT_STRLITZ: return("STRLITZ");
        case FT_LS_COMP: return("LS_COMP");
        case FT_LS_LIT: return("LS_LIT");
        case FT_LS_GETENV: return("LS_GETENV");