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 C72B3431FBC for ; Sat, 7 Mar 2015 06:12:29 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: 1.738 X-Spam-Level: * X-Spam-Status: No, score=1.738 tagged_above=-999 required=5 tests=[DNS_FROM_AHBL_RHSBL=2.438, 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 t01Kiu5cE2LQ for ; Sat, 7 Mar 2015 06:12:26 -0800 (PST) Received: from mail-wi0-f182.google.com (mail-wi0-f182.google.com [209.85.212.182]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (No client certificate requested) by olra.theworths.org (Postfix) with ESMTPS id F2EE8431FAE for ; Sat, 7 Mar 2015 06:12:25 -0800 (PST) Received: by wibbs8 with SMTP id bs8so9778792wib.4 for ; Sat, 07 Mar 2015 06:12:24 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:in-reply-to:references :user-agent:date:message-id:mime-version:content-type; bh=j+4em1Oc67LC6dexZRDuRa1iUu3w02KiwUKB6BeWscY=; b=dzRNLvAxB4lRH5weZAr7zeOTHjE7hdC4FgeU/iG0L3XwrkGeTVxwWDRX+8QnYcoAUg SRt0CtKp/krulIUTfHAExCaE8pcM6Eu62MOJYIQX6gEvDjMZbIk9Tz1vTKT40c0d9lGa bvAcEzm7jat+AfuPVWXu+LRoR3OPYH/iJwm4WNt7qrgd0h+V/vdYDWH5I77ITVNcCHII ZnUSIniI9MpkUP9Wjkpu55Amad9C7PQtwbjdDAcQGvep/V8rH0/m5HvnFvdNxvTQWml+ MyNL4hl9/drrbkZJAY4jR7EkLyicni1v2ALRScS0rgH1j7+YEgg2RdD/UjdmSp01jxXT JybQ== X-Gm-Message-State: ALoCoQlHLLGFFvf7YVm6VlHRUJ+ibBJecsvOO1hyc6izqXvwLgaCAP5Eigd7kk/VY8KeYfrbWThN X-Received: by 10.194.78.231 with SMTP id e7mr39089690wjx.33.1425737544834; Sat, 07 Mar 2015 06:12:24 -0800 (PST) Received: from localhost (mobile-internet-bcee3b-76.dhcp.inet.fi. [188.238.59.76]) by mx.google.com with ESMTPSA id nb18sm6844502wic.3.2015.03.07.06.12.23 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 07 Mar 2015 06:12:24 -0800 (PST) From: Jani Nikula To: Tomi Ollila , notmuch@notmuchmail.org Subject: Re: [PATCH] notmuch-emacs-mua: more options, some fixes In-Reply-To: <1425724605-392-1-git-send-email-tomi.ollila@iki.fi> References: <1425724605-392-1-git-send-email-tomi.ollila@iki.fi> User-Agent: Notmuch/0.19+74~g6aeef2e (http://notmuchmail.org) Emacs/24.4.1 (x86_64-pc-linux-gnu) Date: Sat, 07 Mar 2015 16:12:43 +0200 Message-ID: <87pp8kj3qc.fsf@nikula.org> MIME-Version: 1.0 Content-Type: text/plain Cc: tomi.ollila@iki.fi 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, 07 Mar 2015 14:12:29 -0000 On Sat, 07 Mar 2015, Tomi Ollila wrote: > Two new options added: > --from: specify alternate From: header > --bodytext: possibility to give body content from command line > > Non-forking escape() functionality, also escaping \ (backslash) characters. > > Without content arguments start emacs/emacsclient and run (notmuch-hello), > in this case without assigning anything to message-exit-actions. > > Point is now positioned at the end of the content given last on command > line, unless to: or subject: is missing -- in which case point is > positioned at one of these headers (is both missing, at to:) > > The -nw option is now given to emacs in case --no-window-system command > line option is provided (--no-window-system used to work with emacsclient > only). > > In case EMACS or EMACSCLIENT environment variable was defined but being > empty (null string), use emacs/emacsclient as command instead (null string > as executable name gives confusing error message). Also $EMACS/$EMACSCLIENT > executable name is now quoted to *NOT* split it to separate command line > arguments on any $IFS variables there might be. > > Reorganized content argument handling to combine the content of same option > given multiple times and make it look more readable when --print option is > used. --body option also now checks the existence of the file to be > included and if the file included does not end with newline trailing > newline is inserted to the message buffer. > > As bash supports [[ ]] command and it's special expansion (or lack thereof) > of variables (and ==, && and || inside) the few [ ]'s there were are now > changed to this more advanced format. As I mentioned on IRC, I think there are too many changes here for one patch. One change at a time! In particular because I'm not sure if all of this is really needed... like message_goto and point placement handling. Starts to feel like all of this would be better handled with a dedicated function in emacs! BR, Jani. > --- > > The changes *NOT* taken from my 2 draft patches (*) > > 1) no -nw hacking > > 2) no mailto: handling > > (*) id:1421776424-24304-1-git-send-email-tomi.ollila@iki.fi (later, linking > previous) > > > doc/man1/notmuch-emacs-mua.rst | 8 ++- > notmuch-emacs-mua | 123 ++++++++++++++++++++++++++++++----------- > 2 files changed, 99 insertions(+), 32 deletions(-) > > diff --git a/doc/man1/notmuch-emacs-mua.rst b/doc/man1/notmuch-emacs-mua.rst > index eb47098..29f7e0c 100644 > --- a/doc/man1/notmuch-emacs-mua.rst > +++ b/doc/man1/notmuch-emacs-mua.rst > @@ -22,6 +22,9 @@ Supported options for **notmuch-emacs-mua** include > Use emacsclient, rather than emacs. This will start > an emacs daemon process if necessary. > > + ``--from=``\ > + Specify alternate sender (From) of the message. > + > ``-s, --subject=``\ > Specify the subject of the message. > > @@ -37,6 +40,9 @@ Supported options for **notmuch-emacs-mua** include > ``-i, --body=``\ > Specify a file to include into the body of the message. > > + ``--bodytext=``\ > + Specify text content to be inserted into the body of the message. > + > ``--no-window-system`` > Even if a window system is available, use the current terminal > > @@ -60,4 +66,4 @@ Name of emacsclient comment to invoke > SEE ALSO > ======== > > -**notmuch(1)**, **emacsclient(1)**, **mutt(1)** > +**notmuch(1)**, **emacs(1)**, **emacsclient(1)**, **mutt(1)** > diff --git a/notmuch-emacs-mua b/notmuch-emacs-mua > index b8cbc82..17365b9 100755 > --- a/notmuch-emacs-mua > +++ b/notmuch-emacs-mua > @@ -1,4 +1,5 @@ > #!/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 > # > @@ -18,25 +19,47 @@ > # along with this program. If not, see http://www.gnu.org/licenses/ . > # > # Authors: Jani Nikula > +# Tomi Ollila > # > > set -eu > > +# escape: "expand" '\' to '\\' & '"' to '\"' > +# Calling convention: escape -v var "$arg" (like in bash printf). > escape () > { > - echo "${1//\"/\\\"}" > + local arg=${3//\\/\\\\} > + eval $2='${arg//\"/\\\"}' > } > > -EMACS=${EMACS-emacs} > -EMACSCLIENT=${EMACSCLIENT-emacsclient} > +EMACS=${EMACS:-emacs} > +EMACSCLIENT=${EMACSCLIENT:-emacsclient} > > PRINT_ONLY= > USE_EMACSCLIENT= > -CLIENT_TYPE="-c" > +EMACSCLIENT_TYPE='-c' > +EMACS_NW= > > -# The crux of it all: construct an elisp progn and eval it. > -ELISP="(prog1 'done (require 'notmuch) (notmuch-mua-new-mail)" > -ELISP="${ELISP} (setq message-exit-actions (list #'save-buffers-kill-terminal))" > +exec_mua () > +{ > + if [[ -n $PRINT_ONLY ]]; then > + echo "$1" > + exit > + fi > + > + if [[ -n $USE_EMACSCLIENT ]]; then > + # Evaluate the progn. > + exec "${EMACSCLIENT}" ${EMACSCLIENT_TYPE} -a '' --eval "$1" > + else > + exec "${EMACS}" ${EMACS_NW} --eval "$1" > + fi > + exit not reached > +} > + > +SUBJECT= TO= CC= BCC= BODY= FROM= > + > +unset message_goto # Final elisp function to execute, when defined. > +cddone=false > > while getopts :s:c:b:i:hC opt; do > # Handle errors and long options. > @@ -47,14 +70,14 @@ while getopts :s:c:b:i:hC opt; do > ;; > \?) > opt=$1 > - if [ "${OPTARG}" != "-" ]; then > + 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=*) > + --subject=*|--to=*|--cc=*|--bcc=*|--body=*|--from=*|--bodytext=*) > OPTARG=${opt#--*=} > opt=${opt%%=*} > ;; > @@ -71,9 +94,7 @@ while getopts :s:c:b:i:hC opt; do > ;; > esac > > - > - OPTARG="${OPTARG-none}" > - OPTARG="$(escape "${OPTARG}")" > + escape -v OPTARG "${OPTARG-}" > > case "${opt}" in > --help|h) > @@ -82,26 +103,48 @@ while getopts :s:c:b:i:hC opt; do > --client|C) > USE_EMACSCLIENT="yes" > ;; > + --from) > + FROM=${OPTARG} > + ;; > --subject|s) > - ELISP="${ELISP} (message-goto-subject) (insert \"${OPTARG}\")" > + SUBJECT=${SUBJECT:+$SUBJECT }${OPTARG} > + message_goto='(message-goto-subject)' > ;; > --to) > - ELISP="${ELISP} (message-goto-to) (insert \"${OPTARG}, \")" > + TO=${TO:+$TO, }${OPTARG} > + message_goto='(message-goto-to)' > ;; > --cc|c) > - ELISP="${ELISP} (message-goto-cc) (insert \"${OPTARG}, \")" > + CC=${CC:+$CC, }${OPTARG} > + message_goto='(message-goto-cc)' > ;; > --bcc|b) > - ELISP="${ELISP} (message-goto-bcc) (insert \"${OPTARG}, \")" > + BCC=${BCC:+$BCC, }${OPTARG} > + message_goto='(message-goto-bcc)' > ;; > --body|i) > - ELISP="${ELISP} (message-goto-body) (cd \"${PWD}\") (insert-file \"${OPTARG}\")" > + if [[ ! -f ${OPTARG} ]]; then > + echo "$0: '${OPTARG}': no such file" >&2 > + exit 1 > + fi > + if [[ $cddone == 'false' ]]; then > + BODY=${BODY}$'\n'" (cd \"${PWD}\")" > + cddone=true > + fi > + BODY=${BODY}$'\n'" (insert-file \"${OPTARG}\")" > + BODY=${BODY}$'\n'" (if (/= (point) (line-beginning-position)) (insert \"\\n\"))" > + unset message_goto > + ;; > + --bodytext) > + BODY=${BODY}$'\n'" (insert \"${OPTARG}\\n\")" > + unset message_goto > ;; > --print) > PRINT_ONLY=1 > ;; > --no-window-system) > - CLIENT_TYPE="-t" > + EMACSCLIENT_TYPE='-t' > + EMACS_NW='-nw' > ;; > *) > # We should never end up here. > @@ -116,21 +159,39 @@ done > > # Positional parameters. > for arg; do > - arg="$(escape "${arg}")" > - ELISP="${ELISP} (message-goto-to) (insert \"${arg}, \")" > + escape -v _arg "${arg}" > + TO=${TO:+$TO, }${_arg} > + message_goto='(message-goto-to)' > done > > -# End progn. > -ELISP="${ELISP})" > +# The newlines are here for better user experience when --print option is used. > +NL=$'\n' > +ELISP="\ > +${CC:+$NL (message-goto-cc) (insert \"$CC\")}\ > +${BCC:+$NL (message-goto-bcc) (insert \"$BCC\")}\ > +${BODY:+$NL (message-goto-body)$BODY}" > > -if [ -n "$PRINT_ONLY" ]; then > - echo ${ELISP} > - exit 0 > -fi > - > -if [ -n "$USE_EMACSCLIENT" ]; then > - # Evaluate the progn. > - exec ${EMACSCLIENT} ${CLIENT_TYPE} -a '' --eval "${ELISP}" > +if [[ $TO == '' && $SUBJECT == '' && $ELISP == '' ]] > +then > + exec_mua "(prog1 'done (require 'notmuch) (notmuch-hello))" > else > - exec ${EMACS} --eval "${ELISP}" > + [[ $FROM != '' ]] && OH="(list (cons 'From \"$FROM\"))" || OH=nil > + > + if [[ $SUBJECT == '' ]]; then > + SUBJECT=nil > + message_goto='(message-goto-subject)' > + else > + SUBJECT=\"$SUBJECT\" > + fi > + if [[ $TO == '' ]]; then > + TO=nil > + message_goto='(message-goto-to)' > + else > + TO=\"$TO\" > + fi > + exec_mua "(prog1 'done (require 'notmuch) > + (setq message-exit-actions (list #'save-buffers-kill-terminal)) > + (notmuch-mua-mail ${TO} ${SUBJECT} > + ${OH} nil (notmuch-mua-get-switch-function))\ > +${ELISP}${NL} (set-buffer-modified-p nil)${message_goto+ $message_goto})" > fi > -- > 2.1.0 > > _______________________________________________ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch