;;; gnus-sum.el --- summary mode commands for Gnus
;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007 Free Software Foundation, Inc.
+;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; 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
;; 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 <http://www.gnu.org/licenses/>.
;;; 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-mode))
+ (require 'cl))
+
+(defvar tool-bar-mode)
+(defvar gnus-tmp-header)
(require 'gnus)
(require 'gnus-group)
See `gnus-group-goto-unread'."
:link '(custom-manual "(gnus)Group Maneuvering")
:group 'gnus-summary-exit
- :version "23.0" ;; No Gnus
+ :version "23.1" ;; No Gnus
:type 'boolean)
(defcustom gnus-fetch-old-headers nil
The server has to support NOV for any of this to work.
This feature can seriously impact performance it ignores all
-locally cached header entries."
+locally cached header entries. Setting it to t for groups for a
+server that doesn't expire articles (such as news.gmane.org),
+leads to very slow summary generation."
:group 'gnus-thread
:type '(choice (const :tag "off" nil)
(const :tag "on" t)
If it has any other value or there is no next (unread) article, the
article selected before entering to the ephemeral group will appear."
- :version "23.0" ;; No Gnus
+ :version "23.1" ;; No Gnus
:group 'gnus-summary-maneuvering
:type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
(const next) (const next-unread)
:group 'gnus-summary
:type 'boolean)
+(defcustom gnus-mark-copied-or-moved-articles-as-expirable nil
+ "If non-nil, mark articles copied or moved to auto-expire group as expirable.
+If nil, the expirable marks will be unchanged except that the marks
+will be removed when copying or moving articles to a group that has
+not turned auto-expire on. If non-nil, articles that have been read
+will be marked as expirable when being copied or moved to a group in
+which auto-expire is turned on."
+ :version "23.2"
+ :type 'boolean
+ :group 'gnus-summary-marks)
+
(defcustom gnus-view-pseudos nil
"*If `automatic', pseudo-articles will be viewed automatically.
If `not-confirm', pseudos will be viewed automatically, and the user
:group 'gnus-summary-visual
:type '(repeat (cons (sexp :tag "Form" nil)
face)))
+(put 'gnus-summary-highlight 'risky-local-variable t)
(defcustom gnus-alter-header-function nil
"Function called to allow alteration of article header structures.
:type '(repeat symbol)
:group 'gnus-charset)
+(defcustom gnus-newsgroup-maximum-articles nil
+ "The maximum number of articles a newsgroup.
+If this is a number, old articles in a newsgroup exceeding this number
+are silently ignored. If it is nil, no article is ignored. Note that
+setting this variable to a number might prevent you from reading very
+old articles."
+ :group 'gnus-group-select
+ :version "22.2"
+ :type '(choice (const :tag "No limit" nil)
+ integer))
+
(gnus-define-group-parameter
ignored-charsets
:type list
:type 'boolean
:group 'gnus-summary-marks)
+(defcustom gnus-propagate-marks t
+ "If non-nil, do not propagate marks to the backends."
+ :version "23.1" ;; No Gnus
+ :type 'boolean
+ :group 'gnus-summary-marks)
+
(defcustom gnus-alter-articles-to-read-function nil
"Function to be called to alter the list of articles to be selected."
:type '(choice (const nil) function)
:group 'gnus-summary
:type '(choice boolean regexp))
+(defcustom gnus-summary-pipe-output-default-command nil
+ "Command (and optional arguments) used to pipe article to subprocess.
+This will be used as the default command if it is non-nil. The value
+will be updated if you modify it when executing the command
+`gnus-summary-pipe-output' or the function `gnus-summary-save-in-pipe'."
+ :version "23.1" ;; No Gnus
+ :group 'gnus-summary
+ :type '(radio (const :tag "None" nil) (string :tag "Command")))
+
(defcustom gnus-summary-muttprint-program "muttprint"
- "Command (and optional arguments) used to run Muttprint."
+ "Command (and optional arguments) used to run Muttprint.
+The value will be updated if you modify it when executing the command
+`gnus-summary-muttprint'."
:version "22.1"
:group 'gnus-summary
:type 'string)
(?E gnus-newsgroup-expunged-tally ?d)
(?s (gnus-current-score-file-nondirectory) ?s)))
+;; This is here rather than in gnus-art for compilation reasons.
+(defvar gnus-article-mode-line-format-alist
+ (nconc '((?w (gnus-article-wash-status) ?s)
+ (?m (gnus-article-mime-part-status) ?s))
+ gnus-summary-mode-line-format-alist))
+
(defvar gnus-last-search-regexp nil
"Default regexp for article search command.")
\"^From:\\\\|^Newsgroups:\\\\|^Subject:\\\\|^Date:\\\\|^To:\")))
")
-;; Byte-compiler warning.
(eval-when-compile
;; Bind features so that require will believe that gnus-sum has
;; already been loaded (avoids infinite recursion)
(let ((features (cons 'gnus-sum features)))
- ;; Several of the declarations in gnus-sum are needed to load the
- ;; following files. Right now, these definitions have been
- ;; compiled but not defined (evaluated). We could either do a
- ;; eval-and-compile about all of the declarations or evaluate the
- ;; source file.
- (if (boundp 'gnus-newsgroup-variables)
- nil
- (load "gnus-sum.el" t t t))
- (require 'gnus)
(require 'gnus-art)))
;; MIME stuff.
(eq gnus-newsgroup-name
(car gnus-decode-encoded-word-methods-cache)))
(setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
- (mapcar (lambda (x)
- (if (symbolp x)
- (nconc gnus-decode-encoded-word-methods-cache (list x))
- (if (and gnus-newsgroup-name
- (string-match (car x) gnus-newsgroup-name))
- (nconc gnus-decode-encoded-word-methods-cache
- (list (cdr x))))))
- gnus-decode-encoded-word-methods))
- (let ((xlist gnus-decode-encoded-word-methods-cache))
- (pop xlist)
- (while xlist
- (setq string (funcall (pop xlist) string))))
- string)
+ (dolist (method gnus-decode-encoded-word-methods)
+ (if (symbolp method)
+ (nconc gnus-decode-encoded-word-methods-cache (list method))
+ (if (and gnus-newsgroup-name
+ (string-match (car method) gnus-newsgroup-name))
+ (nconc gnus-decode-encoded-word-methods-cache
+ (list (cdr method)))))))
+ (dolist (method (cdr gnus-decode-encoded-word-methods-cache) string)
+ (setq string (funcall method string))))
;; Subject simplification.
(setq modified-tick (buffer-modified-tick))
(cond
((listp gnus-simplify-subject-fuzzy-regexp)
- (mapcar 'gnus-simplify-buffer-fuzzy-step
- gnus-simplify-subject-fuzzy-regexp))
+ (mapc 'gnus-simplify-buffer-fuzzy-step
+ gnus-simplify-subject-fuzzy-regexp))
(gnus-simplify-subject-fuzzy-regexp
(gnus-simplify-buffer-fuzzy-step gnus-simplify-subject-fuzzy-regexp)))
(gnus-simplify-buffer-fuzzy-step "^ *\\[[-+?*!][-+?*!]\\] *")
"?" gnus-summary-mark-as-dormant
"\C-c\M-\C-s" gnus-summary-limit-include-expunged
"\C-c\C-s\C-n" gnus-summary-sort-by-number
+ "\C-c\C-s\C-m\C-n" gnus-summary-sort-by-most-recent-number
"\C-c\C-s\C-l" gnus-summary-sort-by-lines
"\C-c\C-s\C-c" gnus-summary-sort-by-chars
"\C-c\C-s\C-a" gnus-summary-sort-by-author
"\C-c\C-s\C-t" gnus-summary-sort-by-recipient
"\C-c\C-s\C-s" gnus-summary-sort-by-subject
"\C-c\C-s\C-d" gnus-summary-sort-by-date
+ "\C-c\C-s\C-m\C-d" gnus-summary-sort-by-most-recent-date
"\C-c\C-s\C-i" gnus-summary-sort-by-score
"\C-c\C-s\C-o" gnus-summary-sort-by-original
"\C-c\C-s\C-r" gnus-summary-sort-by-random
(gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
"k" gnus-summary-kill-thread
+ "E" gnus-summary-expire-thread
"l" gnus-summary-lower-thread
"i" gnus-summary-raise-thread
"T" gnus-summary-toggle-threads
"g" gnus-summary-show-article
"s" gnus-summary-isearch-article
"P" gnus-summary-print-article
+ "S" gnus-sticky-article
"M" gnus-mailing-list-insinuate
"t" gnus-article-babel)
"O" gnus-uu-decode-save
"b" gnus-uu-decode-binhex
"B" gnus-uu-decode-binhex
+ "Y" gnus-uu-decode-yenc
"p" gnus-uu-decode-postscript
"P" gnus-uu-decode-postscript-and-save)
["Set mark below..." gnus-score-set-mark-below t]
["Set expunge below..." gnus-score-set-expunge-below t]
["Edit current score file" gnus-score-edit-current-scores t]
- ["Edit score file" gnus-score-edit-file t]
+ ["Edit score file..." gnus-score-edit-file t]
["Trace score" gnus-score-find-trace t]
["Find words" gnus-score-find-favourite-words t]
["Rescore buffer" gnus-summary-rescore t]
["Remove article" gnus-cache-remove-article t])
["Translate" gnus-article-babel t]
["Select article buffer" gnus-summary-select-article-buffer t]
+ ["Make article buffer sticky" gnus-sticky-article t]
["Enter digest buffer" gnus-summary-enter-digest-group t]
["Isearch article..." gnus-summary-isearch-article t]
["Beginning of the article" gnus-summary-beginning-of-article t]
["Go up thread" gnus-summary-up-thread t]
["Top of thread" gnus-summary-top-thread t]
["Mark thread as read" gnus-summary-kill-thread t]
+ ["Mark thread as expired" gnus-summary-expire-thread t]
["Lower thread score" gnus-summary-lower-thread t]
["Raise thread score" gnus-summary-raise-thread t]
["Rethread current" gnus-summary-rethread-current t]))
["Followup via news" gnus-summary-followup-to-mail t]
["Followup via news and yank"
gnus-summary-followup-to-mail-with-original t]
+ ["Strip signature on reply"
+ (lambda ()
+ (interactive)
+ (if (not (memq message-cite-function
+ '(message-cite-original-without-signature
+ message-cite-original)))
+ ;; Stupid workaround for XEmacs not honoring :visible.
+ (message "Can't toggle this value of `message-cite-function'")
+ (setq message-cite-function
+ (if (eq message-cite-function
+ 'message-cite-original-without-signature)
+ 'message-cite-original
+ 'message-cite-original-without-signature))))
+ ;; XEmacs barfs on :visible.
+ ,@(if (featurep 'xemacs) nil
+ '(:visible (memq message-cite-function
+ '(message-cite-original-without-signature
+ message-cite-original))))
+ :style toggle
+ :selected (eq message-cite-function
+ 'message-cite-original-without-signature)
+ ,@(if (featurep 'xemacs) nil
+ '(:help "Strip signature from cited article when replying."))]
;;("Draft"
;;["Send" gnus-summary-send-draft t]
;;["Send bounced" gnus-resend-bounced-mail t])
gnus-newsgroup-process-stack]
["Save" gnus-summary-save-process-mark t]
["Run command on marked..." gnus-summary-universal-argument t]))
+ ("Registry Marks")
("Scroll article"
["Page forward" gnus-summary-next-page
,@(if (featurep 'xemacs) '(t)
["Pop article off history" gnus-summary-pop-article t])
("Sort"
["Sort by number" gnus-summary-sort-by-number t]
+ ["Sort by most recent number" gnus-summary-sort-by-most-recent-number t]
["Sort by author" gnus-summary-sort-by-author t]
["Sort by recipient" gnus-summary-sort-by-recipient t]
["Sort by subject" gnus-summary-sort-by-subject t]
["Sort by date" gnus-summary-sort-by-date t]
+ ["Sort by most recent date" gnus-summary-sort-by-most-recent-date t]
["Sort by score" gnus-summary-sort-by-score t]
["Sort by lines" gnus-summary-sort-by-lines t]
["Sort by characters" gnus-summary-sort-by-chars t]
(const :tag "Retro look" gnus-summary-tool-bar-retro)
(repeat :tag "User defined list" gmm-tool-bar-item)
(symbol))
- :version "23.0" ;; No Gnus
+ :version "23.1" ;; No Gnus
:initialize 'custom-initialize-default
:set 'gnus-summary-tool-bar-update
:group 'gnus-summary)
See `gmm-tool-bar-from-list' for the format of the list."
:type '(repeat gmm-tool-bar-item)
- :version "23.0" ;; No Gnus
+ :version "23.1" ;; No Gnus
:initialize 'custom-initialize-default
:set 'gnus-summary-tool-bar-update
:group 'gnus-summary)
See `gmm-tool-bar-from-list' for the format of the list."
:type '(repeat gmm-tool-bar-item)
- :version "23.0" ;; No Gnus
+ :version "23.1" ;; No Gnus
:initialize 'custom-initialize-default
:set 'gnus-summary-tool-bar-update
:group 'gnus-summary)
See `gmm-tool-bar-from-list' for the format of the list."
:type 'gmm-tool-bar-zap-list
- :version "23.0" ;; No Gnus
+ :version "23.1" ;; No Gnus
:initialize 'custom-initialize-default
:set 'gnus-summary-tool-bar-update
:group 'gnus-summary)
(defvar image-load-path)
+(defvar tool-bar-map)
(defun gnus-summary-make-tool-bar (&optional force)
"Make a summary mode tool bar from `gnus-summary-tool-bar'.
(setq headers (cdr headers)))
(list (nreverse outh))))))))
+
+(declare-function turn-on-gnus-mailing-list-mode "gnus-ml" ())
+
\f
(defun gnus-summary-mode (&optional group)
(setq buffer-read-only t ;Disable modification
show-trailing-whitespace nil)
(setq truncate-lines t)
- (setq selective-display t)
- (setq selective-display-ellipses t) ;Display `...'
+ (add-to-invisibility-spec '(gnus-sum . t))
(gnus-summary-set-display-table)
(gnus-set-default-directory)
(make-local-variable 'gnus-summary-line-format)
(defun gnus-restore-hidden-threads-configuration (config)
"Restore hidden threads configuration from CONFIG."
(save-excursion
- (let (point buffer-read-only)
+ (let (point (inhibit-read-only t))
(while (setq point (pop config))
(when (and (< point (point-max))
(goto-char point)
(i 32))
;; Nix out all the control chars...
(while (>= (setq i (1- i)) 0)
- (aset table i [??]))
+ (gnus-put-display-table i [??] table))
;; ... but not newline and cr, of course. (cr is necessary for the
;; selective display).
- (aset table ?\n nil)
- (aset table ?\r nil)
+ (gnus-put-display-table ?\n nil table)
+ (gnus-put-display-table ?\r nil table)
;; We keep TAB as well.
- (aset table ?\t nil)
+ (gnus-put-display-table ?\t nil table)
;; We nix out any glyphs 127 through 255, or 127 through 159 in
;; Emacs 23 (unicode), that are not set already.
(let ((i (if (ignore-errors (= (make-char 'latin-iso8859-1 160) 160))
256)))
(while (>= (setq i (1- i)) 127)
;; Only modify if the entry is nil.
- (unless (aref table i)
- (aset table i [??]))))
+ (unless (gnus-get-display-table i table)
+ (gnus-put-display-table i [??] table))))
(setq buffer-display-table table)))
(defun gnus-summary-set-article-display-arrow (pos)
"Update the overlay arrow to point to line at position POS."
- (when (and gnus-summary-display-arrow
- (boundp 'overlay-arrow-position)
- (boundp 'overlay-arrow-string))
+ (when gnus-summary-display-arrow
+ (make-local-variable 'overlay-arrow-position)
+ (make-local-variable 'overlay-arrow-string)
(save-excursion
(goto-char pos)
(beginning-of-line)
(gnus-tmp-subject (mail-header-subject gnus-tmp-header))
(gnus-tmp-opening-bracket (if gnus-tmp-dummy ?\< ?\[))
(gnus-tmp-closing-bracket (if gnus-tmp-dummy ?\> ?\]))
- (buffer-read-only nil))
+ (inhibit-read-only t))
(when (string= gnus-tmp-name "")
(setq gnus-tmp-name gnus-tmp-from))
(unless (numberp gnus-tmp-lines)
(if (= gnus-tmp-lines -1)
(setq gnus-tmp-lines "?")
(setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
- (gnus-put-text-property
- (point)
- (progn (eval gnus-summary-line-format-spec) (point))
- 'gnus-number gnus-tmp-number)
+ (condition-case ()
+ (gnus-put-text-property
+ (point)
+ (progn (eval gnus-summary-line-format-spec) (point))
+ 'gnus-number gnus-tmp-number)
+ (error (gnus-message 5 "Error updating the summary line")))
(when (gnus-visual-p 'summary-highlight 'highlight)
(forward-line -1)
(gnus-run-hooks 'gnus-summary-update-hook)
(consp (cdr elem)) ; The cdr has to be a list.
(symbolp (car elem)) ; Has to be a symbol in there.
(not (memq (car elem) vars))
- (ignore-errors ; So we set it.
+ (ignore-errors
(push (car elem) vars)
- (make-local-variable (car elem))
- (set (car elem) (eval (nth 1 elem))))))))
+ ;; Variables like `gnus-show-threads' that are globally
+ ;; bound, if used as group parameters, need to get to be
+ ;; buffer-local, whereas just parameters like `gcc-self',
+ ;; `timestamp', etc. should not be bound as variables.
+ (if (boundp (car elem))
+ (set (make-local-variable (car elem)) (eval (nth 1 elem)))
+ (eval (nth 1 elem))))))))
(defun gnus-summary-read-group (group &optional show-all no-article
kill-buffer no-display backward
(defun gnus-summary-prepare ()
"Generate the summary buffer."
(interactive)
- (let ((buffer-read-only nil))
+ (let ((inhibit-read-only t))
(erase-buffer)
(setq gnus-newsgroup-data nil
gnus-newsgroup-data-reverse nil)
"Query where the respool algorithm would put this article."
(interactive)
(gnus-summary-select-article)
- (message (gnus-general-simplify-subject (gnus-summary-article-subject))))
+ (message "%s" (gnus-general-simplify-subject (gnus-summary-article-subject))))
(defun gnus-gather-threads-by-subject (threads)
"Gather threads by looking at Subject headers."
(erase-buffer)))
(kill-buffer (current-buffer)))
;; Sort over trustworthiness.
- (mapcar
- (lambda (relation)
- (when (gnus-dependencies-add-header
- (make-full-mail-header
- gnus-reffed-article-number
- (nth 3 relation) "" (or (nth 4 relation) "")
- (nth 1 relation)
- (or (nth 2 relation) "") 0 0 "")
- gnus-newsgroup-dependencies nil)
- (push gnus-reffed-article-number gnus-newsgroup-limit)
- (push gnus-reffed-article-number gnus-newsgroup-sparse)
- (push (cons gnus-reffed-article-number gnus-sparse-mark)
- gnus-newsgroup-reads)
- (decf gnus-reffed-article-number)))
- (sort relations 'car-less-than-car))
+ (dolist (relation (sort relations 'car-less-than-car))
+ (when (gnus-dependencies-add-header
+ (make-full-mail-header
+ gnus-reffed-article-number
+ (nth 3 relation) "" (or (nth 4 relation) "")
+ (nth 1 relation)
+ (or (nth 2 relation) "") 0 0 "")
+ gnus-newsgroup-dependencies nil)
+ (push gnus-reffed-article-number gnus-newsgroup-limit)
+ (push gnus-reffed-article-number gnus-newsgroup-sparse)
+ (push (cons gnus-reffed-article-number gnus-sparse-mark)
+ gnus-newsgroup-reads)
+ (decf gnus-reffed-article-number)))
(gnus-message 7 "Making sparse threads...done")))
(defun gnus-build-old-threads ()
(let ((deps gnus-newsgroup-dependencies)
found header)
(prog1
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (with-current-buffer nntp-server-buffer
(let ((case-fold-search nil))
(goto-char (point-min))
(while (and (not found)
(mail-parse-charset gnus-newsgroup-charset)
(dependencies gnus-newsgroup-dependencies)
header article)
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (with-current-buffer nntp-server-buffer
(let ((case-fold-search nil))
(goto-char (point-min))
(while (not (eobp))
(gnus-summary-goto-subject article)
(let* ((datal (gnus-data-find-list article))
(data (car datal))
- (buffer-read-only nil)
+ (inhibit-read-only t)
(level (gnus-summary-thread-level)))
(gnus-delete-line)
(let ((inserted (- (point)
(not (equal "" references)))
references))
"none")))
- (buffer-read-only nil)
+ (inhibit-read-only t)
(old (car thread)))
(when thread
(unless iheader
(defun gnus-rebuild-thread (id &optional line)
"Rebuild the thread containing ID.
If LINE, insert the rebuilt thread starting on line LINE."
- (let ((buffer-read-only nil)
+ (let ((inhibit-read-only t)
old-pos current thread data)
(if (not gnus-show-threads)
(setq thread (list (car (gnus-id-to-thread id))))
(gnus-thread-header h1) (gnus-thread-header h2)))
(defsubst gnus-article-sort-by-random (h1 h2)
- "Sort articles by article number."
+ "Sort articles randomly."
(zerop (random 2)))
(defun gnus-thread-sort-by-random (h1 h2)
- "Sort threads by root article number."
+ "Sort threads randomly."
(gnus-article-sort-by-random
(gnus-thread-header h1) (gnus-thread-header h2)))
(defsubst gnus-article-sort-by-author (h1 h2)
"Sort articles by root author."
- (string-lessp
+ (gnus-string<
(let ((extract (funcall
gnus-extract-address-components
(mail-header-from h1))))
(defsubst gnus-article-sort-by-recipient (h1 h2)
"Sort articles by recipient."
- (string-lessp
+ (gnus-string<
(let ((extract (funcall
gnus-extract-address-components
(or (cdr (assq 'To (mail-header-extra h1))) ""))))
(defsubst gnus-article-sort-by-subject (h1 h2)
"Sort articles by root subject."
- (string-lessp
+ (gnus-string<
(downcase (gnus-simplify-subject-re (mail-header-subject h1)))
(downcase (gnus-simplify-subject-re (mail-header-subject h2)))))
(lambda (header)
(setq previous-time
(condition-case ()
- (time-to-seconds (mail-header-parse-date
+ (gnus-float-time (mail-header-parse-date
(mail-header-date header)))
(error previous-time))))
(sort
(defvar gnus-tmp-root-expunged nil)
(defvar gnus-tmp-dummy-line nil)
-(eval-when-compile (defvar gnus-tmp-header))
(defun gnus-extra-header (type &optional header)
"Return the extra header of TYPE."
(or (cdr (assq type (mail-header-extra (or header gnus-tmp-header))))
:type 'string
:group 'gnus-thread)
+(defcustom gnus-summary-display-while-building nil
+ "If non-nil, show and update the summary buffer as it's being built.
+If the value is t, update the buffer after every line is inserted. If
+the value is an integer (N), update the display every N lines."
+ :version "22.1"
+ :group 'gnus-thread
+ :type '(choice (const :tag "off" nil)
+ number
+ (const :tag "frequently" t)))
+
(defun gnus-summary-prepare-threads (threads)
"Prepare summary buffer from THREADS and indentation LEVEL.
THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'
(setq gnus-tmp-lines "?")
(setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
(gnus-put-text-property
- (point)
- (progn (eval gnus-summary-line-format-spec) (point))
+ (point)
+ (progn (eval gnus-summary-line-format-spec) (point))
'gnus-number number)
- (when gnus-visual-p
- (forward-line -1)
- (gnus-run-hooks 'gnus-summary-update-hook)
- (forward-line 1))
+ (when gnus-visual-p
+ (forward-line -1)
+ (gnus-run-hooks 'gnus-summary-update-hook)
+ (forward-line 1))
- (setq gnus-tmp-prev-subject simp-subject)))
+ (setq gnus-tmp-prev-subject simp-subject)))
(when (nth 1 thread)
(push (list (max 0 gnus-tmp-level)
(gnus-inverse-list-range-intersection
gnus-newsgroup-articles gnus-newsgroup-seen))))
+(declare-function gnus-get-predicate "gnus-agent" (predicate))
+
(defun gnus-summary-display-make-predicate (display)
(require 'gnus-agent)
(when (= (length display) 1)
(gnus-get-predicate display)))
;; Uses the dynamically bound `number' variable.
-(eval-when-compile
- (defvar number))
+(defvar number)
(defun gnus-article-marked-p (type &optional article)
(let ((article (or article number)))
(cond
;; articles in the group, or (if that's nil), the
;; articles in the cache.
(or
- (gnus-uncompress-range (gnus-active group))
+ (if gnus-newsgroup-maximum-articles
+ (let ((active (gnus-active group)))
+ (gnus-uncompress-range
+ (cons (max (car active)
+ (- (cdr active)
+ gnus-newsgroup-maximum-articles
+ -1))
+ (cdr active))))
+ (gnus-uncompress-range (gnus-active group)))
(gnus-cache-articles-in-group group))
;; Select only the "normal" subset of articles.
(gnus-sorted-nunion
(symbol-value
(intern (format "gnus-%s-mode-line-format-spec" where))))
(let (mode-string)
- (save-excursion
- ;; We evaluate this in the summary buffer since these
- ;; variables are buffer-local to that buffer.
- (set-buffer gnus-summary-buffer)
- ;; We bind all these variables that are used in the `eval' form
+ ;; We evaluate this in the summary buffer since these
+ ;; variables are buffer-local to that buffer.
+ (with-current-buffer gnus-summary-buffer
+ ;; We bind all these variables that are used in the `eval' form
;; below.
(let* ((mformat (symbol-value
(intern
headers id end ref number
(mail-parse-charset gnus-newsgroup-charset)
(mail-parse-ignored-charsets
- (save-excursion (condition-case nil
- (set-buffer gnus-summary-buffer)
- (error))
- gnus-newsgroup-ignored-charsets)))
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (save-current-buffer (condition-case nil
+ (set-buffer gnus-summary-buffer)
+ (error))
+ gnus-newsgroup-ignored-charsets)))
+ (with-current-buffer nntp-server-buffer
;; Translate all TAB characters into SPACE characters.
(subst-char-in-region (point-min) (point-max) ?\t ? t)
(subst-char-in-region (point-min) (point-max) ?\r ? t)
(t
nil)))
number headers header)
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (with-current-buffer nntp-server-buffer
(subst-char-in-region (point-min) (point-max) ?\r ? t)
;; Allow the user to mangle the headers before parsing them.
(gnus-run-hooks 'gnus-parse-headers-hook)
"Return a list of articles to be worked upon.
The prefix argument, the list of process marked articles, and the
current article will be taken into consideration."
- (save-excursion
- (set-buffer gnus-summary-buffer)
+ (with-current-buffer gnus-summary-buffer
(cond
(n
;; A numerical prefix has been given.
(defun gnus-summary-search-group (&optional backward use-level)
"Search for next unread newsgroup.
If optional argument BACKWARD is non-nil, search backward instead."
- (save-excursion
- (set-buffer gnus-group-buffer)
+ (with-current-buffer gnus-group-buffer
(when (gnus-group-search-forward
backward nil (if use-level (gnus-group-group-level) nil))
(gnus-group-group-name))))
(when (and gnus-auto-center-summary
(not (eq gnus-auto-center-summary 'vertical)))
(gnus-horizontal-recenter))
- (recenter n))
+ (if (fboundp 'recenter-top-bottom)
+ (recenter-top-bottom n)
+ (recenter n)))
+
+(put 'gnus-recenter 'isearch-scroll t)
+
+(defun gnus-forward-line-ignore-invisible (n)
+ "Move N lines forward (backward if N is negative).
+Like forward-line, but skip over (and don't count) invisible lines."
+ (let (done)
+ (while (and (> n 0) (not done))
+ ;; If the following character is currently invisible,
+ ;; skip all characters with that same `invisible' property value.
+ (while (gnus-invisible-p (point))
+ (goto-char (gnus-next-char-property-change (point))))
+ (forward-line 1)
+ (if (eobp)
+ (setq done t)
+ (setq n (1- n))))
+ (while (and (< n 0) (not done))
+ (forward-line -1)
+ (if (bobp) (setq done t)
+ (setq n (1+ n))
+ (while (and (not (bobp)) (gnus-invisible-p (1- (point))))
+ (goto-char (gnus-previous-char-property-change (point))))))))
(defun gnus-summary-recenter ()
"Center point in the summary window.
gnus-auto-center-summary
(/ (1- (window-height)) 2)))))
(height (1- (window-height)))
- (bottom (save-excursion (goto-char (point-max))
- (forward-line (- height))
- (point)))
+ (bottom (save-excursion
+ (goto-char (point-max))
+ (gnus-forward-line-ignore-invisible (- height))
+ (point)))
(window (get-buffer-window (current-buffer))))
(when (get-buffer-window gnus-article-buffer)
;; Only do recentering when the article buffer is displayed,
;; Set the window start to either `bottom', which is the biggest
;; possible valid number, or the second line from the top,
;; whichever is the least.
- (let ((top-pos (save-excursion (forward-line (- top)) (point))))
+ (let ((top-pos (save-excursion
+ (gnus-forward-line-ignore-invisible (- top))
+ (point))))
(if (> bottom top-pos)
;; Keep the second line from the top visible
(set-window-start window top-pos)
;; visible, or revert to using TOP-POS.
(save-excursion
(goto-char (point-max))
- (forward-line -1)
+ (gnus-forward-line-ignore-invisible -1)
(let ((last-line-start (point)))
(goto-char bottom)
(set-window-start window (point) t)
(when (not (pos-visible-in-window-p last-line-start window))
- (forward-line 1)
+ (gnus-forward-line-ignore-invisible 1)
(set-window-start window (min (point) top-pos) t)))))))
;; Do horizontal recentering while we're at it.
(when (and (get-buffer-window (current-buffer) t)
(gnus-group-jump-to-group newsgroup))
(save-excursion
;; Take care of tree window mode.
- (if (get-buffer-window gnus-group-buffer)
+ (if (get-buffer-window gnus-group-buffer 0)
(pop-to-buffer gnus-group-buffer)
(set-buffer gnus-group-buffer))
(gnus-group-jump-to-group newsgroup))))
(active (or (gnus-active group) (gnus-activate-group group)))
(last (or (cdr active)
(error "Group %s couldn't be activated " group)))
+ (bottom (if gnus-newsgroup-maximum-articles
+ (max (car active)
+ (- last gnus-newsgroup-maximum-articles -1))
+ (car active)))
first nlast unread)
;; If none are read, then all are unread.
(if (not read)
- (setq first (car active))
+ (setq first bottom)
;; If the range of read articles is a single range, then the
;; first unread article is the article after the last read
;; article. Sounds logical, doesn't it?
(if (and (not (listp (cdr read)))
- (or (< (car read) (car active))
+ (or (< (car read) bottom)
(progn (setq read (list read))
nil)))
- (setq first (max (car active) (1+ (cdr read))))
+ (setq first (max bottom (1+ (cdr read))))
;; `read' is a list of ranges.
(when (/= (setq nlast (or (and (numberp (car read)) (car read))
(caar read)))
1)
- (setq first (car active)))
+ (setq first bottom))
(while read
(when first
(while (< first nlast)
(gnus-list-range-difference
(gnus-list-range-difference
(gnus-sorted-complement
- (gnus-uncompress-range active)
+ (gnus-uncompress-range
+ (if gnus-newsgroup-maximum-articles
+ (cons (max (car active)
+ (- (cdr active)
+ gnus-newsgroup-maximum-articles
+ -1))
+ (cdr active))
+ active))
(gnus-list-of-unread-articles group))
(cdr (assq 'dormant marked)))
(cdr (assq 'tick marked))))))
(let* ((read (gnus-info-read (gnus-get-info group)))
(active (or (gnus-active group) (gnus-activate-group group)))
(last (cdr active))
+ (bottom (if gnus-newsgroup-maximum-articles
+ (max (car active)
+ (- last gnus-newsgroup-maximum-articles -1))
+ (car active)))
first nlast unread)
;; If none are read, then all are unread.
(if (not read)
- (setq first (car active))
+ (setq first bottom)
;; If the range of read articles is a single range, then the
;; first unread article is the article after the last read
;; article. Sounds logical, doesn't it?
(if (and (not (listp (cdr read)))
- (or (< (car read) (car active))
+ (or (< (car read) bottom)
(progn (setq read (list read))
nil)))
- (setq first (max (car active) (1+ (cdr read))))
+ (setq first (max bottom (1+ (cdr read))))
;; `read' is a list of ranges.
(when (/= (setq nlast (or (and (numberp (car read)) (car read))
(caar read)))
1)
- (setq first (car active)))
+ (setq first bottom))
(while read
(when first
(push (cons first nlast) unread))
(gnus-save-newsrc-file)
(gnus-dribble-save)))
+(declare-function gnus-cache-write-active "gnus-cache" (&optional force))
+
(defun gnus-summary-exit (&optional temporary leave-hidden)
"Exit reading current newsgroup, and then return to group selection mode.
`gnus-exit-group-hook' is called with no arguments if that value is non-nil."
(interactive)
(gnus-set-global-variables)
(when (gnus-buffer-live-p gnus-article-buffer)
- (save-excursion
- (set-buffer gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
(mm-destroy-parts gnus-article-mime-handles)
;; Set it to nil for safety reason.
(setq gnus-article-mime-handle-alist nil)
(gnus-run-hooks 'gnus-summary-prepare-exit-hook)
;; If we have several article buffers, we kill them at exit.
(unless gnus-single-article-buffer
- (gnus-kill-buffer gnus-article-buffer)
- (gnus-kill-buffer gnus-original-article-buffer)
- (setq gnus-article-current nil))
+ (when (gnus-buffer-live-p gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
+ ;; Don't kill sticky article buffers
+ (unless (eq major-mode 'gnus-sticky-article-mode)
+ (gnus-kill-buffer gnus-article-buffer)
+ (setq gnus-article-current nil))))
+ (gnus-kill-buffer gnus-original-article-buffer))
(when gnus-use-cache
(gnus-cache-possibly-remove-articles)
(gnus-cache-save-buffers))
(setq group-point (point))
(if temporary
nil ;Nothing to do.
- ;; If we have several article buffers, we kill them at exit.
- (unless gnus-single-article-buffer
- (gnus-kill-buffer gnus-article-buffer)
- (gnus-kill-buffer gnus-original-article-buffer)
- (setq gnus-article-current nil))
(set-buffer buf)
(if (not gnus-kill-summary-on-exit)
(progn
(gnus-async-halt-prefetch)
(run-hooks 'gnus-summary-prepare-exit-hook)
(when (gnus-buffer-live-p gnus-article-buffer)
- (save-excursion
- (set-buffer gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
(mm-destroy-parts gnus-article-mime-handles)
;; Set it to nil for safety reason.
(setq gnus-article-mime-handle-alist nil)
(cond ((eq major-mode 'gnus-summary-mode)
(gnus-set-global-variables))
((eq major-mode 'gnus-article-mode)
- (save-excursion
+ (save-current-buffer
;; The `gnus-summary-buffer' variable may point
;; to the old summary buffer when using a single
;; article buffer.
(gnus-kill-summary-on-exit
(when (and gnus-use-trees
(gnus-buffer-exists-p buffer))
- (save-excursion
- (set-buffer buffer)
+ (with-current-buffer buffer
(gnus-tree-close gnus-newsgroup-name)))
(gnus-kill-buffer buffer))
;; Deaden the buffer.
((gnus-buffer-exists-p buffer)
- (save-excursion
- (set-buffer buffer)
+ (with-current-buffer buffer
(gnus-deaden-summary))))))
(defun gnus-summary-wake-up-the-dead (&rest args)
(gnus-summary-position-point))
(defun gnus-summary-goto-subject (article &optional force silent)
- "Go the subject line of ARTICLE.
+ "Go to the subject line of ARTICLE.
If FORCE, also allow jumping to articles not currently shown."
(interactive "nArticle number: ")
(unless (numberp article)
(defun gnus-summary-display-article (article &optional all-header)
"Display ARTICLE in article buffer."
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (mm-enable-multibyte)))
+ (unless (and (gnus-buffer-live-p gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
+ (eq major-mode 'gnus-article-mode)))
+ (gnus-article-setup-buffer))
(gnus-set-global-variables)
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (setq gnus-article-charset gnus-newsgroup-charset)
- (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
- (mm-enable-multibyte)))
+ (with-current-buffer gnus-article-buffer
+ (setq gnus-article-charset gnus-newsgroup-charset)
+ (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
+ (mm-enable-multibyte))
(if (null article)
nil
(prog1
(and (not pseudo)
(gnus-summary-article-pseudo-p article)
(error "This is a pseudo-article"))
- (save-excursion
- (set-buffer gnus-summary-buffer)
+ (with-current-buffer gnus-summary-buffer
(if (or (and gnus-single-article-buffer
(or (null gnus-current-article)
(null gnus-article-current)
(t
(unless (gnus-ephemeral-group-p gnus-newsgroup-name)
(gnus-summary-jump-to-group gnus-newsgroup-name))
- (let ((cmd last-command-char)
+ (let ((cmd (if (featurep 'xemacs)
+ last-command-char
+ last-command-event))
(point
(with-current-buffer gnus-group-buffer
(point)))
(?\C-p (gnus-group-prev-unread-group 1))))
(cursor-in-echo-area t)
keve key group ended prompt)
- (save-excursion
- (set-buffer gnus-group-buffer)
+ (with-current-buffer gnus-group-buffer
(goto-char start)
(setq group
(if (eq gnus-keep-same-level 'best)
(gnus-summary-article-subject))))
(defun gnus-summary-prev-article (&optional unread subject)
- "Select the article after the current one.
+ "Select the article before the current one.
If UNREAD is non-nil, only unread articles are selected."
(interactive "P")
(gnus-summary-next-article unread subject t))
(defalias 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
(make-obsolete
- 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
+ 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread "Emacs 20.4")
(defun gnus-summary-limit-to-unread (&optional all)
"Limit the summary buffer to articles that are not marked as read.
(defalias 'gnus-summary-delete-marked-with 'gnus-summary-limit-exclude-marks)
(make-obsolete 'gnus-summary-delete-marked-with
- 'gnus-summary-limit-exclude-marks)
+ 'gnus-summary-limit-exclude-marks "Emacs 20.4")
(defun gnus-summary-limit-exclude-marks (marks &optional reverse)
"Exclude articles that are marked with MARKS (e.g. \"DK\").
This entails weeding out unwanted dormants, low-scored articles,
fetch-old-headers verbiage, and so on."
;; Most groups have nothing to remove.
- (if (or gnus-inhibit-limiting
- (and (null gnus-newsgroup-dormant)
- (eq gnus-newsgroup-display 'gnus-not-ignore)
- (not (eq gnus-fetch-old-headers 'some))
- (not (numberp gnus-fetch-old-headers))
- (not (eq gnus-fetch-old-headers 'invisible))
- (null gnus-summary-expunge-below)
- (not (eq gnus-build-sparse-threads 'some))
- (not (eq gnus-build-sparse-threads 'more))
- (null gnus-thread-expunge-below)
- (not gnus-use-nocem)))
- () ; Do nothing.
+ (unless (or gnus-inhibit-limiting
+ (and (null gnus-newsgroup-dormant)
+ (eq gnus-newsgroup-display 'gnus-not-ignore)
+ (not (eq gnus-fetch-old-headers 'some))
+ (not (numberp gnus-fetch-old-headers))
+ (not (eq gnus-fetch-old-headers 'invisible))
+ (null gnus-summary-expunge-below)
+ (not (eq gnus-build-sparse-threads 'some))
+ (not (eq gnus-build-sparse-threads 'more))
+ (null gnus-thread-expunge-below)
+ (not gnus-use-nocem)))
(push gnus-newsgroup-limit gnus-newsgroup-limits)
(setq gnus-newsgroup-limit nil)
(mapatoms
;; References header, since this is slightly more
;; reliable than the References field we got from the
;; server.
- (save-excursion
- (set-buffer gnus-original-article-buffer)
+ (with-current-buffer gnus-original-article-buffer
(nnheader-narrow-to-headers)
(unless (setq ref (message-fetch-field "references"))
(when (setq ref (message-fetch-field "in-reply-to"))
(case-fold-search t)
(buf (current-buffer))
dig to-address)
- (save-excursion
- (set-buffer gnus-original-article-buffer)
+ (with-current-buffer gnus-original-article-buffer
;; Have the digest group inherit the main mail address of
;; the parent article.
(when (setq to-address (or (gnus-fetch-field "reply-to")
(nndoc-article-type guess))
t nil t))
(progn
- ;; Make all postings to this group go to the parent group.
+ ;; Make all postings to this group go to the parent group.
(nconc (gnus-info-params (gnus-get-info egroup))
params)
(push egroup groups))
This search includes all articles in the current group that Gnus has
fetched headers for, whether they are displayed or not."
(let ((articles nil)
+ ;; Can't eta-reduce because it's a macro.
(func `(lambda (h) (,(intern (concat "mail-header-" header)) h)))
(case-fold-search t))
(dolist (header gnus-newsgroup-headers)
(goto-char (point-max))
(recenter -3)
(when gnus-break-pages
- (when (re-search-backward page-delimiter nil t)
- (narrow-to-region (match-end 0) (point-max)))
(gnus-narrow-to-page))))
(defun gnus-summary-print-truncate-and-quote (string &optional len)
(mail-header-date gnus-current-headers) ")"))))
(gnus-run-hooks 'gnus-ps-print-hook)
(save-excursion
- (if window-system
+ (if ps-print-color-p
(ps-spool-buffer-with-faces)
(ps-spool-buffer)))))
(kill-buffer buffer))))
(gnus-summary-select-article nil 'force)
(let ((deps gnus-newsgroup-dependencies)
head header lines)
- (save-excursion
- (set-buffer gnus-original-article-buffer)
+ (with-current-buffer gnus-original-article-buffer
(save-restriction
(message-narrow-to-head)
(setq head (buffer-string))
gnus-break-pages)
;; Destroy any MIME parts.
(when (gnus-buffer-live-p gnus-article-buffer)
- (save-excursion
- (set-buffer gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
(mm-destroy-parts gnus-article-mime-handles)
;; Set it to nil for safety reason.
(setq gnus-article-mime-handle-alist nil)
(with-current-buffer gnus-article-buffer
(widen)
(article-narrow-to-head)
- (let* ((buffer-read-only nil)
+ (let* ((inhibit-read-only t)
(inhibit-point-motion-hooks t)
(hidden (if (numberp arg)
(>= arg 0)
(if gnus-break-pages
(gnus-narrow-to-page)
(when (gnus-visual-p 'page-marker)
- (let ((buffer-read-only nil))
+ (let ((inhibit-read-only t))
(gnus-remove-text-with-property 'gnus-prev)
(gnus-remove-text-with-property 'gnus-next))))
(gnus-set-mode-line 'article)))))
(save-restriction
(widen)
(let ((start (window-start))
- buffer-read-only)
+ (inhibit-read-only t))
(if (equal arg '(4))
(message-caesar-buffer-body nil t)
(message-caesar-buffer-body arg))
;; Create buttons and stuff...
(gnus-treat-article nil))
+(declare-function idna-to-unicode "ext:idna" (str))
+
(defun gnus-summary-idna-message (&optional arg)
"Decode IDNA encoded domain names in the current articles.
IDNA encoded domain names looks like `xn--bar'. If a string
(save-restriction
(widen)
(let ((pos (window-start))
- buffer-read-only)
+ (inhibit-read-only t))
(goto-char (point-min))
(when (message-goto-body)
(gnus-narrow-to-body))
(gnus-eval-in-buffer-window gnus-article-buffer
(widen)
(when (gnus-visual-p 'page-marker)
- (let ((buffer-read-only nil))
+ (let ((inhibit-read-only t))
(gnus-remove-text-with-property 'gnus-prev)
(gnus-remove-text-with-property 'gnus-next))
(setq gnus-page-broken nil))))
move-is-internal))) ; is this move internal?
;; Copy the article.
((eq action 'copy)
- (save-excursion
- (set-buffer copy-buf)
+ (with-current-buffer copy-buf
(when (gnus-request-article-this-buffer article gnus-newsgroup-name)
(save-restriction
(nnheader-narrow-to-headers)
(delete "Xref:" (delete new-xref xref))
" ")
" " new-xref))
- (save-excursion
- (set-buffer copy-buf)
+ (with-current-buffer copy-buf
;; First put the article in the destination group.
(gnus-request-article-this-buffer article gnus-newsgroup-name)
(when (consp (setq art-group
(list (cdr art-group)))))
;; See whether the article is to be put in the cache.
- (let ((marks (if (gnus-group-auto-expirable-p to-group)
- gnus-article-mark-lists
- (delete '(expirable . expire)
- (copy-sequence gnus-article-mark-lists))))
- (to-article (cdr art-group)))
+ (let* ((expirable (gnus-group-auto-expirable-p to-group))
+ (marks (if expirable
+ gnus-article-mark-lists
+ (delete '(expirable . expire)
+ (copy-sequence gnus-article-mark-lists))))
+ (to-article (cdr art-group)))
;; Enter the article into the cache in the new group,
;; if that is required.
to-group (cdar marks) (list to-article) info)))
(setq marks (cdr marks)))
+ (when (and expirable
+ gnus-mark-copied-or-moved-articles-as-expirable
+ (not (memq 'expire to-marks)))
+ ;; Mark this article as expirable.
+ (push 'expire to-marks)
+ (when (equal to-group gnus-newsgroup-name)
+ (push to-article gnus-newsgroup-expirable))
+ ;; Copy the expirable mark to other group.
+ (gnus-add-marked-articles
+ to-group 'expire (list to-article) info))
+
(gnus-request-set-mark
to-group (list (list (list to-article) 'add to-marks))))
;; Update the Xref header in this article to point to
;; the new crossposted article we have just created.
(when (eq action 'crosspost)
- (save-excursion
- (set-buffer copy-buf)
+ (with-current-buffer copy-buf
(gnus-request-article-this-buffer article gnus-newsgroup-name)
(nnheader-replace-header "Xref" new-xref)
(gnus-request-replace-article
(apply 'gnus-summary-remove-process-mark articles-to-update-marks)
;; Re-activate all groups that have been moved to.
- (save-excursion
- (set-buffer gnus-group-buffer)
+ (with-current-buffer gnus-group-buffer
(let ((gnus-group-marked to-groups))
(gnus-group-get-new-news-this-group nil t)))
:type 'symbol
:group 'gnus-summary-mail)
-(defcustom gnus-summary-display-while-building nil
- "If non-nil, show and update the summary buffer as it's being built.
-If the value is t, update the buffer after every line is inserted. If
-the value is an integer (N), update the display every N lines."
- :version "22.1"
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- number
- (const :tag "frequently" t)))
-
(defun gnus-summary-respool-article (&optional n method)
"Respool the current article.
The article will be squeezed through the mail spooling process again,
(or (file-readable-p file)
(not (file-regular-p file))
(error "Can't read %s" file))
- (save-excursion
- (set-buffer (gnus-get-buffer-create " *import file*"))
+ (with-current-buffer (gnus-get-buffer-create " *import file*")
(erase-buffer)
(nnheader-insert-file-contents file)
(goto-char (point-min))
group-art)
(unless (gnus-check-backend-function 'request-accept-article group)
(error "%s does not support article importing" group))
- (save-excursion
- (set-buffer (gnus-get-buffer-create " *import file*"))
+ (with-current-buffer (gnus-get-buffer-create " *import file*")
(erase-buffer)
(goto-char (point-min))
;; This doesn't look like an article, so we fudge some headers.
"nndraft:queue")))
(error "Can't edit the raw article in group %s"
gnus-newsgroup-name))
- (save-excursion
- (set-buffer gnus-summary-buffer)
+ (with-current-buffer gnus-summary-buffer
(let ((mail-parse-charset gnus-newsgroup-charset)
(mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets))
(gnus-set-global-variables)
(let ((nntp-server-buffer (current-buffer)))
(setq header (car (gnus-get-newsgroup-headers
nil t))))
- (save-excursion
- (set-buffer gnus-summary-buffer)
+ (with-current-buffer gnus-summary-buffer
(gnus-data-set-header
(gnus-data-find (cdr gnus-article-current))
header)
(cdr gnus-article-current))))
;; Prettify the article buffer again.
(unless no-highlight
- (save-excursion
- (set-buffer gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
;;;!!! Fix this -- article should be rehighlighted.
;;;(gnus-run-hooks 'gnus-article-display-hook)
(set-buffer gnus-original-article-buffer)
(interactive)
(let (gnus-mark-article-hook)
(gnus-summary-select-article)
- (save-excursion
- (set-buffer gnus-original-article-buffer)
+ (with-current-buffer gnus-original-article-buffer
(let ((groups (nnmail-article-group 'identity trace)))
(unless silent
(if groups
(unless (numberp article)
(error "%s is not a number" article))
(push article gnus-newsgroup-replied)
- (let ((buffer-read-only nil))
+ (let ((inhibit-read-only t))
(when (gnus-summary-goto-subject article nil t)
(gnus-summary-update-secondary-mark article))))))
(let ((articles (if (listp article) article (list article))))
(dolist (article articles)
(push article gnus-newsgroup-forwarded)
- (let ((buffer-read-only nil))
+ (let ((inhibit-read-only t))
(when (gnus-summary-goto-subject article nil t)
(gnus-summary-update-secondary-mark article))))))
(= mark gnus-dormant-mark) (= mark gnus-unread-mark))))
(when (gnus-summary-goto-subject article nil t)
- (let ((buffer-read-only nil))
+ (let ((inhibit-read-only t))
(gnus-summary-show-thread)
;; Fix the mark.
(gnus-summary-update-mark mark 'unread)
(defun gnus-summary-update-mark (mark type)
(let ((forward (cdr (assq type gnus-summary-mark-positions)))
- (buffer-read-only nil))
+ (inhibit-read-only t))
(re-search-backward "[\n\r]" (point-at-bol) 'move-to-limit)
(when forward
(when (looking-at "\r")
(defalias 'gnus-summary-mark-as-unread-forward
'gnus-summary-tick-article-forward)
(make-obsolete 'gnus-summary-mark-as-unread-forward
- 'gnus-summary-tick-article-forward)
+ 'gnus-summary-tick-article-forward "Emacs 20.4")
(defun gnus-summary-tick-article-forward (n)
"Tick N articles forwards.
If N is negative, tick backwards instead.
(defalias 'gnus-summary-mark-as-unread-backward
'gnus-summary-tick-article-backward)
(make-obsolete 'gnus-summary-mark-as-unread-backward
- 'gnus-summary-tick-article-backward)
+ 'gnus-summary-tick-article-backward "Emacs 20.4")
(defun gnus-summary-tick-article-backward (n)
"Tick N articles backwards.
The difference between N and the number of articles ticked is returned."
(gnus-summary-mark-forward (- n) gnus-ticked-mark))
(defalias 'gnus-summary-mark-as-unread 'gnus-summary-tick-article)
-(make-obsolete 'gnus-summary-mark-as-unread 'gnus-summary-tick-article)
+(make-obsolete 'gnus-summary-mark-as-unread 'gnus-summary-tick-article "Emacs 20.4")
(defun gnus-summary-tick-article (&optional article clear-mark)
"Mark current article as unread.
Optional 1st argument ARTICLE specifies article number to be marked as unread.
(gnus-summary-mark-forward (- n) gnus-unread-mark))
(defun gnus-summary-mark-unread-as-read ()
- "Intended to be used by `gnus-summary-mark-article-hook'."
+ "Intended to be used by `gnus-mark-article-hook'."
(when (memq gnus-current-article gnus-newsgroup-unreads)
(gnus-summary-mark-article gnus-current-article gnus-read-mark)))
(defun gnus-summary-mark-read-and-unread-as-read (&optional new-mark)
- "Intended to be used by `gnus-summary-mark-article-hook'."
+ "Intended to be used by `gnus-mark-article-hook'."
(let ((mark (gnus-summary-article-mark)))
(when (or (gnus-unread-mark-p mark)
(gnus-read-mark-p mark))
(or new-mark gnus-read-mark)))))
(defun gnus-summary-mark-current-read-and-unread-as-read (&optional new-mark)
- "Intended to be used by `gnus-summary-mark-article-hook'."
+ "Intended to be used by `gnus-mark-article-hook'."
(let ((mark (gnus-summary-article-mark)))
(when (or (gnus-unread-mark-p mark)
(gnus-read-mark-p mark))
(or new-mark gnus-read-mark)))))
(defun gnus-summary-mark-unread-as-ticked ()
- "Intended to be used by `gnus-summary-mark-article-hook'."
+ "Intended to be used by `gnus-mark-article-hook'."
(when (memq gnus-current-article gnus-newsgroup-unreads)
(gnus-summary-mark-article gnus-current-article gnus-ticked-mark)))
(setq score (if score
(prefix-numeric-value score)
(or gnus-summary-default-score 0)))
- (save-excursion
- (set-buffer gnus-summary-buffer)
+ (with-current-buffer gnus-summary-buffer
(goto-char (point-min))
(while
(progn
(setq score (if score
(prefix-numeric-value score)
(or gnus-summary-default-score 0)))
- (save-excursion
- (set-buffer gnus-summary-buffer)
+ (with-current-buffer gnus-summary-buffer
(goto-char (point-min))
(while (and (progn
(when (> (gnus-summary-article-score) score)
(defun gnus-summary-limit-include-expunged (&optional no-error)
"Display all the hidden articles that were expunged for low scores."
(interactive)
- (let ((buffer-read-only nil))
+ (let ((inhibit-read-only t))
(let ((scored gnus-newsgroup-scored)
headers h)
(while scored
(goto-char (point-min))
(push gnus-newsgroup-limit gnus-newsgroup-limits)
(setq gnus-newsgroup-limit (copy-sequence gnus-newsgroup-limit))
- (mapcar (lambda (x) (push (mail-header-number x)
- gnus-newsgroup-limit))
- headers)
+ (dolist (x headers)
+ (push (mail-header-number x) gnus-newsgroup-limit))
(gnus-summary-prepare-unthreaded (nreverse headers))
(goto-char (point-min))
(gnus-summary-position-point)
(gnus-message 6 "Threading is now %s" (if gnus-show-threads "on" "off"))
(gnus-summary-position-point)))
+(eval-and-compile
+ (if (fboundp 'remove-overlays)
+ (defalias 'gnus-remove-overlays 'remove-overlays)
+ (defun gnus-remove-overlays (beg end name val)
+ "Clear BEG and END of overlays whose property NAME has value VAL.
+For compatibility with Emacs 21 and XEmacs."
+ (dolist (ov (gnus-overlays-in beg end))
+ (when (eq (gnus-overlay-get ov name) val)
+ (gnus-delete-overlay ov))))))
+
(defun gnus-summary-show-all-threads ()
"Show all threads."
(interactive)
- (save-excursion
- (let ((buffer-read-only nil))
- (subst-char-in-region (point-min) (point-max) ?\^M ?\n t)))
+ (gnus-remove-overlays (point-min) (point-max) 'invisible 'gnus-sum)
(gnus-summary-position-point))
(defun gnus-summary-show-thread ()
"Show thread subtrees.
Returns nil if no thread was there to be shown."
(interactive)
- (let ((buffer-read-only nil)
- (orig (point))
- (end (point-at-eol))
- ;; Leave point at bol
- (beg (progn (beginning-of-line) (point))))
- (prog1
- ;; Any hidden lines here?
- (search-forward "\r" end t)
- (subst-char-in-region beg end ?\^M ?\n t)
+ (let* ((orig (point))
+ (end (point-at-eol))
+ ;; Leave point at bol
+ (beg (progn (beginning-of-line) (if (bobp) (point) (1- (point)))))
+ (eoi (when (eq (get-char-property end 'invisible) 'gnus-sum)
+ (if (fboundp 'next-single-char-property-change)
+ (or (next-single-char-property-change end 'invisible)
+ (point-max))
+ (while (progn
+ (end-of-line 2)
+ (and (not (eobp))
+ (eq (get-char-property (point) 'invisible)
+ 'gnus-sum))))
+ (point)))))
+ (when eoi
+ (gnus-remove-overlays beg eoi 'invisible 'gnus-sum)
(goto-char orig)
- (gnus-summary-position-point))))
+ (gnus-summary-position-point)
+ eoi)))
(defun gnus-summary-maybe-hide-threads ()
"If requested, hide the threads that should be hidden."
will not be hidden.
Returns nil if no threads were there to be hidden."
(interactive)
- (let ((buffer-read-only nil)
- (start (point))
+ (let ((start (point))
+ (starteol (line-end-position))
(article (gnus-summary-article-number)))
(goto-char start)
- ;; Go forward until either the buffer ends or the subthread
- ;; ends.
+ ;; Go forward until either the buffer ends or the subthread ends.
(when (and (not (eobp))
(or (zerop (gnus-summary-next-thread 1 t))
(goto-char (point-max))))
- (prog1
- (if (and (> (point) start)
- (search-backward "\n" start t))
- (progn
- (subst-char-in-region start (point) ?\n ?\^M)
- (gnus-summary-goto-subject article))
- (goto-char start)
- nil)))))
+ (if (and (> (point) start)
+ ;; FIXME: this should actually search for a non-invisible \n.
+ (search-backward "\n" start t))
+ (progn
+ (when (> (point) starteol)
+ (gnus-remove-overlays starteol (point) 'invisible 'gnus-sum)
+ (let ((ol (gnus-make-overlay starteol (point) nil t nil)))
+ (gnus-overlay-put ol 'invisible 'gnus-sum)
+ (gnus-overlay-put ol 'evaporate t)))
+ (gnus-summary-goto-subject article))
+ (goto-char start)
+ nil))))
(defun gnus-summary-go-to-next-thread (&optional previous)
"Go to the same level (or less) next thread.
(while (gnus-summary-go-up-thread))
(gnus-summary-article-number))
+(defun gnus-summary-expire-thread ()
+ "Mark articles under current thread as expired."
+ (interactive)
+ (gnus-summary-kill-thread 0))
+
(defun gnus-summary-kill-thread (&optional unmark)
"Mark articles under current thread as read.
If the prefix argument is positive, remove any kinds of marks.
+If the prefix argument is zero, mark thread as expired.
If the prefix argument is negative, tick articles instead."
(interactive "P")
(when unmark
(setq unmark (prefix-numeric-value unmark)))
- (let ((articles (gnus-summary-articles-in-thread)))
+ (let ((articles (gnus-summary-articles-in-thread))
+ (hide (or (null unmark) (= unmark 0))))
(save-excursion
;; Expand the thread.
(gnus-summary-show-thread)
(gnus-summary-mark-article-as-read gnus-killed-mark))
((> unmark 0)
(gnus-summary-mark-article-as-unread gnus-unread-mark))
+ ((= unmark 0)
+ (gnus-summary-mark-article-as-unread gnus-expirable-mark))
(t
(gnus-summary-mark-article-as-unread gnus-ticked-mark)))
(setq articles (cdr articles))))
- ;; Hide killed subtrees.
- (and (null unmark)
+ ;; Hide killed subtrees when hide is true.
+ (and hide
gnus-thread-hide-killed
(gnus-summary-hide-thread))
- ;; If marked as read, go to next unread subject.
- (when (null unmark)
+ ;; If hide is t, go to next unread subject.
+ (when hide
;; Go to next unread subject.
(gnus-summary-next-subject 1 t)))
(gnus-set-mode-line 'summary))
(interactive "P")
(gnus-summary-sort 'number reverse))
+(defun gnus-summary-sort-by-most-recent-number (&optional reverse)
+ "Sort the summary buffer by most recent article number.
+Argument REVERSE means reverse order."
+ (interactive "P")
+ (gnus-summary-sort 'most-recent-number reverse))
+
(defun gnus-summary-sort-by-random (&optional reverse)
"Randomize the order in the summary buffer.
Argument REVERSE means to randomize in reverse order."
(interactive "P")
(gnus-summary-sort 'date reverse))
+(defun gnus-summary-sort-by-most-recent-date (&optional reverse)
+ "Sort the summary buffer by most recent date.
+Argument REVERSE means reverse order."
+ (interactive "P")
+ (gnus-summary-sort 'most-recent-date reverse))
+
(defun gnus-summary-sort-by-score (&optional reverse)
"Sort the summary buffer by score.
Argument REVERSE means reverse order."
"Sort the summary buffer using the default sorting method.
Argument REVERSE means reverse order."
(interactive "P")
- (let* ((buffer-read-only)
+ (let* ((inhibit-read-only t)
(gnus-summary-prepare-hook nil))
;; We do the sorting by regenerating the threads.
(gnus-summary-prepare)
article
`(lambda (t1 t2)
(,article t2 t1))))
- (buffer-read-only)
+ (inhibit-read-only t)
(gnus-summary-prepare-hook nil))
;; We do the sorting by regenerating the threads.
(gnus-summary-prepare)
gnus-display-mime-function))
(gnus-article-prepare-hook (when decode
gnus-article-prepare-hook)))
- (gnus-summary-select-article t nil nil article)
+ (gnus-summary-select-article t t nil article)
(gnus-summary-goto-subject article)))
- (save-excursion
- (set-buffer save-buffer)
+ (with-current-buffer save-buffer
(erase-buffer)
(insert-buffer-substring (if decode
gnus-article-buffer
(gnus-set-mode-line 'summary)
n))
-(defun gnus-summary-pipe-output (&optional arg headers)
+(defun gnus-summary-pipe-output (&optional n sym)
"Pipe the current article to a subprocess.
If N is a positive number, pipe the N next articles.
If N is a negative number, pipe the N previous articles.
If N is nil and any articles have been marked with the process mark,
pipe those articles instead.
-If HEADERS (the symbolic prefix), include the headers, too."
+The default command to which articles are piped is specified by the
+variable `gnus-summary-pipe-output-default-command'; if it is nil, you
+will be prompted for the command.
+
+The properties `:decode' and `:headers' that are put to the function
+symbol `gnus-summary-save-in-pipe' control whether this function
+decodes articles and what headers to keep (see the doc string for the
+`gnus-default-article-saver' variable). If SYM (the symbolic prefix)
+is neither omitted nor the symbol `r', force including all headers
+regardless of the `:headers' property. If it is the symbol `r',
+articles that are not decoded and include all headers will be piped
+no matter what the properties `:decode' and `:headers' are."
(interactive (gnus-interactive "P\ny"))
(require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-save-in-pipe)
- (gnus-save-all-headers (or headers gnus-save-all-headers)))
- (gnus-summary-save-article arg t))
- (let ((buffer (get-buffer "*Shell Command Output*")))
- (when (and buffer
- (not (zerop (buffer-size buffer))))
- (gnus-configure-windows 'pipe))))
+ (let* ((articles (gnus-summary-work-articles n))
+ (result-buffer "*Shell Command Output*")
+ (all-headers (not (memq sym '(nil r))))
+ (gnus-save-all-headers (or all-headers gnus-save-all-headers))
+ (raw (eq sym 'r))
+ (headers (get 'gnus-summary-save-in-pipe :headers))
+ command result)
+ (unless (numberp (car articles))
+ (error "No article to pipe"))
+ (setq command (gnus-read-shell-command
+ (concat "Shell command on "
+ (if (cdr articles)
+ (format "these %d articles" (length articles))
+ "this article")
+ ": ")
+ gnus-summary-pipe-output-default-command))
+ (when (string-equal command "")
+ (error "A command is required"))
+ (when all-headers
+ (put 'gnus-summary-save-in-pipe :headers nil))
+ (unwind-protect
+ (while articles
+ (gnus-summary-goto-subject (pop articles))
+ (save-window-excursion (gnus-summary-save-in-pipe command raw))
+ (when (and (get-buffer result-buffer)
+ (not (zerop (buffer-size (get-buffer result-buffer)))))
+ (setq result (concat result (with-current-buffer result-buffer
+ (buffer-string))))))
+ (put 'gnus-summary-save-in-pipe :headers headers))
+ (unless (zerop (length result))
+ (if (with-current-buffer (get-buffer-create result-buffer)
+ (erase-buffer)
+ (insert result)
+ (prog1
+ (and (= (count-lines (point-min) (point)) 1)
+ (progn
+ (end-of-line 0)
+ (<= (current-column)
+ (window-width (minibuffer-window)))))
+ (goto-char (point-min))))
+ (message "%s" (substring result 0 -1))
+ (message nil)
+ (gnus-configure-windows 'pipe)))))
(defun gnus-summary-save-article-mail (&optional arg)
"Append the current article to a Unix mail box file.
(save-restriction
(widen)
(let ((start (window-start))
- buffer-read-only)
+ (inhibit-read-only t))
(message-pipe-buffer-body program)
(set-window-start (get-buffer-window (current-buffer)) start))))))
"Return a value based on the split METHODS."
(let (split-name method result match)
(when methods
- (save-excursion
- (set-buffer gnus-original-article-buffer)
+ (with-current-buffer gnus-original-article-buffer
(save-restriction
(nnheader-narrow-to-headers)
(while (and methods (not split-name))
encoded)))
(defvar gnus-summary-save-parts-counter)
+(declare-function mm-uu-dissect "mm-uu" (&optional noheader mime-type))
(defun gnus-summary-save-parts (type dir n &optional reverse)
"Save parts matching TYPE to DIR.
current-prefix-arg))
(gnus-summary-iterate n
(let ((gnus-display-mime-function nil)
+ gnus-article-prepare-hook
+ gnus-article-decode-hook
+ gnus-display-mime-function
+ gnus-break-pages
(gnus-inhibit-treatment t))
(gnus-summary-select-article))
- (save-excursion
- (set-buffer gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
(let ((handles (or gnus-article-mime-handles
(mm-dissect-buffer nil gnus-article-loose-mime)
(and gnus-article-emulate-mime
;; Summary extract commands
(defun gnus-summary-insert-pseudos (pslist &optional not-view)
- (let ((buffer-read-only nil)
+ (let ((inhibit-read-only t)
(article (gnus-summary-article-number))
after-article b e)
(unless (gnus-summary-goto-subject article)
;; We have found the header.
header
;; We have to really fetch the header to this article.
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (with-current-buffer nntp-server-buffer
(when (setq where (gnus-request-head id group))
(nnheader-fold-continuation-lines)
(goto-char (point-max))
;; a different group (or server), we fudge some bogus
;; article numbers for this article.
(mail-header-set-number header gnus-reffed-article-number))
- (save-excursion
- (set-buffer gnus-summary-buffer)
+ (with-current-buffer gnus-summary-buffer
(decf gnus-reffed-article-number)
(gnus-remove-header (mail-header-number header))
(push header gnus-newsgroup-headers)
(save-excursion
(let (setmarkundo)
;; Propagate the read marks to the backend.
- (when (gnus-check-backend-function 'request-set-mark group)
+ (when (and gnus-propagate-marks
+ (gnus-check-backend-function 'request-set-mark group))
(let ((del (gnus-remove-from-range (gnus-info-read info) read))
(add (gnus-remove-from-range read (gnus-info-read info))))
(when (or add del)
(when gnus-suppress-duplicates
(gnus-dup-suppress-articles))
- ;; We might want to build some more threads first.
- (when (and gnus-fetch-old-headers
- (eq gnus-headers-retrieved-by 'nov))
- (if (eq gnus-fetch-old-headers 'invisible)
- (gnus-build-all-threads)
- (gnus-build-old-threads)))
+ (if (and gnus-fetch-old-headers
+ (eq gnus-headers-retrieved-by 'nov))
+ ;; We might want to build some more threads first.
+ (if (eq gnus-fetch-old-headers 'invisible)
+ (gnus-build-all-threads)
+ (gnus-build-old-threads))
+ ;; Mark the inserted articles that are unread as unread.
+ (setq gnus-newsgroup-unreads
+ (gnus-sorted-nunion
+ gnus-newsgroup-unreads
+ (gnus-sorted-nintersection
+ (gnus-list-of-unread-articles gnus-newsgroup-name)
+ articles)))
+ ;; Mark the inserted articles as selected so that the information
+ ;; of the marks having been changed by a user may be updated when
+ ;; exiting this group. See `gnus-summary-update-info'.
+ (dolist (art articles)
+ (setq gnus-newsgroup-unselected (delq art gnus-newsgroup-unselected))))
;; Let the Gnus agent mark articles as read.
(when gnus-agent
(gnus-agent-get-undownloaded-list))