X-Git-Url: http://cgit.sxemacs.org/?p=gnus;a=blobdiff_plain;f=lisp%2Fgnus-group.el;h=c0a1cfc136fe2a3d171716002af419d3cf9c4ca6;hp=535641c293d2f9a430335ea58e1301904b373d10;hb=c9a393eeb329a99695566342a9f03b8a30000898;hpb=a467d2cec1faed6953e68a21ad144fbe90d29fdc diff --git a/lisp/gnus-group.el b/lisp/gnus-group.el index 535641c29..c0a1cfc13 100644 --- a/lisp/gnus-group.el +++ b/lisp/gnus-group.el @@ -1,35 +1,37 @@ ;;; gnus-group.el --- group mode commands for Gnus ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -;; 2005 Free Software Foundation, Inc. +;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen ;; Keywords: news ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: +;; For Emacs < 22.2. +(eval-and-compile + (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))) + (eval-when-compile - (require 'cl) - (defvar tool-bar-map)) + (require 'cl)) +(defvar tool-bar-mode) (require 'gnus) (require 'gnus-start) @@ -39,6 +41,7 @@ (require 'gnus-range) (require 'gnus-win) (require 'gnus-undo) +(require 'gmm-utils) (require 'time-date) (require 'gnus-ems) @@ -107,6 +110,18 @@ If nil, no groups are permanently visible." :group 'gnus-group-listing :type '(choice regexp (const nil))) +(defcustom gnus-safe-html-newsgroups "\\`nnrss[+:]" + "Groups in which links in html articles are considered all safe. +The value may be a regexp matching those groups, a list of group names, +or nil. This overrides `mm-w3m-safe-url-regexp' (which see). This is +effective only when emacs-w3m renders html articles, i.e., in the case +`mm-text-html-renderer' is set to `w3m'." + :version "23.2" + :group 'gnus-group-various + :type '(choice regexp + (repeat :tag "List of group names" (string :tag "Group")) + (const nil))) + (defcustom gnus-list-groups-with-ticked-articles t "*If non-nil, list groups that have only ticked articles. If nil, only list groups that have unread articles." @@ -134,7 +149,7 @@ for the groups to be sorted. Pre-made functions include `gnus-group-sort-by-score', `gnus-group-sort-by-method', `gnus-group-sort-by-server', and `gnus-group-sort-by-rank'. -This variable can also be a list of sorting functions. In that case, +This variable can also be a list of sorting functions. In that case, the most significant sort function should be the last function in the list." :group 'gnus-group-listing @@ -196,7 +211,7 @@ with some simple extensions. Note that this format specification is not always respected. For reasons of efficiency, when listing killed groups, this specification -is ignored altogether. If the spec is changed considerably, your +is ignored altogether. If the spec is changed considerably, your output may end up looking strange when listing both alive and killed groups. @@ -288,14 +303,15 @@ variable." :type 'hook) (defcustom gnus-useful-groups - '(("(ding) mailing list mirrored at sunsite.auc.dk" - "emacs.ding" - (nntp "sunsite.auc.dk" - (nntp-address "sunsite.auc.dk"))) - ("gnus-bug archive" - "gnus-bug" - (nndir "/ftp@ftp.ifi.uio.no:/pub/emacs/gnus/gnus-bug/")) - ("Gnus help group" + '(("(ding) mailing list mirrored at gmane.org" + "gmane.emacs.gnus.general" + (nntp "Gmane" + (nntp-address "news.gmane.org"))) + ("Gnus bug archive" + "gnus.gnus-bug" + (nntp "news.gnus.org" + (nntp-address "news.gnus.org"))) + ("Local Gnus help group" "gnus-help" (nndoc "gnus-help" (nndoc-article-type mbox) @@ -380,6 +396,7 @@ score: The score of the group. ticked: The number of ticked articles." :group 'gnus-group-visual :type '(repeat (cons (sexp :tag "Form") face))) +(put 'gnus-group-highlight 'risky-local-variable t) (defcustom gnus-new-mail-mark ?% "Mark used for groups with new mail." @@ -417,6 +434,7 @@ score: The score of the group. ticked: The number of ticked articles." :group 'gnus-group-icons :type '(repeat (cons (sexp :tag "Form") file))) +(put 'gnus-group-icon-list 'risky-local-variable t) (defcustom gnus-group-name-charset-method-alist nil "Alist of method and the charset for group names. @@ -642,7 +660,6 @@ simple manner.") "h" gnus-group-make-help-group "u" gnus-group-make-useful-group "a" gnus-group-make-archive-group - "k" gnus-group-make-kiboze-group "l" gnus-group-nnimap-edit-acl "m" gnus-group-make-group "E" gnus-group-edit-group @@ -662,13 +679,6 @@ simple manner.") "\177" gnus-group-delete-group [delete] gnus-group-delete-group) -(gnus-define-keys (gnus-group-soup-map "s" gnus-group-group-map) - "b" gnus-group-brew-soup - "w" gnus-soup-save-areas - "s" gnus-soup-send-replies - "p" gnus-soup-pack-packet - "r" nnsoup-pack-replies) - (gnus-define-keys (gnus-group-sort-map "S" gnus-group-group-map) "s" gnus-group-sort-groups "a" gnus-group-sort-groups-by-alphabet @@ -920,7 +930,6 @@ simple manner.") ["Add the archive group" gnus-group-make-archive-group t] ["Make a doc group..." gnus-group-make-doc-group t] ["Make a web group..." gnus-group-make-web-group t] - ["Make a kiboze group..." gnus-group-make-kiboze-group t] ["Make a virtual group..." gnus-group-make-empty-virtual t] ["Add a group to a virtual..." gnus-group-add-to-virtual t] ["Make an ephemeral group..." gnus-group-read-ephemeral-group t] @@ -954,13 +963,6 @@ simple manner.") (easy-menu-define gnus-group-misc-menu gnus-group-mode-map "" `("Gnus" - ("SOUP" - ["Pack replies" nnsoup-pack-replies (fboundp 'nnsoup-request-group)] - ["Send replies" gnus-soup-send-replies - (fboundp 'gnus-soup-pack-packet)] - ["Pack packet" gnus-soup-pack-packet (fboundp 'gnus-soup-pack-packet)] - ["Save areas" gnus-soup-save-areas (fboundp 'gnus-soup-pack-packet)] - ["Brew SOUP" gnus-group-brew-soup (fboundp 'gnus-soup-pack-packet)]) ["Send a mail" gnus-group-mail t] ["Send a message (mail or news)" gnus-group-post-news t] ["Create a local message" gnus-group-news t] @@ -978,7 +980,6 @@ simple manner.") ["Browse foreign server..." gnus-group-browse-foreign-server t] ["Enter server buffer" gnus-group-enter-server-mode t] ["Expire all expirable articles" gnus-group-expire-all-groups t] - ["Generate any kiboze groups" nnkiboze-generate-groups t] ["Gnus version" gnus-version t] ["Save .newsrc files" gnus-group-save-newsrc t] ["Suspend Gnus" gnus-group-suspend t] @@ -994,43 +995,145 @@ simple manner.") (gnus-run-hooks 'gnus-group-menu-hook))) -(defvar gnus-group-toolbar-map nil) - -;; Emacs 21 tool bar. Should be no-op otherwise. -(defun gnus-group-make-tool-bar () - (if (and - (condition-case nil (require 'tool-bar) (error nil)) - (fboundp 'tool-bar-add-item-from-menu) - (default-value 'tool-bar-mode) - (not gnus-group-toolbar-map)) - (setq gnus-group-toolbar-map - (let ((tool-bar-map (make-sparse-keymap)) - (load-path (mm-image-load-path))) - (tool-bar-add-item-from-menu - 'gnus-group-get-new-news "get-news" gnus-group-mode-map) - (tool-bar-add-item-from-menu - 'gnus-group-get-new-news-this-group "gnntg" gnus-group-mode-map) - (tool-bar-add-item-from-menu - 'gnus-group-catchup-current "catchup" gnus-group-mode-map) - (tool-bar-add-item-from-menu - 'gnus-group-describe-group "describe-group" gnus-group-mode-map) - (tool-bar-add-item "subscribe" 'gnus-group-subscribe 'subscribe - :help "Subscribe to the current group") - (tool-bar-add-item "unsubscribe" 'gnus-group-unsubscribe - 'unsubscribe - :help "Unsubscribe from the current group") - (tool-bar-add-item-from-menu - 'gnus-group-exit "exit-gnus" gnus-group-mode-map) - tool-bar-map))) - (if gnus-group-toolbar-map - (set (make-local-variable 'tool-bar-map) gnus-group-toolbar-map))) + +(defvar gnus-group-tool-bar-map nil) + +(defun gnus-group-tool-bar-update (&optional symbol value) + "Update group buffer toolbar. +Setter function for custom variables." + (when symbol + (set-default symbol value)) + ;; (setq-default gnus-group-tool-bar-map nil) + ;; (use-local-map gnus-group-mode-map) + (when (gnus-alive-p) + (with-current-buffer gnus-group-buffer + (gnus-group-make-tool-bar t)))) + +(defcustom gnus-group-tool-bar (if (eq gmm-tool-bar-style 'gnome) + 'gnus-group-tool-bar-gnome + 'gnus-group-tool-bar-retro) + "Specifies the Gnus group tool bar. + +It can be either a list or a symbol refering to a list. See +`gmm-tool-bar-from-list' for the format of the list. The +default key map is `gnus-group-mode-map'. + +Pre-defined symbols include `gnus-group-tool-bar-gnome' and +`gnus-group-tool-bar-retro'." + :type '(choice (const :tag "GNOME style" gnus-group-tool-bar-gnome) + (const :tag "Retro look" gnus-group-tool-bar-retro) + (repeat :tag "User defined list" gmm-tool-bar-item) + (symbol)) + :version "23.1" ;; No Gnus + :initialize 'custom-initialize-default + :set 'gnus-group-tool-bar-update + :group 'gnus-group) + +(defcustom gnus-group-tool-bar-gnome + '((gnus-group-post-news "mail/compose") + ;; Some useful agent icons? I don't use the agent so agent users should + ;; suggest useful commands: + (gnus-agent-toggle-plugged "disconnect" t + :help "Gnus is currently unplugged. Click to work online." + :visible (and gnus-agent (not gnus-plugged))) + (gnus-agent-toggle-plugged "connect" t + :help "Gnus is currently plugged. Click to work offline." + :visible (and gnus-agent gnus-plugged)) + ;; FIXME: gnus-agent-toggle-plugged (in gnus-agent-group-make-menu-bar) + ;; should have a better help text. + (gnus-group-send-queue "mail/outbox" t + :visible (and gnus-agent gnus-plugged) + :help "Send articles from the queue group") + (gnus-group-get-new-news "mail/inbox" nil + :visible (or (not gnus-agent) + gnus-plugged)) + ;; FIXME: gnus-*-read-group should have a better help text. + (gnus-topic-read-group "open" nil + :visible (and (boundp 'gnus-topic-mode) + gnus-topic-mode)) + (gnus-group-read-group "open" nil + :visible (not (and (boundp 'gnus-topic-mode) + gnus-topic-mode))) + ;; (gnus-group-find-new-groups "???" nil) + (gnus-group-save-newsrc "save") + (gnus-group-describe-group "describe") + (gnus-group-unsubscribe-current-group "gnus/toggle-subscription") + (gnus-group-prev-unread-group "left-arrow") + (gnus-group-next-unread-group "right-arrow") + (gnus-group-exit "exit") + (gmm-customize-mode "preferences" t :help "Edit mode preferences") + (gnus-info-find-node "help")) + "List of functions for the group tool bar (GNOME style). + +See `gmm-tool-bar-from-list' for the format of the list." + :type '(repeat gmm-tool-bar-item) + :version "23.1" ;; No Gnus + :initialize 'custom-initialize-default + :set 'gnus-group-tool-bar-update + :group 'gnus-group) + +(defcustom gnus-group-tool-bar-retro + '((gnus-group-get-new-news "gnus/get-news") + (gnus-group-get-new-news-this-group "gnus/gnntg") + (gnus-group-catchup-current "gnus/catchup") + (gnus-group-describe-group "gnus/describe-group") + (gnus-group-subscribe "gnus/subscribe" t + :help "Subscribe to the current group") + (gnus-group-unsubscribe "gnus/unsubscribe" t + :help "Unsubscribe from the current group") + (gnus-group-exit "gnus/exit-gnus" gnus-group-mode-map)) + "List of functions for the group tool bar (retro look). + +See `gmm-tool-bar-from-list' for the format of the list." + :type '(repeat gmm-tool-bar-item) + :version "23.1" ;; No Gnus + :initialize 'custom-initialize-default + :set 'gnus-group-tool-bar-update + :group 'gnus-group) + +(defcustom gnus-group-tool-bar-zap-list t + "List of icon items from the global tool bar. +These items are not displayed in the Gnus group mode tool bar. + +See `gmm-tool-bar-from-list' for the format of the list." + :type 'gmm-tool-bar-zap-list + :version "23.1" ;; No Gnus + :initialize 'custom-initialize-default + :set 'gnus-group-tool-bar-update + :group 'gnus-group) + +(defvar image-load-path) +(defvar tool-bar-map) + +(defun gnus-group-make-tool-bar (&optional force) + "Make a group mode tool bar from `gnus-group-tool-bar'. +When FORCE, rebuild the tool bar." + (when (and (not (featurep 'xemacs)) + (boundp 'tool-bar-mode) + tool-bar-mode + ;; The Gnus 5.10.6 code checked (default-value 'tool-bar-mode). + ;; Why? --rsteib + (or (not gnus-group-tool-bar-map) force)) + (let* ((load-path + (gmm-image-load-path-for-library "gnus" + "gnus/toggle-subscription.xpm" + nil t)) + (image-load-path (cons (car load-path) + (when (boundp 'image-load-path) + image-load-path))) + (map (gmm-tool-bar-from-list gnus-group-tool-bar + gnus-group-tool-bar-zap-list + 'gnus-group-mode-map))) + (if map + (set (make-local-variable 'tool-bar-map) map)))) + gnus-group-tool-bar-map) (defun gnus-group-mode () "Major mode for reading news. All normal editing commands are switched off. \\ -The group buffer lists (some of) the groups available. For instance, +The group buffer lists (some of) the groups available. For instance, `\\[gnus-group-list-groups]' will list all subscribed groups with unread articles, while `\\[gnus-group-list-zombies]' lists all zombie groups. @@ -1079,8 +1182,8 @@ The following commands are available: (goto-char (point-min)) (setq gnus-group-mark-positions (list (cons 'process (and (search-forward - (mm-string-as-multibyte "\200") nil t) - (- (point) 2)))))))) + (mm-string-to-multibyte "\200") nil t) + (- (point) (point-min) 1)))))))) (defun gnus-mouse-pick-group (e) "Enter the group under the mouse pointer." @@ -1115,7 +1218,10 @@ The following commands are available: (defun gnus-group-name-charset (method group) (if (null method) (setq method (gnus-find-method-for-group group))) - (let ((item (assoc method gnus-group-name-charset-method-alist)) + (let ((item (or (assoc method gnus-group-name-charset-method-alist) + (and (consp method) + (assoc (list (car method) (cadr method)) + gnus-group-name-charset-method-alist)))) (alist gnus-group-name-charset-group-alist) result) (if item @@ -1249,7 +1355,8 @@ if it is a string, only list groups matching REGEXP." (setq not-in-list (delete group not-in-list))) (when (gnus-group-prepare-logic group - (and unread ; This group might be unchecked + (and (or unread ; This group might be unchecked + predicate) ; Check if this group should be listed (or (not (stringp regexp)) (string-match regexp group)) (<= (setq clevel (gnus-info-level info)) level) @@ -1263,7 +1370,7 @@ if it is a string, only list groups matching REGEXP." (if (eq unread t) ; Unactivated? gnus-group-list-inactive-groups ; We list unactivated - (> unread 0)) + (and (numberp unread) (> unread 0))) ; We list groups with unread articles (and gnus-list-groups-with-ticked-articles (cdr (assq 'tick (gnus-info-marks info)))) @@ -1395,6 +1502,36 @@ if it is a string, only list groups matching REGEXP." (gnus-range-difference (list active) (gnus-info-read info)) seen)))))) +;; Moving through the Group buffer (in topic mode) e.g. with C-n doesn't +;; update the state (enabled/disabled) of the icon `gnus-group-describe-group' +;; automatically. After `C-l' the state is correct. See the following report +;; on emacs-devel +;; : +;; From: Reiner Steib +;; Subject: tool bar icons not updated according to :active condition +;; Newsgroups: gmane.emacs.devel +;; Date: Mon, 23 Jan 2006 19:59:13 +0100 +;; Message-ID: + +(defcustom gnus-group-update-tool-bar + (and (not (featurep 'xemacs)) + (boundp 'tool-bar-mode) + tool-bar-mode + ;; Using `redraw-frame' (see `gnus-tool-bar-update') in Emacs 21 might + ;; be confusing, so maybe we shouldn't call it by default. + (fboundp 'force-window-update)) + "Force updating the group buffer tool bar." + :group 'gnus-group + :version "22.1" + :initialize 'custom-initialize-default + :set (lambda (symbol value) + (set-default symbol value) + (when (gnus-alive-p) + (with-current-buffer gnus-group-buffer + ;; FIXME: Is there a better way to redraw the group buffer? + (gnus-group-get-new-news 0)))) + :type 'boolean) + (defun gnus-group-insert-group-line (gnus-tmp-group gnus-tmp-level gnus-tmp-marked number gnus-tmp-method) @@ -1459,8 +1596,10 @@ if it is a string, only list groups matching REGEXP." (if (member gnus-tmp-group gnus-group-marked) gnus-process-mark ? )) (buffer-read-only nil) + beg end header gnus-tmp-header) ; passed as parameter to user-funcs. (beginning-of-line) + (setq beg (point)) (gnus-add-text-properties (point) (prog1 (1+ (point)) @@ -1475,6 +1614,12 @@ if it is a string, only list groups matching REGEXP." gnus-marked ,gnus-tmp-marked-mark gnus-indentation ,gnus-group-indentation gnus-level ,gnus-tmp-level)) + (setq end (point)) + (when gnus-group-update-tool-bar + (gnus-put-text-property beg end 'point-entered + 'gnus-tool-bar-update) + (gnus-put-text-property beg end 'point-left + 'gnus-tool-bar-update)) (forward-line -1) (when (inline (gnus-visual-p 'group-highlight 'highlight)) (gnus-run-hooks 'gnus-group-update-hook)) @@ -1509,6 +1654,24 @@ if it is a string, only list groups matching REGEXP." (ticked (gnus-range-length (cdr (assq 'tick marked)))) (group-age (gnus-group-timestamp-delta group)) (inhibit-read-only t)) + ;; FIXME: http://thread.gmane.org/gmane.emacs.gnus.general/65451/focus=65465 + ;; ====================================================================== + ;; From: Richard Stallman + ;; Subject: Re: Rewriting gnus-group-highlight-line (was: [...]) + ;; Cc: ding@gnus.org + ;; Date: Sat, 27 Oct 2007 19:41:20 -0400 + ;; Message-ID: + ;; + ;; [...] + ;; The kludge is that the alist elements contain expressions that refer + ;; to local variables with short names. Perhaps write your own tiny + ;; evaluator that handles just `and', `or', and numeric comparisons + ;; and just a few specific variables. + ;; ====================================================================== + ;; + ;; Similar for other evaluated variables. Grep for risky-local-variable + ;; to find them! -- rsteib + ;; ;; Eval the cars of the lists until we find a match. (while (and list (not (eval (caar list)))) @@ -1703,7 +1866,7 @@ If FIRST-TOO, the current line is also eligible as a target." (size (+ size-in-cache size-in-agent)) (suffix '("B" "K" "M" "G")) (scale 1024.0) - (cutoff (* 10 scale))) + (cutoff scale)) (while (> size cutoff) (setq size (/ size scale) suffix (cdr suffix))) @@ -1887,10 +2050,15 @@ and with point over the group in question." (defun gnus-group-read-group (&optional all no-article group select-articles) "Read news in this newsgroup. If the prefix argument ALL is non-nil, already read articles become -readable. IF ALL is a number, fetch this number of articles. If the -optional argument NO-ARTICLE is non-nil, no article will be -auto-selected upon group entry. If GROUP is non-nil, fetch that -group." +readable. + +If ALL is a positive number, fetch this number of the latest +articles in the group. If ALL is a negative number, fetch this +number of the earliest articles in the group. + +If the optional argument NO-ARTICLE is non-nil, no article will +be auto-selected upon group entry. If GROUP is non-nil, fetch +that group." (interactive "P") (let ((no-display (eq all 0)) (group (or group (gnus-group-group-name))) @@ -1930,11 +2098,11 @@ articles in the group." (forward-line -1)) (gnus-group-read-group all t)) -(defun gnus-group-quick-select-group (&optional all) - "Select the current group \"quickly\". -This means that no highlighting or scoring will be performed. -If ALL (the prefix argument) is 0, don't even generate the summary -buffer. +(defun gnus-group-quick-select-group (&optional all group) + "Select the GROUP \"quickly\". +This means that no highlighting or scoring will be performed. If +ALL (the prefix argument) is 0, don't even generate the summary +buffer. If GROUP is nil, use current group. This might be useful if you want to toggle threading before entering the group." @@ -1945,7 +2113,7 @@ before entering the group." gnus-home-score-file gnus-apply-kill-hook gnus-summary-expunge-below) - (gnus-group-read-group all t))) + (gnus-group-read-group all t group))) (defun gnus-group-visible-select-group (&optional all) "Select the current group without hiding any articles." @@ -1969,14 +2137,89 @@ be permanent." (gnus-group-read-ephemeral-group (gnus-group-prefixed-name group method) method))) +(defun gnus-group-name-at-point () + "Return a group name from around point if it exists, or nil." + (if (eq major-mode 'gnus-group-mode) + (let ((group (gnus-group-group-name))) + (when group + (gnus-group-decoded-name group))) + (let ((regexp "[][\C-@-\t\v-*,/:-@\\^`{-\C-?]*\ +\\(nn[a-z]+\\(?:\\+[^][\C-@-*,/:-@\\^`{-\C-?]+\\)?:\ +\[^][\C-@-*,./:-@\\^`{-\C-?]+\\(?:\\.[^][\C-@-*,./:-@\\^`{-\C-?]+\\)*\ +\\|[^][\C-@-*,./:-@\\^`{-\C-?]+\\(?:\\.[^][\C-@-*,./:-@\\^`{-\C-?]+\\)+\\)") + (start (point)) + (case-fold-search nil)) + (prog1 + (if (or (and (not (or (eobp) + (looking-at "[][\C-@-*,/;-@\\^`{-\C-?]"))) + (prog1 t + (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?" + (point-at-bol)))) + (and (looking-at "[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*$") + (prog1 t + (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?") + (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?" + (point-at-bol)))) + (string-match "\\`[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*\\'" + (buffer-substring (point-at-bol) (point)))) + (when (looking-at regexp) + (match-string 1)) + (let (group distance) + (when (looking-at regexp) + (setq group (match-string 1) + distance (- (match-beginning 1) (match-beginning 0)))) + (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?") + (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?" + (point-at-bol)) + (if (looking-at regexp) + (if (and group (<= distance (- start (match-end 0)))) + group + (match-string 1)) + group))) + (goto-char start))))) + +(defun gnus-group-completing-read (prompt &optional collection predicate + require-match initial-input hist def + &rest args) + "Read a group name with completion. Non-ASCII group names are allowed. +The arguments are the same as `completing-read' except that COLLECTION +and HIST default to `gnus-active-hashtb' and `gnus-group-history' +respectively if they are omitted." + (let ((completion-styles (and (boundp 'completion-styles) + completion-styles)) + group) + (push 'substring completion-styles) + (mapatoms (lambda (symbol) + (setq group (symbol-name symbol)) + (set (intern (if (string-match "[^\000-\177]" group) + (gnus-group-decoded-name group) + group) + collection) + group)) + (prog1 + (or collection + (setq collection (or gnus-active-hashtb [0]))) + (setq collection (gnus-make-hashtable (length collection))))) + (setq group (apply 'completing-read prompt collection predicate + require-match initial-input + (or hist 'gnus-group-history) + def args)) + (or (prog1 + (symbol-value (intern-soft group collection)) + (setq collection nil)) + (mm-encode-coding-string group (gnus-group-name-charset nil group))))) + ;;;###autoload (defun gnus-fetch-group (group &optional articles) "Start Gnus if necessary and enter GROUP. +If ARTICLES, display those articles. Returns whether the fetching was successful or not." - (interactive (list (completing-read "Group name: " gnus-active-hashtb))) - (unless (get-buffer gnus-group-buffer) + (interactive (list (gnus-group-completing-read "Group name: " + nil nil nil + (gnus-group-name-at-point)))) + (unless (gnus-alive-p) (gnus-no-server)) - (gnus-group-read-group articles nil group)) + (gnus-group-read-group (if articles nil t) nil group articles)) ;;;###autoload (defun gnus-fetch-group-other-frame (group) @@ -2034,10 +2277,7 @@ Return the name of the group if selection was successful." (interactive (list ;; (gnus-read-group "Group name: ") - (completing-read - "Group: " gnus-active-hashtb - nil nil nil - 'gnus-group-history) + (gnus-group-completing-read "Group: ") (gnus-read-method "From method: "))) ;; Transform the select method into a unique server. (when (stringp method) @@ -2083,23 +2323,154 @@ Return the name of the group if selection was successful." (message "Quit reading the ephemeral group") nil))))) +(defcustom gnus-gmane-group-download-format + "http://download.gmane.org/%s/%s/%s" + "URL for downloading mbox files. +It must contain three \"%s\". They correspond to the group, the +minimal and maximal article numbers, respectively." + :group 'gnus-group-foreign + :version "23.1" ;; No Gnus + :type 'string) + +(autoload 'url-insert-file-contents "url-handlers") +;; FIXME: +;; - Add documentation, menu, key bindings, ... + +(defun gnus-read-ephemeral-gmane-group (group start &optional range) + "Read articles from Gmane group GROUP as an ephemeral group. +START is the first article. RANGE specifies how many articles +are fetched. The articles are downloaded via HTTP using the URL +specified by `gnus-gmane-group-download-format'." + ;; See for more information. + (interactive + (list + (gnus-group-completing-read "Gmane group: ") + (read-number "Start article number: ") + (read-number "How many articles: "))) + (unless range (setq range 500)) + (when (< range 1) + (error "Invalid range: %s" range)) + (let ((tmpfile (mm-make-temp-file + (format "%s.start-%s.range-%s." group start range))) + (gnus-thread-sort-functions '(gnus-thread-sort-by-number))) + (with-temp-file tmpfile + (url-insert-file-contents + (format gnus-gmane-group-download-format + group start (+ start range))) + (write-region (point-min) (point-max) tmpfile) + (gnus-group-read-ephemeral-group + (format "%s.start-%s.range-%s" group start range) + `(nndoc ,tmpfile + (nndoc-article-type mbox)))) + (delete-file tmpfile))) + +(defun gnus-read-ephemeral-gmane-group-url (url) + "Create an ephemeral Gmane group from URL. + +Valid input formats include: +\"http://thread.gmane.org/gmane.foo.bar/12300/focus=12399\", +\"http://thread.gmane.org/gmane.foo.bar/12345/\", +\"http://article.gmane.org/gmane.foo.bar/12345/\", +\"http://news.gmane.org/group/gmane.foo.bar/thread=12345\"" + ;; - Feel free to add other useful Gmane URLs here! Maybe the URLs should + ;; be customizable? + ;; - The URLs should be added to `gnus-button-alist'. Probably we should + ;; prompt the user to decide: "View via `browse-url' or in Gnus? " + ;; (`gnus-read-ephemeral-gmane-group-url') + (interactive + (list (gnus-group-completing-read "Gmane URL: "))) + (let (group start range) + (cond + ;; URLs providing `group', `start' and `range': + ((string-match + ;; http://thread.gmane.org/gmane.emacs.devel/86326/focus=86525 + "^http://thread\.gmane\.org/\\([^/]+\\)/\\([0-9]+\\)/focus=\\([0-9]+\\)$" + url) + (setq group (match-string 1 url) + start (string-to-number (match-string 2 url)) + ;; Ensure that `range' is large enough to ensure focus article is + ;; included. + range (- (string-to-number (match-string 3 url)) + start -1))) + ;; URLs providing `group' and `start': + ((or (string-match + ;; http://article.gmane.org/gmane.comp.gnu.make.bugs/3584 + "^http://\\(?:thread\\|article\\|permalink\\)\.gmane\.org/\\([^/]+\\)/\\([0-9]+\\)" + url) + (string-match + ;; Don't advertise these in the doc string yet: + "^\\(?:nntp\\|news\\)://news\.gmane\.org/\\([^/]+\\)/\\([0-9]+\\)" + url) + (string-match + ;; http://news.gmane.org/group/gmane.emacs.gnus.general/thread=65099/force_load=t + "^http://news\.gmane\.org/group/\\([^/]+\\)/thread=\\([0-9]+\\)" + url)) + (setq group (match-string 1 url) + start (string-to-number (match-string 2 url)))) + (t + (error "Can't parse URL %s" url))) + (gnus-read-ephemeral-gmane-group group start range))) + +(defcustom gnus-bug-group-download-format-alist + '((emacs . "http://debbugs.gnu.org/%s;mbox=yes") + (debian + . "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s&mbox=yes")) + "Alist of symbols for bug trackers and the corresponding URL format string. +The URL format string must contain a single \"%s\", specifying +the bug number, and browsing the URL must return mbox output." + :group 'gnus-group-foreign + :version "23.2" ;; No Gnus + :type '(repeat (cons (symbol) (string :tag "URL format string")))) + +(defun gnus-read-ephemeral-bug-group (number mbox-url) + "Browse bug NUMBER as ephemeral group." + (interactive (list (read-string "Enter bug number: " + (thing-at-point 'word) nil) + ;; FIXME: Add completing-read from + ;; `gnus-emacs-bug-group-download-format' ... + (cdr (assoc 'emacs gnus-bug-group-download-format-alist)))) + (when (stringp number) + (setq number (string-to-number number))) + (let ((tmpfile (mm-make-temp-file "gnus-temp-group-"))) + (with-temp-file tmpfile + (url-insert-file-contents (format mbox-url number)) + (write-region (point-min) (point-max) tmpfile) + (gnus-group-read-ephemeral-group + "gnus-read-ephemeral-bug" + `(nndoc ,tmpfile + (nndoc-article-type mbox)))) + (delete-file tmpfile))) + +(defun gnus-read-ephemeral-debian-bug-group (number) + "Browse Debian bug NUMBER as ephemeral group." + (interactive (list (read-string "Enter bug number: " + (thing-at-point 'word) nil))) + (gnus-read-ephemeral-bug-group + number + (cdr (assoc 'debian gnus-bug-group-download-format-alist)))) + +(defun gnus-read-ephemeral-emacs-bug-group (number) + "Browse Emacs bug NUMBER as ephemeral group." + (interactive (list (read-string "Enter bug number: " + (thing-at-point 'word) nil))) + (gnus-read-ephemeral-bug-group + number + (cdr (assoc 'emacs gnus-bug-group-download-format-alist)))) + (defun gnus-group-jump-to-group (group &optional prompt) "Jump to newsgroup GROUP. If PROMPT (the prefix) is a number, use the prompt specified in `gnus-group-jump-to-group-prompt'." (interactive - (list (mm-string-make-unibyte - (completing-read - "Group: " gnus-active-hashtb nil - (gnus-read-active-file-p) - (if current-prefix-arg - (cdr (assq current-prefix-arg gnus-group-jump-to-group-prompt)) - (or (and (stringp gnus-group-jump-to-group-prompt) - gnus-group-jump-to-group-prompt) - (let ((p (cdr (assq 0 gnus-group-jump-to-group-prompt)))) - (and (stringp p) p)))) - 'gnus-group-history)))) + (list (gnus-group-completing-read + "Group: " nil nil (gnus-read-active-file-p) + (if current-prefix-arg + (cdr (assq current-prefix-arg gnus-group-jump-to-group-prompt)) + (or (and (stringp gnus-group-jump-to-group-prompt) + gnus-group-jump-to-group-prompt) + (let ((p (cdr (assq 0 gnus-group-jump-to-group-prompt)))) + (and (stringp p) p))))))) (when (equal group "") (error "Empty group name")) @@ -2247,6 +2618,25 @@ If EXCLUDE-GROUP, do not go to that group." (gnus-group-position-point) (and best-point (gnus-group-group-name)))) +;; Is there something like an after-point-motion-hook? +;; (inhibit-point-motion-hooks?). Is there a tool-bar-update function? + +;; (defun gnus-group-menu-bar-update () +;; (let* ((buf (list (with-current-buffer gnus-group-buffer +;; (current-buffer)))) +;; (name (buffer-name (car buf)))) +;; (setcdr buf +;; (if (> (length name) 27) +;; (concat (substring name 0 12) +;; "..." +;; (substring name -12)) +;; name)) +;; (menu-bar-update-buffers-1 buf))) + +;; (defun gnus-group-position-point () +;; (gnus-goto-colon) +;; (gnus-group-menu-bar-update)) + (defun gnus-group-first-unread-group () "Go to the first group with unread articles." (interactive) @@ -2271,17 +2661,16 @@ If EXCLUDE-GROUP, do not go to that group." (defun gnus-group-make-group-simple (&optional group) "Add a new newsgroup. The user will be prompted for GROUP." - (interactive - (list (completing-read "Group: " gnus-active-hashtb - nil nil nil 'gnus-group-history))) - (gnus-group-make-group - (gnus-group-real-name group) - (gnus-group-server group))) + (interactive (list (gnus-group-completing-read "Group: "))) + (gnus-group-make-group (gnus-group-real-name group) + (gnus-group-server group) + nil nil t)) -(defun gnus-group-make-group (name &optional method address args) +(defun gnus-group-make-group (name &optional method address args encoded) "Add a new newsgroup. The user will be prompted for a NAME, for a select METHOD, and an -ADDRESS." +ADDRESS. NAME should be a human-readable string (i.e., not be encoded +even if it contains non-ASCII characters) unless ENCODED is non-nil." (interactive (list (gnus-read-group "Group name: ") @@ -2289,6 +2678,10 @@ ADDRESS." (when (stringp method) (setq method (or (gnus-server-to-method method) method))) + (unless encoded + (setq name (mm-encode-coding-string + name + (gnus-group-name-charset method name)))) (let* ((meth (gnus-method-simplify (when (and method (not (gnus-server-equal method gnus-select-method))) @@ -2379,14 +2772,19 @@ be removed from the server, even when it's empty." When used interactively, GROUP is the group under point and NEW-NAME will be prompted for." (interactive - (list - (gnus-group-group-name) - (progn - (unless (gnus-check-backend-function - 'request-rename-group (gnus-group-group-name)) - (error "This back end does not support renaming groups")) - (gnus-read-group "Rename group to: " - (gnus-group-real-name (gnus-group-group-name)))))) + (let ((group (gnus-group-group-name)) + method new-name) + (unless (gnus-check-backend-function 'request-rename-group group) + (error "This back end does not support renaming groups")) + (setq new-name (gnus-read-group + "Rename group to: " + (gnus-group-real-name (gnus-group-decoded-name group))) + method (gnus-info-method (gnus-get-info group))) + (list group (mm-encode-coding-string + new-name + (gnus-group-name-charset + method + (gnus-group-prefixed-name new-name method)))))) (unless (gnus-check-backend-function 'request-rename-group group) (error "This back end does not support renaming groups")) @@ -2405,29 +2803,34 @@ and NEW-NAME will be prompted for." (gnus-group-real-name new-name) (gnus-info-method (gnus-get-info group))))) - (when (gnus-active new-name) - (error "The group %s already exists" new-name)) + (let ((decoded-group (gnus-group-decoded-name group)) + (decoded-new-name (gnus-group-decoded-name new-name))) + (when (gnus-active new-name) + (error "The group %s already exists" decoded-new-name)) - (gnus-message 6 "Renaming group %s to %s..." group new-name) - (prog1 - (if (progn - (gnus-group-goto-group group) - (not (when (< (gnus-group-group-level) gnus-level-zombie) - (gnus-request-rename-group group new-name)))) - (gnus-error 3 "Couldn't rename group %s to %s" group new-name) - ;; We rename the group internally by killing it... - (gnus-group-kill-group) - ;; ... changing its name ... - (setcar (cdar gnus-list-of-killed-groups) new-name) - ;; ... and then yanking it. Magic! - (gnus-group-yank-group) - (gnus-set-active new-name (gnus-active group)) - (gnus-message 6 "Renaming group %s to %s...done" group new-name) - new-name) - (setq gnus-killed-list (delete group gnus-killed-list)) - (gnus-set-active group nil) - (gnus-dribble-touch) - (gnus-group-position-point))) + (gnus-message 6 "Renaming group %s to %s..." + decoded-group decoded-new-name) + (prog1 + (if (progn + (gnus-group-goto-group group) + (not (when (< (gnus-group-group-level) gnus-level-zombie) + (gnus-request-rename-group group new-name)))) + (gnus-error 3 "Couldn't rename group %s to %s" + decoded-group decoded-new-name) + ;; We rename the group internally by killing it... + (gnus-group-kill-group) + ;; ... changing its name ... + (setcar (cdar gnus-list-of-killed-groups) new-name) + ;; ... and then yanking it. Magic! + (gnus-group-yank-group) + (gnus-set-active new-name (gnus-active group)) + (gnus-message 6 "Renaming group %s to %s...done" + decoded-group decoded-new-name) + new-name) + (setq gnus-killed-list (delete group gnus-killed-list)) + (gnus-set-active group nil) + (gnus-dribble-touch) + (gnus-group-position-point)))) (defun gnus-group-edit-group (group &optional part) "Edit the group on the current line." @@ -2520,7 +2923,10 @@ and NEW-NAME will be prompted for." (let ((entry (assoc (completing-read "Create group: " gnus-useful-groups nil t) gnus-useful-groups))) - (list (cadr entry) (caddr entry)))) + (list (cadr entry) + ;; Don't use `caddr' here since macros within the `interactive' + ;; form won't be expanded. + (car (cddr entry))))) (setq method (gnus-copy-sequence method)) (let (entry) (while (setq entry (memq (assq 'eval method) method)) @@ -2579,15 +2985,18 @@ If called with a prefix argument, ask for the file type." (t (setq err (format "%c unknown. " char)) nil)))) (setq type found))) - (let* ((file (expand-file-name file)) - (name (gnus-generate-new-group-name + (setq file (expand-file-name file)) + (let* ((name (gnus-generate-new-group-name (gnus-group-prefixed-name - (file-name-nondirectory file) '(nndoc ""))))) + (file-name-nondirectory file) '(nndoc "")))) + (method (list 'nndoc file + (list 'nndoc-address file) + (list 'nndoc-article-type (or type 'guess)))) + (coding (gnus-group-name-charset method name))) + (setcar (cdr method) (mm-encode-coding-string file coding)) (gnus-group-make-group - (gnus-group-real-name name) - (list 'nndoc file - (list 'nndoc-address file) - (list 'nndoc-article-type (or type 'guess)))))) + (mm-encode-coding-string (gnus-group-real-name name) coding) + method nil nil t))) (defvar nnweb-type-definition) (defvar gnus-group-web-type-history nil) @@ -2628,8 +3037,8 @@ If SOLID (the prefix), create a solid group." (cons (current-buffer) (if (eq major-mode 'gnus-summary-mode) 'summary 'group)))))) +(defvar nnrss-group-alist) (eval-when-compile - (defvar nnrss-group-alist) (defun nnrss-discover-feed (arg)) (defun nnrss-save-server-data (arg))) (defun gnus-group-make-rss-group (&optional url) @@ -2641,65 +3050,36 @@ If there is, use Gnus to create an nnrss group" (setq url (read-from-minibuffer "URL to Search for RSS: "))) (let ((feedinfo (nnrss-discover-feed url))) (if feedinfo - (let ((title (gnus-newsgroup-savable-name - (read-from-minibuffer "Title: " - (gnus-newsgroup-savable-name - (or (cdr (assoc 'title - feedinfo)) - ""))))) - (desc (read-from-minibuffer "Description: " - (cdr (assoc 'description - feedinfo)))) - (href (cdr (assoc 'href feedinfo))) - (encodable (mm-coding-system-p 'utf-8))) - (when encodable + (let* ((title (gnus-newsgroup-savable-name + (read-from-minibuffer "Title: " + (gnus-newsgroup-savable-name + (mapconcat + 'identity + (split-string + (or (cdr (assoc 'title + feedinfo)) + "")) + " "))))) + (desc (read-from-minibuffer "Description: " + (mapconcat + 'identity + (split-string + (or (cdr (assoc 'description + feedinfo)) + "")) + " "))) + (href (cdr (assoc 'href feedinfo))) + (coding (gnus-group-name-charset '(nnrss "") title))) + (when coding ;; Unify non-ASCII text. (setq title (mm-decode-coding-string - (mm-encode-coding-string title 'utf-8) 'utf-8))) - (gnus-group-make-group (if encodable - (mm-encode-coding-string title 'utf-8) - title) - '(nnrss "")) + (mm-encode-coding-string title coding) + coding))) + (gnus-group-make-group title '(nnrss "")) (push (list title href desc) nnrss-group-alist) (nnrss-save-server-data nil)) (error "No feeds found for %s" url)))) -(defvar nnwarchive-type-definition) -(defvar gnus-group-warchive-type-history nil) -(defvar gnus-group-warchive-login-history nil) -(defvar gnus-group-warchive-address-history nil) - -(defun gnus-group-make-warchive-group () - "Create a nnwarchive group." - (interactive) - (require 'nnwarchive) - (let* ((group (gnus-read-group "Group name: ")) - (default-type (or (car gnus-group-warchive-type-history) - (symbol-name (caar nnwarchive-type-definition)))) - (type - (gnus-string-or - (completing-read - (format "Warchive type (default %s): " default-type) - (mapcar (lambda (elem) (list (symbol-name (car elem)))) - nnwarchive-type-definition) - nil t nil 'gnus-group-warchive-type-history) - default-type)) - (address (read-string "Warchive address: " - nil 'gnus-group-warchive-address-history)) - (default-login (or (car gnus-group-warchive-login-history) - user-mail-address)) - (login - (gnus-string-or - (read-string - (format "Warchive login (default %s): " user-mail-address) - default-login 'gnus-group-warchive-login-history) - user-mail-address)) - (method - `(nnwarchive ,address - (nnwarchive-type ,(intern type)) - (nnwarchive-login ,login)))) - (gnus-group-make-group group method))) - (defun gnus-group-make-archive-group (&optional all) "Create the (ding) Gnus archive group of the most recent articles. Given a prefix, create a full group." @@ -2719,7 +3099,7 @@ Given a prefix, create a full group." (defun gnus-group-make-directory-group (dir) "Create an nndir group. The user will be prompted for a directory. The contents of this -directory will be used as a newsgroup. The directory should contain +directory will be used as a newsgroup. The directory should contain mail messages or news articles in files that have numeric names." (interactive (list (read-file-name "Create group from directory: "))) @@ -2740,39 +3120,6 @@ mail messages or news articles in files that have numeric names." (gnus-group-real-name group) (list 'nndir (gnus-group-real-name group) (list 'nndir-directory dir))))) -(defvar nnkiboze-score-file) -(defun gnus-group-make-kiboze-group (group address scores) - "Create an nnkiboze group. -The user will be prompted for a name, a regexp to match groups, and -score file entries for articles to include in the group." - (interactive - (list - (read-string "nnkiboze group name: ") - (read-string "Source groups (regexp): ") - (let ((headers (mapcar 'list - '("subject" "from" "number" "date" "message-id" - "references" "chars" "lines" "xref" - "followup" "all" "body" "head"))) - scores header regexp regexps) - (while (not (equal "" (setq header (completing-read - "Match on header: " headers nil t)))) - (setq regexps nil) - (while (not (equal "" (setq regexp (read-string - (format "Match on %s (regexp): " - header))))) - (push (list regexp nil nil 'r) regexps)) - (push (cons header regexps) scores)) - scores))) - (gnus-group-make-group group "nnkiboze" address) - (let* ((nnkiboze-current-group group) - (score-file (car (nnkiboze-score-file ""))) - (score-dir (file-name-directory score-file))) - (unless (file-exists-p score-dir) - (make-directory score-dir)) - (with-temp-file score-file - (let (emacs-lisp-mode-hook) - (gnus-pp scores))))) - (defun gnus-group-add-to-virtual (n vgroup) "Add the current group to a virtual group." (interactive @@ -2823,10 +3170,9 @@ score file entries for articles to include in the group." 'summary 'group))) (error "Couldn't enter %s" dir)))) -(eval-and-compile - (autoload 'nnimap-expunge "nnimap") - (autoload 'nnimap-acl-get "nnimap") - (autoload 'nnimap-acl-edit "nnimap")) +(autoload 'nnimap-expunge "nnimap") +(autoload 'nnimap-acl-get "nnimap") +(autoload 'nnimap-acl-edit "nnimap") (defun gnus-group-nnimap-expunge (group) "Expunge deleted articles in current nnimap GROUP." @@ -3054,7 +3400,7 @@ sort in reverse order." (defun gnus-group-sort-by-unread (info1 info2) "Sort by number of unread articles." (let ((n1 (gnus-group-unread (gnus-info-group info1))) - (n2 (gnus-group-unread (gnus-info-group info1)))) + (n2 (gnus-group-unread (gnus-info-group info2)))) (< (or (and (numberp n1) n1) 0) (or (and (numberp n2) n2) 0)))) @@ -3174,13 +3520,15 @@ up is returned." (when (eq 'nnvirtual (car method)) (nnvirtual-catchup-group (gnus-group-real-name group) (nth 1 method) all))) - (if (>= (gnus-group-level group) gnus-level-zombie) - (gnus-message 2 "Dead groups can't be caught up") - (if (prog1 - (gnus-group-goto-group group) - (gnus-group-catchup group all)) - (gnus-group-update-group-line) - (setq ret (1+ ret))))) + (cond + ((>= (gnus-group-level group) gnus-level-zombie) + (gnus-message 2 "Dead groups can't be caught up")) + ((prog1 + (gnus-group-goto-group group) + (gnus-group-catchup group all)) + (gnus-group-update-group-line)) + (t + (setq ret (1+ ret))))) (gnus-group-next-unread-group 1) ret))) @@ -3218,10 +3566,12 @@ or nil if no action could be taken." (gnus-add-marked-articles group 'dormant nil nil 'force)) ;; Do auto-expirable marks if that's required. (when (gnus-group-auto-expirable-p group) - (gnus-range-map (lambda (article) - (gnus-add-marked-articles group 'expire (list article)) - (gnus-request-set-mark group (list (list (list article) 'add '(expire))))) - unread)) + (gnus-range-map + (lambda (article) + (gnus-add-marked-articles group 'expire (list article)) + (gnus-request-set-mark group (list (list (list article) + 'add '(expire))))) + unread)) (let ((gnus-newsgroup-name group)) (gnus-run-hooks 'gnus-group-catchup-group-hook)) num))) @@ -3349,12 +3699,8 @@ If given numerical prefix, toggle the N next groups." "Toggle subscription to GROUP. Killed newsgroups are subscribed. If SILENT, don't try to update the group line." - (interactive - (list (completing-read - "Group: " gnus-active-hashtb nil - (gnus-read-active-file-p) - nil - 'gnus-group-history))) + (interactive (list (gnus-group-completing-read + "Group: " nil nil (gnus-read-active-file-p)))) (let ((newsrc (gnus-group-entry group))) (cond ((string-match "^[ \t]*$" group) @@ -3387,7 +3733,7 @@ group line." (defun gnus-group-transpose-groups (n) "Move the current newsgroup up N places. -If given a negative prefix, move down instead. The difference between +If given a negative prefix, move down instead. The difference between N and the number of steps taken is returned." (interactive "p") (unless (gnus-group-group-name) @@ -3638,7 +3984,10 @@ re-scanning. If ARG is non-nil and not a number, this will force ;; We might read in new NoCeM messages here. (when (and gnus-use-nocem - (null arg)) + (or (and (numberp gnus-use-nocem) + (numberp arg) + (>= arg gnus-use-nocem)) + (not arg))) (gnus-nocem-scan-groups)) ;; If ARG is not a number, then we read the active file. (when (and arg (not (numberp arg))) @@ -3738,7 +4087,7 @@ to use." If given a prefix argument, prompt for a group." (interactive (list (or (when current-prefix-arg - (completing-read "Group: " gnus-active-hashtb)) + (gnus-group-completing-read "Group: ")) (gnus-group-group-name) gnus-newsgroup-name))) (unless group @@ -3766,7 +4115,7 @@ If given a prefix argument, prompt for a group." If given a prefix argument, prompt for a group." (interactive (list (or (when current-prefix-arg - (completing-read "Group: " gnus-active-hashtb)) + (gnus-group-completing-read "Group: ")) (gnus-group-group-name) gnus-newsgroup-name))) (unless group @@ -3992,12 +4341,12 @@ The hook `gnus-suspend-gnus-hook' is called before actually suspending." (gnus-offer-save-summaries) ;; Kill Gnus buffers except for group mode buffer. (let ((group-buf (get-buffer gnus-group-buffer))) - (mapcar (lambda (buf) - (unless (or (member buf (list group-buf gnus-dribble-buffer)) - (with-current-buffer buf - (eq major-mode 'message-mode))) - (gnus-kill-buffer buf))) - (gnus-buffers)) + (dolist (buf (gnus-buffers)) + (unless (or (eq buf group-buf) + (eq buf gnus-dribble-buffer) + (with-current-buffer buf + (eq major-mode 'message-mode))) + (gnus-kill-buffer buf))) (setq gnus-backlog-articles nil) (gnus-kill-gnus-frames) (when group-buf @@ -4097,7 +4446,7 @@ and the second element is the address." (unless entry (error "Trying to change non-existent group %s" method-only-group)) ;; We have received parts of the actual group info - either the - ;; select method or the group parameters. We first check + ;; select method or the group parameters. We first check ;; whether we have to extend the info, and if so, do that. (let ((len (length info)) (total (if (eq part 'method) 5 6))) @@ -4122,9 +4471,10 @@ and the second element is the address." (if (stringp method) method (prin1-to-string (car method))) (and (consp method) - (nth 1 (gnus-info-method info)))) + (nth 1 (gnus-info-method info))) + nil t) ;; It's a native group. - (gnus-group-make-group (gnus-info-group info)))) + (gnus-group-make-group (gnus-info-group info) nil nil nil t))) (gnus-message 6 "Note: New group created") (setq entry (gnus-group-entry (gnus-group-prefixed-name @@ -4344,14 +4694,16 @@ This command may read the active file." ;;; -;;; Group compaction +;;; Group compaction. -- dvl ;;; (defun gnus-group-compact-group (group) - "Conpact the current group. + "Compact the current group. Compaction means removing gaps between article numbers. Hence, this operation is only meaningful for back ends using one file per article -\(e.g. nnml)." +\(e.g. nnml). + +Note: currently only implemented in nnml." (interactive (list (gnus-group-group-name))) (unless group (error "No group to compact")) @@ -4366,9 +4718,14 @@ Compacting group %s... (this may take a long time)" (gnus-error 3 "Couldn't compact group %s" group-decoded) (gnus-message 6 "Compacting group %s...done" group-decoded) t) + ;; Invalidate the "original article" buffer which might be out of date. + ;; #### NOTE: Yes, this might be a bit rude, but since compaction + ;; #### will not happen very often, I think this is acceptable. + (let ((original (get-buffer gnus-original-article-buffer))) + (and original (gnus-kill-buffer original))) + ;; Update the group line to reflect new information (art number etc). (gnus-group-update-group-line)))) (provide 'gnus-group) -;;; arch-tag: 2eb5440f-0bca-4091-814c-e37817536af6 ;;; gnus-group.el ends here