*** empty log message ***
[gnus] / lisp / gnus-vis.el
1 ;;; gnus-vis.el --- display-oriented parts of Gnus
2 ;; Copyright (C) 1995 Free Software Foundation, Inc.
3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;;      Per Abrahamsen <abraham@iesd.auc.dk>
6 ;; Keywords: news
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
22 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 ;;; Commentary:
25
26 ;;; Code:
27
28 (require 'gnus)
29 (require gnus-easymenu)
30
31 ;;; summary highligts
32
33 (defvar gnus-summary-selected-face 'underline
34   "*Face used for highlighting the current article in the summary buffer.")
35
36 (defvar gnus-summary-highlight
37   '(((> score default) . bold)
38     ((< score default) . italic))
39   "*Alist of `(FORM . FACE)'.
40 Summary lines are highlighted with the FACE for the first FORM which
41 evaluate to a non-nil value.  
42
43 Point will be at the beginning of the line when FORM is evaluated.
44 The following can be used for convenience:
45
46 score:   (gnus-summary-article-score)
47 default: gnus-summary-default-score
48 below:   gnus-summary-mark-below
49
50 To check for marks, e.g. to underline replied articles, use
51 `gnus-summary-article-mark': 
52
53    ((= (gnus-summary-article-mark) gnus-replied-mark) . underline)")
54
55 ;;; article highlights
56
57 (defvar gnus-make-foreground t
58   "Non nil means foreground color to highlight citations.")
59
60 (defvar gnus-article-button-face 'bold
61   "Face used for text buttons.")
62
63 (defvar gnus-article-mouse-face (if (boundp 'gnus-mouse-face)
64                                     gnus-mouse-face
65                                   'highlight)
66   "Face used when the mouse is over the button.")
67
68 (defvar gnus-header-face-alist '(("" bold italic))
69   "Alist of headers and faces used for highlighting them.
70 The entries in the list has the form `(REGEXP NAME CONTENT)', where
71 REGEXP is a regeular expression matching the beginning of the header,
72 NAME is the face used for highlighting the header name and CONTENT is
73 the face used for highlighting the header content. 
74
75 The first non-nil NAME or CONTENT with a matching REGEXP in the list
76 will be used.") 
77
78 (defvar gnus-signature-face 'italic
79   "Face used for signature.")
80
81 (defvar gnus-button-alist 
82   '(("in\\( +article\\)? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)" 2 
83      (assq (count-lines (point-min) (match-end 0)) 
84            gnus-cite-attribution-alist)
85      gnus-button-message-id 3)
86     ;; This is how URLs _should_ be embedded in text...
87     ("<URL:\\([^\n\r>]*\\)>" 0 t gnus-button-url 1)
88     ;; Next regexp stolen from highlight-headers.el
89     ("\\b\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\):\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?[-a-zA-Z0-9_=?#$@~`%&*+|\\/.,]+" 0 t
90      gnus-button-url 0))
91   "Alist of regexps matching buttons in an article.
92
93 Each entry has the form (REGEXP BUTTON FORM CALLBACK PAR...), where
94 REGEXP: is the string matching text around the button,
95 BUTTON: is the number of the regexp grouping actually matching the button,
96 FORM: is a lisp expression which must eval to true for the button to
97 be added, 
98 CALLBACK: is the function to call when the user push this button, and each
99 PAR: is a number of a regexp grouping whose text will be passed to CALLBACK.
100
101 CALLBACK can also be a variable, in that case the value of that
102 variable it the real callback function.")
103
104 (defvar gnus-button-url (cond ((fboundp 'w3-fetch)
105                                'w3-fetch)
106                               ((fboundp 'highlight-headers-follow-url-netscape)
107                                'highlight-headers-follow-url-netscape)
108                               (t nil))
109   "Function to fetch URL.  
110 The function will be called with one argument, the URL to fetch.
111 Useful values of this function are:
112
113 w3-fetch: 
114    defined in the w3 emacs package by William M. Perry.
115 highlight-headers-follow-url-netscape: 
116    from `highlight-headers.el' for loading NetScape 1.1.")
117
118 \f
119
120 (eval-and-compile
121   (autoload 'nnkiboze-generate-groups "nnkiboze")
122   (autoload 'gnus-cite-parse-maybe "gnus-cite" nil t))
123
124 ;;;
125 ;;; gnus-menu
126 ;;;
127
128 ;; Newsgroup buffer
129
130 (defun gnus-group-make-menu-bar ()
131   (easy-menu-define
132    gnus-group-reading-menu
133    gnus-group-mode-map
134    ""
135    '("Group"
136      ["Read" gnus-group-read-group t]
137      ["Select" gnus-group-select-group t]
138      ["Catch up" gnus-group-catchup-current t]
139      ["Catch up all articles" gnus-group-catchup-current-all t]
140      ["Check for new articles" gnus-group-get-new-news-this-group t]
141      ["Toggle subscription" gnus-group-unsubscribe-current-group t]
142      ["Kill" gnus-group-kill-group t]
143      ["Yank" gnus-group-yank-group t]
144      ["Describe" gnus-group-describe-group t]
145      ["Fetch FAQ" gnus-group-fetch-faq t]
146      ["Edit kill file" gnus-group-edit-local-kill t]
147      ["Expire articles" gnus-group-expire-articles t]
148      ["Set group level" gnus-group-set-current-level t]
149      ))
150   
151   (easy-menu-define
152    gnus-group-group-menu
153    gnus-group-mode-map
154    ""
155    '("Groups"
156      ("Listing"
157       ["List subscribed groups" gnus-group-list-groups t]
158       ["List all groups" gnus-group-list-all-groups t]
159       ["List groups matching..." gnus-group-list-matching t]
160       ["List killed groups" gnus-group-list-killed t]
161       ["List zombie groups" gnus-group-list-zombies t]
162       ["Describe all groups" gnus-group-describe-all-groups t]
163       ["Group apropos" gnus-group-apropos t]
164       ["Group and description apropos" gnus-group-description-apropos t]
165       ["List groups matching..." gnus-group-list-matching t])
166      ("Mark"
167       ["Mark group" gnus-group-mark-group t]
168       ["Unmark group" gnus-group-unmark-group t]
169       ["Mark region" gnus-group-mark-region t])
170      ("Subscribe"
171       ["Subscribe to random group" gnus-group-unsubscribe-group t]
172       ["Kill all newsgroups in region" gnus-group-kill-region t]
173       ["Kill all zombie groups" gnus-group-kill-all-zombies t])
174      ("Foreign groups"
175       ["Make a foreign group" gnus-group-make-group t]
176       ["Edit a group entry" gnus-group-edit-group t]
177       ["Add a directory group" gnus-group-make-directory-group t]
178       ["Add the help group" gnus-group-make-help-group t]
179       ["Add the archive group" gnus-group-make-archive-group t]
180       ["Make a doc group" gnus-group-make-doc-group t]
181       ["Make a kiboze group" gnus-group-make-kiboze-group t]
182       ["Make a virtual group" gnus-group-make-empty-virtual t]
183       ["Add a group to a virtual" gnus-group-add-to-virtual t])
184      ["Read a directory as a group" gnus-group-enter-directory t]
185      ["Jump to group" gnus-group-jump-to-group t]
186      ["Best unread group" gnus-group-best-unread-group t]
187      ))
188
189   (easy-menu-define
190    gnus-group-post-menu
191    gnus-group-mode-map
192    ""
193    '("Post"
194      ["Send a mail" gnus-group-mail t]
195      ["Post an article" gnus-group-post-news t]
196      ))
197   
198   (easy-menu-define
199    gnus-group-misc-menu
200    gnus-group-mode-map
201    ""
202    '("Misc"
203      ["Send a bug report" gnus-bug t]
204      ["Check for new news" gnus-group-get-new-news t]     
205      ["Delete bogus groups" gnus-group-check-bogus-groups t]
206      ["Find new newsgroups" gnus-find-new-newsgroups t]
207      ["Restart Gnus" gnus-group-restart t]
208      ["Read init file" gnus-group-read-init-file t]
209      ["Browse foreign server" gnus-group-browse-foreign-server t]
210      ["Enter server buffer" gnus-group-enter-server-mode t]
211      ["Expire expirable articles" gnus-group-expire-all-groups t]
212      ["Generate any kiboze groups" nnkiboze-generate-groups t]
213      ["Gnus version" gnus-version t]
214      ["Save .newsrc files" gnus-group-save-newsrc t]
215      ["Suspend Gnus" gnus-group-suspend t]
216      ["Clear dribble buffer" gnus-group-clear-dribble t]
217      ["Exit from Gnus" gnus-group-exit t]
218      ["Exit without saving" gnus-group-quit t]
219      ["Edit global kill file" gnus-group-edit-global-kill t]
220      ["Sort group buffer" gnus-group-sort-groups t]
221      ))
222
223   )
224
225 ;; Server mode
226 (defun gnus-server-make-menu-bar ()
227   (easy-menu-define
228    gnus-server-menu
229    gnus-server-mode-map
230    ""
231    '("Server"
232      ["Add" gnus-server-add-server t]
233      ["Browse" gnus-server-read-server t]
234      ["List" gnus-server-list-servers t]
235      ["Kill" gnus-server-kill-server t]
236      ["Yank" gnus-server-yank-server t]
237      ["Copy" gnus-server-copy-server t]
238      ["Edit" gnus-server-edit-server t]
239      ["Exit" gnus-server-exit t]
240      )))
241
242 ;; Browse mode
243 (defun gnus-browse-make-menu-bar ()
244   (easy-menu-define
245    gnus-browse-menu
246    gnus-browse-mode-map
247    ""
248    '("Browse"
249      ["Subscribe" gnus-browse-unsubscribe-current-group t]
250      ["Read" gnus-group-read-group t]
251      ["Exit" gnus-browse-exit t]
252      )))
253
254 ;; Summary buffer
255 (defun gnus-summary-make-menu-bar ()
256
257   (easy-menu-define
258    gnus-summary-mark-menu
259    gnus-summary-mode-map
260    ""
261    '("Mark"
262      ("Read"
263       ["Mark as read" gnus-summary-mark-as-read-forward t]
264       ["Mark same subject and select" gnus-summary-kill-same-subject-and-select t]
265       ["Mark same subject" gnus-summary-kill-same-subject t]
266       ["Catchup" gnus-summary-catchup t]
267       ["Catchup all" gnus-summary-catchup-all t]
268       ["Catchup to here" gnus-summary-catchup-to-here t]
269       ["Catchup region" gnus-summary-mark-region-as-read t])
270      ("Various"
271       ["Tick" gnus-summary-tick-article-forward t]
272       ["Mark as dormant" gnus-summary-mark-as-dormant t]
273       ["Remove marks" gnus-summary-clear-mark-forward t]
274       ["Set expirable mark" gnus-summary-mark-as-expirable t]
275       ["Set bookmark" gnus-summary-set-bookmark t]
276       ["Remove bookmark" gnus-summary-remove-bookmark t])
277      ("Display"
278       ["Remove lines marked as read" gnus-summary-remove-lines-marked-as-read t]
279       ["Remove lines marked with..." gnus-summary-remove-lines-marked-with t]
280       ["Show dormant articles" gnus-summary-show-all-dormant t]
281       ["Hide dormant articles" gnus-summary-hide-all-dormant t]
282       ["Show expunged articles" gnus-summary-show-all-expunged t])
283      ("Process mark"
284       ["Set mark" gnus-summary-mark-as-processable t]
285       ["Remove mark" gnus-summary-unmark-as-processable t]
286       ["Remove all marks" gnus-summary-unmark-all-processable t]
287       ["Mark series" gnus-uu-mark-series t]
288       ["Mark region" gnus-uu-mark-region t]
289       ["Mark by regexp" gnus-uu-mark-by-regexp t]
290       ["Mark all" gnus-uu-mark-all t]
291       ["Mark sparse" gnus-uu-mark-sparse t]
292       ["Mark thread" gnus-uu-mark-thread t]
293       )
294      ))
295
296   (easy-menu-define
297    gnus-summary-move-menu
298    gnus-summary-mode-map
299    ""
300    '("Move"
301      ["Scroll article forwards" gnus-summary-next-page t]
302      ["Next unread article" gnus-summary-next-unread-article t]
303      ["Previous unread article" gnus-summary-prev-unread-article t]
304      ["Next article" gnus-summary-next-article t]
305      ["Previous article" gnus-summary-prev-article t]
306      ["Next article same subject" gnus-summary-next-same-subject t]
307      ["Previous article same subject" gnus-summary-prev-same-subject t]
308      ["First unread article" gnus-summary-first-unread-article t]
309      ["Go to subject number..." gnus-summary-goto-subject t]
310      ["Go to the last article" gnus-summary-goto-last-article t]
311      ["Pop article off history" gnus-summary-pop-article t]
312      ))
313
314   (easy-menu-define
315    gnus-summary-article-menu
316    gnus-summary-mode-map
317    ""
318    '("Article"
319      ("Hide"
320       ("Date"
321        ["Local" gnus-article-date-local t]
322        ["UT" gnus-article-date-local t]
323        ["Lapsed" gnus-article-date-local t])
324       ["Headers" gnus-article-hide-headers t]
325       ["Signature" gnus-article-hide-signature t]
326       ["Citation" gnus-article-hide-citation t]
327       ["Overstrike" gnus-article-treat-overstrike t]
328       ["Word wrap" gnus-article-word-wrap t]
329       ["CR" gnus-article-remove-cr t]
330       ["Show X-Face" gnus-article-display-x-face t]
331       ["Quoted-Printable" gnus-article-de-quoted-unreadable t])
332      ("Extract"
333       ["Uudecode" gnus-uu-decode-uu t]
334       ["Uudecode and save" gnus-uu-decode-uu-and-save t]
335       ["Unshar" gnus-uu-decode-unshar t]
336       ["Unshar and save" gnus-uu-decode-unshar-and-save t]
337       ["Save" gnus-uu-decode-save t]
338       ["Binhex" gnus-uu-decode-binhex t])
339      ["Enter digest buffer" gnus-summary-enter-digest-group t]
340      ["Isearch article" gnus-summary-isearch-article t]
341      ["Search all articles" gnus-summary-search-article-forward t]
342      ["Beginning of the article" gnus-summary-beginning-of-article t]
343      ["End of the article" gnus-summary-end-of-article t]
344      ["Fetch parent of article" gnus-summary-refer-parent-article t]
345      ["Fetch article with id..." gnus-summary-refer-article t]
346      ["Stop page breaking" gnus-summary-stop-page-breaking t]
347      ["Caesar rotate" gnus-summary-caesar-message t]
348      ["Redisplay" gnus-summary-show-article t]
349      ["Toggle header" gnus-summary-toggle-header t]
350      ["Toggle MIME" gnus-summary-toggle-mime t]
351      ["Save" gnus-summary-save-article t]
352      ["Save in mail format" gnus-summary-save-article-mail t]
353      ["Pipe through a filter" gnus-summary-pipe-output t]
354      ("Mail articles"
355       ["Respool article" gnus-summary-respool-article t]
356       ["Move article" gnus-summary-move-article t]
357       ["Copy article" gnus-summary-copy-article t]
358       ["Import file" gnus-summary-import-article t]
359       ["Edit article" gnus-summary-edit-article t]
360       ["Delete article" gnus-summary-delete-article t])
361      ))
362
363   (easy-menu-define
364    gnus-summary-thread-menu
365    gnus-summary-mode-map
366    ""
367    '("Threads"
368      ["Toggle threading" gnus-summary-toggle-threads t]
369      ["Display hidden thread" gnus-summary-show-thread t]
370      ["Hide thread" gnus-summary-hide-thread t]
371      ["Go to next thread" gnus-summary-next-thread t]
372      ["Go to previous thread" gnus-summary-prev-thread t]
373      ["Go down thread" gnus-summary-down-thread t]
374      ["Go up thread" gnus-summary-up-thread t]
375      ["Mark thread as read" gnus-summary-kill-thread t]
376      ["Lower thread score" gnus-summary-lower-thread t]
377      ["Raise thread score" gnus-summary-raise-thread t]
378      ))
379
380   (easy-menu-define
381    gnus-summary-misc-menu
382    gnus-summary-mode-map
383    ""
384    '("Misc"
385      ("Sort"
386       ["Sort by number" gnus-summary-sort-by-number t]
387       ["Sort by author" gnus-summary-sort-by-author t]
388       ["Sort by subject" gnus-summary-sort-by-subject t]
389       ["Sort by date" gnus-summary-sort-by-date t]
390       ["Sort by score" gnus-summary-sort-by-score t])
391      ("Exit"
392       ["Catchup and exit" gnus-summary-catchup-and-exit t]
393       ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
394       ["Exit group" gnus-summary-exit t]
395       ["Exit group without updating" gnus-summary-exit-no-update t]
396       ["Reselect group" gnus-summary-reselect-current-group t]
397       ["Rescan group" gnus-summary-rescan-group t])
398      ["Fetch group FAQ" gnus-summary-fetch-faq t]
399      ["Filter articles" gnus-summary-execute-command t]
400      ["Toggle line truncation" gnus-summary-toggle-truncation t]
401      ["Expire expirable articles" gnus-summary-expire-articles t]
402      ["Describe group" gnus-summary-describe-group t]
403      ["Edit local kill file" gnus-summary-edit-local-kill t]
404      ))
405
406   (easy-menu-define
407    gnus-summary-post-menu
408    gnus-summary-mode-map
409    ""
410    '("Post"
411      ["Post an article" gnus-summary-post-news t]
412      ["Followup" gnus-summary-followup t]
413      ["Followup and yank" gnus-summary-followup-with-original t]
414      ["Supersede article" gnus-summary-supersede-article t]
415      ["Cancel article" gnus-summary-cancel-article t]
416      ["Reply" gnus-summary-reply t]
417      ["Reply and yank" gnus-summary-reply-with-original t]
418      ["Mail forward" gnus-summary-mail-forward t]
419      ["Post forward" gnus-summary-post-forward t]
420      ["Digest and mail" gnus-uu-digest-mail-forward t]
421      ["Digest and post" gnus-uu-digest-post-forward t]
422      ["Send a mail" gnus-summary-mail-other-window t]
423      ["Reply & followup" gnus-summary-followup-and-reply t]
424      ["Reply & followup and yank" gnus-summary-followup-and-reply-with-original t]
425      ["Uuencode and post" gnus-uu-post-news t]
426      ))
427
428   (easy-menu-define
429    gnus-summary-kill-menu
430    gnus-summary-mode-map
431    ""
432    '("Score"
433      ["Enter score" gnus-summary-score-entry t]
434      ["Raise score" gnus-summary-increase-score t]
435      ["Lower score" gnus-summary-lower-score t]
436      ["Current score" gnus-summary-current-score t]
437      ["Set score" gnus-summary-set-score t]
438      ("Score file"
439       ["Customize score file" gnus-score-customize t]
440       ["Switch current score file" gnus-score-change-score-file t]
441       ["Set mark below" gnus-score-set-mark-below t]
442       ["Set expunge below" gnus-score-set-expunge-below t]
443       ["Edit current score file" gnus-score-edit-alist t]
444       ["Edit score file" gnus-score-edit-file t]
445       ["Trace score" gnus-score-find-trace t])
446      ))
447   )
448  
449 ;; Article buffer
450 (defun gnus-article-make-menu-bar ()
451
452  (easy-menu-define
453    gnus-article-article-menu
454    gnus-article-mode-map
455    ""
456    '("Article"
457      ["Scroll forwards" gnus-article-next-page t]
458      ["Scroll backwards" gnus-article-prev-page t]
459      ["Show summary" gnus-article-show-summary t]
460      ["Fetch Message-ID at point" gnus-article-refer-article t]
461      ["Mail to address at point" gnus-article-mail t]
462      ["Mail to address at point and include original"
463       gnus-article-mail-with-original t]
464      ))
465
466  (easy-menu-define
467    gnus-article-treatment-menu
468    gnus-article-mode-map
469    ""
470    '("Treatment"
471      ["Hide headers" gnus-article-hide-headers t]
472      ["Hide signature" gnus-article-hide-signature t]
473      ["Hide citation" gnus-article-hide-citation t]
474      ["Treat overstrike" gnus-article-treat-overstrike t]
475      ["Remove carriage return" gnus-article-remove-cr t]
476      ["Remove quoted-unreadble" gnus-article-de-quoted-unreadable t]
477      ))
478  )
479
480 ;;;
481 ;;; summary highlights
482 ;;;
483
484 (defun gnus-highlight-selected-summary ()
485   ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
486   ;; Highlight selected article in summary buffer
487   (if gnus-summary-selected-face
488       (save-excursion
489         (let* ((beg (progn (beginning-of-line) (point)))
490                (end (progn (end-of-line) (point)))
491                ;; Fix by Mike Dugan <dugan@bucrf16.bu.edu>.
492                (from (if (get-text-property beg 'mouse-face) 
493                          beg
494                        (1+ (or (next-single-property-change 
495                                 beg 'mouse-face nil end) 
496                                beg))))
497                (to (1- (or (next-single-property-change
498                             from 'mouse-face nil end)
499                            end))))
500           ;; If no mouse-face prop on line (e.g. xemacs) we 
501           ;; will have to = from = end, so we highlight the
502           ;; entire line instead.
503           (if (= to from)
504               (progn
505                 (setq from beg)
506                 (setq to end)))
507           (if gnus-newsgroup-selected-overlay
508               (move-overlay gnus-newsgroup-selected-overlay 
509                             from to (current-buffer))
510             (setq gnus-newsgroup-selected-overlay (make-overlay from to))
511             (overlay-put gnus-newsgroup-selected-overlay 'face 
512                          gnus-summary-selected-face))))))
513
514
515 ;; New implementation by Christian Limpach <Christian.Limpach@nice.ch>.
516 (defun gnus-summary-highlight-line ()
517   "Highlight current line according to `gnus-summary-highlight'."
518   (let* ((list gnus-summary-highlight)
519          (p (point))
520          (end (progn (end-of-line) (point)))
521          ;; now find out where the line starts and leave point there.
522          (beg (progn (beginning-of-line) (point)))
523          (score (or (cdr (assq (or (get-text-property beg 'gnus-number)
524                                    gnus-current-article)
525                                gnus-newsgroup-scored))
526                     gnus-summary-default-score 0))
527          (default gnus-summary-default-score)
528          (mark (get-text-property beg 'gnus-mark))
529          (inhibit-read-only t))
530     (while (and list (not (eval (car (car list)))))
531       (setq list (cdr list)))
532     (let ((face (and list (cdr (car list)))))
533       ;; BUG! For some reason the text properties of the first
534       ;; characters get mangled.
535       (or (eobp)
536           (eq face (get-text-property beg 'face))
537           (put-text-property beg end 'face face)))
538     (goto-char p)))
539
540 ;;;
541 ;;; gnus-carpal
542 ;;;
543
544 (defvar gnus-carpal-group-buffer-buttons
545   '(("next" . gnus-group-next-unread-group)
546     ("prev" . gnus-group-prev-unread-group)
547     ("read" . gnus-group-read-group)
548     ("select" . gnus-group-select-group)
549     ("catch up" . gnus-group-catchup-current)
550     ("new news" . gnus-group-get-new-news-this-group)
551     ("toggle sub" . gnus-group-unsubscribe-current-group)
552     ("subscribe" . gnus-group-unsubscribe-group)
553     ("kill" . gnus-group-kill-group)
554     ("yank" . gnus-group-yank-group)
555     ("describe" . gnus-group-describe-group)
556     "list"
557     ("subscribed" . gnus-group-list-groups)
558     ("all" . gnus-group-list-all-groups)
559     ("killed" . gnus-group-list-killed)
560     ("zombies" . gnus-group-list-zombies)
561     ("matching" . gnus-group-list-matching)
562     ("post" . gnus-group-post-news)
563     ("mail" . gnus-group-mail)
564     ("new news" . gnus-group-get-new-news)
565     ("browse foreign" . gnus-group-browse-foreign)
566     ("exit" . gnus-group-exit)))
567
568 (defvar gnus-carpal-summary-buffer-buttons
569   '("mark" 
570     ("read" . gnus-summary-mark-as-read-forward)
571     ("tick" . gnus-summary-tick-article-forward)
572     ("clear" . gnus-summary-clear-mark-forward)
573     ("expirable" . gnus-summary-mark-as-expirable)
574     "move"
575     ("scroll" . gnus-summary-next-page)
576     ("next unread" . gnus-summary-next-unread-article)
577     ("prev unread" . gnus-summary-prev-unread-article)
578     ("first" . gnus-summary-first-unread-article)
579     ("best" . gnus-summary-best-unread-article)
580     "article"
581     ("headers" . gnus-summary-toggle-header)
582     ("uudecode" . gnus-uu-decode-uu)
583     ("enter digest" . gnus-summary-enter-digest-group)
584     ("fetch parent" . gnus-summary-refer-parent-article)
585     "mail"
586     ("move" . gnus-summary-move-article)
587     ("copy" . gnus-summary-copy-article)
588     ("respool" . gnus-summary-respool-article)
589     "threads"
590     ("lower" . gnus-summary-lower-thread)
591     ("kill" . gnus-summary-kill-thread)
592     "post"
593     ("post" . gnus-summary-post-news)
594     ("mail" . gnus-summary-mail)
595     ("followup" . gnus-summary-followup-with-original)
596     ("reply" . gnus-summary-reply-with-original)
597     ("cancel" . gnus-summary-cancel-article)
598     "misc"
599     ("exit" . gnus-summary-exit)
600     ("fed up" . gnus-summary-catchup-and-goto-next-group)))
601
602 (defvar gnus-carpal-server-buffer-buttons 
603   '(("add" . gnus-server-add-server)
604     ("browse" . gnus-server-browse-server)
605     ("list" . gnus-server-list-servers)
606     ("kill" . gnus-server-kill-server)
607     ("yank" . gnus-server-yank-server)
608     ("copy" . gnus-server-copy-server)
609     ("exit" . gnus-server-exit)))
610
611 (defvar gnus-carpal-browse-buffer-buttons
612   '(("subscribe" . gnus-browse-unsubscribe-current-group)
613     ("exit" . gnus-browse-exit)))
614
615 (defvar gnus-carpal-group-buffer "*Carpal Group*")
616 (defvar gnus-carpal-summary-buffer "*Carpal Summary*")
617 (defvar gnus-carpal-server-buffer "*Carpal Server*")
618 (defvar gnus-carpal-browse-buffer "*Carpal Browse*")
619
620 (defvar gnus-carpal-attached-buffer nil)
621
622 (defvar gnus-carpal-mode-hook nil
623   "*Hook run in carpal mode buffers.")
624
625 (defvar gnus-carpal-button-face 'bold
626   "*Face used on carpal buttons.")
627
628 (defvar gnus-carpal-header-face 'bold-italic
629   "*Face used on carpal buffer headers.")
630
631 (defvar gnus-carpal-mode-map nil)
632 (put 'gnus-carpal-mode 'mode-class 'special)
633
634 (if gnus-carpal-mode-map
635     nil
636   (setq gnus-carpal-mode-map (make-keymap))
637   (suppress-keymap gnus-carpal-mode-map)
638   (define-key gnus-carpal-mode-map " " 'gnus-carpal-select)
639   (define-key gnus-carpal-mode-map "\r" 'gnus-carpal-select)
640   (define-key gnus-carpal-mode-map gnus-mouse-2 'gnus-carpal-mouse-select))
641
642 (defun gnus-carpal-mode ()
643   "Major mode clicking buttons.
644
645 All normal editing commands are switched off.
646 \\<gnus-carpal-mode-map>
647 The following commands are available:
648
649 \\{gnus-carpal-mode-map}"
650   (interactive)
651   (kill-all-local-variables)
652   (setq mode-line-modified "-- ")
653   (setq major-mode 'gnus-carpal-mode)
654   (setq mode-name "Gnus Carpal")
655   (setq mode-line-process nil)
656   (use-local-map gnus-carpal-mode-map)
657   (buffer-disable-undo (current-buffer))
658   (setq buffer-read-only t)
659   (make-local-variable 'gnus-carpal-attached-buffer)
660   (run-hooks 'gnus-carpal-mode-hook))
661
662 (defun gnus-carpal-setup-buffer (type)
663   (let ((buffer (symbol-value (intern (format "gnus-carpal-%s-buffer" type)))))
664     (if (get-buffer buffer)
665         ()
666       (save-excursion
667         (set-buffer (get-buffer-create buffer))
668         (gnus-carpal-mode)
669         (setq gnus-carpal-attached-buffer 
670               (intern (format "gnus-%s-buffer" type)))
671         (gnus-add-current-to-buffer-list)
672         (let ((buttons (symbol-value 
673                         (intern (format "gnus-carpal-%s-buffer-buttons"
674                                         type))))
675               (buffer-read-only nil)
676               button)
677           (while buttons
678             (setq button (car buttons)
679                   buttons (cdr buttons))
680             (if (stringp button)
681                 (set-text-properties
682                  (point)
683                  (prog2 (insert button) (point) (insert " "))
684                  (list 'face gnus-carpal-header-face))
685               (set-text-properties
686                (point)
687                (prog2 (insert (car button)) (point) (insert " "))
688                (list 'gnus-callback (cdr button)
689                      'face gnus-carpal-button-face
690                      'mouse-face 'highlight))))
691           (let ((fill-column (- (window-width) 2)))
692             (fill-region (point-min) (point-max)))
693           (set-window-point (get-buffer-window (current-buffer)) 
694                             (point-min)))))))
695
696 (defun gnus-carpal-select ()
697   "Select the button under point."
698   (interactive)
699   (let ((func (get-text-property (point) 'gnus-callback)))
700     (if (null func)
701         ()
702       (pop-to-buffer (symbol-value gnus-carpal-attached-buffer))
703       (call-interactively func))))
704
705 (defun gnus-carpal-mouse-select (event)
706   "Select the button under the mouse pointer."
707   (interactive "e")
708   (mouse-set-point event)
709   (gnus-carpal-select))
710
711 ;;; 
712 ;;; article highlights
713 ;;;
714
715 ;; Written by Per Abrahamsen <abraham@iesd.auc.dk>.
716
717 ;;; Internal Variables:
718
719 (defvar gnus-button-regexp nil)
720 ;; Regexp matching any of the regexps from `gnus-button-alist'.
721
722 (defvar gnus-button-last nil)
723 ;; The value of `gnus-button-alist' when `gnus-button-regexp' was build.
724
725 ;;; Commands:
726
727 (defun gnus-article-push-button (event)
728   "Check text under the mouse pointer for a callback function.
729 If the text under the mouse pointer has a `gnus-callback' property,
730 call it with the value of the `gnus-data' text property."
731   (interactive "e")
732   (set-buffer (window-buffer (posn-window (event-start event))))
733   (let* ((pos (posn-point (event-start event)))
734          (data (get-text-property pos 'gnus-data))
735          (fun (get-text-property pos 'gnus-callback)))
736       (if fun (funcall fun data))))
737
738 (defun gnus-article-press-button ()
739   "Check text at point for a callback function.
740 If the text at point has a `gnus-callback' property,
741 call it with the value of the `gnus-data' text property."
742   (interactive)
743   (let* ((data (get-text-property (point) 'gnus-data))
744          (fun (get-text-property (point) 'gnus-callback)))
745       (if fun (funcall fun data))))
746
747 ;; Suggested by Arne Elofsson <arne@hodgkin.mbi.ucla.edu>
748 (defun gnus-article-next-button ()
749   "Move point to next button."
750   (interactive)
751   (if (get-text-property (point) 'gnus-callback)
752       (goto-char (next-single-property-change (point) 'gnus-callback
753                                        nil (point-max))))
754   (let ((pos (next-single-property-change (point) 'gnus-callback)))
755     (if pos
756         (goto-char pos)
757       (setq pos (next-single-property-change (point-min) 'gnus-callback))
758       (if pos
759           (goto-char pos)
760         (error "No buttons found")))))
761
762 (defun gnus-article-highlight ()
763   "Highlight current article.
764 This function calls `gnus-article-highlight-headers',
765 `gnus-article-highlight-citation', 
766 `gnus-article-highlight-signature', and `gnus-article-add-buttons' to
767 do the highlighting.  See the documentation for those functions."
768   (interactive)
769   (gnus-article-highlight-headers)
770   (gnus-article-highlight-citation)
771   (gnus-article-highlight-signature)
772   (gnus-article-add-buttons))
773
774 (defun gnus-article-hide ()
775   "Hide current article.
776 This function calls `gnus-article-hide-headers',
777 `gnus-article-hide-citation-maybe', and `gnus-article-hide-signature'
778 to do the hiding.  See the documentation for those functions." 
779   (interactive)
780   (gnus-article-hide-headers)
781   (gnus-article-hide-citation-maybe)
782   (gnus-article-hide-signature))
783
784 (defun gnus-article-highlight-headers ()
785   "Highlight article headers as specified by `gnus-header-face-alist'."
786   (interactive)
787   (save-excursion
788     (set-buffer gnus-article-buffer)
789     (goto-char (point-min))
790     (search-forward "\n\n")
791     (beginning-of-line 0)
792     (while (not (bobp))
793       (let ((alist gnus-header-face-alist)
794             (buffer-read-only nil)
795             (case-fold-search t)
796             (end (point))
797             (inhibit-point-motion-hooks t)
798             begin entry regexp header-face field-face header-found field-found)
799         (re-search-backward "^[^ \t]" nil t)
800         (setq begin (point))
801         (while alist
802           (setq entry (car alist)
803                 regexp (nth 0 entry)
804                 header-face (nth 1 entry)
805                 field-face (nth 2 entry)
806                 alist (cdr alist))
807           (if (looking-at regexp)
808               (let ((from (point)))
809                 (skip-chars-forward "^:\n")
810                 (and (not header-found)
811                      header-face
812                      (progn
813                        (put-text-property  from (point) 'face header-face)
814                        (setq header-found t)))
815                 (and (not field-found)
816                      field-face
817                      (progn 
818                        (skip-chars-forward ": \t")
819                        (let ((from (point)))
820                          (goto-char end)
821                          (skip-chars-backward " \t")
822                          (put-text-property from (point) 'face field-face)
823                          (setq field-found t))))))
824           (goto-char begin))))))
825
826 (defun gnus-article-highlight-signature ()
827   "Highlight the signature in an article.
828 It does this by highlighting everything after
829 `gnus-signature-separator' using `gnus-signature-face'." 
830   (interactive)
831   (save-excursion
832     (set-buffer gnus-article-buffer)
833     (let ((buffer-read-only nil)
834           (inhibit-point-motion-hooks t))
835       (goto-char (point-max))
836       (and (re-search-backward gnus-signature-separator nil t)
837            gnus-signature-face
838            (let ((start (match-beginning 0))
839                  (end (match-end 0)))
840              (gnus-article-add-button start end 'gnus-signature-toggle end)
841              (overlay-put (make-overlay end (point-max))
842                           'face gnus-signature-face))))))
843
844 (defun gnus-article-hide-signature ()
845   "Hide the signature in an article.
846 It does this by making everything after `gnus-signature-separator' invisible."
847   (interactive)
848   (save-excursion
849     (set-buffer gnus-article-buffer)
850     (let ((buffer-read-only nil))
851       (goto-char (point-max))
852       (and (re-search-backward gnus-signature-separator nil t)
853            gnus-signature-face
854            (add-text-properties (match-end 0) (point-max)
855                                 gnus-hidden-properties)))))
856
857 (defun gnus-article-add-buttons ()
858   "Find external references in article and make them to buttons.
859
860 External references are things like message-ids and URLs, as specified by 
861 `gnus-button-alist'."
862   (interactive)
863   (if (eq gnus-button-last gnus-button-alist)
864       ()
865     (setq gnus-button-regexp (mapconcat 'car gnus-button-alist  "\\|")
866           gnus-button-last gnus-button-alist))
867   (save-excursion
868     (set-buffer gnus-article-buffer)
869     (gnus-cite-parse-maybe)
870     (let ((buffer-read-only nil)
871           (inhibit-point-motion-hooks t)
872           (case-fold-search t))
873       (goto-char (point-min))
874       (search-forward "\n\n")
875       (while (re-search-forward gnus-button-regexp nil t)
876         (goto-char (match-beginning 0))
877         (let* ((from (point))
878                (entry (gnus-button-entry))
879                (start (and entry (match-beginning (nth 1 entry))))
880                (end (and entry (match-end (nth 1 entry))))
881                (form (nth 2 entry))
882                marker)
883           (if (not entry)
884               ()
885             (goto-char (match-end 0))
886             (if (eval form)
887                 (gnus-article-add-button start end 'gnus-button-push
888                                          (set-marker (make-marker)
889                                                      from)))))))))
890
891 ;;; External functions:
892
893 (defun gnus-article-add-button (from to fun &optional data)
894   "Create a button between FROM and TO with callback FUN and data DATA."
895   (add-text-properties from to
896                        (append (if gnus-article-button-face
897                                    (list 'face gnus-article-button-face))
898                                (if gnus-article-mouse-face
899                                    (list 'mouse-face gnus-article-mouse-face))
900                                (list 'gnus-callback fun)
901                                (if data (list 'gnus-data data)))))
902
903 ;;; Internal functions:
904
905 (defun gnus-signature-toggle (end)
906   (save-excursion
907     (set-buffer gnus-article-buffer)
908     (let ((buffer-read-only nil))
909       (if (get-text-property end 'invisible)
910           (remove-text-properties end (point-max) gnus-hidden-properties)
911         (add-text-properties end (point-max) gnus-hidden-properties)))))
912
913 (defun gnus-make-face (color)
914   ;; Create entry for face with background COLOR.
915   (let ((name (intern (concat "gnus " color))))
916     (make-face name)
917     (if gnus-make-foreground
918         (set-face-foreground name color)
919       (set-face-background name color))
920     name))
921
922 (defun gnus-button-entry ()
923   ;; Return the first entry in `gnus-button-alist' matching this place.
924   (let ((alist gnus-button-alist)
925         (entry nil))
926     (while alist
927       (setq entry (car alist)
928             alist (cdr alist))
929       (if (looking-at (car entry))
930           (setq alist nil)
931         (setq entry nil)))
932     entry))
933
934 (defun gnus-button-push (marker)
935   ;; Push button starting at MARKER.
936   (save-excursion
937     (set-buffer gnus-article-buffer)
938     (goto-char marker)
939     (let* ((entry (gnus-button-entry))
940            (inhibit-point-motion-hooks t)
941            (fun (nth 3 entry))
942            (args (mapcar (lambda (group) 
943                            (let ((string (buffer-substring
944                                           (match-beginning group)
945                                           (match-end group))))
946                            (set-text-properties 0 (length string) nil string)
947                            string))
948                          (nthcdr 4 entry))))
949       (cond ((fboundp fun)
950              (apply fun args))
951             ((and (boundp fun)
952                   (fboundp (symbol-value fun)))
953              (apply (symbol-value fun) args))
954             (t
955              (message "You must define `%S' to use this button"
956                       (cons fun args)))))))
957
958 (defun gnus-button-message-id (message-id)
959   ;; Push on MESSAGE-ID.
960   (save-excursion
961     (set-buffer gnus-summary-buffer)
962     (gnus-summary-refer-article message-id)))
963
964 ;;; Compatibility Functions:
965
966 (or (fboundp 'rassoc)
967     ;; Introduced in Emacs 19.29.
968     (defun rassoc (elt list)
969       "Return non-nil if ELT is `equal' to the cdr of an element of LIST.
970 The value is actually the element of LIST whose cdr is ELT."
971       (let (result)
972         (while list
973           (setq result (car list))
974           (if (equal (cdr result) elt)
975               (setq list nil)
976             (setq result nil
977                   list (cdr list))))
978         result)))
979
980 (provide 'gnus-vis)
981
982 ;;; gnus-vis.el ends here