shithub: Nail

Download patch

ref: ed0a057803a11e12326211123433100647d6c8f9
parent: 8c81b45793912daa0c3a27eba1859b3b42bfeb38
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Nov 21 15:29:21 EST 2020

mbox: custom format strings.

--- a/mbox.c
+++ b/mbox.c
@@ -26,6 +26,7 @@
 
 char	*maildir	= "/mail/fs";
 char	*mailbox	= "mbox";
+char	*listfmt	= "%>40s\t<%f>";
 Mesg	dead = {.messageid="", .hash=42};
 
 Reprog	*addrpat;
@@ -435,32 +436,146 @@
 	qsort(mbox.mesg, mbox.nmesg, sizeof(Mesg*), cmpmesg);	
 }
 
+static char*
+getflag(Mesg *m)
+{
+	char* flag;
+
+	flag = "★";
+	if(m->flags & Fseen)	flag = " ";
+	if(m->flags & Fresp)	flag = "←";
+	if(m->flags & Fdel)	flag = "∉";
+	if(m->flags & Ftodel)	flag = "∉";
+	return flag;
+}
+
 static void
-showmesg(Biobuf *bfd, Mesg *m, int depth, int recurse)
+printw(Biobuf *bp, char *s, int width)
 {
-	char *sep, *flag, *dots;
-	int i, width;
+	char *dots;
 
-	if(!(m->state & Sdummy)){
+	if(width <= 0)
+		Bprint(bp, "%s", s);
+	else{
 		dots = "";
-		flag = "★";
-		sep = depth ? "\t" : "";
-		width = depth ? Subjlen - 4 : Subjlen;
-		if(m->flags & Fseen)	flag = " ";
-		if(m->flags & Fresp)	flag = "←";
-		if(m->flags & Fdel)	flag = "∉";
-		if(m->flags & Ftodel)	flag = "∉";
-		if(utflen(m->subject) > Subjlen){
+		if(utflen(s) > width){
 			width -= 3;
 			dots = "...";
 		}
+		Bprint(bp, "%*.*s%s", -width, width, s, dots);
+	}
+}
 
-		Bprint(bfd, "%-6s\t%s %s%*.*s%s\t<%s>\n",
-			m->name,
-			flag, sep, -width, width,
-			m->subject,
-			dots,
-			m->from);
+/*
+ * Message format string:
+ * ======================
+  * %s: subject
+ * %f: from address
+ * %F: name + from address
+ * %t: to address
+ * %c: CC address
+ * %r: replyto address
+ * %[...]: string to display for child messages
+ * %{...}: date format string
+ */
+static void
+fmtmesg(Biobuf *bp, char *fmt, Mesg *m, int depth)
+{
+	char *p, *e, buf[64];
+	int width, i, indent;
+	Tm tm;
+
+	Bprint(bp, "%-6s\t%s ", m->name, getflag(m));
+	for(p = fmt; *p; p++){
+		if(*p != '%'){
+			Bputc(bp, *p);
+			continue;
+		}
+		p++;
+		width = 0;
+		indent = 0;
+		while(*p == '>'){
+			p++;
+			indent++;
+		}
+		while('0'<=*p && *p<='9')
+			width = width * 10 + *p++ - '0';
+		for(i = 0; indent && i < depth; i++){
+			Bputc(bp, '\t');
+			width -= 4;
+			if(indent == 1)
+				break;
+		}
+		switch(*p){
+		case '%':
+			Bprint(bp, "%%");
+			break;
+		case 'i':
+			if(depth > 0)
+				depth = 1;
+		case 'I':
+			for(i = 0; i < depth; i++){
+				if(width>0)
+					Bprint(bp, "%*s", width, "");
+				else
+					Bprint(bp, "\t");
+			}
+			break;
+		case 's':
+			printw(bp, m->subject, width);
+			break;
+		case 'f':
+			printw(bp, m->from, width);
+			break;
+		case 'F':
+			printw(bp, m->fromcolon, width);
+			break;
+		case 't':
+			printw(bp, m->to, width);
+			break;
+		case 'c':
+			printw(bp, m->cc, width);
+			break;
+		case 'r':
+			printw(bp, m->replyto, width);
+			break;
+		case '[':
+			if((e = strchr(p, ']')) == nil)
+				sysfatal("missing closing '}' in %%{");
+			if(e - p >= sizeof(buf) - 1)
+				sysfatal("%%{} contents too long");
+			snprint(buf, sizeof(buf), "%.*s", (int)(e - p), p);
+			if(depth > 0)
+				Bprint(bp, "%s", buf);
+			p = e;
+			break;
+		case '{':
+			p++;
+			if((e = strchr(p, '}')) == nil)
+				sysfatal("missing closing '}' in %%{");
+			if(e - p >= sizeof(buf) - 1)
+				sysfatal("%%{} contents too long");
+			snprint(buf, sizeof(buf), "%.*s", (int)(e - p), p);
+			tmtime(&tm, m->time, nil);
+			Bprint(bp, "%τ", tmfmt(&tm, buf));
+			p = e;
+			break;
+		default:
+			sysfatal("invalid directive '%%%c' in format string", *p);
+			break;
+		}
+	}
+	Bputc(bp, '\n');
+}
+
+
+static void
+showmesg(Biobuf *bfd, Mesg *m, int depth, int recurse)
+{
+	int i;
+
+	if(!(m->state & Sdummy)){
+		fmtmesg(bfd, listfmt, m, depth);
 		depth++;
 	}
 	if(recurse && mbox.view != Vflat)
@@ -858,7 +973,7 @@
 static void
 usage(void)
 {
-	fprint(2, "usage: %s [-T] [-f mailfs] [mbox]\n", argv0);
+	fprint(2, "usage: %s [-T] [-m mailfs] [-s] [-f format] [mbox]\n", argv0);
 	exits("usage");
 }
 
@@ -870,16 +985,19 @@
 	int i;
 
 	mbox.view = Vgroup;
+	doquote = needsrcquote;
+	quotefmtinstall();
+	tmfmtinstall();
 
 	fmtstrinit(&fmt);
 	for(i = 0; i < argc; i++)
-		fmtprint(&fmt, "%s ", argv[i]);
+		fmtprint(&fmt, "%q ", argv[i]);
 	cmd = fmtstrflush(&fmt);
 	if(cmd == nil)
 		sysfatal("out of memory");
 
 	ARGBEGIN{
-	case 'f':
+	case 'm':
 		maildir = EARGF(usage());
 		break;
 	case 'T':
@@ -888,7 +1006,9 @@
 	case 's':
 		sender++;
 		break;
-
+	case 'f':
+		listfmt = EARGF(usage());
+		break;
 	default:
 		usage();
 		break;
@@ -898,10 +1018,6 @@
 		usage();
 	if(argc == 1)
 		mailbox = argv[0];
-
-	doquote = needsrcquote;
-	quotefmtinstall();
-	tmfmtinstall();
 
 	addrpat = regcomp("[^ \t]*@[^ \t]*\\.[^ \t]*");
 	mesgpat = regcomp("[0-9]+(/.*)?");