Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: mairix+mutt+zsh (Was: outputting quotes in a command)



On Tue, Dec 04, 2007 at 01:15:52PM +0000, Stephane CHAZELAS wrote:
> On Tue, Dec 04, 2007 at 01:54:42PM +0100, Frank Terbeck wrote:
> > Eric Smith <es@xxxxxxxxxxxx>:
> > > I want to output from a script the following command
> > > (obviously where I will have foo bar as variables).
> > > 
> > >  $  mutt -f foo -e 'push "<limit> ~f bar ~d <2w^M"'
> > > Where ^M represents a carriage return
> > 
> > That works here (unless I'm misunderstanding you).
> > Note, that you can use:
> > 
> >   % mutt -f foo -e 'push "<limit> ~f bar ~d <2w<enter>"'
> [...]
> 
> You may also want to consider "mairix" for mail box indexing.
> mairix integrates very well with mutt.
> 
> For those interested, I can share my mairix+zsh+mutt
> customizations (where mairix is invoked within mutt via a zsh
> script that handles a command line with history and completion).
[...]

Ok then, here it is:

In ~/.muttrc, I have:

macro generic S "<enter-command>set my_cmd = \`mutt-mairix\`<return><enter-command>push \$my_cmd<return>"

Where mutt-mairix is the script attached.

mutt-mairix is a wrapper script to mairix that calls an
interactive zsh with "vared" to query the user with search
criteria.

mairix configuration is in ~/.mairixrc as usual. For me,
something like:

base=/home/stephane/Mail
maildir=INBOX...
maildir=Sent Items...
maildir=other-mailboxes...
mfolder=.mairix/mfolder
database=/home/stephane/Mail/.mairix/database

(my mail is in maildir format in ~/Mail).

There's a bit of configuration at the top of mutt-mairix to
match that.

In ~/Mail/.mairix, I also have a .zshrc that customizes the
completion stuff (see attached). It completes using the values
returned by mairix -d (except for body searches for size
reasons).

It completes the f:, a:, n:... stuff. The command lines are
saved in ~/Mail/.mairix/cmdhist, you can use the usual zsh key
binding to look through the history.

It could be tidied up a bit and made more self-contained, but
that works well enough for me as it is.

HTH,
Stephane
#! /bin/sh -
# require a POSIX sh, on those systems where the POSIX sh is not in /bin
# (like Solaris), you may need to adapt the shebang line above
# (/usr/xpg4/bin/sh on Solaris). You also need a terminfo aware "tput",
# ncurses one (the default on most systems) will do.

# wrapper around mairix, the mail indexing/searching utility for mutt.
# in your ~/.muttrc:
# macro generic S "<enter-command>set my_cmd = \`mutt-mairix\`<return><enter-command>push \$my_cmd<return>"
# we're not using <shell-escape> because we want to prompt the user in
# mutt's prompt area and still have mutt's index visible.

mairix_base=~/Mail/.mairix
histfile=$mairix_base/cmdhist

# mairix result folder in mutt folder syntax:
mfolder=+.mairix/mfolder

set -f

# restore stdin/stdout to the terminal, fd 3 goes to mutt's backticks.
exec < /dev/tty 3>&1 > /dev/tty

# save tty settings before modifying them
saved_tty_settings=$(stty -g)

trap '
    printf "\r"; tput ed; tput rc
    printf "<refresh>" >&3
    stty "$saved_tty_settings"
    exit
' INT TERM

# retrieve the size of the screen.
set $(stty size)

# save cursor position:
tput sc

# go to last line of the screen
tput cup "$1" 0

# Clear.
tput ed


# run zsh in interactive mode (for history to work and .zshrc to
# be read).
search=$(
  histfile=$histfile ZDOTDIR=$mairix_base zsh -ic '
  stty sane
  bindkey -e
  send-break() {
    print "<BREAK>"
    kill -HUP $$
  }
  accept-line() {
    print -r -- "$BUFFER"
    print -rs -- "$BUFFER"
    fc -P
    kill -HUP $$
  }
  zle -N accept-line
  zle -N send-break
  fc -p -a "$histfile" 100
  a=; vared -p "Search: " -eh a'
)

args=

case $search in
  ("<BREAK>") ;;
  ("")
    # rebuild the index
    args="$args -F"
    cmd="<refresh>"
    ;;
  (+*)
    # append mode
    args="$args -a ${search#+}"
    cmd="<refresh><change-folder-readonly>$mfolder<return>"
    ;;
  (*)
    args="$args $search"
    cmd="<refresh><change-folder-readonly>$mfolder<return>"
    ;;
esac
mairix $args > /dev/null 3>&- &

# clear our mess
printf '\r'; tput ed

# restore cursor position
tput rc

# and tty settings
stty "$saved_tty_settings"

printf %s "$cmd" >&3
zstyle ':completion:*' completer _expand _complete _ignored _correct _approximate _prefix
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=* l:|=*'
zstyle ':completion:*' max-errors 1 not-numeric
zstyle ':completion:*' menu select=0
zstyle ':completion:*' original true
zstyle ':completion:*' prompt 'correct> '
zstyle ':completion:*' select-prompt '%SScrolling active: current selection at %p%s'
autoload -U compinit
compinit -i

mairix_comp() {
  typeset -gA mairix_comp_cache
  typeset -gA mairix_comp_table
  typeset -ga mairix_comp_flags
  typeset -ga mairix_comp_query
  if ((!$#mairix_comp_cache)); then
    . <(
      mairix -d | awk -F '[<>]' '
	/^Contents of <.*> table/ {
	  if (table != "") print "'\''"
	  table = $2
	  gsub(/ .*/, "", table)
	  if (table == "Body")
	    table = ""
	  else {
	    print "zle -R \"Building completion cache [" table "]\""
	    print "mairix_comp_cache[" table "]='\''"
	  }
	  next
	}
	table == "" {next}
	/^Word/ {
	  word = $(NF-1)
	  if (length(word) < 6) next
	  gsub(/'\''/, "'\''\\'\'\''", word)
	  print word
	}
	END {
	  if (table != "") print "'\''"
	}'
    )
    mairix_comp_flags=(
      s:Message\ Seen
      r:Message\ Replied
      f:Message\ Flagged
    )
    mairix_comp_table=(
      t To
      c Cc
      f From
      s Subject
      n Attachment
    )
    mairix_comp_query=(
      t:To
      c:Cc
      f:From
      b:Body
      s:Subject
      n:Attachment
      d:Date
      z:Size
      F:Flags
      m:Message-Id
    )
  fi
    
  if compset -P '*:(*[,/]|)([~^]|)'; then
    local i category
    category=${${IPREFIX%:}//a/bft}
    if [[ $category = F ]]; then
      _describe -t flags 'Message flags' mairix_comp_flags
    else
      typeset -gUa mairix_comp_result
      mairix_comp_result=()
      for i in ${(us::)${IPREFIX%:}//a/cft}; do
	mairix_comp_result+=(${(f)mairix_comp_cache[$mairix_comp_table[$i]]})
      done
      (($#mairix_comp_result)) && compadd $mairix_comp_result
    fi
  else
    local suf
    IPREFIX=$PREFIX[1,-2]
    PREFIX=${PREFIX#$IPREFIX}
    compset -S ':*' || suf=:
    compset -S '*'
    _describe -t query-type 'Query type' mairix_comp_query -S "$suf"
  fi
}
compdef mairix_comp -vared-


Messages sorted by: Reverse Date, Date, Thread, Author