*** 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 ;; New implementation by Christian Limpach <Christian.Limpach@nice.ch>.
515 (defun gnus-summary-highlight-line ()
516   "Highlight current line according to `gnus-summary-highlight'."
517   (let* ((list gnus-summary-highlight)
518          (p (point))
519          (end (progn (end-of-line) (point)))
520          ;; now find out where the line starts and leave point there.
521          (beg (progn (beginning-of-line) (point)))
522          (score (or (cdr (assq (or (get-text-property beg 'gnus-number)
523                                    gnus-current-article)
524                                gnus-newsgroup-scored))
525                     gnus-summary-default-score 0))
526          (default gnus-summary-default-score)
527          (mark (get-text-property beg 'gnus-mark))
528          (inhibit-read-only t))
529     (while (and list (not (eval (car (car list)))))
530       (setq list (cdr list)))
531     (let ((face (and list (cdr (car list)))))
532       ;; BUG! For some reason the text properties of the first
533       ;; characters get mangled.
534       (or (eobp)
535           (eq face (get-text-property beg 'face))
536           (put-text-property beg end 'face face)))
537     (goto-char p)))
538
539 ;;;
540 ;;; gnus-carpal
541 ;;;
542
543 (defvar gnus-carpal-group-buffer-buttons
544   '(("next" . gnus-group-next-unread-group)
545     ("prev" . gnus-group-prev-unread-group)
546     ("read" . gnus-group-read-group)
547     ("select" . gnus-group-select-group)
548     ("catch up" . gnus-group-catchup-current)
549     ("new news" . gnus-group-get-new-news-this-group)
550     ("toggle sub" . gnus-group-unsubscribe-current-group)
551     ("subscribe" . gnus-group-unsubscribe-group)
552     ("kill" . gnus-group-kill-group)
553     ("yank" . gnus-group-yank-group)
554     ("describe" . gnus-group-describe-group)
555     "list"
556     ("subscribed" . gnus-group-list-groups)
557     ("all" . gnus-group-list-all-groups)
558     ("killed" . gnus-group-list-killed)
559     ("zombies" . gnus-group-list-zombies)
560     ("matching" . gnus-group-list-matching)
561     ("post" . gnus-group-post-news)
562     ("mail" . gnus-group-mail)
563     ("new news" . gnus-group-get-new-news)
564     ("browse foreign" . gnus-group-browse-foreign)
565     ("exit" . gnus-group-exit)))
566
567 (defvar gnus-carpal-summary-buffer-buttons
568   '("mark" 
569     ("read" . gnus-summary-mark-as-read-forward)
570     ("tick" . gnus-summary-tick-article-forward)
571     ("clear" . gnus-summary-clear-mark-forward)
572     ("expirable" . gnus-summary-mark-as-expirable)
573     "move"
574     ("scroll" . gnus-summary-next-page)
575     ("next unread" . gnus-summary-next-unread-article)
576     ("prev unread" . gnus-summary-prev-unread-article)
577     ("first" . gnus-summary-first-unread-article)
578     ("best" . gnus-summary-best-unread-article)
579     "article"
580     ("headers" . gnus-summary-toggle-header)
581     ("uudecode" . gnus-uu-decode-uu)
582     ("enter digest" . gnus-summary-enter-digest-group)
583     ("fetch parent" . gnus-summary-refer-parent-article)
584     "mail"
585     ("move" . gnus-summary-move-article)
586     ("copy" . gnus-summary-copy-article)
587     ("respool" . gnus-summary-respool-article)
588     "threads"
589     ("lower" . gnus-summary-lower-thread)
590     ("kill" . gnus-summary-kill-thread)
591     "post"
592     ("post" . gnus-summary-post-news)
593     ("mail" . gnus-summary-mail)
594     ("followup" . gnus-summary-followup-with-original)
595     ("reply" . gnus-summary-reply-with-original)
596     ("cancel" . gnus-summary-cancel-article)
597     "misc"
598     ("exit" . gnus-summary-exit)
599     ("fed up" . gnus-summary-catchup-and-goto-next-group)))
600
601 (defvar gnus-carpal-server-buffer-buttons 
602   '(("add" . gnus-server-add-server)
603     ("browse" . gnus-server-browse-server)
604     ("list" . gnus-server-list-servers)
605     ("kill" . gnus-server-kill-server)
606     ("yank" . gnus-server-yank-server)
607     ("copy" . gnus-server-copy-server)
608     ("exit" . gnus-server-exit)))
609
610 (defvar gnus-carpal-browse-buffer-buttons
611   '(("subscribe" . gnus-browse-unsubscribe-current-group)
612     ("exit" . gnus-browse-exit)))
613
614 (defvar gnus-carpal-group-buffer "*Carpal Group*")
615 (defvar gnus-carpal-summary-buffer "*Carpal Summary*")
616 (defvar gnus-carpal-server-buffer "*Carpal Server*")
617 (defvar gnus-carpal-browse-buffer "*Carpal Browse*")
618
619 (defvar gnus-carpal-attached-buffer nil)
620
621 (defvar gnus-carpal-mode-hook nil
622   "*Hook run in carpal mode buffers.")
623
624 (defvar gnus-carpal-button-face 'bold
625   "*Face used on carpal buttons.")
626
627 (defvar gnus-carpal-header-face 'bold-italic
628   "*Face used on carpal buffer headers.")
629
630 (defvar gnus-carpal-mode-map nil)
631 (put 'gnus-carpal-mode 'mode-class 'special)
632
633 (if gnus-carpal-mode-map
634     nil
635   (setq gnus-carpal-mode-map (make-keymap))
636   (suppress-keymap gnus-carpal-mode-map)
637   (define-key gnus-carpal-mode-map " " 'gnus-carpal-select)
638   (define-key gnus-carpal-mode-map "\r" 'gnus-carpal-select)
639   (define-key gnus-carpal-mode-map gnus-mouse-2 'gnus-carpal-mouse-select))
640
641 (defun gnus-carpal-mode ()
642   "Major mode clicking buttons.
643
644 All normal editing commands are switched off.
645 \\<gnus-carpal-mode-map>
646 The following commands are available:
647
648 \\{gnus-carpal-mode-map}"
649   (interactive)
650   (kill-all-local-variables)
651   (setq mode-line-modified "-- ")
652   (setq major-mode 'gnus-carpal-mode)
653   (setq mode-name "Gnus Carpal")
654   (setq mode-line-process nil)
655   (use-local-map gnus-carpal-mode-map)
656   (buffer-disable-undo (current-buffer))
657   (setq buffer-read-only t)
658   (make-local-variable 'gnus-carpal-attached-buffer)
659   (run-hooks 'gnus-carpal-mode-hook))
660
661 (defun gnus-carpal-setup-buffer (type)
662   (let ((buffer (symbol-value (intern (format "gnus-carpal-%s-buffer" type)))))
663     (if (get-buffer buffer)
664         ()
665       (save-excursion
666         (set-buffer (get-buffer-create buffer))
667         (gnus-carpal-mode)
668         (setq gnus-carpal-attached-buffer 
669               (intern (format "gnus-%s-buffer" type)))
670         (gnus-add-current-to-buffer-list)
671         (let ((buttons (symbol-value 
672                         (intern (format "gnus-carpal-%s-buffer-buttons"
673                                         type))))
674               (buffer-read-only nil)
675               button)
676           (while buttons
677             (setq button (car buttons)
678                   buttons (cdr buttons))
679             (if (stringp button)
680                 (set-text-properties
681                  (point)
682                  (prog2 (insert button) (point) (insert " "))
683                  (list 'face gnus-carpal-header-face))
684               (set-text-properties
685                (point)
686                (prog2 (insert (car button)) (point) (insert " "))
687                (list 'gnus-callback (cdr button)
688                      'face gnus-carpal-button-face
689                      'mouse-face 'highlight))))
690           (let ((fill-column (- (window-width) 2)))
691             (fill-region (point-min) (point-max)))
692           (set-window-point (get-buffer-window (current-buffer)) 
693                             (point-min)))))))
694
695 (defun gnus-carpal-select ()
696   "Select the button under point."
697   (interactive)
698   (let ((func (get-text-property (point) 'gnus-callback)))
699     (if (null func)
700         ()
701       (pop-to-buffer (symbol-value gnus-carpal-attached-buffer))
702       (call-interactively func))))
703
704 (defun gnus-carpal-mouse-select (event)
705   "Select the button under the mouse pointer."
706   (interactive "e")
707   (mouse-set-point event)
708   (gnus-carpal-select))
709
710 ;;; 
711 ;;; article highlights
712 ;;;
713
714 ;; Written by Per Abrahamsen <abraham@iesd.auc.dk>.
715
716 ;;; Internal Variables:
717
718 (defvar gnus-button-regexp nil)
719 ;; Regexp matching any of the regexps from `gnus-button-alist'.
720
721 (defvar gnus-button-last nil)
722 ;; The value of `gnus-button-alist' when `gnus-button-regexp' was build.
723
724 ;;; Commands:
725
726 (defun gnus-article-push-button (event)
727   "Check text under the mouse pointer for a callback function.
728 If the text under the mouse pointer has a `gnus-callback' property,
729 call it with the value of the `gnus-data' text property."
730   (interactive "e")
731   (set-buffer (window-buffer (posn-window (event-start event))))
732   (let* ((pos (posn-point (event-start event)))
733          (data (get-text-property pos 'gnus-data))
734          (fun (get-text-property pos 'gnus-callback)))
735       (if fun (funcall fun data))))
736
737 (defun gnus-article-press-button ()
738   "Check text at point for a callback function.
739 If the text at point has a `gnus-callback' property,
740 call it with the value of the `gnus-data' text property."
741   (interactive)
742   (let* ((data (get-text-property (point) 'gnus-data))
743          (fun (get-text-property (point) 'gnus-callback)))
744       (if fun (funcall fun data))))
745
746 ;; Suggested by Arne Elofsson <arne@hodgkin.mbi.ucla.edu>
747 (defun gnus-article-next-button ()
748   "Move point to next button."
749   (interactive)
750   (if (get-text-property (point) 'gnus-callback)
751       (goto-char (next-single-property-change (point) 'gnus-callback
752                                        nil (point-max))))
753   (let ((pos (next-single-property-change (point) 'gnus-callback)))
754     (if pos
755         (goto-char pos)
756       (setq pos (next-single-property-change (point-min) 'gnus-callback))
757       (if pos
758           (goto-char pos)
759         (error "No buttons found")))))
760
761 (defun gnus-article-highlight ()
762   "Highlight current article.
763 This function calls `gnus-article-highlight-headers',
764 `gnus-article-highlight-citation', 
765 `gnus-article-highlight-signature', and `gnus-article-add-buttons' to
766 do the highlighting.  See the documentation for those functions."
767   (interactive)
768   (gnus-article-highlight-headers)
769   (gnus-article-highlight-citation)
770   (gnus-article-highlight-signature)
771   (gnus-article-add-buttons))
772
773 (defun gnus-article-hide ()
774   "Hide current article.
775 This function calls `gnus-article-hide-headers',
776 `gnus-article-hide-citation-maybe', and `gnus-article-hide-signature'
777 to do the hiding.  See the documentation for those functions." 
778   (interactive)
779   (gnus-article-hide-headers)
780   (gnus-article-hide-citation-maybe)
781   (gnus-article-hide-signature))
782
783 (defun gnus-article-highlight-headers ()
784   "Highlight article headers as specified by `gnus-header-face-alist'."
785   (interactive)
786   (save-excursion
787     (set-buffer gnus-article-buffer)
788     (goto-char (point-min))
789     (search-forward "\n\n")
790     (beginning-of-line 0)
791     (while (not (bobp))
792       (let ((alist gnus-header-face-alist)
793             (buffer-read-only nil)
794             (case-fold-search t)
795             (end (point))
796             (inhibit-point-motion-hooks t)
797             begin entry regexp header-face field-face header-found field-found)
798         (re-search-backward "^[^ \t]" nil t)
799         (setq begin (point))
800         (while alist
801           (setq entry (car alist)
802                 regexp (nth 0 entry)
803                 header-face (nth 1 entry)
804                 field-face (nth 2 entry)
805                 alist (cdr alist))
806           (if (looking-at regexp)
807               (let ((from (point)))
808                 (skip-chars-forward "^:\n")
809                 (and (not header-found)
810                      header-face
811                      (progn
812                        (put-text-property  from (point) 'face header-face)
813                        (setq header-found t)))
814                 (and (not field-found)
815                      field-face
816                      (progn 
817                        (skip-chars-forward ": \t")
818                        (let ((from (point)))
819                          (goto-char end)
820                          (skip-chars-backward " \t")
821                          (put-text-property from (point) 'face field-face)
822                          (setq field-found t))))))
823           (goto-char begin))))))
824
825 (defun gnus-article-highlight-signature ()
826   "Highlight the signature in an article.
827 It does this by highlighting everything after
828 `gnus-signature-separator' using `gnus-signature-face'." 
829   (interactive)
830   (save-excursion
831     (set-buffer gnus-article-buffer)
832     (let ((buffer-read-only nil)
833           (inhibit-point-motion-hooks t))
834       (goto-char (point-max))
835       (and (re-search-backward gnus-signature-separator nil t)
836            gnus-signature-face
837            (let ((start (match-beginning 0))
838                  (end (match-end 0)))
839              (gnus-article-add-button start end 'gnus-signature-toggle end)
840              (overlay-put (make-overlay end (point-max))
841                           'face gnus-signature-face))))))
842
843 (defun gnus-article-hide-signature ()
844   "Hide the signature in an article.
845 It does this by making everything after `gnus-signature-separator' invisible."
846   (interactive)
847   (save-excursion
848     (set-buffer gnus-article-buffer)
849     (let ((buffer-read-only nil))
850       (goto-char (point-max))
851       (and (re-search-backward gnus-signature-separator nil t)
852            gnus-signature-face
853            (add-text-properties (match-end 0) (point-max)
854                                 gnus-hidden-properties)))))
855
856 (defun gnus-article-add-buttons ()
857   "Find external references in article and make them to buttons.
858
859 External references are things like message-ids and URLs, as specified by 
860 `gnus-button-alist'."
861   (interactive)
862   (if (eq gnus-button-last gnus-button-alist)
863       ()
864     (setq gnus-button-regexp (mapconcat 'car gnus-button-alist  "\\|")
865           gnus-button-last gnus-button-alist))
866   (save-excursion
867     (set-buffer gnus-article-buffer)
868     (gnus-cite-parse-maybe)
869     (let ((buffer-read-only nil)
870           (inhibit-point-motion-hooks t)
871           (case-fold-search t))
872       (goto-char (point-min))
873       (search-forward "\n\n")
874       (while (re-search-forward gnus-button-regexp nil t)
875         (goto-char (match-beginning 0))
876         (let* ((from (point))
877                (entry (gnus-button-entry))
878                (start (and entry (match-beginning (nth 1 entry))))
879                (end (and entry (match-end (nth 1 entry))))
880                (form (nth 2 entry))
881                marker)
882           (if (not entry)
883               ()
884             (goto-char (match-end 0))
885             (if (eval form)
886                 (gnus-article-add-button start end 'gnus-button-push
887                                          (set-marker (make-marker)
888                                                      from)))))))))
889
890 ;;; External functions:
891
892 (defun gnus-article-add-button (from to fun &optional data)
893   "Create a button between FROM and TO with callback FUN and data DATA."
894   (add-text-properties from to
895                        (append (if gnus-article-button-face
896                                    (list 'face gnus-article-button-face))
897                                (if gnus-article-mouse-face
898                                    (list 'mouse-face gnus-article-mouse-face))
899                                (list 'gnus-callback fun)
900                                (if data (list 'gnus-data data)))))
901
902 ;;; Internal functions:
903
904 (defun gnus-signature-toggle (end)
905   (save-excursion
906     (set-buffer gnus-article-buffer)
907     (let ((buffer-read-only nil))
908       (if (get-text-property end 'invisible)
909           (remove-text-properties end (point-max) gnus-hidden-properties)
910         (add-text-properties end (point-max) gnus-hidden-properties)))))
911
912 (defun gnus-make-face (color)
913   ;; Create entry for face with background COLOR.
914   (let ((name (intern (concat "gnus " color))))
915     (make-face name)
916     (if gnus-make-foreground
917         (set-face-foreground name color)
918       (set-face-background name color))
919     name))
920
921 (defun gnus-button-entry ()
922   ;; Return the first entry in `gnus-button-alist' matching this place.
923   (let ((alist gnus-button-alist)
924         (entry nil))
925     (while alist
926       (setq entry (car alist)
927             alist (cdr alist))
928       (if (looking-at (car entry))
929           (setq alist nil)
930         (setq entry nil)))
931     entry))
932
933 (defun gnus-button-push (marker)
934   ;; Push button starting at MARKER.
935   (save-excursion
936     (set-buffer gnus-article-buffer)
937     (goto-char marker)
938     (let* ((entry (gnus-button-entry))
939            (inhibit-point-motion-hooks t)
940            (fun (nth 3 entry))
941            (args (mapcar (lambda (group) 
942                            (let ((string (buffer-substring
943                                           (match-beginning group)
944                                           (match-end group))))
945                            (set-text-properties 0 (length string) nil string)
946                            string))
947                          (nthcdr 4 entry))))
948       (cond ((fboundp fun)
949              (apply fun args))
950             ((and (boundp fun)
951                   (fboundp (symbol-value fun)))
952              (apply (symbol-value fun) args))
953             (t
954              (message "You must define `%S' to use this button"
955                       (cons fun args)))))))
956
957 (defun gnus-button-message-id (message-id)
958   ;; Push on MESSAGE-ID.
959   (save-excursion
960     (set-buffer gnus-summary-buffer)
961     (gnus-summary-refer-article message-id)))
962
963 ;;; Compatibility Functions:
964
965 (or (fboundp 'rassoc)
966     ;; Introduced in Emacs 19.29.
967     (defun rassoc (elt list)
968       "Return non-nil if ELT is `equal' to the cdr of an element of LIST.
969 The value is actually the element of LIST whose cdr is ELT."
970       (let (result)
971         (while list
972           (setq result (car list))
973           (if (equal (cdr result) elt)
974               (setq list nil)
975             (setq result nil
976                   list (cdr list))))
977         result)))
978
979 (provide 'gnus-vis)
980
981 ;;; gnus-vis.el ends here