1 ;;; gnus-topic.el --- a folding minor mode for Gnus group buffers
2 ;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
4 ;; Author: Ilja Weis <kult@uni-paderborn.de>
5 ;; Lars Magne Ingebrigtsen <larsi@gnus.org>
8 ;; This file is part of GNU Emacs.
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)
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.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
29 (eval-when-compile (require 'cl))
36 (defgroup gnus-topic nil
40 (defvar gnus-topic-mode nil
41 "Minor mode for Gnus group buffers.")
43 (defcustom gnus-topic-mode-hook nil
44 "Hook run in topic mode buffers."
48 (defcustom gnus-topic-line-format "%i[ %(%{%n%}%) -- %A ]%v\n"
49 "Format of topic lines.
50 It works along the same lines as a normal formatting string,
51 with some simple extensions.
53 %i Indentation based on topic level.
55 %v Nothing if the topic is visible, \"...\" otherwise.
56 %g Number of groups in the topic.
57 %a Number of unread articles in the groups in the topic.
58 %A Number of unread articles in the groups in the topic and its subtopics.
63 (defcustom gnus-topic-indent-level 2
64 "*How much each subtopic should be indented."
68 (defcustom gnus-topic-display-empty-topics t
69 "*If non-nil, display the topic lines even of topics that have no unread articles."
73 ;; Internal variables.
75 (defvar gnus-topic-active-topology nil)
76 (defvar gnus-topic-active-alist nil)
77 (defvar gnus-topic-unreads nil)
79 (defvar gnus-topology-checked-p nil
80 "Whether the topology has been checked in this session.")
82 (defvar gnus-topic-killed-topics nil)
83 (defvar gnus-topic-inhibit-change-level nil)
85 (defconst gnus-topic-line-format-alist
89 (?g number-of-groups ?d)
90 (?a (gnus-topic-articles-in-topic entries) ?d)
91 (?A total-number-of-articles ?d)
94 (defvar gnus-topic-line-format-spec nil)
98 (defun gnus-group-topic-name ()
99 "The name of the topic on the current line."
100 (let ((topic (get-text-property (gnus-point-at-bol) 'gnus-topic)))
101 (and topic (symbol-name topic))))
103 (defun gnus-group-topic-level ()
104 "The level of the topic on the current line."
105 (get-text-property (gnus-point-at-bol) 'gnus-topic-level))
107 (defun gnus-group-topic-unread ()
108 "The number of unread articles in topic on the current line."
109 (get-text-property (gnus-point-at-bol) 'gnus-topic-unread))
111 (defun gnus-topic-unread (topic)
112 "Return the number of unread articles in TOPIC."
113 (or (cdr (assoc topic gnus-topic-unreads))
116 (defun gnus-group-topic-p ()
117 "Return non-nil if the current line is a topic."
118 (gnus-group-topic-name))
120 (defun gnus-topic-visible-p ()
121 "Return non-nil if the current topic is visible."
122 (get-text-property (gnus-point-at-bol) 'gnus-topic-visible))
124 (defun gnus-topic-articles-in-topic (entries)
128 (when (numberp (setq number (car (pop entries))))
129 (incf total number)))
132 (defun gnus-group-topic (group)
133 "Return the topic GROUP is a member of."
134 (let ((alist gnus-topic-alist)
137 (when (member group (cdar alist))
138 (setq out (caar alist)
140 (setq alist (cdr alist)))
143 (defun gnus-group-parent-topic (group)
144 "Return the topic GROUP is member of by looking at the group buffer."
146 (set-buffer gnus-group-buffer)
147 (if (gnus-group-goto-group group)
149 (gnus-group-topic group))))
151 (defun gnus-topic-goto-topic (topic)
154 (gnus-goto-char (text-property-any (point-min) (point-max)
155 'gnus-topic (intern topic)))))
157 (defun gnus-current-topic ()
158 "Return the name of the current topic."
160 (or (get-text-property (point) 'gnus-topic)
162 (and (gnus-goto-char (previous-single-property-change
163 (point) 'gnus-topic))
164 (get-text-property (max (1- (point)) (point-min))
167 (symbol-name result))))
169 (defun gnus-current-topics (&optional topic)
170 "Return a list of all current topics, lowest in hierarchy first.
171 If TOPIC, start with that topic."
172 (let ((topic (or topic (gnus-current-topic)))
176 (setq topic (gnus-topic-parent-topic topic)))
179 (defun gnus-group-active-topic-p ()
180 "Say whether the current topic comes from the active topics."
183 (get-text-property (point) 'gnus-active)))
185 (defun gnus-topic-find-groups (topic &optional level all lowest)
186 "Return entries for all visible groups in TOPIC."
187 (let ((groups (cdr (assoc topic gnus-topic-alist)))
188 info clevel unread group params visible-groups entry active)
189 (setq lowest (or lowest 1))
190 (setq level (or level gnus-level-unsubscribed))
191 ;; We go through the newsrc to look for matches.
193 (when (setq group (pop groups))
194 (setq entry (gnus-gethash group gnus-newsrc-hashtb)
196 params (gnus-info-params info)
197 active (gnus-active group)
198 unread (or (car entry)
199 (and (not (equal group "dummy.group"))
201 (- (1+ (cdr active)) (car active))))
202 clevel (or (gnus-info-level info)
203 (if (member group gnus-zombie-list)
204 gnus-level-zombie gnus-level-killed))))
206 unread ; nil means that the group is dead.
208 (>= clevel lowest) ; Is inside the level we want.
211 gnus-group-list-inactive-groups
213 (and gnus-list-groups-with-ticked-articles
214 (cdr (assq 'tick (gnus-info-marks info))))
215 ; Has right readedness.
216 ;; Check for permanent visibility.
217 (and gnus-permanently-visible-groups
218 (string-match gnus-permanently-visible-groups group))
219 (memq 'visible params)
220 (cdr (assq 'visible params)))
221 ;; Add this group to the list of visible groups.
222 (push (or entry group) visible-groups)))
223 (nreverse visible-groups)))
225 (defun gnus-topic-previous-topic (topic)
226 "Return the previous topic on the same level as TOPIC."
227 (let ((top (cddr (gnus-topic-find-topology
228 (gnus-topic-parent-topic topic)))))
229 (unless (equal topic (caaar top))
230 (while (and top (not (equal (caaadr top) topic)))
231 (setq top (cdr top)))
234 (defun gnus-topic-parent-topic (topic &optional topology)
235 "Return the parent of TOPIC."
237 (setq topology gnus-topic-topology))
238 (let ((parent (car (pop topology)))
241 (not (setq found (equal (caaar topology) topic)))
242 (not (setq result (gnus-topic-parent-topic
243 topic (car topology)))))
244 (setq topology (cdr topology)))
245 (or result (and found parent))))
247 (defun gnus-topic-next-topic (topic &optional previous)
248 "Return the next sibling of TOPIC."
249 (let ((parentt (cddr (gnus-topic-find-topology