1 ;;; gnus-sum.el --- summary mode commands for Gnus
2 ;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
28 (eval-when-compile (require 'cl))
36 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
38 (defcustom gnus-kill-summary-on-exit t
39 "*If non-nil, kill the summary buffer when you exit from it.
40 If nil, the summary will become a \"*Dead Summary*\" buffer, and
41 it will be killed sometime later."
42 :group 'gnus-summary-exit
45 (defcustom gnus-fetch-old-headers nil
46 "*Non-nil means that Gnus will try to build threads by grabbing old headers.
47 If an unread article in the group refers to an older, already read (or
48 just marked as read) article, the old article will not normally be
49 displayed in the Summary buffer. If this variable is non-nil, Gnus
50 will attempt to grab the headers to the old articles, and thereby
51 build complete threads. If it has the value `some', only enough
52 headers to connect otherwise loose threads will be displayed. This
53 variable can also be a number. In that case, no more than that number
54 of old headers will be fetched. If it has the value `invisible', all
55 old headers will be fetched, but none will be displayed.
57 The server has to support NOV for any of this to work."
59 :type '(choice (const :tag "off" nil)
62 (sexp :menu-tag "other" t)))
64 (defcustom gnus-refer-thread-limit 200
65 "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
66 If t, fetch all the available old headers."
69 (sexp :menu-tag "other" t)))
71 (defcustom gnus-summary-make-false-root 'adopt
72 "*nil means that Gnus won't gather loose threads.
73 If the root of a thread has expired or been read in a previous
74 session, the information necessary to build a complete thread has been
75 lost. Instead of having many small sub-threads from this original thread
76 scattered all over the summary buffer, Gnus can gather them.
78 If non-nil, Gnus will try to gather all loose sub-threads from an
79 original thread into one large thread.
81 If this variable is non-nil, it should be one of `none', `adopt',
84 If this variable is `none', Gnus will not make a false root, but just
85 present the sub-threads after another.
86 If this variable is `dummy', Gnus will create a dummy root that will
87 have all the sub-threads as children.
88 If this variable is `adopt', Gnus will make one of the \"children\"
89 the parent and mark all the step-children as such.
90 If this variable is `empty', the \"children\" are printed with empty
91 subject fields. (Or rather, they will be printed with a string
92 given by the `gnus-summary-same-subject' variable.)"
94 :type '(choice (const :tag "off" nil)
100 (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
101 "*A regexp to match subjects to be excluded from loose thread gathering.
102 As loose thread gathering is done on subjects only, that means that
103 there can be many false gatherings performed. By rooting out certain
104 common subjects, gathering might become saner."
108 (defcustom gnus-summary-gather-subject-limit nil
109 "*Maximum length of subject comparisons when gathering loose threads.
110 Use nil to compare full subjects. Setting this variable to a low
111 number will help gather threads that have been corrupted by
112 newsreaders chopping off subject lines, but it might also mean that
113 unrelated articles that have subject that happen to begin with the
114 same few characters will be incorrectly gathered.
116 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
119 :type '(choice (const :tag "off" nil)
121 (sexp :menu-tag "on" t)))
123 (defcustom gnus-simplify-subject-functions nil
124 "List of functions taking a string argument that simplify subjects.
125 The functions are applied recursively.
127 Useful functions to put in this list include: `gnus-simplify-subject-re',
128 `gnus-simplify-subject-fuzzy' and `gnus-simplify-whitespace'."
130 :type '(repeat function))
132 (defcustom gnus-simplify-ignored-prefixes nil
133 "*Regexp, matches for which are removed from subject lines when simplifying fuzzily."
135 :type '(choice (const :tag "off" nil)
138 (defcustom gnus-build-sparse-threads nil
139 "*If non-nil, fill in the gaps in threads.
140 If `some', only fill in the gaps that are needed to tie loose threads
141 together. If `more', fill in all leaf nodes that Gnus can find. If
142 non-nil and non-`some', fill in all gaps that Gnus manages to guess."
144 :type '(choice (const :tag "off" nil)
147 (sexp :menu-tag "all" t)))
149 (defcustom gnus-summary-thread-gathering-function
150 'gnus-gather-threads-by-subject
151 "*Function used for gathering loose threads.
152 There are two pre-defined functions: `gnus-gather-threads-by-subject',
153 which only takes Subjects into consideration; and
154 `gnus-gather-threads-by-references', which compared the References
155 headers of the articles to find matches."
157 :type '(radio (function-item gnus-gather-threads-by-subject)
158 (function-item gnus-gather-threads-by-references)
159 (function :tag "other")))
161 (defcustom gnus-summary-same-subject ""
162 "*String indicating that the current article has the same subject as the previous.
163 This variable will only be used if the value of
164 `gnus-summary-make-false-root' is `empty'."
165 :group 'gnus-summary-format
168 (defcustom gnus-summary-goto-unread t
169 "*If t, marking commands will go to the next unread article.
170 If `never', commands that usually go to the next unread article, will
171 go to the next article, whether it is read or not.
172 If nil, only the marking commands will go to the next (un)read article."
173 :group 'gnus-summary-marks
174 :link '(custom-manual "(gnus)Setting Marks")
175 :type '(choice (const :tag "off" nil)
177 (sexp :menu-tag "on" t)))
179 (defcustom gnus-summary-default-score 0
180 "*Default article score level.
181 All scores generated by the score files will be added to this score.
182 If this variable is nil, scoring will be disabled."
183 :group 'gnus-score-default
184 :type '(choice (const :tag "disable")
187 (defcustom gnus-summary-zcore-fuzz 0
188 "*Fuzziness factor for the zcore in the summary buffer.
189 Articles with scores closer than this to `gnus-summary-default-score'
191 :group 'gnus-summary-format
194 (defcustom gnus-simplify-subject-fuzzy-regexp nil
195 "*Strings to be removed when doing fuzzy matches.
196 This can either be a regular expression or list of regular expressions
197 that will be removed from subject strings if fuzzy subject
198 simplification is selected."
200 :type '(repeat regexp))
202 (defcustom gnus-show-threads t
203 "*If non-nil, display threads in summary mode."
207 (defcustom gnus-thread-hide-subtree nil
208 "*If non-nil, hide all threads initially.
209 If threads are hidden, you have to run the command
210 `gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
211 to expose hidden threads."
215 (defcustom gnus-thread-hide-killed t
216 "*If non-nil, hide killed threads automatically."
220 (defcustom gnus-thread-ignore-subject nil
221 "*If non-nil, ignore subjects and do all threading based on the Reference header.
222 If nil, which is the default, articles that have different subjects
223 from their parents will start separate threads."
227 (defcustom gnus-thread-operation-ignore-subject t
228 "*If non-nil, subjects will be ignored when doing thread commands.
229 This affects commands like `gnus-summary-kill-thread' and
230 `gnus-summary-lower-thread'.
232 If this variable is nil, articles in the same thread with different
233 subjects will not be included in the operation in question. If this
234 variable is `fuzzy', only articles that have subjects that are fuzzily
235 equal will be included."
237 :type '(choice (const :tag "off" nil)
241 (defcustom gnus-thread-indent-level 4
242 "*Number that says how much each sub-thread should be indented."
246 (defcustom gnus-auto-extend-newsgroup t
247 "*If non-nil, extend newsgroup forward and backward when requested."
248 :group 'gnus-summary-choose
251 (defcustom gnus-auto-select-first t
252 "*If nil, don't select the first unread article when entering a group.
253 If this variable is `best', select the highest-scored unread article
254 in the group. If neither nil nor `best', select the first unread
257 If you want to prevent automatic selection of the first unread article
258 in some newsgroups, set the variable to nil in
259 `gnus-select-group-hook'."
260 :group 'gnus-group-select
261 :type '(choice (const :tag "none" nil)
263 (sexp :menu-tag "first" t)))
265 (defcustom gnus-auto-select-next t
266 "*If non-nil, offer to go to the next group from the end of the previous.
267 If the value is t and the next newsgroup is empty, Gnus will exit
268 summary mode and go back to group mode. If the value is neither nil
269 nor t, Gnus will select the following unread newsgroup. In
270 particular, if the value is the symbol `quietly', the next unread
271 newsgroup will be selected without any confirmation, and if it is
272 `almost-quietly', the next group will be selected without any
273 confirmation if you are located on the last article in the group.
274 Finally, if this variable is `slightly-quietly', the `Z n' command
275 will go to the next group without confirmation."
276 :group 'gnus-summary-maneuvering
277 :type '(choice (const :tag "off" nil)
279 (const almost-quietly)
280 (const slightly-quietly)
281 (sexp :menu-tag "on" t)))
283 (defcustom gnus-auto-select-same nil
284 "*If non-nil, select the next article with the same subject."
285 :group 'gnus-summary-maneuvering
288 (defcustom gnus-summary-check-current nil
289 "*If non-nil, consider the current article when moving.
290 The \"unread\" movement commands will stay on the same line if the
291 current article is unread."
292 :group 'gnus-summary-maneuvering
295 (defcustom gnus-auto-center-summary t
296 "*If non-nil, always center the current summary buffer.
297 In particular, if `vertical' do only vertical recentering. If non-nil
298 and non-`vertical', do both horizontal and vertical recentering."
299 :group 'gnus-summary-maneuvering
300 :type '(choice (const :tag "none" nil)
302 (sexp :menu-tag "both" t)))
304 (defcustom gnus-show-all-headers nil
305 "*If non-nil, don't hide any headers."
306 :group 'gnus-article-hiding
307 :group 'gnus-article-headers
310 (defcustom gnus-summary-ignore-duplicates nil
311 "*If non-nil, ignore articles with identical Message-ID headers."
315 (defcustom gnus-single-article-buffer t
316 "*If non-nil, display all articles in the same buffer.
317 If nil, each group will get its own article buffer."
318 :group 'gnus-article-various
321 (defcustom gnus-break-pages t
322 "*If non-nil, do page breaking on articles.
323 The page delimiter is specified by the `gnus-page-delimiter'
325 :group 'gnus-article-various
328 (defcustom gnus-show-mime nil
329 "*If non-nil, do mime processing of articles.
330 The articles will simply be fed to the function given by
331 `gnus-show-mime-method'."
332 :group 'gnus-article-mime
335 (defcustom gnus-move-split-methods nil
336 "*Variable used to suggest where articles are to be moved to.
337 It uses the same syntax as the `gnus-split-methods' variable."
338 :group 'gnus-summary-mail
339 :type '(repeat (choice (list :value (fun) function)
340 (cons :value ("" "") regexp (repeat string))
343 (defcustom gnus-unread-mark ?
344 "*Mark used for unread articles."
345 :group 'gnus-summary-marks
348 (defcustom gnus-ticked-mark ?!
349 "*Mark used for ticked articles."
350 :group 'gnus-summary-marks
353 (defcustom gnus-dormant-mark ??
354 "*Mark used for dormant articles."
355 :group 'gnus-summary-marks
358 (defcustom gnus-del-mark ?r
359 "*Mark used for del'd articles."
360 :group 'gnus-summary-marks
363 (defcustom gnus-read-mark ?R
364 "*Mark used for read articles."
365 :group 'gnus-summary-marks
368 (defcustom gnus-expirable-mark ?E
369 "*Mark used for expirable articles."
370 :group 'gnus-summary-marks
373 (defcustom gnus-killed-mark ?K
374 "*Mark used for killed articles."
375 :group 'gnus-summary-marks
378 (defcustom gnus-souped-mark ?F
379 "*Mark used for killed articles."
380 :group 'gnus-summary-marks
383 (defcustom gnus-kill-file-mark ?X
384 "*Mark used for articles killed by kill files."
385 :group 'gnus-summary-marks
388 (defcustom gnus-low-score-mark ?Y
389 "*Mark used for articles with a low score."
390 :group 'gnus-summary-marks
393 (defcustom gnus-catchup-mark ?C
394 "*Mark used for articles that are caught up."
395 :group 'gnus-summary-marks
398 (defcustom gnus-replied-mark ?A
399 "*Mark used for articles that have been replied to."
400 :group 'gnus-summary-marks
403 (defcustom gnus-cached-mark ?*
404 "*Mark used for articles that are in the cache."
405 :group 'gnus-summary-marks
408 (defcustom gnus-saved-mark ?S
409 "*Mark used for articles that have been saved to."
410 :group 'gnus-summary-marks
413 (defcustom gnus-ancient-mark ?O
414 "*Mark used for ancient articles."
415 :group 'gnus-summary-marks
418 (defcustom gnus-sparse-mark ?Q
419 "*Mark used for sparsely reffed articles."
420 :group 'gnus-summary-marks
423 (defcustom gnus-canceled-mark ?G
424 "*Mark used for canceled articles."
425 :group 'gnus-summary-marks
428 (defcustom gnus-duplicate-mark ?M
429 "*Mark used for duplicate articles."
430 :group 'gnus-summary-marks
433 (defcustom gnus-undownloaded-mark ?@
434 "*Mark used for articles that weren't downloaded."
435 :group 'gnus-summary-marks
438 (defcustom gnus-downloadable-mark ?%
439 "*Mark used for articles that are to be downloaded."
440 :group 'gnus-summary-marks
443 (defcustom gnus-unsendable-mark ?=
444 "*Mark used for articles that won't be sent."
445 :group 'gnus-summary-marks
448 (defcustom gnus-score-over-mark ?+
449 "*Score mark used for articles with high scores."
450 :group 'gnus-summary-marks
453 (defcustom gnus-score-below-mark ?-
454 "*Score mark used for articles with low scores."
455 :group 'gnus-summary-marks
458 (defcustom gnus-empty-thread-mark ?
459 "*There is no thread under the article."
460 :group 'gnus-summary-marks
463 (defcustom gnus-not-empty-thread-mark ?=
464 "*There is a thread under the article."
465 :group 'gnus-summary-marks
468 (defcustom gnus-view-pseudo-asynchronously nil
469 "*If non-nil, Gnus will view pseudo-articles asynchronously."
470 :group 'gnus-extract-view
473 (defcustom gnus-view-pseudos nil
474 "*If `automatic', pseudo-articles will be viewed automatically.
475 If `not-confirm', pseudos will be viewed automatically, and the user
476 will not be asked to confirm the command."
477 :group 'gnus-extract-view
478 :type '(choice (const :tag "off" nil)
480 (const not-confirm)))
482 (defcustom gnus-view-pseudos-separately t
483 "*If non-nil, one pseudo-article will be created for each file to be viewed.
484 If nil, all files that use the same viewing command will be given as a
485 list of parameters to that command."
486 :group 'gnus-extract-view
489 (defcustom gnus-insert-pseudo-articles t
490 "*If non-nil, insert pseudo-articles when decoding articles."
491 :group 'gnus-extract-view
494 (defcustom gnus-summary-dummy-line-format
496 "*The format specification for the dummy roots in the summary buffer.
497 It works along the same lines as a normal formatting string,
498 with some simple extensions.
501 :group 'gnus-threading
504 (defcustom gnus-summary-mode-line-format "Gnus: %%b [%A] %Z"
505 "*The format specification for the summary mode line.
506 It works along the same lines as a normal formatting string,
507 with some simple extensions:
510 %p Unprefixed group name
511 %A Current article number
512 %z Current article score
514 %U Number of unread articles in the group
515 %e Number of unselected articles in the group
516 %Z A string with unread/unselected article counts
517 %g Shortish group name
518 %S Subject of the current article
520 %s Current score file name
521 %d Number of dormant articles
522 %r Number of articles that have been marked as read in this session
523 %E Number of articles expunged by the score files"
524 :group 'gnus-summary-format
527 (defcustom gnus-summary-mark-below 0
528 "*Mark all articles with a score below this variable as read.
529 This variable is local to each summary buffer and usually set by the
531 :group 'gnus-score-default
534 (defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
535 "*List of functions used for sorting articles in the summary buffer.
536 This variable is only used when not using a threaded display."
537 :group 'gnus-summary-sort
538 :type '(repeat (choice (function-item gnus-article-sort-by-number)
539 (function-item gnus-article-sort-by-author)
540 (function-item gnus-article-sort-by-subject)
541 (function-item gnus-article-sort-by-date)
542 (function-item gnus-article-sort-by-score)
543 (function :tag "other"))))
545 (defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
546 "*List of functions used for sorting threads in the summary buffer.
547 By default, threads are sorted by article number.
549 Each function takes two threads and return non-nil if the first thread
550 should be sorted before the other. If you use more than one function,
551 the primary sort function should be the last. You should probably
552 always include `gnus-thread-sort-by-number' in the list of sorting
553 functions -- preferably first.
555 Ready-made functions include `gnus-thread-sort-by-number',
556 `gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
557 `gnus-thread-sort-by-date', `gnus-thread-sort-by-score' and
558 `gnus-thread-sort-by-total-score' (see `gnus-thread-score-function')."
559 :group 'gnus-summary-sort
560 :type '(repeat (choice (function-item gnus-thread-sort-by-number)
561 (function-item gnus-thread-sort-by-author)
562 (function-item gnus-thread-sort-by-subject)
563 (function-item gnus-thread-sort-by-date)
564 (function-item gnus-thread-sort-by-score)
565 (function-item gnus-thread-sort-by-total-score)
566 (function :tag "other"))))
568 (defcustom gnus-thread-score-function '+
569 "*Function used for calculating the total score of a thread.
571 The function is called with the scores of the article and each
572 subthread and should then return the score of the thread.
574 Some functions you can use are `+', `max', or `min'."
575 :group 'gnus-summary-sort
578 (defcustom gnus-summary-expunge-below nil
579 "All articles that have a score less than this variable will be expunged.
580 This variable is local to the summary buffers."
581 :group 'gnus-score-default
582 :type '(choice (const :tag "off" nil)
585 (defcustom gnus-thread-expunge-below nil
586 "All threads that have a total score less than this variable will be expunged.
587 See `gnus-thread-score-function' for en explanation of what a