Replace `iff' in doc-strings and comments.
[bpt/emacs.git] / lisp / wid-edit.el
index d861429..6725144 100644 (file)
@@ -1,6 +1,7 @@
 ;;; wid-edit.el --- Functions for creating and using widgets -*-byte-compile-dynamic: t;-*-
 ;;
-;; Copyright (C) 1996,97,1999,2000,01,02,2003, 2004, 2005  Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003,
+;;   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Maintainer: FSF
@@ -10,7 +11,7 @@
 
 ;; 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)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -57,6 +58,8 @@
 
 ;;; Code:
 
+(defvar widget)
+
 ;;; Compatibility.
 
 (defun widget-event-point (event)
@@ -81,7 +84,7 @@
   :group 'hypermedia)
 
 (defgroup widget-documentation nil
-  "Options controling the display of documentation strings."
+  "Options controlling the display of documentation strings."
   :group 'widgets)
 
 (defgroup widget-faces nil
@@ -272,14 +275,15 @@ minibuffer."
                     keys
                     (char 0)
                     (arg 1))
-                (while (not (or (and (>= char ?0) (< char next-digit))
+                (while (not (or (and (integerp char)
+                                     (>= char ?0) (< char next-digit))
                                 (eq value 'keyboard-quit)))
                   ;; Unread a SPC to lead to our new menu.
-                  (setq unread-command-events (cons ?\  unread-command-events))
+                  (setq unread-command-events (cons ?\s unread-command-events))
                   (setq keys (read-key-sequence title))
                   (setq value
                         (lookup-key overriding-terminal-local-map keys t)
-                        char (string-to-char (substring keys 1)))
+                        char (aref keys 1))
                   (cond ((eq value 'scroll-other-window)
                          (let ((minibuffer-scroll-window
                                 (get-buffer-window buf)))
@@ -377,7 +381,7 @@ new value.")
            (end (widget-field-end field)))
        (when size
          (while (and (> end begin)
-                     (eq (char-after (1- end)) ?\ ))
+                     (eq (char-after (1- end)) ?\s))
            (setq end (1- end))))
        (while (< begin end)
          (let ((old (char-after begin)))
@@ -400,10 +404,8 @@ new value.")
     ;; We want to avoid the face with image buttons.
     (unless (widget-get widget :suppress-face)
       (overlay-put overlay 'face (widget-apply widget :button-face-get))
-      ; Text terminals cannot change mouse pointer shape, so use mouse
-      ; face instead.
-      (or (display-graphic-p)
-         (overlay-put overlay 'mouse-face widget-mouse-face)))
+      (overlay-put overlay 'mouse-face
+                  (widget-apply widget :mouse-face-get)))
     (overlay-put overlay 'pointer 'hand)
     (overlay-put overlay 'follow-link follow-link)
     (overlay-put overlay 'help-echo help-echo)))
@@ -481,7 +483,7 @@ new value.")
 
 ;;;###autoload
 (defun widgetp (widget)
-  "Return non-nil iff WIDGET is a widget."
+  "Return non-nil if WIDGET is a widget."
   (if (symbolp widget)
       (get widget 'widget-type)
     (and (consp widget)
@@ -498,7 +500,7 @@ Otherwise, just return the value."
       value)))
 
 (defun widget-member (widget property)
-  "Non-nil iff there is a definition in WIDGET for PROPERTY."
+  "Non-nil if there is a definition in WIDGET for PROPERTY."
   (cond ((plist-member (cdr widget) property)
         t)
        ((car widget)
@@ -597,7 +599,7 @@ automatically."
   :type 'directory)
 
 (defcustom widget-image-enable t
-  "If non nil, use image buttons in widgets when available."
+  "If non-nil, use image buttons in widgets when available."
   :version "21.1"
   :group 'widgets
   :type 'boolean)
@@ -657,6 +659,14 @@ button is pressed or inactive, respectively.  These are currently ignored."
                            tag 'mouse-face widget-button-pressed-face)))
     (insert tag)))
 
+(defun widget-move-and-invoke (event)
+  "Move to where you click, and if it is an active field, invoke it."
+  (interactive "e")
+  (mouse-set-point event)
+  (let ((pos (widget-event-point event)))
+    (if (and pos (get-char-property pos 'button))
+       (widget-button-click event))))
+
 ;;; Buttons.
 
 (defgroup widget-button nil
@@ -796,8 +806,8 @@ The optional ARGS are additional keyword arguments."
                                 &optional button-from button-to
                                 &rest args)
   "Return a widget of type TYPE with endpoint FROM TO.
-Optional ARGS are extra keyword arguments for TYPE.
-and TO will be used as the widgets end points. If optional arguments
+No text will be inserted to the buffer, instead the text between FROM
+and TO will be used as the widgets end points.  If optional arguments
 BUTTON-FROM and BUTTON-TO are given, these will be used as the widgets
 button end points.
 Optional ARGS are extra keyword arguments for TYPE."
@@ -840,13 +850,18 @@ button end points."
 
 ;;; Keymap and Commands.
 
+;;;###autoload
+(defalias 'advertised-widget-backward 'widget-backward)
+
 ;;;###autoload
 (defvar widget-keymap
   (let ((map (make-sparse-keymap)))
     (define-key map "\t" 'widget-forward)
-    (define-key map [(shift tab)] 'widget-backward)
+    (define-key map "\e\t" 'widget-backward)
+    (define-key map [(shift tab)] 'advertised-widget-backward)
     (define-key map [backtab] 'widget-backward)
     (define-key map [down-mouse-2] 'widget-button-click)
+    (define-key map [down-mouse-1] 'widget-button-click)
     (define-key map "\C-m" 'widget-button-press)
     map)
   "Keymap containing useful binding for buffers containing widgets.
@@ -898,75 +913,94 @@ Recommended as a parent keymap for modes using widgets.")
 ;; backward-compatibility alias
 (put 'widget-button-pressed-face 'face-alias 'widget-button-pressed)
 
+(defvar widget-button-click-moves-point nil
+  "If non-nil, `widget-button-click' moves point to a button after invoking it.
+If nil, point returns to its original position after invoking a button.")
+
 (defun widget-button-click (event)
   "Invoke the button that the mouse is pointing at."
   (interactive "e")
   (if (widget-event-point event)
-      (let* ((pos (widget-event-point event))
+      (let* ((oevent event)
+            (mouse-1 (memq (event-basic-type event) '(mouse-1 down-mouse-1)))
+            (pos (widget-event-point event))
             (start (event-start event))
             (button (get-char-property
                      pos 'button (and (windowp (posn-window start))
-                                      (window-buffer (posn-window start))))))
-       (if button
-           ;; Mouse click on a widget button.  Do the following
-           ;; in a save-excursion so that the click on the button
-           ;; doesn't change point.
-           (save-selected-window
-             (select-window (posn-window (event-start event)))
-             (save-excursion
-               (goto-char (posn-point (event-start event)))
-               (let* ((overlay (widget-get button :button-overlay))
-                      (face (overlay-get overlay 'face))
-                      (mouse-face (overlay-get overlay 'mouse-face)))
-                 (unwind-protect
-                     ;; Read events, including mouse-movement events
-                     ;; until we receive a release event.  Highlight/
-                     ;; unhighlight the button the mouse was initially
-                     ;; on when we move over it.
-                     (save-excursion
-                       (when face      ; avoid changing around image
-                         (overlay-put overlay
-                                      'face widget-button-pressed-face)
-                         (overlay-put overlay
-                                      'mouse-face widget-button-pressed-face))
-                       (unless (widget-apply button :mouse-down-action event)
-                         (let ((track-mouse t))
-                           (while (not (widget-button-release-event-p event))
-                             (setq event (read-event)
-                                   pos (widget-event-point event))
-                             (if (and pos
-                                      (eq (get-char-property pos 'button)
-                                          button))
-                                 (when face
-                                   (overlay-put overlay
-                                                'face
-                                                widget-button-pressed-face)
-                                   (overlay-put overlay
-                                                'mouse-face
-                                                widget-button-pressed-face))
-                               (overlay-put overlay 'face face)
-                               (overlay-put overlay 'mouse-face mouse-face)))))
-
-                       ;; When mouse is released over the button, run
-                       ;; its action function.
-                       (when (and pos
-                                  (eq (get-char-property pos 'button) button))
-                         (widget-apply-action button event)))
-                   (overlay-put overlay 'face face)
-                   (overlay-put overlay 'mouse-face mouse-face))))
-
-             (unless (pos-visible-in-window-p (widget-event-point event))
-               (mouse-set-point event)
-               (beginning-of-line)
-               (recenter))
-             )
-
+                                      (window-buffer (posn-window start)))))
+            newpoint)
+       (when (or (null button)
+                 (catch 'button-press-cancelled
+             ;; Mouse click on a widget button.  Do the following
+             ;; in a save-excursion so that the click on the button
+             ;; doesn't change point.
+             (save-selected-window
+               (select-window (posn-window (event-start event)))
+               (save-excursion
+                 (goto-char (posn-point (event-start event)))
+                 (let* ((overlay (widget-get button :button-overlay))
+                        (pressed-face (or (widget-get button :pressed-face)
+                                          widget-button-pressed-face))
+                        (face (overlay-get overlay 'face))
+                        (mouse-face (overlay-get overlay 'mouse-face)))
+                   (unwind-protect
+                       ;; Read events, including mouse-movement
+                       ;; events, waiting for a release event.  If we
+                       ;; began with a mouse-1 event and receive a
+                       ;; movement event, that means the user wants
+                       ;; to perform drag-selection, so cancel the
+                       ;; button press and do the default mouse-1
+                       ;; action.  For mouse-2, just highlight/
+                       ;; unhighlight the button the mouse was
+                       ;; initially on when we move over it.
+                       (save-excursion
+                         (when face    ; avoid changing around image
+                           (overlay-put overlay 'face pressed-face)
+                           (overlay-put overlay 'mouse-face pressed-face))
+                         (unless (widget-apply button :mouse-down-action event)
+                           (let ((track-mouse t))
+                             (while (not (widget-button-release-event-p event))
+                               (setq event (read-event))
+                               (when (and mouse-1 (mouse-movement-p event))
+                                 (push event unread-command-events)
+                                 (setq event oevent)
+                                 (throw 'button-press-cancelled t))
+                               (unless (or (integerp event)
+                                           (memq (car event) '(switch-frame select-window))
+                                           (eq (car event) 'scroll-bar-movement))
+                                 (setq pos (widget-event-point event))
+                                 (if (and pos
+                                          (eq (get-char-property pos 'button)
+                                              button))
+                                     (when face
+                                       (overlay-put overlay 'face pressed-face)
+                                       (overlay-put overlay 'mouse-face pressed-face))
+                                   (overlay-put overlay 'face face)
+                                   (overlay-put overlay 'mouse-face mouse-face))))))
+
+                         ;; When mouse is released over the button, run
+                         ;; its action function.
+                         (when (and pos (eq (get-char-property pos 'button) button))
+                           (goto-char pos)
+                           (widget-apply-action button event)
+                           (if widget-button-click-moves-point
+                               (setq newpoint (point)))))
+                     (overlay-put overlay 'face face)
+                     (overlay-put overlay 'mouse-face mouse-face))))
+
+               (if newpoint (goto-char newpoint))
+               ;; This loses if the widget action switches windows. -- cyd
+               ;; (unless (pos-visible-in-window-p (widget-event-point event))
+               ;;   (mouse-set-point event)
+               ;;   (beginning-of-line)
+               ;;   (recenter))
+               )
+             nil))
          (let ((up t) command)
            ;; Mouse click not on a widget button.  Find the global
            ;; command to run, and check whether it is bound to an
            ;; up event.
-           (mouse-set-point event)
-           (if (memq (event-basic-type event) '(mouse-1 down-mouse-1))
+           (if mouse-1
                (cond ((setq command    ;down event
                             (lookup-key widget-global-map [down-mouse-1]))
                       (setq up nil))
@@ -1105,7 +1139,7 @@ the field."
   :group 'widgets)
 
 (defun widget-narrow-to-field ()
-  "Narrow to field"
+  "Narrow to field."
   (interactive)
   (let ((field (widget-field-find (point))))
     (if field
@@ -1193,27 +1227,29 @@ When not inside a field, move to the previous button or field."
     ;; or if a special `boundary' field has been added after the widget
     ;; field.
     (if (overlayp overlay)
-       (if (and (not (eq (with-current-buffer
-                             (widget-field-buffer widget)
-                           (save-restriction
-                             ;; `widget-narrow-to-field' can be
-                             ;; active when this function is called
-                             ;; from an change-functions hook. So
-                             ;; temporarily remove field narrowing
-                             ;; before to call `get-char-property'.
-                             (widen)
-                             (get-char-property (overlay-end overlay)
-                                                'field)))
-                         'boundary))
-                (or widget-field-add-space
-                    (null (widget-get widget :size))))
-           (1- (overlay-end overlay))
-         (overlay-end overlay))
+        ;; Don't proceed if overlay has been removed from buffer.
+        (when (overlay-buffer overlay)
+          (if (and (not (eq (with-current-buffer
+                                (widget-field-buffer widget)
+                              (save-restriction
+                                ;; `widget-narrow-to-field' can be
+                                ;; active when this function is called
+                                ;; from an change-functions hook. So
+                                ;; temporarily remove field narrowing
+                                ;; before to call `get-char-property'.
+                                (widen)
+                                (get-char-property (overlay-end overlay)
+                                                   'field)))
+                            'boundary))
+                   (or widget-field-add-space
+                       (null (widget-get widget :size))))
+              (1- (overlay-end overlay))
+            (overlay-end overlay)))
       (cdr overlay))))
 
 (defun widget-field-find (pos)
   "Return the field at POS.
-Unlike (get-char-property POS 'field) this, works with empty fields too."
+Unlike (get-char-property POS 'field), this works with empty fields too."
   (let ((fields widget-field-list)
        field found)
     (while fields
@@ -1263,7 +1299,7 @@ Unlike (get-char-property POS 'field) this, works with empty fields too."
                   ;; Field too small.
                   (save-excursion
                     (goto-char end)
-                    (insert-char ?\  (- (+ begin size) end))))
+                    (insert-char ?\s (- (+ begin size) end))))
                  ((> (- end begin) size)
                   ;; Field too large and
                   (if (or (< (point) (+ begin size))
@@ -1274,7 +1310,7 @@ Unlike (get-char-property POS 'field) this, works with empty fields too."
                     (setq begin (point)))
                   (save-excursion
                     (goto-char end)
-                    (while (and (eq (preceding-char) ?\ )
+                    (while (and (eq (preceding-char) ?\s)
                                 (> (point) begin))
                       (delete-backward-char 1)))))))
        (widget-specify-secret field))
@@ -1382,6 +1418,7 @@ The value of the :type attribute should be an unconverted widget type."
   :offset 0
   :format-handler 'widget-default-format-handler
   :button-face-get 'widget-default-button-face-get
+  :mouse-face-get 'widget-default-mouse-face-get
   :sample-face-get 'widget-default-sample-face-get
   :delete 'widget-default-delete
   :copy 'identity
@@ -1434,7 +1471,7 @@ If that does not exists, call the value of `widget-complete-field'."
               ((eq escape ?n)
                (when (widget-get widget :indent)
                  (insert ?\n)
-                 (insert-char ?  (widget-get widget :indent))))
+                 (insert-char ?\s (widget-get widget :indent))))
               ((eq escape ?t)
                (let ((image (widget-get widget :tag-glyph))
                      (tag (widget-get widget :tag)))
@@ -1498,7 +1535,7 @@ If that does not exists, call the value of `widget-complete-field'."
             (when doc-text
               (and (eq (preceding-char) ?\n)
                    (widget-get widget :indent)
-                   (insert-char ?  (widget-get widget :indent)))
+                   (insert-char ?\s (widget-get widget :indent)))
               ;; The `*' in the beginning is redundant.
               (when (eq (aref doc-text  0) ?*)
                 (setq doc-text (substring doc-text 1)))
@@ -1526,6 +1563,14 @@ If that does not exists, call the value of `widget-complete-field'."
            (widget-apply parent :button-face-get)
          widget-button-face))))
 
+(defun widget-default-mouse-face-get (widget)
+  ;; Use :mouse-face or widget-mouse-face
+  (or (widget-get widget :mouse-face)
+      (let ((parent (widget-get widget :parent)))
+       (if parent
+           (widget-apply parent :mouse-face-get)
+         widget-mouse-face))))
+
 (defun widget-default-sample-face-get (widget)
   ;; Use :sample-face.
   (widget-get widget :sample-face))
@@ -1596,7 +1641,7 @@ If that does not exists, call the value of `widget-complete-field'."
       (widget-princ-to-string (widget-get widget :value))))
 
 (defun widget-default-active (widget)
-  "Return t iff this widget active (user modifiable)."
+  "Return t if this widget is active (user modifiable)."
   (or (widget-get widget :always-active)
       (and (not (widget-get widget :inactive))
           (let ((parent (widget-get widget :parent)))
@@ -1675,7 +1720,7 @@ If END is omitted, it defaults to the length of LIST."
 ;;; The `push-button' Widget.
 
 ;; (defcustom widget-push-button-gui t
-;;   "If non nil, use GUI push buttons when available."
+;;   "If non-nil, use GUI push buttons when available."
 ;;   :group 'widgets
 ;;   :type 'boolean)
 
@@ -1751,7 +1796,7 @@ If END is omitted, it defaults to the length of LIST."
   :action 'widget-url-link-action)
 
 (defun widget-url-link-action (widget &optional event)
-  "Open the url specified by WIDGET."
+  "Open the URL specified by WIDGET."
   (browse-url (widget-value widget)))
 
 ;;; The `function-link' Widget.
@@ -1791,7 +1836,7 @@ If END is omitted, it defaults to the length of LIST."
   :action 'widget-emacs-library-link-action)
 
 (defun widget-emacs-library-link-action (widget &optional event)
-  "Find the Emacs Library file specified by WIDGET."
+  "Find the Emacs library file specified by WIDGET."
   (find-file (locate-library (widget-value widget))))
 
 ;;; The `emacs-commentary-link' Widget.
@@ -1807,7 +1852,9 @@ If END is omitted, it defaults to the length of LIST."
 ;;; The `editable-field' Widget.
 
 (define-widget 'editable-field 'default
-  "An editable text field."
+  "An editable text field.
+Note: In an `editable-field' widget, the `%v' escape must be preceded
+by some other text in the `:format' string (if specified)."
   :convert-widget 'widget-value-convert-widget
   :keymap widget-field-keymap
   :format "%v"
@@ -1829,7 +1876,7 @@ If END is omitted, it defaults to the length of LIST."
   "History of field minibuffer edits.")
 
 (defun widget-field-prompt-internal (widget prompt initial history)
-  "Read string for WIDGET promptinhg with PROMPT.
+  "Read string for WIDGET prompting with PROMPT.
 INITIAL is the initial input and HISTORY is a symbol containing
 the earlier input."
   (read-string prompt initial history))
@@ -1872,7 +1919,7 @@ the earlier input."
     (insert value)
     (and size
         (< (length value) size)
-        (insert-char ?\  (- size (length value))))
+        (insert-char ?\s (- size (length value))))
     (unless (memq widget widget-field-list)
       (setq widget-field-new (cons widget widget-field-new)))
     (move-marker (cdr overlay) (point))
@@ -1905,7 +1952,7 @@ the earlier input."
          (while (and size
                      (not (zerop size))
                      (> to from)
-                     (eq (char-after (1- to)) ?\ ))
+                     (eq (char-after (1- to)) ?\s))
            (setq to (1- to)))
          (let ((result (buffer-substring-no-properties from to)))
            (when secret
@@ -1955,13 +2002,14 @@ the earlier input."
        (args (widget-get widget :args))
        (explicit (widget-get widget :explicit-choice))
        current)
-    (if (and explicit (equal value (widget-get widget :explicit-choice-value)))
+    (if explicit
        (progn
          ;; If the user specified the choice for this value,
-         ;; respect that choice as long as the value is the same.
+         ;; respect that choice.
          (widget-put widget :children (list (widget-create-child-value
                                              widget explicit value)))
-         (widget-put widget :choice explicit))
+         (widget-put widget :choice explicit)
+         (widget-put widget :explicit-choice nil))
       (while args
        (setq current (car args)
              args (cdr args))
@@ -2047,13 +2095,10 @@ when he invoked the menu."
                 (setq this-explicit t)
                 (widget-choose tag (reverse choices) event))))
     (when current
-      ;; If this was an explicit user choice,
-      ;; record the choice, and the record the value it was made for.
-      ;; widget-choice-value-create will respect this choice,
-      ;; as long as the value is the same.
+      ;; If this was an explicit user choice, record the choice,
+      ;; so that widget-choice-value-create will respect it.
       (when this-explicit
-       (widget-put widget :explicit-choice current)
-       (widget-put widget :explicit-choice-value (widget-get widget :value)))
+       (widget-put widget :explicit-choice current))
       (widget-value-set widget (widget-default-get current))
       (widget-setup)
       (widget-apply widget :notify widget event)))
@@ -2154,7 +2199,8 @@ when he invoked the menu."
     (when sibling
       (if (widget-value widget)
          (widget-apply sibling :activate)
-       (widget-apply sibling :deactivate)))))
+       (widget-apply sibling :deactivate))
+      (widget-clear-undo))))
 
 ;;; The `checklist' Widget.
 
@@ -2186,7 +2232,7 @@ when he invoked the menu."
 If the item is checked, CHOSEN is a cons whose cdr is the value."
   (and (eq (preceding-char) ?\n)
        (widget-get widget :indent)
-       (insert-char ?  (widget-get widget :indent)))
+       (insert-char ?\s (widget-get widget :indent)))
   (widget-specify-insert
    (let* ((children (widget-get widget :children))
          (buttons (widget-get widget :buttons))
@@ -2366,7 +2412,7 @@ Return an alist of (TYPE MATCH)."
   ;; (setq type (widget-convert type))
   (and (eq (preceding-char) ?\n)
        (widget-get widget :indent)
-       (insert-char ?  (widget-get widget :indent)))
+       (insert-char ?\s (widget-get widget :indent)))
   (widget-specify-insert
    (let* ((value (widget-get widget :value))
          (children (widget-get widget :children))
@@ -2519,7 +2565,7 @@ Return an alist of (TYPE MATCH)."
 ;;; The `editable-list' Widget.
 
 ;; (defcustom widget-editable-list-gui nil
-;;   "If non nil, use GUI push-buttons in editable list when available."
+;;   "If non-nil, use GUI push-buttons in editable list when available."
 ;;   :type 'boolean
 ;;   :group 'widgets)
 
@@ -2544,7 +2590,7 @@ Return an alist of (TYPE MATCH)."
     ;; (let ((widget-push-button-gui widget-editable-list-gui))
     (cond ((eq escape ?i)
           (and (widget-get widget :indent)
-               (insert-char ?\  (widget-get widget :indent)))
+               (insert-char ?\s (widget-get widget :indent)))
           (apply 'widget-create-child-and-convert
                  widget 'insert-button
                  (widget-get widget :append-button-args)))
@@ -2656,7 +2702,7 @@ Return an alist of (TYPE MATCH)."
     (widget-specify-insert
      (save-excursion
        (and (widget-get widget :indent)
-           (insert-char ?\  (widget-get widget :indent)))
+           (insert-char ?\s (widget-get widget :indent)))
        (insert (widget-get widget :entry-format)))
      ;; Parse % escapes in format.
      (while (re-search-forward "%\\(.\\)" nil t)
@@ -2720,7 +2766,7 @@ Return an alist of (TYPE MATCH)."
            value (cdr answer))
       (and (eq (preceding-char) ?\n)
           (widget-get widget :indent)
-          (insert-char ?\  (widget-get widget :indent)))
+          (insert-char ?\s (widget-get widget :indent)))
       (push (cond ((null answer)
                   (widget-create-child widget arg))
                  ((widget-get arg :inline)
@@ -2821,7 +2867,7 @@ The first group should be the link itself."
 
 (defcustom widget-documentation-link-p 'intern-soft
   "Predicate used to test if a string is useful as a link.
-The value should be a function.  The function will be called one
+The value should be a function.  The function will be called with one
 argument, a string, and should return non-nil if there should be a
 link for that string."
   :type 'function
@@ -2859,7 +2905,7 @@ link for that string."
          (narrow-to-region from to)
          (goto-char (point-min))
          (while (search-forward "\n" nil t)
-           (insert-char ?\  indent)))))))
+           (insert-char ?\s indent)))))))
 
 ;;; The `documentation-string' Widget.
 
@@ -2879,7 +2925,7 @@ link for that string."
        (let ((before (substring doc 0 (match-beginning 0)))
              (after (substring doc (match-beginning 0)))
              button)
-         (insert before ?\ )
+         (insert before ?\s)
          (widget-documentation-link-add widget start (point))
          (setq button
                (widget-create-child-and-convert
@@ -2893,7 +2939,7 @@ link for that string."
          (when shown
            (setq start (point))
            (when (and indent (not (zerop indent)))
-             (insert-char ?\  indent))
+             (insert-char ?\s indent))
            (insert after)
            (widget-documentation-link-add widget start (point)))
          (widget-put widget :buttons (list button)))
@@ -2980,7 +3026,7 @@ as the value."
 
 (define-widget 'file 'string
   "A file widget.
-It will read a file name from the minibuffer when invoked."
+It reads a file name from an editable text field."
   :complete-function 'widget-file-complete
   :prompt-value 'widget-file-prompt-value
   :format "%{%t%}: %v"
@@ -2992,12 +3038,12 @@ It will read a file name from the minibuffer when invoked."
   "Perform completion on file name preceding point."
   (interactive)
   (let* ((end (point))
-        (beg (save-excursion
-               (skip-chars-backward "^ ")
-               (point)))
+        (beg (widget-field-start widget))
         (pattern (buffer-substring beg end))
         (name-part (file-name-nondirectory pattern))
-        (directory (file-name-directory pattern))
+        ;; I think defaulting to root is right
+        ;; because these really should be absolute file names.
+        (directory (or (file-name-directory pattern) "/"))
         (completion (file-name-completion name-part directory)))
     (cond ((eq completion t))
          ((null completion)
@@ -3011,7 +3057,8 @@ It will read a file name from the minibuffer when invoked."
           (with-output-to-temp-buffer "*Completions*"
             (display-completion-list
              (sort (file-name-all-completions name-part directory)
-                   'string<)))
+                   'string<)
+             name-part))
           (message "Making completion list...%s" "done")))))
 
 (defun widget-file-prompt-value (widget prompt value unbound)
@@ -3019,7 +3066,7 @@ It will read a file name from the minibuffer when invoked."
   (abbreviate-file-name
    (if unbound
        (read-file-name prompt)
-     (let ((prompt2 (format "%s (default %s) " prompt value))
+     (let ((prompt2 (format "%s (default %s): " prompt value))
           (dir (file-name-directory value))
           (file (file-name-nondirectory value))
           (must-match (widget-get widget :must-match)))
@@ -3032,7 +3079,7 @@ It will read a file name from the minibuffer when invoked."
 ;;;     (file (file-name-nondirectory value))
 ;;;     (menu-tag (widget-apply widget :menu-tag-get))
 ;;;     (must-match (widget-get widget :must-match))
-;;;     (answer (read-file-name (concat menu-tag ": (default `" value "') ")
+;;;     (answer (read-file-name (concat menu-tag " (default " value "): ")
 ;;;                             dir nil must-match file)))
 ;;;    (widget-value-set widget (abbreviate-file-name answer))
 ;;;    (widget-setup)
@@ -3041,7 +3088,7 @@ It will read a file name from the minibuffer when invoked."
 ;; Fixme: use file-name-as-directory.
 (define-widget 'directory 'file
   "A directory widget.
-It will read a directory name from the minibuffer when invoked."
+It reads a directory name from an editable text field."
   :tag "Directory")
 
 (defvar widget-symbol-prompt-value-history nil
@@ -3109,7 +3156,7 @@ It will read a directory name from the minibuffer when invoked."
                       (interactive)
                       (lisp-complete-symbol 'boundp))
   :tag "Variable")
-
+\f
 (defvar widget-coding-system-prompt-value-history nil
   "History of input to `widget-coding-system-prompt-value'.")
 
@@ -3136,10 +3183,10 @@ It will read a directory name from the minibuffer when invoked."
   "Read coding-system from minibuffer."
   (if (widget-get widget :base-only)
       (intern
-       (completing-read (format "%s (default %s) " prompt value)
+       (completing-read (format "%s (default %s): " prompt value)
                        (mapcar #'list (coding-system-list t)) nil nil nil
                        coding-system-history))
-      (read-coding-system (format "%s (default %s) " prompt value) value)))
+      (read-coding-system (format "%s (default %s): " prompt value) value)))
 
 (defun widget-coding-system-action (widget &optional event)
   (let ((answer
@@ -3152,6 +3199,84 @@ It will read a directory name from the minibuffer when invoked."
     (widget-apply widget :notify widget event)
     (widget-setup)))
 \f
+;;; I'm not sure about what this is good for?  KFS.
+(defvar widget-key-sequence-prompt-value-history nil
+  "History of input to `widget-key-sequence-prompt-value'.")
+
+(defvar widget-key-sequence-default-value [ignore]
+  "Default value for an empty key sequence.")
+
+(defvar widget-key-sequence-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map widget-field-keymap)
+    (define-key map [(control ?q)] 'widget-key-sequence-read-event)
+    map))
+
+(define-widget 'key-sequence 'restricted-sexp
+  "A key sequence."
+  :prompt-value 'widget-field-prompt-value
+  :prompt-internal 'widget-symbol-prompt-internal
+; :prompt-match 'fboundp   ;; What was this good for?  KFS
+  :prompt-history 'widget-key-sequence-prompt-value-history
+  :action 'widget-field-action
+  :match-alternatives '(stringp vectorp)
+  :format "%{%t%}: %v"
+  :validate 'widget-key-sequence-validate
+  :value-to-internal 'widget-key-sequence-value-to-internal
+  :value-to-external 'widget-key-sequence-value-to-external
+  :value widget-key-sequence-default-value
+  :keymap widget-key-sequence-map
+  :help-echo "C-q: insert KEY, EVENT, or CODE; RET: enter value"
+  :tag "Key sequence")
+
+(defun widget-key-sequence-read-event (ev)
+  (interactive (list
+               (let ((inhibit-quit t) quit-flag)
+                 (read-event "Insert KEY, EVENT, or CODE: "))))
+  (let ((ev2 (and (memq 'down (event-modifiers ev))
+                 (read-event)))
+       (tr (and (keymapp function-key-map)
+                (lookup-key function-key-map (vector ev)))))
+    (when (and (integerp ev)
+              (or (and (<= ?0 ev) (< ev (+ ?0 (min 10 read-quoted-char-radix))))
+                  (and (<= ?a (downcase ev))
+                       (< (downcase ev) (+ ?a -10 (min 36 read-quoted-char-radix))))))
+      (setq unread-command-events (cons ev unread-command-events)
+           ev (read-quoted-char (format "Enter code (radix %d)" read-quoted-char-radix))
+           tr nil)
+      (if (and (integerp ev) (not (char-valid-p ev)))
+         (insert (char-to-string ev))))  ;; throw invalid char error
+    (setq ev (key-description (list ev)))
+    (when (arrayp tr)
+      (setq tr (key-description (list (aref tr 0))))
+      (if (y-or-n-p (format "Key %s is translated to %s -- use %s? " ev tr tr))
+         (setq ev tr ev2 nil)))
+    (insert (if (= (char-before) ?\s)  "" " ") ev " ")
+    (if ev2
+       (insert (key-description (list ev2)) " "))))
+
+(defun widget-key-sequence-validate (widget)
+  (unless (or (stringp (widget-value widget))
+             (vectorp (widget-value widget)))
+    (widget-put widget :error (format "Invalid key sequence: %S"
+                                     (widget-value widget)))
+    widget))
+
+(defun widget-key-sequence-value-to-internal (widget value)
+  (if (widget-apply widget :match value)
+      (if (equal value widget-key-sequence-default-value)
+         ""
+       (key-description value))
+    value))
+
+(defun widget-key-sequence-value-to-external (widget value)
+  (if (stringp value)
+      (if (string-match "\\`[[:space:]]*\\'" value)
+         widget-key-sequence-default-value
+       (read-kbd-macro value))
+    value))
+
+\f
 (define-widget 'sexp 'editable-field
   "An arbitrary Lisp expression."
   :tag "Lisp expression"
@@ -3545,7 +3670,7 @@ example:
 ;; Fixme: match
 (define-widget 'color 'editable-field
   "Choose a color name (with sample)."
-  :format "%t: %v (%{sample%})\n"
+  :format "%{%t%}: %v (%{sample%})\n"
   :size 10
   :tag "Color"
   :value "black"
@@ -3570,7 +3695,8 @@ example:
          (t
           (message "Making completion list...")
           (with-output-to-temp-buffer "*Completions*"
-            (display-completion-list (all-completions prefix list nil)))
+            (display-completion-list (all-completions prefix list nil)
+                                     prefix))
           (message "Making completion list...done")))))
 
 (defun widget-color-sample-face-get (widget)
@@ -3594,7 +3720,7 @@ example:
       (widget-apply widget :notify widget event))))
 
 (defun widget-color-notify (widget child &optional event)
-  "Update the sample, and notofy the parent."
+  "Update the sample, and notify the parent."
   (overlay-put (widget-get widget :sample-overlay)
               'face (widget-apply widget :sample-face-get))
   (widget-default-notify widget child event))