aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2008-12-04 22:49:21 +0000
committerChong Yidong2008-12-04 22:49:21 +0000
commitbc6cdadc9444314c865a3ebf340c18421273ab89 (patch)
treef5ffc6a06e66a9e49ffdc7a84b348a0babbadcc8
parent0efcb0dc64b1b7b85a97eebdb023d8dd8ee913d0 (diff)
downloademacs-bc6cdadc9444314c865a3ebf340c18421273ab89.tar.gz
emacs-bc6cdadc9444314c865a3ebf340c18421273ab89.zip
Sync with rmailkwd.el.
-rw-r--r--lisp/mail/pmailkwd.el347
1 files changed, 203 insertions, 144 deletions
diff --git a/lisp/mail/pmailkwd.el b/lisp/mail/pmailkwd.el
index 6bce28a59e2..4f95cb8f3f3 100644
--- a/lisp/mail/pmailkwd.el
+++ b/lisp/mail/pmailkwd.el
@@ -1,7 +1,7 @@
1;;; pmailkwd.el --- part of the "PMAIL" mail reader for Emacs 1;;; pmailkwd.el --- part of the "PMAIL" mail reader for Emacs
2 2
3;; Copyright (C) 1985, 1988, 1994, 2001, 2002, 2003, 2004, 2005, 2006, 3;; Copyright (C) 1985, 1988, 1994, 2001, 2002, 2003, 2004,
4;; 2007, 2008 Free Software Foundation, Inc. 4;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 5
6;; Maintainer: FSF 6;; Maintainer: FSF
7;; Keywords: mail 7;; Keywords: mail
@@ -23,9 +23,6 @@
23 23
24;;; Commentary: 24;;; Commentary:
25 25
26;; This library manages keywords (labels). Labels are stored in the
27;; variable `pmail-keywords'.
28
29;;; Code: 26;;; Code:
30 27
31(defvar pmail-buffer) 28(defvar pmail-buffer)
@@ -39,148 +36,158 @@
39;; completion. It is better to use strings with the label functions 36;; completion. It is better to use strings with the label functions
40;; and let them worry about making the label. 37;; and let them worry about making the label.
41 38
42(eval-when-compile 39(defvar pmail-label-obarray (make-vector 47 0))
43 (require 'mail-utils))
44 40
45;; Named list of symbols representing valid message attributes in PMAIL. 41;; Named list of symbols representing valid message attributes in PMAIL.
46 42
47(defconst pmail-attributes 43(defconst pmail-attributes
48 '(deleted answered filed forwarded unseen edited resent) 44 (cons 'pmail-keywords
49 "Keywords with defined semantics used to label messages. 45 (mapcar (function (lambda (s) (intern s pmail-label-obarray)))
50These have a well-defined meaning to the PMAIL system.") 46 '("deleted" "answered" "filed" "forwarded" "unseen" "edited"
47 "resent"))))
51 48
52(defconst pmail-deleted-label 'deleted) 49(defconst pmail-deleted-label (intern "deleted" pmail-label-obarray))
53 50
54;; Named list of symbols representing valid message keywords in PMAIL. 51;; Named list of symbols representing valid message keywords in PMAIL.
55 52
56(defvar pmail-keywords nil 53(defvar pmail-keywords)
57 "Keywords used to label messages.
58These are all user-defined, unlike `pmail-attributes'.")
59 54
55;;;###autoload
56(defun pmail-add-label (string)
57 "Add LABEL to labels associated with current PMAIL message.
58Completion is performed over known labels when reading."
59 (interactive (list (pmail-read-label "Add label")))
60 (pmail-set-label string t))
60 61
61;; External library declarations. 62;;;###autoload
62(declare-function mail-comma-list-regexp "mail-utils" (labels)) 63(defun pmail-kill-label (string)
63(declare-function mail-parse-comma-list "mail-utils" ()) 64 "Remove LABEL from labels associated with current PMAIL message.
64(declare-function pmail-desc-add-keyword "pmaildesc" (keyword n)) 65Completion is performed over known labels when reading."
65(declare-function pmail-desc-get-end "pmaildesc" (n)) 66 (interactive (list (pmail-read-label "Remove label")))
66(declare-function pmail-desc-get-keywords "pmaildesc" (n)) 67 (pmail-set-label string nil))
67(declare-function pmail-desc-get-start "pmaildesc" (n)) 68
68(declare-function pmail-desc-remove-keyword "pmaildesc" (keyword n)) 69;;;###autoload
70(defun pmail-read-label (prompt)
71 (with-current-buffer pmail-buffer
72 (if (not pmail-keywords) (pmail-parse-file-keywords))
73 (let ((result
74 (completing-read (concat prompt
75 (if pmail-last-label
76 (concat " (default "
77 (symbol-name pmail-last-label)
78 "): ")
79 ": "))
80 pmail-label-obarray
81 nil
82 nil)))
83 (if (string= result "")
84 pmail-last-label
85 (setq pmail-last-label (pmail-make-label result t))))))
86
87(declare-function pmail-maybe-set-message-counters "pmail" ())
69(declare-function pmail-display-labels "pmail" ()) 88(declare-function pmail-display-labels "pmail" ())
70(declare-function pmail-message-labels-p "pmail" (msg labels))
71(declare-function pmail-msgbeg "pmail" (n)) 89(declare-function pmail-msgbeg "pmail" (n))
72(declare-function pmail-set-attribute "pmail" (attr state &optional msgnum)) 90(declare-function pmail-set-message-deleted-p "pmail" (n state))
91(declare-function pmail-message-labels-p "pmail" (msg labels))
73(declare-function pmail-show-message "pmail" (&optional n no-summary)) 92(declare-function pmail-show-message "pmail" (&optional n no-summary))
74(declare-function pmail-summary-exists "pmail" ()) 93(declare-function mail-comma-list-regexp "mail-utils" (labels))
75(declare-function pmail-summary-update "pmailsum" (n)) 94(declare-function mail-parse-comma-list "mail-utils.el" ())
76 95
77;;;; Low-level functions. 96(defun pmail-set-label (l state &optional n)
97 (with-current-buffer pmail-buffer
98 (pmail-maybe-set-message-counters)
99 (if (not n) (setq n pmail-current-message))
100 (aset pmail-summary-vector (1- n) nil)
101 (let* ((attribute (pmail-attribute-p l))
102 (keyword (and (not attribute)
103 (or (pmail-keyword-p l)
104 (pmail-install-keyword l))))
105 (label (or attribute keyword)))
106 (if label
107 (let ((omax (- (buffer-size) (point-max)))
108 (omin (- (buffer-size) (point-min)))
109 (buffer-read-only nil)
110 (case-fold-search t))
111 (unwind-protect
112 (save-excursion
113 (widen)
114 (goto-char (pmail-msgbeg n))
115 (forward-line 1)
116 (if (not (looking-at "[01],"))
117 nil
118 (let ((start (1+ (point)))
119 (bound))
120 (narrow-to-region (point) (progn (end-of-line) (point)))
121 (setq bound (point-max))
122 (search-backward ",," nil t)
123 (if attribute
124 (setq bound (1+ (point)))
125 (setq start (1+ (point))))
126 (goto-char start)
127; (while (re-search-forward "[ \t]*,[ \t]*" nil t)
128; (replace-match ","))
129; (goto-char start)
130 (if (re-search-forward
131 (concat ", " (pmail-quote-label-name label) ",")
132 bound
133 'move)
134 (if (not state) (replace-match ","))
135 (if state (insert " " (symbol-name label) ",")))
136 (if (eq label pmail-deleted-label)
137 (pmail-set-message-deleted-p n state)))))
138 (narrow-to-region (- (buffer-size) omin) (- (buffer-size) omax))
139 (if (= n pmail-current-message) (pmail-display-labels))))))))
140
141;; Commented functions aren't used by PMAIL but might be nice for user
142;; packages that do stuff with PMAIL. Note that pmail-message-labels-p
143;; is in pmail.el now.
144
145;(defun pmail-message-label-p (label &optional n)
146; "Returns symbol if LABEL (attribute or keyword) on NTH or current message."
147; (pmail-message-labels-p (or n pmail-current-message) (regexp-quote label)))
148
149;(defun pmail-parse-message-labels (&optional n)
150; "Returns labels associated with NTH or current PMAIL message.
151;The result is a list of two lists of strings. The first is the
152;message attributes and the second is the message keywords."
153; (let (atts keys)
154; (save-restriction
155; (widen)
156; (goto-char (pmail-msgbeg (or n pmail-current-message)))
157; (forward-line 1)
158; (or (looking-at "[01],") (error "Malformed label line"))
159; (forward-char 2)
160; (while (looking-at "[ \t]*\\([^ \t\n,]+\\),")
161; (setq atts (cons (buffer-substring (match-beginning 1) (match-end 1))
162; atts))
163; (goto-char (match-end 0)))
164; (or (looking-at ",") (error "Malformed label line"))
165; (forward-char 1)
166; (while (looking-at "[ \t]*\\([^ \t\n,]+\\),")
167; (setq keys (cons (buffer-substring (match-beginning 1) (match-end 1))
168; keys))
169; (goto-char (match-end 0)))
170; (or (looking-at "[ \t]*$") (error "Malformed label line"))
171; (list (nreverse atts) (nreverse keys)))))
78 172
79(defun pmail-attribute-p (s) 173(defun pmail-attribute-p (s)
80 "Non-nil if S is a known attribute.
81See `pmail-attributes'."
82 (let ((symbol (pmail-make-label s))) 174 (let ((symbol (pmail-make-label s)))
83 (memq symbol pmail-attributes))) 175 (if (memq symbol (cdr pmail-attributes)) symbol)))
84 176
85(defun pmail-keyword-p (s) 177(defun pmail-keyword-p (s)
86 "Non-nil if S is a known keyword for this Pmail file.
87See `pmail-keywords'."
88 (let ((symbol (pmail-make-label s))) 178 (let ((symbol (pmail-make-label s)))
89 (memq symbol pmail-keywords))) 179 (if (memq symbol (cdr (pmail-keywords))) symbol)))
90 180
91(defun pmail-make-label (s &optional forcep) 181(defun pmail-make-label (s &optional forcep)
92 (cond ((symbolp s) s) 182 (cond ((symbolp s) s)
93 (forcep (intern (downcase s))) 183 (forcep (intern (downcase s) pmail-label-obarray))
94 (t (intern-soft (downcase s))))) 184 (t (intern-soft (downcase s) pmail-label-obarray))))
185
186(defun pmail-force-make-label (s)
187 (intern (downcase s) pmail-label-obarray))
95 188
96(defun pmail-quote-label-name (label) 189(defun pmail-quote-label-name (label)
97 (regexp-quote (symbol-name (pmail-make-label label t)))) 190 (regexp-quote (symbol-name (pmail-make-label label t))))
98
99;;;###autoload
100(defun pmail-register-keywords (words)
101 "Add the strings in WORDS to `pmail-keywords'."
102 (dolist (word words)
103 (pmail-register-keyword word)))
104
105(defun pmail-register-keyword (word)
106 "Append the string WORD to `pmail-keywords',
107unless it already is a keyword or an attribute."
108 (let ((keyword (pmail-make-label word t)))
109 (unless (or (pmail-attribute-p keyword)
110 (pmail-keyword-p keyword))
111 (setq pmail-keywords (cons keyword pmail-keywords)))))
112
113;;;; Adding and removing message keywords.
114
115;;;###autoload
116(defun pmail-add-label (string)
117 "Add LABEL to labels associated with current PMAIL message."
118 (interactive (list (pmail-read-label "Add label")))
119 (pmail-set-label (pmail-make-label string) t)
120 (pmail-display-labels))
121
122;;;###autoload
123(defun pmail-kill-label (string)
124 "Remove LABEL from labels associated with current PMAIL message."
125 (interactive (list (pmail-read-label "Remove label" t)))
126 (pmail-set-label (pmail-make-label string) nil))
127
128;;;###autoload
129(defun pmail-read-label (prompt &optional existing)
130 "Ask for a label using PROMPT.
131If EXISTING is non-nil, ask for one of the labels of the current
132message."
133 (when (= pmail-total-messages 0)
134 (error "No messages in this file"))
135 (with-current-buffer pmail-buffer
136 (let ((result (if existing
137 (let* ((keywords (pmail-desc-get-keywords
138 pmail-current-message))
139 (last (symbol-name pmail-last-label))
140 (default (if (member last keywords)
141 last
142 (car keywords))))
143 (unless keywords
144 (error "No labels for the current message"))
145 (completing-read
146 (concat prompt " (default " default "): ")
147 keywords nil t nil nil default))
148 (let ((default (symbol-name pmail-last-label)))
149 (completing-read
150 (concat prompt (if pmail-last-label
151 (concat " (default " default "): ")
152 ": "))
153 (mapcar 'list pmail-keywords)
154 nil nil nil nil default)))))
155 (setq pmail-last-label (pmail-make-label result t))
156 ;; return the string, not the symbol
157 result)))
158
159(defun pmail-set-label (l state &optional n)
160 "Add or remove label L in message N.
161The label L is added when STATE is non-nil, otherwise it is
162removed. If N is nil then use the current Pmail message. The
163current buffer, possibly narrowed, displays a message."
164 (if (= pmail-total-messages 0)
165 (error "No messages in this file"))
166 (with-current-buffer pmail-buffer
167 (if (not n) (setq n pmail-current-message))
168 (save-restriction
169 (widen)
170 (narrow-to-region (pmail-desc-get-start n) (pmail-desc-get-end n))
171 ;; FIXME: we should move all string-using functions to symbols!
172 (let ((str (symbol-name l)))
173 (if (pmail-attribute-p l)
174 (pmail-set-attribute str state n)
175 ;; Make sure the keyword is registered.
176 (pmail-register-keyword l)
177 (if state
178 (pmail-desc-add-keyword str n)
179 (pmail-desc-remove-keyword str n))))))
180 (pmail-display-labels)
181 ;; Deal with the summary buffer.
182 (when (pmail-summary-exists)
183 (pmail-summary-update n)))
184 191
185;; Motion on messages with keywords. 192;; Motion on messages with keywords.
186 193
@@ -200,32 +207,84 @@ LABELS should be a comma-separated list of label names.
200If LABELS is empty, the last set of labels specified is used. 207If LABELS is empty, the last set of labels specified is used.
201With prefix argument N moves forward N messages with these labels." 208With prefix argument N moves forward N messages with these labels."
202 (interactive "p\nsMove to next msg with labels: ") 209 (interactive "p\nsMove to next msg with labels: ")
203 (when (string= labels "") 210 (if (string= labels "")
204 (setq labels pmail-last-multi-labels)) 211 (setq labels pmail-last-multi-labels))
205 (unless labels 212 (or labels
206 (error "No labels to find have been specified previously")) 213 (error "No labels to find have been specified previously"))
207 (with-current-buffer pmail-buffer 214 (set-buffer pmail-buffer)
208 (setq pmail-last-multi-labels labels) 215 (setq pmail-last-multi-labels labels)
209 (let ((lastwin pmail-current-message) 216 (pmail-maybe-set-message-counters)
210 (current pmail-current-message) 217 (let ((lastwin pmail-current-message)
211 (regexp (concat ", ?\\(" 218 (current pmail-current-message)
212 (mail-comma-list-regexp labels) 219 (regexp (concat ", ?\\("
213 "\\),"))) 220 (mail-comma-list-regexp labels)
214 (save-restriction 221 "\\),")))
215 (widen) 222 (save-restriction
216 (while (and (> n 0) (< current pmail-total-messages)) 223 (widen)
217 (setq current (1+ current)) 224 (while (and (> n 0) (< current pmail-total-messages))
218 (when (pmail-message-labels-p current regexp) 225 (setq current (1+ current))
226 (if (pmail-message-labels-p current regexp)
219 (setq lastwin current n (1- n)))) 227 (setq lastwin current n (1- n))))
220 (while (and (< n 0) (> current 1)) 228 (while (and (< n 0) (> current 1))
221 (setq current (1- current)) 229 (setq current (1- current))
222 (when (pmail-message-labels-p current regexp) 230 (if (pmail-message-labels-p current regexp)
223 (setq lastwin current n (1+ n))))) 231 (setq lastwin current n (1+ n)))))
224 (pmail-show-message lastwin) 232 (pmail-show-message lastwin)
225 (when (< n 0) 233 (if (< n 0)
226 (message "No previous message with labels %s" labels)) 234 (message "No previous message with labels %s" labels))
227 (when (> n 0) 235 (if (> n 0)
228 (message "No following message with labels %s" labels))))) 236 (message "No following message with labels %s" labels))))
237
238;;; Manipulate the file's Labels option.
239
240;; Return a list of symbols for all
241;; the keywords (labels) recorded in this file's Labels option.
242(defun pmail-keywords ()
243 (or pmail-keywords (pmail-parse-file-keywords)))
244
245;; Set pmail-keywords to a list of symbols for all
246;; the keywords (labels) recorded in this file's Labels option.
247(defun pmail-parse-file-keywords ()
248 (save-restriction
249 (save-excursion
250 (widen)
251 (goto-char 1)
252 (setq pmail-keywords
253 (if (search-forward "\nLabels:" (pmail-msgbeg 1) t)
254 (progn
255 (narrow-to-region (point) (progn (end-of-line) (point)))
256 (goto-char (point-min))
257 (cons 'pmail-keywords
258 (mapcar 'pmail-force-make-label
259 (mail-parse-comma-list)))))))))
260
261;; Add WORD to the list in the file's Labels option.
262;; Any keyword used for the first time needs this done.
263(defun pmail-install-keyword (word)
264 (let ((keyword (pmail-make-label word t))
265 (keywords (pmail-keywords)))
266 (if (not (or (pmail-attribute-p keyword)
267 (pmail-keyword-p keyword)))
268 (let ((omin (- (buffer-size) (point-min)))
269 (omax (- (buffer-size) (point-max))))
270 (unwind-protect
271 (save-excursion
272 (widen)
273 (goto-char 1)
274 (let ((case-fold-search t)
275 (buffer-read-only nil))
276 (or (search-forward "\nLabels:" nil t)
277 (progn
278 (end-of-line)
279 (insert "\nLabels:")))
280 (delete-region (point) (progn (end-of-line) (point)))
281 (setcdr keywords (cons keyword (cdr keywords)))
282 (while (setq keywords (cdr keywords))
283 (insert (symbol-name (car keywords)) ","))
284 (delete-char -1)))
285 (narrow-to-region (- (buffer-size) omin)
286 (- (buffer-size) omax)))))
287 keyword))
229 288
230(provide 'pmailkwd) 289(provide 'pmailkwd)
231 290