"*Function used for sorting the group buffer.
This function will be called with group info entries as the arguments
for the groups to be sorted. Pre-made functions include
-`gnus-group-sort-by-alphabet', `gnus-group-sort-by-unread',
-`gnus-group-sort-by-level', `gnus-group-sort-by-score',
-`gnus-group-sort-by-method', and `gnus-group-sort-by-rank'.
+`gnus-group-sort-by-alphabet', `gnus-group-sort-by-real-name',
+`gnus-group-sort-by-unread', `gnus-group-sort-by-level',
+`gnus-group-sort-by-score', `gnus-group-sort-by-method', and
+`gnus-group-sort-by-rank'.
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
groups.
If you use %o or %O, reading the active file will be slower and quite
-a bit of extra memory will be used. %D will also worsen performance.
+a bit of extra memory will be used. %D will also worsen performance.
Also note that if you change the format specification to include any
of these specs, you must probably re-start Gnus to see them go into
effect.")
(defvar gnus-group-mode-hook nil
"*A hook for Gnus group mode.")
+(defvar gnus-group-menu-hook nil
+ "*Hook run after the creation of the group mode menu.")
+
(defvar gnus-group-catchup-group-hook nil
"*A hook run when catching up a group from the group buffer.")
highlight the line according to the `gnus-group-highlight'
variable.")
+(defvar gnus-useful-groups
+ `(("(ding) mailing list mirrored at sunsite.auc.dk"
+ "emacs.ding"
+ (nntp "sunsite.auc.dk"
+ (nntp-address "sunsite.auc.dk")))
+ ("Gnus help group"
+ "gnus-help"
+ (nndoc "gnus-help"
+ (nndoc-article-type mbox)
+ (eval `(nndoc-address
+ ,(let ((file (nnheader-find-etc-directory
+ "gnus-tut.txt" t)))
+ (unless file
+ (error "Couldn't find doc group"))
+ file))))))
+ "Alist of useful group-server pairs.")
+
+(defvar gnus-group-highlight
+ (cond
+ ((not (eq gnus-display-type 'color))
+ '((mailp . bold)
+ ((= unread 0) . italic)))
+ ((eq gnus-background-mode 'dark)
+ `(((and (not mailp) (eq level 1)) .
+ ,(custom-face-lookup "PaleTurquoise" nil nil t))
+ ((and (not mailp) (eq level 2)) .
+ ,(custom-face-lookup "turquoise" nil nil t))
+ ((and (not mailp) (eq level 3)) .
+ ,(custom-face-lookup "MediumTurquoise" nil nil t))
+ ((and (not mailp) (>= level 4)) .
+ ,(custom-face-lookup "DarkTurquoise" nil nil t))
+ ((and mailp (eq level 1)) .
+ ,(custom-face-lookup "aquamarine1" nil nil t))
+ ((and mailp (eq level 2)) .
+ ,(custom-face-lookup "aquamarine2" nil nil t))
+ ((and mailp (eq level 3)) .
+ ,(custom-face-lookup "aquamarine3" nil nil t))
+ ((and mailp (>= level 4)) .
+ ,(custom-face-lookup "aquamarine4" nil nil t))
+ ))
+ (t
+ `(((and (not mailp) (<= level 3)) .
+ ,(custom-face-lookup "ForestGreen" nil nil t))
+ ((and (not mailp) (eq level 4)) .
+ ,(custom-face-lookup "DarkGreen" nil nil t))
+ ((and (not mailp) (eq level 5)) .
+ ,(custom-face-lookup "CadetBlue4" nil nil t))
+ ((and mailp (eq level 1)) .
+ ,(custom-face-lookup "DeepPink3" nil nil t))
+ ((and mailp (eq level 2)) .
+ ,(custom-face-lookup "HotPink3" nil nil t))
+ ((and mailp (eq level 3)) .
+ ,(custom-face-lookup "dark magenta" nil nil t))
+ ((and mailp (eq level 4)) .
+ ,(custom-face-lookup "DeepPink4" nil nil t))
+ ((and mailp (> level 4)) .
+ ,(custom-face-lookup "DarkOrchid4" nil nil t))
+ )))
+ "Controls the highlighting of group buffer lines.
+
+Below is a list of `Form'/`Face' pairs. When deciding how a a
+particular group line should be displayed, each form is
+evaluated. The content of the face field after the first true form is
+used. You can change how those group lines are displayed by
+editing the face field.
+
+It is also possible to change and add form fields, but currently that
+requires an understanding of Lisp expressions. Hopefully this will
+change in a future release. For now, you can use the following
+variables in the Lisp expression:
+
+group: The name of the group.
+unread: The number of unread articles in the group.
+method: The select method used.
+mailp: Whether it's a mail group or not.
+level: The level of the group.
+score: The score of the group.
+ticked: The number of ticked articles.")
+
+
;;; Internal variables
+(defvar gnus-group-sort-alist-function 'gnus-group-sort-flat
+ "Function for sorting the group buffer.")
+
+(defvar gnus-group-sort-selected-function 'gnus-group-sort-selected-flat
+ "Function for sorting the selected groups in the group buffer.")
+
(defvar gnus-group-indentation-function nil)
(defvar gnus-goto-missing-group-function nil)
-(defvar gnus-group-get-parameter-function 'gnus-group-get-parameter)
+(defvar gnus-group-update-group-function nil)
(defvar gnus-group-goto-next-group-function nil
"Function to override finding the next group after listing groups.")
"V" gnus-version
"s" gnus-group-save-newsrc
"z" gnus-group-suspend
- ; "Z" gnus-group-clear-dribble
"q" gnus-group-exit
"Q" gnus-group-quit
"?" gnus-group-describe-briefly
(gnus-define-keys (gnus-group-group-map "G" gnus-group-mode-map)
"d" gnus-group-make-directory-group
"h" gnus-group-make-help-group
+ "u" gnus-group-make-useful-group
"a" gnus-group-make-archive-group
"k" gnus-group-make-kiboze-group
"m" gnus-group-make-group
"V" gnus-group-make-empty-virtual
"D" gnus-group-enter-directory
"f" gnus-group-make-doc-group
+ "w" gnus-group-make-web-group
"r" gnus-group-rename-group
"\177" gnus-group-delete-group
[delete] gnus-group-delete-group)
"r" gnus-group-sort-groups-by-rank
"m" gnus-group-sort-groups-by-method)
+ (gnus-define-keys (gnus-group-sort-map "P" gnus-group-group-map)
+ "s" gnus-group-sort-selected-groups
+ "a" gnus-group-sort-selected-groups-by-alphabet
+ "u" gnus-group-sort-selected-groups-by-unread
+ "l" gnus-group-sort-selected-groups-by-level
+ "v" gnus-group-sort-selected-groups-by-score
+ "r" gnus-group-sort-selected-groups-by-rank
+ "m" gnus-group-sort-selected-groups-by-method)
+
(gnus-define-keys (gnus-group-list-map "A" gnus-group-mode-map)
"k" gnus-group-list-killed
"z" gnus-group-list-zombies
"f" gnus-score-flush-cache)
(gnus-define-keys (gnus-group-help-map "H" gnus-group-mode-map)
+ "d" gnus-group-describe-group
"f" gnus-group-fetch-faq)
(gnus-define-keys (gnus-group-sub-map "S" gnus-group-mode-map)
"\C-k" gnus-group-kill-level
"z" gnus-group-kill-all-zombies))
+(defun gnus-group-make-menu-bar ()
+ (gnus-turn-off-edit-menu 'group)
+ (unless (boundp 'gnus-group-reading-menu)
+
+ (easy-menu-define
+ gnus-group-reading-menu gnus-group-mode-map ""
+ '("Group"
+ ["Read" gnus-group-read-group (gnus-group-group-name)]
+ ["Select" gnus-group-select-group (gnus-group-group-name)]
+ ["See old articles" (gnus-group-select-group 'all)
+ :keys "C-u SPC" :active (gnus-group-group-name)]
+ ["Catch up" gnus-group-catchup-current (gnus-group-group-name)]
+ ["Catch up all articles" gnus-group-catchup-current-all
+ (gnus-group-group-name)]
+ ["Check for new articles" gnus-group-get-new-news-this-group
+ (gnus-group-group-name)]
+ ["Toggle subscription" gnus-group-unsubscribe-current-group
+ (gnus-group-group-name)]
+ ["Kill" gnus-group-kill-group (gnus-group-group-name)]
+ ["Yank" gnus-group-yank-group gnus-list-of-killed-groups]
+ ["Describe" gnus-group-describe-group (gnus-group-group-name)]
+ ["Fetch FAQ" gnus-group-fetch-faq (gnus-group-group-name)]
+ ["Edit kill file" gnus-group-edit-local-kill
+ (gnus-group-group-name)]
+ ;; Actually one should check, if any of the marked groups gives t for
+ ;; (gnus-check-backend-function 'request-expire-articles ...)
+ ["Expire articles" gnus-group-expire-articles
+ (or (and (gnus-group-group-name)
+ (gnus-check-backend-function
+ 'request-expire-articles
+ (gnus-group-group-name))) gnus-group-marked)]
+ ["Set group level" gnus-group-set-current-level
+ (gnus-group-group-name)]
+ ["Select quick" gnus-group-quick-select-group (gnus-group-group-name)]
+ ))
+
+ (easy-menu-define
+ gnus-group-group-menu gnus-group-mode-map ""
+ '("Groups"
+ ("Listing"
+ ["List unread subscribed groups" gnus-group-list-groups t]
+ ["List (un)subscribed groups" gnus-group-list-all-groups t]
+ ["List killed groups" gnus-group-list-killed gnus-killed-list]
+ ["List zombie groups" gnus-group-list-zombies gnus-zombie-list]
+ ["List level..." gnus-group-list-level t]
+ ["Describe all groups" gnus-group-describe-all-groups t]
+ ["Group apropos..." gnus-group-apropos t]
+ ["Group and description apropos..." gnus-group-description-apropos t]
+ ["List groups matching..." gnus-group-list-matching t]
+ ["List all groups matching..." gnus-group-list-all-matching t]
+ ["List active file" gnus-group-list-active t])
+ ("Sort"
+ ["Default sort" gnus-group-sort-groups t]
+ ["Sort by method" gnus-group-sort-groups-by-method t]
+ ["Sort by rank" gnus-group-sort-groups-by-rank t]
+ ["Sort by score" gnus-group-sort-groups-by-score t]
+ ["Sort by level" gnus-group-sort-groups-by-level t]
+ ["Sort by unread" gnus-group-sort-groups-by-unread t]
+ ["Sort by name" gnus-group-sort-groups-by-alphabet t])
+ ("Sort process/prefixed"
+ ["Default sort" gnus-group-sort-selected-groups
+ (or (not (boundp 'gnus-topic-mode)) (not gnus-topic-mode))]
+ ["Sort by method" gnus-group-sort-selected-groups-by-method
+ (or (not (boundp 'gnus-topic-mode)) (not gnus-topic-mode))]
+ ["Sort by rank" gnus-group-sort-selected-groups-by-rank
+ (or (not (boundp 'gnus-topic-mode)) (not gnus-topic-mode))]
+ ["Sort by score" gnus-group-sort-selected-groups-by-score
+ (or (not (boundp 'gnus-topic-mode)) (not gnus-topic-mode))]
+ ["Sort by level" gnus-group-sort-selected-groups-by-level
+ (or (not (boundp 'gnus-topic-mode)) (not gnus-topic-mode))]
+ ["Sort by unread" gnus-group-sort-selected-groups-by-unread
+ (or (not (boundp 'gnus-topic-mode)) (not gnus-topic-mode))]
+ ["Sort by name" gnus-group-sort-selected-groups-by-alphabet
+ (or (not (boundp 'gnus-topic-mode)) (not gnus-topic-mode))])
+ ("Mark"
+ ["Mark group" gnus-group-mark-group
+ (and (gnus-group-group-name)
+ (not (memq (gnus-group-group-name) gnus-group-marked)))]
+ ["Unmark group" gnus-group-unmark-group
+ (and (gnus-group-group-name)
+ (memq (gnus-group-group-name) gnus-group-marked))]
+ ["Unmark all" gnus-group-unmark-all-groups gnus-group-marked]
+ ["Mark regexp..." gnus-group-mark-regexp t]
+ ["Mark region" gnus-group-mark-region t]
+ ["Mark buffer" gnus-group-mark-buffer t]
+ ["Execute command" gnus-group-universal-argument
+ (or gnus-group-marked (gnus-group-group-name))])
+ ("Subscribe"
+ ["Subscribe to a group" gnus-group-unsubscribe-group t]
+ ["Kill all newsgroups in region" gnus-group-kill-region t]
+ ["Kill all zombie groups" gnus-group-kill-all-zombies
+ gnus-zombie-list]
+ ["Kill all groups on level..." gnus-group-kill-level t])
+ ("Foreign groups"
+ ["Make a foreign group" gnus-group-make-group t]
+ ["Add a directory group" gnus-group-make-directory-group t]
+ ["Add the help group" gnus-group-make-help-group t]
+ ["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]
+ ["Rename group" gnus-group-rename-group
+ (gnus-check-backend-function
+ 'request-rename-group (gnus-group-group-name))]
+ ["Delete group" gnus-group-delete-group
+ (gnus-check-backend-function
+ 'request-delete-group (gnus-group-group-name))])
+ ("Editing groups"
+ ["Parameters" gnus-group-edit-group-parameters
+ (gnus-group-group-name)]
+ ["Select method" gnus-group-edit-group-method
+ (gnus-group-group-name)]
+ ["Info" gnus-group-edit-group (gnus-group-group-name)])
+ ("Score file"
+ ["Flush cache" gnus-score-flush-cache t])
+ ("Move"
+ ["Next" gnus-group-next-group t]
+ ["Previous" gnus-group-prev-group t]
+ ["Next unread" gnus-group-next-unread-group t]
+ ["Previous unread" gnus-group-prev-unread-group t]
+ ["Next unread same level" gnus-group-next-unread-group-same-level t]
+ ["Previous unread same level"
+ gnus-group-prev-unread-group-same-level t]
+ ["Jump to group" gnus-group-jump-to-group t]
+ ["First unread group" gnus-group-first-unread-group t]
+ ["Best unread group" gnus-group-best-unread-group t])
+ ["Transpose" gnus-group-transpose-groups
+ (gnus-group-group-name)]
+ ["Read a directory as a group..." gnus-group-enter-directory t]
+ ))
+
+ (easy-menu-define
+ gnus-group-misc-menu gnus-group-mode-map ""
+ '("Misc"
+ ["Send a bug report" gnus-bug t]
+ ["Send a mail" gnus-group-mail t]
+ ["Post an article..." gnus-group-post-news t]
+ ["Check for new news" gnus-group-get-new-news t]
+ ["Activate all groups" gnus-activate-all-groups t]
+ ["Delete bogus groups" gnus-group-check-bogus-groups t]
+ ["Find new newsgroups" gnus-find-new-newsgroups t]
+ ["Restart Gnus" gnus-group-restart t]
+ ["Read init file" gnus-group-read-init-file t]
+ ["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]
+ ["Clear dribble buffer" gnus-group-clear-dribble t]
+ ["Edit global kill file" gnus-group-edit-global-kill t]
+ ["Read manual" gnus-info-find-node t]
+ ["Toggle topics" gnus-topic-mode t]
+ ("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-soup-brew-soup (fboundp 'gnus-soup-pack-packet)])
+ ["Exit from Gnus" gnus-group-exit t]
+ ["Exit without saving" gnus-group-quit t]
+ ))
+
+ (run-hooks 'gnus-group-menu-hook)
+ ))
+
(defun gnus-group-mode ()
"Major mode for reading news.
(buffer-disable-undo (current-buffer))
(setq truncate-lines t)
(setq buffer-read-only t)
+ (gnus-set-default-directory)
(gnus-update-format-specifications nil 'group 'group-mode)
(gnus-update-group-mark-positions)
(gnus-make-local-hook 'post-command-hook)
Default is all subscribed groups.
If argument UNREAD is non-nil, groups with no unread articles are also
listed."
- (interactive (list (if current-prefix-arg
- (prefix-numeric-value current-prefix-arg)
- (or
- (gnus-group-default-level nil t)
- gnus-group-default-list-level
- gnus-level-subscribed))))
- (or level
- (setq level (car gnus-group-list-mode)
- unread (cdr gnus-group-list-mode)))
+ (interactive
+ (list (if current-prefix-arg
+ (prefix-numeric-value current-prefix-arg)
+ (or
+ (gnus-group-default-level nil t)
+ gnus-group-default-list-level
+ gnus-level-subscribed))))
+ (unless level
+ (setq level (car gnus-group-list-mode)
+ unread (cdr gnus-group-list-mode)))
(setq level (gnus-group-default-level level))
(gnus-group-setup-buffer) ;May call from out of group buffer
- (gnus-update-format-specifications)
+ (gnus-update-format-specifications nil 'group 'group-mode)
(let ((case-fold-search nil)
(props (text-properties-at (gnus-point-at-bol)))
(group (gnus-group-group-name)))
;; has disappeared in the new listing, try to find the next
;; one. If no next one can be found, just leave point at the
;; first newsgroup in the buffer.
- (if (not (gnus-goto-char
- (text-property-any
- (point-min) (point-max)
- 'gnus-group (gnus-intern-safe group gnus-active-hashtb))))
- (let ((newsrc (cdddr (gnus-gethash group gnus-newsrc-hashtb))))
- (while (and newsrc
- (not (gnus-goto-char
- (text-property-any
- (point-min) (point-max) 'gnus-group
- (gnus-intern-safe
- (caar newsrc) gnus-active-hashtb)))))
- (setq newsrc (cdr newsrc)))
- (or newsrc (progn (goto-char (point-max))
- (forward-line -1)))))))
+ (when (not (gnus-goto-char
+ (text-property-any
+ (point-min) (point-max)
+ 'gnus-group (gnus-intern-safe
+ group gnus-active-hashtb))))
+ (let ((newsrc (cdddr (gnus-gethash group gnus-newsrc-hashtb))))
+ (while (and newsrc
+ (not (gnus-goto-char
+ (text-property-any
+ (point-min) (point-max) 'gnus-group
+ (gnus-intern-safe
+ (caar newsrc) gnus-active-hashtb)))))
+ (setq newsrc (cdr newsrc)))
+ (unless newsrc
+ (goto-char (point-max))
+ (forward-line -1))))))
;; Adjust cursor point.
(gnus-group-position-point))))
(not (gnus-ephemeral-group-p group))
(gnus-dribble-enter
(concat "(gnus-group-set-info '"
- (prin1-to-string (nth 2 entry)) ")")))
+ (gnus-prin1-to-string (nth 2 entry)) ")")))
(setq gnus-group-indentation (gnus-group-group-indentation))
(gnus-delete-line)
(gnus-group-insert-group-line-info group)
(defun gnus-group-insert-group-line-info (group)
"Insert GROUP on the current line."
(let ((entry (gnus-gethash group gnus-newsrc-hashtb))
+ (gnus-group-indentation (gnus-group-group-indentation))
active info)
(if entry
(progn
;; Insert the text.
(eval gnus-group-line-format-spec))
`(gnus-group ,(gnus-intern-safe gnus-tmp-group gnus-active-hashtb)
- gnus-unread ,(if (numberp number)
- (string-to-int gnus-tmp-number-of-unread)
- t)
- gnus-marked ,gnus-tmp-marked-mark
- gnus-indentation ,gnus-group-indentation
- gnus-level ,gnus-tmp-level))
+ gnus-unread ,(if (numberp number)
+ (string-to-int gnus-tmp-number-of-unread)
+ t)
+ gnus-marked ,gnus-tmp-marked-mark
+ gnus-indentation ,gnus-group-indentation
+ gnus-level ,gnus-tmp-level))
(when (inline (gnus-visual-p 'group-highlight 'highlight))
(forward-line -1)
(run-hooks 'gnus-group-update-hook)
;; Allow XEmacs to remove front-sticky text properties.
(gnus-group-remove-excess-properties)))
+(defun gnus-group-highlight-line ()
+ "Highlight the current line according to `gnus-group-highlight'."
+ (let* ((list gnus-group-highlight)
+ (p (point))
+ (end (progn (end-of-line) (point)))
+ ;; now find out where the line starts and leave point there.
+ (beg (progn (beginning-of-line) (point)))
+ (group (gnus-group-group-name))
+ (entry (gnus-group-entry group))
+ (unread (if (numberp (car entry)) (car entry) 0))
+ (active (gnus-active group))
+ (total (if active (1+ (- (cdr active) (car active))) 0))
+ (info (nth 2 entry))
+ (method (gnus-server-get-method group (gnus-info-method info)))
+ (marked (gnus-info-marks info))
+ (mailp (memq 'mail (assoc (symbol-name
+ (car (or method gnus-select-method)))
+ gnus-valid-select-methods)))
+ (level (or (gnus-info-level info) 9))
+ (score (or (gnus-info-score info) 0))
+ (ticked (gnus-range-length (cdr (assq 'tick marked))))
+ (inhibit-read-only t))
+ ;; Eval the cars of the lists until we find a match.
+ (while (and list
+ (not (eval (caar list))))
+ (setq list (cdr list)))
+ (let ((face (cdar list)))
+ (unless (eq face (get-text-property beg 'face))
+ (gnus-put-text-property
+ beg end 'face
+ (setq face (if (boundp face) (symbol-value face) face)))
+ (gnus-extent-start-open beg)))
+ (goto-char p)))
+
(defun gnus-group-update-group (group &optional visible-only)
"Update all lines where GROUP appear.
If VISIBLE-ONLY is non-nil, the group won't be displayed if it isn't
(let ((entry (gnus-gethash group gnus-newsrc-hashtb)))
(if (and entry (not (gnus-ephemeral-group-p group)))
(gnus-dribble-enter
- (concat "(gnus-group-set-info '" (prin1-to-string (nth 2 entry))
+ (concat "(gnus-group-set-info '"
+ (gnus-prin1-to-string (nth 2 entry))
")"))))
;; Find all group instances. If topics are in use, each group
;; may be listed in more than once.
(save-excursion
(forward-line -1)
(run-hooks 'gnus-group-update-group-hook))))
+ (when gnus-group-update-group-function
+ (funcall gnus-group-update-group-function group))
(gnus-group-set-mode-line)))))
(defun gnus-group-set-mode-line ()
(setq gnus-group-marked (cons group (delete group gnus-group-marked)))))
(defun gnus-group-universal-argument (arg &optional groups func)
- "Perform any command on all groups accoring to the process/prefix convention."
+ "Perform any command on all groups according to the process/prefix convention."
(interactive "P")
(let ((groups (or groups (gnus-group-process-prefix arg)))
- group func)
+ func)
(if (eq (setq func (or func
(key-binding
(read-key-sequence
'undefined)
(gnus-error 1 "Undefined key")
(while groups
- (gnus-group-remove-mark (setq group (pop groups)))
+ (gnus-group-remove-mark (pop groups))
(command-execute func))))
(gnus-group-position-point))
auto-selected upon group entry. If GROUP is non-nil, fetch that
group."
(interactive "P")
- (let ((group (or group (gnus-group-group-name)))
+ (let ((no-display (eq all 0))
+ (group (or group (gnus-group-group-name)))
number active marked entry)
- (or group (error "No group on current line"))
- (setq marked (nth 3 (nth 2 (setq entry (gnus-gethash
- group gnus-newsrc-hashtb)))))
+ (when (eq all 0)
+ (setq all nil))
+ (unless group
+ (error "No group on current line"))
+ (setq marked (gnus-info-marks
+ (nth 2 (setq entry (gnus-gethash
+ group gnus-newsrc-hashtb)))))
;; This group might be a dead group. In that case we have to get
;; the number of unread articles from `gnus-active-hashtb'.
(setq number
(cdr (assq 'tick marked)))
(gnus-range-length
(cdr (assq 'dormant marked)))))))
- no-article)))
+ no-article nil no-display)))
(defun gnus-group-select-group (&optional all)
"Select this newsgroup.
(defun gnus-group-quick-select-group (&optional all)
"Select the current group \"quickly\".
-This means that no highlighting or scoring will be performed."
+This means that no highlighting or scoring will be performed.
+If ALL (the prefix argument) is 0, don't even generate the summary
+buffer."
(interactive "P")
(let (gnus-visual
gnus-score-find-score-files-function
;; Enter a group that is not in the group buffer. Non-nil is returned
;; if selection was successful.
-(defun gnus-group-read-ephemeral-group
- (group method &optional activate quit-config request-only)
+(defun gnus-group-read-ephemeral-group (group method &optional activate
+ quit-config request-only)
"Read GROUP from METHOD as an ephemeral group.
If ACTIVATE, request the group first.
-If QUIT-CONFIG, use that window configuration when
-exiting from the ephemeral group.
-If REQUEST-ONLY, don't actually read the group; just
-request it.
+If QUIT-CONFIG, use that window configuration when exiting from the
+ephemeral group.
+If REQUEST-ONLY, don't actually read the group; just request it.
Return the name of the group is selection was successful."
(let ((group (if (gnus-group-foreign-p group) group
(gnus-group-prefixed-name group method))))
(gnus-sethash
group
- `(t nil (,group ,gnus-level-default-subscribed nil nil ,method
- ((quit-config . ,(if quit-config quit-config
- (cons (current-buffer) 'summary))))))
+ `(-1 nil (,group
+ ,gnus-level-default-subscribed nil nil ,method
+ ((quit-config .
+ ,(if quit-config quit-config
+ (cons gnus-summary-buffer
+ gnus-current-window-configuration))))))
gnus-newsrc-hashtb)
(set-buffer gnus-group-buffer)
(unless (gnus-check-server method)
(error "Unable to contact server: %s" (gnus-status-message method)))
(when activate
+ (gnus-activate-group group 'scan t)
(unless (gnus-request-group group)
- (error "Couldn't request group")))
+ (error "Couldn't request group: %s"
+ (nnheader-get-report (car method)))))
(if request-only
group
(condition-case ()
(when (equal group "")
(error "Empty group name"))
- (when (string-match "[\000-\032]" group)
- (error "Control characters in group: %s" group))
-
- (let ((b (text-property-any
- (point-min) (point-max)
- 'gnus-group (gnus-intern-safe group gnus-active-hashtb))))
- (unless (gnus-ephemeral-group-p group)
- (if b
- ;; Either go to the line in the group buffer...
- (goto-char b)
- ;; ... or insert the line.
- (or
- t ;; Don't activate group.
- (gnus-active group)
- (gnus-activate-group group)
- (error "%s error: %s" group (gnus-status-message group)))
-
- (gnus-group-update-group group)
- (goto-char (text-property-any
- (point-min) (point-max)
- 'gnus-group (gnus-intern-safe group gnus-active-hashtb)))))
- ;; Adjust cursor point.
- (gnus-group-position-point)))
+ (unless (gnus-ephemeral-group-p group)
+ ;; Either go to the line in the group buffer...
+ (unless (gnus-group-goto-group group)
+ ;; ... or insert the line.
+ (gnus-group-update-group group)
+ (gnus-group-goto-group group)))
+ ;; Adjust cursor point.
+ (gnus-group-position-point))
(defun gnus-group-goto-group (group &optional far)
"Goto to newsgroup GROUP.
(interactive)
(gnus-enter-server-buffer))
-(defun gnus-group-make-group (name &optional method address)
+(defun gnus-group-make-group (name &optional method address args)
"Add a new newsgroup.
The user will be prompted for a NAME, for a select METHOD, and an
ADDRESS."
(gnus-set-active nname (cons 1 0))
(or (gnus-ephemeral-group-p name)
(gnus-dribble-enter
- (concat "(gnus-group-set-info '" (prin1-to-string (cdr info)) ")")))
+ (concat "(gnus-group-set-info '"
+ (gnus-prin1-to-string (cdr info)) ")")))
;; Insert the line.
(gnus-group-insert-group-line-info nname)
(forward-line -1)
(require backend))
(gnus-check-server meth)
(and (gnus-check-backend-function 'request-create-group nname)
- (gnus-request-create-group nname))
+ (gnus-request-create-group nname nil args))
t))
(defun gnus-group-delete-group (group &optional force)
(format
"Do you really want to delete %s%s? "
group (if force " and all its contents" ""))))
- () ; Whew!
+ () ; Whew!
(gnus-message 6 "Deleting group %s..." group)
(if (not (gnus-request-delete-group group force))
(gnus-error 3 "Couldn't delete group %s" group)
(gnus-group-update-group (or new-group group))
(gnus-group-position-point)))
+(defun gnus-group-make-useful-group (group method)
+ (interactive
+ (let ((entry (assoc (completing-read "Create group: " gnus-useful-groups
+ nil t)
+ gnus-useful-groups)))
+ (list (cadr entry) (caddr entry))))
+ (setq method (gnus-copy-sequence method))
+ (let (entry)
+ (while (setq entry (memq (assq 'eval method) method))
+ (setcar entry (eval (cadar entry)))))
+ (gnus-group-make-group group method))
+
(defun gnus-group-make-help-group ()
"Create the Gnus documentation group."
(interactive)
- (let ((path load-path)
- (name (gnus-group-prefixed-name "gnus-help" '(nndoc "gnus-help")))
- file dir)
- (and (gnus-gethash name gnus-newsrc-hashtb)
- (error "Documentation group already exists"))
- (while path
- (setq dir (file-name-as-directory (expand-file-name (pop path)))
- file nil)
- (when (or (file-exists-p (setq file (concat dir "gnus-tut.txt")))
- (file-exists-p
- (setq file (concat (file-name-directory
- (directory-file-name dir))
- "etc/gnus-tut.txt"))))
- (setq path nil)))
+ (let ((name (gnus-group-prefixed-name "gnus-help" '(nndoc "gnus-help")))
+ (file (nnheader-find-etc-directory "gnus-tut.txt" t))
+ dir)
+ (when (gnus-gethash name gnus-newsrc-hashtb)
+ (error "Documentation group already exists"))
(if (not file)
(gnus-message 1 "Couldn't find doc group")
(gnus-group-make-group
char found)
(while (not found)
(message
- "%sFile type (mbox, babyl, digest, forward, mmfd, guess) [mbdfag]: "
+ "%sFile type (mbox, babyl, digest, forward, mmdf, guess) [mbdfag]: "
err)
(setq found (cond ((= (setq char (read-char)) ?m) 'mbox)
((= char ?b) 'babyl)
(list 'nndoc-address file)
(list 'nndoc-article-type (or type 'guess))))))
+(defvar nnweb-type-definition)
+(defvar gnus-group-web-type-history nil)
+(defvar gnus-group-web-search-history nil)
+(defun gnus-group-make-web-group (&optional solid)
+ "Create an ephemeral nnweb group.
+If SOLID (the prefix), create a solid group."
+ (interactive "P")
+ (require 'nnweb)
+ (let* ((group
+ (if solid (read-string "Group name: ") (message-unique-id)))
+ (type
+ (completing-read
+ "Search engine type: "
+ (mapcar (lambda (elem) (list (symbol-name (car elem))))
+ nnweb-type-definition)
+ nil t (cons (or (car gnus-group-web-type-history)
+ (symbol-name (caar nnweb-type-definition)))
+ 0)
+ 'gnus-group-web-type-history))
+ (search
+ (read-string
+ "Search string: "
+ (cons (or (car gnus-group-web-search-history) "") 0)
+ 'gnus-group-web-search-history))
+ (method
+ `(nnweb ,group (nnweb-search ,search)
+ (nnweb-type ,(intern type))
+ (nnweb-ephemeral-p t))))
+ (if solid
+ (gnus-group-make-group group "nnweb" "" `(,(intern type) ,search))
+ (gnus-group-read-ephemeral-group
+ group method t
+ (cons (current-buffer)
+ (if (eq major-mode 'gnus-summary-mode) 'summary 'group))))))
+
(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."
(defun gnus-group-enter-directory (dir)
"Enter an ephemeral nneething group."
(interactive "DDirectory to read: ")
- (let* ((method (list 'nneething dir))
+ (let* ((method (list 'nneething dir '(nneething-read-only t)))
(leaf (gnus-group-prefixed-name
(file-name-nondirectory (directory-file-name dir))
method))
(name (gnus-generate-new-group-name leaf)))
- (let ((nneething-read-only t))
- (or (gnus-group-read-ephemeral-group
- name method t
- (cons (current-buffer) (if (eq major-mode 'gnus-summary-mode)
- 'summary 'group)))
- (error "Couldn't enter %s" dir)))))
+ (unless (gnus-group-read-ephemeral-group
+ name method t
+ (cons (current-buffer)
+ (if (eq major-mode 'gnus-summary-mode)
+ 'summary 'group)))
+ (error "Couldn't enter %s" dir))))
;; Group sorting commands
;; Suggested by Joe Hildebrand <hildjj@idaho.fuentez.com>.
(defun gnus-group-sort-groups (func &optional reverse)
"Sort the group buffer according to FUNC.
If REVERSE, reverse the sorting order."
- (interactive (list gnus-group-sort-function
- current-prefix-arg))
- (let ((func (cond
- ((not (listp func)) func)
- ((null func) func)
- ((= 1 (length func)) (car func))
- (t `(lambda (t1 t2)
- ,(gnus-make-sort-function
- (reverse func)))))))
- ;; We peel off the dummy group from the alist.
- (when func
- (when (equal (car (gnus-info-group gnus-newsrc-alist)) "dummy.group")
- (pop gnus-newsrc-alist))
- ;; Do the sorting.
- (setq gnus-newsrc-alist
- (sort gnus-newsrc-alist func))
- (when reverse
- (setq gnus-newsrc-alist (nreverse gnus-newsrc-alist)))
- ;; Regenerate the hash table.
- (gnus-make-hashtable-from-newsrc-alist)
- (gnus-group-list-groups))))
+ (interactive (list gnus-group-sort-function current-prefix-arg))
+ (funcall gnus-group-sort-alist-function
+ (gnus-make-sort-function func) reverse)
+ (gnus-group-list-groups))
+
+(defun gnus-group-sort-flat (func reverse)
+ ;; We peel off the dummy group from the alist.
+ (when func
+ (when (equal (car (gnus-info-group gnus-newsrc-alist)) "dummy.group")
+ (pop gnus-newsrc-alist))
+ ;; Do the sorting.
+ (setq gnus-newsrc-alist
+ (sort gnus-newsrc-alist func))
+ (when reverse
+ (setq gnus-newsrc-alist (nreverse gnus-newsrc-alist)))
+ ;; Regenerate the hash table.
+ (gnus-make-hashtable-from-newsrc-alist)))
(defun gnus-group-sort-groups-by-alphabet (&optional reverse)
"Sort the group buffer alphabetically by group name.
(interactive "P")
(gnus-group-sort-groups 'gnus-group-sort-by-method reverse))
+;;; Selected group sorting.
+
+(defun gnus-group-sort-selected-groups (n func &optional reverse)
+ "Sort the process/prefixed groups."
+ (interactive (list current-prefix-arg gnus-group-sort-function))
+ (let ((groups (gnus-group-process-prefix n)))
+ (funcall gnus-group-sort-selected-function
+ groups (gnus-make-sort-function func) reverse)
+ (gnus-group-list-groups)))
+
+(defun gnus-group-sort-selected-flat (groups func reverse)
+ (let (entries infos)
+ ;; First find all the group entries for these groups.
+ (while groups
+ (push (nthcdr 2 (gnus-gethash (pop groups) gnus-newsrc-hashtb))
+ entries))
+ ;; Then sort the infos.
+ (setq infos
+ (sort
+ (mapcar
+ (lambda (entry) (car entry))
+ (setq entries (nreverse entries)))
+ func))
+ (when reverse
+ (setq infos (nreverse infos)))
+ ;; Go through all the infos and replace the old entries
+ ;; with the new infos.
+ (while infos
+ (setcar entries (pop infos))
+ (pop entries))
+ ;; Update the hashtable.
+ (gnus-make-hashtable-from-newsrc-alist)))
+
+(defun gnus-group-sort-selected-groups-by-alphabet (&optional reverse)
+ "Sort the group buffer alphabetically by group name.
+If REVERSE, sort in reverse order."
+ (interactive "P")
+ (gnus-group-sort-selected-groups 'gnus-group-sort-by-alphabet reverse))
+
+(defun gnus-group-sort-selected-groups-by-unread (&optional reverse)
+ "Sort the group buffer by number of unread articles.
+If REVERSE, sort in reverse order."
+ (interactive "P")
+ (gnus-group-sort-selected-groups 'gnus-group-sort-by-unread reverse))
+
+(defun gnus-group-sort-selected-groups-by-level (&optional reverse)
+ "Sort the group buffer by group level.
+If REVERSE, sort in reverse order."
+ (interactive "P")
+ (gnus-group-sort-selected-groups 'gnus-group-sort-by-level reverse))
+
+(defun gnus-group-sort-selected-groups-by-score (&optional reverse)
+ "Sort the group buffer by group score.
+If REVERSE, sort in reverse order."
+ (interactive "P")
+ (gnus-group-sort-selected-groups 'gnus-group-sort-by-score reverse))
+
+(defun gnus-group-sort-selected-groups-by-rank (&optional reverse)
+ "Sort the group buffer by group rank.
+If REVERSE, sort in reverse order."
+ (interactive "P")
+ (gnus-group-sort-selected-groups 'gnus-group-sort-by-rank reverse))
+
+(defun gnus-group-sort-selected-groups-by-method (&optional reverse)
+ "Sort the group buffer alphabetically by backend name.
+If REVERSE, sort in reverse order."
+ (interactive "P")
+ (gnus-group-sort-selected-groups 'gnus-group-sort-by-method reverse))
+
+;;; Sorting predicates.
+
(defun gnus-group-sort-by-alphabet (info1 info2)
"Sort alphabetically."
(string< (gnus-info-group info1) (gnus-info-group info2)))
+(defun gnus-group-sort-by-real-name (info1 info2)
+ "Sort alphabetically on real (unprefixed) names."
+ (string< (gnus-group-real-name (gnus-info-group info1))
+ (gnus-group-real-name (gnus-info-group info2))))
+
(defun gnus-group-sort-by-unread (info1 info2)
"Sort by number of unread articles."
(let ((n1 (car (gnus-gethash (gnus-info-group info1) gnus-newsrc-hashtb)))
expirable
(gnus-compress-sequence
(if expiry-wait
- ;; We set the expiry variables to the groupp
+ ;; We set the expiry variables to the group
;; parameter.
(let ((nnmail-expiry-wait-function nil)
(nnmail-expiry-wait expiry-wait))
(setq entry (gnus-gethash group gnus-newsrc-hashtb)))
(gnus-undo-register
`(progn
- (gnus-group-goto-group ,(gnus-group-group-name))
- (gnus-group-yank-group)))
+ (gnus-group-goto-group ,(gnus-group-group-name))
+ (gnus-group-yank-group)))
(push (cons (car entry) (nth 2 entry))
gnus-list-of-killed-groups))
(gnus-group-change-level
(gnus-group-insert-group-line-info group)
(gnus-undo-register
`(when (gnus-group-goto-group ,group)
- (gnus-group-kill-group 1))))
+ (gnus-group-kill-group 1))))
(forward-line -1)
(gnus-group-position-point)
(if (< (length out) 2) (car out) (nreverse out))))
re-scanning. If ARG is non-nil and not a number, this will force
\"hard\" re-reading of the active files from all servers."
(interactive "P")
- (save-excursion
- (set-buffer gnus-group-buffer)
- (run-hooks 'gnus-get-new-news-hook)
- ;; We might read in new NoCeM messages here.
- (when (and gnus-use-nocem
- (null arg))
- (gnus-nocem-scan-groups))
- ;; If ARG is not a number, then we read the active file.
- (when (and arg (not (numberp arg)))
- (let ((gnus-read-active-file t))
- (gnus-read-active-file))
- (setq arg nil))
-
- (setq arg (gnus-group-default-level arg t))
- (if (and gnus-read-active-file (not arg))
- (progn
- (gnus-read-active-file)
- (gnus-get-unread-articles arg))
- (let ((gnus-read-active-file (if arg nil gnus-read-active-file)))
- (gnus-get-unread-articles arg)))
- (run-hooks 'gnus-after-getting-new-news-hook)
- (gnus-group-list-groups)))
+ (run-hooks 'gnus-get-new-news-hook)
+
+ ;; Read any slave files.
+ (unless gnus-slave
+ (gnus-master-read-slave-newsrc))
+
+ ;; We might read in new NoCeM messages here.
+ (when (and gnus-use-nocem
+ (null arg))
+ (gnus-nocem-scan-groups))
+ ;; If ARG is not a number, then we read the active file.
+ (when (and arg (not (numberp arg)))
+ (let ((gnus-read-active-file t))
+ (gnus-read-active-file))
+ (setq arg nil))
+
+ (setq arg (gnus-group-default-level arg t))
+ (if (and gnus-read-active-file (not arg))
+ (progn
+ (gnus-read-active-file)
+ (gnus-get-unread-articles arg))
+ (let ((gnus-read-active-file (if arg nil gnus-read-active-file)))
+ (gnus-get-unread-articles arg)))
+ (run-hooks 'gnus-after-getting-new-news-hook)
+ (gnus-group-list-groups))
(defun gnus-group-get-new-news-this-group (&optional n)
"Check for newly arrived news in the current group (and the N-1 next groups).
group)
(while (setq group (pop groups))
(gnus-group-remove-mark group)
+ ;; Bypass any previous denials from the server.
+ (gnus-remove-denial (gnus-find-method-for-group group))
(if (gnus-activate-group group 'scan)
(progn
(gnus-get-unread-articles-in-group
(gnus-group-update-group group))
(if (eq (gnus-server-status (gnus-find-method-for-group group))
'denied)
- (gnus-error "Server denied access")
+ (gnus-error 3 "Server denied access")
(gnus-error 3 "%s error: %s" group (gnus-status-message group)))))
(when beg (goto-char beg))
(when gnus-goto-next-group-when-activating
ret))
(defun gnus-group-fetch-faq (group &optional faq-dir)
- "Fetch the FAQ for the current group."
+ "Fetch the FAQ for the current group.
+If given a prefix argument, prompt for the FAQ dir
+to use."
(interactive
(list
- (and (gnus-group-group-name)
- (gnus-group-real-name (gnus-group-group-name)))
+ (gnus-group-group-name)
(cond (current-prefix-arg
(completing-read
"Faq dir: " (and (listp gnus-group-faq-directory)
(mapcar (lambda (file) (list file))
gnus-group-faq-directory)))))))
- (or faq-dir
- (setq faq-dir (if (listp gnus-group-faq-directory)
- (car gnus-group-faq-directory)
- gnus-group-faq-directory)))
- (or group (error "No group name given"))
- (let ((file (concat (file-name-as-directory faq-dir)
- (gnus-group-real-name group))))
- (if (not (file-exists-p file))
- (error "No such file: %s" file)
- (find-file file))))
+ (unless group
+ (error "No group name given"))
+ (let ((dirs (or faq-dir gnus-group-faq-directory))
+ dir found file)
+ (unless (listp dirs)
+ (setq dirs (list dirs)))
+ (while (and (not found)
+ (setq dir (pop dirs)))
+ (setq file (concat (file-name-as-directory dir)
+ (gnus-group-real-name group)))
+ (if (not (file-exists-p file))
+ (gnus-message 1 "No such file: %s" file)
+ (find-file file)
+ (setq found t)))))
(defun gnus-group-describe-group (force &optional group)
"Display a description of the current newsgroup."
(setq desc (gnus-group-get-description group))
(gnus-read-descriptions-file method))
(gnus-message 1
- (or desc (gnus-gethash group gnus-description-hashtb)
- "No description available")))))
+ (or desc (gnus-gethash group gnus-description-hashtb)
+ "No description available")))))
;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
(defun gnus-group-describe-all-groups (&optional force)
"Force Gnus to read the .newsrc file."
(interactive "P")
(when (gnus-yes-or-no-p
- (format "Are you sure you want to read %s? "
- gnus-current-startup-file))
+ (format "Are you sure you want to restart Gnus? "))
(gnus-save-newsrc-file)
(gnus-setup-news 'force)
(gnus-group-list-groups arg)))
(sort (nconc (gnus-uncompress-range (cdr m))
(copy-sequence articles)) '<) t))))))
-(defun gnus-update-read-articles (group unread)
- "Update the list of read articles in GROUP."
- (let* ((active (or gnus-newsgroup-active (gnus-active group)))
- (entry (gnus-gethash group gnus-newsrc-hashtb))
- (info (nth 2 entry))
- (prev 1)
- (unread (sort (copy-sequence unread) '<))
- read)
- (if (or (not info) (not active))
- ;; There is no info on this group if it was, in fact,
- ;; killed. Gnus stores no information on killed groups, so
- ;; there's nothing to be done.
- ;; One could store the information somewhere temporarily,
- ;; perhaps... Hmmm...
- ()
- ;; Remove any negative articles numbers.
- (while (and unread (< (car unread) 0))
- (setq unread (cdr unread)))
- ;; Remove any expired article numbers
- (while (and unread (< (car unread) (car active)))
- (setq unread (cdr unread)))
- ;; Compute the ranges of read articles by looking at the list of
- ;; unread articles.
- (while unread
- (if (/= (car unread) prev)
- (setq read (cons (if (= prev (1- (car unread))) prev
- (cons prev (1- (car unread)))) read)))
- (setq prev (1+ (car unread)))
- (setq unread (cdr unread)))
- (when (<= prev (cdr active))
- (setq read (cons (cons prev (cdr active)) read)))
- (gnus-undo-register
- `(progn
- (gnus-info-set-marks ,info ,(gnus-info-marks info))
- (gnus-info-set-read ,info ,(gnus-info-read info))
- (gnus-get-unread-articles-in-group ,info (gnus-active ,group))))
- ;; Enter this list into the group info.
- (gnus-info-set-read
- info (if (> (length read) 1) (nreverse read) read))
- ;; Set the number of unread articles in gnus-newsrc-hashtb.
- (gnus-get-unread-articles-in-group info (gnus-active group))
- t)))
-
(provide 'gnus-group)
;;; gnus-group.el ends here