From ef4ed154abd5b68eed6e21bc1c5f92b1cc7ae1fd Mon Sep 17 00:00:00 2001 From: Lars Magne Ingebrigtsen Date: Tue, 4 Mar 1997 06:35:43 +0000 Subject: [PATCH] *** empty log message *** --- lisp/ChangeLog | 60 ++++++ lisp/gnus-cache.el | 14 +- lisp/gnus-msg.el | 41 ++-- lisp/gnus-picon.el | 121 ++++++++++++ lisp/gnus-score.el | 33 ++-- lisp/gnus-uu.el | 162 ++++++++++------ lisp/gnus.el | 474 ++++++++++++++++++++++++++++----------------- lisp/nnheader.el | 2 +- lisp/nnml.el | 16 +- texi/ChangeLog | 9 + texi/gnus.texi | 189 ++++++++++++------ 11 files changed, 776 insertions(+), 345 deletions(-) create mode 100644 lisp/gnus-picon.el diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 14c9b14b9..7f91d05c9 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,7 +1,67 @@ +Sat Dec 16 14:26:27 1995 Lars Magne Ingebrigtsen + + * gnus.el (gnus-summary-exit): Would nix out the group name of + parents to nndoc groups. + +Fri Dec 15 20:55:26 1995 Lars Ingebrigtsen + + * gnus.el (gnus-buffer-configuration): New default value. + (gnus-configure-windows): Use it. + (gnus-all-windows-visible-p): New implementation. + +Fri Dec 15 19:28:07 1995 Jason L. Tibbitts, III + + * nnml.el (nnml-generate-nov-file): Directory names with/without + slashes. + +Fri Dec 15 18:55:28 1995 Lars Ingebrigtsen + + * gnus-cache.el (gnus-cache-generate-nov-databases): Called wrong + nnml function. + + * gnus.el (gnus-summary-exit): Don't clear the group name until + the last hook has been run. + +Fri Dec 15 18:53:29 1995 Lance A. Brown + + * gnus.el (gnus-parse-simple-format): %4,4i would break function. + +Fri Dec 15 18:48:07 1995 Michael Sperber + + * nnheader.el (nnheader-file-to-number): Would return a list of + strings. + +Fri Dec 15 12:14:08 1995 Lars Ingebrigtsen + + * gnus.el (gnus-configure-frame): New function. + +Thu Dec 14 20:16:30 1995 Jason L. Tibbitts, III + + * gnus.el (gnus-simplify-subject-fully): New function. + +Thu Dec 14 17:55:03 1995 Lars Ingebrigtsen + + * gnus.el (gnus-update-missing-marks): New function. + (gnus-select-newsgroup): Use it. + + * gnus-uu.el (gnus-uu-grabbed-file-functions): New variable. + (gnus-uu-grab-articles): Use it. + (gnus-uu-grab-view, gnus-uu-grab-move): New functions. + + * gnus-score.el (gnus-possibly-score-headers): Allow a + `score-file' group parameter. + +Thu Dec 14 12:42:20 1995 Lars Magne Ingebrigtsen + + * nnheader.el (nnheader-file-to-number): Returned strings instead + of numbers. + Thu Dec 14 10:48:51 1995 Lars Magne Ingebrigtsen * gnus.el (gnus-summary-toggle-header): Don't do that hook dance. + * gnus.el: 0.22 is released. + Thu Dec 14 10:02:08 1995 Lars Magne Ingebrigtsen * gnus-xmas.el (gnus-xmas-read-event-char): New function. diff --git a/lisp/gnus-cache.el b/lisp/gnus-cache.el index 91f1f8d0d..6e52f4f55 100644 --- a/lisp/gnus-cache.el +++ b/lisp/gnus-cache.el @@ -55,6 +55,9 @@ variable to \"^nnml\".") (defvar gnus-cache-active-hashtb nil) (defvar gnus-cache-active-altered nil) +(eval-and-compile + (autoload 'nnml-generate-nov-databases-1 "nnml")) + ;;; Functions called from Gnus. @@ -493,12 +496,14 @@ If LOW, update the lower bound instead." "Generate the cache active file." (interactive) (let* ((top (null directory)) - (directory (or directory (expand-file-name gnus-cache-directory))) + (directory (expand-file-name (or directory gnus-cache-directory))) (files (directory-files directory 'full)) (group (progn - (string-match (concat "^" (expand-file-name gnus-cache-directory)) - directory) + (string-match + (concat "^" (file-name-as-directory + (expand-file-name gnus-cache-directory))) + directory) (gnus-replace-chars-in-string (substring directory (match-end 0)) ?/ ?.))) @@ -534,9 +539,8 @@ If LOW, update the lower bound instead." "Generate NOV files recursively starting in DIR." (interactive (list gnus-cache-directory)) (gnus-cache-close) - (require 'nnml) (let ((nnml-generate-active-function 'identity)) - (nnml-generate-nov-databases dir))) + (nnml-generate-nov-databases-1 dir))) (provide 'gnus-cache) diff --git a/lisp/gnus-msg.el b/lisp/gnus-msg.el index 64e169220..54be0e2e5 100644 --- a/lisp/gnus-msg.el +++ b/lisp/gnus-msg.el @@ -1202,26 +1202,27 @@ Headers in `gnus-required-headers' will be generated." '(gnus-deletable t face italic) (current-buffer))))))) ;; Insert new Sender if the From is strange. (let ((from (mail-fetch-field "from")) - (sender (mail-fetch-field "sender"))) - (if (and from - (not (gnus-check-before-posting 'sender)) - (not (string= - (downcase (car (cdr (gnus-extract-address-components from)))) - (downcase (gnus-inews-real-user-address)))) - (or (null sender) - (not - (string= - (downcase (car (cdr (gnus-extract-address-components sender)))) - (downcase (gnus-inews-real-user-address)))))) - (progn - (goto-char (point-min)) - (and (re-search-forward "^Sender:" nil t) - (progn - (beginning-of-line) - (insert "Original-") - (beginning-of-line))) - (insert "Sender: " (gnus-inews-real-user-address) "\n")))))) - + (sender (mail-fetch-field "sender")) + (secure-sender (gnus-inews-real-user-address))) + (when (and from + (not (gnus-check-before-posting 'sender)) + (not (string= + (downcase (car (cdr (gnus-extract-address-components + from)))) + (downcase (gnus-inews-real-user-address)))) + (or (null sender) + (not + (string= + (downcase (car (cdr (gnus-extract-address-components + sender)))) + (downcase secure-sender))))) + (goto-char (point-min)) + ;; Rename any old Sender headers to Original-Sender. + (when (re-search-forward "^Sender:" nil t) + (beginning-of-line) + (insert "Original-") + (beginning-of-line)) + (insert "Sender: " secure-sender "\n"))))) (defun gnus-inews-insert-signature () "Insert a signature file. diff --git a/lisp/gnus-picon.el b/lisp/gnus-picon.el new file mode 100644 index 000000000..9e0d4a381 --- /dev/null +++ b/lisp/gnus-picon.el @@ -0,0 +1,121 @@ +;; gnus-picon.el: Copyright (C) 1995 Wes Hardaker +;; Icon hacks for displaying pretty icons in Gnus. +;; +;; Author: Wes hardaker +;; hardaker@ece.ucdavis.edu +;; +;; Usage: +;; - You must have XEmacs to use this. +;; - (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t) +;; This HAS to have the 't' flag above to make sure it appends the hook. +;; - Read the variable descriptions below. +;; +;; Warnings: +;; - I'm not even close to being a lisp expert. +;; +;; TODO: +;; - Following the Gnus motto: We've got to build him bigger, +;; better, stronger, faster than before... errr.... sorry. +;; - Create a seperate frame to store icons in so icons are +;; visibile immediately upon entering a group rather than just +;; at the top of the article buffer. +;; +;; + +(require 'xpm) +(require 'annotations) + +(defvar gnus-picons-database "/usr/local/faces" + "defines the location of the faces database. For information on + obtaining this database of pretty pictures, please see + http://www.cs.indiana.edu/picons/ftp/index.html" +) + +(defvar gnus-picons-news-directory "news" + "Sub-directory of the faces database containing the icons for + newsgroups." +) + +(defvar gnus-picons-user-directories '("local" "users" "usenix" "misc/MISC") + "List of directories to search for user faces." +) + +(defvar gnus-picons-domain-directories '("domains") + "List of directories to search for domain faces. Some people may + want to add \"unknown\" to this list." +) + +(defun gnus-article-display-picons () + "prepare article buffer with pretty pictures" + (interactive) + (if (featurep 'xpm) + (save-excursion + (beginning-of-buffer) + (open-line 1) + (let* ((iconpoint (point)) (from (mail-fetch-field "from")) + (username + (progn + (string-match "\\([-_a-zA-Z0-9]+\\)@" from) + (match-string 1 from))) + (hostpath + (gnus-picons-reverse-domain-path + (replace-in-string + (replace-in-string from ".*@\\([_a-zA-Z0-9-.]+\\).*" "\\1") + "\\." "/")))) + (if (equal username from) + (setq username (replace-in-string from + ".*<\\([_a-zA-Z0-9-.]+\\)>.*" + "\\1"))) + (insert username) + (gnus-picons-insert-face-if-exists + (concat gnus-picons-database "/" gnus-picons-news-directory) + (concat (replace-in-string gnus-newsgroup-name "\\." "/") "/unknown") + iconpoint) + (mapcar '(lambda (pathpart) + (gnus-picons-insert-face-if-exists + (concat gnus-picons-database "/" pathpart) + (concat hostpath "/" username) + iconpoint)) + gnus-picons-user-directories) + (mapcar '(lambda (pathpart) + (gnus-picons-insert-face-if-exists + (concat gnus-picons-database "/" pathpart) + (concat hostpath "/" "unknown") + iconpoint)) + gnus-picons-domain-directories) + )))) + +(defun gnus-picons-insert-face-if-exists (path filename ipoint) + "inserts a face at point if I can find one" + (let ((pathfile (concat path "/" filename "/face"))) + (let ((newfilename + (replace-in-string filename + "[_a-zA-Z0-9-]+/\\([_A-Za-z0-9-]+\\)$" "\\1"))) + (if (not (equal filename newfilename)) + (gnus-picons-insert-face-if-exists path newfilename ipoint))) + (if (not (gnus-picons-try-to-find-face (concat pathfile ".xpm") ipoint)) + (gnus-picons-try-to-find-face (concat pathfile ".xbm") ipoint)) + ) + ) + + +(defun gnus-picons-try-to-find-face (path ipoint) + "if path exists, display it as a bitmap. Returns t if succedded." + (if (file-exists-p path) + (progn + (setq gl (make-glyph path)) + (set-glyph-face gl 'default) + (setq annot (make-annotation gl ipoint 'text)) + t) +; (insert (format "no: %s\n" path)) + nil)) + +(defun gnus-picons-reverse-domain-path (str) + "a/b/c/d -> d/c/b/a" + (if (equal (replace-in-string str "^[^/]*$" "") "") + str + (concat (replace-in-string str "^.*/\\([_a-zA-Z0-9-]+\\)$" "\\1") "/" + (gnus-picons-reverse-domain-path + (replace-in-string str "^\\(.*\\)/[_a-zA-Z0-9-]+$" "\\1"))))) + + diff --git a/lisp/gnus-score.el b/lisp/gnus-score.el index 2f27b9049..0c1d3d65d 100644 --- a/lisp/gnus-score.el +++ b/lisp/gnus-score.el @@ -1952,21 +1952,30 @@ The list is determined from the variable gnus-score-file-alist." score-files))) (defun gnus-possibly-score-headers (&optional trace) - (let ((func gnus-score-find-score-files-function) + (let ((funcs gnus-score-find-score-files-function) score-files) - (and func - (not (listp func)) - (setq func (list func))) + ;; Make sure funcs is a list. + (and funcs + (not (listp funcs)) + (setq funcs (list funcs))) + ;; Get the initial score files for this group. + (when funcs + (setq score-files (gnus-score-find-alist gnus-newsgroup-name))) ;; Go through all the functions for finding score files (or actual ;; scores) and add them to a list. - (and func (setq score-files (gnus-score-find-alist gnus-newsgroup-name))) - (while func - (and (symbolp (car func)) - (fboundp (car func)) - (setq score-files - (nconc score-files (funcall (car func) gnus-newsgroup-name)))) - (setq func (cdr func))) - (if score-files (gnus-score-headers score-files trace)))) + (while funcs + (when (gnus-functionp (car funcs)) + (setq score-files + (nconc score-files (funcall (car funcs) gnus-newsgroup-name)))) + (setq funcs (cdr funcs))) + ;; Check whether there is a `score-file' group parameter. + (let ((param-file (gnus-group-get-parameter + gnus-newsgroup-name 'score-file))) + (when param-file + (push param-file score-files))) + ;; Do the scoring if there are any score files for this group. + (when score-files + (gnus-score-headers score-files trace)))) (defun gnus-score-file-name (newsgroup &optional suffix) "Return the name of a score file for NEWSGROUP." diff --git a/lisp/gnus-uu.el b/lisp/gnus-uu.el index 85267aad9..e8c06de9e 100644 --- a/lisp/gnus-uu.el +++ b/lisp/gnus-uu.el @@ -192,6 +192,12 @@ viewing is unsuccessful. Default is nil.") "*Non-nil means that gnus-uu will ignore the default viewing rules. Only the user viewing rules will be consulted. Default is nil.") +(defvar gnus-uu-grabbed-file-functions nil + "*Functions run on each file after successful decoding. +They will be called with the name of the file as the argument. +Likely functions you can use in this list are `gnus-uu-grab-view' +and `gnus-uu-grab-move'.") + (defvar gnus-uu-ignore-default-archive-rules nil "*Non-nil means that gnus-uu will ignore the default archive unpacking commands. Only the user unpacking commands will be consulted. Default is nil.") @@ -845,12 +851,10 @@ The headers will be included in the sequence they are matched.") (setq end-char (point)) (set-buffer (get-buffer-create gnus-uu-output-buffer-name)) (insert-buffer-substring process-buffer start-char end-char) - (setq file-name (concat gnus-uu-work-dir (cdr gnus-article-current) ".ps")) + (setq file-name (concat gnus-uu-work-dir + (cdr gnus-article-current) ".ps")) (write-region (point-min) (point-max) file-name) - (setq state (list file-name'begin 'end)) - - )) - ) + (setq state (list file-name 'begin 'end))))) state)) @@ -1092,31 +1096,26 @@ The headers will be included in the sequence they are matched.") (defun gnus-uu-grab-articles (articles process-function &optional sloppy limit no-errors) (let ((state 'first) - has-been-begin article result-file result-files process-state) + has-been-begin article result-file result-files process-state + article-series) - (if (not (gnus-server-opened gnus-current-select-method)) - (progn - (gnus-start-news-server) - (gnus-request-group gnus-newsgroup-name))) - - (setq gnus-uu-has-been-grabbed nil) - (while (and articles (not (memq 'error process-state)) (or sloppy (not (memq 'end process-state)))) - (setq article (car articles)) - (setq articles (cdr articles)) - (setq gnus-uu-has-been-grabbed (cons article gnus-uu-has-been-grabbed)) + (setq article (pop articles)) + (push article article-series) - (if (eq articles ()) - (if (eq state 'first) - (setq state 'first-and-last) - (setq state 'last))) + (unless articles + (if (eq state 'first) + (setq state 'first-and-last) + (setq state 'last))) (message "Getting article %d, %s" article (gnus-uu-part-number article)) (gnus-summary-display-article article) + + ;; Push the article to the processing function. (save-excursion (set-buffer gnus-original-article-buffer) (let ((buffer-read-only nil)) @@ -1125,39 +1124,59 @@ The headers will be included in the sequence they are matched.") (setq process-state (funcall process-function gnus-original-article-buffer state))))) + (gnus-summary-remove-process-mark article) - (if (or (memq 'begin process-state) - (and (or (eq state 'first) (eq state 'first-and-last)) - (memq 'ok process-state))) - (progn - (if has-been-begin - (if (and result-file (file-exists-p result-file)) - (delete-file result-file))) - (if (memq 'begin process-state) - (setq result-file (car process-state))) - (setq has-been-begin t))) - - (if (memq 'end process-state) - (progn - (setq gnus-uu-has-been-grabbed nil) - (setq result-files (cons (list (cons 'name result-file) - (cons 'article article)) - result-files)) - (setq has-been-begin nil) - (and limit (= (length result-files) limit) - (setq articles nil)))) - - (if (and (or (eq state 'last) (eq state 'first-and-last)) - (not (memq 'end process-state))) - (if (and result-file (file-exists-p result-file)) + ;; If this is the beginning of a decoded file, we push it + ;; on to a list. + (when (or (memq 'begin process-state) + (and (or (eq state 'first) + (eq state 'first-and-last)) + (memq 'ok process-state))) + (if has-been-begin + ;; If there is a `result-file' here, that means that the + ;; file was unsuccessfully decoded, so we delete it. + (when (and result-file + (file-exists-p result-file)) (delete-file result-file))) + (when (memq 'begin process-state) + (setq result-file (car process-state))) + (setq has-been-begin t)) + + ;; Check whether we have decoded one complete file. + (when (memq 'end process-state) + (setq article-series nil) + (setq has-been-begin nil) + (push (list (cons 'name result-file) + (cons 'article article)) + result-files) + ;; Allow user-defined functions to be run on this file. + (when gnus-uu-grabbed-file-functions + (let ((funcs gnus-uu-grabbed-file-functions)) + (unless (listp funcs) + (setq funcs (list funcs))) + (while funcs + (funcall (pop funcs) result-file)))) + ;; Check whether we have decoded enough articles. + (and limit (= (length result-files) limit) + (setq articles nil))) + + ;; If this is the last article to be decoded, and + ;; we still haven't reached the end, then we delete + ;; the partially decoded file. + (and (or (eq state 'last) (eq state 'first-and-last) + (not (memq 'end process-state))) + result-file + (file-exists-p result-file) + (delete-file result-file)) - (if (not (memq 'wrong-type process-state)) - () - (if gnus-uu-unmark-articles-not-decoded - (gnus-summary-tick-article article t))) + ;; If this was a file of the wrong sort, then + (when (and (or (memq 'wrong-type process-state) + (memq 'error process-state)) + gnus-uu-unmark-articles-not-decoded) + (gnus-summary-tick-article article t)) + ;; Set the new series state. (if (and (not has-been-begin) (not sloppy) (or (memq 'end process-state) @@ -1168,24 +1187,41 @@ The headers will be included in the sequence they are matched.") (sleep-for 2)) (setq state 'middle))) - ;; Make sure the last article is put in the article buffer & fix - ;; windows etc. + ;; When there are no result-files, then something must be wrong. + (unless result-files + (cond + ((not has-been-begin) + (message "Wrong type file")) + ((memq 'error process-state) + (message "An error occurred during decoding")) + ((not (or (memq 'ok process-state) + (memq 'end process-state))) + (message "End of articles reached before end of file"))) + ;; Make unsuccessfully decoded articles unread. + (when gnus-uu-unmark-articles-not-decoded + (while article-series + (gnus-summary-tick-article (pop article-series) t)))) - (if result-files - () - (if (not has-been-begin) - (if (not no-errors) (message "Wrong type file")) - (if (memq 'error process-state) - (setq result-files nil) - (if (not (or (memq 'ok process-state) - (memq 'end process-state))) - (progn - (if (not no-errors) - (message "End of articles reached before end of file")) - (setq result-files nil)) - (gnus-uu-unmark-list-of-grabbed))))) result-files)) +(defun gnus-uu-grab-view (file) + "View FILE using the gnus-uu methods." + (let ((action (gnus-uu-get-action file))) + (gnus-execute-command + (if (string-match "%" action) + (format action file) + (concat action " " file)) + (eq gnus-view-pseudos 'not-confirm)))) + +(defun gnus-uu-grab-move (file) + "Move FILE to somewhere." + (when gnus-uu-default-dir + (let ((to-file (concat (file-name-as-directory gnus-uu-default-dir) + (file-name-nondirectory file)))) + (rename-file file to-file) + (unless (file-exists-p file) + (make-symbolic-link to-file file))))) + (defun gnus-uu-part-number (article) (let ((subject (mail-header-subject (gnus-summary-article-header article)))) (if (string-match "[0-9]+ */[0-9]+\\|[0-9]+ * of *[0-9]+" diff --git a/lisp/gnus.el b/lisp/gnus.el index 1b8c66daf..8f8d3b3e3 100644 --- a/lisp/gnus.el +++ b/lisp/gnus.el @@ -374,6 +374,9 @@ articles. This is not a good idea.") (defvar gnus-use-scoring t "*If non-nil, enable scoring.") +(defvar gnus-use-picon nil + "*If non-nil, display picons.") + (defvar gnus-fetch-old-headers nil "*Non-nil means that Gnus will try to build threads by grabbing old headers. If an unread article in the group refers to an older, already read (or @@ -601,7 +604,7 @@ will not be marked.") (defvar gnus-simplify-subject-fuzzy-regexp nil "*Strings to be removed when doing fuzzy matches. -This can either be a egular expression or list of regular expressions +This can either be a regular expression or list of regular expressions that will be removed from subject strings if fuzzy subject simplification is selected.") @@ -763,45 +766,95 @@ beginning of a line.") "Obsolete variable. See `gnus-buffer-configuration'.") (defvar gnus-buffer-configuration - '((group ([group 1.0 point] - (if gnus-carpal [group-carpal 4]))) - (summary ([summary 1.0 point] - (if gnus-carpal [summary-carpal 4]))) - (article ([summary 0.25 point] - (if gnus-carpal [summary-carpal 4]) - [article 1.0])) - (server ([server 1.0 point] - (if gnus-carpal [server-carpal 2]))) - (browse ([browse 1.0 point] - (if gnus-carpal [browse-carpal 2]))) - (group-mail ([mail 1.0 point])) - (summary-mail ([mail 1.0 point])) - (summary-reply ([article 0.5] - [mail 1.0 point])) - (info ([nil 1.0 point])) - (summary-faq ([summary 0.25] - [faq 1.0 point])) - (edit-group ([group 0.5] - [edit-group 1.0 point])) - (edit-server ([server 0.5] - [edit-server 1.0 point])) - (edit-score ([summary 0.25] - [edit-score 1.0 point])) - (post ([post 1.0 point])) - (reply ([article 0.5] - [mail 1.0 point])) - (mail-forward ([mail 1.0 point])) - (post-forward ([post 1.0 point])) - (reply-yank ([mail 1.0 point])) - (mail-bounce ([article 0.5] - [mail 1.0 point])) - (draft ([draft 1.0 point])) - (pipe ([summary 0.25 point] - (if gnus-carpal [summary-carpal 4]) - ["*Shell Command Output*" 1.0])) - (followup ([article 0.5] - [post 1.0 point])) - (followup-yank ([post 1.0 point]))) + '((group + (vertical 1.0 + (group 1.0 point) + (if gnus-carpal (group-carpal 4)))) + (summary + (vertical 1.0 + (summary 1.0 point) + (if gnus-carpal (summary-carpal 4)))) + (article + (vertical 1.0 + (if gnus-use-picon + '(horizontal 0.25 + (summary 1.0 point) + (picon 10)) + '(summary 0.25 point)) + (if gnus-carpal (summary-carpal 4)) + (article 1.0))) + (server + (vertical 1.0 + (server 1.0 point) + (if gnus-carpal (server-carpal 2)))) + (browse + (vertical 1.0 + (browse 1.0 point) + (if gnus-carpal (browse-carpal 2)))) + (group-mail + (vertical 1.0 + (mail 1.0 point))) + (summary-mail + (vertical 1.0 + (mail 1.0 point))) + (summary-reply + (vertical 1.0 + (article 0.5) + (mail 1.0 point))) + (info + (vertical 1.0 + (nil 1.0 point))) + (summary-faq + (vertical 1.0 + (summary 0.25) + (faq 1.0 point))) + (edit-group + (vertical 1.0 + (group 0.5) + (edit-group 1.0 point))) + (edit-server + (vertical 1.0 + (server 0.5) + (edit-server 1.0 point))) + (edit-score + (vertical 1.0 + (summary 0.25) + (edit-score 1.0 point))) + (post + (vertical 1.0 + (post 1.0 point))) + (reply + (vertical 1.0 + (article 0.5) + (mail 1.0 point))) + (mail-forward + (vertical 1.0 + (mail 1.0 point))) + (post-forward + (vertical 1.0 + (post 1.0 point))) + (reply-yank + (vertical 1.0 + (mail 1.0 point))) + (mail-bounce + (vertical 1.0 + (article 0.5) + (mail 1.0 point))) + (draft + (vertical 1.0 + (draft 1.0 point))) + (pipe + (vertical 1.0 + (summary 0.25 point) + (if gnus-carpal (summary-carpal 4)) + ("*Shell Command Output*" 1.0))) + (followup + (vertical 1.0 + (article 0.5) + (post 1.0 point))) + (followup-yank + (vertical 1.0 + (post 1.0 point)))) "Window configuration for all possible Gnus buffers. This variable is a list of lists. Each of these lists has a NAME and a RULE. The NAMEs are commonsense names like `group', which names a @@ -833,6 +886,7 @@ buffer configuration.") (mail . gnus-mail-buffer) (post . gnus-post-news-buffer) (faq . gnus-faq-buffer) + (picon . gnus-picon-buffer) (draft . gnus-draft-buffer)) "Mapping from short symbols to buffer names or buffer variables.") @@ -1379,6 +1433,12 @@ automatically when it is selected.") ;; Internal variables +(defconst gnus-article-mark-lists + '((marked . tick) (replied . reply) + (expirable . expire) (killed . killed) + (bookmarks . bookmark) (dormant . dormant) + (scored . score) (saved . save))) + ;; Avoid highlighting in kill files. (defvar gnus-summary-inhibit-highlight nil) (defvar gnus-newsgroup-selected-overlay nil) @@ -1511,7 +1571,7 @@ variable (string, integer, character, etc).") "gnus-bug@ifi.uio.no (The Gnus Bugfixing Girls + Boys)" "The mail address of the Gnus maintainers.") -(defconst gnus-version "September Gnus v0.22" +(defconst gnus-version "September Gnus v0.23" "Version number for this version of Gnus.") (defvar gnus-info-nodes @@ -1864,6 +1924,7 @@ Thank you for your help in stamping out bugs. gnus-summary-reply gnus-summary-reply-with-original gnus-summary-mail-forward gnus-summary-mail-other-window gnus-bug) + ("gnus-picon" gnus-article-display-picon) ("gnus-vm" gnus-vm-mail-setup) ("gnus-vm" :interactive t gnus-summary-save-in-vm gnus-summary-save-article-vm gnus-yank-article)))) @@ -2427,8 +2488,9 @@ Thank you for your help in stamping out bugs. (setq flist (cons (gnus-max-width-function el max-width) flist)) (setq newspec ?s)) - (setq flist (cons (car elem) flist))) - (setq newspec (car (cdr elem)))) + (progn + (setq flist (cons (car elem) flist)) + (setq newspec (car (cdr elem)))))) ;; Remove the old specification (and possibly a ",12" string). (delete-region beg (match-end 2)) ;; Insert the new specification. @@ -2947,22 +3009,111 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only." (cons conf (delq (assq (car conf) gnus-buffer-configuration) gnus-buffer-configuration)))) +(defun gnus-configure-frame (split &optional window) + "Split WINDOW according to SPLIT." + (unless window + (setq window (get-buffer-window (current-buffer)))) + (select-window window) + ;; This might be an old-stylee buffer config. + (when (vectorp split) + (setq split (append split nil))) + (when (or (consp (car split)) + (vectorp (car split))) + (push 1.0 split) + (push 'vertical split)) + ;; The SPLIT might be something that is to be evaled to + ;; return a new SPLIT. + (while (and (not (assq (car split) gnus-window-to-buffer)) + (gnus-functionp (car split))) + (setq split (eval split))) + (let* ((type (car split)) + (subs (cdr (cdr split))) + (len (if (eq type 'horizontal) (window-width) (window-height) )) + (total 0) + s result new-win rest comp-subs size sub) + (cond + ;; Nothing to do here. + ((null split)) + ;; This is a buffer to be selected. + ((not (or (eq type 'horizontal) (eq type 'vertical))) + (let ((buffer (cdr (assq type gnus-window-to-buffer)))) + (unless buffer + (error "Illegal buffer type: %s" type)) + (switch-to-buffer (get-buffer (if (symbolp buffer) + (symbol-value buffer) + buffer))) + ;; We return the window if it has the `point' spec. + (and (memq 'point split) window))) + ;; This is a normal split + (t + (when (> (length subs) 0) + ;; First we have to compute the sizes of all new windows. + (while subs + (setq sub (append (pop subs) nil)) + (while (and (not (assq (car sub) gnus-window-to-buffer)) + (gnus-functionp (car sub))) + (setq sub (eval sub))) + (when sub + (push sub comp-subs) + (setq size (cadar comp-subs)) + (cond ((equal size 1.0) + (setq rest (car comp-subs)) + (setq s 0)) + ((floatp size) + (setq s (floor (* size len)))) + ((integerp size) + (setq s size)) + (t + (error "Illegal size: %s" size))) + ;; Try to make sure that we are inside the safe limits. + (cond ((zerop s)) + ((and (eq type 'horizontal) + (< s 10)) + (setq s 10)) + ((and (eq type 'vertical) + (< s 4)) + (setq s 4))) + (setcar (cdar comp-subs) s) + (incf total s))) + ;; Take care of the "1.0" spec. + (if rest + (setcar (cdr rest) (- len total)) + (error "No 1.0 specs in %s" split)) + ;; The we do the actual splitting in a nice recursive + ;; fashion. + (setq comp-subs (nreverse comp-subs)) + (while comp-subs + (if (null (cdr comp-subs)) + (setq new-win window) + (setq new-win + (split-window window (cadar comp-subs) + (eq type 'horizontal)))) + (setq result (or (gnus-configure-frame + (car comp-subs) window) result)) + (select-window new-win) + (setq window new-win) + (setq comp-subs (cdr comp-subs)))) + ;; Return the proper window, if any. + (when result + (select-window result)))))) + (defun gnus-configure-windows (setting &optional force) (setq setting (gnus-windows-old-to-new setting)) - (let ((r (if (symbolp setting) - (cdr (assq setting gnus-buffer-configuration)) - setting)) + (let ((split (if (symbolp setting) + (car (cdr (assq setting gnus-buffer-configuration))) + setting)) (in-buf (current-buffer)) rule val w height hor ohor heights sub jump-buffer rel total to-buf all-visible) - (or r (error "No such setting: %s" setting)) - (if (and (not force) (setq all-visible (gnus-all-windows-visible-p r))) + (unless split + (error "No such setting: %s" setting)) + + (if (and (not force) (setq all-visible (gnus-all-windows-visible-p split))) ;; All the windows mentioned are already visible, so we just ;; put point in the assigned buffer, and do not touch the ;; winconf. - (select-window (get-buffer-window all-visible t)) - + (select-window all-visible) ;; Either remove all windows or just remove all Gnus windows. (if gnus-use-full-window @@ -2970,115 +3121,49 @@ If optional argument RE-ONLY is non-nil, strip `Re:' only." (gnus-remove-some-windows) (switch-to-buffer nntp-server-buffer)) - (while r - (setq hor (car r) - ohor nil) - - ;; We have to do the (possible) horizontal splitting before the - ;; vertical. - (if (and (listp (car hor)) - (eq (car (car hor)) 'horizontal)) - (progn - (split-window - nil - (if (integerp (nth 1 (car hor))) - (nth 1 (car hor)) - (- (frame-width) (floor (* (frame-width) (nth 1 (car hor)))))) - t) - (setq hor (cdr hor)))) - - ;; Go through the rules and eval the elements that are to be - ;; evaled. - (while hor - (if (setq val (if (vectorp (car hor)) (car hor) (eval (car hor)))) - (progn - ;; Expand short buffer name. - (setq w (aref val 0)) - (and (setq w (cdr (assq w gnus-window-to-buffer))) - (progn - (setq val (apply 'vector (mapcar 'identity val))) - (aset val 0 w))) - (setq ohor (cons val ohor)))) - (setq hor (cdr hor))) - (setq rule (cons (nreverse ohor) rule)) - (setq r (cdr r))) - (setq rule (nreverse rule)) - - ;; We tally the window sizes. - (setq total (window-height)) - (while rule - (setq hor (car rule)) - (if (and (listp (car hor)) (eq (car (car hor)) 'horizontal)) - (setq hor (cdr hor))) - (setq sub 0) - (while hor - (setq rel (aref (car hor) 1) - heights (cons - (cond ((and (floatp rel) (= 1.0 rel)) - 'x) - ((integerp rel) - rel) - (t - (max (floor (* total rel)) 4))) - heights) - sub (+ sub (if (numberp (car heights)) (car heights) 0)) - hor (cdr hor))) - (setq heights (nreverse heights) - hor (car rule)) - - ;; We then go through these heighs and create windows for them. - (while heights - (setq height (car heights) - heights (cdr heights)) - (and (eq height 'x) - (setq height (- total sub))) - (and heights - (split-window nil height)) - (setq to-buf (aref (car hor) 0)) - (switch-to-buffer - (cond ((not to-buf) - in-buf) - ((symbolp to-buf) - (symbol-value (aref (car hor) 0))) - (t - (aref (car hor) 0)))) - (and (> (length (car hor)) 2) - (eq (aref (car hor) 2) 'point) - (setq jump-buffer (current-buffer))) - (other-window 1) - (setq hor (cdr hor))) - - (setq rule (cdr rule))) - - ;; Finally, we pop to the buffer that's supposed to have point. - (or jump-buffer (error "Missing `point' in spec for %s" setting)) - - (select-window (get-buffer-window jump-buffer t)) - (set-buffer jump-buffer)))) - -(defun gnus-all-windows-visible-p (rule) - (let (invisible hor jump-buffer val buffer) - ;; Go through the rules and eval the elements that are to be - ;; evaled. - (while (and rule (not invisible)) - (setq hor (car rule) - rule (cdr rule)) - (while (and hor (not invisible)) - (if (setq val (if (vectorp (car hor)) - (car hor) - (if (not (eq (car (car hor)) 'horizontal)) - (eval (car hor))))) - (progn - ;; Expand short buffer name. - (setq buffer (or (cdr (assq (aref val 0) gnus-window-to-buffer)) - (aref val 0))) - (setq buffer (if (symbolp buffer) (symbol-value buffer) - buffer)) - (and (> (length val) 2) (eq 'point (aref val 2)) - (setq jump-buffer buffer)) - (setq invisible (not (and buffer (get-buffer-window buffer)))))) - (setq hor (cdr hor)))) - (and (not invisible) jump-buffer))) + (switch-to-buffer nntp-server-buffer) + (gnus-configure-frame split (get-buffer-window (current-buffer)))))) + +(defun gnus-all-windows-visible-p (split) + (when (vectorp split) + (setq split (append split nil))) + (when (or (consp (car split)) + (vectorp (car split))) + (push 1.0 split) + (push 'vertical split)) + ;; The SPLIT might be something that is to be evaled to + ;; return a new SPLIT. + (while (and (not (assq (car split) gnus-window-to-buffer)) + (gnus-functionp (car split))) + (setq split (eval split))) + (let* ((type (elt split 0))) + (cond + ((null split) + t) + ((not (or (eq type 'horizontal) (eq type 'vertical))) + (let ((buffer (cdr (assq type gnus-window-to-buffer))) + win) + (unless buffer + (error "Illegal buffer type: %s" type)) + (setq win + (get-buffer-window (get-buffer (if (symbolp buffer) + (symbol-value buffer) + buffer)))) + (when win + (if (memq 'point split) + win + t)))) + (t + (let ((n (mapcar 'gnus-all-windows-visible-p + (cdr (cdr split)))) + (win t)) + (while n + (cond ((windowp (car n)) + (setq win (car n))) + ((null (car n)) + (setq win nil))) + (setq n (cdr n))) + win))))) (defun gnus-window-top-edge (&optional window) (nth 1 (window-edges window))) @@ -3226,20 +3311,28 @@ that that variable is buffer-local to the summary buffers." (and gnus-auto-expirable-newsgroups ; Check var. (string-match gnus-auto-expirable-newsgroups group))))) -(defun gnus-subject-equal (s1 s2) - "Check whether two subjects are equal." +(defsubst gnus-simplify-subject-fully (subject) + "Simplify a subject string according to the user's wishes." (cond ((null gnus-summary-gather-subject-limit) - (equal (gnus-simplify-subject-re s1) - (gnus-simplify-subject-re s2))) + (gnus-simplify-subject-re subject)) ((eq gnus-summary-gather-subject-limit 'fuzzy) - (equal (gnus-simplify-subject-fuzzy s1) - (gnus-simplify-subject-fuzzy s2))) + (gnus-simplify-subject-fuzzy subject)) ((numberp gnus-summary-gather-subject-limit) - (equal (gnus-limit-string s1 gnus-summary-gather-subject-limit) - (gnus-limit-string s2 gnus-summary-gather-subject-limit))) + (gnus-limit-string subject gnus-summary-gather-subject-limit)) (t - (equal s1 s2)))) + subject))) + +(defsubst gnus-subject-equal (s1 s2 &optional simple-first) + "Check whether two subjects are equal. If optional argument +simple-first is t, first argument is already simplified." + (cond + ((null simple-first) + (equal (gnus-simplify-subject-fully s1) + (gnus-simplify-subject-fully s2))) + (t + (equal s1 + (gnus-simplify-subject-fully s2))))) ;; Returns a list of writable groups. (defun gnus-writable-groups () @@ -7954,7 +8047,7 @@ or a straight list of headers." If READ-ALL is non-nil, all articles in the group are selected." (let* ((entry (gnus-gethash group gnus-newsrc-hashtb)) (info (nth 2 entry)) - articles) + articles fetched-articles) (or (gnus-check-server (setq gnus-current-select-method (gnus-find-method-for-group group))) @@ -8022,8 +8115,12 @@ If READ-ALL is non-nil, all articles in the group are selected." (setq gnus-newsgroup-unreads (gnus-set-sorted-intersection gnus-newsgroup-unreads - (mapcar (lambda (headers) (mail-header-number headers)) - gnus-newsgroup-headers))) + (setq fetched-articles + (mapcar (lambda (headers) (mail-header-number headers)) + gnus-newsgroup-headers)))) + ;; Removed marked articles that do not exist. + (gnus-update-missing-marks + (gnus-sorted-complement fetched-articles articles)) ;; We might want to build some more threads first. (and gnus-fetch-old-headers (eq gnus-headers-retrieved-by 'nov) @@ -8120,10 +8217,7 @@ If READ-ALL is non-nil, all articles in the group are selected." (active (gnus-active (gnus-info-group info))) (min (car active)) (max (cdr active)) - (types '((marked . tick) (replied . reply) - (expirable . expire) (killed . killed) - (bookmarks . bookmark) (dormant . dormant) - (scored . score) (saved . save))) + (types gnus-article-mark-lists) (uncompressed '(score bookmark)) marks var articles article mark) @@ -8151,12 +8245,24 @@ If READ-ALL is non-nil, all articles in the group are selected." (> (car article) max)) (set var (delq article (symbol-value var)))))))))) +(defun gnus-update-missing-marks (missing) + "Go through the list of MISSING articles and remove them mark lists." + (when missing + (let ((types gnus-article-mark-lists) + var m) + ;; Go through all types. + (while types + (setq var (intern (format "gnus-newsgroup-%s" (car (pop types))))) + (when (symbol-value var) + ;; This list has articles. So we delete all missing articles + ;; from it. + (setq m missing) + (while m + (set var (delq (pop m) (symbol-value var))))))))) + (defun gnus-update-marks () "Enter the various lists of marked articles into the newsgroup info list." - (let ((types '((marked . tick) (replied . reply) - (expirable . expire) (killed . killed) - (bookmarks . bookmark) (dormant . dormant) - (scored . score) (saved . save))) + (let ((types gnus-article-mark-lists) (info (gnus-get-info gnus-newsgroup-name)) (uncompressed '(score bookmark killed)) var type list newmarked symbol) @@ -8820,7 +8926,8 @@ If EXCLUDE-GROUP, do not go to this group." (gnus-data-number result))))) (defun gnus-summary-find-subject (subject &optional unread backward article) - (let* ((article (or article (gnus-summary-article-number))) + (let* ((simp-subject (gnus-simplify-subject-fully subject)) + (article (or article (gnus-summary-article-number))) (articles (gnus-data-list backward)) (arts (gnus-data-find-list article articles)) result) @@ -8833,7 +8940,7 @@ If EXCLUDE-GROUP, do not go to this group." (gnus-data-unread-p (car arts))) (vectorp (gnus-data-header (car arts))) (gnus-subject-equal - subject (mail-header-subject (gnus-data-header (car arts)))) + simp-subject (mail-header-subject (gnus-data-header (car arts))) t) (setq result (car arts) arts nil)) (setq arts (cdr arts))) @@ -9100,7 +9207,6 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil." (setq gnus-current-select-method gnus-select-method) (pop-to-buffer gnus-group-buffer) ;; Clear the current group name. - (setq gnus-newsgroup-name nil) (if (not quit-config) (progn (gnus-group-jump-to-group group) @@ -9111,7 +9217,9 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil." (and (eq major-mode 'gnus-summary-mode) (gnus-set-global-variables)) (gnus-configure-windows (cdr quit-config)))) - (run-hooks 'gnus-summary-exit-hook)))) + (run-hooks 'gnus-summary-exit-hook) + (unless quit-config + (setq gnus-newsgroup-name nil))))) (defalias 'gnus-summary-quit 'gnus-summary-exit-no-update) (defun gnus-summary-exit-no-update (&optional no-questions) diff --git a/lisp/nnheader.el b/lisp/nnheader.el index 901643caf..a53f0bc17 100644 --- a/lisp/nnheader.el +++ b/lisp/nnheader.el @@ -414,7 +414,7 @@ Return the number of headers removed." (if (not (boundp 'jka-compr-compression-info-list)) (string-to-int file) (string-match nnheader-numerical-short-files file) - (match-string 1 file))) + (string-to-int (match-string 0 file)))) (defun nnheader-directory-articles (dir) (mapcar 'nnheader-file-to-number diff --git a/lisp/nnml.el b/lisp/nnml.el index 46e6fcdbc..d4168d1fc 100644 --- a/lisp/nnml.el +++ b/lisp/nnml.el @@ -31,6 +31,9 @@ (require 'nnheader) (require 'nnmail) +(eval-when-compile (require 'cl)) + +(require 'cl) (defvar nnml-directory "~/Mail/" "Mail spool directory.") @@ -718,7 +721,7 @@ all. This may very well take some time.") (let ((group (nnmail-replace-chars-in-string (substring dir (length nnml-directory)) ?/ ?.))) - (setq nnml-group-alist (delq (assoc group nnml-group-alist))) + (setq nnml-group-alist (delq (assoc group nnml-group-alist) nnml-group-alist)) (push (list group (cons (car files) (let ((f files)) @@ -727,9 +730,10 @@ all. This may very well take some time.") nnml-group-alist))) (defun nnml-generate-nov-file (dir files) - (let ((nov (concat dir "/" nnml-nov-file-name)) - (nov-buffer (get-buffer-create " *nov*")) - nov-line chars) + (let* ((dir (file-name-as-directory dir)) + (nov (concat dir nnml-nov-file-name)) + (nov-buffer (get-buffer-create " *nov*")) + nov-line chars) (save-excursion ;; Init the nov buffer. (set-buffer nov-buffer) @@ -741,13 +745,13 @@ all. This may very well take some time.") (funcall nnmail-delete-file-function nov)) (while files (erase-buffer) - (insert-file-contents (concat dir "/" (int-to-string (car files)))) + (insert-file-contents (concat dir (int-to-string (car files)))) (narrow-to-region (goto-char (point-min)) (progn (search-forward "\n\n" nil t) (setq chars (- (point-max) (point))) - (1- (point)))) + (max 1 (1- (point))))) (when (and (not (= 0 chars)) ; none of them empty files... (not (= (point-min) (point-max)))) (goto-char (point-min)) diff --git a/texi/ChangeLog b/texi/ChangeLog index c20dc3e2d..f64806bd7 100644 --- a/texi/ChangeLog +++ b/texi/ChangeLog @@ -1,3 +1,12 @@ +Fri Dec 15 13:53:02 1995 Lars Ingebrigtsen + + * gnus.texi (Windows Configuration): Addition, change. + +Thu Dec 14 17:57:19 1995 Lars Ingebrigtsen + + * gnus.texi (Group Parameters): Addition. + (Other Decode Variables): Addition. + Wed Dec 13 16:13:56 1995 Lars Ingebrigtsen * gnus.texi (Selecting a Group): Addition. diff --git a/texi/gnus.texi b/texi/gnus.texi index 143c7b535..81f117b80 100644 --- a/texi/gnus.texi +++ b/texi/gnus.texi @@ -3171,6 +3171,11 @@ If the group parameter has an element that looks like @samp{(expiry-wait The value can either be a number of days (not necessarily an integer) or the symbols @code{never} or @code{immediate}. +@item score-file +Elements that look like @samp{(score-file . "file")} will make +@samp{file} into the current score file for the group in question. This +means that all score commands you issue will end up in that file. + @item @var{(variable form)} You can use the group parameters to set variables local to the group you are entering. Say you want to turn threading off in @@ -6566,10 +6571,28 @@ This variable can be used to say what commands should be used to unpack archives. @end table + @node Other Decode Variables @subsubsection Other Decode Variables @table @code +@vindex gnus-uu-grabbed-file-functions +@item gnus-uu-grabbed-file-functions +All functions in this list will be called right each file has been +successfully decoded---so that you can move or view files right away, +and don't have to wait for all files to be decoded before you can do +anything. Ready-made functions you can put in this list are: + +@table @code +@item gnus-uu-grab-view +@findex gnus-uu-grab-view +View the file. + +@item gnus-uu-grab-move +@findex gnus-uu-grab-move +Move the file (if you're using a saving function.) +@end table + @item gnus-uu-ignore-files-by-name @vindex gnus-uu-ignore-files-by-name Files with name matching this regular expression won't be viewed. @@ -8785,22 +8808,19 @@ examine the resulting lisp code to be run to generate the line. No, there's nothing here about X, so be quiet. -@table @code -@item gnus-use-full-window @vindex gnus-use-full-window -If non-@code{nil}, Gnus will delete all other windows and occupy the -entire Emacs screen by itself. It is @code{t} by default. +If @code{gnus-use-full-window} non-@code{nil}, Gnus will delete all +other windows and occupy the entire Emacs screen by itself. It is +@code{t} by default. -@item gnus-buffer-configuration -@vindex gnus-buffer-configuration -This variable describes how much space each Gnus buffer should be given. -Here's an excerpt of this variable: +@code{gnus-buffer-configuration} describes how much space each Gnus +buffer should be given. Here's an excerpt of this variable: @lisp -((group ([group 1.0 point] - (if gnus-carpal [group-carpal 4]))) - (article ([summary 0.25 point] - [article 1.0]))) +((group (vertical 1.0 (group 1.0 point) + (if gnus-carpal (group-carpal 4)))) + (article (vertical 1.0 (summary 0.25 point) + (article 1.0)))) @end lisp This is an alist. The @dfn{key} is a symbol that names some action or @@ -8808,21 +8828,22 @@ other. For instance, when displaying the group buffer, the window configuration function will use @code{group} as the key. A full list of possible names is listed below. -The @dfn{value} is a @dfn{rule} that says how much space each buffer -should occupy. To take the @code{article} rule as an example - +The @dfn{value} (i. e., the @dfn{split}) says how much space each buffer +should occupy. To take the @code{article} split as an example - @lisp -(article ([summary 0.25 point] - [article 1.0])) +(article (vertical 1.0 (summary 0.25 point) + (article 1.0))) @end lisp -This rule says that the summary buffer should occupy 25% of the screen, -and that it is placed over the article buffer. As you may have noticed, -100% + 25% is actually 125% (yup, I saw y'all reaching for that -calculator there). However, the special number @code{1.0} is used to -signal that this buffer should soak up all the rest of the space -avaiable after the rest of the buffers have taken whatever they need. -There should be only one buffer with the @code{1.0} size spec. +This @dfn{split} says that the summary buffer should occupy 25% of upper +half of the screen, and that it is placed over the article buffer. As +you may have noticed, 100% + 25% is actually 125% (yup, I saw y'all +reaching for that calculator there). However, the special number +@code{1.0} is used to signal that this buffer should soak up all the +rest of the space avaiable after the rest of the buffers have taken +whatever they need. There should be only one buffer with the @code{1.0} +size spec per split. Point will be put in the buffer that has the optional third element @code{point}. @@ -8830,47 +8851,104 @@ Point will be put in the buffer that has the optional third element Here's a more complicated example: @lisp -(article ([group 4] - [summary 0.25 point] - (if gnus-carpal [summary-carpal 4]) - [article 1.0]) +(article (vertical 1.0 (group 4) + (summary 0.25 point) + (if gnus-carpal (summary-carpal 4)) + (article 1.0))) @end lisp If the size spec is an integer instead of a floating point number, then that number will be used to say how many lines a buffer should occupy, not a percentage. -If an element is a list instead of a vector, this list will be -@code{eval}ed. If the result is non-@code{nil}, it will be used. This -means that there will be three buffers if @code{gnus-carpal} is -@code{nil}, and four buffers if @code{gnus-carpal} is non-@code{nil}. +If the @dfn{split} looks like something that can be @code{eval}ed (to be +precise---if the @code{car} of the split is a function or a subr), this +split will be @code{eval}ed. If the result is non-@code{nil}, it will +be used as a split. This means that there will be three buffers if +@code{gnus-carpal} is @code{nil}, and four buffers if @code{gnus-carpal} +is non-@code{nil}. Not complicated enough for you? Well, try this on for size: @lisp -(article ([group 1.0] - [gnus-carpal 4]) - ((horizontal 0.5) - [summary 0.25 point] - [summary-carpal 4] - [article 1.0])) +(article (horizontal 1.0 + (vertical 0.5 + (group 1.0) + (gnus-carpal 4)) + (vertical 1.0 + (summary 0.25 point) + (summary-carpal 4) + (article 1.0)))) @end lisp Whoops. Two buffers with the mystery 100% tag. And what's that @code{horizontal} thingie? -If the first element in one of the rule lists is a list with -@code{horizontal} as the first element, Gnus will split the window -horizontally, giving you two windows side-by-side. Inside each of these -strips you may carry on all you like in the normal fashion. The number -following @code{horizontal} says what percentage of the screen is to be -given to this strip. +If the first element in one of the split is @code{horizontal}, Gnus will +split the window horizontally, giving you two windows side-by-side. +Inside each of these strips you may carry on all you like in the normal +fashion. The number following @code{horizontal} says what percentage of +the screen is to be given to this strip. -For each horizontal split, there @emph{must} be one element that has the -100% tag. The splitting is never accurate, and this buffer will eat any -leftover lines from the splits. +For each split, there @emph{must} be one element that has the 100% tag. +The splitting is never accurate, and this buffer will eat any leftover +lines from the splits. -Here's a list of all possible keys: +To be slightly more formal, here's a definition of what a legal split +may look like: + +@example +split = frame | horizontal | vertical | buffer | form +frame = "(frame " frame-size *split ")" +horizontal = "(horizontal " size *split ")" +vertical = "(vertical " size *split ")" +buffer = "(" buffer-name " " size *[ "point" ] ")" +frame-size = "(" number " . " number ")" +size = number +buffer-name = group | article | summary ... +@end example + +The limitations are that the @samp{frame} split can only appear as the +top-level split. @samp{form} should be an Emacs Lisp form that should +return a valid split. We see that each split is fully recursive, and +may contain any number of @samp{vertical} and @samp{horizontal} splits. + +Finding the right sizes can be a bit complicated. No window may be less +than 4 characters high, and all windows must be at least 10 characters +wide. Gnus will try to enforce this before applying the splits. + +If you're not familiar with Emacs terminology, @samp{horizontal} and +@samp{vertical} splits may work the opposite way of what you'd expect. +Windows inside a @samp{horizontal} split are shown side-by-side, and +windows within a @samp{vertical} split are shown above each other. + +@findex gnus-configure-frame +If you want to experiment with window placement, a good tip is to call +@code{gnus-configure-frame} directly with a split. This is the function +that does all the real work when splitting buffers. Below is a pretty +nonsensical configuration with 5 windows; two for the group buffer and +three for the article buffer. (I said it was nonsensical.) If you +@code{eval} the statement below, you can get an idea of how that would +look straight away, without going through the normal Gnus channels. +Play with it until you're satisfied, and then use +@code{gnus-add-configuration} to add your new creation to the buffer +configuration list. + +@example +(gnus-configure-frame + '(horizontal 1.0 + (vertical 10 + (group 1.0) + (article 0.3 point)) + (vertical 1.0 + (article 1.0) + (horizontal 4 + (group 1.0) + (article 10))))) +@end example + +Here's a list of all possible keys for +@code{gnus-buffer-configuaration}: @code{group}, @code{summary}, @code{article}, @code{server}, @code{browse}, @code{group-mail}, @code{summary-mail}, @@ -8879,19 +8957,20 @@ Here's a list of all possible keys: @code{followup}, @code{followup-yank}, @code{edit-score}. @findex gnus-add-configuration -Since this variable is so long and complicated, there's a function you -can use to ease changing the config of a single setting: -@code{gnus-add-configuration}. If, for instance, you want to change the -@code{article} setting, you could say: +Since the @code{gnus-buffer-configuration} variable is so long and +complicated, there's a function you can use to ease changing the config +of a single setting: @code{gnus-add-configuration}. If, for instance, +you want to change the @code{article} setting, you could say: @lisp (gnus-add-configuration - '(article ([group 4] - [summary .25 point] - [article 1.0]))) + '(article (vertical 1.0 + (group 4) + (summary .25 point) + (article 1.0)))) @end lisp -@end table + @node Buttons @section Buttons -- 2.25.1