On Fri, 11 Jul 2014, Tomi Ollila <tomi.ollila at 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 at nikula.org>
> +#          Tomi Ollila <tomi.ollila at 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

Reply via email to