Convert consecutive FSF copyright years to ranges.
[gnus] / lisp / gnus-group.el
1 ;;; gnus-group.el --- group mode commands for Gnus
2
3 ;; Copyright (C) 1996-2011
4 ;;   Free Software Foundation, Inc.
5
6 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
7 ;; Keywords: news
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
23
24 ;;; Commentary:
25
26 ;;; Code:
27
28 ;; For Emacs <22.2 and XEmacs.
29 (eval-and-compile
30   (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
31
32 (eval-when-compile
33   (require 'cl))
34 (defvar tool-bar-mode)
35
36 (require 'gnus)
37 (require 'gnus-start)
38 (require 'nnmail)
39 (require 'gnus-spec)
40 (require 'gnus-int)
41 (require 'gnus-range)
42 (require 'gnus-win)
43 (require 'gnus-undo)
44 (require 'gmm-utils)
45 (require 'time-date)
46 (require 'gnus-ems)
47
48 (eval-when-compile
49   (require 'mm-url)
50   (let ((features (cons 'gnus-group features)))
51     (require 'gnus-sum))
52   (unless (boundp 'gnus-cache-active-hashtb)
53     (defvar gnus-cache-active-hashtb nil)))
54
55 (autoload 'gnus-agent-total-fetched-for "gnus-agent")
56 (autoload 'gnus-cache-total-fetched-for "gnus-cache")
57
58 (autoload 'gnus-group-make-nnir-group "nnir")
59
60 (defcustom gnus-no-groups-message "No Gnus is good news"
61   "*Message displayed by Gnus when no groups are available."
62   :group 'gnus-start
63   :type 'string)
64
65 (defcustom gnus-keep-same-level nil
66   "*Non-nil means that the next newsgroup after the current will be on the same level.
67 When you type, for instance, `n' after reading the last article in the
68 current newsgroup, you will go to the next newsgroup.  If this variable
69 is nil, the next newsgroup will be the next from the group
70 buffer.
71 If this variable is non-nil, Gnus will either put you in the
72 next newsgroup with the same level, or, if no such newsgroup is
73 available, the next newsgroup with the lowest possible level higher
74 than the current level.
75 If this variable is `best', Gnus will make the next newsgroup the one
76 with the best level."
77   :group 'gnus-group-levels
78   :type '(choice (const nil)
79                  (const best)
80                  (sexp :tag "other" t)))
81
82 (defcustom gnus-group-goto-unread t
83   "*If non-nil, movement commands will go to the next unread and subscribed group."
84   :link '(custom-manual "(gnus)Group Maneuvering")
85   :group 'gnus-group-various
86   :type 'boolean)
87
88 (defcustom gnus-goto-next-group-when-activating t
89   "*If non-nil, the \\<gnus-group-mode-map>\\[gnus-group-get-new-news-this-group] command will advance point to the next group."
90   :link '(custom-manual "(gnus)Scanning New Messages")
91   :group 'gnus-group-various
92   :type 'boolean)
93
94 (defcustom gnus-permanently-visible-groups nil
95   "*Regexp to match groups that should always be listed in the group buffer.
96 This means that they will still be listed even when there are no
97 unread articles in the groups.
98
99 If nil, no groups are permanently visible."
100   :group 'gnus-group-listing
101   :type '(choice regexp (const nil)))
102
103 (defcustom gnus-safe-html-newsgroups "\\`nnrss[+:]"
104   "Groups in which links in html articles are considered all safe.
105 The value may be a regexp matching those groups, a list of group names,
106 or nil.  This overrides `mm-w3m-safe-url-regexp' (which see).  This is
107 effective only when emacs-w3m renders html articles, i.e., in the case
108 `mm-text-html-renderer' is set to `w3m'."
109   :version "23.2"
110   :group 'gnus-group-various
111   :type '(choice regexp
112                  (repeat :tag "List of group names" (string :tag "Group"))
113                  (const nil)))
114
115 (defcustom gnus-list-groups-with-ticked-articles t
116   "*If non-nil, list groups that have only ticked articles.
117 If nil, only list groups that have unread articles."
118   :group 'gnus-group-listing
119   :type 'boolean)
120
121 (defcustom gnus-group-default-list-level gnus-level-subscribed
122   "Default listing level.
123 Ignored if `gnus-group-use-permanent-levels' is non-nil."
124   :group 'gnus-group-listing
125   :type '(choice (integer :tag "Level")
126                  (function :tag "Function returning level")))
127
128 (defcustom gnus-group-list-inactive-groups t
129   "*If non-nil, inactive groups will be listed."
130   :group 'gnus-group-listing
131   :group 'gnus-group-levels
132   :type 'boolean)
133
134 (defcustom gnus-group-sort-function 'gnus-group-sort-by-alphabet
135   "*Function used for sorting the group buffer.
136 This function will be called with group info entries as the arguments
137 for the groups to be sorted.  Pre-made functions include
138 `gnus-group-sort-by-alphabet', `gnus-group-sort-by-real-name',
139 `gnus-group-sort-by-unread', `gnus-group-sort-by-level',
140 `gnus-group-sort-by-score', `gnus-group-sort-by-method',
141 `gnus-group-sort-by-server', and `gnus-group-sort-by-rank'.
142
143 This variable can also be a list of sorting functions.  In that case,
144 the most significant sort function should be the last function in the
145 list."
146   :group 'gnus-group-listing
147   :link '(custom-manual "(gnus)Sorting Groups")
148   :type '(repeat :value-to-internal (lambda (widget value)
149                                       (if (listp value) value (list value)))
150                  :match (lambda (widget value)
151                           (or (symbolp value)
152                               (widget-editable-list-match widget value)))
153                  (choice (function-item gnus-group-sort-by-alphabet)
154                          (function-item gnus-group-sort-by-real-name)
155                          (function-item gnus-group-sort-by-unread)
156                          (function-item gnus-group-sort-by-level)
157                          (function-item gnus-group-sort-by-score)
158                          (function-item gnus-group-sort-by-method)
159                          (function-item gnus-group-sort-by-server)
160                          (function-item gnus-group-sort-by-rank)
161                          (function :tag "other" nil))))
162
163 (defcustom gnus-group-line-format "%M\%S\%p\%P\%5y:%B%(%g%)\n"
164   "*Format of group lines.
165 It works along the same lines as a normal formatting string,
166 with some simple extensions.
167
168 %M    Only marked articles (character, \"*\" or \" \")
169 %S    Whether the group is subscribed (character, \"U\", \"K\", \"Z\" or \" \")
170 %L    Level of subscribedness (integer)
171 %N    Number of unread articles (integer)
172 %I    Number of dormant articles (integer)
173 %i    Number of ticked and dormant (integer)
174 %T    Number of ticked articles (integer)
175 %R    Number of read articles (integer)
176 %U    Number of unseen articles (integer)
177 %t    Estimated total number of articles (integer)
178 %y    Number of unread, unticked articles (integer)
179 %G    Group name (string)
180 %g    Qualified group name (string)
181 %c    Short (collapsed) group name.  See `gnus-group-uncollapsed-levels'.
182 %C    Group comment (string)
183 %D    Group description (string)
184 %s    Select method (string)
185 %o    Moderated group (char, \"m\")
186 %p    Process mark (char)
187 %B    Whether a summary buffer for the group is open (char, \"*\")
188 %O    Moderated group (string, \"(m)\" or \"\")
189 %P    Topic indentation (string)
190 %m    Whether there is new(ish) mail in the group (char, \"%\")
191 %n    Select from where (string)
192 %z    A string that look like `<%s:%n>' if a foreign select method is used
193 %d    The date the group was last entered.
194 %E    Icon as defined by `gnus-group-icon-list'.
195 %F    The disk space used by the articles fetched by both the cache and agent.
196 %u    User defined specifier.  The next character in the format string should
197       be a letter.  Gnus will call the function gnus-user-format-function-X,
198       where X is the letter following %u.  The function will be passed a
199       single dummy parameter as argument.  The function should return a
200       string, which will be inserted into the buffer just like information
201       from any other group specifier.
202
203 Note that this format specification is not always respected.  For
204 reasons of efficiency, when listing killed groups, this specification
205 is ignored altogether.  If the spec is changed considerably, your
206 output may end up looking strange when listing both alive and killed
207 groups.
208
209 If you use %o or %O, reading the active file will be slower and quite
210 a bit of extra memory will be used.  %D and %F will also worsen
211 performance.  Also note that if you change the format specification to
212 include any of these specs, you must probably re-start Gnus to see
213 them go into effect.
214
215 General format specifiers can also be used.
216 See Info node `(gnus)Formatting Variables'."
217   :link '(custom-manual "(gnus)Formatting Variables")
218   :group 'gnus-group-visual
219   :type 'string)
220
221 (defcustom gnus-group-mode-line-format "Gnus: %%b {%M\%:%S}"
222   "*The format specification for the group mode line.
223 It works along the same lines as a normal formatting string,
224 with some simple extensions:
225
226 %S   The native news server.
227 %M   The native select method.
228 %:   \":\" if %S isn't \"\"."
229   :group 'gnus-group-visual
230   :type 'string)
231
232 ;; Extracted from gnus-xmas-redefine in order to preserve user settings
233 (when (featurep 'xemacs)
234   (add-hook 'gnus-group-mode-hook 'gnus-xmas-group-menu-add)
235   (add-hook 'gnus-group-mode-hook 'gnus-xmas-setup-group-toolbar))
236
237 (defcustom gnus-group-menu-hook nil
238   "Hook run after the creation of the group mode menu."
239   :group 'gnus-group-various
240   :type 'hook)
241
242 (defcustom gnus-group-catchup-group-hook nil
243   "Hook run when catching up a group from the group buffer."
244   :group 'gnus-group-various
245   :link '(custom-manual "(gnus)Group Data")
246   :type 'hook)
247
248 (defcustom gnus-group-update-group-hook nil
249   "Hook called when updating group lines."
250   :group 'gnus-group-visual
251   :type 'hook)
252
253 (defcustom gnus-group-prepare-function 'gnus-group-prepare-flat
254   "*A function that is called to generate the group buffer.
255 The function is called with three arguments: The first is a number;
256 all group with a level less or equal to that number should be listed,
257 if the second is non-nil, empty groups should also be displayed.  If
258 the third is non-nil, it is a number.  No groups with a level lower
259 than this number should be displayed.
260
261 The only current function implemented is `gnus-group-prepare-flat'."
262   :group 'gnus-group-listing
263   :type 'function)
264
265 (defcustom gnus-group-prepare-hook nil
266   "Hook called after the group buffer has been generated.
267 If you want to modify the group buffer, you can use this hook."
268   :group 'gnus-group-listing
269   :type 'hook)
270
271 (defcustom gnus-suspend-gnus-hook nil
272   "Hook called when suspending (not exiting) Gnus."
273   :group 'gnus-exit
274   :type 'hook)
275
276 (defcustom gnus-exit-gnus-hook nil
277   "Hook called when exiting Gnus."
278   :group 'gnus-exit
279   :type 'hook)
280
281 (defcustom gnus-after-exiting-gnus-hook nil
282   "Hook called after exiting Gnus."
283   :group 'gnus-exit
284   :type 'hook)
285
286 (defcustom gnus-group-update-hook nil
287   "Hook called when a group line is changed."
288   :group 'gnus-group-visual
289   :version "24.1"
290   :type 'hook)
291
292 (defcustom gnus-useful-groups
293   '(("(ding) mailing list mirrored at gmane.org"
294      "gmane.emacs.gnus.general"
295      (nntp "Gmane"
296            (nntp-address "news.gmane.org")))
297     ("Gnus bug archive"
298      "gnus.gnus-bug"
299      (nntp "news.gnus.org"
300            (nntp-address "news.gnus.org")))
301     ("Local Gnus help group"
302      "gnus-help"
303      (nndoc "gnus-help"
304             (nndoc-article-type mbox)
305             (eval `(nndoc-address
306                     ,(let ((file (nnheader-find-etc-directory
307                                   "gnus-tut.txt" t)))
308                        (unless file
309                          (error "Couldn't find doc group"))
310                        file))))))
311   "*Alist of useful group-server pairs."
312   :group 'gnus-group-listing
313   :type '(repeat (list (string :tag "Description")
314                        (string :tag "Name")
315                        (sexp :tag "Method"))))
316
317 (defcustom gnus-group-highlight
318   '(;; Mail.
319     ((and mailp (= unread 0) (eq level 1)) .
320      gnus-group-mail-1-empty)
321     ((and mailp (eq level 1)) .
322      gnus-group-mail-1)
323     ((and mailp (= unread 0) (eq level 2)) .
324      gnus-group-mail-2-empty)
325     ((and mailp (eq level 2)) .
326      gnus-group-mail-2)
327     ((and mailp (= unread 0) (eq level 3)) .
328      gnus-group-mail-3-empty)
329     ((and mailp (eq level 3)) .
330      gnus-group-mail-3)
331     ((and mailp (= unread 0)) .
332      gnus-group-mail-low-empty)
333     ((and mailp) .
334      gnus-group-mail-low)
335     ;; News.
336     ((and (= unread 0) (eq level 1)) .
337      gnus-group-news-1-empty)
338     ((and (eq level 1)) .
339      gnus-group-news-1)
340     ((and (= unread 0) (eq level 2)) .
341      gnus-group-news-2-empty)
342     ((and (eq level 2)) .
343      gnus-group-news-2)
344     ((and (= unread 0) (eq level 3)) .
345      gnus-group-news-3-empty)
346     ((and (eq level 3)) .
347      gnus-group-news-3)
348     ((and (= unread 0) (eq level 4)) .
349      gnus-group-news-4-empty)
350     ((and (eq level 4)) .
351      gnus-group-news-4)
352     ((and (= unread 0) (eq level 5)) .
353      gnus-group-news-5-empty)
354     ((and (eq level 5)) .
355      gnus-group-news-5)
356     ((and (= unread 0) (eq level 6)) .
357      gnus-group-news-6-empty)
358     ((and (eq level 6)) .
359      gnus-group-news-6)
360     ((and (= unread 0)) .
361      gnus-group-news-low-empty)
362     (t .
363      gnus-group-news-low))
364   "*Controls the highlighting of group buffer lines.
365
366 Below is a list of `Form'/`Face' pairs.  When deciding how a a
367 particular group line should be displayed, each form is
368 evaluated.  The content of the face field after the first true form is
369 used.  You can change how those group lines are displayed by
370 editing the face field.
371
372 It is also possible to change and add form fields, but currently that
373 requires an understanding of Lisp expressions.  Hopefully this will
374 change in a future release.  For now, you can use the following
375 variables in the Lisp expression:
376
377 group: The name of the group.
378 unread: The number of unread articles in the group.
379 method: The select method used.
380 mailp: Whether it's a mail group or not.
381 level: The level of the group.
382 score: The score of the group.
383 ticked: The number of ticked articles."
384   :group 'gnus-group-visual
385   :type '(repeat (cons (sexp :tag "Form") face)))
386 (put 'gnus-group-highlight 'risky-local-variable t)
387
388 (defcustom gnus-new-mail-mark ?%
389   "Mark used for groups with new mail."
390   :group 'gnus-group-visual
391   :type 'character)
392
393 (defgroup gnus-group-icons nil
394   "Add Icons to your group buffer."
395   :group 'gnus-group-visual)
396
397 (defcustom gnus-group-icon-list
398   nil
399   "*Controls the insertion of icons into group buffer lines.
400
401 Below is a list of `Form'/`File' pairs.  When deciding how a
402 particular group line should be displayed, each form is evaluated.
403 The icon from the file field after the first true form is used.  You
404 can change how those group lines are displayed by editing the file
405 field.  The File will either be found in the
406 `gnus-group-glyph-directory' or by designating absolute name of the
407 file.
408
409 It is also possible to change and add form fields, but currently that
410 requires an understanding of Lisp expressions.  Hopefully this will
411 change in a future release.  For now, you can use the following
412 variables in the Lisp expression:
413
414 group: The name of the group.
415 unread: The number of unread articles in the group.
416 method: The select method used.
417 mailp: Whether it's a mail group or not.
418 level: The level of the group.
419 score: The score of the group.
420 ticked: The number of ticked articles."
421   :group 'gnus-group-icons