diff options
| author | Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> | 2025-09-12 19:15:35 +0300 |
|---|---|---|
| committer | Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> | 2025-09-12 18:56:31 +0300 |
| commit | 97d6a41823a76351ed26693b8db167cc6ee14881 (patch) | |
| tree | cb4ea1ff37f9ca50930341dd1141628e664ea8fa /mu4e | |
| parent | 7d5cdf061a15157e4fb677c7d90795e4e0502b24 (diff) | |
mu4e: labels tweaks
Make the code a little clearer, and catch error earlier.
Allow for comma-separated labels.
Diffstat (limited to 'mu4e')
| -rw-r--r-- | mu4e/mu4e-labels.el | 106 | ||||
| -rw-r--r-- | mu4e/mu4e-mark.el | 5 |
2 files changed, 44 insertions, 67 deletions
diff --git a/mu4e/mu4e-labels.el b/mu4e/mu4e-labels.el index 11384bc..fd05c4f 100644 --- a/mu4e/mu4e-labels.el +++ b/mu4e/mu4e-labels.el @@ -30,21 +30,13 @@ (require 'mu4e-helpers) (defconst mu4e-label-regex - "[^\"'+/\\`[:cntrl:][:blank:]-][^\"'/\\`[:cntrl:][:blank:]]*" - ;;Emacs 30: - ;;(rx-let ((taboo (any cntrl blank "\"'\\/`$")) - ;; (taboo1-extra (any "-+"))) - ;; (rx (seq - ;; ;; First character: base forbidden + extra chars - ;; (not (or taboo taboo1-extra)) - ;; ;; Rest: just base forbidden chars - ;; (zero-or-more (not taboo))))) + "[^\"',+/\\`[:cntrl:][:blank:]-][^\"'$,/\\`[:cntrl:][:blank:]]+" "Unanchored regular expression matching a valid label. Any character is allowed that is not a control-character, a -blank, or ASCII single/double quotes,backtick or -forward/backward slash; additionally, the first character cannot -be a \"+\" or \"-\", \"$\" either.") +blank, or a number of special characters. Additionally, the first +character cannot be + or - either.") +;; sadly, the 'rx' macro is not expressive enough, pre-emacs30 (defun mu4e-label-validate (str) "Validate label STR. @@ -55,45 +47,34 @@ checking a regular expression. See `mu4e-label-regex' for the definition of the valid format." (when (string-empty-p str) ;; i. must not be empty - (mu4e-warn "invalid: empty string")) - (let ((first (aref str 0))) + (mu4e-warn "an empty string is a not a valid label")) + (let ((first (aref str 0)) + ;; anchored + (valid-rx (rx bos (regex mu4e-label-regex) eos))) ;; ii. must not start with + or - (when (or (char-equal first ?+) (char-equal first ?-)) - (mu4e-warn "invalid: starts with '%c'" first)) - ;; iii. check all characters a valid: - (seq-do (lambda (kar) - (unless (string-match-p mu4e-label-regex - (string ?_ kar)) - (mu4e-warn "invalid: character '%c'" kar))) - str)) + (mu4e-warn "labels cannot starts with '%c'" first)) + ;; iii. match the regexp + (unless (string-match-p valid-rx str) + (mu4e-warn "not a valid label: %S" str))) str) -(defun mu4e-label-parse-expr (expr) - "Parse a single delta expression EXPR. - -If EXPR is non-empty, raises a warning if EXPR is not a valid -delta expression. Otherwise, returns EXPR with extra whitespace -removed. - -If STR is empty, return nil." - (let ((op (aref expr 0)) - (label (substring expr 1))) - ;; guess we could _imply_ '+', but for now let's not - ;; be too magical. - (unless (or (char-equal op ?+) (char-equal op ?-)) - (mu4e-warn "delta-expressions must start with + or - ('%s')" - expr)) - (concat (char-to-string op) - (mu4e-label-validate label)))) - -(defun mu4e-label-parse-exprs (exprs) - "Parse a string EXPRS with deltas to a string. - -If EXPRS is non-empty, raises an error if EXPRS is invalid. -Otherwise, return EXPRS with extra whitespace removed. - -If EXPRS is empty, return nil." - (mapconcat #'mu4e-label-parse-expr (split-string exprs) " ")) +(defun mu4e-label-parse-delta-exprs (delta-exprs) + "Parse a string a DELTA-EXPRS. + +If empty, return nil. Otherwise, raise an error if it is invalid. +Otherwise, return a list with the invidual elements." + (seq-map (lambda (delta-expr) + (when (string-empty-p delta-expr) + (mu4e-warn "delta-expression cannot be empty")) + (let ((op (aref delta-expr 0)) + (label (substring delta-expr 1))) + (unless (or (char-equal op ?+) (char-equal op ?-)) + (mu4e-warn (concat "labels in delta-expression" + " must start with +/- ('%s')") + delta-expr)) + (concat (char-to-string op) (mu4e-label-validate label)))) + (split-string delta-exprs "[,[:space:]]+" t))) (defvar mu4e-labels-list nil "Cached list of labels.") @@ -119,14 +100,20 @@ If EXPRS is empty, return nil." "The keymap for reading label delta expression.") (defun mu4e-labels-delta-read () - "Ask for a labels delta expression." + "Ask for a label delta +/ expression. + +I.e., a sequence of 1 or more space-separated labels, each +prefixed with \"+\" for addding the label, or \"-\" for removing +it." (minibuffer-with-setup-hook (lambda () (setq-local completion-at-point-functions #'mu4e--labels-completion-at-point) (use-local-map mu4e-minibuffer-label-expr-map)) - (mu4e-label-parse-exprs - (read-string "Label delta expression: ")))) + (string-join + (mu4e-label-parse-delta-exprs + (read-string "Label delta (+/-) expression: ")) + " "))) (defun mu4e--labels-update-server (docid expr) "Tell the server to update message with DOCID with EXPR. @@ -134,18 +121,13 @@ EXPR is a label delta-expression, such as \"+foo -bar\". Update the label cache while doing so." ;; update the cache - (let ((expr (mu4e-label-parse-exprs expr)) - (labels ;; the list of labels without +/- prefix - (seq-map (lambda (pmlabel) - (substring pmlabel 1)) - (split-string expr " ")))) - ;; don't care about dups etc.; the list - ;; will be replaced by a fresh server-side one, after - ;; update / restart - (setq mu4e-labels-list - (append labels mu4e-labels-list)) - ;; update the server - (mu4e--server-label docid expr))) + (let ((deltas (mu4e-label-parse-delta-exprs expr))) + ;; update cache + (seq-do (lambda (delta-label) + (cl-pushnew (substring delta-label 1) mu4e-labels-list)) + deltas) + ;; maybe pass as list? + (mu4e--server-label docid (string-join deltas " ")))) (defun mu4e--labels-clear-server (docid) "Clear all labels from message with DOCID." diff --git a/mu4e/mu4e-mark.el b/mu4e/mu4e-mark.el index b466817..42ccfc2 100644 --- a/mu4e/mu4e-mark.el +++ b/mu4e/mu4e-mark.el @@ -329,11 +329,6 @@ The following marks are available, and the corresponding props: (when (mu4e-create-maildir-maybe fulltarget) target))) -(defun mu4e--mark-get-labels-target () - "Ask for a labels expression." - (let* ((exprs (read-from-minibuffer "Label expression: "))) - (mu4e-label-parse-exprs exprs))) - (defun mu4e--mark-ask-target (mark) "Ask the target for MARK, if the user should be asked the target." (let ((getter (plist-get (cdr (assq mark mu4e-marks)) :ask-target))) |
