:group 'gnus-registry
:type '(repeat regexp))
-(defcustom gnus-registry-install nil
+(defcustom gnus-registry-install 'ask
"Whether the registry should be installed."
:group 'gnus-registry
- :type 'boolean)
+ :type '(choice (const :tag "Never Install" nil)
+ (const :tag "Always Install" t)
+ (const :tag "Ask Me" ask)))
(defcustom gnus-registry-clean-empty t
"Whether the empty registry entries should be deleted.
(const :tag "Track by subject (Subject: header)" subject)
(const :tag "Track by sender (From: header)" sender)))
+(defcustom gnus-registry-split-strategy nil
+ "Whether the registry should track extra data about a message.
+The Subject and Sender (From:) headers are currently tracked this
+way."
+ :group 'gnus-registry
+ :type
+ '(choice :tag "Tracking choices"
+ (const :tag "Only use single choices, discard multiple matches" nil)
+ (const :tag "Majority of matches wins" majority)
+ (const :tag "First found wins" first)))
+
(defcustom gnus-registry-entry-caching t
"Whether the registry should cache extra information."
:group 'gnus-registry
nnmail-split-fancy-with-parent-ignore-groups
(list nnmail-split-fancy-with-parent-ignore-groups)))
(log-agent "gnus-registry-split-fancy-with-parent")
- found)
+ found found-full)
;; this is a big if-else statement. it uses
;; gnus-registry-post-process-groups to filter the results after
log-agent reference refstr group)
(push group found))))
;; filter the found groups and return them
+ ;; the found groups are the full groups
(setq found (gnus-registry-post-process-groups
- "references" refstr found)))
-
+ "references" refstr found found)))
+
;; else: there were no matches, now try the extra tracking by sender
((and (gnus-registry-track-sender-p)
sender)
matches)
(when (and this-sender
(equal sender this-sender))
- (setq found (append (gnus-registry-fetch-groups key) found))
+ (let ((groups (gnus-registry-fetch-groups key)))
+ (dolist (group groups)
+ (push group found-full)
+ (setq found (append (list group) (delete group found)))))
(push key matches)
(gnus-message
;; raise level of messaging if gnus-registry-track-extra
log-agent sender found matches))))
gnus-registry-hashtb)
;; filter the found groups and return them
- (setq found (gnus-registry-post-process-groups "sender" sender found)))
+ ;; the found groups are NOT the full groups
+ (setq found (gnus-registry-post-process-groups
+ "sender" sender found found-full)))
;; else: there were no matches, now try the extra tracking by subject
((and (gnus-registry-track-subject-p)
matches)
(when (and this-subject
(equal subject this-subject))
- (setq found (append (gnus-registry-fetch-groups key) found))
+ (let ((groups (gnus-registry-fetch-groups key)))
+ (dolist (group groups)
+ (push group found-full)
+ (setq found (append (list group) (delete group found)))))
(push key matches)
(gnus-message
;; raise level of messaging if gnus-registry-track-extra
log-agent subject found matches))))
gnus-registry-hashtb)
;; filter the found groups and return them
+ ;; the found groups are NOT the full groups
(setq found (gnus-registry-post-process-groups
- "subject" subject found))))))
+ "subject" subject found found-full))))
+ ;; after the (cond) we extract the actual value safely
+ (car-safe found)))
-(defun gnus-registry-post-process-groups (mode key groups)
+(defun gnus-registry-post-process-groups (mode key groups groups-full)
"Modifies GROUPS found by MODE for KEY to determine which ones to follow.
MODE can be 'subject' or 'sender' for example. The KEY is the
false. Foreign methods are not supported so they are rejected.
Reduces the list to a single group, or complains if that's not
-possible."
+possible. Uses `gnus-registry-split-strategy' and GROUPS-FULL if
+necessary."
(let ((log-agent "gnus-registry-post-process-group")
out)
+
+ ;; the strategy can be 'first, 'majority, or nil
+ (when (eq gnus-registry-split-strategy 'first)
+ (when groups
+ (setq groups (list (car-safe groups)))))
+
+ (when (eq gnus-registry-split-strategy 'majority)
+ (let ((freq (make-hash-table
+ :size 256
+ :test 'equal)))
+ (mapc (lambda(x) (puthash x (1+ (gethash x freq 0)) freq)) groups-full)
+ (setq groups (list (car-safe
+ (sort
+ groups
+ (lambda (a b)
+ (> (gethash a freq 0)
+ (gethash b freq 0)))))))))
+
(if gnus-registry-use-long-group-names
(dolist (group groups)
(let ((m1 (gnus-find-method-for-group group))
(funcall function mark cell-data)))))
;;; this is ugly code, but I don't know how to do it better
-
-;;; TODO: clear the gnus-registry-mark-map before running (but I think
-;;; gnus-define-keys does it by default)
-(defun gnus-registry-install-shortcuts-and-menus ()
+(defun gnus-registry-install-shortcuts ()
"Install the keyboard shortcuts and menus for the registry.
Uses `gnus-registry-marks' to find what shortcuts to install."
- (gnus-registry-do-marks
- :char
- (lambda (mark data)
- (let ((function-format
- (format "gnus-registry-%%s-article-%s-mark" mark)))
+ (let (keys-plist)
+ (gnus-registry-do-marks
+ :char
+ (lambda (mark data)
+ (let ((function-format
+ (format "gnus-registry-%%s-article-%s-mark" mark)))
;;; The following generates these functions:
;;; (defun gnus-registry-set-article-Important-mark (&rest articles)
;;; (interactive (gnus-summary-work-articles current-prefix-arg))
;;; (gnus-registry-set-article-mark-internal 'Important articles t t))
- (dolist (remove '(t nil))
- (let* ((variant-name (if remove "remove" "set"))
- (function-name (format function-format variant-name))
- (shortcut (format "%c" data))
- (shortcut (if remove (upcase shortcut) shortcut)))
- (unintern function-name)
- (eval
- `(defun
- ;; function name
- ,(intern function-name)
- ;; parameter definition
- (&rest articles)
- ;; documentation
- ,(format
- "%s the %s mark over process-marked ARTICLES."
- (upcase-initials variant-name)
- mark)
- ;; interactive definition
- (interactive
- (gnus-summary-work-articles current-prefix-arg))
- ;; actual code
- (gnus-registry-set-article-mark-internal
- ;; all this just to get the mark, I must be doing it wrong
- (intern ,(symbol-name mark))
- articles ,remove t)))
- (gnus-message 9 "Defined mark handling function %s" function-name))))))
- ;; I don't know how to do this inside the loop above, because
- ;; gnus-define-keys is a macro
- (gnus-define-keys (gnus-registry-mark-map "M" gnus-summary-mark-map)
- "i" gnus-registry-set-article-Important-mark
- "I" gnus-registry-remove-article-Important-mark
- "w" gnus-registry-set-article-Work-mark
- "W" gnus-registry-remove-article-Work-mark
- "l" gnus-registry-set-article-Later-mark
- "L" gnus-registry-remove-article-Later-mark
- "p" gnus-registry-set-article-Personal-mark
- "P" gnus-registry-remove-article-Personal-mark
- "t" gnus-registry-set-article-To-Do-mark
- "T" gnus-registry-remove-article-To-Do-mark))
+ (dolist (remove '(t nil))
+ (let* ((variant-name (if remove "remove" "set"))
+ (function-name (format function-format variant-name))
+ (shortcut (format "%c" data))
+ (shortcut (if remove (upcase shortcut) shortcut)))
+ (unintern function-name)
+ (eval
+ `(defun
+ ;; function name
+ ,(intern function-name)
+ ;; parameter definition
+ (&rest articles)
+ ;; documentation
+ ,(format
+ "%s the %s mark over process-marked ARTICLES."
+ (upcase-initials variant-name)
+ mark)
+ ;; interactive definition
+ (interactive
+ (gnus-summary-work-articles current-prefix-arg))
+ ;; actual code
+
+ ;; if this is called and the user doesn't want the
+ ;; registry enabled, we'll ask anyhow
+ (when (eq gnus-registry-install nil)
+ (setq gnus-registry-install 'ask))
+
+ ;; now the user is asked if gnus-registry-install is 'ask
+ (when (gnus-registry-install-p)
+ (gnus-registry-set-article-mark-internal
+ ;; all this just to get the mark, I must be doing it wrong
+ (intern ,(symbol-name mark))
+ articles ,remove t)
+ (dolist (article articles)
+ (gnus-summary-update-article
+ article
+ (assoc article (gnus-data-list nil)))))))
+ (push (intern function-name) keys-plist)
+ (push shortcut keys-plist)
+ (gnus-message
+ 9
+ "Defined mark handling function %s"
+ function-name))))))
+ (gnus-define-keys-1
+ '(gnus-registry-mark-map "M" gnus-summary-mark-map)
+ keys-plist)))
;;; use like this:
-;;; (defalias 'gnus-user-format-function-M 'gnus-registry-user-format-function-M)
+;;; (defalias 'gnus-user-format-function-M
+;;; 'gnus-registry-user-format-function-M)
(defun gnus-registry-user-format-function-M (headers)
(let* ((id (mail-header-message-id headers))
- (marks (when id (gnus-registry-fetch-extra-marks id)))
- (out ""))
- (dolist (mark marks)
- (let ((c (plist-get
- (cdr-safe
- (assoc mark gnus-registry-marks)) :char)))
- (setq out (format "%s%s"
- out
- (if c
- (char-to-string c)
- "")))))
- out))
+ (marks (when id (gnus-registry-fetch-extra-marks id))))
+ (apply 'concat (mapcar (lambda(mark)
+ (let ((c
+ (plist-get
+ (cdr-safe
+ (assoc mark gnus-registry-marks))
+ :char)))
+ (if c
+ (list c)
+ nil)))
+ marks))))
(defun gnus-registry-read-mark ()
"Read a mark name from the user with completion."
;;;###autoload
(defun gnus-registry-initialize ()
+"Initialize the Gnus registry."
(interactive)
- (setq gnus-registry-install t)
+ (gnus-message 5 "Initializing the registry")
+ (setq gnus-registry-install t) ; in case it was 'ask or nil
(gnus-registry-install-hooks)
- (gnus-registry-install-shortcuts-and-menus)
+ (gnus-registry-install-shortcuts)
(gnus-registry-read))
;;;###autoload
(add-hook 'gnus-registry-unload-hook 'gnus-registry-unload-hook)
-(when gnus-registry-install
- (gnus-registry-install-hooks)
- (gnus-registry-read))
-
-;; TODO: a lot of things
+(defun gnus-registry-install-p ()
+ (interactive)
+ (when (eq gnus-registry-install 'ask)
+ (setq gnus-registry-install
+ (gnus-y-or-n-p
+ (concat "Enable the Gnus registry? "
+ "See the variable `gnus-registry-install' "
+ "to get rid of this query permanently. ")))
+ (when gnus-registry-install
+ ;; we just set gnus-registry-install to t, so initialize the registry!
+ (gnus-registry-initialize)))
+;;; we could call it here: (customize-variable 'gnus-registry-install)
+ gnus-registry-install)
+
+(when (or (eq gnus-registry-install t)
+ (gnus-registry-install-p))
+ (gnus-registry-initialize))
+
+;; TODO: a few things
(provide 'gnus-registry)
-;;; arch-tag: 5cba0a32-718a-4a97-8c91-0a15af21da94
+;; arch-tag: 5cba0a32-718a-4a97-8c91-0a15af21da94
;;; gnus-registry.el ends here