*** empty log message ***
[gnus] / lisp / gnus-cus.el
1 ;;; gnus-cus.el --- User friendly customization of Gnus
2 ;; Copyright (C) 1995,96 Free Software Foundation, Inc.
3 ;;
4 ;; Author: Per Abrahamsen <abraham@iesd.auc.dk>
5 ;; Keywords: help, news
6 ;; Version: 0.1
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it 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 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;;; Code:
28
29 (require 'custom)
30 (require 'gnus-ems)
31 (require 'browse-url)
32 (eval-when-compile (require 'cl))
33
34 ;; The following is just helper functions and data, not meant to be set
35 ;; by the user.
36 (defun gnus-make-face (color)
37   ;; Create entry for face with COLOR.
38   (custom-face-lookup color nil nil nil nil nil))
39
40 (defvar gnus-face-light-name-list
41   '("light blue" "light cyan" "light yellow" "light pink"
42     "pale green" "beige" "orange" "magenta" "violet" "medium purple"
43     "turquoise"))
44
45 (defvar gnus-face-dark-name-list
46   '("dark blue" "firebrick" "dark green" "OrangeRed" 
47     "dark khaki" "dark violet" "SteelBlue4"))
48 ; CornflowerBlue SeaGreen OrangeRed SteelBlue4 DeepPink3
49 ; DarkOlviveGreen4 
50
51 (custom-declare '()
52   '((tag . "Gnus")
53     (doc . "\
54 The coffee-brewing, all singing, all dancing, kitchen sink newsreader.")
55     (type . group)
56     (data
57      ((tag . "Visual")
58       (doc . "\
59 Gnus can be made colorful and fun or grey and dull as you wish.")
60       (type . group)
61       (data
62        ((tag . "Visual")
63         (doc . "Enable visual features.
64 If `visual' is disabled, there will be no menus and few faces.  Most of
65 the visual customization options below will be ignored.  Gnus will use
66 less space and be faster as a result.")
67         (default . 
68           (summary-highlight group-highlight
69                              article-highlight 
70                              mouse-face
71                              summary-menu group-menu article-menu
72                              tree-highlight menu highlight
73                              browse-menu server-menu
74                              page-marker tree-menu binary-menu pick-menu
75                              grouplens-menu))
76         (name . gnus-visual)
77         (type . sexp))
78        ((tag . "WWW Browser")
79         (doc . "\
80 WWW Browser to call when clicking on an URL button in the article buffer.
81
82 You can choose between one of the predefined browsers, or `Other'.")
83         (name . browse-url-browser-function)
84         (calculate . (cond ((boundp 'browse-url-browser-function)
85                             browse-url-browser-function)
86                            ((fboundp 'w3-fetch) 
87                             'w3-fetch)
88                            ((eq window-system 'x) 
89                             'gnus-netscape-open-url)))
90         (type . choice)
91         (data
92          ((tag . "W3")
93           (type . const)
94           (default . w3-fetch))
95          ((tag . "Netscape")
96           (type . const)
97           (default . browse-url-netscape))
98          ((prompt . "Other")
99           (doc . "\
100 You must specify the name of a Lisp function here.  The lisp function
101 should open a WWW browser when called with an URL (a string).
102 ")
103           (default . __uninitialized__)
104           (type . symbol))))
105        ((tag . "Mouse Face")
106         (doc . "\
107 Face used for group or summary buffer mouse highlighting.
108 The line beneath the mouse pointer will be highlighted with this
109 face.")
110         (name . gnus-mouse-face)
111         (calculate . (if (gnus-visual-p 'mouse-face 'highlight)
112                          (if (boundp 'gnus-mouse-face)
113                              gnus-mouse-face
114                            'highlight)
115                        'default))
116         (type . face))
117        ((tag . "Article Display")
118         (doc . "Controls how the article buffer will look.
119
120 If you leave the list empty, the article will appear exactly as it is
121 stored on the disk.  The list entries will hide or highlight various
122 parts of the article, making it easier to find the information you
123 want.")
124         (name . gnus-article-display-hook)
125         (type . list)
126         (calculate 
127          . (if (and (string-match "xemacs" emacs-version)
128                     (featurep 'xface))
129                '(gnus-article-hide-headers-if-wanted
130                 gnus-article-hide-boring-headers
131                 gnus-article-treat-overstrike
132                 gnus-article-maybe-highlight
133                 gnus-article-display-x-face)
134              '(gnus-article-hide-headers-if-wanted
135               gnus-article-hide-boring-headers
136               gnus-article-treat-overstrike
137               gnus-article-maybe-highlight)))
138         (data 
139          ((type . repeat)
140           (header . nil)
141           (data
142            (tag . "Filter")
143            (type . choice)
144            (data
145             ((tag . "Treat Overstrike")
146              (doc . "\
147 Convert use of overstrike into bold and underline.
148
149 Two identical letters separated by a backspace are displayed as a
150 single bold letter, while a letter followed by a backspace and an
151 underscore will be displayed as a single underlined letter.  This
152 technique was developed for old line printers (think about it), and is
153 still in use on some newsgroups, in particular the ClariNet
154 hierarchy.
155 ")
156              (type . const)
157              (default . 
158                gnus-article-treat-overstrike))
159             ((tag . "Word Wrap")
160              (doc . "\
161 Format too long lines.
162 ")
163              (type . const)
164              (default . gnus-article-word-wrap))
165             ((tag . "Remove CR")
166              (doc . "\
167 Remove carriage returns from an article.
168 ")
169              (type . const)
170              (default . gnus-article-remove-cr))
171             ((tag . "Display X-Face")
172              (doc . "\
173 Look for an X-Face header and display it if present.
174
175 See also `X Face Command' for a definition of the external command
176 used for decoding and displaying the face.
177 ")
178              (type . const)
179              (default . gnus-article-display-x-face))
180             ((tag . "Unquote Printable")
181              (doc . "\
182 Transform MIME quoted printable into 8-bit characters.
183
184 Quoted printable is often seen by strings like `=EF' where you would
185 expect a non-English letter.
186 ")
187              (type . const)
188              (default .
189                gnus-article-de-quoted-unreadable))
190             ((tag . "Universal Time")
191              (doc . "\
192 Convert date header to universal time.
193 ")
194              (type . const)
195              (default . gnus-article-date-ut))
196             ((tag . "Local Time")
197              (doc . "\
198 Convert date header to local timezone.
199 ")
200              (type . const)
201              (default . gnus-article-date-local))
202             ((tag . "Lapsed Time")
203              (doc . "\
204 Replace date header with a header showing the articles age.
205 ")
206              (type . const)
207              (default . gnus-article-date-lapsed))
208             ((tag . "Highlight")
209              (doc . "\
210 Highlight headers, citations, signature, and buttons.
211 ")
212              (type . const)
213              (default . gnus-article-highlight))
214             ((tag . "Maybe Highlight")
215              (doc . "\
216 Highlight headers, signature, and buttons if `Visual' is turned on.
217 ")
218              (type . const)
219              (default . 
220                gnus-article-maybe-highlight))
221             ((tag . "Highlight Some")
222              (doc . "\
223 Highlight headers, signature, and buttons.
224 ")
225              (type . const)
226              (default . gnus-article-highlight-some))
227             ((tag . "Highlight Headers")
228              (doc . "\
229 Highlight headers as specified by `Article Header Highlighting'.
230 ")
231              (type . const)
232              (default .
233                gnus-article-highlight-headers))
234             ((tag . "Highlight Signature")
235              (doc . "\
236 Highlight the signature as specified by `Article Signature Face'.
237 ")
238              (type . const)
239              (default .
240                gnus-article-highlight-signature))
241             ((tag . "Citation")
242              (doc . "\
243 Highlight the citations as specified by `Citation Faces'.
244 ")
245              (type . const)
246              (default . 
247                gnus-article-highlight-citation))
248             ((tag . "Hide")
249              (doc . "\
250 Hide unwanted headers, excess citation, and the signature.
251 ")
252              (type . const)
253              (default . gnus-article-hide))
254             ((tag . "Hide Headers If Wanted")
255              (doc . "\
256 Hide headers, but allow user to display them with `t' or `v'.
257 ")
258              (type . const)
259              (default . 
260                gnus-article-hide-headers-if-wanted))
261             ((tag . "Hide Headers")
262              (doc . "\
263 Hide unwanted headers and possibly sort them as well.
264 Most likely you want to use `Hide Headers If Wanted' instead.
265 ")
266              (type . const)
267              (default . gnus-article-hide-headers))
268             ((tag . "Hide Signature")
269              (doc . "\
270 Hide the signature.
271 ")
272              (type . const)
273              (default . gnus-article-hide-signature))
274             ((tag . "Hide Excess Citations")
275              (doc . "\
276 Hide excess citation.
277
278 Excess is defined by `Citation Hide Percentage' and `Citation Hide Absolute'.
279 ")
280              (type . const)
281              (default . 
282                gnus-article-hide-citation-maybe))
283             ((tag . "Hide Citations")
284              (doc . "\
285 Hide all cited text.
286 ")
287              (type . const)
288              (default . gnus-article-hide-citation))
289             ((tag . "Add Buttons")
290              (doc . "\
291 Make URL's into clickable buttons.
292 ")
293              (type . const)
294              (default . gnus-article-add-buttons))
295             ((prompt . "Other")
296              (doc . "\
297 Name of Lisp function to call.
298
299 Push the `Filter' button to select one of the predefined filters.
300 ")
301              (type . symbol)))))))
302        ((tag . "Article Button Face")
303         (doc . "\
304 Face used for highlighting buttons in the article buffer.
305
306 An article button is a piece of text that you can activate by pressing
307 `RET' or `mouse-2' above it.")
308         (name . gnus-article-button-face)
309         (default . bold)
310         (type . face))
311        ((tag . "Article Mouse Face")
312         (doc . "\
313 Face used for mouse highlighting in the article buffer.
314
315 Article buttons will be displayed in this face when the cursor is
316 above them.")
317         (name . gnus-article-mouse-face)
318         (default . highlight)
319         (type . face))
320        ((tag . "Article Signature Face")
321         (doc . "\
322 Face used for highlighting a signature in the article buffer.")
323         (name . gnus-signature-face)
324         (default . italic)
325         (type . face))
326        ((tag . "Article Header Highlighting")
327         (doc . "\
328 Controls highlighting of article header.
329
330 Below is a list of article header names, and the faces used for
331 displaying the name and content of the header.  The `Header' field
332 should contain the name of the header.  The field actually contains a
333 regular expression that should match the beginning of the header line,
334 but if you don't know what a regular expression is, just write the
335 name of the header.  The second field is the `Name' field, which
336 determines how the the header name (i.e. the part of the header left
337 of the `:') is displayed.  The third field is the `Content' field,
338 which determines how the content (i.e. the part of the header right of
339 the `:') is displayed.  
340
341 If you leave the last `Header' field in the list empty, the `Name' and
342 `Content' fields will determine how headers not listed above are
343 displayed.  
344
345 If you only want to change the display of the name part for a specific
346 header, specify `None' in the `Content' field.  Similarly, specify
347 `None' in the `Name' field if you only want to leave the name part
348 alone.")
349         (name . gnus-header-face-alist)
350         (type . list)
351         (calculate
352          . (cond 
353             ((not (eq gnus-display-type 'color))
354              '(("" bold italic)))
355             ((eq gnus-background-mode 'dark)
356              (list 
357               (list "From" nil 
358                     (custom-face-lookup "light blue" nil nil t t nil))
359               (list "Subject" nil 
360                     (custom-face-lookup "pink" nil nil t t nil))
361               (list "Newsgroups:.*," nil
362                     (custom-face-lookup "yellow" nil nil t t nil))
363               (list 
364                "" 
365                (custom-face-lookup "cyan" nil nil t nil nil)
366                (custom-face-lookup "forestgreen" nil nil nil t 
367                                    nil))))
368             (t
369              (list
370               (list "From" nil
371                     (custom-face-lookup "MidnightBlue" nil nil t t nil))
372               (list "Subject" nil 
373                     (custom-face-lookup "firebrick" nil nil t t nil))
374               (list "Newsgroups:.*," nil
375                     (custom-face-lookup "indianred" nil nil t t nil))
376               (list ""
377                     (custom-face-lookup 
378                      "DarkGreen" nil nil t nil nil)
379                     (custom-face-lookup "DarkGreen" nil nil
380                                         nil t nil))))))
381         (data
382          ((type . repeat)
383           (header . nil)
384           (data 
385            (type . list)
386            (compact . t)
387            (data
388             ((type . string)
389              (prompt . "Header")
390              (tag . "Header "))
391             "\n            "
392             ((type . face)
393              (prompt . "Name")
394              (tag . "Name   "))
395             "\n            "
396             ((type . face)
397              (tag . "Content"))
398             "\n")))))
399        ((tag . "Attribution Face")
400         (doc . "\
401 Face used for attribution lines.
402 It is merged with the face for the cited text belonging to the attribution.")
403         (name . gnus-cite-attribution-face)
404         (default . underline)
405         (type . face))
406        ((tag . "Citation Faces")
407         (doc . "\
408 List of faces used for highlighting citations. 
409
410 When there are citations from multiple articles in the same message,
411 Gnus will try to give each citation from each article its own face.
412 This should make it easier to see who wrote what.")
413         (name . gnus-cite-face-list)
414         (import . gnus-custom-import-cite-face-list)
415         (type . list)
416         (calculate . (cond ((not (eq gnus-display-type 'color))
417                             '(italic))
418                            ((eq gnus-background-mode 'dark)
419                             (mapcar 'gnus-make-face 
420                                     gnus-face-light-name-list))
421                            (t 
422                             (mapcar 'gnus-make-face 
423                                     gnus-face-dark-name-list))))
424         (data
425          ((type . repeat)
426           (header . nil)
427           (data (type . face)
428                 (tag . "Face")))))
429        ((tag . "Citation Hide Percentage")
430         (doc . "\
431 Only hide excess citation if above this percentage of the body.")
432         (name . gnus-cite-hide-percentage)
433         (default . 50)
434         (type . integer))
435        ((tag . "Citation Hide Absolute")
436         (doc . "\
437 Only hide excess citation if above this number of lines in the body.")
438         (name . gnus-cite-hide-absolute)
439         (default . 10)
440         (type . integer))
441        ((tag . "Summary Selected Face")
442         (doc . "\
443 Face used for highlighting the current article in the summary buffer.")
444         (name . gnus-summary-selected-face)
445         (default . underline)
446         (type . face))
447        ((tag . "Summary Line Highlighting")
448         (doc . "\
449 Controls the highlighting of summary buffer lines. 
450
451 Below is a list of `Form'/`Face' pairs.  When deciding how a a
452 particular summary line should be displayed, each form is
453 evaluated. The content of the face field after the first true form is
454 used.  You can change how those summary lines are displayed, by
455 editing the face field.  
456
457 It is also possible to change and add form fields, but currently that
458 requires an understanding of Lisp expressions.  Hopefully this will
459 change in a future release.  For now, you can use the following
460 variables in the Lisp expression:
461
462 score:   The article's score
463 default: The default article score.
464 below:   The score below which articles are automatically marked as read. 
465 mark:    The article's mark.")
466         (name . gnus-summary-highlight)
467         (type . list)
468         (calculate 
469          . (cond
470             ((not (eq gnus-display-type 'color))
471              '(((> score default) . bold)
472                ((< score default) . italic)))
473             ((eq gnus-background-mode 'dark)
474              (list
475               (cons 
476                '(= mark gnus-canceled-mark)
477                (custom-face-lookup "yellow" "black" nil
478                                    nil nil nil))
479               (cons '(and (> score default) 
480                           (or (= mark gnus-dormant-mark)
481                               (= mark gnus-ticked-mark)))
482                     (custom-face-lookup 
483                      "pink" nil nil t nil nil))
484               (cons '(and (< score default) 
485                           (or (= mark gnus-dormant-mark)
486                               (= mark gnus-ticked-mark)))
487                     (custom-face-lookup "pink" nil nil 
488                                         nil t nil))
489               (cons '(or (= mark gnus-dormant-mark)
490                          (= mark gnus-ticked-mark))
491                     (custom-face-lookup 
492                      "pink" nil nil nil nil nil))
493
494               (cons
495                '(and (> score default) (= mark gnus-ancient-mark))
496                (custom-face-lookup "medium blue" nil nil t
497                                    nil nil))
498               (cons 
499                '(and (< score default) (= mark gnus-ancient-mark))
500                (custom-face-lookup "SkyBlue" nil nil
501                                    nil t nil))
502               (cons 
503                '(= mark gnus-ancient-mark)
504                (custom-face-lookup "SkyBlue" nil nil
505                                    nil nil nil))
506               (cons '(and (> score default) (= mark gnus-unread-mark))
507                     (custom-face-lookup "white" nil nil t
508                                         nil nil))
509               (cons '(and (< score default) (= mark gnus-unread-mark))
510                     (custom-face-lookup "white" nil nil
511                                         nil t nil))
512               (cons '(= mark gnus-unread-mark)
513                     (custom-face-lookup
514                      "white" nil nil nil nil nil))
515
516               (cons '(> score default) 'bold)
517               (cons '(< score default) 'italic)))
518             (t
519              (list
520               (cons
521                '(= mark gnus-canceled-mark)
522                (custom-face-lookup
523                 "yellow" "black" nil nil nil nil))
524               (cons '(and (> score default) 
525                           (or (= mark gnus-dormant-mark)
526                               (= mark gnus-ticked-mark)))
527                     (custom-face-lookup "firebrick" nil nil
528                                         t nil nil))
529               (cons '(and (< score default) 
530                           (or (= mark gnus-dormant-mark)
531                               (= mark gnus-ticked-mark)))
532                     (custom-face-lookup "firebrick" nil nil
533                                         nil t nil))
534               (cons 
535                '(or (= mark gnus-dormant-mark)
536                     (= mark gnus-ticked-mark))
537                (custom-face-lookup 
538                 "firebrick" nil nil nil nil nil))
539
540               (cons '(and (> score default) (= mark gnus-ancient-mark))
541                     (custom-face-lookup "RoyalBlue" nil nil
542                                         t nil nil))
543               (cons '(and (< score default) (= mark gnus-ancient-mark))
544                     (custom-face-lookup "RoyalBlue" nil nil
545                                         nil t nil))
546               (cons 
547                '(= mark gnus-ancient-mark)
548                (custom-face-lookup
549                 "RoyalBlue" nil nil nil nil nil))
550
551               (cons '(and (> score default) (/= mark gnus-unread-mark))
552                     (custom-face-lookup "DarkGreen" nil nil
553                                         t nil nil))
554               (cons '(and (< score default) (/= mark gnus-unread-mark))
555                     (custom-face-lookup "DarkGreen" nil nil
556                                         nil t nil))
557               (cons
558                '(/= mark gnus-unread-mark)
559                (custom-face-lookup "DarkGreen" nil nil 
560                                    nil nil nil))
561
562               (cons '(> score default) 'bold)
563               (cons '(< score default) 'italic)))))
564         (data
565          ((type . repeat)
566           (header . nil)
567           (data (type . pair)
568                 (compact . t)
569                 (data ((type . sexp)
570                        (width . 60)
571                        (tag . "Form"))
572                       "\n            "
573                       ((type . face)
574                        (tag . "Face"))
575                       "\n")))))
576
577        ((tag . "Group Line Highlighting")
578         (doc . "\
579 Controls the highlighting of group buffer lines. 
580
581 Below is a list of `Form'/`Face' pairs.  When deciding how a a
582 particular group line should be displayed, each form is
583 evaluated. The content of the face field after the first true form is
584 used.  You can change how those group lines are displayed by
585 editing the face field.  
586
587 It is also possible to change and add form fields, but currently that
588 requires an understanding of Lisp expressions.  Hopefully this will
589 change in a future release.  For now, you can use the following
590 variables in the Lisp expression:
591
592 group: The name of the group.
593 unread: The number of unread articles in the group.
594 method: The select method used.
595 mailp: Whether it's a mail group or not.
596 level: The level of the group.
597 score: The score of the group.
598 ticked: The number of ticked articles.")
599         (name . gnus-group-highlight)
600         (type . list)
601         (calculate 
602          . (cond 
603             ((not (eq gnus-display-type 'color))
604              '((mailp . bold)
605                ((= unread 0) . italic)))
606             ((eq gnus-background-mode 'dark)
607              `(((and (not mailp) (eq level 1)) .
608                 ,(custom-face-lookup "PaleTurquoise" nil nil t))
609                ((and (not mailp) (eq level 2)) .
610                 ,(custom-face-lookup "turquoise" nil nil t))
611                ((and (not mailp) (eq level 3)) .
612                 ,(custom-face-lookup "MediumTurquoise" nil nil t))
613                ((and (not mailp) (>= level 4)) .
614                 ,(custom-face-lookup "DarkTurquoise" nil nil t))
615                ((and mailp (eq level 1)) .
616                 ,(custom-face-lookup "aquamarine1" nil nil t))
617                ((and mailp (eq level 2)) .
618                 ,(custom-face-lookup "aquamarine2" nil nil t))
619                ((and mailp (eq level 3)) .
620                 ,(custom-face-lookup "aquamarine3" nil nil t))
621                ((and mailp (>= level 4)) .
622                 ,(custom-face-lookup "aquamarine4" nil nil t))
623                ))
624             (t
625              `(((and (not mailp) (<= level 3)) .
626                 ,(custom-face-lookup "ForestGreen" nil nil t))
627                ((and (not mailp) (eq level 4)) .
628                 ,(custom-face-lookup "DarkGreen" nil nil t))
629                ((and (not mailp) (eq level 5)) .
630                 ,(custom-face-lookup "CadetBlue4" nil nil t))
631                ((and mailp (eq level 1)) .
632                 ,(custom-face-lookup "DeepPink3" nil nil t))
633                ((and mailp (eq level 2)) .
634                 ,(custom-face-lookup "HotPink3" nil nil t))
635                ((and mailp (eq level 3)) .
636                 ,(custom-face-lookup "dark magenta" nil nil t))
637                ((and mailp (eq level 4)) .
638                 ,(custom-face-lookup "DeepPink4" nil nil t))
639                ((and mailp (> level 4)) .
640                 ,(custom-face-lookup "DarkOrchid4" nil nil t))
641                ))))
642         (data
643          ((type . repeat)
644           (header . nil)
645           (data (type . pair)
646                 (compact . t)
647                 (data ((type . sexp)
648                        (width . 60)
649                        (tag . "Form"))
650                       "\n            "
651                       ((type . face)
652                        (tag . "Face"))
653                       "\n")))))
654
655        ;; Do not define `gnus-button-alist' before we have
656        ;; some `complexity' attribute so we can hide it from
657        ;; beginners. 
658        )))))
659
660 (defun gnus-custom-import-cite-face-list (custom alist)
661   ;; Backward compatible grokking of light and dark.
662   (cond ((eq alist 'light)
663          (setq alist (mapcar 'gnus-make-face gnus-face-light-name-list)))
664         ((eq alist 'dark)
665          (setq alist (mapcar 'gnus-make-face gnus-face-dark-name-list))))
666   (funcall (custom-super custom 'import) custom alist))
667
668 (provide 'gnus-cus)
669
670 ;;; gnus-cus.el ends here