comparison lisp/gnus/gnus-topic.el @ 89971:cce1c0ee76ee

Revision: miles@gnu.org--gnu-2004/emacs--unicode--0--patch-36 Merge from emacs--cvs-trunk--0, emacs--gnus--5.10, gnus--rel--5.10 Patches applied: * miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-523 Merge from emacs--gnus--5.10, gnus--rel--5.10 * miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-524 - miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-534 Update from CVS * miles@gnu.org--gnu-2004/emacs--gnus--5.10--base-0 tag of miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-464 * miles@gnu.org--gnu-2004/emacs--gnus--5.10--patch-1 Import from CVS branch gnus-5_10-branch * miles@gnu.org--gnu-2004/emacs--gnus--5.10--patch-2 Merge from lorentey@elte.hu--2004/emacs--multi-tty--0, emacs--cvs-trunk--0 * miles@gnu.org--gnu-2004/emacs--gnus--5.10--patch-3 Merge from gnus--rel--5.10 * miles@gnu.org--gnu-2004/emacs--gnus--5.10--patch-4 Merge from gnus--rel--5.10 * miles@gnu.org--gnu-2004/gnus--rel--5.10--patch-18 Update from CVS * miles@gnu.org--gnu-2004/gnus--rel--5.10--patch-19 Remove autoconf-generated files from archive * miles@gnu.org--gnu-2004/gnus--rel--5.10--patch-20 Update from CVS
author Miles Bader <miles@gnu.org>
date Thu, 09 Sep 2004 09:36:36 +0000
parents 561b856c5b1f 55fd4f77387a
children f9a65d7ebd29
comparison
equal deleted inserted replaced
89970:a849e5779b8c 89971:cce1c0ee76ee
1 ;;; gnus-topic.el --- a folding minor mode for Gnus group buffers 1 ;;; gnus-topic.el --- a folding minor mode for Gnus group buffers
2 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 2 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3 ;; Free Software Foundation, Inc. 3 ;; Free Software Foundation, Inc.
4 4
5 ;; Author: Ilja Weis <kult@uni-paderborn.de> 5 ;; Author: Ilja Weis <kult@uni-paderborn.de>
6 ;; Lars Magne Ingebrigtsen <larsi@gnus.org> 6 ;; Lars Magne Ingebrigtsen <larsi@gnus.org>
7 ;; Keywords: news 7 ;; Keywords: news
43 43
44 (defcustom gnus-topic-mode-hook nil 44 (defcustom gnus-topic-mode-hook nil
45 "Hook run in topic mode buffers." 45 "Hook run in topic mode buffers."
46 :type 'hook 46 :type 'hook
47 :group 'gnus-topic) 47 :group 'gnus-topic)
48
49 (when (featurep 'xemacs)
50 (add-hook 'gnus-topic-mode-hook 'gnus-xmas-topic-menu-add))
48 51
49 (defcustom gnus-topic-line-format "%i[ %(%{%n%}%) -- %A ]%v\n" 52 (defcustom gnus-topic-line-format "%i[ %(%{%n%}%) -- %A ]%v\n"
50 "Format of topic lines. 53 "Format of topic lines.
51 It works along the same lines as a normal formatting string, 54 It works along the same lines as a normal formatting string,
52 with some simple extensions. 55 with some simple extensions.
55 %n Topic name. 58 %n Topic name.
56 %v Nothing if the topic is visible, \"...\" otherwise. 59 %v Nothing if the topic is visible, \"...\" otherwise.
57 %g Number of groups in the topic. 60 %g Number of groups in the topic.
58 %a Number of unread articles in the groups in the topic. 61 %a Number of unread articles in the groups in the topic.
59 %A Number of unread articles in the groups in the topic and its subtopics. 62 %A Number of unread articles in the groups in the topic and its subtopics.
60 " 63
64 General format specifiers can also be used.
65 See Info node `(gnus)Formatting Variables'."
66 :link '(custom-manual "(gnus)Formatting Variables")
61 :type 'string 67 :type 'string
62 :group 'gnus-topic) 68 :group 'gnus-topic)
63 69
64 (defcustom gnus-topic-indent-level 2 70 (defcustom gnus-topic-indent-level 2
65 "*How much each subtopic should be indented." 71 "*How much each subtopic should be indented."
159 (interactive 165 (interactive
160 (list (completing-read "Go to topic: " 166 (list (completing-read "Go to topic: "
161 (mapcar 'list (gnus-topic-list)) 167 (mapcar 'list (gnus-topic-list))
162 nil t))) 168 nil t)))
163 (dolist (topic (gnus-current-topics topic)) 169 (dolist (topic (gnus-current-topics topic))
170 (gnus-topic-goto-topic topic)
164 (gnus-topic-fold t)) 171 (gnus-topic-fold t))
165 (gnus-topic-goto-topic topic)) 172 (gnus-topic-goto-topic topic))
166 173
167 (defun gnus-current-topic () 174 (defun gnus-current-topic ()
168 "Return the name of the current topic." 175 "Return the name of the current topic."
194 201
195 (defun gnus-topic-find-groups (topic &optional level all lowest recursive) 202 (defun gnus-topic-find-groups (topic &optional level all lowest recursive)
196 "Return entries for all visible groups in TOPIC. 203 "Return entries for all visible groups in TOPIC.
197 If RECURSIVE is t, return groups in its subtopics too." 204 If RECURSIVE is t, return groups in its subtopics too."
198 (let ((groups (cdr (assoc topic gnus-topic-alist))) 205 (let ((groups (cdr (assoc topic gnus-topic-alist)))
199 info clevel unread group params visible-groups entry active) 206 info clevel unread group params visible-groups entry active)
200 (setq lowest (or lowest 1)) 207 (setq lowest (or lowest 1))
201 (setq level (or level gnus-level-unsubscribed)) 208 (setq level (or level gnus-level-unsubscribed))
202 ;; We go through the newsrc to look for matches. 209 ;; We go through the newsrc to look for matches.
203 (while groups 210 (while groups
204 (when (setq group (pop groups)) 211 (when (setq group (pop groups))
243 (caar topic-topology) 250 (caar topic-topology)
244 level all lowest topic-topology)))) 251 level all lowest topic-topology))))
245 (cdr recursive))) 252 (cdr recursive)))
246 visible-groups)) 253 visible-groups))
247 254
255 (defun gnus-topic-goto-previous-topic (n)
256 "Go to the N'th previous topic."
257 (interactive "p")
258 (gnus-topic-goto-next-topic (- n)))
259
260 (defun gnus-topic-goto-next-topic (n)
261 "Go to the N'th next topic."
262 (interactive "p")
263 (let ((backward (< n 0))
264 (n (abs n))
265 (topic (gnus-current-topic)))
266 (while (and (> n 0)
267 (setq topic
268 (if backward
269 (gnus-topic-previous-topic topic)
270 (gnus-topic-next-topic topic))))
271 (gnus-topic-goto-topic topic)
272 (setq n (1- n)))
273 (when (/= 0 n)
274 (gnus-message 7 "No more topics"))
275 n))
276
248 (defun gnus-topic-previous-topic (topic) 277 (defun gnus-topic-previous-topic (topic)
249 "Return the previous topic on the same level as TOPIC." 278 "Return the previous topic on the same level as TOPIC."
250 (let ((top (cddr (gnus-topic-find-topology 279 (let ((top (cddr (gnus-topic-find-topology
251 (gnus-topic-parent-topic topic))))) 280 (gnus-topic-parent-topic topic)))))
252 (unless (equal topic (caaar top)) 281 (unless (equal topic (caaar top))
349 378
350 (defun gnus-group-topic-parameters (group) 379 (defun gnus-group-topic-parameters (group)
351 "Compute the group parameters for GROUP taking into account inheritance from topics." 380 "Compute the group parameters for GROUP taking into account inheritance from topics."
352 (let ((params-list (copy-sequence (gnus-group-get-parameter group)))) 381 (let ((params-list (copy-sequence (gnus-group-get-parameter group))))
353 (save-excursion 382 (save-excursion
354 (gnus-group-goto-group group)
355 (nconc params-list 383 (nconc params-list
356 (gnus-topic-hierarchical-parameters (gnus-current-topic)))))) 384 (gnus-topic-hierarchical-parameters
385 ;; First we try to go to the group within the group
386 ;; buffer and find the topic for the group that way.
387 ;; This hopefully copes well with groups that are in
388 ;; more than one topic. Failing that (i.e. when the
389 ;; group isn't visible in the group buffer) we find a
390 ;; topic for the group via gnus-group-topic.
391 (or (and (gnus-group-goto-group group)
392 (gnus-current-topic))
393 (gnus-group-topic group)))))))
357 394
358 (defun gnus-topic-hierarchical-parameters (topic) 395 (defun gnus-topic-hierarchical-parameters (topic)
359 "Return a topic list computed for TOPIC." 396 "Return a topic list computed for TOPIC."
360 (let ((topics (gnus-current-topics topic)) 397 (let ((topics (gnus-current-topics topic))
361 params-list param out params) 398 params-list param out params)
382 (gnus-dribble-enter 419 (gnus-dribble-enter
383 (format "(setq gnus-topic-topology '%S)" gnus-topic-topology))) 420 (format "(setq gnus-topic-topology '%S)" gnus-topic-topology)))
384 421
385 ;;; Generating group buffers 422 ;;; Generating group buffers
386 423
387 (defun gnus-group-prepare-topics (level &optional all lowest 424 (defun gnus-group-prepare-topics (level &optional predicate lowest
388 regexp list-topic topic-level) 425 regexp list-topic topic-level)
389 "List all newsgroups with unread articles of level LEVEL or lower. 426 "List all newsgroups with unread articles of level LEVEL or lower.
390 Use the `gnus-group-topics' to sort the groups. 427 Use the `gnus-group-topics' to sort the groups.
391 If ALL is non-nil, list groups that have no unread articles. 428 If PREDICTE is a function, list groups that the function returns non-nil;
429 if it is t, list groups that have no unread articles.
392 If LOWEST is non-nil, list all newsgroups of level LOWEST or higher." 430 If LOWEST is non-nil, list all newsgroups of level LOWEST or higher."
393 (set-buffer gnus-group-buffer) 431 (set-buffer gnus-group-buffer)
394 (let ((buffer-read-only nil) 432 (let ((buffer-read-only nil)
395 (lowest (or lowest 1))) 433 (lowest (or lowest 1))
396 434 (not-in-list
435 (and gnus-group-listed-groups
436 (copy-sequence gnus-group-listed-groups))))
437
438 (gnus-update-format-specifications nil 'topic)
439
397 (when (or (not gnus-topic-alist) 440 (when (or (not gnus-topic-alist)
398 (not gnus-topology-checked-p)) 441 (not gnus-topology-checked-p))
399 (gnus-topic-check-topology)) 442 (gnus-topic-check-topology))
400 443
401 (unless list-topic 444 (unless list-topic
402 (erase-buffer)) 445 (erase-buffer))
403 446
404 ;; List dead groups? 447 ;; List dead groups?
405 (when (and (>= level gnus-level-zombie) 448 (when (or gnus-group-listed-groups
406 (<= lowest gnus-level-zombie)) 449 (and (>= level gnus-level-zombie)
450 (<= lowest gnus-level-zombie)))
407 (gnus-group-prepare-flat-list-dead 451 (gnus-group-prepare-flat-list-dead
408 (setq gnus-zombie-list (sort gnus-zombie-list 'string<)) 452 (setq gnus-zombie-list (sort gnus-zombie-list 'string<))
409 gnus-level-zombie ?Z 453 gnus-level-zombie ?Z
410 regexp)) 454 regexp))
411 455
412 (when (and (>= level gnus-level-killed) (<= lowest gnus-level-killed)) 456 (when (or gnus-group-listed-groups
457 (and (>= level gnus-level-killed)
458 (<= lowest gnus-level-killed)))
413 (gnus-group-prepare-flat-list-dead 459 (gnus-group-prepare-flat-list-dead
414 (setq gnus-killed-list (sort gnus-killed-list 'string<)) 460 (setq gnus-killed-list (sort gnus-killed-list 'string<))
415 gnus-level-killed ?K 461 gnus-level-killed ?K regexp)
416 regexp)) 462 (when not-in-list
463 (unless gnus-killed-hashtb
464 (gnus-make-hashtable-from-killed))
465 (gnus-group-prepare-flat-list-dead
466 (gnus-remove-if (lambda (group)
467 (or (gnus-gethash group gnus-newsrc-hashtb)
468 (gnus-gethash group gnus-killed-hashtb)))
469 not-in-list)
470 gnus-level-killed ?K regexp)))
417 471
418 ;; Use topics. 472 ;; Use topics.
419 (prog1 473 (prog1
420 (when (< lowest gnus-level-zombie) 474 (when (or (< lowest gnus-level-zombie)
475 gnus-group-listed-groups)
421 (if list-topic 476 (if list-topic
422 (let ((top (gnus-topic-find-topology list-topic))) 477 (let ((top (gnus-topic-find-topology list-topic)))
423 (gnus-topic-prepare-topic (cdr top) (car top) 478 (gnus-topic-prepare-topic (cdr top) (car top)
424 (or topic-level level) all 479 (or topic-level level) predicate
425 nil lowest)) 480 nil lowest regexp))
426 (gnus-topic-prepare-topic gnus-topic-topology 0 481 (gnus-topic-prepare-topic gnus-topic-topology 0
427 (or topic-level level) all 482 (or topic-level level) predicate
428 nil lowest))) 483 nil lowest regexp)))
429
430 (gnus-group-set-mode-line) 484 (gnus-group-set-mode-line)
431 (setq gnus-group-list-mode (cons level all)) 485 (setq gnus-group-list-mode (cons level predicate))
432 (gnus-run-hooks 'gnus-group-prepare-hook)))) 486 (gnus-run-hooks 'gnus-group-prepare-hook))))
433 487
434 (defun gnus-topic-prepare-topic (topicl level &optional list-level all silent 488 (defun gnus-topic-prepare-topic (topicl level &optional list-level
435 lowest) 489 predicate silent
490 lowest regexp)
436 "Insert TOPIC into the group buffer. 491 "Insert TOPIC into the group buffer.
437 If SILENT, don't insert anything. Return the number of unread 492 If SILENT, don't insert anything. Return the number of unread
438 articles in the topic and its subtopics." 493 articles in the topic and its subtopics."
439 (let* ((type (pop topicl)) 494 (let* ((type (pop topicl))
440 (entries (gnus-topic-find-groups 495 (entries (gnus-topic-find-groups
441 (car type) list-level 496 (car type)
442 (or all 497 (if gnus-group-listed-groups
498 gnus-level-killed
499 list-level)
500 (or predicate gnus-group-listed-groups
443 (cdr (assq 'visible 501 (cdr (assq 'visible
444 (gnus-topic-hierarchical-parameters 502 (gnus-topic-hierarchical-parameters
445 (car type))))) 503 (car type)))))
446 lowest)) 504 (if gnus-group-listed-groups 0 lowest)))
447 (visiblep (and (eq (nth 1 type) 'visible) (not silent))) 505 (visiblep (and (eq (nth 1 type) 'visible) (not silent)))
448 (gnus-group-indentation 506 (gnus-group-indentation
449 (make-string (* gnus-topic-indent-level level) ? )) 507 (make-string (* gnus-topic-indent-level level) ? ))
450 (beg (progn (beginning-of-line) (point))) 508 (beg (progn (beginning-of-line) (point)))
451 (topicl (reverse topicl)) 509 (topicl (reverse topicl))
456 info entry end active tick) 514 info entry end active tick)
457 ;; Insert any sub-topics. 515 ;; Insert any sub-topics.
458 (while topicl 516 (while topicl
459 (incf unread 517 (incf unread
460 (gnus-topic-prepare-topic 518 (gnus-topic-prepare-topic
461 (pop topicl) (1+ level) list-level all 519 (pop topicl) (1+ level) list-level predicate
462 (not visiblep) lowest))) 520 (not visiblep) lowest regexp)))
463 (setq end (point)) 521 (setq end (point))
464 (goto-char beg) 522 (goto-char beg)
465 ;; Insert all the groups that belong in this topic. 523 ;; Insert all the groups that belong in this topic.
466 (while (setq entry (pop entries)) 524 (while (setq entry (pop entries))
467 (when visiblep 525 (when (if (stringp entry)
468 (if (stringp entry) 526 (gnus-group-prepare-logic
469 ;; Dead groups. 527 entry
470 (gnus-group-insert-group-line 528 (and
471 entry (if (member entry gnus-zombie-list) 529 (or (not gnus-group-listed-groups)
472 gnus-level-zombie gnus-level-killed) 530 (if (< list-level gnus-level-zombie) nil
473 nil (- (1+ (cdr (setq active (gnus-active entry)))) 531 (let ((entry-level
474 (car active)) 532 (if (member entry gnus-zombie-list)
475 nil) 533 gnus-level-zombie gnus-level-killed)))
476 ;; Living groups. 534 (and (<= entry-level list-level)
477 (when (setq info (nth 2 entry)) 535 (>= entry-level lowest)))))
478 (gnus-group-insert-group-line 536 (cond
479 (gnus-info-group info) 537 ((stringp regexp)
480 (gnus-info-level info) (gnus-info-marks info) 538 (string-match regexp entry))
481 (car entry) (gnus-info-method info))))) 539 ((functionp regexp)
482 (when (and (listp entry) 540 (funcall regexp entry))
483 (numberp (car entry))) 541 ((null regexp) t)
484 (incf unread (car entry))) 542 (t nil))))
485 (when (listp entry) 543 (setq info (nth 2 entry))
486 (setq tick t))) 544 (gnus-group-prepare-logic
545 (gnus-info-group info)
546 (and (or (not gnus-group-listed-groups)
547 (let ((entry-level (gnus-info-level info)))
548 (and (<= entry-level list-level)
549 (>= entry-level lowest))))
550 (or (not (functionp predicate))
551 (funcall predicate info))
552 (or (not (stringp regexp))
553 (string-match regexp (gnus-info-group info))))))
554 (when visiblep
555 (if (stringp entry)
556 ;; Dead groups.
557 (gnus-group-insert-group-line
558 entry (if (member entry gnus-zombie-list)
559 gnus-level-zombie gnus-level-killed)
560 nil (- (1+ (cdr (setq active (gnus-active entry))))
561 (car active))
562 nil)
563 ;; Living groups.
564 (when (setq info (nth 2 entry))
565 (gnus-group-insert-group-line
566 (gnus-info-group info)
567 (gnus-info-level info) (gnus-info-marks info)
568 (car entry) (gnus-info-method info)))))
569 (when (and (listp entry)
570 (numberp (car entry)))
571 (incf unread (car entry)))
572 (when (listp entry)
573 (setq tick t))))
487 (goto-char beg) 574 (goto-char beg)
488 ;; Insert the topic line. 575 ;; Insert the topic line.
489 (when (and (not silent) 576 (when (and (not silent)
490 (or gnus-topic-display-empty-topics ;We want empty topics 577 (or gnus-topic-display-empty-topics ;We want empty topics
491 (not (zerop unread)) ;Non-empty 578 (not (zerop unread)) ;Non-empty
591 (defun gnus-topic-update-topic () 678 (defun gnus-topic-update-topic ()
592 "Update all parent topics to the current group." 679 "Update all parent topics to the current group."
593 (when (and (eq major-mode 'gnus-group-mode) 680 (when (and (eq major-mode 'gnus-group-mode)
594 gnus-topic-mode) 681 gnus-topic-mode)
595 (let ((group (gnus-group-group-name)) 682 (let ((group (gnus-group-group-name))
596 (m (point-marker)) 683 (m (point-marker))
597 (buffer-read-only nil)) 684 (buffer-read-only nil))
598 (when (and group 685 (when (and group
599 (gnus-get-info group) 686 (gnus-get-info group)
600 (gnus-topic-goto-topic (gnus-current-topic))) 687 (gnus-topic-goto-topic (gnus-current-topic)))
601 (gnus-topic-update-topic-line (gnus-group-topic-name)) 688 (gnus-topic-update-topic-line (gnus-group-topic-name))
609 (groups (cdr (assoc topic gnus-topic-alist))) 696 (groups (cdr (assoc topic gnus-topic-alist)))
610 (g (cdr (member group groups))) 697 (g (cdr (member group groups)))
611 (unfound t) 698 (unfound t)
612 entry) 699 entry)
613 ;; Try to jump to a visible group. 700 ;; Try to jump to a visible group.
614 (while (and g (not (gnus-group-goto-group (car g) t))) 701 (while (and g
702 (not (gnus-group-goto-group (car g) t)))
615 (pop g)) 703 (pop g))
616 ;; It wasn't visible, so we try to see where to insert it. 704 ;; It wasn't visible, so we try to see where to insert it.
617 (when (not g) 705 (when (not g)
618 (setq g (cdr (member group (reverse groups)))) 706 (setq g (cdr (member group (reverse groups))))
619 (while (and g unfound) 707 (while (and g unfound)
621 (forward-line 1) 709 (forward-line 1)
622 (setq unfound nil))) 710 (setq unfound nil)))
623 (when (and unfound 711 (when (and unfound
624 topic 712 topic
625 (not (gnus-topic-goto-missing-topic topic))) 713 (not (gnus-topic-goto-missing-topic topic)))
626 (let* ((top (gnus-topic-find-topology topic)) 714 (gnus-topic-display-missing-topic topic)))))
627 (children (cddr top)) 715
628 (type (cadr top)) 716 (defun gnus-topic-display-missing-topic (topic)
629 (unread 0) 717 "Insert topic lines recursively for missing topics."
630 (entries (gnus-topic-find-groups 718 (let ((parent (gnus-topic-find-topology
631 (car type) (car gnus-group-list-mode) 719 (gnus-topic-parent-topic topic))))
632 (cdr gnus-group-list-mode)))) 720 (when (and parent
633 (while children 721 (not (gnus-topic-goto-missing-topic (caadr parent))))
634 (incf unread (gnus-topic-unread (caar (pop children))))) 722 (gnus-topic-display-missing-topic (caadr parent))))
635 (while (setq entry (pop entries)) 723 (gnus-topic-goto-missing-topic topic)
636 (when (numberp (car entry)) 724 (let* ((top (gnus-topic-find-topology topic))
637 (incf unread (car entry)))) 725 (children (cddr top))
638 (gnus-topic-insert-topic-line 726 (type (cadr top))
639 topic t t (car (gnus-topic-find-topology topic)) nil unread)))))) 727 (unread 0)
728 (entries (gnus-topic-find-groups
729 (car type) (car gnus-group-list-mode)
730 (cdr gnus-group-list-mode)))
731 entry)
732 (while children
733 (incf unread (gnus-topic-unread (caar (pop children)))))
734 (while (setq entry (pop entries))
735 (when (numberp (car entry))
736 (incf unread (car entry))))
737 (gnus-topic-insert-topic-line
738 topic t t (car (gnus-topic-find-topology topic)) nil unread)))
640 739
641 (defun gnus-topic-goto-missing-topic (topic) 740 (defun gnus-topic-goto-missing-topic (topic)
642 (if (gnus-topic-goto-topic topic) 741 (if (gnus-topic-goto-topic topic)
643 (forward-line 1) 742 (forward-line 1)
644 ;; Topic not displayed. 743 ;; Topic not displayed.
828 (gnus-group-topic-level)) 927 (gnus-group-topic-level))
829 0)) 928 0))
830 ? )) 929 ? ))
831 (yanked (list group)) 930 (yanked (list group))
832 alist talist end) 931 alist talist end)
833 ;; Then we enter the yanked groups into the topics they belong 932 ;; Then we enter the yanked groups into the topics
834 ;; to. 933 ;; they belong to.
835 (when (setq alist (assoc (save-excursion 934 (when (setq alist (assoc (save-excursion
836 (forward-line -1) 935 (forward-line -1)
837 (or 936 (or
838 (gnus-current-topic) 937 (gnus-current-topic)
839 (caar gnus-topic-topology))) 938 (caar gnus-topic-topology)))
947 (gnus-define-keys gnus-topic-mode-map 1046 (gnus-define-keys gnus-topic-mode-map
948 "=" gnus-topic-select-group 1047 "=" gnus-topic-select-group
949 "\r" gnus-topic-select-group 1048 "\r" gnus-topic-select-group
950 " " gnus-topic-read-group 1049 " " gnus-topic-read-group
951 "\C-c\C-x" gnus-topic-expire-articles 1050 "\C-c\C-x" gnus-topic-expire-articles
1051 "c" gnus-topic-catchup-articles
952 "\C-k" gnus-topic-kill-group 1052 "\C-k" gnus-topic-kill-group
953 "\C-y" gnus-topic-yank-group 1053 "\C-y" gnus-topic-yank-group
954 "\M-g" gnus-topic-get-new-news-this-topic 1054 "\M-g" gnus-topic-get-new-news-this-topic
955 "AT" gnus-topic-list-active 1055 "AT" gnus-topic-list-active
956 "Gp" gnus-topic-edit-parameters 1056 "Gp" gnus-topic-edit-parameters
973 "h" gnus-topic-hide-topic 1073 "h" gnus-topic-hide-topic
974 "s" gnus-topic-show-topic 1074 "s" gnus-topic-show-topic
975 "j" gnus-topic-jump-to-topic 1075 "j" gnus-topic-jump-to-topic
976 "M" gnus-topic-move-matching 1076 "M" gnus-topic-move-matching
977 "C" gnus-topic-copy-matching 1077 "C" gnus-topic-copy-matching
1078 "\M-p" gnus-topic-goto-previous-topic
1079 "\M-n" gnus-topic-goto-next-topic
978 "\C-i" gnus-topic-indent 1080 "\C-i" gnus-topic-indent
979 [tab] gnus-topic-indent 1081 [tab] gnus-topic-indent
980 "r" gnus-topic-rename 1082 "r" gnus-topic-rename
981 "\177" gnus-topic-delete 1083 "\177" gnus-topic-delete
982 [delete] gnus-topic-delete 1084 [delete] gnus-topic-delete
985 (gnus-define-keys (gnus-topic-sort-map "S" gnus-group-topic-map) 1087 (gnus-define-keys (gnus-topic-sort-map "S" gnus-group-topic-map)
986 "s" gnus-topic-sort-groups 1088 "s" gnus-topic-sort-groups
987 "a" gnus-topic-sort-groups-by-alphabet 1089 "a" gnus-topic-sort-groups-by-alphabet
988 "u" gnus-topic-sort-groups-by-unread 1090 "u" gnus-topic-sort-groups-by-unread
989 "l" gnus-topic-sort-groups-by-level 1091 "l" gnus-topic-sort-groups-by-level
1092 "e" gnus-topic-sort-groups-by-server
990 "v" gnus-topic-sort-groups-by-score 1093 "v" gnus-topic-sort-groups-by-score
991 "r" gnus-topic-sort-groups-by-rank 1094 "r" gnus-topic-sort-groups-by-rank
992 "m" gnus-topic-sort-groups-by-method)) 1095 "m" gnus-topic-sort-groups-by-method))
993 1096
994 (defun gnus-topic-make-menu-bar () 1097 (defun gnus-topic-make-menu-bar ()
996 (easy-menu-define 1099 (easy-menu-define
997 gnus-topic-menu gnus-topic-mode-map "" 1100 gnus-topic-menu gnus-topic-mode-map ""
998 '("Topics" 1101 '("Topics"
999 ["Toggle topics" gnus-topic-mode t] 1102 ["Toggle topics" gnus-topic-mode t]
1000 ("Groups" 1103 ("Groups"
1001 ["Copy" gnus-topic-copy-group t] 1104 ["Copy..." gnus-topic-copy-group t]
1002 ["Move" gnus-topic-move-group t] 1105 ["Move..." gnus-topic-move-group t]
1003 ["Remove" gnus-topic-remove-group t] 1106 ["Remove" gnus-topic-remove-group t]
1004 ["Copy matching" gnus-topic-copy-matching t] 1107 ["Copy matching..." gnus-topic-copy-matching t]
1005 ["Move matching" gnus-topic-move-matching t]) 1108 ["Move matching..." gnus-topic-move-matching t])
1006 ("Topics" 1109 ("Topics"
1007 ["Goto" gnus-topic-jump-to-topic t] 1110 ["Goto..." gnus-topic-jump-to-topic t]
1008 ["Show" gnus-topic-show-topic t] 1111 ["Show" gnus-topic-show-topic t]
1009 ["Hide" gnus-topic-hide-topic t] 1112 ["Hide" gnus-topic-hide-topic t]
1010 ["Delete" gnus-topic-delete t] 1113 ["Delete" gnus-topic-delete t]
1011 ["Rename" gnus-topic-rename t] 1114 ["Rename..." gnus-topic-rename t]
1012 ["Create" gnus-topic-create-topic t] 1115 ["Create..." gnus-topic-create-topic t]
1013 ["Mark" gnus-topic-mark-topic t] 1116 ["Mark" gnus-topic-mark-topic t]
1014 ["Indent" gnus-topic-indent t] 1117 ["Indent" gnus-topic-indent t]
1015 ["Sort" gnus-topic-sort-topics t] 1118 ["Sort" gnus-topic-sort-topics t]
1119 ["Previous topic" gnus-topic-goto-previous-topic t]
1120 ["Next topic" gnus-topic-goto-next-topic t]
1016 ["Toggle hide empty" gnus-topic-toggle-display-empty-topics t] 1121 ["Toggle hide empty" gnus-topic-toggle-display-empty-topics t]
1017 ["Edit parameters" gnus-topic-edit-parameters t]) 1122 ["Edit parameters" gnus-topic-edit-parameters t])
1018 ["List active" gnus-topic-list-active t])))) 1123 ["List active" gnus-topic-list-active t]))))
1019 1124
1020 (defun gnus-topic-mode (&optional arg redisplay) 1125 (defun gnus-topic-mode (&optional arg redisplay)
1025 (setq gnus-topic-mode 1130 (setq gnus-topic-mode
1026 (if (null arg) (not gnus-topic-mode) 1131 (if (null arg) (not gnus-topic-mode)
1027 (> (prefix-numeric-value arg) 0))) 1132 (> (prefix-numeric-value arg) 0)))
1028 ;; Infest Gnus with topics. 1133 ;; Infest Gnus with topics.
1029 (if (not gnus-topic-mode) 1134 (if (not gnus-topic-mode)
1030 (setq gnus-goto-missing-group-function nil) 1135 (setq gnus-goto-missing-group-function nil)
1031 (when (gnus-visual-p 'topic-menu 'menu) 1136 (when (gnus-visual-p 'topic-menu 'menu)
1032 (gnus-topic-make-menu-bar)) 1137 (gnus-topic-make-menu-bar))
1033 (gnus-set-format 'topic t) 1138 (gnus-set-format 'topic t)
1034 (gnus-add-minor-mode 'gnus-topic-mode " Topic" 1139 (gnus-add-minor-mode 'gnus-topic-mode " Topic"
1035 gnus-topic-mode-map nil (lambda (&rest junk) 1140 gnus-topic-mode-map nil (lambda (&rest junk)
1048 'gnus-topic-update-topics-containing-group) 1153 'gnus-topic-update-topics-containing-group)
1049 (set (make-local-variable 'gnus-group-sort-alist-function) 1154 (set (make-local-variable 'gnus-group-sort-alist-function)
1050 'gnus-group-sort-topic) 1155 'gnus-group-sort-topic)
1051 (setq gnus-group-change-level-function 'gnus-topic-change-level) 1156 (setq gnus-group-change-level-function 'gnus-topic-change-level)
1052 (setq gnus-goto-missing-group-function 'gnus-topic-goto-missing-group) 1157 (setq gnus-goto-missing-group-function 'gnus-topic-goto-missing-group)
1053 (make-local-hook 'gnus-check-bogus-groups-hook) 1158 (gnus-make-local-hook 'gnus-check-bogus-groups-hook)
1054 (add-hook 'gnus-check-bogus-groups-hook 'gnus-topic-clean-alist) 1159 (add-hook 'gnus-check-bogus-groups-hook 'gnus-topic-clean-alist
1160 nil 'local)
1055 (setq gnus-topology-checked-p nil) 1161 (setq gnus-topology-checked-p nil)
1056 ;; We check the topology. 1162 ;; We check the topology.
1057 (when gnus-newsrc-alist 1163 (when gnus-newsrc-alist
1058 (gnus-topic-check-topology)) 1164 (gnus-topic-check-topology))
1059 (gnus-run-hooks 'gnus-topic-mode-hook)) 1165 (gnus-run-hooks 'gnus-topic-mode-hook))
1068 (gnus-group-list-groups)))) 1174 (gnus-group-list-groups))))
1069 1175
1070 (defun gnus-topic-select-group (&optional all) 1176 (defun gnus-topic-select-group (&optional all)
1071 "Select this newsgroup. 1177 "Select this newsgroup.
1072 No article is selected automatically. 1178 No article is selected automatically.
1179 If the group is opened, just switch the summary buffer.
1073 If ALL is non-nil, already read articles become readable. 1180 If ALL is non-nil, already read articles become readable.
1074 If ALL is a number, fetch this number of articles. 1181 If ALL is a number, fetch this number of articles.
1075 1182
1076 If performed over a topic line, toggle folding the topic." 1183 If performed over a topic line, toggle folding the topic."
1077 (interactive "P") 1184 (interactive "P")
1185 (when (and (eobp) (not (gnus-group-group-name)))
1186 (forward-line -1))
1078 (if (gnus-group-topic-p) 1187 (if (gnus-group-topic-p)
1079 (let ((gnus-group-list-mode 1188 (let ((gnus-group-list-mode
1080 (if all (cons (if (numberp all) all 7) t) gnus-group-list-mode))) 1189 (if all (cons (if (numberp all) all 7) t) gnus-group-list-mode)))
1081 (gnus-topic-fold all) 1190 (gnus-topic-fold all)
1082 (gnus-dribble-touch)) 1191 (gnus-dribble-touch))
1095 (call-interactively 'gnus-group-expire-articles) 1204 (call-interactively 'gnus-group-expire-articles)
1096 (save-excursion 1205 (save-excursion
1097 (gnus-message 5 "Expiring groups in %s..." topic) 1206 (gnus-message 5 "Expiring groups in %s..." topic)
1098 (let ((gnus-group-marked 1207 (let ((gnus-group-marked
1099 (mapcar (lambda (entry) (car (nth 2 entry))) 1208 (mapcar (lambda (entry) (car (nth 2 entry)))
1100 (gnus-topic-find-groups topic gnus-level-killed t)))) 1209 (gnus-topic-find-groups topic gnus-level-killed t
1210 nil t))))
1101 (gnus-group-expire-articles nil)) 1211 (gnus-group-expire-articles nil))
1102 (gnus-message 5 "Expiring groups in %s...done" topic)))) 1212 (gnus-message 5 "Expiring groups in %s...done" topic))))
1213
1214 (defun gnus-topic-catchup-articles (topic)
1215 "Catchup this topic or group.
1216 Also see `gnus-group-catchup'."
1217 (interactive (list (gnus-group-topic-name)))
1218 (if (not topic)
1219 (call-interactively 'gnus-group-catchup-current)
1220 (save-excursion
1221 (let* ((groups
1222 (mapcar (lambda (entry) (car (nth 2 entry)))
1223 (gnus-topic-find-groups topic gnus-level-killed t
1224 nil t)))
1225 (buffer-read-only nil)
1226 (gnus-group-marked groups))
1227 (gnus-group-catchup-current)
1228 (mapcar 'gnus-topic-update-topics-containing-group groups)))))
1103 1229
1104 (defun gnus-topic-read-group (&optional all no-article group) 1230 (defun gnus-topic-read-group (&optional all no-article group)
1105 "Read news in this newsgroup. 1231 "Read news in this newsgroup.
1106 If the prefix argument ALL is non-nil, already read articles become 1232 If the prefix argument ALL is non-nil, already read articles become
1107 readable. IF ALL is a number, fetch this number of articles. If the 1233 readable. IF ALL is a number, fetch this number of articles. If the
1155 (defun gnus-topic-move-group (n topic &optional copyp) 1281 (defun gnus-topic-move-group (n topic &optional copyp)
1156 "Move the next N groups to TOPIC. 1282 "Move the next N groups to TOPIC.
1157 If COPYP, copy the groups instead." 1283 If COPYP, copy the groups instead."
1158 (interactive 1284 (interactive
1159 (list current-prefix-arg 1285 (list current-prefix-arg
1160 (completing-read "Move to topic: " gnus-topic-alist nil t))) 1286 (gnus-completing-read "Move to topic" gnus-topic-alist nil t
1287 'gnus-topic-history)))
1161 (let ((use-marked (and (not n) (not (gnus-region-active-p)) 1288 (let ((use-marked (and (not n) (not (gnus-region-active-p))
1162 gnus-group-marked t)) 1289 gnus-group-marked t))
1163 (groups (gnus-group-process-prefix n)) 1290 (groups (gnus-group-process-prefix n))
1164 (topicl (assoc topic gnus-topic-alist)) 1291 (topicl (assoc topic gnus-topic-alist))
1165 (start-topic (gnus-group-topic-name)) 1292 (start-topic (gnus-group-topic-name))
1301 (completing-read "Show topic: " gnus-topic-alist nil t)))) 1428 (completing-read "Show topic: " gnus-topic-alist nil t))))
1302 (setcar (cddr (cadr topic)) nil) 1429 (setcar (cddr (cadr topic)) nil)
1303 (setcar (cdr (cadr topic)) 'visible) 1430 (setcar (cdr (cadr topic)) 'visible)
1304 (gnus-group-list-groups))))) 1431 (gnus-group-list-groups)))))
1305 1432
1306 (defun gnus-topic-mark-topic (topic &optional unmark recursive) 1433 (defun gnus-topic-mark-topic (topic &optional unmark non-recursive)
1307 "Mark all groups in the TOPIC with the process mark. 1434 "Mark all groups in the TOPIC with the process mark.
1308 If RECURSIVE is t, mark its subtopics too." 1435 If NON-RECURSIVE (which is the prefix) is t, don't mark its subtopics."
1309 (interactive (list (gnus-group-topic-name) 1436 (interactive (list (gnus-group-topic-name)
1310 nil 1437 nil
1311 (and current-prefix-arg t))) 1438 (and current-prefix-arg t)))
1312 (if (not topic) 1439 (if (not topic)
1313 (call-interactively 'gnus-group-mark-group) 1440 (call-interactively 'gnus-group-mark-group)
1314 (save-excursion 1441 (save-excursion
1315 (let ((groups (gnus-topic-find-groups topic gnus-level-killed t nil 1442 (let ((groups (gnus-topic-find-groups topic gnus-level-killed t nil
1316 recursive))) 1443 (not non-recursive))))
1317 (while groups 1444 (while groups
1318 (funcall (if unmark 'gnus-group-remove-mark 'gnus-group-set-mark) 1445 (funcall (if unmark 'gnus-group-remove-mark 'gnus-group-set-mark)
1319 (gnus-info-group (nth 2 (pop groups))))))))) 1446 (gnus-info-group (nth 2 (pop groups)))))))))
1320 1447
1321 (defun gnus-topic-unmark-topic (topic &optional dummy recursive) 1448 (defun gnus-topic-unmark-topic (topic &optional dummy non-recursive)
1322 "Remove the process mark from all groups in the TOPIC. 1449 "Remove the process mark from all groups in the TOPIC.
1323 If RECURSIVE is t, unmark its subtopics too." 1450 If NON-RECURSIVE (which is the prefix) is t, don't unmark its subtopics."
1324 (interactive (list (gnus-group-topic-name) 1451 (interactive (list (gnus-group-topic-name)
1325 nil 1452 nil
1326 (and current-prefix-arg t))) 1453 (and current-prefix-arg t)))
1327 (if (not topic) 1454 (if (not topic)
1328 (call-interactively 'gnus-group-unmark-group) 1455 (call-interactively 'gnus-group-unmark-group)
1329 (gnus-topic-mark-topic topic t recursive))) 1456 (gnus-topic-mark-topic topic t non-recursive)))
1330 1457
1331 (defun gnus-topic-get-new-news-this-topic (&optional n) 1458 (defun gnus-topic-get-new-news-this-topic (&optional n)
1332 "Check for new news in the current topic." 1459 "Check for new news in the current topic."
1333 (interactive "P") 1460 (interactive "P")
1334 (if (not (gnus-group-topic-p)) 1461 (if (not (gnus-group-topic-p))
1335 (gnus-group-get-new-news-this-group n) 1462 (gnus-group-get-new-news-this-group n)
1336 (gnus-topic-mark-topic (gnus-group-topic-name) nil (and n t)) 1463 (let* ((topic (gnus-group-topic-name))
1337 (gnus-group-get-new-news-this-group))) 1464 (data (cadr (gnus-topic-find-topology topic))))
1465 (save-excursion
1466 (gnus-topic-mark-topic topic nil (and n t))
1467 (gnus-group-get-new-news-this-group))
1468 (gnus-topic-remove-topic (eq 'visible (cadr data))))))
1338 1469
1339 (defun gnus-topic-move-matching (regexp topic &optional copyp) 1470 (defun gnus-topic-move-matching (regexp topic &optional copyp)
1340 "Move all groups that match REGEXP to some topic." 1471 "Move all groups that match REGEXP to some topic."
1341 (interactive 1472 (interactive
1342 (let (topic) 1473 (let (topic)
1378 (defun gnus-topic-rename (old-name new-name) 1509 (defun gnus-topic-rename (old-name new-name)
1379 "Rename a topic." 1510 "Rename a topic."
1380 (interactive 1511 (interactive
1381 (let ((topic (gnus-current-topic))) 1512 (let ((topic (gnus-current-topic)))
1382 (list topic 1513 (list topic
1383 (read-string (format "Rename %s to: " topic))))) 1514 (read-string (format "Rename %s to: " topic) topic))))
1384 ;; Check whether the new name exists. 1515 ;; Check whether the new name exists.
1385 (when (gnus-topic-find-topology new-name) 1516 (when (gnus-topic-find-topology new-name)
1386 (error "Topic '%s' already exists" new-name)) 1517 (error "Topic '%s' already exists" new-name))
1387 ;; "nil" is an invalid name, for reasons I'd rather not go 1518 ;; "nil" is an invalid name, for reasons I'd rather not go
1388 ;; into here. Trust me. 1519 ;; into here. Trust me.
1550 "Sort the current topic alphabetically by backend name. 1681 "Sort the current topic alphabetically by backend name.
1551 If REVERSE, sort in reverse order." 1682 If REVERSE, sort in reverse order."
1552 (interactive "P") 1683 (interactive "P")
1553 (gnus-topic-sort-groups 'gnus-group-sort-by-method reverse)) 1684 (gnus-topic-sort-groups 'gnus-group-sort-by-method reverse))
1554 1685
1686 (defun gnus-topic-sort-groups-by-server (&optional reverse)
1687 "Sort the current topic alphabetically by server name.
1688 If REVERSE, sort in reverse order."
1689 (interactive "P")
1690 (gnus-topic-sort-groups 'gnus-group-sort-by-server reverse))
1691
1555 (defun gnus-topic-sort-topics-1 (top reverse) 1692 (defun gnus-topic-sort-topics-1 (top reverse)
1556 (if (cdr top) 1693 (if (cdr top)
1557 (let ((subtop 1694 (let ((subtop
1558 (mapcar `(lambda (top) 1695 (mapcar (gnus-byte-compile
1559 (gnus-topic-sort-topics-1 top ,reverse)) 1696 `(lambda (top)
1697 (gnus-topic-sort-topics-1 top ,reverse)))
1560 (sort (cdr top) 1698 (sort (cdr top)
1561 '(lambda (t1 t2) 1699 (lambda (t1 t2)
1562 (string-lessp (caar t1) (caar t2))))))) 1700 (string-lessp (caar t1) (caar t2)))))))
1563 (setcdr top (if reverse (reverse subtop) subtop)))) 1701 (setcdr top (if reverse (reverse subtop) subtop))))
1564 top) 1702 top)
1565 1703
1566 (defun gnus-topic-sort-topics (&optional topic reverse) 1704 (defun gnus-topic-sort-topics (&optional topic reverse)
1567 "Sort topics in TOPIC alphabetically by topic name. 1705 "Sort topics in TOPIC alphabetically by topic name.
1610 (string-match match newsgroup)) 1748 (string-match match newsgroup))
1611 ;; Just subscribe the group. 1749 ;; Just subscribe the group.
1612 (gnus-subscribe-alphabetically newsgroup) 1750 (gnus-subscribe-alphabetically newsgroup)
1613 ;; Add the group to the topic. 1751 ;; Add the group to the topic.
1614 (nconc (assoc topic gnus-topic-alist) (list newsgroup)) 1752 (nconc (assoc topic gnus-topic-alist) (list newsgroup))
1615 (throw 'end t)))))) 1753 ;; if this topic specifies a default level, use it
1754 (let ((subscribe-level (cdr (assq 'subscribe-level
1755 (gnus-topic-parameters topic)))))
1756 (when subscribe-level
1757 (gnus-group-change-level newsgroup subscribe-level
1758 gnus-level-default-subscribed)))
1759 (throw 'end t)))
1760 nil)))
1616 1761
1617 (provide 'gnus-topic) 1762 (provide 'gnus-topic)
1618 1763
1619 ;;; arch-tag: bf176856-f30c-40f0-ae77-e41529a1134c 1764 ;;; arch-tag: bf176856-f30c-40f0-ae77-e41529a1134c
1620 ;;; gnus-topic.el ends here 1765 ;;; gnus-topic.el ends here