mirror of https://github.com/djcb/mu.git
* mu4e: cleanup header sorting (and fix the sort-by-human-date case)
This commit is contained in:
parent
1c1f974807
commit
f957a9ca89
|
@ -149,16 +149,6 @@ match.
|
||||||
* PARAM-FUNC is function that is evaluated once, and its value is then passed to
|
* PARAM-FUNC is function that is evaluated once, and its value is then passed to
|
||||||
PREDICATE-FUNC as PARAM. This is useful for getting user-input.")
|
PREDICATE-FUNC as PARAM. This is useful for getting user-input.")
|
||||||
|
|
||||||
(defvar mu4e-headers-sortfield :date
|
|
||||||
"Field to sort the headers by.
|
|
||||||
Field must be a symbol, one of: :date, :subject, :size, :prio,
|
|
||||||
:from, :to.")
|
|
||||||
|
|
||||||
(defvar mu4e-headers-sort-revert t
|
|
||||||
"Whether to revert the sort-order.
|
|
||||||
i.e. Z>A instead of A>Z. When sorting by date, it's useful to go
|
|
||||||
from biggest to smallest, so newest messages come first.")
|
|
||||||
|
|
||||||
(defvar mu4e-headers-show-threads t
|
(defvar mu4e-headers-show-threads t
|
||||||
"Whether to show threads in the headers list.")
|
"Whether to show threads in the headers list.")
|
||||||
|
|
||||||
|
@ -181,7 +171,7 @@ followed by the docid, followed by `mu4e~headers-docid-post'.")
|
||||||
(defvar mu4e~headers-view-win nil
|
(defvar mu4e~headers-view-win nil
|
||||||
"The view window connected to this headers view.")
|
"The view window connected to this headers view.")
|
||||||
|
|
||||||
(defvar mu4e~headers-sortfield-choices
|
(defvar mu4e~headers-sort-field-choices
|
||||||
'( ("date" . :date)
|
'( ("date" . :date)
|
||||||
("from" . :from)
|
("from" . :from)
|
||||||
("prio" . :prio)
|
("prio" . :prio)
|
||||||
|
@ -353,6 +343,8 @@ date. The formats used for date and time are
|
||||||
(format-time-string mu4e-headers-time-format date)
|
(format-time-string mu4e-headers-time-format date)
|
||||||
(format-time-string mu4e-headers-date-format date))))
|
(format-time-string mu4e-headers-date-format date))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; note: this function is very performance-sensitive
|
;; note: this function is very performance-sensitive
|
||||||
(defun mu4e~headers-header-handler (msg &optional point)
|
(defun mu4e~headers-header-handler (msg &optional point)
|
||||||
"Create a one line description of MSG in this buffer, at POINT,
|
"Create a one line description of MSG in this buffer, at POINT,
|
||||||
|
@ -599,9 +591,9 @@ after the end of the search results."
|
||||||
(define-key menumap [previous] '("Previous" . mu4e-headers-prev))
|
(define-key menumap [previous] '("Previous" . mu4e-headers-prev))
|
||||||
(define-key menumap [sepa4] '("--")))
|
(define-key menumap [sepa4] '("--")))
|
||||||
map)))
|
map)))
|
||||||
|
|
||||||
(fset 'mu4e-headers-mode-map mu4e-headers-mode-map)
|
(fset 'mu4e-headers-mode-map mu4e-headers-mode-map)
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e~header-line-format ()
|
(defun mu4e~header-line-format ()
|
||||||
"Get the format for the header line."
|
"Get the format for the header line."
|
||||||
(cons
|
(cons
|
||||||
|
@ -617,8 +609,8 @@ after the end of the search results."
|
||||||
(downarrow (if mu4e-use-fancy-chars " ▼" " V"))
|
(downarrow (if mu4e-use-fancy-chars " ▼" " V"))
|
||||||
;; triangle to mark the sorted-by column
|
;; triangle to mark the sorted-by column
|
||||||
(arrow
|
(arrow
|
||||||
(when (and sortable (eq (car item) mu4e-headers-sortfield))
|
(when (and sortable (eq (car item) mu4e~headers-sort-field))
|
||||||
(if mu4e-headers-sort-revert downarrow uparrow)))
|
(if (eq mu4e~headers-sort-direction 'descending) downarrow uparrow)))
|
||||||
(name (concat (plist-get info :shortname) arrow))
|
(name (concat (plist-get info :shortname) arrow))
|
||||||
(map (make-sparse-keymap)))
|
(map (make-sparse-keymap)))
|
||||||
(when sortable
|
(when sortable
|
||||||
|
@ -629,10 +621,9 @@ after the end of the search results."
|
||||||
(let* ((obj (posn-object (event-start e)))
|
(let* ((obj (posn-object (event-start e)))
|
||||||
(field
|
(field
|
||||||
(and obj (get-text-property 0 'field (car obj)))))
|
(and obj (get-text-property 0 'field (car obj)))))
|
||||||
(if (eq field mu4e-headers-sortfield)
|
;; "t": if we're already sorted by field, the sort-order is
|
||||||
(setq mu4e-headers-sort-revert (not mu4e-headers-sort-revert))
|
;; changed
|
||||||
(setq mu4e-headers-sortfield field)))
|
(mu4e-headers-change-sorting field t)))))
|
||||||
(mu4e-headers-rerun-search))))
|
|
||||||
(concat
|
(concat
|
||||||
(propertize
|
(propertize
|
||||||
(if width
|
(if width
|
||||||
|
@ -812,6 +803,10 @@ docid is not found."
|
||||||
(delete-region (line-beginning-position) (line-beginning-position 2)))
|
(delete-region (line-beginning-position) (line-beginning-position 2)))
|
||||||
(unless ignore-missing
|
(unless ignore-missing
|
||||||
(mu4e-error "Cannot find message with docid %S" docid)))))
|
(mu4e-error "Cannot find message with docid %S" docid)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
(defun mu4e~headers-search-execute (expr ignore-history)
|
(defun mu4e~headers-search-execute (expr ignore-history)
|
||||||
"Search in the mu database for EXPR, and switch to the output
|
"Search in the mu database for EXPR, and switch to the output
|
||||||
|
@ -838,8 +833,8 @@ the query history stack."
|
||||||
(mu4e~proc-find
|
(mu4e~proc-find
|
||||||
expr
|
expr
|
||||||
mu4e-headers-show-threads
|
mu4e-headers-show-threads
|
||||||
mu4e-headers-sortfield
|
mu4e~headers-sort-field
|
||||||
mu4e-headers-sort-revert
|
mu4e~headers-sort-direction
|
||||||
(unless mu4e-headers-full-search mu4e-search-results-limit))))
|
(unless mu4e-headers-full-search mu4e-search-results-limit))))
|
||||||
|
|
||||||
(defun mu4e~headers-redraw-get-view-window ()
|
(defun mu4e~headers-redraw-get-view-window ()
|
||||||
|
@ -1088,26 +1083,50 @@ the last search expression."
|
||||||
(format "(%s) AND %s" mu4e~headers-last-query filter)))
|
(format "(%s) AND %s" mu4e~headers-last-query filter)))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-headers-change-sorting (&optional dont-refresh)
|
(defvar mu4e~headers-sort-field :date
|
||||||
"Interactively change the sorting/threading parameters.
|
"Field to sort the headers by.
|
||||||
With prefix-argument, do _not_ refresh the last search with the
|
Field must be a symbol, one of: :date, :subject, :size, :prio,
|
||||||
new parameters."
|
:from, :to.")
|
||||||
(interactive "P")
|
|
||||||
(let* ((sortfield
|
(defvar mu4e~headers-sort-direction 'descending
|
||||||
(mu4e-read-option "Sortfield: " mu4e~headers-sortfield-choices))
|
"Direction to sort by; a symbol either `descending' (sorting
|
||||||
(revert
|
Z->A) or `ascending' (sorting A->Z).")
|
||||||
(mu4e-read-option "Direction: "
|
|
||||||
'(("ascending" . nil) ("descending" . t)))))
|
(defun mu4e-headers-change-sorting (&optional field dir)
|
||||||
|
"Change the sorting/threading parameters.
|
||||||
|
FIELD is the field to sort by; DIR is a symbol: either 'ascending,
|
||||||
|
'descending, 't (meaning: if FIELD is the same as the current
|
||||||
|
sortfield, change the sort-order) or nil (ask the user)."
|
||||||
|
(interactive)
|
||||||
|
(let* ((field
|
||||||
|
(or field
|
||||||
|
(mu4e-read-option "Sortfield: " mu4e~headers-sort-field-choices)))
|
||||||
|
;; note: 'sortable' is either a boolean (meaning: if non-nil, this is
|
||||||
|
;; sortable field), _or_ another field (meaning: sort by this other field).
|
||||||
|
(sortable (plist-get (cdr (assoc field mu4e-header-info)) :sortable))
|
||||||
|
;; error check
|
||||||
|
(sortable
|
||||||
|
(if sortable
|
||||||
|
sortable
|
||||||
|
(mu4e-error "Not a sortable field")))
|
||||||
|
(sortfield (if (booleanp sortable) field sortable))
|
||||||
|
(dir
|
||||||
|
(case dir
|
||||||
|
((ascending descending) dir)
|
||||||
|
;; change the sort order if field = curfield
|
||||||
|
(t
|
||||||
|
(if (eq sortfield mu4e~headers-sort-field)
|
||||||
|
(if (eq mu4e~headers-sort-direction 'ascending)
|
||||||
|
'descending 'ascending)))
|
||||||
|
(mu4e-read-option "Direction: "
|
||||||
|
'(("ascending" . 'ascending) ("descending" . 'descending))))))
|
||||||
(setq
|
(setq
|
||||||
mu4e-headers-sortfield sortfield
|
mu4e~headers-sort-field sortfield
|
||||||
mu4e-headers-sort-revert revert) ;; "descending" means "revert"
|
mu4e~headers-sort-direction dir)
|
||||||
(mu4e-message "Sorting by %s (%s)%s"
|
(mu4e-message "Sorting by %s (%s)"
|
||||||
(symbol-name sortfield)
|
(symbol-name sortfield)
|
||||||
(if revert "descending" "ascending")
|
(symbol-name mu4e~headers-sort-direction))
|
||||||
(if dont-refresh
|
(mu4e-headers-rerun-search)))
|
||||||
" (press 'g' to refresh)" ""))
|
|
||||||
(unless dont-refresh
|
|
||||||
(mu4e-headers-rerun-search))))
|
|
||||||
|
|
||||||
(defun mu4e-headers-toggle-threading (&optional dont-refresh)
|
(defun mu4e-headers-toggle-threading (&optional dont-refresh)
|
||||||
"Toggle threading on/off for the search results.
|
"Toggle threading on/off for the search results.
|
||||||
|
|
|
@ -317,23 +317,24 @@ In particular, backslashes and double-quotes."
|
||||||
(let ((esc (replace-regexp-in-string "\\\\" "\\\\\\\\" query)))
|
(let ((esc (replace-regexp-in-string "\\\\" "\\\\\\\\" query)))
|
||||||
(replace-regexp-in-string "\"" "\\\\\"" esc)))
|
(replace-regexp-in-string "\"" "\\\\\"" esc)))
|
||||||
|
|
||||||
(defun mu4e~proc-find (query threads sortfield revert maxnum)
|
(defun mu4e~proc-find (query threads sortfield sortdir maxnum)
|
||||||
"Start a database query for QUERY.
|
"Start a database query for QUERY.
|
||||||
If THREADS is non-nil, show results in threaded fasion, SORTFIELD
|
If THREADS is non-nil, show results in threaded fasion, SORTFIELD
|
||||||
is a symbol describing the field to sort by (or nil); see
|
is a symbol describing the field to sort by (or nil); see
|
||||||
`mu4e~headers-sortfield-choices'. If REVERT is non-nil, sort Z->A
|
`mu4e~headers-sortfield-choices'. If SORT is `descending', sort
|
||||||
instead of A->Z. MAXNUM determines the maximum number of results
|
Z->A, if it's `ascending', sort A->Z. MAXNUM determines the maximum
|
||||||
to return, or nil for 'unlimited'. For each result found, a
|
number of results to return, or nil for 'unlimited'. For each
|
||||||
function is called, depending on the kind of result. The
|
result found, a function is called, depending on the kind of
|
||||||
variables `mu4e-error-func' contain the function that will be
|
result. The variables `mu4e-error-func' contain the function that
|
||||||
called for, resp., a message (header row) or an error."
|
will be called for, resp., a message (header row) or an error."
|
||||||
(mu4e~proc-send-command
|
(mu4e~proc-send-command
|
||||||
"find query:\"%s\" threads:%s sortfield:%s reverse:%s maxnum:%d"
|
"find query:\"%s\" threads:%s sortfield:%s reverse:%s maxnum:%d"
|
||||||
(mu4e~proc-escape-query query)
|
(mu4e~proc-escape-query query)
|
||||||
(if threads "true" "false")
|
(if threads "true" "false")
|
||||||
;; sortfield is e.g. ':subject'; this removes the ':'
|
;; sortfield is e.g. ':subject'; this removes the ':'
|
||||||
(if (null sortfield) "nil" (substring (symbol-name sortfield) 1))
|
(if (null sortfield) "nil" (substring (symbol-name sortfield) 1))
|
||||||
(if revert "true" "false")
|
;; TODO: use ascending/descending in backend too (it's clearer than 'reverse'
|
||||||
|
(if (eq sortdir 'descending) "true" "false")
|
||||||
(if maxnum maxnum -1)))
|
(if maxnum maxnum -1)))
|
||||||
|
|
||||||
(defun mu4e~proc-move (docid-or-msgid &optional maildir flags)
|
(defun mu4e~proc-move (docid-or-msgid &optional maildir flags)
|
||||||
|
|
|
@ -492,7 +492,7 @@ I.e. a message with the draft flag set."
|
||||||
( :name "Date"
|
( :name "Date"
|
||||||
:shortname "Date"
|
:shortname "Date"
|
||||||
:help "Date/time when the message was written."
|
:help "Date/time when the message was written."
|
||||||
:sortable t))
|
:sortable :date))
|
||||||
(:flags .
|
(:flags .
|
||||||
( :name "Flags"
|
( :name "Flags"
|
||||||
:shortname "Flgs"
|
:shortname "Flgs"
|
||||||
|
@ -544,13 +544,19 @@ I.e. a message with the draft flag set."
|
||||||
:help "Recipient of the message"
|
:help "Recipient of the message"
|
||||||
:sortable t)))
|
:sortable t)))
|
||||||
"An alist of all possible header fields and information about them.
|
"An alist of all possible header fields and information about them.
|
||||||
This is used in the UI (the column headers in the header list,
|
This is used in the user-interface (the column headers in the header list, and
|
||||||
and the fields the message view).
|
the fields the message view).
|
||||||
|
|
||||||
Most fields should be self-explanatory. A special one is
|
Most fields should be self-explanatory. A special one is
|
||||||
`:from-or-to', which is equal to `:from' unless `:from' matches
|
`:from-or-to', which is equal to `:from' unless `:from' matches
|
||||||
`mu4e-user-mail-address-regexp', in which case it will be equal
|
`mu4e-user-mail-address-regexp', in which case it will be equal to
|
||||||
to `:to'.")
|
`:to'.
|
||||||
|
|
||||||
|
Furthermore, the property `:sortable' determines whether we can
|
||||||
|
sort by this field. This can be either a boolean (nil or t), or a
|
||||||
|
symbol for /another/ field. For example, the `:human-date' field
|
||||||
|
uses `:date' for that.
|
||||||
|
")
|
||||||
|
|
||||||
(defvar mu4e-custom-header-info nil
|
(defvar mu4e-custom-header-info nil
|
||||||
"A list like `mu4e-custom-header-info', but for custom headers.
|
"A list like `mu4e-custom-header-info', but for custom headers.
|
||||||
|
|
Loading…
Reference in New Issue