X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=emacs%2Fnotmuch-hello.el;h=2f7e17dc0aed79bd6c614768cd35bfcd57ef2fd8;hp=4b6a90dbc0ecc3e5a334c3a68d301e451c57fa46;hb=7edf9e2765d2795ca85dd2c239af20a7493e2085;hpb=ee578338a691bb948a00d9372f9fe2b898f2b267 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 4b6a90db..2f7e17dc 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -42,6 +42,26 @@ :type 'boolean :group 'notmuch) +(defun notmuch-sort-saved-searches (alist) + "Generate an alphabetically sorted saved searches alist." + (sort alist (lambda (a b) (string< (car a) (car b))))) + +(defcustom notmuch-saved-search-sort-function nil + "Function used to sort the saved searches for the notmuch-hello view. + +This variable controls how saved searches should be sorted. No +sorting (nil) displays the saved searches in the order they are +stored in `notmuch-saved-searches'. Sort alphabetically sorts the +saved searches in alphabetical order. Custom sort function should +be a function or a lambda expression that takes the saved +searches alist as a parameter, and returns a new saved searches +alist to be used." + :type '(choice (const :tag "No sorting" nil) + (const :tag "Sort alphabetically" notmuch-sort-saved-searches) + (function :tag "Custom sort function" + :value notmuch-sort-saved-searches)) + :group 'notmuch) + (defvar notmuch-hello-indent 4 "How much to indent non-headers.") @@ -55,6 +75,27 @@ :type 'boolean :group 'notmuch) +(defcustom notmuch-hello-tag-list-make-query nil + "Function or string to generate queries for the all tags list. + +This variable controls which query results are shown for each tag +in the \"all tags\" list. If nil, it will use all messages with +that tag. If this is set to a string, it is used as a filter for +messages having that tag (equivalent to \"tag:TAG and (THIS-VARIABLE)\"). +Finally this can be a function that will be called for each tag and +should return a filter for that tag, or nil to hide the tag." + :type '(choice (const :tag "All messages" nil) + (const :tag "Unread messages" "tag:unread") + (string :tag "Custom filter" + :value "tag:unread") + (function :tag "Custom filter function")) + :group 'notmuch) + +(defcustom notmuch-hello-hide-tags nil + "List of tags to be hidden in the \"all tags\"-section." + :type '(repeat string) + :group 'notmuch) + (defface notmuch-hello-logo-background '((((class color) (background dark)) @@ -91,13 +132,25 @@ So: (integer :tag "Number of characters") (float :tag "Fraction of window"))) -(defcustom notmuch-decimal-separator "," - "The string used as a decimal separator. +(defcustom notmuch-hello-thousands-separator " " + "The string used as a thousands separator. -Typically \",\" in the US and UK and \".\" in Europe." +Typically \",\" in the US and UK and \".\" or \" \" in Europe. +The latter is recommended in the SI/ISO 31-0 standard and by the +International Bureau of Weights and Measures." :group 'notmuch :type 'string) +(defcustom notmuch-hello-mode-hook nil + "Functions called after entering `notmuch-hello-mode'." + :group 'notmuch + :type 'hook) + +(defcustom notmuch-hello-refresh-hook nil + "Functions called after updating a `notmuch-hello' buffer." + :type 'hook + :group 'notmuch) + (defvar notmuch-hello-url "http://notmuchmail.org" "The `notmuch' web site.") @@ -119,7 +172,7 @@ Typically \",\" in the US and UK and \".\" in Europe." (apply #'concat (number-to-string (car result)) (mapcar (lambda (elem) - (format "%s%03d" notmuch-decimal-separator elem)) + (format "%s%03d" notmuch-hello-thousands-separator elem)) (cdr result))))) (defun notmuch-hello-trim (search) @@ -148,8 +201,8 @@ Typically \",\" in the US and UK and \".\" in Europe." collect elem)) ;; Add the new one. (customize-save-variable 'notmuch-saved-searches - (push (cons name search) - notmuch-saved-searches)) + (add-to-list 'notmuch-saved-searches + (cons name search) t)) (message "Saved '%s' as '%s'." search name) (notmuch-hello-update))) @@ -291,14 +344,14 @@ should be. Returns a cons cell `(tags-per-line width)'." (defvar notmuch-hello-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map widget-keymap) - (define-key map "v" '(lambda () "Display the notmuch version" (interactive) - (message "notmuch version %s" (notmuch-version)))) + (define-key map "v" (lambda () "Display the notmuch version" (interactive) + (message "notmuch version %s" (notmuch-version)))) (define-key map "?" 'notmuch-help) - (define-key map "q" 'kill-this-buffer) + (define-key map "q" 'notmuch-kill-this-buffer) (define-key map "=" 'notmuch-hello-update) (define-key map "G" 'notmuch-hello-poll-and-update) (define-key map (kbd "") 'widget-backward) - (define-key map "m" 'notmuch-mua-mail) + (define-key map "m" 'notmuch-mua-new-mail) (define-key map "s" 'notmuch-hello-goto-search) map) "Keymap for \"notmuch hello\" buffers.") @@ -315,9 +368,29 @@ Complete list of currently available key bindings: (use-local-map notmuch-hello-mode-map) (setq major-mode 'notmuch-hello-mode mode-name "notmuch-hello") + (run-mode-hooks 'notmuch-hello-mode-hook) ;;(setq buffer-read-only t) ) +(defun notmuch-hello-generate-tag-alist () + "Return an alist from tags to queries to display in the all-tags section." + (notmuch-remove-if-not + #'cdr + (mapcar (lambda (tag) + (cons tag + (cond + ((functionp notmuch-hello-tag-list-make-query) + (concat "tag:" tag " and (" + (funcall notmuch-hello-tag-list-make-query tag) ")")) + ((stringp notmuch-hello-tag-list-make-query) + (concat "tag:" tag " and (" + notmuch-hello-tag-list-make-query ")")) + (t (concat "tag:" tag))))) + (notmuch-remove-if-not + (lambda (tag) + (not (member tag notmuch-hello-hide-tags))) + (process-lines notmuch-command "search-tags"))))) + ;;;###autoload (defun notmuch-hello (&optional no-display) "Run notmuch and display saved searches, known tags, etc." @@ -338,11 +411,16 @@ Complete list of currently available key bindings: (progn (widget-forward 1) (widget-value (widget-at))) - (error nil))))) + (error nil)))) + (inhibit-read-only t)) + + ;; Delete all editable widget fields. Editable widget fields are + ;; tracked in a buffer local variable `widget-field-list' (and + ;; others). If we do `erase-buffer' without properly deleting the + ;; widgets, some widget-related functions are confused later. + (mapc 'widget-delete widget-field-list) - (kill-all-local-variables) - (let ((inhibit-read-only t)) - (erase-buffer)) + (erase-buffer) (unless (eq major-mode 'notmuch-hello-mode) (notmuch-hello-mode)) @@ -389,20 +467,22 @@ Complete list of currently available key bindings: (let ((found-target-pos nil) (final-target-pos nil)) (let* ((saved-alist - ;; Filter out empty saved seaches if required. + ;; Filter out empty saved searches if required. (if notmuch-show-empty-saved-searches notmuch-saved-searches (loop for elem in notmuch-saved-searches if (> (string-to-number (notmuch-saved-search-count (cdr elem))) 0) collect elem))) (saved-widest (notmuch-hello-longest-label saved-alist)) - (alltags-alist (if notmuch-show-all-tags-list - (mapcar '(lambda (tag) (cons tag (concat "tag:" tag))) - (process-lines notmuch-command "search-tags")))) + (alltags-alist (if notmuch-show-all-tags-list (notmuch-hello-generate-tag-alist))) (alltags-widest (notmuch-hello-longest-label alltags-alist)) (widest (max saved-widest alltags-widest))) (when saved-alist + ;; Sort saved searches if required. + (when notmuch-saved-search-sort-function + (setq saved-alist + (funcall notmuch-saved-search-sort-function saved-alist))) (widget-insert "\nSaved searches: ") (widget-create 'push-button :notify (lambda (&rest ignore) @@ -425,6 +505,10 @@ Complete list of currently available key bindings: (length "Search: "))) :action (lambda (widget &rest ignore) (notmuch-hello-search (widget-value widget)))) + ;; add an invisible space to make `widget-end-of-line' ignore + ;; trailine spaces in the search widget field + (widget-insert " ") + (put-text-property (1- (point)) (point) 'invisible t) (widget-insert "\n") (when notmuch-hello-recent-searches @@ -437,36 +521,36 @@ Complete list of currently available key bindings: (widget-insert "\n\n") (let ((start (point)) (nth 0)) - (mapc '(lambda (search) - (let ((widget-symbol (intern (format "notmuch-hello-search-%d" nth)))) - (set widget-symbol - (widget-create 'editable-field - ;; Don't let the search boxes be - ;; less than 8 characters wide. - :size (max 8 - (- (window-width) - ;; Leave some space - ;; at the start and - ;; end of the - ;; boxes. - (* 2 notmuch-hello-indent) - ;; 1 for the space - ;; before the - ;; `[save]' button. 6 - ;; for the `[save]' - ;; button. - 1 6)) - :action (lambda (widget &rest ignore) - (notmuch-hello-search (widget-value widget))) - search)) - (widget-insert " ") - (widget-create 'push-button - :notify (lambda (widget &rest ignore) - (notmuch-hello-add-saved-search widget)) - :notmuch-saved-search-widget widget-symbol - "save")) - (widget-insert "\n") - (setq nth (1+ nth))) + (mapc (lambda (search) + (let ((widget-symbol (intern (format "notmuch-hello-search-%d" nth)))) + (set widget-symbol + (widget-create 'editable-field + ;; Don't let the search boxes be + ;; less than 8 characters wide. + :size (max 8 + (- (window-width) + ;; Leave some space + ;; at the start and + ;; end of the + ;; boxes. + (* 2 notmuch-hello-indent) + ;; 1 for the space + ;; before the + ;; `[save]' button. 6 + ;; for the `[save]' + ;; button. + 1 6)) + :action (lambda (widget &rest ignore) + (notmuch-hello-search (widget-value widget))) + search)) + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (widget &rest ignore) + (notmuch-hello-add-saved-search widget)) + :notmuch-saved-search-widget widget-symbol + "save")) + (widget-insert "\n") + (setq nth (1+ nth))) notmuch-hello-recent-searches) (indent-rigidly start (point) notmuch-hello-indent))) @@ -514,7 +598,9 @@ Complete list of currently available key bindings: (widget-forward 1))) (unless (widget-at) - (notmuch-hello-goto-search))))) + (notmuch-hello-goto-search)))) + + (run-hooks 'notmuch-hello-refresh-hook)) (defun notmuch-folder () "Deprecated function for invoking notmuch---calling `notmuch' is preferred now."