From 735366a138a301fb86f83b8434ecff8c8da35d16 Mon Sep 17 00:00:00 2001 From: jao Date: Thu, 10 Jun 2021 22:32:45 +0100 Subject: [PATCH] Allow sorting in notmuch-tree search buffers. - CLI/show: accept --sort - emacs/hello: honouring :sort-order in threaded queries - emacs/tree: command to toggle search sort order in tree mode --- devel/emacs-keybindings.org | 10 +++++----- doc/man1/notmuch-show.rst | 13 +++++++++++++ doc/notmuch-emacs.rst | 7 +++++++ emacs/notmuch-hello.el | 4 +++- emacs/notmuch-tree.el | 24 +++++++++++++++++++----- notmuch-show.c | 7 +++++++ test/T520-show.sh | 17 +++++++++++++++++ 7 files changed, 71 insertions(+), 11 deletions(-) diff --git a/devel/emacs-keybindings.org b/devel/emacs-keybindings.org index 65dfe0eb..f7df3040 100644 --- a/devel/emacs-keybindings.org +++ b/devel/emacs-keybindings.org @@ -15,7 +15,7 @@ | l | notmuch-search-filter | notmuch-show-filter-thread | | | m | notmuch-mua-new-mail | notmuch-mua-new-mail | notmuch-mua-new-mail | | n | notmuch-search-next-thread | notmuch-show-next-open-message | notmuch-tree-next-matching-message | -| o | notmuch-search-toggle-order | | | +| o | notmuch-search-toggle-order | | notmuch-tree-toggle-order | | p | notmuch-search-previous-thread | notmuch-show-previous-open-message | notmuch-tree-prev-matching-message | | q | notmuch-bury-or-kill-this-buffer | notmuch-bury-or-kill-this-buffer | notmuch-bury-or-kill-this-buffer | | r | notmuch-search-reply-to-thread-sender | notmuch-show-reply-sender | notmuch-show-reply-sender | @@ -38,10 +38,10 @@ | V | | notmuch-show-view-raw-message | notmuch-show-view-raw-message | | X | | notmuch-show-archive-thread-then-exit | | | Z | notmuch-tree-from-search-current-query | notmuch-tree-from-show-current-query | | -| =!= | | notmuch-show-toggle-elide-non-matching | | -| =#= | | notmuch-show-print-message | | -| =$= | | notmuch-show-toggle-process-crypto | | -| =*= | notmuch-search-tag-all | notmuch-show-tag-all | notmuch-tree-tag-thread | +| =!= | | notmuch-show-toggle-elide-non-matching | | +| =#= | | notmuch-show-print-message | | +| =$= | | notmuch-show-toggle-process-crypto | | +| =*= | notmuch-search-tag-all | notmuch-show-tag-all | notmuch-tree-tag-thread | | + | notmuch-search-add-tag | notmuch-show-add-tag | notmuch-tree-add-tag | | - | notmuch-search-remove-tag | notmuch-show-remove-tag | notmuch-tree-remove-tag | | . | | notmuch-show-part-map | | diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst index fc6bec62..64639174 100644 --- a/doc/man1/notmuch-show.rst +++ b/doc/man1/notmuch-show.rst @@ -111,6 +111,19 @@ Supported options for **show** include part still has two MIME parts: part 0 is the whole message (headers and body) and part 1 is just the body. +.. option:: --sort=(newest-first|oldest-first) + + This option can be used to present results in either chronological + order (**oldest-first**) or reverse chronological order + (**newest-first**). + + Only threads as a whole are reordered. Ordering of messages within + each thread will not be affected by this flag, since that order is + always determined by the thread's replies. + + By default, results will be displayed in reverse chronological + order, (that is, the newest results will be displayed first). + .. option:: --verify Compute and report the validity of any MIME cryptographic diff --git a/doc/notmuch-emacs.rst b/doc/notmuch-emacs.rst index 7772871b..952fe2a5 100644 --- a/doc/notmuch-emacs.rst +++ b/doc/notmuch-emacs.rst @@ -299,12 +299,19 @@ tags. ``p`` Move to previous matching message +``o`` ``notmuch-tree-toggle-order`` + |docstring::notmuch-tree-toggle-order| + ``g`` ``=`` Refresh the buffer ``?`` Display full set of key bindings +As is the case with :ref:`notmuch-search`, the presentation of results +can be controlled by the variable ``notmuch-search-oldest-first``. + + Global key bindings =================== diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 531f209d..5e1ff5fe 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -484,7 +484,9 @@ diagonal." (defun notmuch-hello-widget-search (widget &rest _ignore) (cl-case (widget-get widget :notmuch-search-type) (tree - (notmuch-tree (widget-get widget :notmuch-search-terms))) + (notmuch-tree (widget-get widget :notmuch-search-terms) + nil nil nil nil nil nil + (widget-get widget :notmuch-search-oldest-first))) (unthreaded (notmuch-unthreaded (widget-get widget :notmuch-search-terms))) (t diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el index 00ee78d6..c421cf3f 100644 --- a/emacs/notmuch-tree.el +++ b/emacs/notmuch-tree.el @@ -326,6 +326,7 @@ then NAME behaves like CMD." (define-key map [remap notmuch-mua-new-mail] 'notmuch-tree-new-mail) (define-key map [remap notmuch-jump-search] 'notmuch-tree-jump-search) + (define-key map "o" 'notmuch-tree-toggle-order) (define-key map "S" 'notmuch-search-from-tree-current-query) (define-key map "U" 'notmuch-unthreaded-from-tree-current-query) (define-key map "Z" 'notmuch-tree-from-unthreaded-current-query) @@ -749,7 +750,8 @@ nil otherwise." query-context target nil - unthreaded))) + unthreaded + notmuch-search-oldest-first))) (defun notmuch-tree-thread-top () (when (notmuch-tree-get-message-properties) @@ -1062,7 +1064,8 @@ Complete list of currently available key bindings: (notmuch-sexp-parse-partial-list 'notmuch-tree-insert-forest-thread results-buf))))) -(defun notmuch-tree-worker (basic-query &optional query-context target open-target unthreaded) +(defun notmuch-tree-worker (basic-query &optional query-context target + open-target unthreaded oldest-first) "Insert the tree view of the search in the current buffer. This is is a helper function for notmuch-tree. The arguments are @@ -1070,6 +1073,7 @@ the same as for the function notmuch-tree." (interactive) (notmuch-tree-mode) (add-hook 'post-command-hook #'notmuch-tree-command-hook t t) + (setq notmuch-search-oldest-first oldest-first) (setq notmuch-tree-unthreaded unthreaded) (setq notmuch-tree-basic-query basic-query) (setq notmuch-tree-query-context (if (or (string= query-context "") @@ -1088,6 +1092,7 @@ the same as for the function notmuch-tree." (let* ((search-args (concat basic-query (and query-context (concat " and (" query-context ")")))) + (sort-arg (if oldest-first "--sort=oldest-first" "--sort=newest-first")) (message-arg (if unthreaded "--unthreaded" "--entire-thread"))) (when (equal (car (process-lines notmuch-command "count" search-args)) "0") (setq search-args basic-query)) @@ -1095,7 +1100,7 @@ the same as for the function notmuch-tree." (let ((proc (notmuch-start-notmuch "notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel "show" "--body=false" "--format=sexp" "--format-version=4" - message-arg search-args)) + sort-arg message-arg search-args)) ;; Use a scratch buffer to accumulate partial output. ;; This buffer will be killed by the sentinel, which ;; should be called no matter how the process dies. @@ -1113,8 +1118,17 @@ the same as for the function notmuch-tree." ")") notmuch-tree-basic-query)) +(defun notmuch-tree-toggle-order () + "Toggle the current search order. + +This command toggles the sort order for the current search. The +default sort order is defined by `notmuch-search-oldest-first'." + (interactive) + (setq notmuch-search-oldest-first (not notmuch-search-oldest-first)) + (notmuch-tree-refresh-view)) + (defun notmuch-tree (&optional query query-context target buffer-name - open-target unthreaded parent-buffer) + open-target unthreaded parent-buffer oldest-first) "Display threads matching QUERY in tree view. The arguments are: @@ -1143,7 +1157,7 @@ The arguments are: (pop-to-buffer-same-window buffer)) ;; Don't track undo information for this buffer (setq buffer-undo-list t) - (notmuch-tree-worker query query-context target open-target unthreaded) + (notmuch-tree-worker query query-context target open-target unthreaded oldest-first) (setq notmuch-tree-parent-buffer parent-buffer) (setq truncate-lines t)) diff --git a/notmuch-show.c b/notmuch-show.c index bdb87321..947ffa8d 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -1244,8 +1244,13 @@ notmuch_show_command (notmuch_database_t *notmuch, int argc, char *argv[]) bool single_message; bool unthreaded = FALSE; notmuch_status_t status; + int sort = NOTMUCH_SORT_NEWEST_FIRST; notmuch_opt_desc_t options[] = { + { .opt_keyword = &sort, .name = "sort", .keywords = + (notmuch_keyword_t []){ { "oldest-first", NOTMUCH_SORT_OLDEST_FIRST }, + { "newest-first", NOTMUCH_SORT_NEWEST_FIRST }, + { 0, 0 } } }, { .opt_keyword = &format, .name = "format", .keywords = (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON }, { "text", NOTMUCH_FORMAT_TEXT }, @@ -1362,6 +1367,8 @@ notmuch_show_command (notmuch_database_t *notmuch, int argc, char *argv[]) return EXIT_FAILURE; } + notmuch_query_set_sort (query, sort); + /* Create structure printer. */ formatter = formatters[format]; sprinter = formatter->new_sprinter (notmuch, stdout); diff --git a/test/T520-show.sh b/test/T520-show.sh index 16222650..6f42ca12 100755 --- a/test/T520-show.sh +++ b/test/T520-show.sh @@ -10,4 +10,21 @@ notmuch show foo.. exit_code=$? test_expect_equal 1 $exit_code +test_begin_subtest "notmuch show --sort=newest-first" +notmuch show --entire-thread=true '*' > EXPECTED +notmuch show --entire-thread=true --sort=newest-first '*' > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "notmuch show --sort=oldest-first" +notmuch show --entire-thread=true '*' | grep ^depth:0 > EXPECTED +notmuch show --entire-thread=true --sort=oldest-first '*' | grep ^depth:0 > OLDEST +perl -e 'print reverse<>' OLDEST > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "notmuch show --sort for single thread" +QUERY="id:yun1vjwegii.fsf@aiko.keithp.com" +notmuch show --entire-thread=true --sort=newest-first $QUERY > EXPECTED +notmuch show --entire-thread=true --sort=oldest-first $QUERY > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + test_done -- 2.32.0