1 Return-Path: <jani@nikula.org>
\r
2 X-Original-To: notmuch@notmuchmail.org
\r
3 Delivered-To: notmuch@notmuchmail.org
\r
4 Received: from localhost (localhost [127.0.0.1])
\r
5 by olra.theworths.org (Postfix) with ESMTP id 8E002431FB6
\r
6 for <notmuch@notmuchmail.org>; Tue, 17 Apr 2012 02:58:20 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5
\r
12 tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled
\r
13 Received: from olra.theworths.org ([127.0.0.1])
\r
14 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
15 with ESMTP id cFHKOenqjoIz for <notmuch@notmuchmail.org>;
\r
16 Tue, 17 Apr 2012 02:58:16 -0700 (PDT)
\r
17 Received: from mail-qc0-f181.google.com (mail-qc0-f181.google.com
\r
18 [209.85.216.181]) (using TLSv1 with cipher RC4-SHA (128/128 bits))
\r
19 (No client certificate requested)
\r
20 by olra.theworths.org (Postfix) with ESMTPS id 9F55F431FAE
\r
21 for <notmuch@notmuchmail.org>; Tue, 17 Apr 2012 02:58:16 -0700 (PDT)
\r
22 Received: by qcsk26 with SMTP id k26so4648239qcs.26
\r
23 for <notmuch@notmuchmail.org>; Tue, 17 Apr 2012 02:58:16 -0700 (PDT)
\r
24 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
\r
25 d=google.com; s=20120113;
\r
26 h=from:to:subject:in-reply-to:references:user-agent:date:message-id
\r
27 :mime-version:content-type:x-gm-message-state;
\r
28 bh=Bty/NDpfJZnspuai5BZaVMK5l5phv4gf6byMKxbrBYg=;
\r
29 b=OKvljrvm5LyaO9NFJEMTCm6FFhOTVQj4b4/99Trt1aImELuTaIAB9wHxjw4gtYIGGU
\r
30 dackCLLBw0FRFNSiikP+KnEZa2GTgBSIShJZ8Fo3Scv5JtXsIjylQ56oyb4K9pywGFBI
\r
31 2BS78mpQ6IFvlnzQXQRqlmd4EysyGu5cSnrTHccWRnL46yO8YEHxAQ+FmFH6NaBKDuVW
\r
32 k+S5Elow62ByGRf+pspy3/RCIFfNMkJEAyoN1LndNKXWXxNpIVWlyzCmPCGGsYwuhZOU
\r
33 vhf7On7GXJZAPnOMW6jsO9KTALwHUMoE5eX+qnvu5HS1RSRaxObnNxyA3pDSBsRiiWjw
\r
35 Received: by 10.224.39.211 with SMTP id h19mr19924717qae.24.1334656695982;
\r
36 Tue, 17 Apr 2012 02:58:15 -0700 (PDT)
\r
37 Received: from localhost (nikula.org. [92.243.24.172])
\r
38 by mx.google.com with ESMTPS id g10sm2058363qae.11.2012.04.17.02.58.13
\r
39 (version=SSLv3 cipher=OTHER); Tue, 17 Apr 2012 02:58:15 -0700 (PDT)
\r
40 From: Jani Nikula <jani@nikula.org>
\r
41 To: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>, notmuch@notmuchmail.org
\r
42 Subject: Re: [RFC PATCH 1/4] emacs: simplify point placement in notmuch-hello
\r
43 In-Reply-To: <87aa2aohjs.fsf@gmail.com>
\r
45 <bcfdc0d1969997e89e5abe0b320d77ee2109796a.1334651669.git.jani@nikula.org>
\r
46 <87aa2aohjs.fsf@gmail.com>
\r
47 User-Agent: Notmuch/0.11.1+222~ga47a98c (http://notmuchmail.org) Emacs/23.1.1
\r
49 Date: Tue, 17 Apr 2012 09:58:11 +0000
\r
50 Message-ID: <878vhuvfws.fsf@nikula.org>
\r
52 Content-Type: text/plain; charset=us-ascii
\r
54 ALoCoQmHXQbNirF8HlPXP/3lngz68n4Xjn/PCBBS4rytiR0cGhXnK7XWrbjVB15/uZZnUcckd1d/
\r
55 X-BeenThere: notmuch@notmuchmail.org
\r
56 X-Mailman-Version: 2.1.13
\r
58 List-Id: "Use and development of the notmuch mail system."
\r
59 <notmuch.notmuchmail.org>
\r
60 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
61 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
62 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
63 List-Post: <mailto:notmuch@notmuchmail.org>
\r
64 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
65 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
66 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
67 X-List-Received-Date: Tue, 17 Apr 2012 09:58:20 -0000
\r
69 On Tue, 17 Apr 2012 13:04:39 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
\r
72 > Jani Nikula <jani@nikula.org> writes:
\r
74 > > notmuch-hello (called also through notmuch-hello-update, bound to '='
\r
75 > > by default) tries to find the widget under or following point before
\r
76 > > refresh, and put the point back to the widget afterwards. The code has
\r
77 > > gotten a bit complicated, and has at least the following issues:
\r
79 > > 1) All the individual section functions have to include code to
\r
80 > > support point placement. If there is no such support, point is
\r
81 > > dropped to the search box. Only saved searches and all tags
\r
82 > > sections support point placement.
\r
84 > > 2) Point placement is based on widget-value. If there are two widgets
\r
85 > > with the same widget-value (for example a saved search with the
\r
86 > > same name as a tag) the point is moved to the earlier one.
\r
88 > > 3) When first entering notmuch-hello notmuch-hello-target is nil, and
\r
89 > > point is dropped to the search box.
\r
91 > > This patch simplifies the code by removing all point placement based
\r
92 > > on widgets. Point is simply saved before refresh, and put back to
\r
93 > > where it was. Sometimes, but not very often, this would have the
\r
94 > > appearance of moving the point relative to the nearest widgets. IMHO
\r
95 > > this is a minor problem compared to the issues listed above.
\r
97 > > A downside is that there's no visual cue (point movement) to indicate
\r
98 > > that refresh has finished. Then again, neither was there before, if
\r
99 > > point was at the beginning of a widget.
\r
101 > Thanks for looking into this. This is an annoying issue indeed. And I
\r
102 > was thinking about fixing it myself.
\r
104 > I am not sure I like the approach of moving the cursor to the same
\r
105 > position. It is common that buffer content would change significantly
\r
106 > after a refresh (e.g. after I archived all new mail). That would mean
\r
107 > the cursor would just randomly jump somewhere. IMO we should allow
\r
108 > smart cursor positioning which means that logic should go to individual
\r
110 > I would propose the following plan:
\r
112 > 1. Remove special case for search box. No section should be special.
\r
113 > Moreover it is possible to remove it (I did it) and in that case the
\r
114 > cursor would be left at the end of the buffer. By default, the
\r
115 > cursor should be moved to the beginning of the buffer.
\r
117 > 2. Replace current cursor positioning logic with section specific code.
\r
118 > I.e. `notmuch-hello' would not do any cursor positioning (except for
\r
119 > item 1) but queries and tags section would save required state when a
\r
120 > button is clicked and the same section would use this state to
\r
121 > restore cursor position on refresh. What state should be saved would
\r
122 > depend on the section but we should at least save the section
\r
123 > name/ID. If during refresh no section set the cursor position, then
\r
124 > the cursor is moved to the beginning of the buffer.
\r
126 > 3. Provide a custom variable to set the default section to move the
\r
127 > cursor to. I.e. set the section name/ID part of the state from item
\r
128 > 2. Again, details on what the default position inside the section is
\r
129 > would depend on the section. For search box, it would be the input
\r
130 > field. For queries/tags it would be the first tag.
\r
132 > Item 1 is pretty simple. The rest may be more tricky. What do you
\r
135 My approach was this: keep it extremely simple, and catch the low
\r
136 hanging fruit. It places the point where I want, say, 90% of the
\r
137 time. And when it's wrong, it's not far off. In contrast, the current
\r
138 implementation places the cursor exactly where I do *not* want it about
\r
141 What you describe sounds smart, but complicated. Maybe it just sounds
\r
142 complicated from my limited lisp skills perspective. Personally I don't
\r
143 think sections should have to implement their own logic for point
\r
144 placement. And as a fallback, I prefer keeping the point where it is
\r
145 instead of moving it to the beginning of buffer.
\r
147 I don't oppose to your plan, but I don't think I'm up to implementing it
\r
148 either. I just cooked up something together to fix the #1 annoyance I've
\r
149 lately had with notmuch, and Tomi persuaded me to share the patches as
\r
150 RFC. I still think it's pretty good, considering the simplicity of it
\r
151 all, but certainly not perfect.
\r
163 > > emacs/notmuch-hello.el | 70 +++++++++++------------------------------------
\r
164 > > 1 files changed, 17 insertions(+), 53 deletions(-)
\r
166 > > diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
\r
167 > > index 71d37b8..9cd907a 100644
\r
168 > > --- a/emacs/notmuch-hello.el
\r
169 > > +++ b/emacs/notmuch-hello.el
\r
170 > > @@ -154,11 +154,6 @@ International Bureau of Weights and Measures."
\r
171 > > (defvar notmuch-hello-url "http://notmuchmail.org"
\r
172 > > "The `notmuch' web site.")
\r
174 > > -(defvar notmuch-hello-search-pos nil
\r
175 > > - "Position of search widget, if any.
\r
177 > > -This should only be set by `notmuch-hello-insert-search'.")
\r
179 > > (defvar notmuch-hello-custom-section-options
\r
180 > > '((:filter (string :tag "Filter for each tag"))
\r
181 > > (:filter-count (string :tag "Different filter to generate message counts"))
\r
182 > > @@ -209,11 +204,8 @@ function produces a section simply by adding content to the current
\r
183 > > buffer. A section should not end with an empty line, because a
\r
184 > > newline will be inserted after each section by `notmuch-hello'.
\r
186 > > -Each function should take no arguments. If the produced section
\r
187 > > -includes `notmuch-hello-target' (i.e. cursor should be positioned
\r
188 > > -inside this section), the function should return this element's
\r
190 > > -Otherwise, it should return nil.
\r
191 > > +Each function should take no arguments. The return value is
\r
194 > > For convenience an element can also be a list of the form (FUNC ARG1
\r
195 > > ARG2 .. ARGN) in which case FUNC will be applied to the rest of the
\r
196 > > @@ -240,15 +232,6 @@ supported for \"Customized queries section\" items."
\r
197 > > notmuch-hello-query-section
\r
198 > > (function :tag "Custom section"))))
\r
200 > > -(defvar notmuch-hello-target nil
\r
201 > > - "Button text at position of point before rebuilding the notmuch-buffer.
\r
203 > > -This variable contains the text of the button, if any, the
\r
204 > > -point was positioned at before the notmuch-hello buffer was
\r
205 > > -rebuilt. This should never actually be global and is defined as a
\r
206 > > -defvar only for documentation purposes and to avoid a compiler
\r
207 > > -warning about it occurring as a free variable.")
\r
209 > > (defvar notmuch-hello-hidden-sections nil
\r
210 > > "List of sections titles whose contents are hidden")
\r
212 > > @@ -449,8 +432,6 @@ Such a list can be computed with `notmuch-hello-query-counts'."
\r
213 > > (msg-count (third elem)))
\r
214 > > (widget-insert (format "%8s "
\r
215 > > (notmuch-hello-nice-number msg-count)))
\r
216 > > - (if (string= name notmuch-hello-target)
\r
217 > > - (setq found-target-pos (point-marker)))
\r
218 > > (widget-create 'push-button
\r
219 > > :notify #'notmuch-hello-widget-search
\r
220 > > :notmuch-search-terms query
\r
221 > > @@ -589,7 +570,6 @@ Complete list of currently available key bindings:
\r
222 > > (defun notmuch-hello-insert-search ()
\r
223 > > "Insert a search widget."
\r
224 > > (widget-insert "Search: ")
\r
225 > > - (setq notmuch-hello-search-pos (point-marker))
\r
226 > > (widget-create 'editable-field
\r
227 > > ;; Leave some space at the start and end of the
\r
228 > > ;; search boxes.
\r
229 > > @@ -763,13 +743,7 @@ following:
\r
230 > > (set-buffer "*notmuch-hello*")
\r
231 > > (switch-to-buffer "*notmuch-hello*"))
\r
233 > > - (let ((notmuch-hello-target (if (widget-at)
\r
234 > > - (widget-value (widget-at))
\r
235 > > - (condition-case nil
\r
237 > > - (widget-forward 1)
\r
238 > > - (widget-value (widget-at)))
\r
239 > > - (error nil))))
\r
240 > > + (let ((final-target-pos (point))
\r
241 > > (inhibit-read-only t))
\r
243 > > ;; Delete all editable widget fields. Editable widget fields are
\r
244 > > @@ -788,30 +762,20 @@ following:
\r
245 > > (mapc 'delete-overlay (car all))
\r
246 > > (mapc 'delete-overlay (cdr all)))
\r
248 > > - (let (final-target-pos)
\r
250 > > - (lambda (section)
\r
251 > > - (let ((point-before (point))
\r
252 > > - (result (if (functionp section)
\r
253 > > - (funcall section)
\r
254 > > - (apply (car section) (cdr section)))))
\r
255 > > - (if (and (not final-target-pos) (integer-or-marker-p result))
\r
256 > > - (setq final-target-pos result))
\r
257 > > - ;; don't insert a newline when the previous section didn't show
\r
259 > > - (unless (eq (point) point-before)
\r
260 > > - (widget-insert "\n"))))
\r
261 > > - notmuch-hello-sections)
\r
262 > > - (widget-setup)
\r
264 > > - (when final-target-pos
\r
265 > > - (goto-char final-target-pos)
\r
266 > > - (unless (widget-at)
\r
267 > > - (widget-forward 1)))
\r
269 > > - (unless (widget-at)
\r
270 > > - (when notmuch-hello-search-pos
\r
271 > > - (goto-char notmuch-hello-search-pos)))))
\r
273 > > + (lambda (section)
\r
274 > > + (let ((point-before (point)))
\r
275 > > + (if (functionp section)
\r
276 > > + (funcall section)
\r
277 > > + (apply (car section) (cdr section)))
\r
278 > > + ;; don't insert a newline when the previous section didn't
\r
279 > > + ;; show anything.
\r
280 > > + (unless (eq (point) point-before)
\r
281 > > + (widget-insert "\n"))))
\r
282 > > + notmuch-hello-sections)
\r
283 > > + (widget-setup)
\r
285 > > + (goto-char final-target-pos))
\r
286 > > (run-hooks 'notmuch-hello-refresh-hook)
\r
287 > > (setq notmuch-hello-first-run nil))
\r
292 > > _______________________________________________
\r
293 > > notmuch mailing list
\r
294 > > notmuch@notmuchmail.org
\r
295 > > http://notmuchmail.org/mailman/listinfo/notmuch
\r