* [PATCH v1 0/3] Address completion entirely in elisp. @ 2014-09-05 12:59 David Edmondson 2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson ` (3 more replies) 0 siblings, 4 replies; 7+ messages in thread From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw) To: notmuch Address completion entirely in elisp. I grew frustrated with having to use an external command to provide address completion, as they all had annoyances (up front scanning, requiring python bindings, etc.). This is an attempt to provide something similar to jkr's notmuch-addresses.py (which I was previously using) entirely in elisp, relying only on the `notmuch' command. David Edmondson (3): emacs: Allow query to exclude the entire thread and body. emacs: Add `notmuch-user-all-email'. emacs: Add an address completer in elisp. emacs/notmuch-address.el | 49 +++++++++++++++++++++++++++++++++++++++++++----- emacs/notmuch-lib.el | 4 ++++ emacs/notmuch-query.el | 7 ++++++- 3 files changed, 54 insertions(+), 6 deletions(-) -- 1.8.5.2 (Apple Git-48) ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body. 2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson @ 2014-09-05 12:59 ` David Edmondson 2014-09-05 12:59 ` [PATCH v1 2/3] emacs: Add `notmuch-user-all-email' David Edmondson ` (2 subsequent siblings) 3 siblings, 0 replies; 7+ messages in thread From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw) To: notmuch Callers to `notmuch-query-get-threads' can optionally choose not to receive either the entire thread and/or the body of messages. This is intended to reduce the amount of output in cases where one or both of these items is not useful. --- emacs/notmuch-query.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el index d1daffc..f83ca9b 100644 --- a/emacs/notmuch-query.el +++ b/emacs/notmuch-query.el @@ -21,7 +21,8 @@ (require 'notmuch-lib) -(defun notmuch-query-get-threads (search-terms) +(defun notmuch-query-get-threads (search-terms &optional exclude-entire-thread + exclude-body) "Return a list of threads of messages matching SEARCH-TERMS. A thread is a forest or list of trees. A tree is a two element @@ -31,6 +32,10 @@ is a possibly empty forest of replies. (let ((args '("show" "--format=sexp" "--format-version=1"))) (if notmuch-show-process-crypto (setq args (append args '("--decrypt")))) + (if exclude-entire-thread + (setq args (append args '("--entire-thread=false")))) + (if exclude-body + (setq args (append args '("--body=false")))) (setq args (append args search-terms)) (apply #'notmuch-call-notmuch-sexp args))) -- 1.8.5.2 (Apple Git-48) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 2/3] emacs: Add `notmuch-user-all-email'. 2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson 2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson @ 2014-09-05 12:59 ` David Edmondson 2014-09-05 12:59 ` [PATCH v1 3/3] emacs: Add an address completer in elisp David Edmondson 2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters 3 siblings, 0 replies; 7+ messages in thread From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw) To: notmuch `notmuch-user-all-email' returns a list of the user's primary and secondary email addresses. --- emacs/notmuch-lib.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el index 19269e3..685469c 100644 --- a/emacs/notmuch-lib.el +++ b/emacs/notmuch-lib.el @@ -228,6 +228,10 @@ on the command line, and then retry your notmuch command"))) "Return the user.other_email value (as a list) from the notmuch configuration." (split-string (notmuch-config-get "user.other_email") "\n" t)) +(defun notmuch-user-all-email () + "Return all email addresses for the user from the notmuch configuration." + (append (list (notmuch-user-primary-email)) (notmuch-user-other-email))) + (defun notmuch-poll () "Run \"notmuch new\" or an external script to import mail. -- 1.8.5.2 (Apple Git-48) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 3/3] emacs: Add an address completer in elisp. 2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson 2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson 2014-09-05 12:59 ` [PATCH v1 2/3] emacs: Add `notmuch-user-all-email' David Edmondson @ 2014-09-05 12:59 ` David Edmondson 2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters 3 siblings, 0 replies; 7+ messages in thread From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw) To: notmuch Rather than relying on an external comment to provide address completion in composition mode, provide a solution purely in elisp. Update `notmuch-address-command' to allow it to specify an external command or a function, with the default remaining as an external command called "notmuch-addresses". --- emacs/notmuch-address.el | 49 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/emacs/notmuch-address.el b/emacs/notmuch-address.el index fa65cd5..449fa54 100644 --- a/emacs/notmuch-address.el +++ b/emacs/notmuch-address.el @@ -24,10 +24,17 @@ ;; (defcustom notmuch-address-command "notmuch-addresses" - "The command which generates possible addresses. It must take a -single argument and output a list of possible matches, one per -line." - :type 'string + "Command or function which generates possible addresses. + +A command must take a single argument and output a list of +possible matches, one per line. + +A function must take a single argument and return a list of +possible matches." + :type '(choice (string :tag "External command") + (function :tag "Standard function" + :value notmuch-address-option-generator) + (function :tag "Custom function")) :group 'notmuch-send :group 'notmuch-external) @@ -42,6 +49,32 @@ to know how address selection is made by default." :group 'notmuch-send :group 'notmuch-external) +(defun notmuch-address-extractor (message) + "Return a list of addresses mentioned in `message'." + (let* ((headers (plist-get message :headers)) + (from (plist-get headers :From))) + from)) + +(defun notmuch-address-option-generator (initial) + "Generate a set of possible address completions for `initial'." + (let* ((my-addresses (notmuch-user-all-email)) + (query (list (format "(%s) AND from:%s*" + (mapconcat (lambda (a) (concat "to:" a)) + my-addresses " OR ") + initial))) + bare-results + results) + (dolist (address + (notmuch-query-map-threads 'notmuch-address-extractor + (notmuch-query-get-threads query t t))) + (when address + (let ((bare-address (cadr (std11-extract-address-components address)))) + (unless (or (member bare-address my-addresses) + (member bare-address bare-results)) + (push bare-address bare-results) + (push address results))))) + results)) + (defun notmuch-address-selection-function (prompt collection initial-input) "Call (`completing-read' PROMPT COLLECTION nil nil INITIAL-INPUT 'notmuch-address-history)" @@ -60,7 +93,13 @@ to know how address selection is made by default." (push notmuch-address-message-alist-member message-completion-alist)))) (defun notmuch-address-options (original) - (process-lines notmuch-address-command original)) + (cond + ((stringp notmuch-address-command) + (process-lines notmuch-address-command original)) + ((functionp notmuch-address-command) + (funcall notmuch-address-command original)) + (t + (error "No address completion mechanism defined.")))) (defun notmuch-address-expand-name () (let* ((end (point)) -- 1.8.5.2 (Apple Git-48) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v1 0/3] Address completion entirely in elisp. 2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson ` (2 preceding siblings ...) 2014-09-05 12:59 ` [PATCH v1 3/3] emacs: Add an address completer in elisp David Edmondson @ 2014-09-05 15:29 ` Mark Walters 2014-09-05 16:06 ` David Edmondson 3 siblings, 1 reply; 7+ messages in thread From: Mark Walters @ 2014-09-05 15:29 UTC (permalink / raw) To: David Edmondson, notmuch Hi On Fri, 05 Sep 2014, David Edmondson <dme@dme.org> wrote: > Address completion entirely in elisp. > > I grew frustrated with having to use an external command to provide > address completion, as they all had annoyances (up front scanning, > requiring python bindings, etc.). This is an attempt to provide > something similar to jkr's notmuch-addresses.py (which I was > previously using) entirely in elisp, relying only on the `notmuch' > command. Just a few quick comments: the first is relevant to others trying this patch. 1) You seem to be missing a (require 'std11) somewhere. I did this via M-: and then it ran fine. 2) It is not quick on a spinning rust disk. This may not be relevant as the delay is probably notmuch so would also be the case if I were using notmuch-addresses.py (i normally just use a trivial script that parses my .mailrc) 3) Have you tried id:1407771091-12651-1-git-send-email-sojkam1@fel.cvut.cz and do you have any comments on the comparison? 4) Finally, I wonder if we would be worth approaching the backend notmuch use slightly differently: if we added a notmuch_messages_collect_from function which was very similar to notmuch_messages_collect_tags, and added a corresponding --output=from to notmuch search then you would get the information you need very quickly. I think it might be a lot faster as I think the from header is stored in the database but some other headers are not, so that the current method the show --body=false needs to look at the actually messages I should emphasise that none of the above means I am opposed to the patch: having respectable built in address-completion support would be very nice. Best wishes Mark > > > David Edmondson (3): > emacs: Allow query to exclude the entire thread and body. > emacs: Add `notmuch-user-all-email'. > emacs: Add an address completer in elisp. > > emacs/notmuch-address.el | 49 +++++++++++++++++++++++++++++++++++++++++++----- > emacs/notmuch-lib.el | 4 ++++ > emacs/notmuch-query.el | 7 ++++++- > 3 files changed, 54 insertions(+), 6 deletions(-) > > -- > 1.8.5.2 (Apple Git-48) > > _______________________________________________ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1 0/3] Address completion entirely in elisp. 2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters @ 2014-09-05 16:06 ` David Edmondson 2014-09-06 8:14 ` [PATCH] cli: add --output=address-{from,to,all} to notmuch search Jani Nikula 0 siblings, 1 reply; 7+ messages in thread From: David Edmondson @ 2014-09-05 16:06 UTC (permalink / raw) To: Mark Walters, notmuch On Fri, Sep 05 2014, Mark Walters wrote: > On Fri, 05 Sep 2014, David Edmondson <dme@dme.org> wrote: >> Address completion entirely in elisp. >> >> I grew frustrated with having to use an external command to provide >> address completion, as they all had annoyances (up front scanning, >> requiring python bindings, etc.). This is an attempt to provide >> something similar to jkr's notmuch-addresses.py (which I was >> previously using) entirely in elisp, relying only on the `notmuch' >> command. > > Just a few quick comments: the first is relevant to others trying this > patch. > > 1) You seem to be missing a (require 'std11) somewhere. I did this via M-: > and then it ran fine. My apologies. Will fix (and a compiler warning at the same time). > 2) It is not quick on a spinning rust disk. This may not be relevant as > the delay is probably notmuch so would also be the case if I were using > notmuch-addresses.py (i normally just use a trivial script that parses > my .mailrc) It's not always as fast as I would like on SSD either :-) The mechanism is very similar to the equivalent Python program, so I think that it's probably about the same. > 3) Have you tried > id:1407771091-12651-1-git-send-email-sojkam1@fel.cvut.cz and do you have > any comments on the comparison? No, I will dig it out and look. > 4) Finally, I wonder if we would be worth approaching the backend > notmuch use slightly differently: if we added a > notmuch_messages_collect_from function which was very similar to > notmuch_messages_collect_tags, and added a corresponding --output=from > to notmuch search then you would get the information you need very > quickly. I think it might be a lot faster as I think the from header is > stored in the database but some other headers are not, so that the > current method the show --body=false needs to look at the actually > messages Extending notmuch to help with this was next on my list of things to do. At the moment I just needed a solution that worked. > I should emphasise that none of the above means I am opposed to the > patch: having respectable built in address-completion support would be > very nice. Cool, thanks! ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] cli: add --output=address-{from,to,all} to notmuch search 2014-09-05 16:06 ` David Edmondson @ 2014-09-06 8:14 ` Jani Nikula 0 siblings, 0 replies; 7+ messages in thread From: Jani Nikula @ 2014-09-06 8:14 UTC (permalink / raw) To: notmuch, David Edmondson, Mark Walters address-from prints reply-to or from, address-to prints to, cc, and bcc, and address-all prints all of them. --- Mark, David - I wrote most of this almost two years ago, but wasn't really happy with it. There's address deduplication, but for large result sets that might use lots of memory. Maybe the --duplicate option could be overloaded for doing or not doing deduplication. I'd like to have some way of picking the prettiest (that's subjective too) name part to go with the address, now it's just the first encountered. And so on. But maybe this will be useful for you, and you can pick some ideas. I won't have the time to do much on this. Cheers, Jani. --- notmuch-search.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/notmuch-search.c b/notmuch-search.c index bc9be4593ecc..33da90eaceec 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -26,6 +26,9 @@ typedef enum { OUTPUT_SUMMARY, OUTPUT_THREADS, OUTPUT_MESSAGES, + OUTPUT_ADDRESS_FROM, + OUTPUT_ADDRESS_TO, + OUTPUT_ADDRESS_ALL, OUTPUT_FILES, OUTPUT_TAGS } output_t; @@ -214,6 +217,78 @@ do_search_threads (sprinter_t *format, return 0; } +static void +print_address_list (sprinter_t *format, GHashTable *addrs, + InternetAddressList *list) +{ + InternetAddress *address; + int i; + + for (i = 0; i < internet_address_list_length (list); i++) { + address = internet_address_list_get_address (list, i); + if (INTERNET_ADDRESS_IS_GROUP (address)) { + InternetAddressGroup *group; + InternetAddressList *group_list; + + group = INTERNET_ADDRESS_GROUP (address); + group_list = internet_address_group_get_members (group); + if (group_list == NULL) + continue; + + print_address_list (format, addrs, group_list); + } else { + InternetAddressMailbox *mailbox; + const char *name; + const char *addr; + char *full_address; + + mailbox = INTERNET_ADDRESS_MAILBOX (address); + + name = internet_address_get_name (address); + addr = internet_address_mailbox_get_addr (mailbox); + + if (g_hash_table_lookup_extended (addrs, addr, NULL, NULL)) + continue; + + g_hash_table_insert (addrs, talloc_strdup (NULL, addr), NULL); + + if (name && *name) + full_address = talloc_asprintf (NULL, "%s <%s>", name, addr); + else + full_address = talloc_asprintf (NULL, "<%s>", addr); + + if (!full_address) + break; + + format->string (format, full_address); + format->separator (format); + + talloc_free (full_address); + } + } +} + +static void +print_address_string (sprinter_t *format, GHashTable *addrs, const char *recipients) +{ + InternetAddressList *list; + + if (recipients == NULL) + return; + + list = internet_address_list_parse_string (recipients); + if (list == NULL) + return; + + print_address_list (format, addrs, list); +} + +static void +_my_talloc_free_for_g_hash (void *ptr) +{ + talloc_free (ptr); +} + static int do_search_messages (sprinter_t *format, notmuch_query_t *query, @@ -225,8 +300,14 @@ do_search_messages (sprinter_t *format, notmuch_message_t *message; notmuch_messages_t *messages; notmuch_filenames_t *filenames; + GHashTable *addresses = NULL; int i; + if (output == OUTPUT_ADDRESS_FROM || output == OUTPUT_ADDRESS_TO || + output == OUTPUT_ADDRESS_ALL) + addresses = g_hash_table_new_full (g_str_hash, g_str_equal, + _my_talloc_free_for_g_hash, NULL); + if (offset < 0) { offset += notmuch_query_count_messages (query); if (offset < 0) @@ -264,16 +345,41 @@ do_search_messages (sprinter_t *format, notmuch_filenames_destroy( filenames ); - } else { /* output == OUTPUT_MESSAGES */ + } else if (output == OUTPUT_MESSAGES) { format->set_prefix (format, "id"); format->string (format, notmuch_message_get_message_id (message)); format->separator (format); + } else { + if (output == OUTPUT_ADDRESS_FROM || output == OUTPUT_ADDRESS_ALL) { + const char *addrs; + + addrs = notmuch_message_get_header (message, "reply-to"); + + if (addrs == NULL || *addrs == '\0') + addrs = notmuch_message_get_header (message, "from"); + + print_address_string (format, addresses, addrs); + } + + if (output == OUTPUT_ADDRESS_TO || output == OUTPUT_ADDRESS_ALL) { + const char *hdrs[] = { "to", "cc", "bcc" }; + const char *addrs; + size_t j; + + for (j = 0; j < ARRAY_SIZE (hdrs); j++) { + addrs = notmuch_message_get_header (message, hdrs[j]); + print_address_string (format, addresses, addrs); + } + } } notmuch_message_destroy (message); } + if (addresses) + g_hash_table_unref (addresses); + notmuch_messages_destroy (messages); format->end (format); @@ -368,6 +474,9 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[]) (notmuch_keyword_t []){ { "summary", OUTPUT_SUMMARY }, { "threads", OUTPUT_THREADS }, { "messages", OUTPUT_MESSAGES }, + { "address-from", OUTPUT_ADDRESS_FROM }, + { "address-to", OUTPUT_ADDRESS_TO }, + { "address-all", OUTPUT_ADDRESS_ALL }, { "files", OUTPUT_FILES }, { "tags", OUTPUT_TAGS }, { 0, 0 } } }, @@ -459,6 +568,9 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[]) ret = do_search_threads (format, query, sort, output, offset, limit); break; case OUTPUT_MESSAGES: + case OUTPUT_ADDRESS_FROM: + case OUTPUT_ADDRESS_TO: + case OUTPUT_ADDRESS_ALL: case OUTPUT_FILES: ret = do_search_messages (format, query, output, offset, limit, dupe); break; -- 2.1.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2014-09-06 8:14 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson 2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson 2014-09-05 12:59 ` [PATCH v1 2/3] emacs: Add `notmuch-user-all-email' David Edmondson 2014-09-05 12:59 ` [PATCH v1 3/3] emacs: Add an address completer in elisp David Edmondson 2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters 2014-09-05 16:06 ` David Edmondson 2014-09-06 8:14 ` [PATCH] cli: add --output=address-{from,to,all} to notmuch search Jani Nikula
Code repositories for project(s) associated with this public inbox https://yhetil.org/notmuch.git/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).