an alternative commandline interface to notmuch
authorPeter John Hartman <peterjohnhartman@gmail.com>
Sat, 1 Oct 2011 14:29:06 +0000 (10:29 +2000)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:39:32 +0000 (09:39 -0800)
c0/4f99a530ed6c36dadf6316149e3c0714783362 [new file with mode: 0644]

diff --git a/c0/4f99a530ed6c36dadf6316149e3c0714783362 b/c0/4f99a530ed6c36dadf6316149e3c0714783362
new file mode 100644 (file)
index 0000000..0670569
--- /dev/null
@@ -0,0 +1,370 @@
+Return-Path: <peterjohnhartman@gmail.com>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+       by olra.theworths.org (Postfix) with ESMTP id A0742429E25\r
+       for <notmuch@notmuchmail.org>; Sat,  1 Oct 2011 07:29:11 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.799\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5\r
+       tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
+       FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+       by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+       with ESMTP id WRr-rh2U9lHW for <notmuch@notmuchmail.org>;\r
+       Sat,  1 Oct 2011 07:29:10 -0700 (PDT)\r
+Received: from mail-qw0-f53.google.com (mail-qw0-f53.google.com\r
+       [209.85.216.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
+       (No client certificate requested)\r
+       by olra.theworths.org (Postfix) with ESMTPS id 9D017431FB6\r
+       for <notmuch@notmuchmail.org>; Sat,  1 Oct 2011 07:29:10 -0700 (PDT)\r
+Received: by qafi31 with SMTP id i31so1117678qaf.26\r
+       for <notmuch@notmuchmail.org>; Sat, 01 Oct 2011 07:29:09 -0700 (PDT)\r
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;\r
+       h=date:from:to:subject:message-id:mime-version:content-type\r
+       :content-disposition:content-transfer-encoding:user-agent;\r
+       bh=7Z16G0kWwpuK+c9yPTmsU3umWxcJOK2cpgqZtNsGHDg=;\r
+       b=ACef3DvQsWtCogz+nqTVnPumDuCW905jniOlWQPAyhz/uth5wafaHjCKepatrFs7zC\r
+       nEogpRCssCOyHKEPHS7s8uFk27A6LYIXxIjXJ6PJ4VbPUYxb5cup+cjdUqRQI8i4V+Ig\r
+       uvDsTyzZQWnZZoB1N8wtDT7ZFgEj2LciGR7cU=\r
+Received: by 10.224.203.196 with SMTP id fj4mr9875374qab.362.1317479348788;\r
+       Sat, 01 Oct 2011 07:29:08 -0700 (PDT)\r
+Received: from localhost (ip-64-134-98-119.public.wayport.net.\r
+ [64.134.98.119])      by mx.google.com with ESMTPS id\r
+ du5sm9189819qab.14.2011.10.01.07.29.07        (version=SSLv3 cipher=OTHER); Sat, 01\r
+ Oct 2011 07:29:08 -0700 (PDT)\r
+Date: Sat, 1 Oct 2011 10:29:06 -0400\r
+From: Peter John Hartman <peterjohnhartman@gmail.com>\r
+To: notmuch@notmuchmail.org\r
+Subject: an alternative commandline interface to notmuch\r
+Message-ID: <20111001142906.GA635@leneee.sbx07386.newyony.wayport.net>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain; charset=iso-8859-1\r
+Content-Disposition: inline\r
+Content-Transfer-Encoding: 8bit\r
+User-Agent: Mutt/1.5.21 (2010-09-15)\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+       <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Sat, 01 Oct 2011 14:29:11 -0000\r
+\r
+Hi folks,\r
+\r
+Rafa released slmenu, a dmenu-clone that runs on the commandline, and I\r
+contributed a couple of patches (verticality and tokens) to make it work\r
+nice with notmuch.  So far, I'm pretty happy.  To get slmenu:\r
+\r
+hg clone http://hg.suckless.org/slmenu\r
+\r
+You'll need to apply the patch at the bottom of this e-mail[1].\r
+You'll also want to use the shell script (nmsl) at the bottom of this e-mail[2].\r
+\r
+How it works:\r
+\r
+Basically, it pipes output (after being mangled a bit) from notmuch search\r
+into slmenu/dmenu (so you can select the thread) and then sends that output \r
+to mutt, either via mbox (if notmuch is hosted remote) or maildir (if local).\r
+It also allows you to prepend an entry with v (tag viewed), t +tag (tag\r
+tag), x (tag x-del).\r
+\r
+All this will be at:\r
+\r
+http://durandus.trilidun.org/durandus/code/notmuch-slmenu/\r
+Best,\r
+Peter\r
+\r
+\r
+\r
+[1] token.patch to slmenu\r
+\r
+diff -r 7896c4e3bf21 slmenu.c\r
+--- a/slmenu.c Thu Sep 29 12:45:34 2011 +0200\r
++++ b/slmenu.c Sat Oct 01 10:11:29 2011 -0400\r
+@@ -36,7 +36,7 @@\r
+ static void   drawmenu(void);\r
+ static char  *fstrstr(const char*, const char*);\r
+ static void   insert(const char*, ssize_t);\r
+-static void   match(int);\r
++static void   match(void); \r
+ static size_t nextrune(int);\r
+ static void   readstdin(void);\r
+ static int    run(void);\r
+@@ -60,10 +60,10 @@\r
\r
+ void\r
+ appenditem(Item *item, Item **list, Item **last) {\r
+-      if(!*last)\r
++      if(*last)\r
++              (*last)->right = item;\r
++      else\r
+               *list = item;\r
+-      else\r
+-              (*last)->right = item;\r
+       item->left = *last;\r
+       item->right = NULL;\r
+       *last = item;\r
+@@ -132,13 +132,17 @@\r
+       Item *item;\r
+       int rw;\r
\r
++      fprintf(stderr, "\033[H"); \r
++      fprintf(stderr, "\033[2J"); \r
++\r
+       /* use default colors */\r
+       fprintf(stderr, "\033[0m");\r
++/*    setupterm(); \r
++      putp(clear_screen);  */\r
\r
+       /* place cursor in first column, clear it */\r
+       fprintf(stderr, "\033[0G");\r
+       fprintf(stderr, "\033[K");\r
+-\r
+       if(prompt)\r
+               drawtext(prompt, promptw-4, C_Reverse);\r
\r
+@@ -188,9 +192,10 @@\r
+       if(n > 0)\r
+               memcpy(&text[cursor], str, n);\r
+       cursor += n;\r
+-      match(n > 0 && text[cursor] == '\0');\r
++      match();\r
+ }\r
\r
++/*\r
+ void\r
+ match(int sub) {\r
+       size_t len = strlen(text);\r
+@@ -231,6 +236,60 @@\r
+       curr = sel = matches;\r
+       calcoffsets();\r
+ }\r
++*/\r
++\r
++void\r
++match(void) {\r
++      static char **tokv = NULL;\r
++      static int tokn = 0;\r
++\r
++      char buf[sizeof text], *s;\r
++      int i, tokc = 0;\r
++      size_t len;\r
++      Item *item, *lprefix, *lsubstr, *prefixend, *substrend;\r
++      \r
++      strcpy(buf, text);\r
++      for(s = strtok(buf, " "); s; tokv[tokc-1] = s, s = strtok(NULL, " "))\r
++              if(++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))\r
++                      die("Can't realloc.");\r
++/*                    fprintf("cannot realloc %u bytes\n", tokn * sizeof *tokv); */\r
++      len = tokc ? strlen(tokv[0]) : 0;\r
++      \r
++      matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;\r
++      for(item = items; item && item->text; item++) {\r
++              for(i = 0; i < tokc; i++)\r
++                      if(!fstrstr(item->text, tokv[i]))\r
++                              break;\r
++              if (i != tokc)\r
++                      continue;\r
++              if(!tokc || !fstrncmp(tokv[0], item->text, len+1))\r
++                      appenditem(item, &matches, &matchend);\r
++              else if(!strncmp(tokv[0], item->text, len))\r
++                      appenditem(item, &lprefix, &prefixend);\r
++              else\r
++                      appenditem(item, &lsubstr, &substrend);\r
++      }\r
++      if(lprefix) {\r
++              if(matches) {\r
++                      matchend->right = lprefix;\r
++                      lprefix->left = matchend;\r
++              }\r
++              else\r
++                      matches = lprefix;\r
++              matchend = prefixend;\r
++      }\r
++      if(lsubstr) {\r
++              if(matches) {\r
++                      matchend->right = lsubstr;\r
++                      lsubstr->left = matchend;\r
++              }\r
++              else\r
++                      matches = lsubstr;\r
++              matchend = substrend;\r
++      }\r
++      curr = sel = matches;\r
++      calcoffsets();\r
++}\r
\r
+ size_t\r
+ nextrune(int inc) {\r
+@@ -371,7 +430,7 @@\r
+               case CONTROL('J'):\r
+                       if(sel) strncpy(text, sel->text, sizeof text); /* Complete the input first, when hitting return */\r
+                       cursor = strlen(text);\r
+-                      match(TRUE);\r
++                      match();\r
+                       drawmenu();\r
+                       /* fallthrough */\r
+               case CONTROL(']'):\r
+@@ -441,11 +500,11 @@\r
+                               break;\r
+                       strncpy(text, sel->text, sizeof text);\r
+                       cursor = strlen(text);\r
+-                      match(TRUE);\r
++                      match(); \r
+                       break;\r
+               case CONTROL('K'):\r
+                       text[cursor] = '\0';\r
+-                      match(FALSE);\r
++                      match(); \r
+                       break;\r
+               case CONTROL('U'):\r
+                       insert(NULL, 0 - cursor);\r
+@@ -514,7 +573,7 @@\r
+       lines=MIN(MAX(lines, 0), mh);\r
+       promptw=(prompt?textw(prompt):0);\r
+       inputw=MIN(inputw, mw/3);\r
+-      match(FALSE);\r
++      match();\r
+       if(barpos!=0) resetline();\r
+       drawmenu();\r
+ }\r
+@@ -542,7 +601,7 @@\r
+                       puts("slmenu, © 2011 slmenu engineers, see LICENSE for details");\r
+                       exit(EXIT_SUCCESS);\r
+               }\r
+-              else if(!strcmp(argv[i], "-i"))\r
++              else if(!strcmp(argv[i], "-i")) \r
+                       fstrncmp = strncasecmp;\r
+               else if(!strcmp(argv[i], "-t"))\r
+                       barpos=1;\r
+\r
+[2] nmsl shell script\r
+#!/bin/sh\r
+# Copyright (c) Peter John Hartman (peterjohnhartman at gmail dot com)\r
+#\r
+# * Permission to use, copy, modify, and distribute this software for any\r
+# * purpose with or without fee is hereby granted, provided that the above\r
+# * copyright notice and this permission notice appear in all copies.\r
+# *\r
+# * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\r
+# * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\r
+# * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\r
+# * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r
+# * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER\r
+# * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING\r
+# * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+\r
+maildir="/tmp/maildir"\r
+slmenu="slmenu -i -l 30 -t -p [vtx]:"\r
+#slmenu="dmenu -i -l 30 -p [vtx]:"\r
+notmuch="/usr/local/bin/notmuch"\r
+use_maildir=1\r
+usage() {\r
+  cat << EOF\r
+  usage: $0 options\r
+\r
+  Example: nmsl `nmdate 3 days ago`..`nmdate yesterday` tag:inbox\r
+  Example: nmsl tag:inbox and tag:unread\r
+\r
+  nmdate = echo $(date +%s -d "$*")\r
+\r
+  OPTIONS:\r
+     -h      Show this message\r
+     -s      Use ssh\r
+EOF\r
+}\r
+\r
+while getopts "hsd:" OPTION\r
+do\r
+  case $OPTION in\r
+    h) \r
+      usage\r
+      exit 1\r
+      ;;\r
+    s)\r
+      notmuch="ssh trillap /usr/local/bin/notmuch"\r
+      use_maildir=0\r
+      ;;\r
+  esac\r
+done\r
+\r
+shift $((OPTIND-1))\r
+search=$@\r
+\r
+if [[ $search == "" ]]; then\r
+  search="tag:inbox and tag:unread"\r
+fi\r
+\r
+res=$($notmuch search $search |\\r
+  sed -r 's/([^ ]*) ([^[]*)([^]]*\]) ([^;]*); (.*) (\([^)]*\))/\2\5; \4 \3 \6 \1/' |\\r
+  $slmenu)\r
+\r
+if [[ $res != "" ]]; then\r
+       option=$(echo $res | cut -d' ' -f1)\r
+\r
+       case "$option" in\r
+         x) \r
+         # delete\r
+                thread=$(echo $res | awk -F' ' '{print $NF}')\r
+               notmuch tag -unread +x-del $thread\r
+               nmsl $*\r
+         ;;\r
+         t)\r
+         # tag;\r
+                thread=$(echo $res | awk -F' ' '{print $NF}')\r
+               notmuch tag $(echo $res | cut -d' ' -f2) -inbox $thread\r
+               nmsl $*\r
+         ;;\r
+         v)\r
+         # quick -unread\r
+                thread=$(echo $res | awk -F' ' '{print $NF}')\r
+               notmuch tag -unread $thread\r
+               nmsl $*\r
+         ;;\r
+         *)\r
+                thread=$(echo $res | awk -F' ' '{print $NF}')\r
+                clear\r
+               if [[ $use_maildir -eq 1 ]]; then\r
+                       rm -rf $maildir\r
+                       mkdir $maildir\r
+                       mkdir $maildir/cur\r
+                       mkdir $maildir/new\r
+                       mkdir $maildir/tmp\r
+                       $notmuch search --output=files $thread | sed -e 's: :\\ :g' |\\r
+                               xargs --no-run-if-empty ln -s -t $maildir/cur/\r
+                       mutt -f $maildir\r
+               else\r
+                       $notmuch show --format=mbox $thread > /tmp/nmsearch.$$\r
+                       mutt -f /tmp/nmsearch.$$\r
+                       rm -f -- /tmp/nmsearch.$$\r
+               fi\r
+               nmsl $*\r
+         ;;\r
+       esac\r
+fi\r
+\r
+clear\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+-- \r
+sic dicit magister P\r
+University of Toronto / Fordham University\r
+Collins Hall B06; Office Hours TF10-12\r
+http://individual.utoronto.ca/peterjh\r
+gpg  1024D/ED6EF59B  (7D1A 522F D08E 30F6 FA42  B269 B860 352B ED6E F59B)\r
+gpg --keyserver pgp.mit.edu --recv-keys ED6EF59B\r