[PATCH 4/6] emacs: Support overriding help and describing prefix action
This whole series looks good to me. If you are rolling another version for any reason I have one trivial comment On Sun, 06 Oct 2013, Austin Clements wrote: > Traditionally, function documentation strings are intended primarily > for programmers, rather than users. They're written from the > perspective of calling the function, not interactively invoking it. > They're only ever displayed along with the function prototype (and > often refer to argument names). And built-in help commands like > `describe-bindings' show the name of the command, not its > documentation. > > The notmuch help system is like `describe-bindings', but tries to be > more user-friendly by displaying documentation strings, rather than > Elisp command names. For most commands, this is fine, but for some > the "programmer description" is inappropriate for interactive use. > This is particularly noticeable for commands that take an optional > prefix argument. > > This patch adds support for two symbol properties: notmuch-doc and > notmuch-prefix-doc, which let a command override its interactive > documentation and provide separate documentation for its prefixed > invocation. If notmuch-prefix-doc is present, we add an extra line to > the help giving the prefixed key sequence along with the documentation > for the prefixed command. > --- > emacs/notmuch.el | 29 - > 1 file changed, 24 insertions(+), 5 deletions(-) > > diff --git a/emacs/notmuch.el b/emacs/notmuch.el > index a36849f..278bd35 100644 > --- a/emacs/notmuch.el > +++ b/emacs/notmuch.el > @@ -140,7 +140,7 @@ This is basically just `format-kbd-macro' but we also > convert ESC to M-." > "M-" >(concat desc " " > > -(defun notmuch-describe-keymap (keymap prefix tail) > +(defun notmuch-describe-keymap (keymap ua-keys prefix tail) >"Return a list of strings, each describing one key in KEYMAP. > > Each string gives a human-readable description of the key and the It would be nice to document the ua-keys variable here. It took me some time to work out what was going in (and I worked out based on the caller). Best wishes Mark > @@ -151,10 +151,19 @@ first line of documentation for the bound function." > ((keymapp binding) > (setq tail > (notmuch-describe-keymap > -binding (notmuch-prefix-key-description key) tail))) > +binding ua-keys (notmuch-prefix-key-description key) tail))) > (t > + (when (and ua-keys (symbolp binding) > +(get binding 'notmuch-prefix-doc)) > + ;; Documentation for prefixed command > + (let ((ua-desc (key-description ua-keys))) > + (push (concat ua-desc " " prefix (format-kbd-macro (vector key)) > + "\t" (get binding 'notmuch-prefix-doc)) > + tail))) > + ;; Documentation for command > (push (concat prefix (format-kbd-macro (vector key)) "\t" > - (notmuch-documentation-first-line binding)) > + (or (and (symbolp binding) (get binding 'notmuch-doc)) > + (notmuch-documentation-first-line binding))) > tail > keymap) >tail) > @@ -165,14 +174,24 @@ first line of documentation for the bound function." > (while (string-match "{\\([^}[:space:]]*\\)}" doc beg) >(let* ((keymap-name (substring doc (match-beginning 1) (match-end 1))) >(keymap (symbol-value (intern keymap-name))) > - (desc-list (notmuch-describe-keymap keymap)) > + (ua-keys (where-is-internal 'universal-argument keymap t)) > + (desc-list (notmuch-describe-keymap keymap ua-keys)) >(desc (mapconcat #'identity desc-list "\n"))) > (setq doc (replace-match desc 1 1 doc))) >(setq beg (match-end 0))) > doc)) > > (defun notmuch-help () > - "Display help for the current notmuch mode." > + "Display help for the current notmuch mode. > + > +This is similar to `describe-function' for the current major > +mode, but bindings tables are shown with documentation strings > +rather than command names. By default, this uses the first line > +of each command's documentation string. A command can override > +this by setting the 'notmuch-doc property of its command symbol. > +A command that supports a prefix argument can explicitly document > +its prefixed behavior by setting the 'notmuch-prefix-doc property > +of its command symbol." >(interactive) >(let* ((mode major-mode) >(doc (substitute-command-keys (notmuch-substitute-command-keys > (documentation mode t) > -- > 1.8.4.rc3 > > ___ > notmuch mailing list > notmuch at notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch
Emacs: how to remove "unread" tag while reading emails
On Sat, 05 Oct 2013, Austin Clements wrote: > One of the problems with the current approach, which most of these > options share, is that there's no feedback. For example, when I enter > a thread, I have no idea if the first message was unread or not. Agreed. And this gets repeated for navigating messages within the thread. Very annoying. This should be fixed. Two other things I find annoying: * I often find myself glancing at the first few lines of the message to decide whether I want to read it now or later (potentially never). I still want the unread information be retained if I decide to archive or move on to the next thread, so I often end up restoring the unread tag. So the marking as read is too eager. * I sometimes use the arrow keys and page down/up to read through messages, and this leaves messages unread even though I've read them. So the marking as read is not eager enough. > I'd like a solution that either naturally doesn't have this problem, > that visually indicates that a message *was* unread, or that delays > all unread marking until you leave the thread (possibly combined with > a visual indication of what will be marked unread). Bonus points if > it's easy to adjust what happens, such as saying "keep everything > unread" or "keep everything unread except this one". I'd like to have the visual indication. > To this end, here are my two proposals: > > A1) Mark whole thread read when you leave it (via q, X, A or friends) > and provide a binding to leave a thread without marking it read (C-x k > would do, but we should provide an explicit one; perhaps C-u prefixing > other "leave" bindings? For once, C-u is easy to remember because u > is the first letter of unread). I think I'd like to keep this message based instead of thread based. However it's very difficult to know for sure until one actually gets to try it. I do switch between show buffers (for example, while reading a message, I need to check something from another message) and the marking as read might get lost. Also, it's not clear to me what happens if you refresh the buffer and new messages show up in the thread. Again, difficult to know in advance. My message based proposal: Don't do anything when you enter a message. This keeps the unread tag visible if it's there. Mark each message as read on actions you do when the point already is within the message: n/N/p/P/SPC/a/x/A/X/q/r/R/f (others?), arrow keys, and page up/down, *unless* the action is prefixed with C-u. Collapsed messages would never be marked as read. RET to expand would mark as read. This still does not provide visual indication of the removal of the unread tag in a way that would be always visible. But I think it's more important to know whether the message *was* unread before or not. Here's a proposal independent of the marking-as-read topic that would help with the visual indication: We currently set header-line-format (the top header in show view) to the subject of the first message. The usefulness of the header line could be improved a lot. We could make it reflect the message the point is currently on, with user configurable format not unlike notmuch-search-result-format. Including tags. And this would provide visual indication for marking as read when the message header is not visible. The header would also help in navigating long threads with long messages. > In either case, I'd like an echo message when I leave the thread > telling me what happened ("Thread marked as read", "First 3 messages > marked as read; thread archived", etc.). These would blend especially > well with undo, because they would bundle together all read marking > into a single action that would make sense to undo ("Thread marked as > read [C-/ to undo]"). This might be useful with the message based approach, although it might be too verbose, and a new annoyance... BR, Jani.
[PATCH 6/6] News for Emacs help improvements
--- NEWS | 8 1 file changed, 8 insertions(+) diff --git a/NEWS b/NEWS index 2e845f4..4f3b98a 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,14 @@ New options to better support handling duplicate messages bigger than the number of matching messages due to duplicates (i.e. multiple files having the same message-id). +Emacs Interface +--- + +Built-in help improvements + + Documentation for many commands has been improved, as displayed by + `notmuch-help` (usually bound to "?"). The bindings listed by + `notmuch-help` also now include descriptions of prefixed commands. Notmuch 0.16 (2013-08-03) = -- 1.8.4.rc3
[PATCH 5/6] emacs: Improve interactive use documentation
This improves the function documentation for many interactive commands, either by improving their documentation string where the improvement also makes sense for programmatic use or by adding a 'notmuch-doc property where it doesn't. For nearly all commands that support a prefix argument, this adds a 'notmuch-prefix-doc property to document their prefixed behavior This omits prefix documentation for a few commands where I thought the prefixed behavior was too obscure (or too complex to fit in one line). --- emacs/notmuch-mua.el | 3 ++- emacs/notmuch-show.el | 26 -- emacs/notmuch.el | 11 +-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index f6006ee..53802d2 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -313,8 +313,9 @@ the From: header is already filled in by notmuch." (ido-completing-read "Send mail From: " notmuch-identities nil nil nil 'notmuch-mua-sender-history (car notmuch-identities) +(put 'notmuch-mua-new-mail 'notmuch-prefix-doc "... and prompt for sender") (defun notmuch-mua-new-mail ( prompt-for-sender) - "Invoke the notmuch mail composition window. + "Compose new mail. If PROMPT-FOR-SENDER is non-nil, the user will be prompted for the From: address first." diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 7758eaf..7325792 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1488,6 +1488,8 @@ current thread." "Are the headers of the current message visible?" (notmuch-show-get-prop :headers-visible)) +(put 'notmuch-show-mark-read 'notmuch-prefix-doc + "Mark the current message as unread.") (defun notmuch-show-mark-read ( unread) "Mark the current message as read. @@ -1609,16 +1611,20 @@ any effects from previous calls to ;; Move to the previous message. (notmuch-show-previous-message) +(put 'notmuch-show-reply 'notmuch-prefix-doc "... and prompt for sender") (defun notmuch-show-reply ( prompt-for-sender) "Reply to the sender and all recipients of the current message." (interactive "P") (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender t)) +(put 'notmuch-show-reply-sender 'notmuch-prefix-doc "... and prompt for sender") (defun notmuch-show-reply-sender ( prompt-for-sender) "Reply to the sender of the current message." (interactive "P") (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender nil)) +(put 'notmuch-show-forward-message 'notmuch-prefix-doc + "... and prompt for sender") (defun notmuch-show-forward-message ( prompt-for-sender) "Forward the current message." (interactive "P") @@ -1722,6 +1728,10 @@ to show, nil otherwise." (set-buffer-modified-p nil) (view-buffer buf 'kill-buffer-if-not-modified))) +(put 'notmuch-show-pipe-message 'notmuch-doc + "Pipe the contents of the current message to a command.") +(put 'notmuch-show-pipe-message 'notmuch-prefix-doc + "Pipe the thread as an mbox to a command.") (defun notmuch-show-pipe-message (entire-thread command) "Pipe the contents of the current message (or thread) to COMMAND. @@ -1795,12 +1805,16 @@ See `notmuch-tag' for information on the format of TAG-CHANGES." (notmuch-show-set-tags new-tags)) (defun notmuch-show-add-tag () - "Same as `notmuch-show-tag' but sets initial input to '+'." + "Change tags for the current message (defaulting to add). + +Same as `notmuch-show-tag' but sets initial input to '+'." (interactive) (notmuch-show-tag "+")) (defun notmuch-show-remove-tag () - "Same as `notmuch-show-tag' but sets initial input to '-'." + "Change tags for the current message (defaulting to remove). + +Same as `notmuch-show-tag' but sets initial input to '-'." (interactive) (notmuch-show-tag "-")) @@ -1822,6 +1836,8 @@ See `notmuch-tag' for information on the format of TAG-CHANGES." (not (plist-get props :message-visible (force-window-update)) +(put 'notmuch-show-open-or-close-all 'notmuch-doc "Show all messages.") +(put 'notmuch-show-open-or-close-all 'notmuch-prefix-doc "Hide all messages.") (defun notmuch-show-open-or-close-all () "Set the visibility all of the messages in the current thread. @@ -1873,6 +1889,8 @@ search results instead." (interactive) (notmuch-show-next-thread t t)) +(put 'notmuch-show-archive-thread 'notmuch-prefix-doc + "Un-archive each message in thread.") (defun notmuch-show-archive-thread ( unarchive) "Archive each message in thread. @@ -1902,6 +1920,8 @@ buffer." (notmuch-show-archive-thread) (notmuch-show-next-thread)) +(put 'notmuch-show-archive-message 'notmuch-prefix-doc + "Un-archive the current message.") (defun notmuch-show-archive-message ( unarchive) "Archive the current message. @@ -1953,6 +1973,8 @@ thread from search." (interactive) (notmuch-common-do-stash (notmuch-show-get-from))) +(put
[PATCH 4/6] emacs: Support overriding help and describing prefix action
Traditionally, function documentation strings are intended primarily for programmers, rather than users. They're written from the perspective of calling the function, not interactively invoking it. They're only ever displayed along with the function prototype (and often refer to argument names). And built-in help commands like `describe-bindings' show the name of the command, not its documentation. The notmuch help system is like `describe-bindings', but tries to be more user-friendly by displaying documentation strings, rather than Elisp command names. For most commands, this is fine, but for some the "programmer description" is inappropriate for interactive use. This is particularly noticeable for commands that take an optional prefix argument. This patch adds support for two symbol properties: notmuch-doc and notmuch-prefix-doc, which let a command override its interactive documentation and provide separate documentation for its prefixed invocation. If notmuch-prefix-doc is present, we add an extra line to the help giving the prefixed key sequence along with the documentation for the prefixed command. --- emacs/notmuch.el | 29 - 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index a36849f..278bd35 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -140,7 +140,7 @@ This is basically just `format-kbd-macro' but we also convert ESC to M-." "M-" (concat desc " " -(defun notmuch-describe-keymap (keymap prefix tail) +(defun notmuch-describe-keymap (keymap ua-keys prefix tail) "Return a list of strings, each describing one key in KEYMAP. Each string gives a human-readable description of the key and the @@ -151,10 +151,19 @@ first line of documentation for the bound function." ((keymapp binding) (setq tail (notmuch-describe-keymap - binding (notmuch-prefix-key-description key) tail))) + binding ua-keys (notmuch-prefix-key-description key) tail))) (t + (when (and ua-keys (symbolp binding) + (get binding 'notmuch-prefix-doc)) + ;; Documentation for prefixed command + (let ((ua-desc (key-description ua-keys))) + (push (concat ua-desc " " prefix (format-kbd-macro (vector key)) + "\t" (get binding 'notmuch-prefix-doc)) + tail))) + ;; Documentation for command (push (concat prefix (format-kbd-macro (vector key)) "\t" - (notmuch-documentation-first-line binding)) + (or (and (symbolp binding) (get binding 'notmuch-doc)) + (notmuch-documentation-first-line binding))) tail keymap) tail) @@ -165,14 +174,24 @@ first line of documentation for the bound function." (while (string-match "{\\([^}[:space:]]*\\)}" doc beg) (let* ((keymap-name (substring doc (match-beginning 1) (match-end 1))) (keymap (symbol-value (intern keymap-name))) -(desc-list (notmuch-describe-keymap keymap)) +(ua-keys (where-is-internal 'universal-argument keymap t)) +(desc-list (notmuch-describe-keymap keymap ua-keys)) (desc (mapconcat #'identity desc-list "\n"))) (setq doc (replace-match desc 1 1 doc))) (setq beg (match-end 0))) doc)) (defun notmuch-help () - "Display help for the current notmuch mode." + "Display help for the current notmuch mode. + +This is similar to `describe-function' for the current major +mode, but bindings tables are shown with documentation strings +rather than command names. By default, this uses the first line +of each command's documentation string. A command can override +this by setting the 'notmuch-doc property of its command symbol. +A command that supports a prefix argument can explicitly document +its prefixed behavior by setting the 'notmuch-prefix-doc property +of its command symbol." (interactive) (let* ((mode major-mode) (doc (substitute-command-keys (notmuch-substitute-command-keys (documentation mode t) -- 1.8.4.rc3
[PATCH 3/6] emacs: Clean up a few documentation strings
Correct some grammatical errors, fix some violations of standard documentation string formatting conventions, and be more precise. --- emacs/notmuch-show.el | 18 ++ emacs/notmuch.el | 10 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 5d7e24b..7758eaf 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1575,7 +1575,7 @@ shown." (notmuch-show-archive-thread-then-next))) (defun notmuch-show-rewind () - "Backup through the thread, (reverse scrolling compared to \\[notmuch-show-advance-and-archive]). + "Backup through the thread (reverse scrolling compared to \\[notmuch-show-advance-and-archive]). Specifically, if the beginning of the previous email is fewer than `window-height' lines from the current point, move to it @@ -1723,15 +1723,16 @@ to show, nil otherwise." (view-buffer buf 'kill-buffer-if-not-modified))) (defun notmuch-show-pipe-message (entire-thread command) - "Pipe the contents of the current message (or thread) to the given command. + "Pipe the contents of the current message (or thread) to COMMAND. -The given command will be executed with the raw contents of the -current email message as stdin. Anything printed by the command -to stdout or stderr will appear in the *notmuch-pipe* buffer. +COMMAND will be executed with the raw contents of the current +email message as stdin. Anything printed by the command to stdout +or stderr will appear in the *notmuch-pipe* buffer. -When invoked with a prefix argument, the command will receive all -open messages in the current thread (formatted as an mbox) rather -than only the current message." +If ENTIRE-THREAD is non-nil (or when invoked with a prefix +argument), COMMAND will receive all open messages in the current +thread (formatted as an mbox) rather than only the current +message." (interactive (let ((query-string (if current-prefix-arg "Pipe all open messages to command: " "Pipe message to command: "))) @@ -1823,6 +1824,7 @@ See `notmuch-tag' for information on the format of TAG-CHANGES." (defun notmuch-show-open-or-close-all () "Set the visibility all of the messages in the current thread. + By default make all of the messages visible. With a prefix argument, hide all of the messages." (interactive) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 0ff248b..a36849f 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -869,15 +869,15 @@ PROMPT is the string to prompt with." ;;;###autoload (defun notmuch-search ( query oldest-first target-thread target-line) - "Run \"notmuch search\" with the given `query' and display results. + "Display threads matching QUERY in a notmuch-search buffer. -If `query' is nil, it is read interactively from the minibuffer. +If QUERY is nil, it is read interactively from the minibuffer. Other optional parameters are used as follows: - oldest-first: A Boolean controlling the sort order of returned threads - target-thread: A thread ID (without the thread: prefix) that will be made + OLDEST-FIRST: A Boolean controlling the sort order of returned threads + TARGET-THREAD: A thread ID (without the thread: prefix) that will be made current if it appears in the search results. - target-line: The line number to move to if the target thread does not + TARGET-LINE: The line number to move to if the target thread does not appear in the search results. When called interactively, this will prompt for a query and use -- 1.8.4.rc3
[PATCH 2/6] emacs: `notmuch-mua-new-reply' is also not interactive
Like `notmuch-mua-new-forward-message', this is meant to be invoked programmatically by something that can provide a reasonable query string. In fact, `notmuch-mua-new-reply's interactive specification didn't match its arguments, so it wouldn't have worked interactively. --- emacs/notmuch-mua.el | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index dbb0dae..f6006ee 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -340,8 +340,11 @@ the From: address first." (notmuch-mua-forward-message))) (defun notmuch-mua-new-reply (query-string prompt-for-sender reply-all) - "Invoke the notmuch reply window." - (interactive "P") + "Compose a reply to the message identified by QUERY-STRING. + +If PROMPT-FOR-SENDER is non-nil, the user will be prompted for +the From: address first. If REPLY-ALL is non-nil, the message +will be addressed to all recipients of the source message." (let ((sender (when prompt-for-sender (notmuch-mua-prompt-for-sender -- 1.8.4.rc3
[PATCH 1/6] emacs: `notmuch-mua-new-forward-message' is not interactive
`notmuch-mua-new-forward-message' must be called from a buffer containing a raw RFC2822-formatted message to forward. Hence, it's intended to be invoked programmatically through something else that sets up this buffer (like `notmuch-show-forward-message'), not interactively. Remove its interactive specification and update the documentation string to mention the requirements on the current buffer. --- emacs/notmuch-mua.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index d41c0b3..dbb0dae 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -327,9 +327,10 @@ the From: address first." (defun notmuch-mua-new-forward-message ( prompt-for-sender) "Invoke the notmuch message forwarding window. +The current buffer must contain an RFC2822 message to forward. + If PROMPT-FOR-SENDER is non-nil, the user will be prompted for the From: address first." - (interactive "P") (if (or prompt-for-sender notmuch-always-prompt-for-sender) (let* ((sender (notmuch-mua-prompt-for-sender)) (address-components (mail-extract-address-components sender)) -- 1.8.4.rc3
[PATCH 0/6] emacs: Built-in help improvements and clean up doc strings
The first three patches in this series simply fix some function documentation string problems I found while making the other patches. I'm marking them trivial because they don't affect any code. The rest of this series improves a bunch of the built-in Emacs help, accessed through `notmuch-help' (bound to "?" by default). In addition to improving some documentation strings, it introduces a new facility to `notmuch-help' to explicitly specify interactive documentation and documentation for prefixed commands. For example, where notmuch-help currently says m Invoke the notmuch mail composition window. with this series, it says m Compose new mail. C-u m ... and prompt for sender Feel free to point out commands I missed (or post patches for them). I went through all bound commands in hello, search, and show, as well as all prefixed commands, but didn't go through unbound, non-prefixed commands.
Re: Emacs: how to remove unread tag while reading emails
On Sat, 05 Oct 2013, Austin Clements amdra...@mit.edu wrote: One of the problems with the current approach, which most of these options share, is that there's no feedback. For example, when I enter a thread, I have no idea if the first message was unread or not. Agreed. And this gets repeated for navigating messages within the thread. Very annoying. This should be fixed. Two other things I find annoying: * I often find myself glancing at the first few lines of the message to decide whether I want to read it now or later (potentially never). I still want the unread information be retained if I decide to archive or move on to the next thread, so I often end up restoring the unread tag. So the marking as read is too eager. * I sometimes use the arrow keys and page down/up to read through messages, and this leaves messages unread even though I've read them. So the marking as read is not eager enough. I'd like a solution that either naturally doesn't have this problem, that visually indicates that a message *was* unread, or that delays all unread marking until you leave the thread (possibly combined with a visual indication of what will be marked unread). Bonus points if it's easy to adjust what happens, such as saying keep everything unread or keep everything unread except this one. I'd like to have the visual indication. To this end, here are my two proposals: A1) Mark whole thread read when you leave it (via q, X, A or friends) and provide a binding to leave a thread without marking it read (C-x k would do, but we should provide an explicit one; perhaps C-u prefixing other leave bindings? For once, C-u is easy to remember because u is the first letter of unread). I think I'd like to keep this message based instead of thread based. However it's very difficult to know for sure until one actually gets to try it. I do switch between show buffers (for example, while reading a message, I need to check something from another message) and the marking as read might get lost. Also, it's not clear to me what happens if you refresh the buffer and new messages show up in the thread. Again, difficult to know in advance. My message based proposal: Don't do anything when you enter a message. This keeps the unread tag visible if it's there. Mark each message as read on actions you do when the point already is within the message: n/N/p/P/SPC/a/x/A/X/q/r/R/f (others?), arrow keys, and page up/down, *unless* the action is prefixed with C-u. Collapsed messages would never be marked as read. RET to expand would mark as read. This still does not provide visual indication of the removal of the unread tag in a way that would be always visible. But I think it's more important to know whether the message *was* unread before or not. Here's a proposal independent of the marking-as-read topic that would help with the visual indication: We currently set header-line-format (the top header in show view) to the subject of the first message. The usefulness of the header line could be improved a lot. We could make it reflect the message the point is currently on, with user configurable format not unlike notmuch-search-result-format. Including tags. And this would provide visual indication for marking as read when the message header is not visible. The header would also help in navigating long threads with long messages. In either case, I'd like an echo message when I leave the thread telling me what happened (Thread marked as read, First 3 messages marked as read; thread archived, etc.). These would blend especially well with undo, because they would bundle together all read marking into a single action that would make sense to undo (Thread marked as read [C-/ to undo]). This might be useful with the message based approach, although it might be too verbose, and a new annoyance... BR, Jani. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 4/6] emacs: Support overriding help and describing prefix action
This whole series looks good to me. If you are rolling another version for any reason I have one trivial comment On Sun, 06 Oct 2013, Austin Clements amdra...@mit.edu wrote: Traditionally, function documentation strings are intended primarily for programmers, rather than users. They're written from the perspective of calling the function, not interactively invoking it. They're only ever displayed along with the function prototype (and often refer to argument names). And built-in help commands like `describe-bindings' show the name of the command, not its documentation. The notmuch help system is like `describe-bindings', but tries to be more user-friendly by displaying documentation strings, rather than Elisp command names. For most commands, this is fine, but for some the programmer description is inappropriate for interactive use. This is particularly noticeable for commands that take an optional prefix argument. This patch adds support for two symbol properties: notmuch-doc and notmuch-prefix-doc, which let a command override its interactive documentation and provide separate documentation for its prefixed invocation. If notmuch-prefix-doc is present, we add an extra line to the help giving the prefixed key sequence along with the documentation for the prefixed command. --- emacs/notmuch.el | 29 - 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index a36849f..278bd35 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -140,7 +140,7 @@ This is basically just `format-kbd-macro' but we also convert ESC to M-. M- (concat desc -(defun notmuch-describe-keymap (keymap optional prefix tail) +(defun notmuch-describe-keymap (keymap ua-keys optional prefix tail) Return a list of strings, each describing one key in KEYMAP. Each string gives a human-readable description of the key and the It would be nice to document the ua-keys variable here. It took me some time to work out what was going in (and I worked out based on the caller). Best wishes Mark @@ -151,10 +151,19 @@ first line of documentation for the bound function. ((keymapp binding) (setq tail (notmuch-describe-keymap -binding (notmuch-prefix-key-description key) tail))) +binding ua-keys (notmuch-prefix-key-description key) tail))) (t + (when (and ua-keys (symbolp binding) +(get binding 'notmuch-prefix-doc)) + ;; Documentation for prefixed command + (let ((ua-desc (key-description ua-keys))) + (push (concat ua-desc prefix (format-kbd-macro (vector key)) + \t (get binding 'notmuch-prefix-doc)) + tail))) + ;; Documentation for command (push (concat prefix (format-kbd-macro (vector key)) \t - (notmuch-documentation-first-line binding)) + (or (and (symbolp binding) (get binding 'notmuch-doc)) + (notmuch-documentation-first-line binding))) tail keymap) tail) @@ -165,14 +174,24 @@ first line of documentation for the bound function. (while (string-match {\\([^}[:space:]]*\\)} doc beg) (let* ((keymap-name (substring doc (match-beginning 1) (match-end 1))) (keymap (symbol-value (intern keymap-name))) - (desc-list (notmuch-describe-keymap keymap)) + (ua-keys (where-is-internal 'universal-argument keymap t)) + (desc-list (notmuch-describe-keymap keymap ua-keys)) (desc (mapconcat #'identity desc-list \n))) (setq doc (replace-match desc 1 1 doc))) (setq beg (match-end 0))) doc)) (defun notmuch-help () - Display help for the current notmuch mode. + Display help for the current notmuch mode. + +This is similar to `describe-function' for the current major +mode, but bindings tables are shown with documentation strings +rather than command names. By default, this uses the first line +of each command's documentation string. A command can override +this by setting the 'notmuch-doc property of its command symbol. +A command that supports a prefix argument can explicitly document +its prefixed behavior by setting the 'notmuch-prefix-doc property +of its command symbol. (interactive) (let* ((mode major-mode) (doc (substitute-command-keys (notmuch-substitute-command-keys (documentation mode t) -- 1.8.4.rc3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: On disk tag storage format
Ethan Glasser-Camp ethan.glasser.c...@gmail.com writes: I've modified the script so that it would run by mangling filenames, which is irreversible (the original tried to encode/decode filenames reversibly). Then I got a little carried away, adding --verbose and --dry-run options as well as removing a couple trailing semicolons. Here's my version, in case it should interest anyone else. Hi guys, There was a bug in the previous version I sent. It didn't handle unlinking tags correctly. Also, I spotted a bug in syncing to untagged messages. Maybe I should stop using emails as version control. 8 # Copyright 2013, David Bremner da...@tethera.net # Licensed under the same terms as notmuch. import notmuch import re import os, errno import sys from collections import defaultdict import argparse import hashlib # skip automatic and maildir tags skiptags = re.compile(r^(attachement|signed|encrypted|draft|flagged|passed|replied|unread)$) # some random person on stack overflow suggests: def mkdir_p(path): try: os.makedirs(path) except OSError as exc: # Python 2.5 if exc.errno == errno.EEXIST and os.path.isdir(path): pass else: raise VERBOSE = False def log(msg): if VERBOSE: print(msg) CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_@=.,-' encode_re = '([^{0}])'.format(CHARSET) decode_re = '[%]([0-7][0-9A-Fa-f])' def encode_one_char(match): return('%{:02x}'.format(ord(match.group(1 def encode_for_fs(str): return re.sub(encode_re,encode_one_char, str,0) def mangle_message_id(msg_id): Return a mangled version of the message id, suitable for use as a filename. MAX_LENGTH = 143 FLAGS_LENGTH = 8# :2,S...?? encoded = encode_for_fs(msg_id) if len(encoded) MAX_LENGTH - FLAGS_LENGTH: return encoded SHA_LENGTH = 8 TRUNCATED_ID_LENGTH = MAX_LENGTH - SHA_LENGTH - FLAGS_LENGTH PREFIX_LENGTH = SUFFIX_LENGTH = (TRUNCATED_ID_LENGTH - 3) // 2 prefix = encoded[:PREFIX_LENGTH] suffix = encoded[-SUFFIX_LENGTH:] sha = hashlib.sha256() sha.update(encoded) return prefix + '...' + suffix + sha.hexdigest()[:SHA_LENGTH] def decode_one_char(match): return chr(int(match.group(1),16)) def decode_from_fs(str): return re.sub(decode_re,decode_one_char, str, 0) def mk_tag_dir(tagdir): mkdir_p (os.path.join(tagdir, 'cur')) mkdir_p (os.path.join(tagdir, 'new')) mkdir_p (os.path.join(tagdir, 'tmp')) flagpart = '(:2,[^:]*)' flagre = re.compile(flagpart + '$'); def path_for_msg (dir, msg): filename = msg.get_filename() flagsmatch = flagre.search(filename) if flagsmatch == None: flags = '' else: flags = flagsmatch.group(1) return os.path.join(dir, 'cur', mangle_message_id(msg.get_message_id()) + flags) def unlink_message(dir, msg): dir = os.path.join(dir, 'cur') mangled_id = mangle_message_id(msg.get_message_id()) filepattern = '^' + re.escape(mangled_id) + flagpart +'?$' filere = re.compile(filepattern) for file in os.listdir(dir): if filere.match(file): log(Unlinking {}.format(os.path.join(dir, file))) if not opts.dry_run: os.unlink(os.path.join(dir, file)) def dir_for_tag(tag): enc_tag = encode_for_fs (tag) return os.path.join(tagroot, enc_tag) disk_tags = defaultdict(set) disk_ids = set() def read_tags_from_disk(rootdir): for root, subFolders, files in os.walk(rootdir): for filename in files: mangled_id = filename.split(':')[0] tag = root.split('/')[-2] disk_ids.add(mangled_id) disk_tags[mangled_id].add(decode_from_fs(tag)) # Main program parser = argparse.ArgumentParser(description='Sync notmuch tag database to/from link farm') parser.add_argument('-l','--link-style',choices=['hard','symbolic', 'adaptive'], default='adaptive') parser.add_argument('-d','--destination',choices=['disk','notmuch'], default='disk') parser.add_argument('-t','--threshold', default=5L, type=int) parser.add_argument('-n','--dry-run', default=False, action='store_true') parser.add_argument('-v','--verbose', default=False, action='store_true') parser.add_argument('tagroot') opts=parser.parse_args() VERBOSE = opts.verbose tagroot=opts.tagroot sync_from_links = (opts.destination == 'notmuch') read_tags_from_disk(tagroot) if sync_from_links: db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE) else: db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY) dbtags = filter (lambda tag: not skiptags.match(tag), db.get_all_tags()) if sync_from_links: # have to iterate over even untagged messages querystr = '*' else: querystr = ' OR '.join(map (lambda tag: 'tag:'+tag, dbtags)) q_new = notmuch.Query(db, querystr) q_new.set_sort(notmuch.Query.SORT.UNSORTED) for msg in q_new.search_messages(): # silently ignore
Re: [PATCH 4/6] emacs: Support overriding help and describing prefix action
On Sun, Oct 06 2013, Mark Walters markwalters1...@gmail.com wrote: This whole series looks good to me. If you are rolling another version for any reason I have one trivial comment On Sun, 06 Oct 2013, Austin Clements amdra...@mit.edu wrote: Traditionally, function documentation strings are intended primarily for programmers, rather than users. They're written from the perspective of calling the function, not interactively invoking it. They're only ever displayed along with the function prototype (and often refer to argument names). And built-in help commands like `describe-bindings' show the name of the command, not its documentation. The notmuch help system is like `describe-bindings', but tries to be more user-friendly by displaying documentation strings, rather than Elisp command names. For most commands, this is fine, but for some the programmer description is inappropriate for interactive use. This is particularly noticeable for commands that take an optional prefix argument. This patch adds support for two symbol properties: notmuch-doc and notmuch-prefix-doc, which let a command override its interactive documentation and provide separate documentation for its prefixed invocation. If notmuch-prefix-doc is present, we add an extra line to the help giving the prefixed key sequence along with the documentation for the prefixed command. --- emacs/notmuch.el | 29 - 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index a36849f..278bd35 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -140,7 +140,7 @@ This is basically just `format-kbd-macro' but we also convert ESC to M-. M- (concat desc -(defun notmuch-describe-keymap (keymap optional prefix tail) +(defun notmuch-describe-keymap (keymap ua-keys optional prefix tail) Return a list of strings, each describing one key in KEYMAP. Each string gives a human-readable description of the key and the This series Looks Good To Me, too. It would be nice to document the ua-keys variable here. It took me some time to work out what was going in (and I worked out based on the caller). I did not have any problems understanding this -- probably due to me having played so much with where-is-internal and such commands... ... just that this looks to me as 'first-ua-key' (ua being unversal argument, not user agent ;) If there is need for new version then documenting this would not hurt... if not followup-patch to add this documentation (w/ one line commit message for least review effort! ;) could do) Tomi Best wishes Mark @@ -151,10 +151,19 @@ first line of documentation for the bound function. ((keymapp binding) (setq tail (notmuch-describe-keymap - binding (notmuch-prefix-key-description key) tail))) + binding ua-keys (notmuch-prefix-key-description key) tail))) (t +(when (and ua-keys (symbolp binding) + (get binding 'notmuch-prefix-doc)) + ;; Documentation for prefixed command + (let ((ua-desc (key-description ua-keys))) +(push (concat ua-desc prefix (format-kbd-macro (vector key)) + \t (get binding 'notmuch-prefix-doc)) + tail))) +;; Documentation for command (push (concat prefix (format-kbd-macro (vector key)) \t - (notmuch-documentation-first-line binding)) + (or (and (symbolp binding) (get binding 'notmuch-doc)) + (notmuch-documentation-first-line binding))) tail keymap) tail) @@ -165,14 +174,24 @@ first line of documentation for the bound function. (while (string-match {\\([^}[:space:]]*\\)} doc beg) (let* ((keymap-name (substring doc (match-beginning 1) (match-end 1))) (keymap (symbol-value (intern keymap-name))) - (desc-list (notmuch-describe-keymap keymap)) + (ua-keys (where-is-internal 'universal-argument keymap t)) + (desc-list (notmuch-describe-keymap keymap ua-keys)) (desc (mapconcat #'identity desc-list \n))) (setq doc (replace-match desc 1 1 doc))) (setq beg (match-end 0))) doc)) (defun notmuch-help () - Display help for the current notmuch mode. + Display help for the current notmuch mode. + +This is similar to `describe-function' for the current major +mode, but bindings tables are shown with documentation strings +rather than command names. By default, this uses the first line +of each command's documentation string. A command can override +this by setting the 'notmuch-doc property of its command symbol. +A command that supports a prefix argument can explicitly document +its prefixed behavior by setting the 'notmuch-prefix-doc property +of its command symbol. (interactive)