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