On Fri, 11 Jul 2014, Tomi Ollila <tomi.ollila@iki.fi> wrote: > Highlights: > > * notmuch-emacs-mua without arguments runs (notmuch-hello) > > * runs emacs(1) in case emacsclient(1) fails to connect to running emacs > > * takes -nw option > > * handles mailto: > > * --from option when sending non-mailto: way > > * -i includes file --body[= ]string inserts string > --- > notmuch-emacs-mua | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 200 insertions(+) > create mode 100755 notmuch-emacs-mua > > diff --git a/notmuch-emacs-mua b/notmuch-emacs-mua > new file mode 100755 > index 0000000..b1696f7 > --- /dev/null > +++ b/notmuch-emacs-mua > @@ -0,0 +1,200 @@ > +#!/usr/bin/env bash > +# -*- mode: shell-script; sh-basic-offset: 4; tab-width: 8 -*- > +# > +# notmuch-emacs-mua - start composing a mail on the command line > +# > +# Copyright © 2014 Jani Nikula > +# > +# This program is free software: you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation, either version 3 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program. If not, see http://www.gnu.org/licenses/ . > +# > +# Authors: Jani Nikula <jani@nikula.org> > +# Tomi Ollila <tomi.ollila@iki.fi> > +# > + > +set -eu > + > +# "expand" '\' to '\\' & '"' to '\"' > +escape_optarg () > +{ > + OPTARG=${OPTARG//\\/\\\\}; OPTARG=${OPTARG//\"/\\\"} > +} > + > +# ditto, in case there is '\n' sequence in the source, otherwise > +# "expand" only trailing '\'s to '\\'s > +escape_body_optarg () > +{ > + case ${OPTARG} in > + *'\"'*) OPTARG=${OPTARG//\\/\\\\} ;; > + *'\') OPTARG=$( printf %s "${OPTARG}" | sed 's/\(\\*\)$/\1\1/' ) > + esac > + OPTARG=${OPTARG//\"/\\\"} > +} > + > +unset ALTERNATE_EDITOR > +exec_mua () > +{ > + if "${EMACSCLIENT:=emacsclient}" --eval t >/dev/null 2>&1 > + then > + emacs=$EMACSCLIENT > + # close stdout in case no -nw (and no --print) > + test -n "$W$X" || exec >/dev/null > + else > + emacs=${EMACS:-emacs} > + fi > + ${X:-exec} "$emacs" $W --eval "$*" > + exit > + ${X:-exec "$emacs" $W --eval} "$*" > +} > + > +X= > +W= > + > +SUBJECT= TO= CC= BCC= BODY= FROM= IB= > + > +while > + # first, handle "long" options which cannot be handled by getopts > + case ${1-} in > + -nw) > + W=-nw > + shift > + continue > + ;; How about generalizing this into letting the user pass arguments after a "--" separator to emacs(client)? Would that work? Alternatively, why support -nw which is neither part of the mutt interface I was originally aiming at emulating nor conforms to notmuch style? Just go with --nw or the more verbose --no-window-system (which is also compatible with emacs). > + mailto:*) > + oIFS=$IFS; IFS=; OPTARG="$*" IFS=$oIFS > + escape_optarg > + exec_mua "(progn (require 'notmuch) (browse-url-mail \"$OPTARG\"))" > + exit > + esac Why does mailto: need to be handled here? I think you could either make the usage have a special mailto: case where you only have mailto: at $1, or you handle mailto: as a positional parameter at the end. With these, you could drop this one extra case here, and go back to the more natural "while getopts" argument parsing loop. > + > + getopts :s:c:b:i:h opt > +do > + # Handle errors and long options. > + case ${opt} in > + :) > + echo "$0: short option '-${OPTARG}' requires an argument." >&2 > + exit 1 > + ;; > + \?) > + opt=$1 > + if [[ ${OPTARG} != '-' ]]; then > + echo "$0: unknown short option '-${OPTARG}'." >&2 > + exit 1 > + fi > + > + case ${opt} in > + # Long options with arguments. > + --subject=*|--to=*|--cc=*|--bcc=*|--body=*|--from=*) > + OPTARG=${opt#--*=} > + opt=${opt%%=*} > + ;; > + # Long options with argument in next arg. > + --subject |--to |--cc |--bcc |--body |--from ) This may be git-ish, but I don't think we should support this in notmuch. > + if [[ $# < 2 ]]; then > + echo "$0: option '${opt}' requires an argument." >&2 > + exit 1 > + fi > + OPTARG=$2 > + OPTIND=$((OPTIND + 1)) > + ;; > + # Long options without arguments. > + --help|--nw|--print) > + ;; > + *) > + echo "$0: unknown long option '${opt}', or argument mismatch." >&2 > + exit 1 > + ;; > + esac > + # getopts does not do this for what it considers errors. > + OPTIND=$((OPTIND + 1)) > + ;; > + esac > + > + case ${opt} in > + --help|h) > + exec man notmuch-emacs-mua > + ;; > + --from) > + escape_optarg > + FROM=${OPTARG} > + ;; > + --subject|s) > + escape_optarg > + SUBJECT=${SUBJECT:+$SUBJECT }${OPTARG} > + ;; > + --to) > + escape_optarg > + TO=${TO:+$TO, }${OPTARG} > + ;; > + --cc|c) > + escape_optarg > + CC=${CC:+$CC, }${OPTARG} > + ;; > + --bcc|b) > + escape_optarg > + BCC=${BCC:+$BCC, }${OPTARG} > + ;; > + i) > + escape_optarg > + if [[ ! -f ${OPTARG} ]]; then > + echo "$0: '${OPTARG}': no such file" >&2 > + exit 1 > + fi > + IB=${IB}$'\n'" (insert-file \"${OPTARG}\")" This needs the (cd \"${PWD}\") bit because --body given here may be relative to the script, while emacs likely has a totally different cwd. > + IB=${IB}$'\n'" (if /= (point) (line-beginning-position) (insert \"\\n\"))" > + ;; > + --body) > + escape_body_optarg > + IB=${IB}$'\n'" (insert \"${OPTARG}\\n\")" Why should --body and -i be different? > + ;; > + --nw) > + W=-nw > + ;; > + --print) > + X=echo > + ;; > + *) > + # We should never end up here. > + echo "$0: internal error (option '${opt}')." >&2 > + exit 1 > + ;; > + esac > + > + shift $((OPTIND - 1)) > + OPTIND=1 > +done > + > +# Positional parameters. > +for arg; do > + arg=${arg//\\/\\\\}; arg=${arg//\"/\\\"} > + TO=${TO:+$TO, }${arg} > +done > + > +NL=$'\n' > +ELISP="\ > +${CC:+$NL (message-goto-cc) (insert \"$CC\")}\ > +${BCC:+$NL (message-goto-bcc) (insert \"$BCC\")}\ > +${IB:+$NL (message-goto-body)$IB}" > + > +if [[ $TO == '' && $SUBJECT == '' && $ELISP == '' ]] > +then > + exec_mua "(progn (require 'notmuch) (notmuch-hello))" > +else > + [[ $FROM != '' ]] && OH="(list (cons 'From \"$FROM\"))" || OH=nil > + [[ $TO != '' ]] && TO=\"$TO\" || TO=nil > + [[ $SUBJECT != '' ]] && SUBJECT=\"$SUBJECT\" || SUBJECT=nil > + exec_mua "$NL(progn (require 'notmuch) > + (notmuch-mua-mail $TO $SUBJECT > + $OH nil (notmuch-mua-get-switch-function))\ > +$ELISP$NL (set-buffer-modified-p nil) (message-goto-to))" I think the newlines with $NL hurt readability in the script more than they help readability in the output... which is generally interpreted by emacs which doesn't really care about the newlines! ;) BR, Jani. > +fi > -- > 1.9.0