From f9c33fb2146e4cef334617ed9e5c34130243ec03 Mon Sep 17 00:00:00 2001 From: tomo Date: Sun, 21 Feb 1999 07:12:53 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create tag 'pgnus-0_77'. --- ChangeLog | 277 ---------- Makefile | 36 -- lisp/Makefile | 40 -- lisp/date.el | 124 ----- lisp/gnus-mailcap.el | 850 ------------------------------ lisp/mm.el | 1283 -------------------------------------------- lisp/rfc1522.el | 276 ---------- readme | 52 -- texi/Makefile | 161 ------ texi/custom.texi | 695 ------------------------ texi/widget.texi | 1432 -------------------------------------------------- 11 files changed, 5226 deletions(-) delete mode 100644 ChangeLog delete mode 100644 Makefile delete mode 100644 lisp/Makefile delete mode 100644 lisp/date.el delete mode 100644 lisp/gnus-mailcap.el delete mode 100644 lisp/mm.el delete mode 100644 lisp/rfc1522.el delete mode 100644 readme delete mode 100644 texi/Makefile delete mode 100644 texi/custom.texi delete mode 100644 texi/widget.texi diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index db57397..0000000 --- a/ChangeLog +++ /dev/null @@ -1,277 +0,0 @@ -1998-01-08 MORIOKA Tomohiko - - * lisp/smtpmail.el (smtpmail-via-smtp): Bind - `coding-system-for-read' by `smtpmail-coding-system' to avoid - dead-locking in Emacs 20. - - * lisp/gnus.el: gnus.el (gnus-version-number): Update to version - 6.0.2. - -1998-01-07 MORIOKA Tomohiko - - * lisp/nnmail.el, lisp/message.el: Sync with Quassia Gnus v0.22. - - * lisp/gnus.el: Delete autoload setting for `metamail-buffer'. - - * lisp/gnus.el, lisp/gnus-sum.el: Sync with Quassia Gnus v0.22. - - * lisp/gnus-msg.el: Abolish function - `gnus-inews-insert-mime-headers'. - - * lisp/gnus-msg.el, lisp/gnus-draft.el, lisp/gnus-art.el: Sync - with Quassia Gnus v0.22. - - * lisp/smtpmail.el (smtpmail-coding-system): New variable; abolish - `smtpmail-code-conv-from'. - (smtpmail-via-smtp): Guard `coding-system-for-write' by - `smtpmail-coding-system'. - - * lisp/smtpmail.el: Imported from Emacs 20.2. - - * lisp/pop3.el (pop3-movemail-file-coding-system): Change default - value to `binary'. - (pop3-open-server): Guard `coding-system-for-read' by `binary'. - -1998-01-06 Shuhei Kobayashi - - * texi/message.texi, texi/gnus.texi, texi/ChangeLog, lisp/nnoo.el, - lisp/nnml.el, lisp/message.el, lisp/gnus.el, lisp/gnus-sum.el, - lisp/gnus-start.el, lisp/gnus-ems.el, lisp/gnus-draft.el, - lisp/gnus-agent.el, lisp/ChangeLog: Importing qgnus-0.22 - - * texi/message.texi, texi/gnus.texi, lisp/gnus.el, lisp/ChangeLog: - Importing qgnus-0.21 - - * texi/message.texi, texi/gnus.texi, texi/ChangeLog, - lisp/nnvirtual.el, lisp/nnsoup.el, lisp/nnoo.el, lisp/nnmh.el, - lisp/nnmail.el, lisp/nndraft.el, lisp/gnus.el, lisp/gnus-xmas.el, - lisp/gnus-sum.el, lisp/gnus-start.el, lisp/gnus-score.el, - lisp/gnus-msg.el, lisp/gnus-group.el, lisp/gnus-draft.el, - lisp/gnus-art.el, lisp/ChangeLog: Importing qgnus-0.20 - - * texi/message.texi, texi/gnus.texi, texi/ChangeLog, lisp/pop3.el, - lisp/nntp.el, lisp/nnml.el, lisp/nnmail.el, lisp/nndoc.el, - lisp/message.el, lisp/gnus.el, lisp/gnus-uu.el, - lisp/gnus-topic.el, lisp/gnus-sum.el, lisp/gnus-start.el, - lisp/gnus-score.el, lisp/gnus-group.el, lisp/gnus-cache.el, - lisp/gnus-agent.el, lisp/ChangeLog: Importing qgnus-0.19 - -1997-12-27 MORIOKA Tomohiko - - * lisp/gnus.el (gnus-version-number): Update to version 6.0.1. - - * lisp/message.el (message-resend): Enclose `message-setup' with - `(let (message-setup-hook) ...)' to avoid to `turn-on-mime-edit'; - must setup `message-encoding-buffer' and `message-edit-buffer' for - `message-send-mail'. - -1997-12-08 Shuhei Kobayashi - - * lisp/pop3.el, lisp/message.el, lisp/gnus.el, lisp/gnus-sum.el, - lisp/gnus-art.el, lisp/ChangeLog: Synch'ed up to qgnus-0.18. - - * texi/message.texi, texi/gnus.texi, texi/ChangeLog, - lisp/smiley.el, lisp/pop3.el, lisp/nnweb.el, lisp/nntp.el, - lisp/nnml.el, lisp/nnmail.el, lisp/nnheader.el, lisp/nndraft.el, - lisp/message.el, lisp/lpath.el, lisp/gnus.el, lisp/gnus-util.el, - lisp/gnus-sum.el, lisp/gnus-start.el, lisp/gnus-picon.el, - lisp/gnus-nocem.el, lisp/gnus-mh.el, lisp/gnus-group.el, - lisp/gnus-ems.el, lisp/gnus-cite.el, lisp/gnus-art.el, - lisp/gnus-agent.el, lisp/dgnushack.el, lisp/ChangeLog: Importing - qgnus-0.18 - -1997-11-29 MORIOKA Tomohiko - - * README.semi: New file. - - * lisp/gnus.el (gnus-version): Rename to "Semi-gnus". - -1997-11-28 MORIOKA Tomohiko - - * lisp/gnus-draft.el (gnus-draft-decoding-function): New variable. - (gnus-draft-setup): Use `gnus-draft-decoding-function'. - -1997-11-27 MORIOKA Tomohiko - - * lisp/nnmail.el, lisp/nnheader.el, lisp/message.el, lisp/gnus.el, - lisp/gnus-sum.el, lisp/gnus-msg.el, lisp/gnus-art.el: sync with - qgnus-0.17. - - * texi/message.texi, texi/gnus.texi, lisp/smiley.el, lisp/nnoo.el, - lisp/nnml.el, lisp/nnmail.el, lisp/nnheader.el, - lisp/messagexmas.el, lisp/message.el, lisp/gnus.el, - lisp/gnus-xmas.el, lisp/gnus-util.el, lisp/gnus-sum.el, - lisp/gnus-start.el, lisp/gnus-spec.el, lisp/gnus-score.el, - lisp/gnus-picon.el, lisp/gnus-move.el, lisp/gnus-msg.el, - lisp/gnus-kill.el, lisp/gnus-group.el, lisp/gnus-draft.el, - lisp/gnus-demon.el, lisp/gnus-cite.el, lisp/gnus-art.el, - lisp/ChangeLog: Quassia Gnus v0.17. - - * lisp/gnus-i18n.el: New file. - - * lisp/nnmail.el (nnmail-file-coding-system): Use `raw-text' in - default. - - * lisp/nnheader.el (nnheader-file-coding-system): Use `raw-text' - in default. - - * lisp/message.el (message-encode-function): New variable. - (message-forward-start-separator): Modify for mime-edit. - (message-forward-end-separator): Modify for mime-edit. - (message-setup-hook): Use `(message-maybe-setup-default-charset - turn-on-mime-edit)' in default. - (message-header-hook): Use `(eword-encode-header)' in default. - - (message-send): Use local variable `message-encoding-buffer', - `message-edit-buffer' and `message-mime-mode' as public variables; - use `message-encode-function'. - (message-send-mail): Use `message-encoding-buffer' to get contents - of body; abolish `message-encode-mail-hook'; use - `mime-edit-maybe-split-and-send'; use `message-edit-buffer' to - refer original editing buffer. - (message-send-news): Use `message-encoding-buffer' to get contents - of body; abolish `message-encode-news-hook'; use - `mime-edit-maybe-split-and-send'; use `message-edit-buffer' to - refer original editing buffer. - (message-check-news-syntax): Call `message-check-news-body-syntax' - in `mime-edit-buffer'. - (message-do-fcc): Use `message-encoding-buffer' to get contents; - run `message-header-hook'. - (message-cancel-news): Use `std11-extract-address-components' - instead of `mail-extract-address-components'; bind - `message-encoding-buffer' and `message-edit-buffer'. - - (message-maybe-setup-default-charset): New function. - (message-maybe-encode): New function. - (message-mime-insert-article): New function. - Add setting for mime-view. - - * lisp/gnus.el (gnus-version-number): for version number for Open - gnus. - (gnus-version): Modify for Open gnus. - - * lisp/gnus-sum.el: Autoload gnus-i18n. - - (gnus-show-mime): `t' in default. - (gnus-structured-field-decoder): Use - `eword-decode-structured-field-body' in default. - (gnus-unstructured-field-decoder): Use - `eword-decode-unstructured-field-body' in default. - - (gnus-parse-headers-hook): Use - `(gnus-set-summary-default-charset)' in default. - - (gnus-summary-mode-map): Add binding for - `gnus-summary-scroll-down' and - `gnus-summary-preview-mime-message'. - - (gnus-summary-preview-mime-message): New function. - (gnus-mime-partial-preview-function): New function. - Add setting for mime-view. - - * lisp/gnus-msg.el (gnus-summary-cancel-article): Display - `gnus-article-buffer' instead ofb `gnus-original-article-buffer'. - (gnus-extended-version): Don't return version of emacsen. - (gnus-inews-do-gcc): Refer `message-encoding-buffer'. - - * lisp/gnus-art.el (gnus-show-mime-method): Use - `gnus-article-preview-mime-message' instead of `metamail-buffer' - in default. - (gnus-decode-encoded-word-method): Use - `gnus-article-decode-encoded-word' instead of - `gnus-article-de-quoted-unreadable' in default. - - Abolish `gnus-hack-decode-rfc1522', `gnus-decode-rfc1522', - `article-decode-rfc1522', `article-de-quoted-unreadable', - `article-mime-decode-quoted-printable-buffer' and - `article-mime-decode-quoted-printable'. - (gnus-article-decode-rfc1522): New implementation (use - `eword-decode-header'). - - (gnus-article-preview-mime-message): New function. - (gnus-article-decode-encoded-word): New function. - (gnus-content-header-filter): New function. - (mime-view-quitting-method-for-gnus): New function. - Add setting for mime-view. - - * lisp/message.el: Abolish `message-max-size' because it is not - used. - - * lisp/message.el: sync with qgnus-0.16. - - * texi/Makefile, texi/message.texi, texi/gnus.texi, lisp/nnweb.el, - lisp/nnmh.el, lisp/nnheader.el, lisp/nnfolder.el, lisp/message.el, - lisp/gnus.el, lisp/gnus-xmas.el, lisp/gnus-uu.el, - lisp/gnus-sum.el, lisp/gnus-srvr.el, lisp/gnus-picon.el, - lisp/gnus-group.el, lisp/gnus-cite.el, lisp/gnus-art.el: Quassia - Gnus v0.16. - - * lisp/nnmh.el (nnmh-request-list-1): fix maybe. - - * lisp/message.el (message-do-fcc): Guard - `coding-system-for-write' by `raw-text'; run - `message-before-do-fcc-hook'. - - * lisp/gnus-msg.el (gnus-inews-do-gcc): Guard - `coding-system-for-write' by `raw-text'; run - `gnus-before-do-gcc-hook'. - - * texi/message.texi, texi/gnus.texi, texi/ChangeLog, lisp/nntp.el, - lisp/nnoo.el, lisp/nnml.el, lisp/nndraft.el, lisp/nnbabyl.el, - lisp/message.el, lisp/gnus.el, lisp/gnus-xmas.el, lisp/gnus-uu.el, - lisp/gnus-util.el, lisp/gnus-sum.el, lisp/gnus-start.el, - lisp/gnus-spec.el, lisp/gnus-soup.el, lisp/gnus-score.el, - lisp/gnus-msg.el, lisp/gnus-gl.el, lisp/gnus-ems.el, - lisp/gnus-draft.el, lisp/gnus-cache.el, lisp/gnus-audio.el, - lisp/gnus-art.el, lisp/gnus-agent.el, lisp/ChangeLog: Quassia Gnus - v0.15. - - * lisp/message.el, lisp/ChangeLog: sync with qgnus-0.14. - - * texi/Makefile, texi/gnus.texi: Quassia Gnus v0.14. - - * texi/dir: New file. - - * texi/dir, lisp/pop3.el, lisp/nntp.el, lisp/nnml.el, - lisp/nnmail.el, lisp/nnfolder.el, lisp/message.el, lisp/lpath.el, - lisp/gnus.el, lisp/gnus-win.el, lisp/gnus-util.el, - lisp/gnus-topic.el, lisp/gnus-sum.el, lisp/gnus-start.el, - lisp/gnus-score.el, lisp/gnus-msg.el, lisp/gnus-mh.el, - lisp/gnus-cus.el, lisp/gnus-art.el, lisp/gnus-agent.el, - lisp/ChangeLog: Quassia Gnus v0.14. - - * lisp/message.el, lisp/ChangeLog: sync with qgnus-0.13. - - * texi/gnus.texi, texi/ChangeLog, lisp/pop3.el, lisp/nnweb.el, - lisp/nnmail.el: Quassia Gnus v0.13. - - * lisp/nnlistserv.el: New file. - - * lisp/nnlistserv.el, lisp/message.el, lisp/md5.el, lisp/lpath.el, - lisp/gnus.el, lisp/gnus-topic.el, lisp/gnus-sum.el, - lisp/gnus-score.el, lisp/gnus-picon.el, lisp/gnus-msg.el, - lisp/gnus-group.el, lisp/gnus-art.el, lisp/gnus-agent.el, - lisp/dgnushack.el, lisp/ChangeLog, GNUS-NEWS: Quassia Gnus v0.13. - - * lisp/message.el: sync with qgnus-0.12. - - * texi/message.texi, texi/gnus.texi, texi/gnus-faq.texi, - texi/ChangeLog, lisp/nntp.el, lisp/nnmh.el, lisp/nnmail.el, - lisp/nndraft.el, lisp/messcompat.el, lisp/message.el, - lisp/gnus.el, lisp/gnus-xmas.el, lisp/gnus-uu.el, - lisp/gnus-sum.el, lisp/gnus-score.el, lisp/gnus-salt.el, - lisp/gnus-msg.el, lisp/gnus-int.el, lisp/gnus-group.el, - lisp/gnus-demon.el, lisp/gnus-cache.el, lisp/gnus-art.el, - lisp/gnus-agent.el, lisp/ChangeLog, GNUS-NEWS: Quassia Gnus v0.12. - - * lisp/message.el (message-send-news-function): Use - `message-send-news-with-gnus' in default. - (message-send-via-news): Use `message-send-news' instead of - `message-send-news-function'. - (message-send-mail): Don't avoid text properties; run - `message-encode-mail-hook'. - (message-send-news): Don't avoid text properties; run - `message-encode-news-hook'; use `message-send-news-function'. - (message-send-news-with-gnus): New function. - (message-cancel-news): Use `message-send-news' instead of - `message-send-news-function'. diff --git a/Makefile b/Makefile deleted file mode 100644 index 05503f4..0000000 --- a/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -EMACS=emacs -XEMACS=xemacs - -all: lick info - -lick: - cd lisp; $(MAKE) EMACS=$(EMACS) all - -# Rule for Lars and nobody else. -some: - cd lisp; $(MAKE) EMACS=$(EMACS) some -l: - cd lisp; $(MAKE) EMACS=$(EMACS) clever - -info: - cd texi; $(MAKE) EMACS=$(EMACS) all - -clean: - rm -f */*.orig */*.rej *.orig *.rej - -xsome: - cd lisp; $(MAKE) EMACS=$(XEMACS) some - -elclean: - rm lisp/*.elc - -x: - make EMACS=xemacs - -distclean: - make clean - rm -r *~ - for i in lisp texi; do (cd $$i; make distclean); done - -osome: - make EMACS=emacs-19.34 some diff --git a/lisp/Makefile b/lisp/Makefile deleted file mode 100644 index b949400..0000000 --- a/lisp/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -SHELL = /bin/sh -EMACS=emacs -FLAGS=-batch -q -no-site-file -l ./dgnushack.el - -total: - rm -f *.elc ; $(EMACS) $(FLAGS) -f dgnushack-compile - -all: - rm -f *.elc ; $(EMACS) $(FLAGS) -f dgnushack-compile - -clever: - $(EMACS) $(FLAGS) -f dgnushack-compile - -some: - $(EMACS) $(FLAGS) -f dgnushack-compile - -tags: - etags *.el - -separately: - rm -f *.elc ; for i in *.el; do $(EMACS) $(FLAGS) -f batch-byte-compile $$i; done - -pot: - xpot -drgnus -r`cat ./version` *.el > rgnus.pot - -gnus-load.el: - echo ";;; gnus-load.el --- automatically extracted custom dependencies" > gnus-load.el - echo ";;" >> gnus-load.el - echo ";;; Code:" >> gnus-load.el - echo >> gnus-load.el - $(EMACS) $(FLAGS) -l ./dgnushack.el -l cus-edit.el *.el \ - -f custom-make-dependencies >> gnus-load.el - echo >> gnus-load.el - echo "(provide 'gnus-load)" >> gnus-load.el - echo >> gnus-load.el - echo ";;; gnus-load.el ends here" >> gnus-load.el - -distclean: - rm -f *.orig *.rej *.elc *~ - diff --git a/lisp/date.el b/lisp/date.el deleted file mode 100644 index b593e1c..0000000 --- a/lisp/date.el +++ /dev/null @@ -1,124 +0,0 @@ -;;; date.el --- Date and time handling functions -;; Copyright (C) 1998 Free Software Foundation, Inc. - -;; Author: Lars Magne Ingebrigtsen -;; Masanobu Umeda -;; This file is part of GNU Emacs. - -;; 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. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; 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., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Commentary: - -;;; Code: - -(require 'timezone) - -(defun parse-time-string (date) - "Convert DATE into time." - (decode-time - (condition-case () - (let* ((d1 (timezone-parse-date date)) - (t1 (timezone-parse-time (aref d1 3)))) - (apply 'encode-time - (mapcar (lambda (el) - (and el (string-to-number el))) - (list - (aref t1 2) (aref t1 1) (aref t1 0) - (aref d1 2) (aref d1 1) (aref d1 0) - (number-to-string - (* 60 (timezone-zone-to-minute (aref d1 4)))))))) - ;; If we get an error, then we just return a 0 time. - (error (list 0 0))))) - -(defun date-to-time (date) - "Convert DATE into time." - (apply 'encode-time (parse-time-string date))) - -(defun time-less-p (t1 t2) - "Say whether time T1 is less than time T2." - (or (< (car t1) (car t2)) - (and (= (car t1) (car t2)) - (< (nth 1 t1) (nth 1 t2))))) - -(defun days-to-time (days) - "Convert DAYS into time." - (let* ((seconds (* 1.0 days 60 60 24)) - (rest (expt 2 16)) - (ms (condition-case nil (floor (/ seconds rest)) - (range-error (expt 2 16))))) - (list ms (condition-case nil (round (- seconds (* ms rest))) - (range-error (expt 2 16)))))) - -(defun time-since (time) - "Return the time since TIME, which is either an internal time or a date." - (when (stringp time) - ;; Convert date strings to internal time. - (setq time (date-to-time time))) - (let* ((current (current-time)) - (rest (when (< (nth 1 current) (nth 1 time)) - (expt 2 16)))) - (list (- (+ (car current) (if rest -1 0)) (car time)) - (- (+ (or rest 0) (nth 1 current)) (nth 1 time))))) - -(defun subtract-time (t1 t2) - "Subtract two internal times." - (let ((borrow (< (cadr t1) (cadr t2)))) - (list (- (car t1) (car t2) (if borrow 1 0)) - (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) - -(defun date-to-day (date) - "Return the number of days between year 1 and DATE." - (time-to-day (date-to-time date))) - -(defun days-between (date1 date2) - "Return the number of days between DATE1 and DATE2." - (- (date-to-day date1) (date-to-day date2))) - -(defun date-leap-year-p (year) - "Return t if YEAR is a leap year." - (or (and (zerop (% year 4)) - (not (zerop (% year 100)))) - (zerop (% year 400)))) - -(defun time-to-day-in-year (time) - "Return the day number within the year of the date month/day/year." - (let* ((tim (decode-time time)) - (month (nth 4 tim)) - (day (nth 3 tim)) - (year (nth 5 tim)) - (day-of-year (+ day (* 31 (1- month))))) - (when (> month 2) - (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10))) - (when (date-leap-year-p year) - (setq day-of-year (1+ day-of-year)))) - day-of-year)) - -(defun time-to-day (time) - "The number of days between the Gregorian date 0001-12-31bce and TIME. -The Gregorian date Sunday, December 31, 1bce is imaginary." - (let* ((tim (decode-time time)) - (month (nth 4 tim)) - (day (nth 3 tim)) - (year (nth 5 tim))) - (+ (time-to-day-in-year time) ; Days this year - (* 365 (1- year)) ; + Days in prior years - (/ (1- year) 4) ; + Julian leap years - (- (/ (1- year) 100)) ; - century years - (/ (1- year) 400)))) ; + Gregorian leap years - -(provide 'date) - -;;; date.el ends here diff --git a/lisp/gnus-mailcap.el b/lisp/gnus-mailcap.el deleted file mode 100644 index a352f5b..0000000 --- a/lisp/gnus-mailcap.el +++ /dev/null @@ -1,850 +0,0 @@ -;;; mailcap.el --- Functions for displaying MIME parts -;; Copyright (C) 1998 Free Software Foundation, Inc. - -;; Author: William M. Perry -;; Lars Magne Ingebrigtsen -;; Keywords: news, mail - -;; This file is part of GNU Emacs. - -;; 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. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; 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., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Commentary: - -;;; Code: - -(eval-and-compile - (require 'cl)) -(require 'mail-parse) - -(defvar mailcap-parse-args-syntax-table - (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table))) - (modify-syntax-entry ?' "\"" table) - (modify-syntax-entry ?` "\"" table) - (modify-syntax-entry ?{ "(" table) - (modify-syntax-entry ?} ")" table) - table) - "A syntax table for parsing sgml attributes.") - -(defvar mailcap-mime-data - '(("application" - ("x-x509-ca-cert" - (viewer . ssl-view-site-cert) - (test . (fboundp 'ssl-view-site-cert)) - (type . "application/x-x509-ca-cert")) - ("x-x509-user-cert" - (viewer . ssl-view-user-cert) - (test . (fboundp 'ssl-view-user-cert)) - (type . "application/x-x509-user-cert")) - ("octet-stream" - (viewer . mailcap-save-binary-file) - (type ."application/octet-stream")) - ("dvi" - (viewer . "open %s") - (type . "application/dvi") - (test . (eq (mm-device-type) 'ns))) - ("dvi" - (viewer . "xdvi %s") - (test . (eq (mm-device-type) 'x)) - ("needsx11") - (type . "application/dvi")) - ("dvi" - (viewer . "dvitty %s") - (test . (not (getenv "DISPLAY"))) - (type . "application/dvi")) - ("emacs-lisp" - (viewer . mailcap-maybe-eval) - (type . "application/emacs-lisp")) - ("x-tar" - (viewer . mailcap-save-binary-file) - (type . "application/x-tar")) - ("x-latex" - (viewer . tex-mode) - (test . (fboundp 'tex-mode)) - (type . "application/x-latex")) - ("x-tex" - (viewer . tex-mode) - (test . (fboundp 'tex-mode)) - (type . "application/x-tex")) - ("latex" - (viewer . tex-mode) - (test . (fboundp 'tex-mode)) - (type . "application/latex")) - ("tex" - (viewer . tex-mode) - (test . (fboundp 'tex-mode)) - (type . "application/tex")) - ("texinfo" - (viewer . texinfo-mode) - (test . (fboundp 'texinfo-mode)) - (type . "application/tex")) - ("zip" - (viewer . mailcap-save-binary-file) - (type . "application/zip") - ("copiousoutput")) - ("pdf" - (viewer . "acroread %s") - (type . "application/pdf")) - ("postscript" - (viewer . "open %s") - (type . "application/postscript") - (test . (eq (mm-device-type) 'ns))) - ("postscript" - (viewer . "ghostview %s") - (type . "application/postscript") - (test . (eq (mm-device-type) 'x)) - ("needsx11")) - ("postscript" - (viewer . "ps2ascii %s") - (type . "application/postscript") - (test . (not (getenv "DISPLAY"))) - ("copiousoutput"))) - ("audio" - ("x-mpeg" - (viewer . "maplay %s") - (type . "audio/x-mpeg")) - (".*" - (viewer . mailcap-save-binary-file) - (test . (or (featurep 'nas-sound) - (featurep 'native-sound))) - (type . "audio/*")) - (".*" - (viewer . "showaudio") - (type . "audio/*"))) - ("message" - ("rfc-*822" - (viewer . gnus-article-prepare-display) - (test . (and (featurep 'gnus) - (gnus-alive-p))) - (type . "message/rfc-822")) - ("rfc-*822" - (viewer . vm-mode) - (test . (fboundp 'vm-mode)) - (type . "message/rfc-822")) - ("rfc-*822" - (viewer . w3-mode) - (test . (fboundp 'w3-mode)) - (type . "message/rfc-822")) - ("rfc-*822" - (viewer . view-mode) - (test . (fboundp 'view-mode)) - (type . "message/rfc-822")) - ("rfc-*822" - (viewer . fundamental-mode) - (type . "message/rfc-822"))) - ("image" - ("x-xwd" - (viewer . "xwud -in %s") - (type . "image/x-xwd") - ("compose" . "xwd -frame > %s") - (test . (eq (mm-device-type) 'x)) - ("needsx11")) - ("x11-dump" - (viewer . "xwud -in %s") - (type . "image/x-xwd") - ("compose" . "xwd -frame > %s") - (test . (eq (mm-device-type) 'x)) - ("needsx11")) - ("windowdump" - (viewer . "xwud -in %s") - (type . "image/x-xwd") - ("compose" . "xwd -frame > %s") - (test . (eq (mm-device-type) 'x)) - ("needsx11")) - (".*" - (viewer . "aopen %s") - (type . "image/*") - (test . (eq (mm-device-type) 'ns))) - (".*" - (viewer . "xv -perfect %s") - (type . "image/*") - (test . (eq (mm-device-type) 'x)) - ("needsx11"))) - ("text" - ("plain" - (viewer . w3-mode) - (test . (fboundp 'w3-mode)) - (type . "text/plain")) - ("plain" - (viewer . view-mode) - (test . (fboundp 'view-mode)) - (type . "text/plain")) - ("plain" - (viewer . fundamental-mode) - (type . "text/plain")) - ("enriched" - (viewer . enriched-decode-region) - (test . (fboundp 'enriched-decode)) - (type . "text/enriched")) - ("html" - (viewer . mm-w3-prepare-buffer) - (test . (fboundp 'w3-prepare-buffer)) - (type . "text/html"))) - ("video" - ("mpeg" - (viewer . "mpeg_play %s") - (type . "video/mpeg") - (test . (eq (mm-device-type) 'x)) - ("needsx11"))) - ("x-world" - ("x-vrml" - (viewer . "webspace -remote %s -URL %u") - (type . "x-world/x-vrml") - ("description" - "VRML document"))) - ("archive" - ("tar" - (viewer . tar-mode) - (type . "archive/tar") - (test . (fboundp 'tar-mode))))) - "The mailcap structure is an assoc list of assoc lists. -1st assoc list is keyed on the major content-type -2nd assoc list is keyed on the minor content-type (which can be a regexp) - -Which looks like: ------------------ - ((\"application\" - (\"postscript\" . )) - (\"text\" - (\"plain\" . ))) - -Where is another assoc list of the various information -related to the mailcap RFC. This is keyed on the lowercase -attribute name (viewer, test, etc). This looks like: - ((viewer . viewerinfo) - (test . testinfo) - (xxxx . \"string\")) - -Where viewerinfo specifies how the content-type is viewed. Can be -a string, in which case it is run through a shell, with -appropriate parameters, or a symbol, in which case the symbol is -funcall'd, with the buffer as an argument. - -testinfo is a list of strings, or nil. If nil, it means the -viewer specified is always valid. If it is a list of strings, -these are used to determine whether a viewer passes the 'test' or -not.") - -(defvar mailcap-download-directory nil - "*Where downloaded files should go by default.") - -(defvar mailcap-temporary-directory (or (getenv "TMPDIR") "/tmp") - "*Where temporary files go.") - -;;; -;;; Utility functions -;;; - -(defun mailcap-generate-unique-filename (&optional fmt) - "Generate a unique filename in mailcap-temporary-directory" - (if (not fmt) - (let ((base (format "mailcap-tmp.%d" (user-real-uid))) - (fname "") - (x 0)) - (setq fname (format "%s%d" base x)) - (while (file-exists-p - (expand-file-name fname mailcap-temporary-directory)) - (setq x (1+ x) - fname (concat base (int-to-string x)))) - (expand-file-name fname mailcap-temporary-directory)) - (let ((base (concat "mm" (int-to-string (user-real-uid)))) - (fname "") - (x 0)) - (setq fname (format fmt (concat base (int-to-string x)))) - (while (file-exists-p - (expand-file-name fname mailcap-temporary-directory)) - (setq x (1+ x) - fname (format fmt (concat base (int-to-string x))))) - (expand-file-name fname mailcap-temporary-directory)))) - -(defun mailcap-save-binary-file () - (goto-char (point-min)) - (unwind-protect - (let ((file (read-file-name - "Filename to save as: " - (or mailcap-download-directory "~/"))) - (require-final-newline nil)) - (write-region (point-min) (point-max) file)) - (kill-buffer (current-buffer)))) - -(defun mailcap-maybe-eval () - "Maybe evaluate a buffer of emacs lisp code" - (if (yes-or-no-p "This is emacs-lisp code, evaluate it? ") - (eval-buffer (current-buffer)) - (emacs-lisp-mode))) - -;;; -;;; The mailcap parser -;;; - -(defun mailcap-replace-regexp (regexp to-string) - ;; Quiet replace-regexp. - (goto-char (point-min)) - (while (re-search-forward regexp nil t) - (replace-match to-string t nil))) - -(defvar mailcap-parsed-p nil) - -(defun mailcap-parse-mailcaps (&optional path force) - "Parse out all the mailcaps specified in a unix-style path string PATH. -If FORCE, re-parse even if already parsed." - (interactive (list nil t)) - (when (or (not mailcap-parsed-p) - force) - (cond - (path nil) - ((getenv "MAILCAPS") (setq path (getenv "MAILCAPS"))) - ((memq system-type '(ms-dos ms-windows windows-nt)) - (setq path (mapconcat 'expand-file-name '("~/mail.cap" "~/etc/mail.cap") - ";"))) - (t (setq path (mapconcat 'expand-file-name - '("~/.mailcap" - "/etc/mailcap:/usr/etc/mailcap" - "/usr/local/etc/mailcap") ":")))) - (let ((fnames (reverse - (split-string - path (if (memq system-type - '(ms-dos ms-windows windows-nt)) - ";" - ":")))) - fname) - (while fnames - (setq fname (car fnames)) - (if (and (file-exists-p fname) (file-readable-p fname) - (file-regular-p fname)) - (mailcap-parse-mailcap (car fnames))) - (setq fnames (cdr fnames)))) - (setq mailcap-parsed-p t))) - -(defun mailcap-parse-mailcap (fname) - ;; Parse out the mailcap file specified by FNAME - (let (major ; The major mime type (image/audio/etc) - minor ; The minor mime type (gif, basic, etc) - save-pos ; Misc saved positions used in parsing - viewer ; How to view this mime type - info ; Misc info about this mime type - ) - (with-temp-buffer - (insert-file-contents fname) - (set-syntax-table mailcap-parse-args-syntax-table) - (mailcap-replace-regexp "#.*" "") ; Remove all comments - (mailcap-replace-regexp "\n+" "\n") ; And blank lines - (mailcap-replace-regexp "\\\\[ \t\n]+" " ") ; And collapse spaces - (mailcap-replace-regexp (concat (regexp-quote "\\") "[ \t]*\n") "") - (goto-char (point-max)) - (skip-chars-backward " \t\n") - (delete-region (point) (point-max)) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward " \t\n") - (setq save-pos (point) - info nil) - (skip-chars-forward "^/;") - (downcase-region save-pos (point)) - (setq major (buffer-substring save-pos (point))) - (skip-chars-forward "/ \t\n") - (setq save-pos (point)) - (skip-chars-forward "^;") - (downcase-region save-pos (point)) - (setq minor - (cond - ((eq ?* (or (char-after save-pos) 0)) ".*") - ((= (point) save-pos) ".*") - (t (buffer-substring save-pos (point))))) - (skip-chars-forward "; \t\n") - ;;; Got the major/minor chunks, now for the viewers/etc - ;;; The first item _must_ be a viewer, according to the - ;;; RFC for mailcap files (#1343) - (skip-chars-forward "; \t\n") - (setq save-pos (point)) - (skip-chars-forward "^;\n") - (if (eq (or (char-after save-pos) 0) ?') - (setq viewer (progn - (narrow-to-region (1+ save-pos) (point)) - (goto-char (point-min)) - (prog1 - (read (current-buffer)) - (goto-char (point-max)) - (widen)))) - (setq viewer (buffer-substring save-pos (point)))) - (setq save-pos (point)) - (end-of-line) - (setq info (nconc (list (cons 'viewer viewer) - (cons 'type (concat major "/" - (if (string= minor ".*") - "*" minor)))) - (mailcap-parse-mailcap-extras save-pos (point)))) - (mailcap-mailcap-entry-passes-test info) - (mailcap-add-mailcap-entry major minor info))))) - -(defun mailcap-parse-mailcap-extras (st nd) - ;; Grab all the extra stuff from a mailcap entry - (let ( - name ; From name= - value ; its value - results ; Assoc list of results - name-pos ; Start of XXXX= position - val-pos ; Start of value position - done ; Found end of \'d ;s? - ) - (save-restriction - (narrow-to-region st nd) - (goto-char (point-min)) - (skip-chars-forward " \n\t;") - (while (not (eobp)) - (setq done nil) - (skip-chars-forward " \";\n\t") - (setq name-pos (point)) - (skip-chars-forward "^ \n\t=") - (downcase-region name-pos (point)) - (setq name (buffer-substring name-pos (point))) - (skip-chars-forward " \t\n") - (if (not (eq (char-after (point)) ?=)) ; There is no value - (setq value nil) - (skip-chars-forward " \t\n=") - (setq val-pos (point)) - (if (memq (char-after val-pos) '(?\" ?')) - (progn - (setq val-pos (1+ val-pos)) - (condition-case nil - (progn - (forward-sexp 1) - (backward-char 1)) - (error (goto-char (point-max))))) - (while (not done) - (skip-chars-forward "^;") - (if (eq (char-after (1- (point))) ?\\ ) - (progn - (subst-char-in-region (1- (point)) (point) ?\\ ? ) - (skip-chars-forward ";")) - (setq done t)))) - (setq value (buffer-substring val-pos (point)))) - (setq results (cons (cons name value) results))) - results))) - -(defun mailcap-mailcap-entry-passes-test (info) - ;; Return t iff a mailcap entry passes its test clause or no test - ;; clause is present. - (let (status ; Call-process-regions return value - (test (assq 'test info)) ; The test clause - ) - (setq status (and test (split-string (cdr test) " "))) - (if (and (or (assoc "needsterm" info) - (assoc "needsx11" info)) - (not (getenv "DISPLAY"))) - (setq status nil) - (cond - ((and (equal (nth 0 status) "test") - (equal (nth 1 status) "-n") - (or (equal (nth 2 status) "$DISPLAY") - (equal (nth 2 status) "\"$DISPLAY\""))) - (setq status (if (getenv "DISPLAY") t nil))) - ((and (equal (nth 0 status) "test") - (equal (nth 1 status) "-z") - (or (equal (nth 2 status) "$DISPLAY") - (equal (nth 2 status) "\"$DISPLAY\""))) - (setq status (if (getenv "DISPLAY") nil t))) - (test nil) - (t nil))) - (and test (listp test) (setcdr test status)))) - -;;; -;;; The action routines. -;;; - -(defun mailcap-possible-viewers (major minor) - ;; Return a list of possible viewers from MAJOR for minor type MINOR - (let ((exact '()) - (wildcard '())) - (while major - (cond - ((equal (car (car major)) minor) - (setq exact (cons (cdr (car major)) exact))) - ((and minor (string-match (car (car major)) minor)) - (setq wildcard (cons (cdr (car major)) wildcard)))) - (setq major (cdr major))) - (nconc (nreverse exact) (nreverse wildcard)))) - -(defun mailcap-unescape-mime-test (test type-info) - (let (save-pos save-chr subst) - (cond - ((symbolp test) test) - ((and (listp test) (symbolp (car test))) test) - ((or (stringp test) - (and (listp test) (stringp (car test)) - (setq test (mapconcat 'identity test " ")))) - (with-temp-buffer - (insert test) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward "^%") - (if (/= (- (point) - (progn (skip-chars-backward "\\\\") - (point))) - 0) ; It is an escaped % - (progn - (delete-char 1) - (skip-chars-forward "%.")) - (setq save-pos (point)) - (skip-chars-forward "%") - (setq save-chr (char-after (point))) - (cond - ((null save-chr) nil) - ((= save-chr ?t) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert (or (cdr (assq 'type type-info)) "\"\""))) - ((= save-chr ?M) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert "\"\"")) - ((= save-chr ?n) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert "\"\"")) - ((= save-chr ?F) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert "\"\"")) - ((= save-chr ?{) - (forward-char 1) - (skip-chars-forward "^}") - (downcase-region (+ 2 save-pos) (point)) - (setq subst (buffer-substring (+ 2 save-pos) (point))) - (delete-region save-pos (1+ (point))) - (insert (or (cdr (assoc subst type-info)) "\"\""))) - (t nil)))) - (buffer-string))) - (t (error "Bad value to mailcap-unescape-mime-test. %s" test))))) - -(defvar mailcap-viewer-test-cache nil) - -(defun mailcap-viewer-passes-test (viewer-info type-info) - ;; Return non-nil iff the viewer specified by VIEWER-INFO passes its - ;; test clause (if any). - (let* ((test-info (assq 'test viewer-info)) - (test (cdr test-info)) - (otest test) - (viewer (cdr (assoc 'viewer viewer-info))) - (default-directory (expand-file-name "~/")) - status parsed-test cache result) - (if (setq cache (assoc test mailcap-viewer-test-cache)) - (cadr cache) - (setq - result - (cond - ((not test-info) t) ; No test clause - ((not test) nil) ; Already failed test - ((eq test t) t) ; Already passed test - ((and (symbolp test) ; Lisp function as test - (fboundp test)) - (funcall test type-info)) - ((and (symbolp test) ; Lisp variable as test - (boundp test)) - (symbol-value test)) - ((and (listp test) ; List to be eval'd - (symbolp (car test))) - (eval test)) - (t - (setq test (mailcap-unescape-mime-test test type-info) - test (list shell-file-name nil nil nil - shell-command-switch test) - status (apply 'call-process test)) - (= 0 status)))) - (push (list otest result) mailcap-viewer-test-cache) - result))) - -(defun mailcap-add-mailcap-entry (major minor info) - (let ((old-major (assoc major mailcap-mime-data))) - (if (null old-major) ; New major area - (setq mailcap-mime-data - (cons (cons major (list (cons minor info))) - mailcap-mime-data)) - (let ((cur-minor (assoc minor old-major))) - (cond - ((or (null cur-minor) ; New minor area, or - (assq 'test info)) ; Has a test, insert at beginning - (setcdr old-major (cons (cons minor info) (cdr old-major)))) - ((and (not (assq 'test info)) ; No test info, replace completely - (not (assq 'test cur-minor))) - (setcdr cur-minor info)) - (t - (setcdr old-major (cons (cons minor info) (cdr old-major))))))))) - -;;; -;;; The main whabbo -;;; - -(defun mailcap-viewer-lessp (x y) - ;; Return t iff viewer X is more desirable than viewer Y - (let ((x-wild (string-match "[*?]" (or (cdr-safe (assq 'type x)) ""))) - (y-wild (string-match "[*?]" (or (cdr-safe (assq 'type y)) ""))) - (x-lisp (not (stringp (or (cdr-safe (assq 'viewer x)) "")))) - (y-lisp (not (stringp (or (cdr-safe (assq 'viewer y)) ""))))) - (cond - ((and x-lisp (not y-lisp)) - t) - ((and (not y-lisp) x-wild (not y-wild)) - t) - ((and (not x-wild) y-wild) - t) - (t nil)))) - -(defun mailcap-mime-info (string &optional request) - "Get the MIME viewer command for STRING, return nil if none found. -Expects a complete content-type header line as its argument. - -Second argument REQUEST specifies what information to return. If it is -nil or the empty string, the viewer (second field of the mailcap -entry) will be returned. If it is a string, then the mailcap field -corresponding to that string will be returned (print, description, -whatever). If a number, then all the information for this specific -viewer is returned. If `all', then all possible viewers for -this type is returned." - (let ( - major ; Major encoding (text, etc) - minor ; Minor encoding (html, etc) - info ; Other info - save-pos ; Misc. position during parse - major-info ; (assoc major mailcap-mime-data) - minor-info ; (assoc minor major-info) - test ; current test proc. - viewers ; Possible viewers - passed ; Viewers that passed the test - viewer ; The one and only viewer - ctl) - (save-excursion - (setq ctl (mail-header-parse-content-type (or string "text/plain"))) - (setq major (split-string (car ctl) "/")) - (setq minor (cadr major) - major (car major)) - (when (setq major-info (cdr (assoc major mailcap-mime-data))) - (when (setq viewers (mailcap-possible-viewers major-info minor)) - (setq info (mapcar (lambda (a) (cons (symbol-name (car a)) - (cdr a))) - (cdr ctl))) - (while viewers - (if (mailcap-viewer-passes-test (car viewers) info) - (setq passed (cons (car viewers) passed))) - (setq viewers (cdr viewers))) - (setq passed (sort (nreverse passed) 'mailcap-viewer-lessp)) - (setq viewer (car passed)))) - (when (and (stringp (cdr (assq 'viewer viewer))) - passed) - (setq viewer (car passed))) - (cond - ((and (null viewer) (not (equal major "default")) request) - (mailcap-mime-info "default" request)) - ((or (null request) (equal request "")) - (mailcap-unescape-mime-test (cdr (assq 'viewer viewer)) info)) - ((stringp request) - (if (or (eq request 'test) (eq request 'viewer)) - (mailcap-unescape-mime-test - (cdr-safe (assoc request viewer)) info))) - ((eq request 'all) - passed) - (t - ;; MUST make a copy *sigh*, else we modify mailcap-mime-data - (setq viewer (copy-tree viewer)) - (let ((view (assq 'viewer viewer)) - (test (assq 'test viewer))) - (if view (setcdr view (mailcap-unescape-mime-test (cdr view) info))) - (if test (setcdr test (mailcap-unescape-mime-test (cdr test) info)))) - viewer))))) - -;;; -;;; Experimental MIME-types parsing -;;; - -(defvar mailcap-mime-extensions - '(("" . "text/plain") - (".abs" . "audio/x-mpeg") - (".aif" . "audio/aiff") - (".aifc" . "audio/aiff") - (".aiff" . "audio/aiff") - (".ano" . "application/x-annotator") - (".au" . "audio/ulaw") - (".avi" . "video/x-msvideo") - (".bcpio" . "application/x-bcpio") - (".bin" . "application/octet-stream") - (".cdf" . "application/x-netcdr") - (".cpio" . "application/x-cpio") - (".csh" . "application/x-csh") - (".dvi" . "application/x-dvi") - (".el" . "application/emacs-lisp") - (".eps" . "application/postscript") - (".etx" . "text/x-setext") - (".exe" . "application/octet-stream") - (".fax" . "image/x-fax") - (".gif" . "image/gif") - (".hdf" . "application/x-hdf") - (".hqx" . "application/mac-binhex40") - (".htm" . "text/html") - (".html" . "text/html") - (".icon" . "image/x-icon") - (".ief" . "image/ief") - (".jpg" . "image/jpeg") - (".macp" . "image/x-macpaint") - (".man" . "application/x-troff-man") - (".me" . "application/x-troff-me") - (".mif" . "application/mif") - (".mov" . "video/quicktime") - (".movie" . "video/x-sgi-movie") - (".mp2" . "audio/x-mpeg") - (".mp3" . "audio/x-mpeg") - (".mp2a" . "audio/x-mpeg2") - (".mpa" . "audio/x-mpeg") - (".mpa2" . "audio/x-mpeg2") - (".mpe" . "video/mpeg") - (".mpeg" . "video/mpeg") - (".mpega" . "audio/x-mpeg") - (".mpegv" . "video/mpeg") - (".mpg" . "video/mpeg") - (".mpv" . "video/mpeg") - (".ms" . "application/x-troff-ms") - (".nc" . "application/x-netcdf") - (".nc" . "application/x-netcdf") - (".oda" . "application/oda") - (".pbm" . "image/x-portable-bitmap") - (".pdf" . "application/pdf") - (".pgm" . "image/portable-graymap") - (".pict" . "image/pict") - (".png" . "image/png") - (".pnm" . "image/x-portable-anymap") - (".ppm" . "image/portable-pixmap") - (".ps" . "application/postscript") - (".qt" . "video/quicktime") - (".ras" . "image/x-raster") - (".rgb" . "image/x-rgb") - (".rtf" . "application/rtf") - (".rtx" . "text/richtext") - (".sh" . "application/x-sh") - (".sit" . "application/x-stuffit") - (".snd" . "audio/basic") - (".src" . "application/x-wais-source") - (".tar" . "archive/tar") - (".tcl" . "application/x-tcl") - (".tcl" . "application/x-tcl") - (".tex" . "application/x-tex") - (".texi" . "application/texinfo") - (".tga" . "image/x-targa") - (".tif" . "image/tiff") - (".tiff" . "image/tiff") - (".tr" . "application/x-troff") - (".troff" . "application/x-troff") - (".tsv" . "text/tab-separated-values") - (".txt" . "text/plain") - (".vbs" . "video/mpeg") - (".vox" . "audio/basic") - (".vrml" . "x-world/x-vrml") - (".wav" . "audio/x-wav") - (".wrl" . "x-world/x-vrml") - (".xbm" . "image/xbm") - (".xpm" . "image/xpm") - (".xwd" . "image/windowdump") - (".zip" . "application/zip") - (".ai" . "application/postscript") - (".jpe" . "image/jpeg") - (".jpeg" . "image/jpeg")) - "An assoc list of file extensions and corresponding MIME content-types.") - -(defun mailcap-parse-mimetypes (&optional path) - ;; Parse out all the mimetypes specified in a unix-style path string PATH - (cond - (path nil) - ((getenv "MIMETYPES") (setq path (getenv "MIMETYPES"))) - ((memq system-type '(ms-dos ms-windows windows-nt)) - (setq path (mapconcat 'expand-file-name - '("~/mime.typ" "~/etc/mime.typ") ";"))) - (t (setq path (mapconcat 'expand-file-name - '("~/.mime-types" - "/etc/mime-types:/usr/etc/mime-types" - "/usr/local/etc/mime-types" - "/usr/local/www/conf/mime-types") ":")))) - (let ((fnames (reverse - (split-string path - (if (memq system-type - '(ms-dos ms-windows windows-nt)) - ";" ":")))) - fname) - (while fnames - (setq fname (car fnames)) - (if (and (file-exists-p fname) (file-readable-p fname)) - (mailcap-parse-mimetype-file (car fnames))) - (setq fnames (cdr fnames))))) - -(defun mailcap-parse-mimetype-file (fname) - ;; Parse out a mime-types file - (let (type ; The MIME type for this line - extns ; The extensions for this line - save-pos ; Misc. saved buffer positions - ) - (with-temp-buffer - (insert-file-contents fname) - (mailcap-replace-regexp "#.*" "") - (mailcap-replace-regexp "\n+" "\n") - (mailcap-replace-regexp "[ \t]+$" "") - (goto-char (point-max)) - (skip-chars-backward " \t\n") - (delete-region (point) (point-max)) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward " \t\n") - (setq save-pos (point)) - (skip-chars-forward "^ \t") - (downcase-region save-pos (point)) - (setq type (buffer-substring save-pos (point))) - (while (not (eolp)) - (skip-chars-forward " \t") - (setq save-pos (point)) - (skip-chars-forward "^ \t\n") - (setq extns (cons (buffer-substring save-pos (point)) extns))) - (while extns - (setq mailcap-mime-extensions - (cons - (cons (if (= (string-to-char (car extns)) ?.) - (car extns) - (concat "." (car extns))) type) - mailcap-mime-extensions) - extns (cdr extns))))))) - -(defun mailcap-extension-to-mime (extn) - "Return the MIME content type of the file extensions EXTN." - (if (and (stringp extn) - (not (eq (string-to-char extn) ?.))) - (setq extn (concat "." extn))) - (cdr (assoc (downcase extn) mailcap-mime-extensions))) - -(defvar mailcap-binary-suffixes - (if (memq system-type '(ms-dos windows-nt)) - '(".exe" ".com" ".bat" ".cmd" ".btm" "") - '(""))) - -(defun mailcap-command-p (command) - "Say whether COMMAND is in the exec path. -The path of COMMAND will be returned iff COMMAND is a command." - (let ((path (if (file-name-absolute-p command) '(nil) exec-path)) - file dir) - (catch 'found - (while (setq dir (pop path)) - (let ((suffixes mailcap-binary-suffixes)) - (while suffixes - (when (and (file-executable-p - (setq file (expand-file-name - (concat command (pop suffixes)) - dir))) - (not (file-directory-p file))) - (throw 'found file)))))))) - -(provide 'mailcap) - -;;; mailcap.el ends here diff --git a/lisp/mm.el b/lisp/mm.el deleted file mode 100644 index 1b57cb1..0000000 --- a/lisp/mm.el +++ /dev/null @@ -1,1283 +0,0 @@ -;;; mm.el,v --- Mailcap parsing routines, and MIME handling -;; Author: wmperry -;; Created: 1996/05/28 02:46:51 -;; Version: 1.96 -;; Keywords: mail, news, hypermedia - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Copyright (c) 1994, 1995, 1996 by William M. Perry -;;; Copyright (c) 1996 - 1998 Free Software Foundation, Inc. -;;; -;;; This file is not part of GNU Emacs, but the same permissions apply. -;;; -;;; 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. -;;; -;;; GNU Emacs is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;;; 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., 59 Temple Place - Suite 330, -;;; Boston, MA 02111-1307, USA. -;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Generalized mailcap parsing and access routines -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; -;;; Data structures -;;; --------------- -;;; The mailcap structure is an assoc list of assoc lists. -;;; 1st assoc list is keyed on the major content-type -;;; 2nd assoc list is keyed on the minor content-type (which can be a regexp) -;;; -;;; Which looks like: -;;; ----------------- -;;; ( -;;; ("application" -;;; ("postscript" . ) -;;; ) -;;; ("text" -;;; ("plain" . ) -;;; ) -;;; ) -;;; -;;; Where is another assoc list of the various information -;;; related to the mailcap RFC. This is keyed on the lowercase -;;; attribute name (viewer, test, etc). This looks like: -;;; (("viewer" . viewerinfo) -;;; ("test" . testinfo) -;;; ("xxxx" . "string") -;;; ) -;;; -;;; Where viewerinfo specifies how the content-type is viewed. Can be -;;; a string, in which case it is run through a shell, with -;;; appropriate parameters, or a symbol, in which case the symbol is -;;; funcall'd, with the buffer as an argument. -;;; -;;; testinfo is a list of strings, or nil. If nil, it means the -;;; viewer specified is always valid. If it is a list of strings, -;;; these are used to determine whether a viewer passes the 'test' or -;;; not. -;;; -;;; The main interface to this code is: -;;; -;;; To set everything up: -;;; -;;; (mm-parse-mailcaps [path]) -;;; -;;; Where PATH is a unix-style path specification (: separated list -;;; of strings). If PATH is nil, the environment variable MAILCAPS -;;; will be consulted. If there is no environment variable, then a -;;; default list of paths is used. -;;; -;;; To retrieve the information: -;;; (mm-mime-info st [nd] [request]) -;;; -;;; Where st and nd are positions in a buffer that contain the -;;; content-type header information of a mail/news/whatever message. -;;; st can optionally be a string that contains the content-type -;;; information. -;;; -;;; Third argument REQUEST specifies what information to return. If -;;; it is nil or the empty string, the viewer (second field of the -;;; mailcap entry) will be returned. If it is a string, then the -;;; mailcap field corresponding to that string will be returned -;;; (print, description, whatever). If a number, then all the -;;; information for this specific viewer is returned. -;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Variables, etc -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(eval-and-compile - (require 'cl) -;LMI was here - ;;(require 'devices) - ) - -(defconst mm-version (let ((x "1.96")) - (if (string-match "Revision: \\([^ \t\n]+\\)" x) - (substring x (match-beginning 1) (match-end 1)) - x)) - "Version # of MM package") - -(defvar mm-parse-args-syntax-table - (copy-syntax-table emacs-lisp-mode-syntax-table) - "A syntax table for parsing sgml attributes.") - -(modify-syntax-entry ?' "\"" mm-parse-args-syntax-table) -(modify-syntax-entry ?` "\"" mm-parse-args-syntax-table) -(modify-syntax-entry ?{ "(" mm-parse-args-syntax-table) -(modify-syntax-entry ?} ")" mm-parse-args-syntax-table) - -(defvar mm-mime-data - '( - ("multipart" . ( - ("alternative". (("viewer" . mm-multipart-viewer) - ("type" . "multipart/alternative"))) - ("mixed" . (("viewer" . mm-multipart-viewer) - ("type" . "multipart/mixed"))) - (".*" . (("viewer" . mm-save-binary-file) - ("type" . "multipart/*"))) - ) - ) - ("application" . ( - ("x-x509-ca-cert" . (("viewer" . ssl-view-site-cert) - ("test" . (fboundp 'ssl-view-site-cert)) - ("type" . "application/x-x509-ca-cert"))) - ("x-x509-user-cert" . (("viewer" . ssl-view-user-cert) - ("test" . (fboundp 'ssl-view-user-cert)) - ("type" . "application/x-x509-user-cert"))) - ("octet-stream" . (("viewer" . mm-save-binary-file) - ("type" ."application/octet-stream"))) - ("dvi" . (("viewer" . "open %s") - ("type" . "application/dvi") - ("test" . (eq (device-type) 'ns)))) - ("dvi" . (("viewer" . "xdvi %s") - ("test" . (eq (device-type) 'x)) - ("needsx11") - ("type" . "application/dvi"))) - ("dvi" . (("viewer" . "dvitty %s") - ("test" . (not (getenv "DISPLAY"))) - ("type" . "application/dvi"))) - ("emacs-lisp" . (("viewer" . mm-maybe-eval) - ("type" . "application/emacs-lisp"))) -; ("x-tar" . (("viewer" . tar-mode) -; ("test" . (fboundp 'tar-mode)) -; ("type" . "application/x-tar"))) - ("x-tar" . (("viewer" . mm-save-binary-file) - ("type" . "application/x-tar"))) - ("x-latex" . (("viewer" . tex-mode) - ("test" . (fboundp 'tex-mode)) - ("type" . "application/x-latex"))) - ("x-tex" . (("viewer" . tex-mode) - ("test" . (fboundp 'tex-mode)) - ("type" . "application/x-tex"))) - ("latex" . (("viewer" . tex-mode) - ("test" . (fboundp 'tex-mode)) - ("type" . "application/latex"))) - ("tex" . (("viewer" . tex-mode) - ("test" . (fboundp 'tex-mode)) - ("type" . "application/tex"))) - ("texinfo" . (("viewer" . texinfo-mode) - ("test" . (fboundp 'texinfo-mode)) - ("type" . "application/tex"))) - ("zip" . (("viewer" . mm-save-binary-file) - ("type" . "application/zip") - ("copiousoutput"))) - ("pdf" . (("viewer" . "acroread %s") - ("type" . "application/pdf"))) - ("postscript" . (("viewer" . "open %s") - ("type" . "application/postscript") - ("test" . (eq (device-type) 'ns)))) - ("postscript" . (("viewer" . "ghostview %s") - ("type" . "application/postscript") - ("test" . (eq (device-type) 'x)) - ("needsx11"))) - ("postscript" . (("viewer" . "ps2ascii %s") - ("type" . "application/postscript") - ("test" . (not (getenv "DISPLAY"))) - ("copiousoutput"))) - )) - ("audio" . ( - ("x-mpeg" . (("viewer" . "maplay %s") - ("type" . "audio/x-mpeg"))) - (".*" . (("viewer" . mm-play-sound-file) - ("test" . (or (featurep 'nas-sound) - (featurep 'native-sound))) - ("type" . "audio/*"))) - (".*" . (("viewer" . "showaudio") - ("type" . "audio/*"))) - )) - ("message" . ( - ("rfc-*822" . (("viewer" . vm-mode) - ("test" . (fboundp 'vm-mode)) - ("type" . "message/rfc-822"))) - ("rfc-*822" . (("viewer" . w3-mode) - ("test" . (fboundp 'w3-mode)) - ("type" . "message/rfc-822"))) - ("rfc-*822" . (("viewer" . view-mode) - ("test" . (fboundp 'view-mode)) - ("type" . "message/rfc-822"))) - ("rfc-*822" . (("viewer" . fundamental-mode) - ("type" . "message/rfc-822"))) - )) - ("image" . ( - ("x-xwd" . (("viewer" . "xwud -in %s") - ("type" . "image/x-xwd") - ("compose" . "xwd -frame > %s") - ("test" . (eq (device-type) 'x)) - ("needsx11"))) - ("x11-dump" . (("viewer" . "xwud -in %s") - ("type" . "image/x-xwd") - ("compose" . "xwd -frame > %s") - ("test" . (eq (device-type) 'x)) - ("needsx11"))) - ("windowdump" . (("viewer" . "xwud -in %s") - ("type" . "image/x-xwd") - ("compose" . "xwd -frame > %s") - ("test" . (eq (device-type) 'x)) - ("needsx11"))) - (".*" . (("viewer" . "open %s") - ("type" . "image/*") - ("test" . (eq (device-type) 'ns)))) - (".*" . (("viewer" . "xv -perfect %s") - ("type" . "image/*") - ("test" . (eq (device-type) 'x)) - ("needsx11"))) - )) - ("text" . ( - ("plain" . (("viewer" . w3-mode) - ("test" . (fboundp 'w3-mode)) - ("type" . "text/plain"))) - ("plain" . (("viewer" . view-mode) - ("test" . (fboundp 'view-mode)) - ("type" . "text/plain"))) - ("plain" . (("viewer" . fundamental-mode) - ("type" . "text/plain"))) - ("enriched" . (("viewer" . enriched-decode-region) - ("test" . (fboundp - 'enriched-decode-region)) - ("type" . "text/enriched"))) - ("html" . (("viewer" . w3-prepare-buffer) - ("test" . (fboundp 'w3-prepare-buffer)) - ("type" . "text/html"))) - )) - ("video" . ( - ("mpeg" . (("viewer" . "mpeg_play %s") - ("type" . "video/mpeg") - ("test" . (eq (device-type) 'x)) - ("needsx11"))) - )) - ("x-world" . ( - ("x-vrml" . (("viewer" . "webspace -remote %s -URL %u") - ("type" . "x-world/x-vrml") - ("description" - "VRML document"))))) - ("archive" . ( - ("tar" . (("viewer" . tar-mode) - ("type" . "archive/tar") - ("test" . (fboundp 'tar-mode)))) - )) - ) - "*The mailcap structure is an assoc list of assoc lists. -1st assoc list is keyed on the major content-type -2nd assoc list is keyed on the minor content-type (which can be a regexp) - -Which looks like: ------------------ -( - (\"application\" - (\"postscript\" . ) - ) - (\"text\" - (\"plain\" . ) - ) -) - -Where is another assoc list of the various information -related to the mailcap RFC. This is keyed on the lowercase -attribute name (viewer, test, etc). This looks like: -((\"viewer\" . viewerinfo) - (\"test\" . testinfo) - (\"xxxx\" . \"string\") -) - -Where viewerinfo specifies how the content-type is viewed. Can be -a string, in which case it is run through a shell, with -appropriate parameters, or a symbol, in which case the symbol is -funcall'd, with the buffer as an argument. - -testinfo is a list of strings, or nil. If nil, it means the -viewer specified is always valid. If it is a list of strings, -these are used to determine whether a viewer passes the 'test' or -not.") - -(defvar mm-content-transfer-encodings - '(("base64" . base64-decode-region) - ("7bit" . ignore) - ("8bit" . ignore) - ("binary" . ignore) - ("x-compress" . ("uncompress" "-c")) - ("x-gzip" . ("gzip" "-dc")) - ("compress" . ("uncompress" "-c")) - ("gzip" . ("gzip" "-dc")) - ("x-hqx" . ("mcvert" "-P" "-s" "-S")) - ("quoted-printable" . mm-decode-quoted-printable) - ) - "*An assoc list of content-transfer-encodings and how to decode them.") - -(defvar mm-download-directory nil - "*Where downloaded files should go by default.") - -(defvar mm-temporary-directory (or (getenv "TMPDIR") "/tmp") - "*Where temporary files go.") - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; A few things from w3 and url, just in case this is used without them -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun mm-generate-unique-filename (&optional fmt) - "Generate a unique filename in mm-temporary-directory" - (if (not fmt) - (let ((base (format "mm-tmp.%d" (user-real-uid))) - (fname "") - (x 0)) - (setq fname (format "%s%d" base x)) - (while (file-exists-p - (expand-file-name fname mm-temporary-directory)) - (setq x (1+ x) - fname (concat base (int-to-string x)))) - (expand-file-name fname mm-temporary-directory)) - (let ((base (concat "mm" (int-to-string (user-real-uid)))) - (fname "") - (x 0)) - (setq fname (format fmt (concat base (int-to-string x)))) - (while (file-exists-p - (expand-file-name fname mm-temporary-directory)) - (setq x (1+ x) - fname (format fmt (concat base (int-to-string x))))) - (expand-file-name fname mm-temporary-directory)))) - -(if (and (fboundp 'copy-tree) - (subrp (symbol-function 'copy-tree))) - (fset 'mm-copy-tree 'copy-tree) - (defun mm-copy-tree (tree) - (if (consp tree) - (cons (mm-copy-tree (car tree)) - (mm-copy-tree (cdr tree))) - (if (vectorp tree) - (let* ((new (copy-sequence tree)) - (i (1- (length new)))) - (while (>= i 0) - (aset new i (mm-copy-tree (aref new i))) - (setq i (1- i))) - new) - tree)))) - -;LMI was here -;(require 'mule-sysdp) - -(if (not (fboundp 'w3-save-binary-file)) - (defun mm-save-binary-file () - ;; Ok, this is truly fucked. In XEmacs, if you use the mouse to select - ;; a URL that gets saved via this function, read-file-name will pop up a - ;; dialog box for file selection. For some reason which buffer we are in - ;; gets royally screwed (even with save-excursions and the whole nine - ;; yards). SO, we just keep the old buffer name around and away we go. - (let ((old-buff (current-buffer)) - (file (read-file-name "Filename to save as: " - (or mm-download-directory "~/") - (file-name-nondirectory (url-view-url t)) - nil - (file-name-nondirectory (url-view-url t)))) - (require-final-newline nil)) - (set-buffer old-buff) - (mule-write-region-no-coding-system (point-min) (point-max) file) - (kill-buffer (current-buffer)))) - (fset 'mm-save-binary-file 'w3-save-binary-file)) - -(defun mm-maybe-eval () - "Maybe evaluate a buffer of emacs lisp code" - (if (yes-or-no-p "This is emacs-lisp code, evaluate it? ") - (eval-buffer (current-buffer)) - (emacs-lisp-mode))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; The mailcap parser -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun mm-viewer-unescape (format &optional filename url) - (save-excursion - (set-buffer (get-buffer-create " *mm-parse*")) - (erase-buffer) - (insert format) - (goto-char (point-min)) - (while (re-search-forward "%\\(.\\)" nil t) - (let ((escape (aref (match-string 1) 0))) - (replace-match "" t t) - (case escape - (?% (insert "%")) - (?s (insert (or filename "\"\""))) - (?u (insert (or url "\"\"")))))) - (buffer-string))) - -(defun mm-in-assoc (elt list) - ;; Check to see if ELT matches any of the regexps in the car elements of LIST - (let (rslt) - (while (and list (not rslt)) - (and (car (car list)) - (string-match (car (car list)) elt) - (setq rslt (car list))) - (setq list (cdr list))) - rslt)) - -(defun mm-replace-regexp (regexp to-string) - ;; Quiet replace-regexp. - (goto-char (point-min)) - (while (re-search-forward regexp nil t) - (replace-match to-string t nil))) - -(defun mm-parse-mailcaps (&optional path) - ;; Parse out all the mailcaps specified in a unix-style path string PATH - (cond - (path nil) - ((getenv "MAILCAPS") (setq path (getenv "MAILCAPS"))) - ((memq system-type '(ms-dos ms-windows windows-nt)) - (setq path (mapconcat 'expand-file-name '("~/mail.cap" "~/etc/mail.cap") - ";"))) - (t (setq path (mapconcat 'expand-file-name - '("~/.mailcap" - "/etc/mailcap:/usr/etc/mailcap" - "/usr/local/etc/mailcap") ":")))) - (let ((fnames (reverse - (mm-string-to-tokens path - (if (memq system-type - '(ms-dos ms-windows windows-nt)) - ?; - ?:)))) - fname) - (while fnames - (setq fname (car fnames)) - (if (and (file-exists-p fname) (file-readable-p fname)) - (mm-parse-mailcap (car fnames))) - (setq fnames (cdr fnames))))) - -(defun mm-parse-mailcap (fname) - ;; Parse out the mailcap file specified by FNAME - (let (major ; The major mime type (image/audio/etc) - minor ; The minor mime type (gif, basic, etc) - save-pos ; Misc saved positions used in parsing - viewer ; How to view this mime type - info ; Misc info about this mime type - ) - (save-excursion - (set-buffer (get-buffer-create " *mailcap*")) - (erase-buffer) - (insert-file-contents fname) - (set-syntax-table mm-parse-args-syntax-table) - (mm-replace-regexp "#.*" "") ; Remove all comments - (mm-replace-regexp "\n+" "\n") ; And blank lines - (mm-replace-regexp "\\\\[ \t\n]+" " ") ; And collapse spaces - (mm-replace-regexp (concat (regexp-quote "\\") "[ \t]*\n") "") - (goto-char (point-max)) - (skip-chars-backward " \t\n") - (delete-region (point) (point-max)) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward " \t\n") - (setq save-pos (point) - info nil) - (skip-chars-forward "^/;") - (downcase-region save-pos (point)) - (setq major (buffer-substring save-pos (point))) - (skip-chars-forward "/ \t\n") - (setq save-pos (point)) - (skip-chars-forward "^;") - (downcase-region save-pos (point)) - (setq minor - (cond - ((= ?* (or (char-after save-pos) 0)) ".*") - ((= (point) save-pos) ".*") - (t (buffer-substring save-pos (point))))) - (skip-chars-forward "; \t\n") - ;;; Got the major/minor chunks, now for the viewers/etc - ;;; The first item _must_ be a viewer, according to the - ;;; RFC for mailcap files (#1343) - (skip-chars-forward "; \t\n") - (setq save-pos (point)) - (skip-chars-forward "^;\n") - (if (= (or (char-after save-pos) 0) ?') - (setq viewer (progn - (narrow-to-region (1+ save-pos) (point)) - (goto-char (point-min)) - (prog1 - (read (current-buffer)) - (goto-char (point-max)) - (widen)))) - (setq viewer (buffer-substring save-pos (point)))) - (setq save-pos (point)) - (end-of-line) - (setq info (nconc (list (cons "viewer" viewer) - (cons "type" (concat major "/" - (if (string= minor ".*") - "*" minor)))) - (mm-parse-mailcap-extras save-pos (point)))) - (mm-mailcap-entry-passes-test info) - (mm-add-mailcap-entry major minor info))))) - -(defun mm-parse-mailcap-extras (st nd) - ;; Grab all the extra stuff from a mailcap entry - (let ( - name ; From name= - value ; its value - results ; Assoc list of results - name-pos ; Start of XXXX= position - val-pos ; Start of value position - done ; Found end of \'d ;s? - ) - (save-restriction - (narrow-to-region st nd) - (goto-char (point-min)) - (skip-chars-forward " \n\t;") - (while (not (eobp)) - (setq done nil) - (skip-chars-forward " \";\n\t") - (setq name-pos (point)) - (skip-chars-forward "^ \n\t=") - (downcase-region name-pos (point)) - (setq name (buffer-substring name-pos (point))) - (skip-chars-forward " \t\n") - (if (/= (or (char-after (point)) 0) ?=) ; There is no value - (setq value nil) - (skip-chars-forward " \t\n=") - (setq val-pos (point)) - (if (memq (char-after val-pos) '(?\" ?')) - (progn - (setq val-pos (1+ val-pos)) - (condition-case nil - (progn - (forward-sexp 1) - (backward-char 1)) - (error (goto-char (point-max))))) - (while (not done) - (skip-chars-forward "^;") - (if (= (or (char-after (1- (point))) 0) ?\\ ) - (progn - (subst-char-in-region (1- (point)) (point) ?\\ ? ) - (skip-chars-forward ";")) - (setq done t)))) - (setq value (buffer-substring val-pos (point)))) - (setq results (cons (cons name value) results))) - results))) - -(defun mm-string-to-tokens (str &optional delim) - "Return a list of words from the string STR" - (setq delim (or delim ? )) - (let (results y) - (mapcar - (function - (lambda (x) - (cond - ((and (= x delim) y) (setq results (cons y results) y nil)) - ((/= x delim) (setq y (concat y (char-to-string x)))) - (t nil)))) str) - (nreverse (cons y results)))) - -(defun mm-mailcap-entry-passes-test (info) - ;; Return t iff a mailcap entry passes its test clause or no test - ;; clause is present. - (let (status ; Call-process-regions return value - (test (assoc "test" info)); The test clause - ) - (setq status (and test (mm-string-to-tokens (cdr test)))) - (if (and (assoc "needsx11" info) (not (getenv "DISPLAY"))) - (setq status nil) - (cond - ((and (equal (nth 0 status) "test") - (equal (nth 1 status) "-n") - (or (equal (nth 2 status) "$DISPLAY") - (equal (nth 2 status) "\"$DISPLAY\""))) - (setq status (if (getenv "DISPLAY") t nil))) - ((and (equal (nth 0 status) "test") - (equal (nth 1 status) "-z") - (or (equal (nth 2 status) "$DISPLAY") - (equal (nth 2 status) "\"$DISPLAY\""))) - (setq status (if (getenv "DISPLAY") nil t))) - (test nil) - (t nil))) - (and test (listp test) (setcdr test status)))) - -(defun mm-parse-args (st &optional nd nodowncase) - ;; Return an assoc list of attribute/value pairs from an RFC822-type string - (let ( - name ; From name= - value ; its value - results ; Assoc list of results - name-pos ; Start of XXXX= position - val-pos ; Start of value position - ) - (save-excursion - (if (stringp st) - (progn - (set-buffer (get-buffer-create " *mm-temp*")) - (set-syntax-table mm-parse-args-syntax-table) - (erase-buffer) - (insert st) - (setq st (point-min) - nd (point-max))) - (set-syntax-table mm-parse-args-syntax-table)) - (save-restriction - (narrow-to-region st nd) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward "; \n\t") - (setq name-pos (point)) - (skip-chars-forward "^ \n\t=;") - (if (not nodowncase) - (downcase-region name-pos (point))) - (setq name (buffer-substring name-pos (point))) - (skip-chars-forward " \t\n") - (if (/= (or (char-after (point)) 0) ?=) ; There is no value - (setq value nil) - (skip-chars-forward " \t\n=") - (setq val-pos (point) - value - (cond - ((or (= (or (char-after val-pos) 0) ?\") - (= (or (char-after val-pos) 0) ?')) - (buffer-substring (1+ val-pos) - (condition-case () - (prog2 - (forward-sexp 1) - (1- (point)) - (skip-chars-forward "\"")) - (error - (skip-chars-forward "^ \t\n") - (point))))) - (t - (buffer-substring val-pos - (progn - (skip-chars-forward "^;") - (skip-chars-backward " \t") - (point))))))) - (setq results (cons (cons name value) results)) - (skip-chars-forward "; \n\t")) - results)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; The action routines. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun mm-possible-viewers (major minor) - ;; Return a list of possible viewers from MAJOR for minor type MINOR - (let ((exact '()) - (wildcard '())) - (while major - (cond - ((equal (car (car major)) minor) - (setq exact (cons (cdr (car major)) exact))) - ((string-match (car (car major)) minor) - (setq wildcard (cons (cdr (car major)) wildcard)))) - (setq major (cdr major))) - (nconc (nreverse exact) (nreverse wildcard)))) - -(defun mm-unescape-mime-test (test type-info) - (let ((buff (get-buffer-create " *unescape*")) - save-pos save-chr subst) - (cond - ((symbolp test) test) - ((and (listp test) (symbolp (car test))) test) - ((or (stringp test) - (and (listp test) (stringp (car test)) - (setq test (mapconcat 'identity test " ")))) - (save-excursion - (set-buffer buff) - (erase-buffer) - (insert test) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward "^%") - (if (/= (- (point) - (progn (skip-chars-backward "\\\\") - (point))) - 0) ; It is an escaped % - (progn - (delete-char 1) - (skip-chars-forward "%.")) - (setq save-pos (point)) - (skip-chars-forward "%") - (setq save-chr (char-after (point))) - (cond - ((null save-chr) nil) - ((= save-chr ?t) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert (or (cdr (assoc "type" type-info)) "\"\""))) - ((= save-chr ?M) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert "\"\"")) - ((= save-chr ?n) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert "\"\"")) - ((= save-chr ?F) - (delete-region save-pos (progn (forward-char 1) (point))) - (insert "\"\"")) - ((= save-chr ?{) - (forward-char 1) - (skip-chars-forward "^}") - (downcase-region (+ 2 save-pos) (point)) - (setq subst (buffer-substring (+ 2 save-pos) (point))) - (delete-region save-pos (1+ (point))) - (insert (or (cdr (assoc subst type-info)) "\"\""))) - (t nil)))) - (buffer-string))) - (t (error "Bad value to mm-unescape-mime-test. %s" test))))) - -(defun mm-viewer-passes-test (viewer-info type-info) - ;; Return non-nil iff the viewer specified by VIEWER-INFO passes its - ;; test clause (if any). - (let* ((test-info (assoc "test" viewer-info)) - (test (cdr test-info)) - (viewer (cdr (assoc "viewer" viewer-info))) - (default-directory (expand-file-name "~/")) - status - parsed-test - ) - (cond - ((not test-info) t) ; No test clause - ((not test) nil) ; Already failed test - ((eq test t) t) ; Already passed test - ((and (symbolp test) ; Lisp function as test - (fboundp test)) - (funcall test type-info)) - ((and (symbolp test) ; Lisp variable as test - (boundp test)) - (symbol-value test)) - ((and (listp test) ; List to be eval'd - (symbolp (car test))) - (eval test)) - (t - (setq test (mm-unescape-mime-test test type-info) - test (list shell-file-name nil nil nil shell-command-switch test) - status (apply 'call-process test)) - (= 0 status))))) - -(defun mm-add-mailcap-entry (major minor info) - (let ((old-major (assoc major mm-mime-data))) - (if (null old-major) ; New major area - (setq mm-mime-data - (cons (cons major (list (cons minor info))) - mm-mime-data)) - (let ((cur-minor (assoc minor old-major))) - (cond - ((or (null cur-minor) ; New minor area, or - (assoc "test" info)) ; Has a test, insert at beginning - (setcdr old-major (cons (cons minor info) (cdr old-major)))) - ((and (not (assoc "test" info)); No test info, replace completely - (not (assoc "test" cur-minor))) - (setcdr cur-minor info)) - (t - (setcdr old-major (cons (cons minor info) (cdr old-major))))))))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; The main whabbo -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun mm-viewer-lessp (x y) - ;; Return t iff viewer X is more desirable than viewer Y - (let ((x-wild (string-match "[*?]" (or (cdr-safe (assoc "type" x)) ""))) - (y-wild (string-match "[*?]" (or (cdr-safe (assoc "type" y)) ""))) - (x-lisp (not (stringp (or (cdr-safe (assoc "viewer" x)) "")))) - (y-lisp (not (stringp (or (cdr-safe (assoc "viewer" y)) ""))))) - (cond - ((and x-lisp (not y-lisp)) - t) - ((and (not y-lisp) x-wild (not y-wild)) - t) - ((and (not x-wild) y-wild) - t) - (t nil)))) - -(defun mm-mime-info (st &optional nd request) - "Get the mime viewer command for HEADERLINE, return nil if none found. -Expects a complete content-type header line as its argument. This can -be simple like text/html, or complex like text/plain; charset=blah; foo=bar - -Third argument REQUEST specifies what information to return. If it is -nil or the empty string, the viewer (second field of the mailcap -entry) will be returned. If it is a string, then the mailcap field -corresponding to that string will be returned (print, description, -whatever). If a number, then all the information for this specific -viewer is returned." - (let ( - major ; Major encoding (text, etc) - minor ; Minor encoding (html, etc) - info ; Other info - save-pos ; Misc. position during parse - major-info ; (assoc major mm-mime-data) - minor-info ; (assoc minor major-info) - test ; current test proc. - viewers ; Possible viewers - passed ; Viewers that passed the test - viewer ; The one and only viewer - ) - (save-excursion - (cond - ((null st) - (set-buffer (get-buffer-create " *mimeparse*")) - (erase-buffer) - (insert "text/plain") - (setq st (point-min))) - ((stringp st) - (set-buffer (get-buffer-create " *mimeparse*")) - (erase-buffer) - (insert st) - (setq st (point-min))) - ((null nd) - (narrow-to-region st (progn (goto-char st) (end-of-line) (point)))) - (t (narrow-to-region st nd))) - (goto-char st) - (skip-chars-forward ": \t\n") - (buffer-enable-undo) - (setq viewer - (catch 'mm-exit - (setq save-pos (point)) - (skip-chars-forward "^/") - (downcase-region save-pos (point)) - (setq major (buffer-substring save-pos (point))) - (if (not (setq major-info (cdr (assoc major mm-mime-data)))) - (throw 'mm-exit nil)) - (skip-chars-forward "/ \t\n") - (setq save-pos (point)) - (skip-chars-forward "^ \t\n;") - (downcase-region save-pos (point)) - (setq minor (buffer-substring save-pos (point))) - (if (not - (setq viewers (mm-possible-viewers major-info minor))) - (throw 'mm-exit nil)) - (skip-chars-forward "; \t") - (if (eolp) - nil ; No qualifiers - (setq save-pos (point)) - (end-of-line) - (setq info (mm-parse-args save-pos (point))) - ) - (while viewers - (if (mm-viewer-passes-test (car viewers) info) - (setq passed (cons (car viewers) passed))) - (setq viewers (cdr viewers))) - (setq passed (sort (nreverse passed) 'mm-viewer-lessp)) - (car passed))) - (if (and (stringp (cdr (assoc "viewer" viewer))) - passed) - (setq viewer (car passed))) - (widen) - (cond - ((and (null viewer) (not (equal major "default"))) - (mm-mime-info "default" nil request)) - ((or (null request) (equal request "")) - (mm-unescape-mime-test (cdr (assoc "viewer" viewer)) info)) - ((stringp request) - (if (or (string= request "test") (string= request "viewer")) - (mm-unescape-mime-test (cdr-safe (assoc request viewer)) info))) - (t - ;; MUST make a copy *sigh*, else we modify mm-mime-data - (setq viewer (mm-copy-tree viewer)) - (let ((view (assoc "viewer" viewer)) - (test (assoc "test" viewer))) - (if view (setcdr view (mm-unescape-mime-test (cdr view) info))) - (if test (setcdr test (mm-unescape-mime-test (cdr test) info)))) - viewer))))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Experimental MIME-types parsing -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defvar mm-mime-extensions - '( - ("" . "text/plain") - (".abs" . "audio/x-mpeg") - (".aif" . "audio/aiff") - (".aifc" . "audio/aiff") - (".aiff" . "audio/aiff") - (".ano" . "application/x-annotator") - (".au" . "audio/ulaw") - (".avi" . "video/x-msvideo") - (".bcpio" . "application/x-bcpio") - (".bin" . "application/octet-stream") - (".cdf" . "application/x-netcdr") - (".cpio" . "application/x-cpio") - (".csh" . "application/x-csh") - (".dvi" . "application/x-dvi") - (".el" . "application/emacs-lisp") - (".eps" . "application/postscript") - (".etx" . "text/x-setext") - (".exe" . "application/octet-stream") - (".fax" . "image/x-fax") - (".gif" . "image/gif") - (".hdf" . "application/x-hdf") - (".hqx" . "application/mac-binhex40") - (".htm" . "text/html") - (".html" . "text/html") - (".icon" . "image/x-icon") - (".ief" . "image/ief") - (".jpg" . "image/jpeg") - (".macp" . "image/x-macpaint") - (".man" . "application/x-troff-man") - (".me" . "application/x-troff-me") - (".mif" . "application/mif") - (".mov" . "video/quicktime") - (".movie" . "video/x-sgi-movie") - (".mp2" . "audio/x-mpeg") - (".mp2a" . "audio/x-mpeg2") - (".mpa" . "audio/x-mpeg") - (".mpa2" . "audio/x-mpeg2") - (".mpe" . "video/mpeg") - (".mpeg" . "video/mpeg") - (".mpega" . "audio/x-mpeg") - (".mpegv" . "video/mpeg") - (".mpg" . "video/mpeg") - (".mpv" . "video/mpeg") - (".ms" . "application/x-troff-ms") - (".nc" . "application/x-netcdf") - (".nc" . "application/x-netcdf") - (".oda" . "application/oda") - (".pbm" . "image/x-portable-bitmap") - (".pdf" . "application/pdf") - (".pgm" . "image/portable-graymap") - (".pict" . "image/pict") - (".png" . "image/png") - (".pnm" . "image/x-portable-anymap") - (".ppm" . "image/portable-pixmap") - (".ps" . "application/postscript") - (".qt" . "video/quicktime") - (".ras" . "image/x-raster") - (".rgb" . "image/x-rgb") - (".rtf" . "application/rtf") - (".rtx" . "text/richtext") - (".sh" . "application/x-sh") - (".sit" . "application/x-stuffit") - (".snd" . "audio/basic") - (".src" . "application/x-wais-source") - (".tar" . "archive/tar") - (".tcl" . "application/x-tcl") - (".tcl" . "application/x-tcl") - (".tex" . "application/x-tex") - (".texi" . "application/texinfo") - (".tga" . "image/x-targa") - (".tif" . "image/tiff") - (".tiff" . "image/tiff") - (".tr" . "application/x-troff") - (".troff" . "application/x-troff") - (".tsv" . "text/tab-separated-values") - (".txt" . "text/plain") - (".vbs" . "video/mpeg") - (".vox" . "audio/basic") - (".vrml" . "x-world/x-vrml") - (".wav" . "audio/x-wav") - (".wrl" . "x-world/x-vrml") - (".xbm" . "image/xbm") - (".xpm" . "image/x-pixmap") - (".xwd" . "image/windowdump") - (".zip" . "application/zip") - (".ai" . "application/postscript") - (".jpe" . "image/jpeg") - (".jpeg" . "image/jpeg") - ) - "*An assoc list of file extensions and the MIME content-types they -correspond to.") - -(defun mm-parse-mimetypes (&optional path) - ;; Parse out all the mimetypes specified in a unix-style path string PATH - (cond - (path nil) - ((getenv "MIMETYPES") (setq path (getenv "MIMETYPES"))) - ((memq system-type '(ms-dos ms-windows windows-nt)) - (setq path (mapconcat 'expand-file-name - '("~/mime.typ" "~/etc/mime.typ") ";"))) - (t (setq path (mapconcat 'expand-file-name - '("~/.mime-types" - "/etc/mime-types:/usr/etc/mime-types" - "/usr/local/etc/mime-types" - "/usr/local/www/conf/mime-types") ":")))) - (let ((fnames (reverse - (mm-string-to-tokens path - (if (memq system-type - '(ms-dos ms-windows windows-nt)) - ?; - ?:)))) - fname) - (while fnames - (setq fname (car fnames)) - (if (and (file-exists-p fname) (file-readable-p fname)) - (mm-parse-mimetype-file (car fnames))) - (setq fnames (cdr fnames))))) - -(defun mm-parse-mimetype-file (fname) - ;; Parse out a mime-types file - (let (type ; The MIME type for this line - extns ; The extensions for this line - save-pos ; Misc. saved buffer positions - ) - (save-excursion - (set-buffer (get-buffer-create " *mime-types*")) - (erase-buffer) - (insert-file-contents fname) - (mm-replace-regexp "#.*" "") - (mm-replace-regexp "\n+" "\n") - (mm-replace-regexp "[ \t]+$" "") - (goto-char (point-max)) - (skip-chars-backward " \t\n") - (delete-region (point) (point-max)) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward " \t\n") - (setq save-pos (point)) - (skip-chars-forward "^ \t") - (downcase-region save-pos (point)) - (setq type (buffer-substring save-pos (point))) - (while (not (eolp)) - (skip-chars-forward " \t") - (setq save-pos (point)) - (skip-chars-forward "^ \t\n") - (setq extns (cons (buffer-substring save-pos (point)) extns))) - (while extns - (setq mm-mime-extensions - (cons - (cons (if (= (string-to-char (car extns)) ?.) - (car extns) - (concat "." (car extns))) type) mm-mime-extensions) - extns (cdr extns))))))) - -(defun mm-extension-to-mime (extn) - "Return the MIME content type of the file extensions EXTN" - (if (and (stringp extn) - (not (eq (string-to-char extn) ?.))) - (setq extn (concat "." extn))) - (cdr (assoc (downcase extn) mm-mime-extensions))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Editing/Composition of body parts -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun mm-compose-type (type) - ;; Compose a body section of MIME-type TYPE. - (let* ((info (mm-mime-info type nil 5)) - (fnam (mm-generate-unique-filename)) - (comp (or (cdr (assoc "compose" info)))) - (ctyp (cdr (assoc "composetyped" info))) - (buff (get-buffer-create " *mimecompose*")) - (typeit (not ctyp)) - (retval "") - (usef nil)) - (setq comp (mm-unescape-mime-test (or comp ctyp) info)) - (while (string-match "\\([^\\\\]\\)%s" comp) - (setq comp (concat (substring comp 0 (match-end 1)) fnam - (substring comp (match-end 0) nil)) - usef t)) - (call-process shell-file-name nil - (if usef nil buff) - nil shell-command-switch comp) - (setq retval - (concat - (if typeit (concat "Content-type: " type "\r\n\r\n") "") - (if usef - (save-excursion - (set-buffer buff) - (erase-buffer) - (insert-file-contents fnam) - (buffer-string)) - (save-excursion - (set-buffer buff) - (buffer-string))) - "\r\n")) - retval)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Misc. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun mm-type-to-file (type) - "Return the file extension for content-type TYPE" - (rassoc type mm-mime-extensions)) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Miscellaneous MIME viewers written in elisp -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun mm-play-sound-file (&optional buff) - "Play a sound file in buffer BUFF (defaults to current buffer)" - (setq buff (or buff (current-buffer))) - (let ((fname (mm-generate-unique-filename "%s.au")) - (synchronous-sounds t)) ; Play synchronously - (mule-write-region-no-coding-system (point-min) (point-max) fname) - (kill-buffer (current-buffer)) - (play-sound-file fname) - (condition-case () - (delete-file fname) - (error nil)))) - -(defun mm-parse-mime-headers (&optional no-delete) - "Return a list of the MIME headers at the top of this buffer. If -optional argument NO-DELETE is non-nil, don't delete the headers." - (let* ((st (point-min)) - (nd (progn - (goto-char (point-min)) - (skip-chars-forward " \t\n") - (if (re-search-forward "^\r*$" nil t) - (1+ (point)) - (point-max)))) - save-pos - status - hname - hvalu - result - search - ) - (narrow-to-region st (min nd (point-max))) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward " \t\n\r") - (setq save-pos (point)) - (skip-chars-forward "^:\n\r") - (downcase-region save-pos (point)) - (setq hname (buffer-substring save-pos (point))) - (skip-chars-forward ": \t ") - (setq save-pos (point)) - (skip-chars-forward "^\n\r") - (setq search t) - (while search - (skip-chars-forward "^\n\r") - (save-excursion - (skip-chars-forward "\n\r") - - (setq search - (string-match "[ \t]" - (char-to-string - (or (char-after (point)) ?a))))) - (if search - (skip-chars-forward "\n\r"))) - (setq hvalu (buffer-substring save-pos (point)) - result (cons (cons hname hvalu) result))) - (or no-delete (delete-region st nd)) - result)) - -(defun mm-find-available-multiparts (separator &optional buf) - "Return a list of mime-headers for the various body parts of a -multipart message in buffer BUF with separator SEPARATOR. -The different multipart specs are put in `mm-temporary-directory'." - (let ((sep (concat "^--" separator "\r*$")) - headers - fname - results) - (save-excursion - (and buf (set-buffer buf)) - (goto-char (point-min)) - (while (re-search-forward sep nil t) - (let ((st (set-marker (make-marker) - (progn - (forward-line 1) - (beginning-of-line) - (point)))) - (nd (set-marker (make-marker) - (if (re-search-forward sep nil t) - (1- (match-beginning 0)) - (point-max))))) - (narrow-to-region st nd) - (goto-char st) - (if (looking-at "^\r*$") - (insert "Content-type: text/plain\n" - "Content-length: " (int-to-string (- nd st)) "\n")) - (setq headers (mm-parse-mime-headers) - fname (mm-generate-unique-filename)) - (let ((x (or (cdr (assoc "content-type" headers)) "text/plain"))) - (if (string-match "name=\"*\\([^ \"]+\\)\"*" x) - (setq fname (expand-file-name - (substring x (match-beginning 1) - (match-end 1)) - mm-temporary-directory)))) - (widen) - (if (assoc "content-transfer-encoding" headers) - (let ((coding (cdr - (assoc "content-transfer-encoding" headers))) - (cmd nil)) - (setq coding (and coding (downcase coding)) - cmd (or (cdr (assoc coding - mm-content-transfer-encodings)) - (read-string - (concat "How shall I decode " coding "? ") - "cat"))) - (if (string= cmd "") (setq cmd "cat")) - (if (stringp cmd) - (shell-command-on-region st nd cmd t) - (funcall cmd st nd)) - (or (eq cmd 'ignore) (set-marker nd (point))))) - (write-region st nd fname nil 5) - (delete-region st nd) - (setq results (cons - (cons - (cons "mm-filename" fname) headers) results))))) - results)) - -(defun mm-format-multipart-as-html (&optional buf type) - (if buf (set-buffer buf)) - (let* ((boundary (if (string-match - "boundary[ \t]*=[ \t\"]*\\([^ \"\t\n]+\\)" - type) - (regexp-quote - (substring type (match-beginning 1) (match-end 1))))) - (parts (mm-find-available-multiparts boundary))) - (erase-buffer) - (insert "\n" - " \n" - " Multipart Message\n" - " \n" - " \n" - "

Multipart message encountered

\n" - "

I have encountered a multipart MIME message.\n" - " The following parts have been detected. Please\n" - " select which one you want to view.\n" - "

\n" - " \n" - " \n" - "\n" - "\n"))) - -(defun mm-multipart-viewer () - (mm-format-multipart-as-html - (current-buffer) - (cdr (assoc "content-type" url-current-mime-headers))) - (let ((w3-working-buffer (current-buffer))) - (w3-prepare-buffer))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Transfer encodings we can decrypt automatically -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun mm-decode-quoted-printable (&optional st nd) - (interactive) - (setq st (or st (point-min)) - nd (or nd (point-max))) - (save-restriction - (narrow-to-region st nd) - (save-excursion - (let ((buffer-read-only nil)) - (goto-char (point-min)) - (while (re-search-forward "=[0-9A-F][0-9A-F]" nil t) - (replace-match - (char-to-string - (+ - (* 16 (mm-hex-char-to-integer - (char-after (1+ (match-beginning 0))))) - (mm-hex-char-to-integer - (char-after (1- (match-end 0)))))))))) - (goto-char (point-max)))) - -;; Taken from hexl.el. -(defun mm-hex-char-to-integer (character) - "Take a char and return its value as if it was a hex digit." - (if (and (>= character ?0) (<= character ?9)) - (- character ?0) - (let ((ch (logior character 32))) - (if (and (>= ch ?a) (<= ch ?f)) - (- ch (- ?a 10)) - (error (format "Invalid hex digit `%c'." ch)))))) - - - -(require 'base64) -(provide 'mm) diff --git a/lisp/rfc1522.el b/lisp/rfc1522.el deleted file mode 100644 index 98c8ea8..0000000 --- a/lisp/rfc1522.el +++ /dev/null @@ -1,276 +0,0 @@ -;;; rfc1522.el --- Functions for encoding and decoding rfc1522 messages -;; Copyright (C) 1998 Free Software Foundation, Inc. - -;; Author: Lars Magne Ingebrigtsen -;; MORIOKA Tomohiko -;; This file is part of GNU Emacs. - -;; 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. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; 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., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Commentary: - -;;; Code: - -(require 'base64) -(require 'qp) -(require 'mm-util) - -(defvar rfc1522-header-encoding-alist - '(("Newsgroups" . nil) - ("Message-ID" . nil) - (t . mime)) - "*Header/encoding method alist. -The list is traversed sequentially. The keys can either be -header regexps or `t'. - -The values can be: - -1) nil, in which case no encoding is done; -2) `mime', in which case the header will be encoded according to RFC1522; -3) a charset, in which case it will be encoded as that charse; -4) `default', in which case the field will be encoded as the rest - of the article.") - -(defvar rfc1522-charset-encoding-alist - '((us-ascii . nil) - (iso-8859-1 . Q) - (iso-8859-2 . Q) - (iso-8859-3 . Q) - (iso-8859-4 . Q) - (iso-8859-5 . Q) - (koi8-r . Q) - (iso-8859-7 . Q) - (iso-8859-8 . Q) - (iso-8859-9 . Q) - (iso-2022-jp . B) - (iso-2022-kr . B) - (gb2312 . B) - (cn-gb . B) - (cn-gb-2312 . B) - (euc-kr . B) - (iso-2022-jp-2 . B) - (iso-2022-int-1 . B)) - "Alist of MIME charsets to RFC1522 encodings. -Valid encodings are nil, `Q' and `B'.") - -(defvar rfc1522-encoding-function-alist - '((Q . rfc1522-q-encode-region) - (B . base64-encode-region) - (nil . ignore)) - "Alist of RFC1522 encodings to encoding functions.") - -(defvar rfc1522-q-encoding-alist - '(("\\(From\\|Cc\\|To\\|Bcc\||Reply-To\\):" . "[^-A-Za-z0-9!*+/=_]") - ("." . "[\000-\007\013\015-\037\200-\377=_?]")) - "Alist of header regexps and valid Q characters.") - -;;; -;;; Functions for encoding RFC1522 messages -;;; - -(defun rfc1522-narrow-to-field () - "Narrow the buffer to the header on the current line." - (beginning-of-line) - (narrow-to-region - (point) - (progn - (forward-line 1) - (if (re-search-forward "^[^ \n\t]" nil t) - (progn - (beginning-of-line) - (point)) - (point-max)))) - (goto-char (point-min))) - -;;;###autoload -(defun rfc1522-encode-message-header () - "Encode the message header according to `rfc1522-header-encoding-alist'. -Should be called narrowed to the head of the message." - (interactive "*") - (when (featurep 'mule) - (save-excursion - (let ((alist rfc1522-header-encoding-alist) - elem method) - (while (not (eobp)) - (save-restriction - (rfc1522-narrow-to-field) - (when (find-non-ascii-charset-region (point-min) (point-max)) - ;; We found something that may perhaps be encoded. - (while (setq elem (pop alist)) - (when (or (and (stringp (car elem)) - (looking-at (car elem))) - (eq (car elem) t)) - (setq alist nil - method (cdr elem)))) - (when method - (cond - ((eq method 'mime) - (rfc1522-encode-region (point-min) (point-max))) - ;; Hm. - (t)))) - (goto-char (point-max)))))))) - -(defun rfc1522-encode-region (b e) - "Encode all encodable words in REGION." - (let (prev c start qstart qprev qend) - (save-excursion - (goto-char b) - (while (re-search-forward "[^ \t\n]+" nil t) - (save-restriction - (narrow-to-region (match-beginning 0) (match-end 0)) - (goto-char (setq start (point-min))) - (setq prev nil) - (while (not (eobp)) - (unless (eq (setq c (char-charset (following-char))) 'ascii) - (cond - ((eq c prev) - ) - ((null prev) - (setq qstart (or qstart start) - qend (point-max) - qprev c) - (setq prev c)) - (t - ;(rfc1522-encode start (setq start (point)) prev) - (setq prev c)))) - (forward-char 1))) - (when (and (not prev) qstart) - (rfc1522-encode qstart qend qprev) - (setq qstart nil))) - (when qstart - (rfc1522-encode qstart qend qprev) - (setq qstart nil))))) - -(defun rfc1522-encode-string (string) - "Encode words in STRING." - (with-temp-buffer - (insert string) - (rfc1522-encode-region (point-min) (point-max)) - (buffer-string))) - -(defun rfc1522-encode (b e charset) - "Encode the word in the region with CHARSET." - (let* ((mime-charset (mm-mule-charset-to-mime-charset charset)) - (encoding (cdr (assq mime-charset - rfc1522-charset-encoding-alist))) - (start (concat - "=?" (downcase (symbol-name mime-charset)) "?" - (downcase (symbol-name encoding)) "?"))) - (save-restriction - (narrow-to-region b e) - (insert - (prog1 - (mm-encode-coding-string (buffer-string) mime-charset) - (delete-region (point-min) (point-max)))) - (funcall (cdr (assq encoding rfc1522-encoding-function-alist)) - (point-min) (point-max)) - (goto-char (point-min)) - (insert start) - (goto-char (point-max)) - (insert "?=") - ;; Encoded words can't be more than 75 chars long, so we have to - ;; split the long ones up. - (end-of-line) - (while (> (current-column) 74) - (beginning-of-line) - (forward-char 73) - (insert "?=\n " start) - (end-of-line))))) - -(defun rfc1522-q-encode-region (b e) - "Encode the header contained in REGION with the Q encoding." - (save-excursion - (save-restriction - (narrow-to-region (goto-char b) e) - (let ((alist rfc1522-q-encoding-alist)) - (while alist - (when (looking-at (caar alist)) - (quoted-printable-encode-region b e nil (cdar alist)) - (subst-char-in-region (point-min) (point-max) ? ?_)) - (pop alist)))))) - -;;; -;;; Functions for decoding RFC1522 messages -;;; - -(defvar rfc1522-encoded-word-regexp - "=\\?\\([^][\000-\040()<>@,\;:\\\"/?.=]+\\)\\?\\(B\\|Q\\)\\?\\([!->@-~]+\\)\\?=") - -;;;###autoload -(defun rfc1522-decode-region (start end) - "Decode MIME-encoded words in region between START and END." - (interactive "r") - (save-excursion - (save-restriction - (narrow-to-region start end) - (goto-char (point-min)) - ;; Remove whitespace between encoded words. - (while (re-search-forward - (concat "\\(" rfc1522-encoded-word-regexp "\\)" - "\\(\n?[ \t]\\)+" - "\\(" rfc1522-encoded-word-regexp "\\)") - nil t) - (delete-region (goto-char (match-end 1)) (match-beginning 6))) - ;; Decode the encoded words. - (goto-char (point-min)) - (while (re-search-forward rfc1522-encoded-word-regexp nil t) - (insert (rfc1522-parse-and-decode - (prog1 - (match-string 0) - (delete-region (match-beginning 0) (match-end 0))))))))) - -;;;###autoload -(defun rfc1522-decode-string (string) - "Decode the quoted-printable-encoded STRING and return the results." - (with-temp-buffer - (insert string) - (inline - (rfc1522-decode-region (point-min) (point-max))) - (buffer-string))) - -(defun rfc1522-parse-and-decode (word) - "Decode WORD and return it if it is an encoded word. -Return WORD if not." - (if (not (string-match rfc1522-encoded-word-regexp word)) - word - (or - (condition-case nil - (rfc1522-decode - (match-string 1 word) - (upcase (match-string 2 word)) - (match-string 3 word)) - (error word)) - word))) - -(defun rfc1522-decode (charset encoding string) - "Decode STRING as an encoded text. -Valid ENCODINGs are \"B\" and \"Q\". -If your Emacs implementation can't decode CHARSET, it returns nil." - (let ((cs (mm-charset-to-coding-system charset))) - (when cs - (mm-decode-coding-string - (cond - ((equal "B" encoding) - (base64-decode string)) - ((equal "Q" encoding) - (quoted-printable-decode-string - (mm-replace-chars-in-string string ?_ ? ))) - (t (error "Invalid encoding: %s" encoding))) - cs)))) - -(provide 'rfc1522) - -;;; rfc1522.el ends here diff --git a/readme b/readme deleted file mode 100644 index e3064ef..0000000 --- a/readme +++ /dev/null @@ -1,52 +0,0 @@ -This package contains a beta version of Gnus. The lisp directory -contains the source lisp files, and the texi directory contains a -draft of the Gnus info pages. - -To use Gnus you first have to unpack the files, which you've obviously -done, because you are reading this. - -You should definitely byte-compile the source files. To do that, you -can simply say "./configure; make" in this directory. If you are -using XEmacs, you *must* say "make EMACS=xemacs". In that case you -may also want to pull down the package of nice glyphs from -. It should be installed -into the "gnus-5.4.53/etc" directory. - -Then you have to tell Emacs where Gnus is. You might put something -like - - (setq load-path (cons (expand-file-name "~/gnus-5.4.53/lisp") load-path)) - -in your .emacs file, or wherever you keep such things. - -To enable reading the Gnus manual, you could say something like: - - (setq Info-default-directory-list - (cons "~/gnus-5.4.53/texi" Info-default-directory-list)) - -Note that Gnus and GNUS can't coexist in a single Emacs. They both use -the same function and variable names. If you have been running GNUS -in your Emacs, you should probably exit that Emacs and start a new one -to fire up Gnus. - -Gnus does absolutely not work with anything older than Emacs 19.33 or -XEmacs 19.14. So you definitely need a new Emacs. - -Then you do a `M-x gnus', and everything should... uhm... it should -work, but it might not. Set `debug-on-error' to t, and mail me the -backtraces, or, better yet, find out why Gnus does something wrong, -fix it, and send me the diffs. :-) - -There are four main things I want your help and input on: - -1) Startup. Does everything go smoothly, and why not? - -2) Any errors while you read news normally? - -3) Any errors if you do anything abnormal? - -4) Features you do not like, or do like, but would like to tweak a - bit, and features you would like to see. - -Send any comments and all your bug fixes/complaints to -`bugs@gnus.org'. diff --git a/texi/Makefile b/texi/Makefile deleted file mode 100644 index ea5ef8f..0000000 --- a/texi/Makefile +++ /dev/null @@ -1,161 +0,0 @@ -TEXI2DVI=texi2dvi -EMACS=emacs -MAKEINFO=$(EMACS) -batch -q -no-site-file -INFOSWI=-l texinfmt -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer -XINFOSWI=-l texinfmt -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer -LATEX=latex -DVIPS=dvips -PERL=perl -INFODIR=/usr/local/info - -all: gnus message - -most: texi2latex.elc latex latexps - -.SUFFIXES: .texi .dvi .ps - -.texi: - $(MAKEINFO) -eval '(find-file "$<")' $(XINFOSWI) - -dvi: gnus.dvi message.dvi - -.texi.dvi : - $(PERL) -n -e 'print unless (/\@iflatex/ .. /\@end iflatex/)' $< > gnustmp.texi - $(TEXI2DVI) gnustmp.texi - cp gnustmp.dvi $*.dvi - rm gnustmp.* - -refcard.dvi: refcard.tex gnuslogo.refcard gnusref.tex - $(LATEX) refcard.tex - -clean: - rm -f gnus.*.bak *.ky *.cp *.fn *.cps *.kys *.log *.aux *.dvi *.vr \ - *.tp *.toc *.pg gnus.latexi *.aux *.[cgk]idx \ - gnus.ilg gnus.ind gnus.[cgk]ind gnus.idx \ - gnus.tmptexi *.tmplatexi gnus.tmplatexi1 texput.log *.orig *.rej \ - gnus.latexi*~* tmp/*.ps xface.tex picons.tex smiley.tex *.latexi - -makeinfo: - makeinfo -o gnus gnus.texi - makeinfo -o message message.texi - -texi2latex.elc: texi2latex.el - $(EMACS) -batch -l bytecomp --eval '(byte-compile-file "texi2latex.el")' - -latex: gnus.texi texi2latex.elc - $(EMACS) -batch -q -no-site-file gnus.texi -l ./texi2latex.elc -f latexi-translate - -latexps: - make texi2latex.elc - rm -f gnus.aux - egrep -v "label.*Index|chapter.*Index" gnus.latexi > gnus.tmplatexi1 - $(LATEX) gnus.tmplatexi1 - ./splitindex - makeindex -o gnus.kind gnus.kidx - makeindex -o gnus.cind gnus.cidx - makeindex -o gnus.gind gnus.gidx - sed 's/\\char 5E\\relax {}/\\symbol{"5E}/' < gnus.kind > gnus.tmpkind - mv gnus.tmpkind gnus.kind - egrep -v "end{document}" gnus.tmplatexi1 > gnus.tmplatexi - cat postamble.tex >> gnus.tmplatexi - $(LATEX) gnus.tmplatexi - $(LATEX) gnus.tmplatexi - $(DVIPS) -f gnus.dvi > gnus.ps - -pss: - make latex - make latexps - -psout: - make latex - make latexboth - make out - -latexboth: - rm -f gnus-manual-a4.ps.gz gnus-manual-standard.ps.gz - make latexps - mv /local/tmp/larsi/gnus.ps /local/tmp/larsi/gnus-manual-a4.ps - gzip /local/tmp/larsi/gnus-manual-a4.ps - sed 's/,a4paper//' gnus.latexi > gnus-standard.latexi - mv gnus-standard.latexi gnus.latexi - make latexps - mv /local/tmp/larsi/gnus.ps /local/tmp/larsi/gnus-manual-standard.ps - gzip /local/tmp/larsi/gnus-manual-standard.ps - -out: - cp /local/tmp/larsi/gnus-manual-standard.ps.gz \ - /local/tmp/larsi/gnus-manual-a4.ps.gz \ - /local/ftp/pub/emacs/gnus/manual - mv /local/tmp/larsi/gnus-manual-standard.ps.gz \ - /local/tmp/larsi/gnus-manual-a4.ps.gz \ - /hom/larsi/www_docs/www.gnus.org/documents - -veryclean: - make clean - rm -f gnus.dvi gnus.ps - -distclean: - make clean - rm -f *.orig *.rej *.elc *~ gnus gnus-[0-9] gnus-[0-9][0-9] - rm -f message message-[0-9] - -install: - cp gnus gnus-[0-9] gnus-[0-9][0-9] $(INFODIR) - cp message $(INFODIR) - - -tmps: - if [ ! -e tmp ]; then mkdir tmp; fi - make screens - make herdss - make etcs - make piconss - make xfaces - make smiley - make miscs - -herdss: - cd herds ; for i in new-herd-[0-9]*.gif; do echo $$i; giftopnm $$i | pnmcrop -white | pnmmargin -white 9 | pnmscale 2 | pnmconvol convol5.pnm | ppmtopgm | pnmdepth 255 | pnmtops -width 100 -height 100 -noturn > ../tmp/`basename $$i .gif`.ps; done - cd herds ; giftopnm new-herd-section.gif | pnmscale 4 | pnmconvol convol11.pnm | ppmtopgm | pnmdepth 255 | pnmtops -noturn -width 100 -height 100 > ../tmp/new-herd-section.ps - - -screens: - cd screen ; for i in *.gif; do echo $$i; giftopnm $$i | pnmmargin -black 1 | ppmtopgm | pnmtops -width 100 -height 100 -noturn > ../tmp/`basename $$i .gif`.ps; done - -miscs: - giftopnm misc/larsi.gif | ppmtopgm | pnmtops -noturn > tmp/larsi.ps - tifftopnm misc/eseptember.tif | pnmscale 4 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/september.ps - tifftopnm misc/fseptember.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/fseptember.ps - tifftopnm misc/fred.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/fred.ps - tifftopnm misc/ered.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/red.ps - -etcs: - cd etc; for i in gnus-*.xpm; do echo $$i; xpmtoppm $$i | ppmtopgm | pnmdepth 255 | pnmtops -noturn > ../tmp/`basename $$i .xpm`.ps; done - -piconss: - cd picons; for i in *.xbm; do echo $$i; xbmtopbm $$i | pnmtops -noturn > ../tmp/picons-`basename $$i .xbm`.ps; done - cd picons; for i in *.gif; do echo $$i; giftopnm $$i | ppmtopgm | pnmtops -noturn > ../tmp/picons-`basename $$i .gif`.ps; done - for i in tmp/picons-*.ps; do echo "\\gnuspicon{$$i}"; done > picons.tex - -xfaces: - cd xface; for i in *.gif; do echo $$i; giftopnm $$i | ppmtopgm | pnmtops -noturn > ../tmp/xface-`basename $$i .gif`.ps; done - for i in tmp/xface-*.ps; do \ - if [ -n "$$a" ]; then a=""; echo "{$$i}"; else \ - a="h"; echo -n "\\gnusxface{$$i}"; fi done > xface.tex; \ - if [ -n "$$a" ]; then echo "{$$i}" >> xface.tex; fi - -smiley: - cd smilies; tifftopnm BigFace.tif | ppmtopgm | pnmtops > ../tmp/BigFace.ps - cd smilies; for i in *.xpm; do echo $$i; sed "s/none/#FFFFFF/" $$i | xpmtoppm | ppmtopgm | pnmdepth 255 | pnmtops > ../tmp/smiley-`basename $$i .xpm`.ps; done - for i in tmp/smiley-*.ps; do \ - if [ -n "$$a" ]; then a=""; echo "{$$i}"; else \ - a="h"; echo -n "\\gnussmiley{$$i}"; fi done > smiley.tex; \ - if [ -n "$$a" ]; then echo "{$$i}" >> smiley.tex; fi - -pspackage: - tar czvf pspackage.tar.gz gnus-faq.texi gnus.texi herds misc pagestyle.sty picons pixidx.sty postamble.tex ps screen smilies splitindex texi2latex.el xface Makefile README etc - -complete: - make texi2latex.elc - make tmps - make pss diff --git a/texi/custom.texi b/texi/custom.texi deleted file mode 100644 index 5b6fe4a..0000000 --- a/texi/custom.texi +++ /dev/null @@ -1,695 +0,0 @@ -\input texinfo.tex - -@c %**start of header -@setfilename custom -@settitle The Customization Library -@iftex -@afourpaper -@headings double -@end iftex -@c %**end of header - -@node Top, Introduction, (dir), (dir) -@comment node-name, next, previous, up -@top The Customization Library - -Version: 1.82 - -@menu -* Introduction:: -* User Commands:: -* The Customization Buffer:: -* Declarations:: -* Utilities:: -* The Init File:: -* Wishlist:: -@end menu - -@node Introduction, User Commands, Top, Top -@comment node-name, next, previous, up -@section Introduction - -This library allows customization of @dfn{user options}. Currently two -types of user options are supported, namely @dfn{variables} and -@dfn{faces}. Each user option can have four different values -simultaneously: -@table @dfn -@item factory setting -The value specified by the programmer. -@item saved value -The value saved by the user as the default for this variable. This -overwrites the factory setting when starting a new emacs. -@item current value -The value used by Emacs. This will not be remembered next time you -run Emacs. -@item widget value -The value entered by the user in a customization buffer, but not yet -applied. -@end table - -Variables also have a @dfn{type}, which specifies what kind of values -the variable can hold, and how the value is presented in a customization -buffer. By default a variable can hold any valid expression, but the -programmer can specify a more limited type when declaring the variable. - -The user options are organized in a number of @dfn{groups}. Each group -can contain a number user options, as well as other groups. The groups -allows the user to concentrate on a specific part of emacs. - -@node User Commands, The Customization Buffer, Introduction, Top -@comment node-name, next, previous, up -@section User Commands - -The following commands will create a customization buffer: - -@table @code -@item customize -Create a customization buffer containing a specific group, by default -the @code{emacs} group. - -@item customize-variable -Create a customization buffer containing a single variable. - -@item customize-face -Create a customization buffer containing a single face. - -@item customize-apropos -Create a customization buffer containing all variables, faces, and -groups that match a user specified regular expression. -@end table - -@node The Customization Buffer, Declarations, User Commands, Top -@comment node-name, next, previous, up -@section The Customization Buffer. - -The customization buffer allows the user to make temporary or permanent -changes to how specific aspects of emacs works, by setting and editing -user options. - -The customization buffer contains three types of text: - -@table @dfn -@item informative text -where the normal editing commands are disabled. - -@item editable fields -where you can edit with the usual emacs commands. Editable fields are -usually displayed with a grey background if your terminal supports -colors, or an italic font otherwise. - -@item buttons -which can be activated by either pressing the @kbd{@key{ret}} while -point is located on the text, or pushing @kbd{mouse-2} while the mouse -pointer is above the tex. Buttons are usually displayed in a bold -font. -@end table - -You can move to the next the next editable field or button by pressing -@kbd{@key{tab}} or the previous with @kbd{M-@key{tab}}. Some buttons -have a small helpful message about their purpose, which will be -displayed when you move to it with the @key{tab} key. - -The buffer is divided into three part, an introductory text, a list of -customization options, and a line of customization buttons. Each part -will be described in the following. - -@menu -* The Introductory Text:: -* The Customization Options:: -* The Variable Options:: -* The Face Options:: -* The Group Options:: -* The State Button:: -* The Customization Buttons:: -@end menu - -@node The Introductory Text, The Customization Options, The Customization Buffer, The Customization Buffer -@comment node-name, next, previous, up -@subsection The Introductory Text - -The start of the buffer contains a short explanation of what it is, and -how to get help. It will typically look like this: - -@example -This is a customization buffer. -Push RET or click mouse-2 on the word _help_ for more information. -@end example - -Rather boring. It is mostly just informative text, but the word -@samp{help} is a button that will bring up this document when -activated. - -@node The Customization Options, The Variable Options, The Introductory Text, The Customization Buffer -@comment node-name, next, previous, up -@subsection The Customization Options - -Each customization option looks similar to the following text: - -@example - *** custom-background-mode: default - State: this item is unchanged from its factory setting. - [ ] [?] The brightness of the background. -@end example - -The option contains the parts described below. - -@table @samp -@item *** -The Level Button. The customization options in the buffer are organized -in a hierarchy, which is indicated by the number of stars in the level -button. The top level options will be shown as @samp{*}. When they are -expanded, the suboptions will be shown as @samp{**}. The example option -is thus a subsuboption. - -Activating the level buttons will toggle between hiding and exposing the -content of that option. The content can either be the value of the -option, as in this example, or a list of suboptions. - -@item custom-background-mode -This is the tag of the the option. The tag is a name of a variable, a -face, or customization group. Activating the tag has an effect that -depends on the exact type of the option. In this particular case, -activating the tag will bring up a menu that will allow you to choose -from the three possible values of the `custom-background-mode' -variable. - -@item default -After the tag, the options value is shown. Depending on its type, you -may be able to edit the value directly. If an option should contain a -file name, it is displayed in an editable field, i.e. you can edit it -using the standard emacs editing commands. - -@item State: this item is unchanged from its factory setting. -The state line. This line will explain the state of the option, -e.g. whether it is currently hidden, or whether it has been modified or -not. Activating the button will allow you to change the state, e.g. set -or reset the changes you have made. This is explained in detail in the -following sections. - -@item [ ] -The magic button. This is an abbreviated version of the state line. - -@item [?] -The documentation button. If the documentation is more than one line, -this button will be present. Activating the button will toggle whether -the complete documentation is shown, or only the first line. - -@item The brightness of the background. -This is a documentation string explaining the purpose of this particular -customization option. - -@end table - -@node The Variable Options, The Face Options, The Customization Options, The Customization Buffer -@comment node-name, next, previous, up -@subsection The Variable Options - -The most common customization options are emacs lisp variables. The -actual editing of these variables depend on what type values the -variable is expected to contain. For example, a lisp variable whose -value should be a string will typically be represented with an editable -text field in the buffer, where you can change the string directly. If -the value is a list, each item in the list will be presented in the -buffer buffer on a separate line, with buttons to insert new items in -the list, or delete existing items from the list. You may want to see -@ref{User Interface,,, widget, The Widget Library}, where some examples -of editing are discussed. - -You can either choose to edit the value directly, or edit the lisp -value for that variable. The lisp value is a lisp expression that -will be evaluated when you start emacs. The result of the evaluation -will be used as the initial value for that variable. Editing the -lisp value is for experts only, but if the current value of the -variable is of a wrong type (i.e. a symbol where a string is expected), -the `edit lisp' mode will always be selected. - -You can see what mode is currently selected by looking at the state -button. If it uses parenthesises (like @samp{( )}) it is in edit lisp -mode, with square brackets (like @samp{[ ]}) it is normal edit mode. -You can switch mode by activating the state button, and select either -@samp{Edit} or @samp{Edit lisp} from the menu. - -You can change the state of the variable with the other menu items: - -@table @samp -@item Set -When you have made your modifications in the buffer, you need to -activate this item to make the modifications take effect. The -modifications will be forgotten next time you run emacs. - -@item Save -Unless you activate this item instead! This will mark the modification -as permanent, i.e. the changes will be remembered in the next emacs -session. - -@item Reset -If you have made some modifications and not yet applied them, you can -undo the modification by activating this item. - -@item Reset to Saved -Activating this item will reset the value of the variable to the last -value you marked as permanent with `Save'. - -@item Reset to Factory Settings -Activating this item will undo all modifications you have made, and -reset the value to the initial value specified by the program itself. -@end table - -By default, the value of large or complicated variables are hidden. You -can show the value by clicking on the level button. - -@node The Face Options, The Group Options, The Variable Options, The Customization Buffer -@comment node-name, next, previous, up -@subsection The Face Options - -A face is an object that controls the appearance of some buffer text. -The face has a number of possible attributes, such as boldness, -foreground color, and more. For each attribute you can specify whether -this attribute is controlled by the face, and if so, what the value is. -For example, if the attribute bold is not controlled by a face, using -that face on some buffer text will not affect its boldness. If the bold -attribute is controlled by the face, it can be turned either on or of. - -It is possible to specify that a face should have different attributes -on different device types. For example, a face may make text red on a -color device, and bold on a monochrome device. You do this by -activating `Edit All' in the state menu. - -The way this is presented in the customization buffer is to have a list -of display specifications, and for each display specification a list of -face attributes. For each face attribute, there is a checkbox -specifying whether this attribute has effect and what the value is. -Here is an example: - -@example - *** custom-invalid-face: (sample) - State: this item is unchanged from its factory setting. - [ ] Face used when the customize item is invalid. - [INS] [DEL] Display: [ ] Type: [ ] X [ ] PM [ ] Win32 [ ] DOS [ ] TTY - [X] Class: [X] Color [ ] Grayscale [ ] Monochrome - [ ] Background: [ ] Light [ ] Dark - Attributes: [ ] Bold: off - [ ] Italic: off - [ ] Underline: off - [X] Foreground: yellow (sample) - [X] Background: red (sample) - [ ] Stipple: - [INS] [DEL] Display: all - Attributes: [X] Bold: on - [X] Italic: on - [X] Underline: on - [ ] Foreground: default (sample) - [ ] Background: default (sample) - [ ] Stipple: - [INS] -@end example - -This has two display specifications. The first will match all color -displays, independently on what window system the device belongs to, and -whether background color is dark or light. For devices matching this -specification, @samp{custom-invalid-face} will force text to be -displayed in yellow on red, but leave all other attributes alone. - -The second display will simply match everything. Since the list is -prioritised, this means that it will match all non-color displays. For -these, the face will not affect the foreground or background color, but -force the font to be both bold, italic, and underline. - -You can add or delete display specifications by activating the -@samp{[INS]} and @samp{[DEL]} buttons, and modify them by clicking on -the check boxes. The first checkbox in each line in the display -specification is special. It specify whether this particular property -will even be relevant. By not checking the box in the first display, we -match all device types, also device types other than those listed. - -After modifying the face, you can activate the state button to make the -changes take effect. The menu items in the state button menu is similar -to the state menu items for variables described in the previous section. - -@node The Group Options, The State Button, The Face Options, The Customization Buffer -@comment node-name, next, previous, up -@subsection The Group Options - -Since Emacs has approximately a zillion configuration options, they have -been organized in groups. Each group can contain other groups, thus -creating a customization hierarchy. The nesting of the customization -within the visible part of this hierarchy is indicated by the number of -stars in the level button. - -Since there is really no customization needed for the group itself, the -menu items in the groups state button will affect all modified group -members recursively. Thus, if you activate the @samp{Set} menu item, -all variables and faces that have been modified and belong to that group -will be applied. For those members that themselves are groups, it will -work as if you had activated the @samp{Set} menu item on them as well. - -@node The State Button, The Customization Buttons, The Group Options, The Customization Buffer -@comment node-name, next, previous, up -@subsection The State Line and The Magic Button - -The state line has two purposes. The first is to hold the state menu, -as described in the previous sections. The second is to indicate the -state of each customization item. - -For the magic button, this is done by the character inside the brackets. -The following states have been defined, the first that applies to the -current item will be used: - -@table @samp -@item - -The option is currently hidden. For group options that means the -members are not shown, for variables and faces that the value is not -shown. You cannot perform any of the state change operations on a -hidden customization option. - -@item * -The value if this option has been modified in the buffer, but not yet -applied. - -@item + -The item has has been set by the user. - -@item : -The current value of this option is different from the saved value. - -@item ! -The saved value of this option is different from the factory setting. - -@item @@ -The factory setting of this option is not known. This occurs when you -try to customize variables or faces that have not been explicitly -declared as customizable. - -@item SPC -The factory setting is still in effect. - -@end table - -For non-hidden group options, the state shown is the most severe state -of its members, where more severe means that it appears earlier in the -list above (except hidden members, which are ignored). - -@node The Customization Buttons, , The State Button, The Customization Buffer -@comment node-name, next, previous, up -@subsection The Customization Buttons - -The last part of the customization buffer looks like this: - -@example -[Set] [Save] [Reset] [Done] -@end example - -Activating the @samp{[Set]}, @samp{[Save]}, or @samp{[Reset]} -button will affect all modified customization items that are visible in -the buffer. @samp{[Done]} will bury the buffer. - -@node Declarations, Utilities, The Customization Buffer, Top -@comment node-name, next, previous, up -@section Declarations - -This section describes how to declare customization groups, variables, -and faces. It doesn't contain any examples, but please look at the file -@file{cus-edit.el} which contains many declarations you can learn from. - -@menu -* Declaring Groups:: -* Declaring Variables:: -* Declaring Faces:: -* Usage for Package Authors:: -@end menu - -All the customization declarations can be changes by keyword arguments. -Groups, variables, and faces all share these common keywords: - -@table @code -@item :group -@var{value} should be a customization group. -Add @var{symbol} to that group. -@item :link -@var{value} should be a widget type. -Add @var{value} to the extrenal links for this customization option. -Useful widget types include @code{custom-manual}, @code{info-link}, and -@code{url-link}. -@item :load -Add @var{value} to the files that should be loaded nefore displaying -this customization option. The value should be iether a string, which -should be a string which will be loaded with @code{load-library} unless -present in @code{load-history}, or a symbol which will be loaded with -@code{require}. -@item :tag -@var{Value} should be a short string used for identifying the option in -customization menus and buffers. By default the tag will be -automatically created from the options name. -@end table - -@node Declaring Groups, Declaring Variables, Declarations, Declarations -@comment node-name, next, previous, up -@subsection Declaring Groups - -Use @code{defgroup} to declare new customization groups. - -@defun defgroup symbol members doc [keyword value]... -Declare @var{symbol} as a customization group containing @var{members}. -@var{symbol} does not need to be quoted. - -@var{doc} is the group documentation. - -@var{members} should be an alist of the form ((@var{name} -@var{widget})...) where @var{name} is a symbol and @var{widget} is a -widget for editing that symbol. Useful widgets are -@code{custom-variable} for editing variables, @code{custom-face} for -editing faces, and @code{custom-group} for editing groups.@refill - -Internally, custom uses the symbol property @code{custom-group} to keep -track of the group members, and @code{group-documentation} for the -documentation string. - -The following additional @var{keyword}'s are defined: - -@table @code -@item :prefix -@var{value} should be a string. If the string is a prefix for the name -of a member of the group, that prefix will be ignored when creating a -tag for that member. -@end table -@end defun - -@node Declaring Variables, Declaring Faces, Declaring Groups, Declarations -@comment node-name, next, previous, up -@subsection Declaring Variables - -Use @code{defcustom} to declare user editable variables. - -@defun defcustom symbol value doc [keyword value]... -Declare @var{symbol} as a customizable variable that defaults to @var{value}. -Neither @var{symbol} nor @var{value} needs to be quoted. -If @var{symbol} is not already bound, initialize it to @var{value}. - -@var{doc} is the variable documentation. - -The following additional @var{keyword}'s are defined: - -@table @code -@item :type -@var{value} should be a widget type. -@item :options -@var{value} should be a list of possible members of the specified type. -For hooks, this is a list of function names. -@end table - -@xref{Sexp Types,,,widget,The Widget Library}, for information about -widgets to use together with the @code{:type} keyword. -@end defun - -Internally, custom uses the symbol property @code{custom-type} to keep -track of the variables type, @code{factory-value} for the program -specified default value, @code{saved-value} for a value saved by the -user, and @code{variable-documentation} for the documentation string. - -Use @code{custom-add-option} to specify that a specific function is -useful as an meber of a hook. - -@defun custom-add-option symbol option -To the variable @var{symbol} add @var{option}. - -If @var{symbol} is a hook variable, @var{option} should be a hook -member. For other types variables, the effect is undefined." -@end defun - -@node Declaring Faces, Usage for Package Authors, Declaring Variables, Declarations -@comment node-name, next, previous, up -@subsection Declaring Faces - -Faces are declared with @code{defface}. - -@defun defface face spec doc [keyword value]... - -Declare @var{face} as a customizable face that defaults to @var{spec}. -@var{face} does not need to be quoted. - -If @var{face} has been set with `custom-set-face', set the face attributes -as specified by that function, otherwise set the face attributes -according to @var{spec}. - -@var{doc} is the face documentation. - -@var{spec} should be an alist of the form @samp{((@var{display} @var{atts})...)}. - -@var{atts} is a list of face attributes and their values. The possible -attributes are defined in the variable `custom-face-attributes'. -Alternatively, @var{atts} can be a face in which case the attributes of -that face is used. - -The @var{atts} of the first entry in @var{spec} where the @var{display} -matches the frame should take effect in that frame. @var{display} can -either be the symbol `t', which will match all frames, or an alist of -the form @samp{((@var{req} @var{item}...)...)}@refill - -For the @var{display} to match a FRAME, the @var{req} property of the -frame must match one of the @var{item}. The following @var{req} are -defined:@refill - -@table @code -@item type -(the value of (window-system))@* -Should be one of @code{x} or @code{tty}. - -@item class -(the frame's color support)@* -Should be one of @code{color}, @code{grayscale}, or @code{mono}. - -@item background -(what color is used for the background text)@* -Should be one of @code{light} or @code{dark}. -@end table - -Internally, custom uses the symbol property @code{factory-face} for the -program specified default face properties, @code{saved-face} for -properties saved by the user, and @code{face-doc-string} for the -documentation string.@refill - -@end defun - -@node Usage for Package Authors, , Declaring Faces, Declarations -@comment node-name, next, previous, up -@subsection Usage for Package Authors - -The recommended usage for the author of a typical emacs lisp package is -to create one group identifying the package, and make all user options -and faces members of that group. If the package has more than around 20 -such options, they should be divided into a number of subgroups, with -each subgroup being member of the top level group. - -The top level group for the package should itself be member of one or -more of the standard customization groups. There exists a group for -each @emph{finder} keyword. Press @kbd{C-c p} to see a list of finder -keywords, and add you group to each of them, using the @code{:group} -keyword. - -@node Utilities, The Init File, Declarations, Top -@comment node-name, next, previous, up -@section Utilities - -These utilities can come in handy when adding customization support. - -@deffn Widget custom-manual -Widget type for specifying the info manual entry for a customization -option. It takes one argument, an info address. -@end deffn - -@defun custom-add-to-group group member widget -To existing @var{group} add a new @var{member} of type @var{widget}, -If there already is an entry for that member, overwrite it. -@end defun - -@defun custom-add-link symbol widget -To the custom option @var{symbol} add the link @var{widget}. -@end defun - -@defun custom-add-load symbol load -To the custom option @var{symbol} add the dependency @var{load}. -@var{load} should be either a library file name, or a feature name. -@end defun - -@defun custom-menu-create symbol &optional name -Create menu for customization group @var{symbol}. -If optional @var{name} is given, use that as the name of the menu. -Otherwise make up a name from @var{symbol}. -The menu is in a format applicable to @code{easy-menu-define}. -@end defun - -@node The Init File, Wishlist, Utilities, Top -@comment node-name, next, previous, up -@section The Init File - -When you save the customizations, call to @code{custom-set-variables}, -@code{custom-set-faces} are inserted into the file specified by -@code{custom-file}. By default @code{custom-file} is your @file{.emacs} -file. If you use another file, you must explicitly load it yourself. -The two functions will initialize variables and faces as you have -specified. - -@node Wishlist, , The Init File, Top -@comment node-name, next, previous, up -@section Wishlist - -@itemize @bullet -@item -The menu items should be grayed out when the information is -missing. I.e. if a variable doesn't have a factory setting, the user -should not be allowed to select the @samp{Factory} menu item. - -@item -Better support for keyboard operations in the customize buffer. - -@item -Integrate with @file{w3} so you can customization buffers with much -better formatting. I'm thinking about adding a name -tag. The latest w3 have some support for this, so come up with a -convincing example. - -@item -Add an `examples' section, with explained examples of custom type -definitions. - -@item -Support selectable color themes. I.e., change many faces by setting one -variable. - -@item -Support undo using lmi's @file{gnus-undo.el}. - -@item -Make it possible to append to `choice', `radio', and `set' options. - -@item -Make it possible to customize code, for example to enable or disable a -global minor mode. - -@item -Ask whether set or modified variables should be saved in -@code{kill-buffer-hook}. - -Ditto for @code{kill-emacs-query-functions}. - -@item -Command to check if there are any customization options that -does not belong to an existing group. - -@item -Optionally disable the point-cursor and instead highlight the selected -item in XEmacs. This is like the *Completions* buffer in XEmacs. -Suggested by Jens Lautenbacher -@samp{}.@refill - -@item -Empty customization groups should start open (harder than it looks). - -@item -Make it possible to include a comment/remark/annotation when saving an -option. - -@end itemize - -@contents -@bye diff --git a/texi/widget.texi b/texi/widget.texi deleted file mode 100644 index b733a78..0000000 --- a/texi/widget.texi +++ /dev/null @@ -1,1432 +0,0 @@ -\input texinfo.tex - -@c %**start of header -@setfilename widget -@settitle The Emacs Widget Library -@iftex -@afourpaper -@headings double -@end iftex -@c %**end of header - -@node Top, Introduction, (dir), (dir) -@comment node-name, next, previous, up -@top The Emacs Widget Library - -Version: 1.82 - -@menu -* Introduction:: -* User Interface:: -* Programming Example:: -* Setting Up the Buffer:: -* Basic Types:: -* Sexp Types:: -* Widget Properties:: -* Defining New Widgets:: -* Widget Wishlist.:: -@end menu - -@node Introduction, User Interface, Top, Top -@comment node-name, next, previous, up -@section Introduction - -Most graphical user interface toolkits, such as Motif and XView, provide -a number of standard user interface controls (sometimes known as -`widgets' or `gadgets'). Emacs doesn't really support anything like -this, except for an incredible powerful text ``widget''. On the other -hand, Emacs does provide the necessary primitives to implement many -other widgets within a text buffer. The @code{widget} package -simplifies this task. - -The basic widgets are: - -@table @code -@item link -Areas of text with an associated action. Intended for hypertext links -embedded in text. -@item push-button -Like link, but intended for stand-alone buttons. -@item editable-field -An editable text field. It can be either variable or fixed length. -@item menu-choice -Allows the user to choose one of multiple options from a menu, each -option is itself a widget. Only the selected option will be visible in -the buffer. -@item radio-button-choice -Allows the user to choose one of multiple options by pushing radio -buttons. The options are implemented as widgets. All options will be -visible in the buffer. -@item item -A simple constant widget intended to be used in the @code{menu-choice} and -@code{radio-button-choice} widgets. -@item choice-item -An button item only intended for use in choices. When pushed, the user -will be asked to select another option from the choice widget. -@item toggle -A simple @samp{on}/@samp{off} switch. -@item checkbox -A checkbox (@samp{[ ]}/@samp{[X]}). -@item editable-list -Create an editable list. The user can insert or delete items in the -list. Each list item is itself a widget. -@end table - -Now of what possible use can support for widgets be in a text editor? -I'm glad you asked. The answer is that widgets are useful for -implementing forms. A @dfn{form} in emacs is a buffer where the user is -supposed to fill out a number of fields, each of which has a specific -meaning. The user is not supposed to change or delete any of the text -between the fields. Examples of forms in Emacs are the @file{forms} -package (of course), the customize buffers, the mail and news compose -modes, and the @sc{html} form support in the @file{w3} browser. - -The advantages for a programmer of using the @code{widget} package to -implement forms are: - -@enumerate -@item -More complex field than just editable text are supported. -@item -You can give the user immediate feedback if he enters invalid data in a -text field, and sometimes prevent entering invalid data. -@item -You can have fixed sized fields, thus allowing multiple field to be -lined up in columns. -@item -It is simple to query or set the value of a field. -@item -Editing happens in buffer, not in the mini-buffer. -@item -Packages using the library get a uniform look, making them easier for -the user to learn. -@item -As support for embedded graphics improve, the widget library will -extended to support it. This means that your code using the widget -library will also use the new graphic features by automatic. -@end enumerate - -In order to minimize the code that is loaded by users who does not -create any widgets, the code has been split in two files: - -@table @file -@item widget.el -This will declare the user variables, define the function -@code{widget-define}, and autoload the function @code{widget-create}. -@item wid-edit.el -Everything else is here, there is no reason to load it explicitly, as -it will be autoloaded when needed. -@end table - -@node User Interface, Programming Example, Introduction, Top -@comment node-name, next, previous, up -@section User Interface - -A form consist of read only text for documentation and some fields, -where each the fields contain two parts, as tag and a value. The tags -are used to identify the fields, so the documentation can refer to the -foo field, meaning the field tagged with @samp{Foo}. Here is an example -form: - -@example -Here is some documentation. - -Name: @i{My Name} @strong{Choose}: This option -Address: @i{Some Place -In some City -Some country.} - -See also @b{_other work_} for more information. - -Numbers: count to three below -@b{[INS]} @b{[DEL]} @i{One} -@b{[INS]} @b{[DEL]} @i{Eh, two?} -@b{[INS]} @b{[DEL]} @i{Five!} -@b{[INS]} - -Select multiple: - -@b{[X]} This -@b{[ ]} That -@b{[X]} Thus - -Select one: - -@b{(*)} One -@b{( )} Another One. -@b{( )} A Final One. - -@b{[Apply Form]} @b{[Reset Form]} -@end example - -The top level widgets in is example are tagged @samp{Name}, -@samp{Choose}, @samp{Address}, @samp{_other work_}, @samp{Numbers}, -@samp{Select multiple}, @samp{Select one}, @samp{[Apply Form]}, and -@samp{[Reset Form]}. There are basically two thing the user can do within -a form, namely editing the editable text fields and activating the -buttons. - -@subsection Editable Text Fields - -In the example, the value for the @samp{Name} is most likely displayed -in an editable text field, and so are values for each of the members of -the @samp{Numbers} list. All the normal Emacs editing operations are -available for editing these fields. The only restriction is that each -change you make must be contained within a single editable text field. -For example, capitalizing all text from the middle of one field to the -middle of another field is prohibited. - -Editing text fields are created by the @code{editable-field} widget. - -The editing text fields are highlighted with the -@code{widget-field-face} face, making them easy to find. - -@deffn Face widget-field-face -Face used for other editing fields. -@end deffn - -@subsection Buttons - -Some portions of the buffer have an associated @dfn{action}, which can -be @dfn{activated} by a standard key or mouse command. These portions -are called @dfn{buttons}. The default commands for activating a button -are: - -@table @kbd -@item @key{RET} -@deffn Command widget-button-press @var{pos} &optional @var{event} -Activate the button at @var{pos}, defaulting to point. -If point is not located on a button, activate the binding in -@code{widget-global-map} (by default the global map). -@end deffn - -@item mouse-2 -@deffn Command widget-button-click @var{event} -Activate the button at the location of the mouse pointer. If the mouse -pointer is located in an editable text field, activate the binding in -@code{widget-global-map} (by default the global map). -@end deffn -@end table - -There are several different kind of buttons, all of which are present in -the example: - -@table @emph -@item The Option Field Tags. -When you activate one of these buttons, you will be asked to choose -between a number of different options. This is how you edit an option -field. Option fields are created by the @code{menu-choice} widget. In -the example, @samp{@b{Choose}} is an option field tag. -@item The @samp{@b{[INS]}} and @samp{@b{[DEL]}} buttons. -Activating these will insert or delete elements from a editable list. -The list is created by the @code{editable-list} widget. -@item Embedded Buttons. -The @samp{@b{_other work_}} is an example of an embedded -button. Embedded buttons are not associated with a fields, but can serve -any purpose, such as implementing hypertext references. They are -usually created by the @code{link} widget. -@item The @samp{@b{[ ]}} and @samp{@b{[X]}} buttons. -Activating one of these will convert it to the other. This is useful -for implementing multiple-choice fields. You can create it wit -@item The @samp{@b{( )}} and @samp{@b{(*)}} buttons. -Only one radio button in a @code{radio-button-choice} widget can be selected at any -time. When you push one of the unselected radio buttons, it will be -selected and the previous selected radio button will become unselected. -@item The @samp{@b{[Apply Form]}} @samp{@b{[Reset Form]}} buttons. -These are explicit buttons made with the @code{push-button} widget. The main -difference from the @code{link} widget is that the buttons are will be -displayed as GUI buttons when possible. -enough. -@end table - -To make them easier to locate, buttons are emphasized in the buffer. - -@deffn Face widget-button-face -Face used for buttons. -@end deffn - -@defopt widget-mouse-face -Face used for buttons when the mouse pointer is above it. -@end defopt - -@subsection Navigation - -You can use all the normal Emacs commands to move around in a form -buffer, plus you will have these additional commands: - -@table @kbd -@item @key{TAB} -@deffn Command widget-forward &optional count -Move point @var{count} buttons or editing fields forward. -@end deffn -@item @key{M-TAB} -@deffn Command widget-backward &optional count -Move point @var{count} buttons or editing fields backward. -@end deffn -@end table - -@node Programming Example, Setting Up the Buffer, User Interface, Top -@comment node-name, next, previous, up -@section Programming Example - -Here is the code to implement the user interface example (see @ref{User -Interface}). - -@lisp -(require 'widget) - -(eval-when-compile - (require 'wid-edit)) - -(defvar widget-example-repeat) - -(defun widget-example () - "Create the widgets from the Widget manual." - (interactive) - (switch-to-buffer "*Widget Example*") - (kill-all-local-variables) - (make-local-variable 'widget-example-repeat) - (let ((inhibit-read-only t)) - (erase-buffer)) - (widget-insert "Here is some documentation.\n\nName: ") - (widget-create 'editable-field - :size 13 - "My Name") - (widget-create 'menu-choice - :tag "Choose" - :value "This" - :help-echo "Choose me, please!" - :notify (lambda (widget &rest ignore) - (message "%s is a good choice!" - (widget-value widget))) - '(item :tag "This option" :value "This") - '(choice-item "That option") - '(editable-field :menu-tag "No option" "Thus option")) - (widget-insert "Address: ") - (widget-create 'editable-field - "Some Place\nIn some City\nSome country.") - (widget-insert "\nSee also ") - (widget-create 'link - :notify (lambda (&rest ignore) - (widget-value-set widget-example-repeat - '("En" "To" "Tre")) - (widget-setup)) - "other work") - (widget-insert " for more information.\n\nNumbers: count to three below\n") - (setq widget-example-repeat - (widget-create 'editable-list - :entry-format "%i %d %v" - :notify (lambda (widget &rest ignore) - (let ((old (widget-get widget - ':example-length)) - (new (length (widget-value widget)))) - (unless (eq old new) - (widget-put widget ':example-length new) - (message "You can count to %d." new)))) - :value '("One" "Eh, two?" "Five!") - '(editable-field :value "three"))) - (widget-insert "\n\nSelect multiple:\n\n") - (widget-create 'checkbox t) - (widget-insert " This\n") - (widget-create 'checkbox nil) - (widget-insert " That\n") - (widget-create 'checkbox - :notify (lambda (&rest ignore) (message "Tickle")) - t) - (widget-insert " Thus\n\nSelect one:\n\n") - (widget-create 'radio-button-choice - :value "One" - :notify (lambda (widget &rest ignore) - (message "You selected %s" - (widget-value widget))) - '(item "One") '(item "Anthor One.") '(item "A Final One.")) - (widget-insert "\n") - (widget-create 'push-button - :notify (lambda (&rest ignore) - (if (= (length (widget-value widget-example-repeat)) - 3) - (message "Congratulation!") - (error "Three was the count!"))) - "Apply Form") - (widget-insert " ") - (widget-create 'push-button - :notify (lambda (&rest ignore) - (widget-example)) - "Reset Form") - (widget-insert "\n") - (use-local-map widget-keymap) - (widget-setup)) -@end lisp - -@node Setting Up the Buffer, Basic Types, Programming Example, Top -@comment node-name, next, previous, up -@section Setting Up the Buffer - -Widgets are created with @code{widget-create}, which returns a -@dfn{widget} object. This object can be queried and manipulated by -other widget functions, until it is deleted with @code{widget-delete}. -After the widgets have been created, @code{widget-setup} must be called -to enable them. - -@defun widget-create type [ keyword argument ]@dots{} -Create and return a widget of type @var{type}. -The syntax for the @var{type} argument is described in @ref{Basic Types}. - -The keyword arguments can be used to overwrite the keyword arguments -that are part of @var{type}. -@end defun - -@defun widget-delete widget -Delete @var{widget} and remove it from the buffer. -@end defun - -@defun widget-setup -Setup a buffer to support widgets. - -This should be called after creating all the widgets and before allowing -the user to edit them. -@refill -@end defun - -If you want to insert text outside the widgets in the form, the -recommended way to do that is with @code{widget-insert}. - -@defun widget-insert -Insert the arguments, either strings or characters, at point. -The inserted text will be read only. -@end defun - -There is a standard widget keymap which you might find useful. - -@defvr Const widget-keymap -A keymap with the global keymap as its parent.@* -@key{TAB} and @kbd{C-@key{TAB}} are bound to @code{widget-forward} and -@code{widget-backward}, respectively. @kbd{@key{RET}} and @kbd{mouse-2} -are bound to @code{widget-button-press} and -@code{widget-button-}.@refill -@end defvr - -@defvar widget-global-map -Keymap used by @code{widget-button-press} and @code{widget-button-click} -when not on a button. By default this is @code{global-map}. -@end defvar - -@node Basic Types, Sexp Types, Setting Up the Buffer, Top -@comment node-name, next, previous, up -@section Basic Types - -The syntax of a type specification is given below: - -@example -NAME ::= (NAME [KEYWORD ARGUMENT]... ARGS) - | NAME -@end example - -Where, @var{name} is a widget name, @var{keyword} is the name of a -property, @var{argument} is the value of the property, and @var{args} -are interpreted in a widget specific way. - -There following keyword arguments that apply to all widgets: - -@table @code -@item :value -The initial value for widgets of this type. - -@item :format -This string will be inserted in the buffer when you create a widget. -The following @samp{%} escapes are available: - -@table @samp -@item %[ -@itemx %] -The text inside will be marked as a button. - -@item %@{ -@itemx %@} -The text inside will be displayed with the face specified by -@code{:sample-face}. - -@item %v -This will be replaces with the buffer representation of the widgets -value. What this is depends on the widget type. - -@item %d -Insert the string specified by @code{:doc} here. - -@item %h -Like @samp{%d}, with the following modifications: If the documentation -string is more than one line, it will add a button which will toggle -between showing only the first line, and showing the full text. -Furthermore, if there is no @code{:doc} property in the widget, it will -instead examine the @code{:documentation-property} property. If it is a -lambda expression, it will be called with the widget's value as an -argument, and the result will be used as the documentation text. - -@item %t -Insert the string specified by @code{:tag} here, or the @code{princ} -representation of the value if there is no tag. - -@item %% -Insert a literal @samp{%}. -@end table - -@item :button-face -Face used to highlight text inside %[ %] in the format. - -@item :doc -The string inserted by the @samp{%d} escape in the format -string. - -@item :tag -The string inserted by the @samp{%t} escape in the format -string. - -@item :tag-glyph -Name of image to use instead of the string specified by `:tag' on -Emacsen that supports it. - -@item :help-echo -Message displayed whenever you move to the widget with either -@code{widget-forward} or @code{widget-backward}. - -@item :indent -An integer indicating the absolute number of spaces to indent children -of this widget. - -@item :offset -An integer indicating how many extra spaces to add to the widget's -grandchildren compared to this widget. - -@item :extra-offset -An integer indicating how many extra spaces to add to the widget's -children compared to this widget. - -@item :notify -A function called each time the widget or a nested widget is changed. -The function is called with two or three arguments. The first argument -is the widget itself, the second argument is the widget that was -changed, and the third argument is the event leading to the change, if -any. - -@item :menu-tag -Tag used in the menu when the widget is used as an option in a -@code{menu-choice} widget. - -@item :menu-tag-get -Function used for finding the tag when the widget is used as an option -in a @code{menu-choice} widget. By default, the tag used will be either the -@code{:menu-tag} or @code{:tag} property if present, or the @code{princ} -representation of the @code{:value} property if not. - -@item :match -Should be a function called with two arguments, the widget and a value, -and returning non-nil if the widget can represent the specified value. - -@item :validate -A function which takes a widget as an argument, and return nil if the -widgets current value is valid for the widget. Otherwise, it should -return the widget containing the invalid data, and set that widgets -@code{:error} property to a string explaining the error. - -@item :tab-order -Specify the order in which widgets are traversed with -@code{widget-forward} or @code{widget-backward}. This is only partially -implemented. - -@enumerate a -@item -Widgets with tabbing order @code{-1} are ignored. - -@item -(Unimplemented) When on a widget with tabbing order @var{n}, go to the -next widget in the buffer with tabbing order @var{n+1} or @code{nil}, -whichever comes first. - -@item -When on a widget with no tabbing order specified, go to the next widget -in the buffer with a positive tabbing order, or @code{nil} -@end enumerate - -@item :parent -The parent of a nested widget (e.g. a @code{menu-choice} item or an -element of a @code{editable-list} widget). - -@item :sibling-args -This keyword is only used for members of a @code{radio-button-choice} or -@code{checklist}. The value should be a list of extra keyword -arguments, which will be used when creating the @code{radio-button} or -@code{checkbox} associated with this item. - -@end table - -@deffn {User Option} widget-glyph-directory -Directory where glyphs are found. -Widget will look here for a file with the same name as specified for the -image, with either a @samp{.xpm} (if supported) or @samp{.xbm} extension. -@end deffn - -@deffn{User Option} widget-glyph-enable -If non-nil, allow glyphs to appear on displayes where they are supported. -@end deffn - - -@menu -* link:: -* url-link:: -* info-link:: -* push-button:: -* editable-field:: -* text:: -* menu-choice:: -* radio-button-choice:: -* item:: -* choice-item:: -* toggle:: -* checkbox:: -* checklist:: -* editable-list:: -@end menu - -@node link, url-link, Basic Types, Basic Types -@comment node-name, next, previous, up -@subsection The @code{link} Widget - -Syntax: - -@example -TYPE ::= (link [KEYWORD ARGUMENT]... [ VALUE ]) -@end example - -The @var{value}, if present, is used to initialize the @code{:value} -property. The value should be a string, which will be inserted in the -buffer. - -@node url-link, info-link, link, Basic Types -@comment node-name, next, previous, up -@subsection The @code{url-link} Widget - -Syntax: - -@example -TYPE ::= (url-link [KEYWORD ARGUMENT]... URL) -@end example - -When this link is activated, the @sc{www} browser specified by -@code{browse-url-browser-function} will be called with @var{url}. - -@node info-link, push-button, url-link, Basic Types -@comment node-name, next, previous, up -@subsection The @code{info-link} Widget - -Syntax: - -@example -TYPE ::= (info-link [KEYWORD ARGUMENT]... ADDRESS) -@end example - -When this link is activated, the build-in info browser is started on -@var{address}. - -@node push-button, editable-field, info-link, Basic Types -@comment node-name, next, previous, up -@subsection The @code{push-button} Widget - -Syntax: - -@example -TYPE ::= (push-button [KEYWORD ARGUMENT]... [ VALUE ]) -@end example - -The @var{value}, if present, is used to initialize the @code{:value} -property. The value should be a string, which will be inserted in the -buffer. - -The following extra properties are recognized. - -@table @code -@item :text-format -The format string used when the push button cannot be displayed -graphically. There are two escapes, @code{%s}, which must be present -exactly once, will be substituted with the tag, and @code{%%} will be -substituted with a singe @samp{%}. -@end table - -By default the tag will be shown in brackets. - -@node editable-field, text, push-button, Basic Types -@comment node-name, next, previous, up -@subsection The @code{editable-field} Widget - -Syntax: - -@example -TYPE ::= (editable-field [KEYWORD ARGUMENT]... [ VALUE ]) -@end example - -The @var{value}, if present, is used to initialize the @code{:value} -property. The value should be a string, which will be inserted in -field. This widget will match all string values. - -The following extra properties are recognized. - -@table @code -@item :size -The width of the editable field.@* -By default the field will reach to the end of the line. - -@item :value-face -Face used for highlighting the editable field. Default is -@code{widget-field-face}. - -@item :secret -Character used to display the value. You can set this to e.g. @code{?*} -if the field contains a password or other secret information. By -default, the value is not secret. - -@item :valid-regexp -By default the @code{:validate} function will match the content of the -field with the value of this attribute. The default value is @code{""} -which matches everything. - -@item :keymap -Keymap used in the editable field. The default value is -@code{widget-field-keymap}, which allows you to use all the normal -editing commands, even if the buffers major mode supress some of them. -Pressing return activates the function specified by @code{:activate}. - -@item :hide-front-space -@itemx :hide-rear-space -In order to keep track of the editable field, emacs places an invisible -space character in front of the field, and for fixed sized fields also -in the rear end of the field. For fields that extent to the end of the -line, the terminating linefeed serves that purpose instead. - -Emacs will try to make the spaces intangible when it is safe to do so. -Intangible means that the cursor motion commands will skip over the -character as if it didn't exist. This is safe to do when the text -preceding or following the widget cannot possible change during the -lifetime of the @code{editable-field} widget. The preferred way to tell -Emacs this, is to add text to the @code{:format} property around the -value. For example @code{:format "Tag: %v "}. - -You can overwrite the internal safety check by setting the -@code{:hide-front-space} or @code{:hide-rear-space} properties to -non-nil. This is not recommended. For example, @emph{all} text that -belongs to a widget (i.e. is created from its @code{:format} string) will -change whenever the widget changes its value. - -@end table - -@node text, menu-choice, editable-field, Basic Types -@comment node-name, next, previous, up -@subsection The @code{text} Widget - -This is just like @code{editable-field}, but intended for multiline text -fields. The default @code{:keymap} is @code{widget-text-keymap}, which -does not rebind the return key. - -@node menu-choice, radio-button-choice, text, Basic Types -@comment node-name, next, previous, up -@subsection The @code{menu-choice} Widget - -Syntax: - -@example -TYPE ::= (menu-choice [KEYWORD ARGUMENT]... TYPE ... ) -@end example - -The @var{type} arguments represents each possible choice. The widgets -value of will be the value of the chosen @var{type} argument. This -widget will match any value that matches at least one of the specified -@var{type} arguments. - -@table @code -@item :void -Widget type used as a fallback when the value does not match any of the -specified @var{type} arguments. - -@item :case-fold -Set this to nil if you don't want to ignore case when prompting for a -choice through the minibuffer. - -@item :children -A list whose car is the widget representing the currently chosen type in -the buffer. - -@item :choice -The current chosen type - -@item :args -The list of types. -@end table - -@node radio-button-choice, item, menu-choice, Basic Types -@comment node-name, next, previous, up -@subsection The @code{radio-button-choice} Widget - -Syntax: - -@example -TYPE ::= (radio-button-choice [KEYWORD ARGUMENT]... TYPE ... ) -@end example - -The @var{type} arguments represents each possible choice. The widgets -value of will be the value of the chosen @var{type} argument. This -widget will match any value that matches at least one of the specified -@var{type} arguments. - -The following extra properties are recognized. - -@table @code -@item :entry-format -This string will be inserted for each entry in the list. -The following @samp{%} escapes are available: -@table @samp -@item %v -Replaced with the buffer representation of the @var{type} widget. -@item %b -Replace with the radio button. -@item %% -Insert a literal @samp{%}. -@end table - -@item button-args -A list of keywords to pass to the radio buttons. Useful for setting -e.g. the @samp{:help-echo} for each button. - -@item :buttons -The widgets representing the radio buttons. - -@item :children -The widgets representing each type. - -@item :choice -The current chosen type - -@item :args -The list of types. -@end table - -You can add extra radio button items to a @code{radio-button-choice} -widget after it has been created with the function -@code{widget-radio-add-item}. - -@defun widget-radio-add-item widget type -Add to @code{radio-button-choice} widget @var{widget} a new radio button item of type -@var{type}. -@end defun - -Please note that such items added after the @code{radio-button-choice} -widget has been created will @strong{not} be properly destructed when -you call @code{widget-delete}. - -@node item, choice-item, radio-button-choice, Basic Types -@comment node-name, next, previous, up -@subsection The @code{item} Widget - -Syntax: - -@example -ITEM ::= (item [KEYWORD ARGUMENT]... VALUE) -@end example - -The @var{value}, if present, is used to initialize the @code{:value} -property. The value should be a string, which will be inserted in the -buffer. This widget will only match the specified value. - -@node choice-item, toggle, item, Basic Types -@comment node-name, next, previous, up -@subsection The @code{choice-item} Widget - -Syntax: - -@example -ITEM ::= (choice-item [KEYWORD ARGUMENT]... VALUE) -@end example - -The @var{value}, if present, is used to initialize the @code{:value} -property. The value should be a string, which will be inserted in the -buffer as a button. Activating the button of a @code{choice-item} is -equivalent to activating the parent widget. This widget will only match -the specified value. - -@node toggle, checkbox, choice-item, Basic Types -@comment node-name, next, previous, up -@subsection The @code{toggle} Widget - -Syntax: - -@example -TYPE ::= (toggle [KEYWORD ARGUMENT]...) -@end example - -The widget has two possible states, `on' and `off', which corresponds to -a @code{t} or @code{nil} value. - -The following extra properties are recognized. - -@table @code -@item :on -String representing the `on' state. By default the string @samp{on}. -@item :off -String representing the `off' state. By default the string @samp{off}. -@item :on-glyph -Name of a glyph to be used instead of the `:on' text string, on emacsen -that supports it. -@item :off-glyph -Name of a glyph to be used instead of the `:off' text string, on emacsen -that supports it. -@end table - -@node checkbox, checklist, toggle, Basic Types -@comment node-name, next, previous, up -@subsection The @code{checkbox} Widget - -The widget has two possible states, `selected' and `unselected', which -corresponds to a @code{t} or @code{nil} value. - -Syntax: - -@example -TYPE ::= (checkbox [KEYWORD ARGUMENT]...) -@end example - -@node checklist, editable-list, checkbox, Basic Types -@comment node-name, next, previous, up -@subsection The @code{checklist} Widget - -Syntax: - -@example -TYPE ::= (checklist [KEYWORD ARGUMENT]... TYPE ... ) -@end example - -The @var{type} arguments represents each checklist item. The widgets -value of will be a list containing the value of each ticked @var{type} -argument. The checklist widget will match a list whose elements all -matches at least one of the specified @var{type} arguments. - -The following extra properties are recognized. - -@table @code -@item :entry-format -This string will be inserted for each entry in the list. -The following @samp{%} escapes are available: -@table @samp -@item %v -Replaced with the buffer representation of the @var{type} widget. -@item %b -Replace with the checkbox. -@item %% -Insert a literal @samp{%}. -@end table - -@item button-args -A list of keywords to pass to the checkboxes. Useful for setting -e.g. the @samp{:help-echo} for each checkbox. - -@item :buttons -The widgets representing the checkboxes. - -@item :children -The widgets representing each type. - -@item :args -The list of types. -@end table - -@node editable-list, , checklist, Basic Types -@comment node-name, next, previous, up -@subsection The @code{editable-list} Widget - -Syntax: - -@example -TYPE ::= (editable-list [KEYWORD ARGUMENT]... TYPE) -@end example - -The value is a list, where each member represent one widget of type -@var{type}. - -The following extra properties are recognized. - -@table @code -@item :entry-format -This string will be inserted for each entry in the list. -The following @samp{%} escapes are available: -@table @samp -@item %v -This will be replaced with the buffer representation of the @var{type} -widget. -@item %i -Insert the @b{[INS]} button. -@item %d -Insert the @b{[DEL]} button. -@item %% -Insert a literal @samp{%}. -@end table - -@item :insert-button-args -A list of keyword arguments to pass to the insert buttons. - -@item :delete-button-args -A list of keyword arguments to pass to the delete buttons. - -@item :append-button-args -A list of keyword arguments to pass to the trailing insert button. - - -@item :buttons -The widgets representing the insert and delete buttons. - -@item :children -The widgets representing the elements of the list. - -@item :args -List whose car is the type of the list elements. - -@end table - -@node Sexp Types, Widget Properties, Basic Types, Top -@comment -@section Sexp Types - -A number of widgets for editing s-expressions (lisp types) are also -available. These basically fall in three categories: @dfn{atoms}, -@dfn{composite types}, and @dfn{generic}. - -@menu -* generic:: -* atoms:: -* composite:: -@end menu - -@node generic, atoms, Sexp Types, Sexp Types -@comment node-name, next, previous, up -@subsection The Generic Widget. - -The @code{const} and @code{sexp} widgets can contain any lisp -expression. In the case of the @code{const} widget the user is -prohibited from editing edit it, which is mainly useful as a component -of one of the composite widgets. - -The syntax for the generic widgets is - -@example -TYPE ::= (const [KEYWORD ARGUMENT]... [ VALUE ]) -@end example - -The @var{value}, if present, is used to initialize the @code{:value} -property and can be any s-expression. - -@deffn Widget const -This will display any valid s-expression in an immutable part of the -buffer. -@end deffn - -@deffn Widget sexp -This will allow you to edit any valid s-expression in an editable buffer -field. - -The @code{sexp} widget takes the same keyword arguments as the -@code{editable-field} widget. -@end deffn - -@node atoms, composite, generic, Sexp Types -@comment node-name, next, previous, up -@subsection Atomic Sexp Widgets. - -The atoms are s-expressions that does not consist of other -s-expressions. A string is an atom, while a list is a composite type. -You can edit the value of an atom with the following widgets. - -The syntax for all the atoms are - -@example -TYPE ::= (NAME [KEYWORD ARGUMENT]... [ VALUE ]) -@end example - -The @var{value}, if present, is used to initialize the @code{:value} -property and must be an expression of the same type as the widget. -I.e. the string widget can only be initialized with a string. - -All the atom widgets take the same keyword arguments as the @code{editable-field} -widget. - -@deffn Widget string -Allows you to edit a string in an editable field. -@end deffn - -@deffn Widget file -Allows you to edit a file name in an editable field. You you activate -the tag button, you can edit the file name in the mini-buffer with -completion. - -Keywords: -@table @code -@item :must-match -If this is set to non-nil, only existing file names will be allowed in -the minibuffer. -@end table -@end deffn - -@deffn Widget directory -Allows you to edit a directory name in an editable field. -Similar to the @code{file} widget. -@end deffn - -@deffn Widget symbol -Allows you to edit a lisp symbol in an editable field. -@end deffn - -@deffn Widget integer -Allows you to edit an integer in an editable field. -@end deffn - -@deffn Widget number -Allows you to edit a number in an editable field. -@end deffn - -@deffn Widget boolean -Allows you to edit a boolean. In lisp this means a variable which is -either nil meaning false, or non-nil meaning true. -@end deffn - - -@node composite, , atoms, Sexp Types -@comment node-name, next, previous, up -@subsection Composite Sexp Widgets. - -The syntax for the composite are - -@example -TYPE ::= (NAME [KEYWORD ARGUMENT]... COMPONENT...) -@end example - -Where each @var{component} must be a widget type. Each component widget -will be displayed in the buffer, and be editable to the user. - -@deffn Widget cons -The value of a @code{cons} widget is a cons-cell where the car is the -value of the first component and the cdr is the value of the second -component. There must be exactly two components. -@end deffn - -@deffn Widget lisp -The value of a @code{lisp} widget is a list containing the value of -each of its component. -@end deffn - -@deffn Widget vector -The value of a @code{vector} widget is a vector containing the value of -each of its component. -@end deffn - -The above suffice for specifying fixed size lists and vectors. To get -variable length lists and vectors, you can use a @code{choice}, -@code{set} or @code{repeat} widgets together with the @code{:inline} -keywords. If any component of a composite widget has the @code{:inline} -keyword set, its value must be a list which will then be spliced into -the composite. For example, to specify a list whose first element must -be a file name, and whose remaining arguments should either by the -symbol @code{t} or two files, you can use the following widget -specification: - -@example -(list file - (choice (const t) - (list :inline t - :value ("foo" "bar") - string string))) -@end example - -The value of a widget of this type will either have the form -@samp{(file t)} or @code{(file string string)}. - -This concept of inline is probably hard to understand. It was certainly -hard to implement so instead of confuse you more by trying to explain it -here, I'll just suggest you meditate over it for a while. - -@deffn Widget choice -Allows you to edit a sexp which may have one of fixed set of types. It -is currently implemented with the @code{choice-menu} basic widget, and -has a similar syntax. -@end deffn - -@deffn Widget set -Allows you to specify a type which must be a list whose elements all -belong to given set. The elements of the list is not significant. This -is implemented on top of the @code{checklist} basic widget, and has a -similar syntax. -@end deffn - -@deffn Widget repeat -Allows you to specify a variable length list whose members are all of -the same type. Implemented on top of the `editable-list' basic widget, -and has a similar syntax. -@end deffn - -@node Widget Properties, Defining New Widgets, Sexp Types, Top -@comment node-name, next, previous, up -@section Properties - -You can examine or set the value of a widget by using the widget object -that was returned by @code{widget-create}. - -@defun widget-value widget -Return the current value contained in @var{widget}. -It is an error to call this function on an uninitialized widget. -@end defun - -@defun widget-value-set widget value -Set the value contained in @var{widget} to @var{value}. -It is an error to call this function with an invalid @var{value}. -@end defun - -@strong{Important:} You @emph{must} call @code{widget-setup} after -modifying the value of a widget before the user is allowed to edit the -widget again. It is enough to call @code{widget-setup} once if you -modify multiple widgets. This is currently only necessary if the widget -contains an editing field, but may be necessary for other widgets in the -future. - -If your application needs to associate some information with the widget -objects, for example a reference to the item being edited, it can be -done with @code{widget-put} and @code{widget-get}. The property names -must begin with a @samp{:}. - -@defun widget-put widget property value -In @var{widget} set @var{property} to @var{value}. -@var{property} should be a symbol, while @var{value} can be anything. -@end defun - -@defun widget-get widget property -In @var{widget} return the value for @var{property}. -@var{property} should be a symbol, the value is what was last set by -@code{widget-put} for @var{property}. -@end defun - -@defun widget-member widget property -Non-nil if @var{widget} has a value (even nil) for property @var{property}. -@end defun - -Occasionally it can be useful to know which kind of widget you have, -i.e. the name of the widget type you gave when the widget was created. - -@defun widget-type widget -Return the name of @var{widget}, a symbol. -@end defun - -Widgets can be in two states: active, which means they are modifiable by -the user, or inactive, which means they cannot be modified by the user. -You can query or set the state with the following code: - -@lisp -;; Examine if @var{widget} is active or not. -(if (widget-apply @var{widget} :active) - (message "Widget is active.") - (message "Widget is inactive.") - -;; Make @var{widget} inactive. -(widget-apply @var{widget} :deactivate) - -;; Make @var{widget} active. -(widget-apply @var{widget} :activate) -@end lisp - -A widget is inactive if itself, or any of its ancestors (found by -following the @code{:parent} link) have been deactivated. To make sure -a widget is really active, you must therefore activate both itself, and -all its ancestors. - -@lisp -(while widget - (widget-apply widget :activate) - (setq widget (widget-get widget :parent))) -@end lisp - -You can check if a widget has been made inactive by examining the value -of @code{:inactive} keyword. If this is non-nil, the widget itself has -been deactivated. This is different from using the @code{:active} -keyword, in that the later tell you if the widget @strong{or} any of its -ancestors have been deactivated. Do not attempt to set the -@code{:inactive} keyword directly. Use the @code{:activate} -@code{:deactivated} keywords instead. - - -@node Defining New Widgets, Widget Wishlist., Widget Properties, Top -@comment node-name, next, previous, up -@section Defining New Widgets - -You can define specialized widgets with @code{define-widget}. It allows -you to create a shorthand for more complex widgets, including specifying -component widgets and default new default values for the keyword -arguments. - -@defun widget-define name class doc &rest args -Define a new widget type named @var{name} from @code{class}. - -@var{name} and class should both be symbols, @code{class} should be one -of the existing widget types. - -The third argument @var{DOC} is a documentation string for the widget. - -After the new widget has been defined, the following two calls will -create identical widgets: - -@itemize @bullet -@item -@lisp -(widget-create @var{name}) -@end lisp - -@item -@lisp -(apply widget-create @var{class} @var{args}) -@end lisp -@end itemize - -@end defun - -Using @code{widget-define} does just store the definition of the widget -type in the @code{widget-type} property of @var{name}, which is what -@code{widget-create} uses. - -If you just want to specify defaults for keywords with no complex -conversions, you can use @code{identity} as your conversion function. - -The following additional keyword arguments are useful when defining new -widgets: -@table @code -@item :convert-widget -Function to convert a widget type before creating a widget of that -type. It takes a widget type as an argument, and returns the converted -widget type. When a widget is created, this function is called for the -widget type and all the widgets parent types, most derived first. - -@item :value-to-internal -Function to convert the value to the internal format. The function -takes two arguments, a widget and an external value, and returns the -internal value. The function is called on the present @code{:value} -when the widget is created, and on any value set later with -@code{widget-value-set}. - -@item :value-to-external -Function to convert the value to the external format. The function -takes two arguments, a widget and an internal value, and returns the -internal value. The function is called on the present @code{:value} -when the widget is created, and on any value set later with -@code{widget-value-set}. - -@item :create -Function to create a widget from scratch. The function takes one -argument, a widget type, and create a widget of that type, insert it in -the buffer, and return a widget object. - -@item :delete -Function to delete a widget. The function takes one argument, a widget, -and should remove all traces of the widget from the buffer. - -@item :value-create -Function to expand the @samp{%v} escape in the format string. It will -be called with the widget as its argument. Should -insert a representation of the widgets value in the buffer. - -@item :value-delete -Should remove the representation of the widgets value from the buffer. -It will be called with the widget as its argument. It doesn't have to -remove the text, but it should release markers and delete nested widgets -if such has been used. - -@item :format-handler -Function to handle unknown @samp{%} escapes in the format string. It -will be called with the widget and the escape character as arguments. -You can set this to allow your widget to handle non-standard escapes. - -You should end up calling @code{widget-default-format-handler} to handle -unknown escape sequences, which will handle the @samp{%h} and any future -escape sequences, as well as give an error for unknown escapes. -@end table - -If you want to define a new widget from scratch, use the @code{default} -widget as its base. - -@deffn Widget default [ keyword argument ] -Widget used as a base for other widgets. - -It provides most of the functionality that is referred to as ``by -default'' in this text. -@end deffn - -@node Widget Wishlist., , Defining New Widgets, Top -@comment node-name, next, previous, up -@section Wishlist. - -@itemize @bullet -@item -It should be possible to add or remove items from a list with @kbd{C-k} -and @kbd{C-o} (suggested by @sc{rms}). - -@item -The @samp{[INS]} and @samp{[DEL]} buttons should be replaced by a single -dash (@samp{-}). The dash should be a button that, when activated, ask -whether you want to add or delete an item (@sc{rms} wanted to git rid of -the ugly buttons, the dash is my idea). - -@item -Widgets such as @code{file} and @code{symbol} should prompt with completion. - -@item -The @code{menu-choice} tag should be prettier, something like the abbreviated -menus in Open Look. - -@item -The functions used in many widgets, like -@code{widget-item-convert-widget}, should not have names that are -specific to the first widget where I happended to use them. - -@item -Flag to make @code{widget-move} skip a specified button. - -@item -Document `helper' functions for defining new widgets. - -@item -Activate the item this is below the mouse when the button is -released, not the item this is below the mouse when the button is -pressed. Dired and grep gets this right. Give feedback if possible. - -@item -Use @samp{@@deffn Widget} to document widgets. - -@item -Document global keywords in one place. - -Document keywords particular to a specific widget in the widget -definition. - -Document the `default' widget first. - -Split, when needed, keywords into those useful for normal -customization, those primarily useful when deriving, and those who -represent runtime information. - -@item -Figure out terminology and @sc{api} for the class/type/object/super -stuff. - -Perhaps the correct model is delegation? - -@item -Document @code{widget-browse}. - -@item -Make indentation work with glyphs and propertional fonts. - -@item -Add object and class hierarchies to the browser. - -@end itemize - -@contents -@bye -- 1.7.10.4