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 60238431FAF for ; Tue, 18 Dec 2012 10:48:30 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: -0.7 X-Spam-Level: X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5 tests=[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 70jvaaDkK7lu for ; Tue, 18 Dec 2012 10:48:29 -0800 (PST) Received: from dmz-mailsec-scanner-6.mit.edu (DMZ-MAILSEC-SCANNER-6.MIT.EDU [18.7.68.35]) by olra.theworths.org (Postfix) with ESMTP id C1373431FAE for ; Tue, 18 Dec 2012 10:48:28 -0800 (PST) X-AuditID: 12074423-b7fcb6d000000927-82-50d0ba7bfbb6 Received: from mailhub-auth-2.mit.edu ( [18.7.62.36]) by dmz-mailsec-scanner-6.mit.edu (Symantec Messaging Gateway) with SMTP id B4.0F.02343.B7AB0D05; Tue, 18 Dec 2012 13:48:27 -0500 (EST) Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103]) by mailhub-auth-2.mit.edu (8.13.8/8.9.2) with ESMTP id qBIImR8V000492; Tue, 18 Dec 2012 13:48:27 -0500 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91]) (authenticated bits=0) (User authenticated as amdragon@ATHENA.MIT.EDU) by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id qBIImPoZ011088 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NOT); Tue, 18 Dec 2012 13:48:26 -0500 (EST) Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.80) (envelope-from ) id 1Tl2DJ-0007YS-Ea; Tue, 18 Dec 2012 13:48:25 -0500 Date: Tue, 18 Dec 2012 13:48:25 -0500 From: Austin Clements To: Mark Walters Subject: Re: [DRAFT PATCH] emacs: Eliminate buffer invisibility specs from show and wash Message-ID: <20121218184825.GM6187@mit.edu> References: <1355812810-32747-1-git-send-email-amdragon@mit.edu> <87licvqlbb.fsf@qmul.ac.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87licvqlbb.fsf@qmul.ac.uk> User-Agent: Mutt/1.5.21 (2010-09-15) X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupjleLIzCtJLcpLzFFi42IRYrdT0a3edSHA4OMKZYvVc3ksrt+cyezA 5LFz1l12j2erbjEHMEVx2aSk5mSWpRbp2yVwZax8/J654IFtxfEdUQ2MLw26GDk5JARMJC4+ /MwGYYtJXLi3Hsjm4hAS2Mco8eFhLyuEs4FRYu1bGOcik8TunSugypYwSjz6/QWsn0VAVWLS 95eMIDabgIbEtv3LwWwRAR2J24cWsIPYzALSEt9+NzOB2MICURIf111hAbF5BbQlenveg80R EoiT2PH7DztEXFDi5MwnLBC9WhI3/r0E6uUAm7P8HwdImBNo1c1HF8BGigqoSEw5uY1tAqPQ LCTds5B0z0LoXsDIvIpRNiW3Sjc3MTOnODVZtzg5MS8vtUjXTC83s0QvNaV0EyM4qF2UdzD+ Oah0iFGAg1GJh1dixYUAIdbEsuLK3EOMkhxMSqK8X7YChfiS8lMqMxKLM+KLSnNSiw8xSnAw K4nwnpsAlONNSaysSi3Kh0lJc7AoifNeS7npLySQnliSmp2aWpBaBJOV4eBQkuB13QnUKFiU mp5akZaZU4KQZuLgBBnOAzTcGaSGt7ggMbc4Mx0if4pRl6Ph5Y2njEIsefl5qVLivHwgRQIg RRmleXBzYMnoFaM40FvCvBogVTzARAY36RXQEiagJUF6YEtKEhFSUg2M4tXS/59Zu+vW5XKm zMjSTEjfYZDTdq2Q2fXrZb6f84MutAmLrLyV/PmfVblIebnLDrn5cqJVSr1bBX2v5xtaBMuk FOQb+WnzF7GZrlrhfpk7KLBvgQmLZY+RHHuz0se9uU8eLtn4seWLpv68TMOXMneUjX+bf2tb /W2DEs9TsS89MVu7/imxFGckGmoxFxUnAgCwQiidIQMAAA== Cc: notmuch@notmuchmail.org 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: Tue, 18 Dec 2012 18:48:30 -0000 Quoth Mark Walters on Dec 18 at 6:14 pm: > On Tue, 18 Dec 2012, Austin Clements wrote: > > Previously, all visibility in show buffers for headers, message > > bodies, and washed text was specified by generating one or more > > symbols for each region and creating overlays with their 'invisible > > property set to carefully crafted combinations of these symbols. > > Visibility was controlled not by modifying the overlays directly, but > > by adding and removing the generated symbols from a gigantic buffer > > invisibilty spec. > > > > This has myriad negative consequences. It's slow because Emacs' > > display engine has to traverse the buffer invisibility list for every > > overlay and, since every overlay has its own symbol, this makes > > rendering O(N^2) in the number of overlays. It composes poorly > > because symbol-type 'invisible properties are taken from the highest > > priority overlay over a given character (which is often ambiguous!), > > rather than being gathered from all overlays over a character. As a > > result, we have to include symbols related to message hiding in the > > wash code lest the wash overlays un-hide parts of hidden messages. It > > also requires various workarounds for isearch to properly open > > overlays, to set up buffer-invisibility-spec for > > remove-from-invisibility-spec to work right, and to explicitly refresh > > the display after updating the buffer invisibility spec. > > > > None of this is necessary. > > > > This patch converts show and wash to use simple boolean 'invisible > > properties and to not use the buffer invisibility spec. Rather than > > adding and removing generated symbols from the invisibility spec, the > > code now directly toggles the 'invisible property of the appropriate > > overlay. This speeds up rendering because the display engine only has > > to check the boolean values of the overlays over a character. It > > composes nicely because text will be invisible if *any* overlay over > > it has 'invisible t, which means we can overlap invisibility overlays > > with abandon. We no longer need any of the workarounds mentioned > > above. And it fixes a minor bug for free: now, when isearch opens a > > washed region, the button text will update to say "Click/Enter to > > hide" rather than remaining unchanged. > > --- > > > > Mark's part toggling code got me thinking about how needlessly > > complicated our other show-mode invisibility code was. This patch is > > a shot at fixing that. It will require a bit of reworking after part > > toggling goes in (owning to the aforementioned non-composability, part > > toggling needs to be intimately aware of wash and message hiding). > > However, I think this patch should wait until after the release > > freeze; this code is fragile (though much less so after this patch), > > so I'd rather it soak for a release than cause user-visible bugs for > > no user-visible gain. > > > > emacs/notmuch-show.el | 42 +++------------------ > > emacs/notmuch-wash.el | 97 ++++++------------------------------------------- > > 2 files changed, 17 insertions(+), 122 deletions(-) > > > > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el > > index 7d9f8a9..4bdd5af 100644 > > --- a/emacs/notmuch-show.el > > +++ b/emacs/notmuch-show.el > > @@ -872,27 +872,8 @@ message at DEPTH in the current thread." > > message-start message-end > > content-start content-end > > headers-start headers-end > > - body-start body-end > > - (headers-invis-spec (notmuch-show-make-symbol "header")) > > - (message-invis-spec (notmuch-show-make-symbol "message")) > > (bare-subject (notmuch-show-strip-re (plist-get headers :Subject)))) > > > > - ;; Set `buffer-invisibility-spec' to `nil' (a list), otherwise > > - ;; removing items from `buffer-invisibility-spec' (which is what > > - ;; `notmuch-show-headers-visible' and > > - ;; `notmuch-show-message-visible' do) is a no-op and has no > > - ;; effect. This caused threads with only matching messages to have > > - ;; those messages hidden initially because > > - ;; `buffer-invisibility-spec' stayed `t'. > > - ;; > > - ;; This needs to be set here (rather than just above the call to > > - ;; `notmuch-show-headers-visible') because some of the part > > - ;; rendering or body washing functions > > - ;; (e.g. `notmuch-wash-text/plain-citations') manipulate > > - ;; `buffer-invisibility-spec'). > > - (when (eq buffer-invisibility-spec t) > > - (setq buffer-invisibility-spec nil)) > > - > > (setq message-start (point-marker)) > > > > (notmuch-show-insert-headerline headers > > @@ -904,9 +885,6 @@ message at DEPTH in the current thread." > > > > (setq content-start (point-marker)) > > > > - (plist-put msg :headers-invis-spec headers-invis-spec) > > - (plist-put msg :message-invis-spec message-invis-spec) > > - > > ;; Set `headers-start' to point after the 'Subject:' header to be > > ;; compatible with the existing implementation. This just sets it > > ;; to after the first header. > > @@ -924,7 +902,6 @@ message at DEPTH in the current thread." > > > > (setq notmuch-show-previous-subject bare-subject) > > > > - (setq body-start (point-marker)) > > ;; A blank line between the headers and the body. > > (insert "\n") > > (notmuch-show-insert-body msg (plist-get msg :body) > > @@ -932,7 +909,6 @@ message at DEPTH in the current thread." > > ;; Ensure that the body ends with a newline. > > (unless (bolp) > > (insert "\n")) > > - (setq body-end (point-marker)) > > (setq content-end (point-marker)) > > > > ;; Indent according to the depth in the thread. > > @@ -945,11 +921,9 @@ message at DEPTH in the current thread." > > ;; message. > > (put-text-property message-start message-end :notmuch-message-extent (cons message-start message-end)) > > > > - (let ((headers-overlay (make-overlay headers-start headers-end)) > > - (invis-specs (list headers-invis-spec message-invis-spec))) > > - (overlay-put headers-overlay 'invisible invis-specs) > > - (overlay-put headers-overlay 'priority 10)) > > - (overlay-put (make-overlay body-start body-end) 'invisible message-invis-spec) > > + ;; Create overlays used to control visibility > > + (plist-put msg :headers-overlay (make-overlay headers-start headers-end)) > > + (plist-put msg :message-overlay (make-overlay headers-start content-end)) > > I am puzzled by this (though it was essentially the same before): > http://www.gnu.org/software/emacs/manual/html_node/elisp/Other-Plists.html > says that "This stores value as the value of the property property in > the property list plist. It may modify plist destructively, or it may > construct a new list structure without altering the old." Does this mean > that this might work but it might not? Yeah, I know. The show code does this all over the place, so I was being consistent. Code like this depends on unspecified behavior, but it is reliable given the actual implementation of plist-put, which will always add new properties to the end of the plist by mutation. Hence the only time the setq is *actually* necessary is when plist-put-ing to an empty plist, and msg will never be an empty plist. > Otherwise, though, this looks good to me. > > My inclination is to get this in and then do the part invisibility on > top. One reason is that I think we definitely want to go this route > soon and if we do it just after the next release we may end up with bugs > being reported (bugs in my invisibility stuff) that there's not much > point in fixing as mainline has diverged. > > Best wishes > > Mark