Mercurial > hg > xemacs-beta
comparison lisp/utils/highlight-headers.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; highlight-headers.el --- highlighting message headers. | |
2 | |
3 ;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. | |
4 ;; Copyright (C) 1995 Tinker Systems | |
5 | |
6 ;; Keywords: mail, news | |
7 | |
8 ;; This file is part of XEmacs. | |
9 | |
10 ;; XEmacs is free software; you can redistribute it and/or modify it | |
11 ;; under the terms of the GNU General Public License as published by | |
12 ;; the Free Software Foundation; either version 2, or (at your option) | |
13 ;; any later version. | |
14 | |
15 ;; XEmacs is distributed in the hope that it will be useful, but | |
16 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 ;; General Public License for more details. | |
19 | |
20 ;; You should have received a copy of the GNU General Public License | |
21 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
22 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
23 | |
24 ;;; Synched up with: Not in FSF. | |
25 | |
26 ;; This code is shared by RMAIL, VM, and GNUS. | |
27 ;; | |
28 ;; Faces: | |
29 ;; | |
30 ;; message-headers the part before the colon | |
31 ;; message-header-contents the part after the colon | |
32 ;; message-highlighted-header-contents contents of "special" headers | |
33 ;; message-cited-text quoted text from other messages | |
34 ;; | |
35 ;; Variables: | |
36 ;; | |
37 ;; highlight-headers-regexp what makes a "special" header | |
38 ;; highlight-headers-citation-regexp matches lines of quoted text | |
39 ;; highlight-headers-citation-header-regexp matches headers for quoted text | |
40 | |
41 (if (find-face 'message-headers) | |
42 nil | |
43 (make-face 'message-headers) | |
44 (or (face-differs-from-default-p 'message-headers) | |
45 (copy-face 'bold 'message-headers))) | |
46 | |
47 (if (find-face 'message-header-contents) | |
48 nil | |
49 (make-face 'message-header-contents) | |
50 (or (face-differs-from-default-p 'message-header-contents) | |
51 (copy-face 'italic 'message-header-contents))) | |
52 | |
53 (if (find-face 'message-highlighted-header-contents) | |
54 nil | |
55 (make-face 'message-highlighted-header-contents) | |
56 (or (face-differs-from-default-p 'message-highlighted-header-contents) | |
57 (progn | |
58 (copy-face 'message-header-contents | |
59 'message-highlighted-header-contents) | |
60 ;; Most people seem not to like underlining, so change | |
61 ;; the font instead. | |
62 ;; (set-face-underline-p 'message-highlighted-header-contents t) | |
63 (or (make-face-bold 'message-highlighted-header-contents) | |
64 (make-face-unbold 'message-highlighted-header-contents) | |
65 (make-face-italic 'message-highlighted-header-contents) | |
66 (make-face-unitalic 'message-highlighted-header-contents)) | |
67 ))) | |
68 | |
69 (if (find-face 'message-cited-text) | |
70 nil | |
71 (make-face 'message-cited-text) | |
72 (or (face-differs-from-default-p 'message-cited-text) | |
73 (copy-face 'italic 'message-cited-text))) | |
74 | |
75 (if (find-face 'x-face) | |
76 nil | |
77 (make-face 'x-face) | |
78 (or (face-differs-from-default-p 'x-face) | |
79 (progn | |
80 (copy-face 'message-highlighted-header-contents 'x-face) | |
81 (set-face-background 'x-face "white") | |
82 (set-face-foreground 'x-face "black")))) | |
83 | |
84 ;;(condition-case nil | |
85 ;; (face-name 'message-addresses) | |
86 ;; (wrong-type-argument | |
87 ;; (make-face 'message-addresses) | |
88 ;; (or (face-differs-from-default-p 'message-addresses) | |
89 ;; (progn | |
90 ;; (copy-face 'bold-italic 'message-addresses) | |
91 ;; (set-face-underline-p 'message-addresses | |
92 ;; (face-underline-p | |
93 ;; 'message-highlighted-header-contents)))))) | |
94 | |
95 (defvar highlight-headers-regexp "Subject[ \t]*:" | |
96 "*The headers whose contents should be emphasized more. | |
97 The contents of these headers will be displayed in the face | |
98 `message-highlighted-header-contents' instead of `message-header-contents'.") | |
99 | |
100 (defvar highlight-headers-citation-regexp | |
101 (concat "^\\(" | |
102 (mapconcat 'identity | |
103 '("[ \t]*[a-zA-Z0-9_]+>+" ; supercite | |
104 "[ \t]*[>]+" ; ">" with leading spaces | |
105 "[]}<>|:]+[ \t]*" ; other chars, no leading space | |
106 ) | |
107 "\\|") | |
108 "\\)[ \t]*") | |
109 "*The pattern to match cited text. | |
110 Text in the body of a message which matches this will be displayed in | |
111 the face `message-cited-text'.") | |
112 | |
113 (defvar highlight-headers-citation-header-regexp | |
114 (concat "^In article\\|^In message\\|" | |
115 "^[^ \t].*\\(writes\\|wrote\\|said\\):\n" | |
116 (substring highlight-headers-citation-regexp 1)) | |
117 "*The pattern to match the prolog of a cited block. | |
118 Text in the body of a message which matches this will be displayed in | |
119 the `message-headers' face.") | |
120 | |
121 (defvar highlight-headers-highlight-citation-too nil | |
122 "*Whether the whole citation line should go in the `mesage-cited-text' face. | |
123 If nil, the text matched by `highlight-headers-citation-regexp' is in the | |
124 default face, and the remainder of the line is in the message-cited-text face.") | |
125 | |
126 (defvar highlight-headers-max-message-size 10000 | |
127 "*If the message body is larger than this many chars, don't highlight it. | |
128 This is to prevent us from wasting time trying to fontify things like | |
129 uuencoded files and large digests. If this is nil, all messages will | |
130 be highlighted.") | |
131 | |
132 (defvar highlight-headers-hack-x-face-p (featurep 'xface) | |
133 "*If true, then the bitmap in an X-Face header will be displayed | |
134 in the buffer. This assumes you have the `uncompface' and `icontopbm' | |
135 programs on your path.") | |
136 | |
137 (defvar highlight-headers-convert-quietly nil | |
138 "*Non-nil inhibits the message that is normally displayed when external | |
139 filters are used to convert an X-Face header. This has no affect if | |
140 XEmacs is compiled with internal support for x-faces.") | |
141 | |
142 (defvar highlight-headers-invert-x-face-data nil | |
143 "*If true, causes the foreground and background bits in an X-Face | |
144 header to be flipped before the image is displayed. If you use a | |
145 light foreground color on a dark background color, you probably want | |
146 to set this to t. This assumes that you have the `pnminvert' program | |
147 on your path. This doesn't presently work with internal xface support.") | |
148 | |
149 | |
150 ;;;###autoload | |
151 (defun highlight-headers (start end hack-sig) | |
152 "Highlight message headers between start and end. | |
153 Faces used: | |
154 message-headers the part before the colon | |
155 message-header-contents the part after the colon | |
156 message-highlighted-header-contents contents of \"special\" headers | |
157 message-cited-text quoted text from other messages | |
158 | |
159 Variables used: | |
160 | |
161 highlight-headers-regexp what makes a \"special\" header | |
162 highlight-headers-citation-regexp matches lines of quoted text | |
163 highlight-headers-citation-header-regexp matches headers for quoted text | |
164 | |
165 If HACK-SIG is true,then we search backward from END for something that | |
166 looks like the beginning of a signature block, and don't consider that a | |
167 part of the message (this is because signatures are often incorrectly | |
168 interpreted as cited text.)" | |
169 (if (< end start) | |
170 (let ((s start)) (setq start end end s))) | |
171 (let* ((too-big (and highlight-headers-max-message-size | |
172 (> (- end start) | |
173 highlight-headers-max-message-size))) | |
174 (real-end end) | |
175 e p hend) | |
176 ;; delete previous highlighting | |
177 (map-extents (function (lambda (extent ignore) | |
178 (if (extent-property extent 'headers) | |
179 (delete-extent extent)) | |
180 nil)) | |
181 (current-buffer) start end) | |
182 (save-excursion | |
183 (save-restriction | |
184 (widen) | |
185 ;; take off signature | |
186 (if (and hack-sig (not too-big)) | |
187 (save-excursion | |
188 (goto-char end) | |
189 (if (re-search-backward "\n--+ *\n" start t) | |
190 (if (eq (char-after (point)) ?\n) | |
191 (setq end (1+ (point))) | |
192 (setq end (point)))))) | |
193 (narrow-to-region start end) | |
194 | |
195 (save-restriction | |
196 ;; narrow down to just the headers... | |
197 (goto-char start) | |
198 ;; If this search fails then the narrowing performed above | |
199 ;; is sufficient | |
200 (if (re-search-forward "^$" nil t) | |
201 (narrow-to-region (point-min) (point))) | |
202 (goto-char start) | |
203 (while (not (eobp)) | |
204 (cond | |
205 ((looking-at "^\\([^ \t\n:]+[ \t]*:\\) *\\(.*\\(\n[ \t].*\\)*\n\\)") | |
206 (setq hend (match-end 0)) | |
207 (setq e (make-extent (match-beginning 1) (match-end 1))) | |
208 (set-extent-face e 'message-headers) | |
209 (set-extent-property e 'headers t) | |
210 (setq p (match-end 1)) | |
211 (cond | |
212 ((and highlight-headers-hack-x-face-p | |
213 (save-match-data (looking-at "^X-Face: *"))) | |
214 ;; make the whole header invisible | |
215 (setq e (make-extent (match-beginning 0) (match-end 0))) | |
216 (set-extent-property e 'invisible t) | |
217 (set-extent-property e 'headers t) | |
218 ;; now extract the xface and put it somewhere interesting | |
219 (let ((xface (highlight-headers-x-face-to-pixmap | |
220 (match-beginning 2) | |
221 (match-end 2)))) | |
222 (if (not xface) | |
223 nil ; just leave the header invisible if | |
224 ; we can't convert the face for some | |
225 ; reason | |
226 (cond ((save-excursion | |
227 (goto-char (point-min)) | |
228 (save-excursion (re-search-forward "^From: *" | |
229 nil t))) | |
230 (setq e (make-extent (match-end 0) | |
231 (match-end 0)))) | |
232 (t | |
233 ;; okay, make the beginning of the the invisible | |
234 ;; move forward to only hide the modem noise... | |
235 (set-extent-endpoints e | |
236 (match-beginning 2) | |
237 (1- (match-end 2))) | |
238 ;; kludge: if a zero-length extent exists at the | |
239 ;; starting point of an invisible extent, then | |
240 ;; it's invisible... even if the invisible extent | |
241 ;; is start-open. | |
242 (setq e (make-extent (1- (match-beginning 2)) | |
243 (match-beginning 2))) | |
244 )) | |
245 (set-extent-property e 'headers t) | |
246 (set-extent-end-glyph e xface)) | |
247 )) | |
248 ;;; I don't think this is worth the effort | |
249 ;;; ((looking-at "\\(From\\|Resent-From\\)[ \t]*:") | |
250 ;;; (setq current 'message-highlighted-header-contents) | |
251 ;;; (goto-char (match-end 0)) | |
252 ;;; (or (looking-at ".*(\\(.*\\))") | |
253 ;;; (looking-at "\\(.*\\)<") | |
254 ;;; (looking-at "\\(.*\\)[@%]") | |
255 ;;; (looking-at "\\(.*\\)")) | |
256 ;;; (end-of-line) | |
257 ;;; (setq e (make-extent p (match-beginning 1))) | |
258 ;;; (set-extent-face e current) | |
259 ;;; (set-extent-property e 'headers t) | |
260 ;;; (setq e (make-extent (match-beginning 1) (match-end 1))) | |
261 ;;; (set-extent-face e 'message-addresses) | |
262 ;;; (set-extent-property e 'headers t) | |
263 ;;; (setq e (make-extent (match-end 1) (point))) | |
264 ;;; (set-extent-face e current) | |
265 ;;; (set-extent-property e 'headers t) | |
266 ;;; ) | |
267 ((and highlight-headers-regexp | |
268 (save-match-data (looking-at highlight-headers-regexp))) | |
269 (setq e (make-extent (match-beginning 2) (match-end 2))) | |
270 (set-extent-face e 'message-highlighted-header-contents) | |
271 (set-extent-property e 'headers t)) | |
272 (t | |
273 (setq e (make-extent (match-beginning 2) (match-end 2))) | |
274 (set-extent-face e 'message-header-contents) | |
275 (set-extent-property e 'headers t)) | |
276 ) | |
277 (goto-char hend)) | |
278 ;; ignore non-header field name lines | |
279 (t (forward-line 1))))) | |
280 | |
281 ;; now do the body, unless it's too big.... | |
282 (if too-big | |
283 nil | |
284 (while (not (eobp)) | |
285 (cond ((null highlight-headers-citation-regexp) | |
286 nil) | |
287 ((looking-at highlight-headers-citation-regexp) | |
288 (or highlight-headers-highlight-citation-too | |
289 (goto-char (match-end 0))) | |
290 (or (save-excursion | |
291 (beginning-of-line) | |
292 (let ((case-fold-search nil)) ; aaaaah, unix... | |
293 (looking-at "^>From "))) | |
294 (setq current 'message-cited-text))) | |
295 ;;; ((or (looking-at "^In article\\|^In message") | |
296 ;;; (looking-at | |
297 ;;; "^[^ \t].*\\(writes\\|wrote\\|said\\):\n[ \t]+[A-Z]*[]}<>|]")) | |
298 ;;; (setq current 'message-headers)) | |
299 ((null highlight-headers-citation-header-regexp) | |
300 nil) | |
301 ((looking-at highlight-headers-citation-header-regexp) | |
302 (setq current 'message-headers)) | |
303 (t (setq current nil))) | |
304 (cond (current | |
305 (setq p (point)) | |
306 (forward-line 1) ; this is to put the \n in the face too | |
307 (setq e (make-extent p (point))) | |
308 (forward-char -1) | |
309 (set-extent-face e current) | |
310 (set-extent-property e 'headers t) | |
311 )) | |
312 (forward-line 1))) | |
313 )) | |
314 (save-excursion | |
315 (save-restriction | |
316 (widen) | |
317 (narrow-to-region start real-end) | |
318 (highlight-headers-mark-urls start real-end))) | |
319 )) | |
320 | |
321 | |
322 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
323 ;;; | |
324 ;;; X-Face header conversion: | |
325 | |
326 ;;; This cache is only used if x-face conversion is done with external | |
327 ;;; filters. If XEmacs is compiled --with-xface, then it's better to | |
328 ;;; convert it twice than to suck up memory for a potentially large cache of | |
329 ;;; stuff that's not difficult to recreate. | |
330 (defvar highlight-headers-x-face-to-pixmap-cache nil) | |
331 | |
332 (defun highlight-headers-x-face-to-pixmap (start end) | |
333 (let* ((string (if (stringp start) start (buffer-substring start end))) | |
334 (data (assoc string highlight-headers-x-face-to-pixmap-cache))) | |
335 (if (featurep 'xface) | |
336 (let ((new-face (make-glyph (concat "X-Face: " string)))) | |
337 (set-glyph-face new-face 'x-face) | |
338 new-face) | |
339 ;; YUCK this is the old two-external-filters-plus-a-bunch-of-lisp method | |
340 (if data | |
341 (cdr data) | |
342 (setq data (cons string | |
343 (condition-case c | |
344 (highlight-headers-parse-x-face-data start end) | |
345 (error | |
346 (display-error c nil) | |
347 (sit-for 2) | |
348 nil)))) | |
349 (setq highlight-headers-x-face-to-pixmap-cache | |
350 (cons data highlight-headers-x-face-to-pixmap-cache)) | |
351 (cdr data))) | |
352 )) | |
353 | |
354 ;;; Kludge kludge kludge for displaying the bitmap in the X-Face header. | |
355 | |
356 ;;; This depends on the following programs: icontopbm, from the pbmplus | |
357 ;;; toolkit (available everywhere) and uncompface, which comes with | |
358 ;;; several faces-related packages, and can also be had at ftp.clark.net | |
359 ;;; in /pub/liebman/compface.tar.Z. See also xfaces 3.*. Not needed | |
360 ;;; for this, but a very nice xbiff replacment. | |
361 | |
362 (defconst highlight-headers-x-face-bitrev | |
363 (purecopy | |
364 (eval-when-compile | |
365 (let* ((v (make-string 256 0)) | |
366 (i (1- (length v)))) | |
367 (while (>= i 0) | |
368 (let ((j 7) | |
369 (k 0)) | |
370 (while (>= j 0) | |
371 (if (/= 0 (logand i (lsh 1 (- 7 j)))) | |
372 (setq k (logior k (lsh 1 j)))) | |
373 (setq j (1- j))) | |
374 (aset v i k)) | |
375 (setq i (1- i))) | |
376 v)))) | |
377 | |
378 (defun highlight-headers-parse-x-face-data (start end) | |
379 (save-excursion | |
380 (let ((b (current-buffer)) | |
381 (lines 0) | |
382 p) | |
383 (or highlight-headers-convert-quietly | |
384 (message "Converting X-Face header to pixmap ...")) | |
385 (set-buffer (get-buffer-create " *x-face-tmp*")) | |
386 (buffer-disable-undo (current-buffer)) | |
387 (erase-buffer) | |
388 (if (stringp start) | |
389 (insert start) | |
390 (insert-buffer-substring b start end)) | |
391 (while (search-forward "\n" nil t) | |
392 (skip-chars-backward " \t\n") | |
393 (setq p (point)) | |
394 (skip-chars-forward " \t\n") | |
395 (delete-region p (point))) | |
396 (call-process-region (point-min) (point-max) "uncompface" t t nil) | |
397 (goto-char (point-min)) | |
398 (while (not (eobp)) | |
399 (or (looking-at "0x....,0x....,0x...., *$") | |
400 (error "unexpected uncompface output")) | |
401 (forward-line 1) | |
402 (setq lines (1+ lines)) | |
403 (delete-char -1)) | |
404 (goto-char (point-min)) | |
405 (insert (format "/* Format_version=1, Width=%d, Height=%d" lines lines)) | |
406 (insert ", Depth=1, Valid_bits_per_item=16\n */\n") | |
407 (while (not (eobp)) | |
408 (insert ?\t) | |
409 (forward-char 56) ; 7 groups per line | |
410 (insert ?\n)) | |
411 (forward-char -1) | |
412 (delete-char -1) ; take off last comma | |
413 ;; | |
414 ;; Ok, now we've got the format that "icontopbm" knows about. | |
415 (call-process-region (point-min) (point-max) "icontopbm" t t nil) | |
416 ;; Invert the image if the user wants us to... | |
417 (if highlight-headers-invert-x-face-data | |
418 (call-process-region (point-min) (point-max) "pnminvert" t t nil)) | |
419 ;; | |
420 ;; If PBM is using binary mode, we're winning. | |
421 (goto-char (point-min)) | |
422 (let ((new-face)) | |
423 (cond ((looking-at "P4\n") | |
424 (forward-line 2) | |
425 (delete-region (point-min) (point)) | |
426 (while (not (eobp)) | |
427 (insert (aref highlight-headers-x-face-bitrev | |
428 (following-char))) | |
429 (delete-char 1)) | |
430 (setq new-face (make-glyph | |
431 (vector 'xbm :data | |
432 (list lines lines (prog1 (buffer-string) | |
433 (erase-buffer)))))) | |
434 (set-glyph-image new-face "[xface]" 'global 'tty) | |
435 (set-glyph-face new-face 'x-face)) | |
436 (t ; fix me | |
437 (error "I only understand binary-format PBM..."))) | |
438 (or highlight-headers-convert-quietly | |
439 (message "Converting X-Face header to pixmap ... done.")) | |
440 new-face) | |
441 ))) | |
442 | |
443 | |
444 ;;; "The Internet's new BBS!" -Boardwatch Magazine | |
445 ;;; URL support by jwz@netscape.com | |
446 | |
447 (defvar highlight-headers-mark-urls (string-match "XEmacs" emacs-version) | |
448 "*Whether to make URLs clickable in message bodies.") | |
449 | |
450 (defvar highlight-headers-follow-url-function 'w3-fetch | |
451 "The function to invoke to follow a URL. | |
452 Possible values that work out of the box are: | |
453 | |
454 'w3-fetch == Use emacs-w3 | |
455 'highlight-headers-follow-url-netscape == Use Netscape 1.1 | |
456 'highlight-headers-follow-url-mosaic == Use Mosaic") | |
457 | |
458 (defvar highlight-headers-follow-url-netscape-auto-raise t | |
459 "*Whether to make Netscape auto-raise when a URL is sent to it.") | |
460 | |
461 (defvar highlight-headers-follow-url-netscape-new-window nil | |
462 "*Whether to make Netscape create a new window when a URL is sent to it.") | |
463 | |
464 ;;;###autoload | |
465 (defun highlight-headers-follow-url-netscape (url) | |
466 (message "Sending URL to Netscape...") | |
467 (save-excursion | |
468 (set-buffer (get-buffer-create "*Shell Command Output*")) | |
469 (erase-buffer) | |
470 (if (equal | |
471 0 | |
472 (apply 'call-process "netscape" nil t nil | |
473 "-remote" | |
474 (nconc | |
475 (and (not highlight-headers-follow-url-netscape-auto-raise) | |
476 (list "-noraise")) | |
477 (list | |
478 (concat "openURL(" url | |
479 (if highlight-headers-follow-url-netscape-new-window | |
480 ",new-window)" ")")))))) | |
481 ;; it worked | |
482 nil | |
483 ;; it didn't work, so start a new Netscape process. | |
484 (call-process "netscape" nil 0 nil url))) | |
485 (message "Sending URL to Netscape... done")) | |
486 | |
487 ;;;###autoload | |
488 (defun highlight-headers-follow-url-mosaic (url) | |
489 (message "Sending URL to Mosaic...") | |
490 (let ((pid-file "~/.mosaicpid") | |
491 (work-buffer " *mosaic work*") | |
492 (pid nil)) | |
493 (cond ((file-readable-p pid-file) | |
494 (set-buffer (get-buffer-create work-buffer)) | |
495 (erase-buffer) | |
496 (insert-file-contents pid-file) | |
497 (setq pid (int-to-string (string-to-int (buffer-string)))) | |
498 (erase-buffer) | |
499 (insert "goto" ?\n) | |
500 (insert url ?\n) | |
501 (write-region (point-min) (point-max) | |
502 (concat "/tmp/Mosaic." pid) | |
503 nil 0) | |
504 (set-buffer-modified-p nil) | |
505 (kill-buffer work-buffer))) | |
506 (cond ((or (null pid) | |
507 (not (equal 0 (call-process "kill" nil nil nil "-USR1" pid)))) | |
508 (call-process "Mosaic" nil 0 nil url)))) | |
509 (message "Sending URL to Mosaic... done")) | |
510 | |
511 (defvar highlight-headers-url-keymap | |
512 (let ((m (make-sparse-keymap))) | |
513 (set-keymap-name m 'highlight-headers-url-keymap) | |
514 (if (string-match "XEmacs" emacs-version) | |
515 (progn | |
516 (define-key m 'button2 'highlight-headers-follow-url) | |
517 )) | |
518 m)) | |
519 | |
520 ;;;###autoload | |
521 (defun highlight-headers-follow-url (event) | |
522 (interactive "e") | |
523 (let* ((p (event-point event)) | |
524 (buffer (window-buffer (event-window event))) | |
525 (extent (and p (extent-at p buffer 'highlight))) | |
526 (url (and extent | |
527 (save-excursion | |
528 (set-buffer buffer) | |
529 (buffer-substring (extent-start-position extent) | |
530 (extent-end-position extent)))))) | |
531 (if (and url (string-match "\\`<\\([^>]+\\)>\\'" url)) | |
532 (setq url (concat "news:" | |
533 (substring url (match-beginning 1) (match-end 1))))) | |
534 (if url | |
535 (funcall highlight-headers-follow-url-function url) | |
536 (beep)))) | |
537 | |
538 | |
539 (defconst highlight-headers-url-pattern | |
540 (concat | |
541 "\\b\\(s?https?\\|ftp\\|file\\|gopher\\|s?news\\|telnet\\|mailbox\\):" | |
542 "\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?" | |
543 "[-a-zA-Z0-9_=?#$@~`%&*+|\\/.,]+" | |
544 )) | |
545 | |
546 (defun highlight-headers-mark-urls (start end) | |
547 (cond | |
548 (highlight-headers-mark-urls | |
549 (save-excursion | |
550 (goto-char start) | |
551 (while (re-search-forward highlight-headers-url-pattern nil t) | |
552 (let ((s (match-beginning 0)) | |
553 e | |
554 extent) | |
555 (goto-char (match-end 0)) | |
556 ;(skip-chars-forward "^ \t\n\r") | |
557 (skip-chars-backward ".?#!*()") | |
558 (setq e (point)) | |
559 (setq extent (make-extent s e)) | |
560 (set-extent-face extent 'bold) | |
561 (set-extent-property extent 'highlight t) | |
562 (set-extent-property extent 'headers t) | |
563 (set-extent-property extent 'keymap highlight-headers-url-keymap) | |
564 )) | |
565 | |
566 (goto-char start) | |
567 (while (re-search-forward "^Message-ID: \\(<[^>\n]+>\\)" nil t) | |
568 (let ((s (match-beginning 1)) | |
569 (e (match-end 1)) | |
570 extent) | |
571 (setq extent (make-extent s e)) | |
572 (set-extent-face extent 'bold) | |
573 (set-extent-property extent 'highlight t) | |
574 (set-extent-property extent 'headers t) | |
575 (set-extent-property extent 'keymap highlight-headers-url-keymap))) | |
576 )))) | |
577 | |
578 | |
579 (provide 'highlight-headers) |