Re: [PATCH 08/11] emacs: Support caching in notmuch-get-bodypart-{binary, text}
authorAustin Clements <amdragon@mit.edu>
Sat, 24 Jan 2015 18:06:59 +0000 (13:06 +1900)
committerW. Trevor King <wking@tremily.us>
Sat, 20 Aug 2016 21:47:47 +0000 (14:47 -0700)
2b/da2f1280a92343a255a5b4a0e213ea116d984d [new file with mode: 0644]

diff --git a/2b/da2f1280a92343a255a5b4a0e213ea116d984d b/2b/da2f1280a92343a255a5b4a0e213ea116d984d
new file mode 100644 (file)
index 0000000..7bdb4a8
--- /dev/null
@@ -0,0 +1,212 @@
+Return-Path: <aclements@csail.mit.edu>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+       by olra.theworths.org (Postfix) with ESMTP id 9BB9C431FCB\r
+       for <notmuch@notmuchmail.org>; Sat, 24 Jan 2015 10:07:03 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.138\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.138 tagged_above=-999 required=5\r
+       tests=[DNS_FROM_AHBL_RHSBL=2.438, RCVD_IN_DNSWL_MED=-2.3]\r
+       autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+       by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+       with ESMTP id cPyXdJMYb6El for <notmuch@notmuchmail.org>;\r
+       Sat, 24 Jan 2015 10:07:00 -0800 (PST)\r
+Received: from outgoing.csail.mit.edu (outgoing.csail.mit.edu [128.30.2.149])\r
+       by olra.theworths.org (Postfix) with ESMTP id 568A2431FAE\r
+       for <notmuch@notmuchmail.org>; Sat, 24 Jan 2015 10:07:00 -0800 (PST)\r
+Received: from [104.131.20.129] (helo=awakeningjr)\r
+       by outgoing.csail.mit.edu with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16)\r
+       (Exim 4.72) (envelope-from <aclements@csail.mit.edu>)\r
+       id 1YF56p-0006Kr-OO; Sat, 24 Jan 2015 13:06:59 -0500\r
+Received: from amthrax by awakeningjr with local (Exim 4.84)\r
+       (envelope-from <aclements@csail.mit.edu>)\r
+       id 1YF56p-0003m9-3E; Sat, 24 Jan 2015 13:06:59 -0500\r
+From: Austin Clements <amdragon@mit.edu>\r
+To: Mark Walters <markwalters1009@gmail.com>\r
+Subject: Re: [PATCH 08/11] emacs: Support caching in\r
+       notmuch-get-bodypart-{binary, text}\r
+In-Reply-To: <87d2g5uczr.fsf@qmul.ac.uk>\r
+References: <1398105468-14317-1-git-send-email-amdragon@mit.edu>\r
+       <1398105468-14317-9-git-send-email-amdragon@mit.edu>\r
+       <87sip3t37f.fsf@qmul.ac.uk> <20140424181216.GO25817@mit.edu>\r
+       <87d2g5uczr.fsf@qmul.ac.uk>\r
+User-Agent: Notmuch/0.18.1+86~gef5e66a (http://notmuchmail.org) Emacs/24.4.1\r
+       (x86_64-pc-linux-gnu)\r
+Date: Sat, 24 Jan 2015 13:06:59 -0500\r
+Message-ID: <87vbjwt5mk.fsf@csail.mit.edu>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain\r
+Cc: notmuch@notmuchmail.org\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+       <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Sat, 24 Jan 2015 18:07:03 -0000\r
+\r
+On Fri, 25 Apr 2014, Mark Walters <markwalters1009@gmail.com> wrote:\r
+> On Thu, 24 Apr 2014, Austin Clements <amdragon@MIT.EDU> wrote:\r
+>> Quoth Mark Walters on Apr 24 at 11:46 am:\r
+>>> \r
+>>> On Mon, 21 Apr 2014, Austin Clements <amdragon@MIT.EDU> wrote:\r
+>>> > (The actual code change here is small, but requires re-indenting\r
+>>> > existing code.)\r
+>>> > ---\r
+>>> >  emacs/notmuch-lib.el | 52 ++++++++++++++++++++++++++++++----------------------\r
+>>> >  1 file changed, 30 insertions(+), 22 deletions(-)\r
+>>> >\r
+>>> > diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el\r
+>>> > index fc67b14..fee8512 100644\r
+>>> > --- a/emacs/notmuch-lib.el\r
+>>> > +++ b/emacs/notmuch-lib.el\r
+>>> > @@ -503,33 +503,39 @@ (defun notmuch-parts-filter-by-type (parts type)\r
+>>> >     (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))\r
+>>> >     parts))\r
+>>> >  \r
+>>> > -(defun notmuch-get-bodypart-binary (msg part process-crypto)\r
+>>> > +(defun notmuch-get-bodypart-binary (msg part process-crypto &optional cache)\r
+>>> >    "Return the unprocessed content of PART in MSG as a unibyte string.\r
+>>> >  \r
+>>> >  This returns the \"raw\" content of the given part after content\r
+>>> >  transfer decoding, but with no further processing (see the\r
+>>> >  discussion of --format=raw in man notmuch-show).  In particular,\r
+>>> >  this does no charset conversion."\r
+>>> > -  (let ((args `("show" "--format=raw"\r
+>>> > -                ,(format "--part=%d" (plist-get part :id))\r
+>>> > -                ,@(when process-crypto '("--decrypt"))\r
+>>> > -                ,(notmuch-id-to-query (plist-get msg :id)))))\r
+>>> > -    (with-temp-buffer\r
+>>> > -      ;; Emacs internally uses a UTF-8-like multibyte string\r
+>>> > -      ;; representation by default (regardless of the coding system,\r
+>>> > -      ;; which only affects how it goes from outside data to this\r
+>>> > -      ;; internal representation).  This *almost* never matters.\r
+>>> > -      ;; Annoyingly, it does matter if we use this data in an image\r
+>>> > -      ;; descriptor, since Emacs will use its internal data buffer\r
+>>> > -      ;; directly and this multibyte representation corrupts binary\r
+>>> > -      ;; image formats.  Since the caller is asking for binary data, a\r
+>>> > -      ;; unibyte string is a more appropriate representation anyway.\r
+>>> > -      (set-buffer-multibyte nil)\r
+>>> > -      (let ((coding-system-for-read 'no-conversion))\r
+>>> > -        (apply #'call-process notmuch-command nil '(t nil) nil args)\r
+>>> > -        (buffer-string)))))\r
+>>> > -\r
+>>> > -(defun notmuch-get-bodypart-text (msg part process-crypto)\r
+>>> > +  (let ((data (plist-get part :binary-content)))\r
+>>> > +    (when (not data)\r
+>>> > +      (let ((args `("show" "--format=raw"\r
+>>> > +                    ,(format "--part=%d" (plist-get part :id))\r
+>>> > +                    ,@(when process-crypto '("--decrypt"))\r
+>>> > +                    ,(notmuch-id-to-query (plist-get msg :id)))))\r
+>>> > +        (with-temp-buffer\r
+>>> > +          ;; Emacs internally uses a UTF-8-like multibyte string\r
+>>> > +          ;; representation by default (regardless of the coding\r
+>>> > +          ;; system, which only affects how it goes from outside data\r
+>>> > +          ;; to this internal representation).  This *almost* never\r
+>>> > +          ;; matters.  Annoyingly, it does matter if we use this data\r
+>>> > +          ;; in an image descriptor, since Emacs will use its internal\r
+>>> > +          ;; data buffer directly and this multibyte representation\r
+>>> > +          ;; corrupts binary image formats.  Since the caller is\r
+>>> > +          ;; asking for binary data, a unibyte string is a more\r
+>>> > +          ;; appropriate representation anyway.\r
+>>> > +          (set-buffer-multibyte nil)\r
+>>> > +          (let ((coding-system-for-read 'no-conversion))\r
+>>> > +            (apply #'call-process notmuch-command nil '(t nil) nil args)\r
+>>> > +            (setq data (buffer-string)))))\r
+>>> > +      (when cache\r
+>>> > +        (plist-put part :binary-content data)))\r
+>>> > +    data))\r
+>>> \r
+>>> I am a little puzzled by this but that could be lack of familiarity with\r
+>>> elisp. As far as I can see plist-put will sometimes modify the original\r
+>>> plist and sometimes return a new plist. If the latter happens then I\r
+>>> think it works out as if we hadn't cached anything as the part passed to\r
+>>> the function is unmodified. That might not matter in this case (though I\r
+>>> find the lack of determinism disturbing).\r
+>>> \r
+>>> Or is something else going on?\r
+>>\r
+>> No, your familiarity with Elisp serves you well.  I'm completely\r
+>> cheating here.  According to the specification of plist-put, it's\r
+>> allowed to return a new list but in reality this only happens when the\r
+>> original plist is nil.  We lean on this already all over the\r
+>> notmuch-emacs code, but maybe that doesn't excuse me adding one more\r
+>> cheat.\r
+>>\r
+>> I could add a comment here explaining what's going on, I could\r
+>> manually do the list insertion in a way that's guaranteed to mutate it\r
+>> in place, or I could add a nil :binary-content property when parts are\r
+>> created (since plist-put is guaranteed to mutate existing keys in\r
+>> place).\r
+>\r
+> I think a comment is fine. \r
+\r
+Done.\r
+\r
+> (Incidentally what is the best way of telling if emacs has changed an\r
+> object or returned a new one for other commands? Something like (setq\r
+> oldobject object) (setq object (operation-on object)) (if (eq object\r
+> oldobject) ... ))\r
+\r
+If `eq' returns t, it definitely returned the original object, though it\r
+may or may not have modified it.  If `eq' returns nil, there's no\r
+guarantee that it *didn't* modify the object you passed in (maybe it\r
+modified it and tacked a new cons on the beginning).  In short, there's\r
+really no way of knowing.\r
+\r
+> Also, I think the function should have a comment about the lifetime of\r
+> the caching. I think in some cases the addition of :binary-content could\r
+> occur on load and thus the plist with binary content added would get\r
+> saved in the buffer when the msg plist was saved as a\r
+> text-property. However, maybe in other cases this gets called after the\r
+> initial insertion and thus the cached value is just used during this\r
+> operation on msg? Sorry that is a little incoherent as I haven't checked\r
+> all callers.\r
+\r
+I believe the caching will always last as long as the buffer.  We only\r
+have one instance of each message plist.  This plist goes in to the text\r
+properties and caching works by mutating this same plist.\r
+\r
+However, I updated the docstring to clarify that the cache is stored in\r
+MSG.  These functions don't ultimately control the lifetime of MSG, but\r
+this gives the caller enough information to know the lifetime of the\r
+cache if it knows the lifetime of MSG.\r
+\r
+> Best wishes\r
+>\r
+> Mark\r
+>\r
+>\r
+>\r
+>>> Best wishes\r
+>>> \r
+>>> Mark\r
+>>> \r
+>>> \r
+>>> \r
+>>> > +\r
+>>> > +(defun notmuch-get-bodypart-text (msg part process-crypto &optional cache)\r
+>>> >    "Return the text content of PART in MSG.\r
+>>> >  \r
+>>> >  This returns the content of the given part as a multibyte Lisp\r
+>>> > @@ -546,7 +552,9 @@ (defun notmuch-get-bodypart-text (msg part process-crypto)\r
+>>> >               (npart (apply #'notmuch-call-notmuch-sexp args)))\r
+>>> >          (setq content (plist-get npart :content))\r
+>>> >          (when (not content)\r
+>>> > -          (error "Internal error: No :content from %S" args))))\r
+>>> > +          (error "Internal error: No :content from %S" args)))\r
+>>> > +      (when cache\r
+>>> > +        (plist-put part :content content)))\r
+>>> >      content))\r
+>>> >  \r
+>>> >  ;; Workaround: The call to `mm-display-part' below triggers a bug in\r