+Thu Oct 3 02:04:37 1996 Lars Magne Ingebrigtsen <larsi@ylfing.ifi.uio.no>
+
+ * gnus-int.el (gnus-request-head): Use the cache.
+
+Wed Oct 2 00:57:22 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * message.el (message-resend): Message.
+
+ * gnus-group.el (gnus-group-timestamp-string): New function.
+
+ * gnus-util.el (gnus-time-iso8601): New function.
+
+ * gnus-group.el (gnus-group-set-timestamp): New function.
+ (gnus-group-timestamp): New subst.
+
+ * gnus-start.el (gnus-subscribe-hierarchical-interactive): Accept
+ RET as default.
+
+Tue Oct 1 05:13:57 1996 Martin Buchholz <mrb@eng.sun.com>
+
+ * gnus-sum.el (gnus-summary-insert-pseudos): Error takes a format
+ string.
+
+Tue Oct 1 05:12:29 1996 Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+
+ * gnus.el: Red Gnus v0.46 is released.
+
Tue Oct 1 03:41:17 1996 Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
* gnus-picon.el (gnus-picons-glyph-hashtb): Made into hashtb.
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, faces
-;; Version: 0.98
+;; Version: 0.991
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
sexp
(list 'quote sexp)))
-(defun custom-unimplemented (&rest ignore)
- "Apologize for my laziness."
- (error "Sorry, not implemented"))
-
;;; Modification of Basic Widgets.
;;
;; We add extra properties to the basic widgets needed here. This is
FACE is a face used to present the state.
The list should be sorted most significant first."
- :type '(repeat (list (choice (item nil)
- (item unknown)
- (item hidden)
- (item invalid)
- (item modified)
- (item applied)
- (item saved)
- (item rogue)
- (item factory))
+ :type '(repeat (list (choice (const nil)
+ (const unknown)
+ (const hidden)
+ (const invalid)
+ (const modified)
+ (const applied)
+ (const saved)
+ (const rogue)
+ (const factory))
string face))
:group 'customize)
;;; The `custom' Widget.
+(defvar custom-save-needed-p nil
+ "Non-nil if any customizations need to be saved.")
+
+(add-hook 'kill-emacs-hook 'custom-save-maybe)
+
+(defun custom-save-maybe ()
+ (and custom-save-needed-p
+ (y-or-n-p "You have unsaved customizations, save them now? ")
+ (custom-save)))
+
(define-widget 'custom 'default
"Customize a user option."
:convert-widget 'widget-item-convert-widget
(defun custom-format-handler (widget escape)
;; We recognize extra escape sequences.
- (let* ((symbol (widget-get widget :value))
- (buttons (widget-get widget :buttons))
+ (let* ((buttons (widget-get widget :buttons))
(level (widget-get widget :custom-level)))
(cond ((eq escape ?l)
(when level
(cond ((eq state 'hidden)
(error "Cannot apply hidden variable."))
((setq val (widget-apply child :validate))
- (error "Invalid %S"))
+ (error "Invalid %S" val))
((eq form 'lisp)
(set symbol (eval (widget-value child))))
(t
(cond ((eq state 'hidden)
(error "Cannot apply hidden variable."))
((setq val (widget-apply child :validate))
- (error "Invalid %S"))
+ (error "Invalid %S" val))
((eq form 'lisp)
+ (setq custom-save-needed-p (cons symbol custom-save-needed-p))
(put symbol 'saved-value (list (widget-value child)))
(set symbol (eval (widget-value child))))
(t
+ (setq custom-save-needed-p (cons symbol custom-save-needed-p))
(put symbol
'saved-value (list (custom-quote (widget-value
child))))
"Restore the factory setting for the variable being edited by WIDGET."
(let ((symbol (widget-value widget)))
(if (get symbol 'factory-value)
- (set symbol (car (get symbol 'factory-value)))
+ (set symbol (eval (car (get symbol 'factory-value))))
(error "No factory default for %S" symbol))
(when (get symbol 'saved-value)
+ (setq custom-save-needed-p (cons symbol custom-save-needed-p))
(put symbol 'saved-value nil))
(widget-put widget :custom-state 'unknown)
(custom-redraw widget)))
(child (car (widget-get widget :children))))
(unless (get symbol 'saved-face)
(error "No saved value for this face")
- (widget-value-set child (get symbol 'saved-face)))))
+ (widget-value-set child (get symbol 'saved-face)))))
(defun custom-face-factory (widget)
"Restore WIDGET to the face's factory settings."
(define-widget 'face 'default
"Select and customize a face."
:convert-widget 'widget-item-convert-widget
- :format "%[%t%]%v"
+ :format "%[%t%]: %v"
+ :tag "Face"
:value 'default
:value-create 'widget-face-value-create
:value-delete 'widget-radio-value-delete
(let* ((symbol (widget-value widget))
(child (widget-create-child-and-convert
widget 'custom-face
+ :format "%t %s%m %h%v"
:custom-level nil
- :tag ""
:value symbol)))
(custom-magic-reset child)
(widget-put widget :children (list child))))
'face-history)))
(unless (zerop (length answer))
(widget-value-set widget (intern answer))
+ (widget-apply widget :notify widget event)
(widget-setup))))
;;; The `custom-group' Widget.
(interactive)
(custom-save-variables)
(custom-save-faces)
+ (setq custom-save-needed-p nil)
(save-excursion
(set-buffer (find-file-noselect custom-file))
(save-buffer)))
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, faces
-;; Version: 0.98
+;; Version: 0.991
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
"\C-c\C-b" gnus-bug
"\C-d" gnus-article-read-summary-keys
+ "\M-*" gnus-article-read-summary-keys
"\M-g" gnus-article-read-summary-keys)
(substitute-key-definition
;; We only request an article by message-id when we do not have the
;; headers for it, so we'll have to get those.
- (when (stringp article)
+ (when (and (not gnus-doing-request-article)
+ (stringp article))
(let ((gnus-override-method gnus-refer-article-method))
(gnus-read-header article)))
%l Whether there are GroupLens predictions for this group (string)
%n Select from where (string)
%z A string that look like `<%s:%n>' if a foreign select method is used
+?d The date the group was last entered.
%u User defined specifier. The next character in the format string should
be a letter. Gnus will call the function gnus-user-format-function-X,
where X is the letter following %u. The function will be passed the
(?l gnus-tmp-grouplens ?s)
(?z gnus-tmp-news-method-string ?s)
(?m (gnus-group-new-mail gnus-tmp-group) ?c)
+ (?d (gnus-group-timestamp-string gnus-tmp-group) ?s)
(?u gnus-tmp-user-defined ?s)))
(defvar gnus-group-mode-line-format-alist
(sort (nconc (gnus-uncompress-range (cdr m))
(copy-sequence articles)) '<) t))))))
+;;;
+;;; Group timestamps
+;;;
+
+(defun gnus-group-set-timestamp ()
+ "Change the timestamp of the current group to the current time.
+This function can be used in hooks like `gnus-select-group-hook'."
+ (let ((time (current-time)))
+ (setcdr (cdr time) nil)
+ (gnus-group-set-parameter gnus-newsgroup-name 'timestamp time)))
+
+(defsubst gnus-group-timestamp (group)
+ "Return the timestamp for GROUP."
+ (gnus-group-get-parameter group 'timestamp))
+
+(defun gnus-group-timestamp-string (group)
+ "Return a string of the timestamp for GROUP."
+ (let ((time (gnus-group-timestamp group)))
+ (if (not time)
+ ""
+ (gnus-time-iso8601 time))))
+
(provide 'gnus-group)
;;; gnus-group.el ends here
(defun gnus-request-head (article group)
"Request the head of ARTICLE in GROUP."
(let* ((method (gnus-find-method-for-group group))
- (head (gnus-get-function method 'request-head t)))
- (if (fboundp head)
- (funcall head article (gnus-group-real-name group) (nth 1 method))
- (let ((res (gnus-request-article article group)))
- (when res
- (save-excursion
- (set-buffer nntp-server-buffer)
- (goto-char (point-min))
- (when (search-forward "\n\n" nil t)
- (delete-region (1- (point)) (point-max)))
- (nnheader-fold-continuation-lines)))
- res))))
+ (head (gnus-get-function method 'request-head t))
+ res clean-up)
+ (cond
+ ;; Check the cache.
+ ((and gnus-use-cache
+ (numberp article)
+ (gnus-cache-request-article article group))
+ (setq res (cons group article)
+ clean-up t))
+ ;; Use `head' function.
+ ((fboundp head)
+ (setq res (funcall head article (gnus-group-real-name group)
+ (nth 1 method))))
+ ;; Use `article' function.
+ (t
+ (setq res (gnus-request-article article group)
+ clean-up t)))
+ (when clean-up
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (goto-char (point-min))
+ (when (search-forward "\n\n" nil t)
+ (delete-region (1- (point)) (point-max)))
+ (nnheader-fold-continuation-lines)))
+ res))
(defun gnus-request-body (article group)
"Request the body of ARTICLE in GROUP."
"right" "before" "our" "without" "too" "those" "why" "must" "part"
"being" "current" "back" "still" "go" "point" "value" "each" "did"
"both" "true" "off" "say" "another" "state" "might" "under" "start"
- "try"
-
- "re")
+ "try" "re")
"Default list of words to be ignored when doing adaptive word scoring.")
(defvar gnus-default-adaptive-word-score-alist
;;; Code:
+(require 'cl)
+
(defvar running-xemacs (string-match "XEmacs\\|Lucid" emacs-version))
(defvar gnus-emacs-lisp-directory (if running-xemacs
(push prefix prefixes)
(message "Descend hierarchy %s? ([y]nsq): "
(substring prefix 1 (1- (length prefix))))
- (while (not (memq (setq ans (read-char)) '(?y ?\n ?n ?s ?q)))
+ (while (not (memq (setq ans (read-char)) '(?y ?\n ?\r ?n ?s ?q)))
(ding)
(message "Descend hierarchy %s? ([y]nsq): "
(substring prefix 1 (1- (length prefix)))))
(setq groups (cdr groups))))
(t nil)))
(message "Subscribe %s? ([n]yq)" (car groups))
- (while (not (memq (setq ans (read-char)) '(?y ?\n ?q ?n)))
+ (while (not (memq (setq ans (read-char)) '(?y ?\n ?\r ?q ?n)))
(ding)
(message "Subscribe %s? ([n]yq)" (car groups)))
(setq group (car groups))
(article (gnus-summary-article-number))
after-article b e)
(unless (gnus-summary-goto-subject article)
- (error (format "No such article: %d" article)))
+ (error "No such article: %d" article))
(gnus-summary-position-point)
;; If all commands are to be bunched up on one line, we collect
;; them here.
;; We have to really fetch the header to this article.
(save-excursion
(set-buffer nntp-server-buffer)
- (when (setq where (gnus-request-article-this-buffer id group))
- (goto-char (point-min))
- (when (search-forward "\n\n" nil t)
- (delete-region (1- (point)) (point-max)))
+ (when (setq where (gnus-request-head id group))
+ (goto-char (point-max))
(insert ".\n")
(goto-char (point-min))
(insert "211 ")
timezone-months-assoc))
"???"))))))
+(defun gnus-time-iso8601 (time)
+ "Return a string of TIME in YYMMDDTHHMMSS format."
+ (format-time-string "%Y%m%dT%H%M%S" time))
+
(defun gnus-date-iso8601 (header)
"Convert the date field in HEADER to YYMMDDTHHMMSS"
(condition-case ()
- (format-time-string "%Y%m%dT%H%M%S"
- (nnmail-date-to-time (mail-header-date header)))
+ (gnus-time-iso8601 (nnmail-date-to-time (mail-header-date header)))
(error "")))
(defun gnus-mode-string-quote (string)
"Score and kill file handling."
:group 'gnus )
-(defconst gnus-version-number "0.46"
+(defconst gnus-version-number "0.47"
"Version number for this version of Gnus.")
(defconst gnus-version (format "Red Gnus v%s" gnus-version-number)
(defun message-resend (address)
"Resend the current article to ADDRESS."
(interactive "sResend message to: ")
+ (message "Resending message to %s..." address)
(save-excursion
(let ((cur (current-buffer))
beg)
(insert "Also-"))
;; Send it.
(message-send-mail)
- (kill-buffer (current-buffer)))))
+ (kill-buffer (current-buffer)))
+ (message "Resending message to %s...done" address)))
;;;###autoload
(defun message-bounce ()
(deffoo nnweb-request-group (group &optional server dont-check)
(nnweb-possibly-change-server nil server)
- (when (and (not (equal group nnweb-group))
+ (when (and group
+ (not (equal group nnweb-group))
(not nnweb-ephemeral-p))
(let ((info (assoc group nnweb-group-alist)))
(setq nnweb-group group)
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: extensions
-;; Version: 0.98
+;; Version: 0.991
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
:match 'widget-item-match
:match-inline 'widget-item-match-inline
:action 'widget-item-action
- :format "%t")
+ :format "%t\n")
(defun widget-item-convert-widget (widget)
;; Initialize :value and :tag from :args in WIDGET.
:value-to-internal
(widget-value widget))
'widget-field-history)))
+ (widget-apply widget :notify widget event)
(widget-setup)))
(defun widget-field-value-create (widget)
(setq from (1+ from)
to (1- to))
(while (and size
+ (not (zerop size))
(> to from)
(eq (char-after (1- to)) ?\ ))
(setq to (1- to)))
"A menu of options."
:convert-widget 'widget-choice-convert-widget
:format "%[%t%]: %v"
+ :case-fold t
:tag "choice"
:void '(item :format "invalid (%t)\n")
:value-create 'widget-choice-value-create
(defun widget-choice-convert-widget (widget)
;; Expand type args into widget objects.
- ; (widget-put widget :args (mapcar (lambda (child)
- ; (if (widget-get child ':converted)
- ; child
- ; (widget-put child ':converted t)
- ; (widget-convert child)))
- ; (widget-get widget :args)))
+; (widget-put widget :args (mapcar (lambda (child)
+; (if (widget-get child ':converted)
+; child
+; (widget-put child ':converted t)
+; (widget-convert child)))
+; (widget-get widget :args)))
(widget-put widget :args (mapcar 'widget-convert (widget-get widget :args)))
widget)
(let ((args (widget-get widget :args))
(old (widget-get widget :choice))
(tag (widget-apply widget :menu-tag-get))
+ (completion-ignore-case (widget-get widget :case-fold))
current choices)
;; Remember old value.
(if (and old (not (widget-apply widget :validate)))
(widget-value-set widget
(widget-apply current :value-to-external
(widget-get current :value)))
- (widget-setup)))
+ (widget-apply widget :notify widget event)
+ (widget-setup)))
;; Notify parent.
(widget-apply widget :notify widget event)
(widget-clear-undo))
(t
(widget-default-format-handler widget escape))))
- ;(defun widget-editable-list-format-handler (widget escape)
+;(defun widget-editable-list-format-handler (widget escape)
; ;; We recognize the insert button.
; (cond ((eq escape ?i)
; (insert " ")
:format "%[%t%]: %v")
(define-widget 'regexp 'string
+ "A regular expression."
;; Should do validation.
- "A regular expression.")
+ :tag "Regexp")
(define-widget 'file 'string
"A file widget.
(answer (read-file-name (concat menu-tag ": (defalt `" value "') ")
dir nil must-match file)))
(widget-value-set widget (abbreviate-file-name answer))
+ (widget-apply widget :notify widget event)
(widget-setup)))
(define-widget 'directory 'file
(t
(read-string prompt (widget-value widget))))))
(unless (zerop (length answer))
- (widget-value-set widget answer))))
+ (widget-value-set widget answer)
+ (widget-apply widget :notify widget event)
+ (widget-setup))))
;;; The Help Echo
(defun widget-echo-help-mouse ()
"Display the help message for the widget under the mouse.
-Enable with (run-with-idle-timer 2 t 'widget-echo-help-mouse)"
+Enable with (run-with-idle-timer 1 t 'widget-echo-help-mouse)"
(let* ((pos (mouse-position))
(frame (car pos))
(x (car (cdr pos)))
;;
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: help, extensions, faces, hypermedia
-;; Version: 0.98
+;; Version: 0.991
;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
;;; Commentary:
(set (car keywords) (car keywords)))
(setq keywords (cdr keywords))))))
-(define-widget-keywords :widget-doc
+(define-widget-keywords :case-fold :widget-doc
:create :convert-widget :format :value-create :offset :extra-offset
:tag :doc :from :to :args :value :value-from :value-to :action
:value-set :value-delete :match :parent :delete :menu-tag-get
+Wed Oct 2 01:32:49 1996 Lars Magne Ingebrigtsen <lars@eyesore.no>
+
+ * gnus.texi (Group Timestamps): New.
+
Tue Oct 1 01:34:45 1996 Lars Magne Ingebrigtsen <larsi@hrym.ifi.uio.no>
* gnus.texi (Expiring Mail): Addition.
\input texinfo @c -*-texinfo-*-
@setfilename gnus
-@settitle Red Gnus 0.46 Manual
+@settitle Red Gnus 0.47 Manual
@synindex fn cp
@synindex vr cp
@synindex pg cp
@tex
@titlepage
-@title Red Gnus 0.46 Manual
+@title Red Gnus 0.47 Manual
@author by Lars Magne Ingebrigtsen
@page
@samp{%} (@code{gnus-new-mail-mark}) if there has arrived new mail to
the group lately.
+@item d
+A string that says when you last read the group (@pxref{Group
+Timestamp}).
+
@item u
User defined specifier. The next character in the format string should
be a letter. @sc{gnus} will call the function
@menu
* Scanning New Messages:: Asking Gnus to see whether new messages have arrived.
* Group Information:: Information and help on groups and Gnus.
+* Group Timestamp:: Making Gnus keep track of when you last read a group.
* File Commands:: Reading and writing the Gnus files.
@end menu
@end table
+@node Group Timestamp
+@subsection Group Timestamp
+@cindex timestamps
+@cindex group timestamps
+
+It can be convenient to let Gnus keep track of when you last read a
+group. To set the ball rolling, you should add
+@code{gnus-group-set-timestamp} to @code{gnus-select-group-hook}:
+
+@lisp
+(add-hook 'gnus-select-group-hook 'gnus-group-set-timestamp)
+@end lisp
+
+After doing this, each time you enter a group, it'll be recorded.
+
+This information can be displayed in various ways---the easiest is to
+use the @samp{%d} spec in the group line format:
+
+@lisp
+(setq gnus-group-line-format
+ "%M\%S\%p\%P\%5y: %(%-40,40g%) %d\n")
+@end lisp
+
+This will result in lines looking like:
+
+@example
+* 0: mail.ding 19961002T012943
+ 0: custom 19961002T012713
+@end example
+
+As you can see, the date is displayed in compact ISO 8601 format. This
+may be a bit too much, so to just display the date, you could say
+something like:
+
+@lisp
+(setq gnus-group-line-format
+ "%M\%S\%p\%P\%5y: %(%-40,40g%) %6,6~(cut 2)d\n")
+@end lisp
+
+
@node File Commands
@subsection File Commands
@cindex file commands
@code{t} and be prompted for the password, or set
@code{nnmail-pop-password} to the password itself.
-Your Emacs has to have been configured with @samp{--use-pop} before
+Your Emacs has to have been configured with @samp{--with-pop} before
compilation. This is the default, but some installations have it
switched off.