[PATCH 4/6] emacs: Support overriding help and describing prefix action

2013-10-06 Thread Mark Walters

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

2013-10-06 Thread Jani Nikula
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

2013-10-06 Thread Austin Clements
---
 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

2013-10-06 Thread Austin Clements
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

2013-10-06 Thread Austin Clements
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

2013-10-06 Thread Austin Clements
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

2013-10-06 Thread Austin Clements
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

2013-10-06 Thread Austin Clements
`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

2013-10-06 Thread Austin Clements
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

2013-10-06 Thread Jani Nikula
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

2013-10-06 Thread Mark Walters

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

2013-10-06 Thread Ethan Glasser-Camp
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

2013-10-06 Thread Tomi Ollila
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)