Mercurial > hg > xemacs-beta
changeset 1309:00abb1091204
[xemacs-hg @ 2003-02-17 14:50:55 by stephent]
charsets-in-region optimization <874r73qa2b.fsf@tleepslib.sk.tsukuba.ac.jp>
wid-edit.el synch <87znovote9.fsf@tleepslib.sk.tsukuba.ac.jp>
author | stephent |
---|---|
date | Mon, 17 Feb 2003 14:51:02 +0000 |
parents | 1741c7ce4ac0 |
children | 903c87981807 |
files | lisp/ChangeLog lisp/mule/mule-charset.el lisp/wid-edit.el |
diffstat | 3 files changed, 326 insertions(+), 179 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Sun Feb 16 22:52:43 2003 +0000 +++ b/lisp/ChangeLog Mon Feb 17 14:51:02 2003 +0000 @@ -1,3 +1,9 @@ +2003-02-17 Stephen J. Turnbull <stephen@xemacs.org> + + * mule/mule-charset.el (charsets-in-region): Remove broken + optimization to get slight speed-up. + (charsets-in-string): Use mapc to iterate in C. + 2003-02-16 Steve Youngs <youngs@xemacs.org> * XEmacs 21.5.11 "cabbage" is released.
--- a/lisp/mule/mule-charset.el Sun Feb 16 22:52:43 2003 +0000 +++ b/lisp/mule/mule-charset.el Mon Feb 17 14:51:02 2003 +0000 @@ -38,6 +38,12 @@ ;;;; Classifying text according to charsets +;; the old version was broken in a couple of ways +;; this is one of several versions, I tried a hash as well as the +;; `prev-charset' cache used in the old version, but this was definitely +;; faster than the hash version and marginally faster than the prev-charset +;; version +;; #### this really needs to be moved into C (defun charsets-in-region (start end &optional buffer) "Return a list of the charsets in the region between START and END. BUFFER defaults to the current buffer if omitted." @@ -49,30 +55,22 @@ (narrow-to-region start end) (goto-char (point-min)) (while (not (eobp)) - (let* (prev-charset - (ch (char-after (point))) - (charset (char-charset ch))) - (if (not (eq prev-charset charset)) - (progn - (setq prev-charset charset) - (or (memq charset list) - (setq list (cons charset list)))))) + ;; the first test will usually succeed on testing the + ;; car of the list; don't waste time let-binding. + (or (memq (char-charset (char-after (point))) list) + (setq list (cons (char-charset (char-after (point))) list))) (forward-char)))) list)) (defun charsets-in-string (string) "Return a list of the charsets in STRING." - (let ((i 0) - (len (length string)) - prev-charset charset list) - (while (< i len) - (setq charset (char-charset (aref string i))) - (if (not (eq prev-charset charset)) - (progn - (setq prev-charset charset) - (or (memq charset list) - (setq list (cons charset list))))) - (setq i (1+ i))) + (let (list) + (mapc (lambda (ch) + ;; the first test will usually succeed on testing the + ;; car of the list; don't waste time let-binding. + (or (memq (char-charset ch) list) + (setq list (cons (char-charset ch) list)))) + string) list)) (defalias 'find-charset-string 'charsets-in-string)
--- a/lisp/wid-edit.el Sun Feb 16 22:52:43 2003 +0000 +++ b/lisp/wid-edit.el Mon Feb 17 14:51:02 2003 +0000 @@ -1,6 +1,6 @@ ;;; wid-edit.el --- Functions for creating and using widgets. ;; -;; Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc. +;; Copyright (C) 1996-1997, 1999-2002 Free Software Foundation, Inc. ;; ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> ;; Maintainer: Hrvoje Niksic <hniksic@xemacs.org> @@ -27,7 +27,7 @@ ;;; Commentary: ;; -;; See `widget.el'. +;; See `widget.el' and the wishlist in `../man/widget.texi'. ;;; Code: @@ -85,7 +85,14 @@ :type 'face :group 'widget-faces) -(defface widget-field-face '((((class grayscale color) +;; #### comment from GNU Emacs 21.3.50, test the first spec. +;; TTY gets special definitions here and in the next defface, because +;; the gray colors defined for other displays cause black text on a black +;; background, at least on light-background TTYs. +(defface widget-field-face '((((type tty)) + (:background "yellow3") + (:foreground "black")) + (((class grayscale color) (background light)) (:background "gray85")) (((class grayscale color) @@ -145,9 +152,9 @@ plist)) (defun widget-princ-to-string (object) - ;; Return string representation of OBJECT, any Lisp object. - ;; No quoting characters are used; no delimiters are printed around - ;; the contents of strings. + "Return string representation of OBJECT, any Lisp object. +No quoting characters are used; no delimiters are printed around +the contents of strings." (with-current-buffer (get-buffer-create " *widget-tmp*") (erase-buffer) (princ object (current-buffer)) @@ -176,6 +183,13 @@ :group 'widgets :type 'integer) +(defcustom widget-menu-max-shortcuts 40 + "Largest number of items for which it works to choose one with a character. +For a larger number of items, the minibuffer is used. +#### Not yet implemented in XEmacs." + :group 'widgets + :type 'integer) + (defcustom widget-menu-minibuffer-flag nil "*Control how to ask for a choice from the keyboard. Non-nil means use the minibuffer; @@ -276,6 +290,15 @@ (cdr (assoc val items))) nil))))) +;; GNU Emacs 21.3.50 uses this in `widget-choose' +(defun widget-remove-if (predicate list) + (let (result (tail list)) + (while tail + (or (funcall predicate (car tail)) + (setq result (cons (car tail) result))) + (setq tail (cdr tail))) + (nreverse result))) + ;;; Widget text specifications. ;; @@ -401,7 +424,7 @@ (format "(widget %S :help-echo %S)" widget help-echo))))) (defun widget-specify-sample (widget from to) - ;; Specify sample for WIDGET between FROM and TO. + "Specify sample for WIDGET between FROM and TO." (let ((face (widget-apply widget :sample-face-get)) (extent (make-extent from to nil))) (set-extent-property extent 'start-open t) @@ -409,7 +432,7 @@ (widget-put widget :sample-extent extent))) (defun widget-specify-doc (widget from to) - ;; Specify documentation for WIDGET between FROM and TO. + "Specify documentation for WIDGET between FROM and TO." (let ((extent (make-extent from to))) (set-extent-property extent 'start-open t) (set-extent-property extent 'widget-doc widget) @@ -551,6 +574,15 @@ "Return the type of WIDGET, a symbol." (car widget)) +;;;###autoload +(defun widgetp (widget) + "Return non-nil iff WIDGET is a widget." + (if (symbolp widget) + (get widget 'widget-type) + (and (consp widget) + (symbolp (car widget)) + (get (car widget) 'widget-type)))) + (when (or (not (fboundp 'widget-put)) widget-shadow-subrs) (defun widget-put (widget property value) @@ -655,8 +687,7 @@ (defun widget-get-sibling (widget) "Get the item WIDGET is assumed to toggle. This is only meaningful for radio buttons or checkboxes in a list." - (let* ((parent (widget-get widget :parent)) - (children (widget-get parent :children)) + (let* ((children (widget-get (widget-get widget :parent) :children)) child) (catch 'child (while children @@ -684,17 +715,21 @@ ;;; Glyphs. (defcustom widget-glyph-directory (locate-data-directory "custom") - "Where widget glyphs are located. + "Where widget button glyphs are located. If this variable is nil, widget will try to locate the directory automatically." :group 'widgets :type 'directory) (defcustom widget-glyph-enable t - "If non nil, use glyphs in images when available." + "If non nil, use glyph buttons in widgets when available." :group 'widgets :type 'boolean) +;; #### What happens if you try to customize this? +(define-compatible-variable-alias 'widget-image-conversion + 'widget-image-file-name-suffixes) + (defcustom widget-image-file-name-suffixes '((xpm ".xpm") (gif ".gif") (png ".png") (jpeg ".jpg" ".jpeg") (xbm ".xbm")) @@ -903,6 +938,10 @@ "Delete WIDGET." (widget-apply widget :delete)) +(defun widget-copy (widget) + "Make a deep copy of WIDGET." + (widget-apply (copy-sequence widget) :copy)) + (defun widget-convert (type &rest args) "Convert TYPE to a widget without inserting it in the buffer. The optional ARGS are additional keyword arguments." @@ -935,19 +974,21 @@ ;; Finally set the keyword args. (while keys (let ((next (nth 0 keys))) - (if (and (symbolp next) (eq (aref (symbol-name next) 0) ?:)) + (if (keywordp next) (progn (widget-put widget next (nth 1 keys)) (setq keys (nthcdr 2 keys))) (setq keys nil)))) ;; Convert the :value to internal format. (if (widget-member widget :value) - (let ((value (widget-get widget :value))) - (widget-put widget - :value (widget-apply widget :value-to-internal value)))) + (widget-put widget + :value (widget-apply widget + :value-to-internal + (widget-get widget :value)))) ;; Return the newly created widget. widget)) +;;;###autoload (defun widget-insert (&rest args) "Call `insert' with ARGS even if surrounding text is read only." (let ((inhibit-read-only t) @@ -991,13 +1032,12 @@ (button (widget-get widget :button-extent)) (sample (widget-get widget :sample-extent)) (doc (widget-get widget :doc-extent)) - (field (widget-get widget :field-extent)) - (children (widget-get widget :children))) + (field (widget-get widget :field-extent))) (set-marker from nil) (set-marker to nil) ;; Maybe we should delete the extents here? As this code doesn't ;; remove them from widget structures, maybe it's safer to just - ;; detach them. That's what `delete-overlay' did. + ;; detach them. That's what GNU-compatible `delete-overlay' does. (when button (detach-extent button)) (when sample @@ -1006,7 +1046,7 @@ (detach-extent doc)) (when field (detach-extent field)) - (mapc 'widget-leave-text children))) + (mapc 'widget-leave-text (widget-get widget :children)))) ;;; Keymap and Commands. @@ -1414,6 +1454,13 @@ ;; List of all editable fields in the buffer. (make-variable-buffer-local 'widget-field-list) +;; Is this a misnomer? +(defun widget-at (pos) + "The button or field at POS." + (or (get-char-property pos 'button) + (get-char-property pos 'field))) + +;;;###autoload (defun widget-setup () "Setup current buffer so editing string widgets works." (let ((inhibit-read-only t) @@ -1446,6 +1493,13 @@ ;; The widget data before the change. (make-variable-buffer-local 'widget-field-was) +(defun widget-field-at (pos) + "Return the widget field at POS, or nil if none." + (let ((field (get-char-property (or pos (point)) 'field))) + (if (eq field 'boundary) + nil + field))) + (defun widget-field-buffer (widget) "Return the buffer containing WIDGET. @@ -1480,27 +1534,13 @@ Warning: using this function after creating the widget but before invoking `widget-setup' will always fail." + ;; XEmacs: use `map-extents' instead of a while loop (let ((field-extent (map-extents (lambda (extent ignore) extent) nil pos pos nil nil 'field))) (and field-extent (extent-property field-extent 'field)))) -;; Old version, without `map-extents'. -;(defun widget-field-find (pos) -; (let ((fields widget-field-list) -; field found) -; (while fields -; (setq field (car fields) -; fields (cdr fields)) -; (let ((start (widget-field-start field)) -; (end (widget-field-end field))) -; (when (and (<= start pos) (<= pos end)) -; (when found -; (debug "Overlapping fields")) -; (setq found field)))) -; found)) - ;; Warning: using this function after creating the widget but before ;; invoking `widget-setup' will always fail. (defun widget-before-change (from to) @@ -1541,10 +1581,10 @@ (add-hook 'after-change-functions 'widget-after-change nil t)) (defun widget-after-change (from to old) - ;; Adjust field size and text properties. - - ;; Also, notify the widgets (so, for example, a variable changes its - ;; state to `modified'. when it is being edited.) + "Adjust field size and text properties. + +Also, notify the widgets (so, for example, a variable changes its +state to `modified'. when it is being edited)." (condition-case nil (let ((field (widget-field-find from)) (other (widget-field-find to))) @@ -1604,7 +1644,13 @@ found (widget-apply child :validate))) found)) -(defun widget-types-convert-widget (widget) +(defun widget-types-copy (widget) + "Copy :args as widget types in WIDGET." + (widget-put widget :args (mapcar 'widget-copy (widget-get widget :args))) + widget) + +;; Made defsubst to speed up face editor creation. +(defsubst widget-types-convert-widget (widget) "Convert :args as widget types in WIDGET." (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args))) widget) @@ -1645,11 +1691,11 @@ :value-inline 'widget-default-value-inline :default-get 'widget-default-default-get :menu-tag-get 'widget-default-menu-tag-get - :validate (lambda (widget) nil) + :validate #'ignore :active 'widget-default-active :activate 'widget-specify-active :deactivate 'widget-default-deactivate - :mouse-down-action (lambda (widget event) nil) + :mouse-down-action #'ignore :action 'widget-default-action :notify 'widget-default-notify :prompt-value 'widget-default-prompt-value) @@ -1657,8 +1703,8 @@ (defun widget-default-complete (widget) "Call the value of the :complete-function property of WIDGET. If that does not exists, call the value of `widget-complete-field'." - (let ((fun (widget-get widget :complete-function))) - (call-interactively (or fun widget-complete-field)))) + (call-interactively (or (widget-get widget :complete-function) + widget-complete-field))) (defun widget-default-create (widget) "Create WIDGET at point in the current buffer." @@ -1670,13 +1716,13 @@ value-pos) (insert (widget-get widget :format)) (goto-char from) - ;; Parse escapes in format. Coding this in C would speed up - ;; things *a lot*. + ;; Parse escapes in format. + ;; Coding this in C would speed up things *a lot*. (while (re-search-forward "%\\(.\\)" nil t) (let ((escape (aref (match-string 1) 0))) (replace-match "" t t) (cond ((eq escape ?%) - (insert "%")) + (insert ?%)) ((eq escape ?\[) (setq button-begin (point-marker)) (set-marker-insertion-type button-begin nil)) @@ -1689,7 +1735,7 @@ (setq sample-end (point))) ((eq escape ?n) (when (widget-get widget :indent) - (insert "\n") + (insert ?\n) (insert-char ?\ (widget-get widget :indent)))) ((eq escape ?t) (let* ((tag (widget-get widget :tag)) @@ -1701,8 +1747,8 @@ (tag (insert tag)) (t - (let ((standard-output (current-buffer))) - (princ (widget-get widget :value))))))) + (princ (widget-get widget :value) + (current-buffer)))))) ((eq escape ?d) (let ((doc (widget-get widget :doc))) (when doc @@ -1710,7 +1756,7 @@ (insert doc) (while (eq (preceding-char) ?\n) (delete-backward-char 1)) - (insert "\n") + (insert ?\n) (setq doc-end (point))))) ((eq escape ?v) (if (and button-begin (not button-end)) @@ -1751,13 +1797,13 @@ (cond ((eq escape ?h) (let* ((doc-property (widget-get widget :documentation-property)) (doc-try (cond ((widget-get widget :doc)) + ((functionp doc-property) + (funcall doc-property + (widget-get widget :value))) ((symbolp doc-property) (documentation-property (widget-get widget :value) - doc-property)) - (t - (funcall doc-property - (widget-get widget :value))))) + doc-property)))) (doc-text (and (stringp doc-try) (> (length doc-try) 1) doc-try)) @@ -1841,10 +1887,10 @@ (widget-apply widget :delete) (widget-put widget :value value) (widget-apply widget :create)) - (when offset - (if (< offset 0) - (goto-char (+ (widget-get widget :to) offset 1)) - (goto-char (min (+ from offset) (1- (widget-get widget :to)))))))) + (if offset + (if (< offset 0) + (goto-char (+ (widget-get widget :to) offset 1)) + (goto-char (min (+ from offset) (1- (widget-get widget :to)))))))) (defun widget-default-value-inline (widget) "Wrap value in a list unless it is inline." @@ -1908,8 +1954,7 @@ (defun widget-item-value-create (widget) "Insert the printed representation of the value." - (let ((standard-output (current-buffer))) - (princ (widget-get widget :value)))) + (princ (widget-get widget :value) (current-buffer))) (defun widget-item-match (widget value) ;; Match if the value is the same. @@ -1929,8 +1974,7 @@ If END is omitted, it defaults to the length of LIST." (if (> start 0) (setq list (nthcdr start list))) (if end - (if (<= end start) - nil + (unless (<= end start) (setq list (copy-sequence list)) (setcdr (nthcdr (- end start 1) list) nil) list) @@ -2035,10 +2079,11 @@ (defun widget-url-link-action (widget &optional event) "Open the url specified by WIDGET." - (if-fboundp 'browse-url + (if (fboundp 'browse-url) (browse-url (widget-value widget)) ;; #### Should subclass a 'missing-package error. - (error 'unimplemented "No `browse-url' package; cannot follow URLs in this XEmacs"))) + (error 'unimplemented + "No `browse-url' package; cannot follow URLs in this XEmacs"))) ;;; The `function-link' Widget. @@ -2101,6 +2146,7 @@ :convert-widget 'widget-value-convert-widget :keymap widget-field-keymap :format "%v" + :help-echo "M-TAB: complete field; RET: enter value" :value "" :prompt-internal 'widget-field-prompt-internal :prompt-history 'widget-field-history @@ -2108,7 +2154,7 @@ :action 'widget-field-action :validate 'widget-field-validate :valid-regexp "" - :error "No match" + :error "Field's value doesn't match allowed forms" :value-create 'widget-field-value-create :value-delete 'widget-field-value-delete :value-get 'widget-field-value-get @@ -2125,14 +2171,15 @@ (defun widget-field-prompt-value (widget prompt value unbound) "Prompt for a string." - (let ((initial (if unbound - nil - (cons (widget-apply widget :value-to-internal - value) 0))) - (history (widget-get widget :prompt-history))) - (let ((answer (widget-apply widget - :prompt-internal prompt initial history))) - (widget-apply widget :value-to-external answer)))) + (widget-apply widget + :value-to-external + (widget-apply widget + :prompt-internal prompt + (unless unbound + (cons (widget-apply widget + :value-to-internal value) + 0)) + (widget-get widget :prompt-history)))) (defvar widget-edit-functions nil) @@ -2167,12 +2214,10 @@ (defun widget-field-validate (widget) "Valid if the content matches `:valid-regexp'." - (save-excursion - (let ((value (widget-apply widget :value-get)) - (regexp (widget-get widget :valid-regexp))) - (if (string-match regexp value) - nil - widget)))) + (save-excursion ; XEmacs + (unless (string-match (widget-get widget :valid-regexp) + (widget-apply widget :value-get)) + widget))) (defun widget-field-value-create (widget) "Create an editable text field." @@ -2241,8 +2286,8 @@ ;;; The `text' Widget. (define-widget 'text 'editable-field - :keymap widget-text-keymap - "A multiline text area.") + "A multiline text area." + :keymap widget-text-keymap) ;;; The `menu-choice' Widget. @@ -2381,12 +2426,9 @@ (defun widget-choice-validate (widget) ;; Valid if we have made a valid choice. - (let ((void (widget-get widget :void)) - (choice (widget-get widget :choice)) - (child (car (widget-get widget :children)))) - (if (eq void choice) - widget - (widget-apply child :validate)))) + (if (eq (widget-get widget :void) (widget-get widget :choice)) + widget + (widget-apply (car (widget-get widget :children)) :validate))) (defun widget-choice-match (widget value) ;; Matches if one of the choices matches. @@ -2503,7 +2545,7 @@ (let ((escape (aref (match-string 1) 0))) (replace-match "" t t) (cond ((eq escape ?%) - (insert "%")) + (insert ?%)) ((eq escape ?b) (setq button (apply 'widget-create-child-and-convert widget 'checkbox @@ -2688,7 +2730,7 @@ (let ((escape (aref (match-string 1) 0))) (replace-match "" t t) (cond ((eq escape ?%) - (insert "%")) + (insert ?%)) ((eq escape ?b) (setq button (apply 'widget-create-child-and-convert widget 'radio-button @@ -2725,11 +2767,9 @@ (while children (setq current (car children) children (cdr children)) - (let* ((button (widget-get current :button)) - (value (widget-apply button :value-get))) - (when value - (setq found current - children nil)))) + (when (widget-apply (widget-get current :button) :value-get) + (setq found current + children nil))) found)) (defun widget-radio-value-inline (widget) @@ -2739,11 +2779,9 @@ (while children (setq current (car children) children (cdr children)) - (let* ((button (widget-get current :button)) - (value (widget-apply button :value-get))) - (when value - (setq found (widget-apply current :value-inline) - children nil)))) + (when (widget-apply (widget-get current :button) :value-get) + (setq found (widget-apply current :value-inline) + children nil))) found)) (defun widget-radio-value-set (widget value) @@ -2864,7 +2902,6 @@ ;; Insert all values (let* ((value (widget-get widget :value)) (type (nth 0 (widget-get widget :args))) - (inlinep (widget-get type :inline)) children) (widget-put widget :value-pos (copy-marker (point))) (set-marker-insertion-type (widget-get widget :value-pos) t) @@ -2873,7 +2910,7 @@ (if answer (setq children (cons (widget-editable-list-entry-create widget - (if inlinep + (if (widget-get type :inline) (car answer) (car (car answer))) t) @@ -2971,7 +3008,7 @@ (let ((escape (aref (match-string 1) 0))) (replace-match "" t t) (cond ((eq escape ?%) - (insert "%")) + (insert ?%)) ((eq escape ?i) (setq insert (apply 'widget-create-child-and-convert widget 'insert-button @@ -3191,7 +3228,7 @@ (let ((before (substring doc 0 (match-beginning 0))) (after (substring doc (match-beginning 0))) buttons) - (insert before " ") + (insert before ?\ ) (widget-documentation-link-add widget start (point)) (push (widget-create-child-and-convert widget 'visibility @@ -3213,7 +3250,7 @@ (widget-put widget :buttons buttons)) (insert doc) (widget-documentation-link-add widget start (point)))) - (insert "\n")) + (insert ?\n)) (defun widget-documentation-string-action (widget &rest ignore) ;; Toggle documentation. @@ -3223,6 +3260,7 @@ ;; Redraw. (widget-value-set widget (widget-value widget))) + ;;; The Sexp Widgets. (define-widget 'const 'item @@ -3247,6 +3285,17 @@ :format "%v\n%h" :documentation-property 'variable-documentation) +(define-widget 'other 'sexp + "Matches any value, but doesn't let the user edit the value. +This is useful as last item in a `choice' widget. +You should use this widget type with a default value, +as in (other DEFAULT) or (other :tag \"NAME\" DEFAULT). +If the user selects this alternative, that specifies DEFAULT +as the value." + :tag "Other" + :format "%t%n" + :value 'other) + (defvar widget-string-prompt-value-history nil "History of input to `widget-string-prompt-value'.") @@ -3275,12 +3324,11 @@ (defun widget-regexp-validate (widget) "Check that the value of WIDGET is a valid regexp." - (let ((value (widget-value widget))) - (condition-case data - (prog1 nil - (string-match value "")) - (error (widget-put widget :error (error-message-string data)) - widget)))) + (condition-case data + (prog1 nil + (string-match (widget-value widget) "")) + (error (widget-put widget :error (error-message-string data)) + widget))) (define-widget 'file 'string "A file widget. @@ -3312,10 +3360,10 @@ (insert (expand-file-name completion directory))) (t (message "Making completion list...") - (let ((list (file-name-all-completions name-part directory))) - (setq list (sort list 'string<)) - (with-output-to-temp-buffer "*Completions*" - (display-completion-list list))) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list + (sort (file-name-all-completions name-part directory) + 'string<))) (message "Making completion list...%s" "done"))))) (defun widget-file-prompt-value (widget prompt value unbound) @@ -3408,36 +3456,40 @@ ;; ;; OK, I'll simply comment the whole thing out, until someone decides ;; to do something with it. -;(defvar widget-coding-system-prompt-value-history nil -; "History of input to `widget-coding-system-prompt-value'.") - -;(define-widget 'coding-system 'symbol -; "A MULE coding-system." -; :format "%{%t%}: %v" -; :tag "Coding system" -; :prompt-history 'widget-coding-system-prompt-value-history -; :prompt-value 'widget-coding-system-prompt-value -; :action 'widget-coding-system-action) - -;(defun widget-coding-system-prompt-value (widget prompt value unbound) -; ;; Read coding-system from minibuffer. -; (intern -; (completing-read (format "%s (default %s) " prompt value) -; (mapcar (lambda (sym) -; (list (symbol-name sym))) -; (coding-system-list))))) - -;(defun widget-coding-system-action (widget &optional event) -; ;; Read a file name from the minibuffer. -; (let ((answer -; (widget-coding-system-prompt-value -; widget -; (widget-apply widget :menu-tag-get) -; (widget-value widget) -; t))) -; (widget-value-set widget answer) -; (widget-apply widget :notify widget event) -; (widget-setup))) + +;; OK, _I_'ll simply comment it back in, so somebody will get irritated and +;; do something about it. + +(defvar widget-coding-system-prompt-value-history nil + "History of input to `widget-coding-system-prompt-value'.") + +(define-widget 'coding-system 'symbol + "A MULE coding-system." + :format "%{%t%}: %v" + :tag "Coding system" + :prompt-history 'widget-coding-system-prompt-value-history + :prompt-value 'widget-coding-system-prompt-value + :action 'widget-coding-system-action) + +(defun widget-coding-system-prompt-value (widget prompt value unbound) + ;; Read coding-system from minibuffer. + (intern + (completing-read (format "%s (default %s) " prompt value) + (mapcar (lambda (sym) + (list (symbol-name sym))) + (coding-system-list))))) + +(defun widget-coding-system-action (widget &optional event) + ;; Read a file name from the minibuffer. + (let ((answer + (widget-coding-system-prompt-value + widget + (widget-apply widget :menu-tag-get) + (widget-value widget) + t))) + (widget-value-set widget answer) + (widget-apply widget :notify widget event) + (widget-setup))) (define-widget 'sexp 'editable-field "An arbitrary Lisp expression." @@ -3539,10 +3591,18 @@ :type-error "This field should contain a number (floating point or integer)" :match-alternatives '(numberp)) +(define-widget 'float 'restricted-sexp + "A floating point number." + :tag "Floating point number" + :value 0.0 + :type-error "This field should contain a floating point number" + :match-alternatives '(floatp)) + (define-widget 'character 'editable-field "A character." :tag "Character" :value ?\0 + :size 1 :format "%{%t%}: %v" :valid-regexp "\\`[\0-\377]\\'" :error "This field should contain a single character" @@ -3583,13 +3643,103 @@ :value-to-internal (lambda (widget value) (list (car value) (cdr value))) :value-to-external (lambda (widget value) - (cons (car value) (cadr value)))) + (cons (nth 0 value) (nth 1 value)))) (defun widget-cons-match (widget value) (and (consp value) (widget-group-match widget (widget-apply widget :value-to-internal value)))) - + +;;; The `plist' Widget. +;; +;; Property lists. + +(define-widget 'plist 'list + "A property list." + :key-type '(symbol :tag "Key") + :value-type '(sexp :tag "Value") + :convert-widget 'widget-plist-convert-widget + :tag "Plist") + +(defvar widget-plist-value-type) ;Dynamic variable + +(defun widget-plist-convert-widget (widget) + ;; Handle `:options'. + (let* ((options (widget-get widget :options)) + (widget-plist-value-type (widget-get widget :value-type)) + (other `(editable-list :inline t + (group :inline t + ,(widget-get widget :key-type) + ,widget-plist-value-type))) + (args (if options + (list `(checklist :inline t + :greedy t + ,@(mapcar 'widget-plist-convert-option + options)) + other) + (list other)))) + (widget-put widget :args args) + widget)) + +(defun widget-plist-convert-option (option) + ;; Convert a single plist option. + (let (key-type value-type) + (if (listp option) + (let ((key (nth 0 option))) + (setq value-type (nth 1 option)) + (if (listp key) + (setq key-type key) + (setq key-type `(const ,key)))) + (setq key-type `(const ,option) + value-type widget-plist-value-type)) + `(group :format "Key: %v" :inline t ,key-type ,value-type))) + + +;;; The `alist' Widget. +;; +;; Association lists. + +(define-widget 'alist 'list + "An association list." + :key-type '(sexp :tag "Key") + :value-type '(sexp :tag "Value") + :convert-widget 'widget-alist-convert-widget + :tag "Alist") + +(defvar widget-alist-value-type) ;Dynamic variable + +(defun widget-alist-convert-widget (widget) + ;; Handle `:options'. + (let* ((options (widget-get widget :options)) + (widget-alist-value-type (widget-get widget :value-type)) + (other `(editable-list :inline t + (cons :format "%v" + ,(widget-get widget :key-type) + ,widget-alist-value-type))) + (args (if options + (list `(checklist :inline t + :greedy t + ,@(mapcar 'widget-alist-convert-option + options)) + other) + (list other)))) + (widget-put widget :args args) + widget)) + +(defun widget-alist-convert-option (option) + ;; Convert a single alist option. + (let (key-type value-type) + (if (listp option) + (let ((key (nth 0 option))) + (setq value-type (nth 1 option)) + (if (listp key) + (setq key-type key) + (setq key-type `(const ,key)))) + (setq key-type `(const ,option) + value-type widget-alist-value-type)) + `(cons :format "Key: %v" ,key-type ,value-type))) + + (define-widget 'choice 'menu-choice "A union of several sexp types." :tag "Choice" @@ -3698,9 +3848,8 @@ (insert (substring completion (length prefix)))) (t (message "Making completion list...") - (let ((list (all-completions prefix list nil))) - (with-output-to-temp-buffer "*Completions*" - (display-completion-list list))) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list (all-completions prefix list nil))) (message "Making completion list...done"))))) (defun widget-color-sample-face-get (widget) @@ -3737,22 +3886,16 @@ (remove-face-property face 'foreground))) (widget-default-notify widget child event)) -;; Is this a misnomer? -(defun widget-at (pos) - "The button or field at POS." - (or (get-char-property pos 'button) - (get-char-property pos 'field))) - ;;; The Help Echo (defun widget-echo-help (pos) "Display the help-echo text for widget at POS." (let* ((widget (widget-at pos)) (help-echo (and widget (widget-get widget :help-echo)))) - (and (functionp help-echo) - (setq help-echo (funcall help-echo widget))) - (when (stringp help-echo) - (display-message 'help-echo help-echo)))) + (if (functionp help-echo) + (setq help-echo (funcall help-echo widget))) + (if (stringp help-echo) + (display-message 'help-echo help-echo)))) ;;; The End: