declare smobs in alloc.c
[bpt/emacs.git] / lisp / wid-edit.el
index 19f7e8e..92e52bf 100644 (file)
@@ -1,11 +1,11 @@
-;;; wid-edit.el --- Functions for creating and using widgets -*-byte-compile-dynamic: t;-*-
+;;; wid-edit.el --- Functions for creating and using widgets -*-byte-compile-dynamic: t; lexical-binding:t -*-
 ;;
-;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-;;   2006, 2007, 2008, 2009, 2010, 2011, 2012  Free Software Foundation, Inc.
+;; Copyright (C) 1996-1997, 1999-2014 Free Software Foundation, Inc.
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: extensions
+;; Package: emacs
 
 ;; This file is part of GNU Emacs.
 
@@ -55,8 +55,7 @@
 ;; See `widget.el'.
 
 ;;; Code:
-
-(defvar widget)
+(require 'cl-lib)
 
 ;;; Compatibility.
 
@@ -78,8 +77,7 @@
   :link '(custom-manual "(widget)Top")
   :link '(emacs-library-link :tag "Lisp File" "widget.el")
   :prefix "widget-"
-  :group 'extensions
-  :group 'hypermedia)
+  :group 'extensions)
 
 (defgroup widget-documentation nil
   "Options controlling the display of documentation strings."
@@ -224,7 +222,7 @@ minibuffer."
        ((or widget-menu-minibuffer-flag
             (> (length items) widget-menu-max-shortcuts))
         ;; Read the choice of name from the minibuffer.
-        (setq items (widget-remove-if 'stringp items))
+        (setq items (cl-remove-if 'stringp items))
         (let ((val (completing-read (concat title ": ") items nil t)))
           (if (stringp val)
               (let ((try (try-completion val items)))
@@ -254,7 +252,9 @@ minibuffer."
               ;; Allocate digits to disabled alternatives
               ;; so that the digit of a given alternative never varies.
               (setq next-digit (1+ next-digit)))
-            (insert "\nC-g = Quit"))
+            (insert "\nC-g = Quit")
+            (goto-char (point-min))
+            (forward-line))
           (or some-choice-enabled
               (error "None of the choices is currently meaningful"))
           (define-key map [?\C-g] 'keyboard-quit)
@@ -296,14 +296,6 @@ minibuffer."
             (error "Canceled"))
           value))))
 
-(defun widget-remove-if (predictate list)
-  (let (result (tail list))
-    (while tail
-      (or (funcall predictate (car tail))
-         (setq result (cons (car tail) result)))
-      (setq tail (cdr tail)))
-    (nreverse result)))
-
 ;;; Widget text specifications.
 ;;
 ;; These functions are for specifying text properties.
@@ -415,7 +407,7 @@ the :notify function can't know the new value.")
     (overlay-put overlay 'follow-link follow-link)
     (overlay-put overlay 'help-echo help-echo)))
 
-(defun widget-mouse-help (window overlay point)
+(defun widget-mouse-help (_window overlay _point)
   "Help-echo callback for widgets whose :help-echo is a function."
   (with-current-buffer (overlay-buffer overlay)
     (let* ((widget (widget-at (overlay-start overlay)))
@@ -467,7 +459,7 @@ the :notify function can't know the new value.")
       (overlay-put overlay 'modification-hooks '(widget-overlay-inactive))
       (widget-put widget :inactive overlay))))
 
-(defun widget-overlay-inactive (&rest junk)
+(defun widget-overlay-inactive (&rest _junk)
   "Ignoring the arguments, signal an error."
   (unless inhibit-read-only
     (error "The widget here is not active")))
@@ -527,7 +519,17 @@ Otherwise, just return the value."
   "Extract the default external value of WIDGET."
   (widget-apply widget :value-to-external
                (or (widget-get widget :value)
-                   (widget-apply widget :default-get))))
+                   (progn
+                     (when (widget-get widget :args)
+                       (setq widget (widget-copy widget))
+                       (let (args)
+                         (dolist (arg (widget-get widget :args))
+                           (setq args (append args
+                                              (if (widget-get arg :inline)
+                                                  (widget-get arg :args)
+                                                (list arg)))))
+                         (widget-put widget :args args)))
+                     (widget-apply widget :default-get)))))
 
 (defun widget-match-inline (widget vals)
   "In WIDGET, match the start of VALS."
@@ -578,7 +580,7 @@ This is only meaningful for radio buttons or checkboxes in a list."
   "Map FUNCTION over the buttons in BUFFER.
 FUNCTION is called with the arguments WIDGET and MAPARG.
 
-If FUNCTION returns non-nil, the walk is cancelled.
+If FUNCTION returns non-nil, the walk is canceled.
 
 The arguments MAPARG, and BUFFER default to nil and (current-buffer),
 respectively."
@@ -637,9 +639,9 @@ extension (xpm, xbm, gif, jpg, or png) located in
                specs)
           (dolist (elt widget-image-conversion)
             (dolist (ext (cdr elt))
-              (push (list :type (car elt) :file (concat image ext)) specs)))
-          (setq specs (nreverse specs))
-          (find-image specs)))
+              (push (list :type (car elt) :file (concat image ext))
+                    specs)))
+          (find-image (nreverse specs))))
        (t
         ;; Oh well.
         nil)))
@@ -649,14 +651,14 @@ extension (xpm, xbm, gif, jpg, or png) located in
 This exists as a variable so it can be set locally in certain
 buffers.")
 
-(defun widget-image-insert (widget tag image &optional down inactive)
+(defun widget-image-insert (widget tag image &optional _down _inactive)
   "In WIDGET, insert the text TAG or, if supported, IMAGE.
 IMAGE should either be an image or an image file name sans extension
 \(xpm, xbm, gif, jpg, or png) located in `widget-image-directory'.
 
 Optional arguments DOWN and INACTIVE are used instead of IMAGE when the
 button is pressed or inactive, respectively.  These are currently ignored."
-  (if (and (display-graphic-p)
+  (if (and (featurep 'image)
           (setq image (widget-image-find image)))
       (progn (widget-put widget :suppress-face t)
             (insert-image image tag))
@@ -1142,12 +1144,6 @@ the field."
        (kill-region (point) end)
       (call-interactively 'kill-line))))
 
-(defcustom widget-complete-field (lookup-key global-map "\M-\t")
-  "Default function to call for completion inside fields."
-  :options '(ispell-complete-word complete-tag lisp-complete-symbol)
-  :type 'function
-  :group 'widgets)
-
 (defun widget-narrow-to-field ()
   "Narrow to field."
   (interactive)
@@ -1162,10 +1158,25 @@ the field."
   "Complete content of editable field from point.
 When not inside a field, signal an error."
   (interactive)
+  (let ((data (widget-completions-at-point)))
+    (cond
+     ((functionp data) (funcall data))
+     ((consp data)
+      (let ((completion-extra-properties (nth 3 data)))
+        (completion-in-region (nth 0 data) (nth 1 data) (nth 2 data)
+                              (plist-get completion-extra-properties
+                                         :predicate))))
+     (t
+      (error "Not in an editable field")))))
+;; We may want to use widget completion in buffers where the major mode
+;; hasn't added widget-completions-at-point to completion-at-point-functions,
+;; so it's not really obsolete (yet).
+;; (make-obsolete 'widget-complete 'completion-at-point "24.1")
+
+(defun widget-completions-at-point ()
   (let ((field (widget-field-find (point))))
-    (if field
-       (widget-apply field :complete)
-      (error "Not in an editable field"))))
+    (when field
+      (widget-apply field :completions-function))))
 
 ;;; Setting up the buffer.
 
@@ -1308,7 +1319,7 @@ Unlike (get-char-property POS 'field), this works with empty fields too."
   (add-hook 'before-change-functions 'widget-before-change nil t)
   (add-hook 'after-change-functions 'widget-after-change nil t))
 
-(defun widget-after-change (from to old)
+(defun widget-after-change (from to _old)
   "Adjust field size and text properties."
   (let ((field (widget-field-find from))
        (other (widget-field-find to)))
@@ -1336,7 +1347,7 @@ Unlike (get-char-property POS 'field), this works with empty fields too."
                     (goto-char end)
                     (while (and (eq (preceding-char) ?\s)
                                 (> (point) begin))
-                      (delete-backward-char 1)))))))
+                      (delete-char -1)))))))
        (widget-specify-secret field))
       (widget-apply field :notify field))))
 
@@ -1432,11 +1443,11 @@ The value of the :type attribute should be an unconverted widget type."
 
 (define-widget 'default nil
   "Basic widget other widgets are derived from."
-  :value-to-internal (lambda (widget value) value)
-  :value-to-external (lambda (widget value) value)
+  :value-to-internal (lambda (_widget value) value)
+  :value-to-external (lambda (_widget value) value)
   :button-prefix 'widget-button-prefix
   :button-suffix 'widget-button-suffix
-  :complete 'widget-default-complete
+  :completions-function #'widget-default-completions
   :create 'widget-default-create
   :indent nil
   :offset 0
@@ -1460,11 +1471,22 @@ The value of the :type attribute should be an unconverted widget type."
   :notify 'widget-default-notify
   :prompt-value 'widget-default-prompt-value)
 
-(defun widget-default-complete (widget)
-  "Call the value of the :complete-function property of WIDGET.
-If that does not exist, call the value of `widget-complete-field'."
-  (call-interactively (or (widget-get widget :complete-function)
-                         widget-complete-field)))
+(defvar widget--completing-widget)
+
+(defun widget-default-completions (widget)
+  "Return completion data, like `completion-at-point-functions' would."
+  (let ((completions (widget-get widget :completions)))
+    (if completions
+        (list (widget-field-start widget)
+              (max (point) (widget-field-text-end widget))
+              completions)
+      (if (widget-get widget :complete)
+          (lambda () (widget-apply widget :complete))
+        (if (widget-get widget :complete-function)
+            (lambda ()
+              (let ((widget--completing-widget widget))
+                (call-interactively
+                 (widget-get widget :complete-function)))))))))
 
 (defun widget-default-create (widget)
   "Create WIDGET at point in the current buffer."
@@ -1479,7 +1501,7 @@ If that does not exist, call the value of `widget-complete-field'."
      ;; Parse escapes in format.
      (while (re-search-forward "%\\(.\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?\[)
@@ -1512,7 +1534,7 @@ If that does not exist, call the value of `widget-complete-field'."
                    (setq doc-begin (point))
                    (insert doc)
                    (while (eq (preceding-char) ?\n)
-                     (delete-backward-char 1))
+                     (delete-char -1))
                    (insert ?\n)
                    (setq doc-end (point)))))
               ((eq escape ?h)
@@ -1541,7 +1563,7 @@ If that does not exist, call the value of `widget-complete-field'."
      (widget-put widget :to to)))
   (widget-clear-undo))
 
-(defun widget-default-format-handler (widget escape)
+(defun widget-default-format-handler (_widget escape)
   (error "Unknown escape `%c'" escape))
 
 (defun widget-default-button-face-get (widget)
@@ -1649,16 +1671,16 @@ If that does not exist, call the value of `widget-complete-field'."
     (when parent
       (widget-apply parent :notify widget event))))
 
-(defun widget-default-notify (widget child &optional event)
+(defun widget-default-notify (widget _child &optional event)
   "Pass notification to parent."
   (widget-default-action widget event))
 
-(defun widget-default-prompt-value (widget prompt value unbound)
+(defun widget-default-prompt-value (_widget prompt _value _unbound)
   "Read an arbitrary value."
   (eval-minibuffer prompt))
 
 (defun widget-docstring (widget)
-  "Return the documentation string specificied by WIDGET, or nil if none.
+  "Return the documentation string specified by WIDGET, or nil if none.
 If WIDGET has a `:doc' property, that specifies the documentation string.
 Otherwise, try the `:documentation-property' property.  If this
 is a function, call it with the widget's value as an argument; if
@@ -1701,14 +1723,14 @@ as the argument to `documentation-property'."
   ;; Match if the value is the same.
   (equal (widget-get widget :value) value))
 
-(defun widget-item-match-inline (widget values)
+(defun widget-item-match-inline (widget vals)
   ;; Match if the value is the same.
   (let ((value (widget-get widget :value)))
     (and (listp value)
-        (<= (length value) (length values))
-        (let ((head (widget-sublist values 0 (length value))))
+        (<= (length value) (length vals))
+        (let ((head (widget-sublist vals 0 (length value))))
           (and (equal head value)
-               (cons head (widget-sublist values (length value))))))))
+               (cons head (widget-sublist vals (length value))))))))
 
 (defun widget-sublist (list start &optional end)
   "Return the sublist of LIST from START to END.
@@ -1793,7 +1815,7 @@ If END is omitted, it defaults to the length of LIST."
   "A link to an info file."
   :action 'widget-info-link-action)
 
-(defun widget-info-link-action (widget &optional event)
+(defun widget-info-link-action (widget &optional _event)
   "Open the info node specified by WIDGET."
   (info (widget-value widget)))
 
@@ -1803,7 +1825,7 @@ If END is omitted, it defaults to the length of LIST."
   "A link to an www page."
   :action 'widget-url-link-action)
 
-(defun widget-url-link-action (widget &optional event)
+(defun widget-url-link-action (widget &optional _event)
   "Open the URL specified by WIDGET."
   (browse-url (widget-value widget)))
 
@@ -1813,7 +1835,7 @@ If END is omitted, it defaults to the length of LIST."
   "A link to an Emacs function."
   :action 'widget-function-link-action)
 
-(defun widget-function-link-action (widget &optional event)
+(defun widget-function-link-action (widget &optional _event)
   "Show the function specified by WIDGET."
   (describe-function (widget-value widget)))
 
@@ -1823,7 +1845,7 @@ If END is omitted, it defaults to the length of LIST."
   "A link to an Emacs variable."
   :action 'widget-variable-link-action)
 
-(defun widget-variable-link-action (widget &optional event)
+(defun widget-variable-link-action (widget &optional _event)
   "Show the variable specified by WIDGET."
   (describe-variable (widget-value widget)))
 
@@ -1833,7 +1855,7 @@ If END is omitted, it defaults to the length of LIST."
   "A link to a file."
   :action 'widget-file-link-action)
 
-(defun widget-file-link-action (widget &optional event)
+(defun widget-file-link-action (widget &optional _event)
   "Find the file specified by WIDGET."
   (find-file (widget-value widget)))
 
@@ -1843,7 +1865,7 @@ If END is omitted, it defaults to the length of LIST."
   "A link to an Emacs Lisp library file."
   :action 'widget-emacs-library-link-action)
 
-(defun widget-emacs-library-link-action (widget &optional event)
+(defun widget-emacs-library-link-action (widget &optional _event)
   "Find the Emacs library file specified by WIDGET."
   (find-file (locate-library (widget-value widget))))
 
@@ -1853,7 +1875,7 @@ If END is omitted, it defaults to the length of LIST."
   "A link to Commentary in an Emacs Lisp library file."
   :action 'widget-emacs-commentary-link-action)
 
-(defun widget-emacs-commentary-link-action (widget &optional event)
+(defun widget-emacs-commentary-link-action (widget &optional _event)
   "Find the Commentary section of the Emacs file specified by WIDGET."
   (finder-commentary (widget-value widget)))
 
@@ -1876,6 +1898,7 @@ by some other text in the `:format' string (if specified)."
   :valid-regexp ""
   :error "Field's value doesn't match allowed forms"
   :value-create 'widget-field-value-create
+  :value-set 'widget-field-value-set
   :value-delete 'widget-field-value-delete
   :value-get 'widget-field-value-get
   :match 'widget-field-match)
@@ -1883,7 +1906,7 @@ by some other text in the `:format' string (if specified)."
 (defvar widget-field-history nil
   "History of field minibuffer edits.")
 
-(defun widget-field-prompt-internal (widget prompt initial history)
+(defun widget-field-prompt-internal (_widget prompt initial history)
   "Read string for WIDGET prompting with PROMPT.
 INITIAL is the initial input and HISTORY is a symbol containing
 the earlier input."
@@ -1903,7 +1926,7 @@ the earlier input."
 
 (defvar widget-edit-functions nil)
 
-(defun widget-field-action (widget &optional event)
+(defun widget-field-action (widget &optional _event)
   "Move to next field."
   (widget-forward 1)
   (run-hook-with-args 'widget-edit-functions widget))
@@ -1914,6 +1937,17 @@ the earlier input."
                        (widget-apply widget :value-get))
     widget))
 
+(defun widget-field-value-set (widget value)
+  "Set an editable text field WIDGET to VALUE"
+  (let ((from (widget-field-start widget))
+       (to (widget-field-text-end widget))
+       (buffer (widget-field-buffer widget)))
+    (when (and from to (buffer-live-p buffer))
+      (with-current-buffer buffer
+       (goto-char from)
+       (delete-char (- to from))
+       (insert value)))))
+
 (defun widget-field-value-create (widget)
   "Create an editable text field."
   (let ((size (widget-get widget :size))
@@ -1946,12 +1980,15 @@ the earlier input."
     (when (overlayp overlay)
       (delete-overlay overlay))))
 
-(defun widget-field-value-get (widget)
-  "Return current text in editing field."
+(defun widget-field-value-get (widget &optional no-truncate)
+  "Return current text in editing field.
+Normally, trailing spaces within the editing field are truncated.
+But if NO-TRUNCATE is non-nil, include them."
   (let ((from (widget-field-start widget))
-       (to (widget-field-text-end widget))
+       (to   (if no-truncate
+                 (widget-field-end widget)
+               (widget-field-text-end widget)))
        (buffer (widget-field-buffer widget))
-       (size (widget-get widget :size))
        (secret (widget-get widget :secret))
        (old (current-buffer)))
     (if (and from to)
@@ -1968,7 +2005,7 @@ the earlier input."
            result))
       (widget-get widget :value))))
 
-(defun widget-field-match (widget value)
+(defun widget-field-match (_widget value)
   ;; Match any string.
   (stringp value))
 
@@ -2039,7 +2076,7 @@ when he invoked the menu."
   :type 'boolean
   :group 'widgets)
 
-(defun widget-choice-mouse-down-action (widget &optional event)
+(defun widget-choice-mouse-down-action (widget &optional _event)
   ;; Return non-nil if we need a menu.
   (let ((args (widget-get widget :args))
        (old (widget-get widget :choice)))
@@ -2123,14 +2160,14 @@ when he invoked the menu."
            found (widget-apply current :match value)))
     found))
 
-(defun widget-choice-match-inline (widget values)
+(defun widget-choice-match-inline (widget vals)
   ;; Matches if one of the choices matches.
   (let ((args (widget-get widget :args))
        current found)
     (while (and args (null found))
       (setq current (car args)
            args (cdr args)
-           found (widget-match-inline current values)))
+           found (widget-match-inline current vals)))
     found))
 
 ;;; The `toggle' Widget.
@@ -2140,27 +2177,19 @@ when he invoked the menu."
   :format "%[%v%]\n"
   :value-create 'widget-toggle-value-create
   :action 'widget-toggle-action
-  :match (lambda (widget value) t)
+  :match (lambda (_widget _value) t)
   :on "on"
   :off "off")
 
 (defun widget-toggle-value-create (widget)
   "Insert text representing the `on' and `off' states."
-  (if (widget-value widget)
-      (let ((image (widget-get widget :on-glyph)))
-       (and (display-graphic-p)
-            (listp image)
-            (not (eq (car image) 'image))
-            (widget-put widget :on-glyph (setq image (eval image))))
-       (widget-image-insert widget
-                            (widget-get widget :on)
-                            image))
-    (let ((image (widget-get widget :off-glyph)))
-      (and (display-graphic-p)
-          (listp image)
-          (not (eq (car image) 'image))
-          (widget-put widget :off-glyph (setq image (eval image))))
-      (widget-image-insert widget (widget-get widget :off) image))))
+  (let* ((val (widget-value widget))
+        (text (widget-get widget (if val :on :off)))
+        (img (widget-image-find
+              (widget-get widget (if val :on-glyph :off-glyph)))))
+    (widget-image-insert widget (or text "")
+                        (if img
+                            (append img '(:ascent center))))))
 
 (defun widget-toggle-action (widget &optional event)
   ;; Toggle value.
@@ -2179,19 +2208,9 @@ when he invoked the menu."
   ;; We could probably do the same job as the images using single
   ;; space characters in a boxed face with a stretch specification to
   ;; make them square.
-  :on-glyph '(create-image "\300\300\141\143\067\076\034\030"
-                          'xbm t :width 8 :height 8
-                          :background "grey75" ; like default mode line
-                          :foreground "black"
-                          :relief -2
-                          :ascent 'center)
+  :on-glyph "checked"
   :off "[ ]"
-  :off-glyph '(create-image (make-string 8 0)
-                           'xbm t :width 8 :height 8
-                           :background "grey75"
-                           :foreground "black"
-                           :relief -2
-                           :ascent 'center)
+  :off-glyph "unchecked"
   :help-echo "Toggle this item."
   :action 'widget-checkbox-action)
 
@@ -2223,11 +2242,10 @@ when he invoked the menu."
 
 (defun widget-checklist-value-create (widget)
   ;; Insert all values
-  (let ((alist (widget-checklist-match-find widget (widget-get widget :value)))
-       (args (widget-get widget :args)))
-    (while args
-      (widget-checklist-add-item widget (car args) (assq (car args) alist))
-      (setq args (cdr args)))
+  (let ((alist (widget-checklist-match-find widget))
+       (args  (widget-get widget :args)))
+    (dolist (item args)
+      (widget-checklist-add-item widget item (assq item alist)))
     (widget-put widget :children (nreverse (widget-get widget :children)))))
 
 (defun widget-checklist-add-item (widget type chosen)
@@ -2248,7 +2266,7 @@ If the item is checked, CHOSEN is a cons whose cdr is the value."
      ;; Parse % escapes in format.
      (while (re-search-forward "%\\([bv%]\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?b)
@@ -2275,34 +2293,35 @@ If the item is checked, CHOSEN is a cons whose cdr is the value."
      (and button (widget-put widget :buttons (cons button buttons)))
      (and child (widget-put widget :children (cons child children))))))
 
-(defun widget-checklist-match (widget values)
+(defun widget-checklist-match (widget vals)
   ;; All values must match a type in the checklist.
-  (and (listp values)
-       (null (cdr (widget-checklist-match-inline widget values)))))
+  (and (listp vals)
+       (null (cdr (widget-checklist-match-inline widget vals)))))
 
-(defun widget-checklist-match-inline (widget values)
+(defun widget-checklist-match-inline (widget vals)
   ;; Find the values which match a type in the checklist.
   (let ((greedy (widget-get widget :greedy))
        (args (copy-sequence (widget-get widget :args)))
        found rest)
-    (while values
-      (let ((answer (widget-checklist-match-up args values)))
+    (while vals
+      (let ((answer (widget-checklist-match-up args vals)))
        (cond (answer
-              (let ((vals (widget-match-inline answer values)))
-                (setq found (append found (car vals))
-                      values (cdr vals)
+              (let ((vals2 (widget-match-inline answer vals)))
+                (setq found (append found (car vals2))
+                      vals (cdr vals2)
                       args (delq answer args))))
              (greedy
-              (setq rest (append rest (list (car values)))
-                    values (cdr values)))
+              (setq rest (append rest (list (car vals)))
+                    vals (cdr vals)))
              (t
-              (setq rest (append rest values)
-                    values nil)))))
+              (setq rest (append rest vals)
+                    vals nil)))))
     (cons found rest)))
 
-(defun widget-checklist-match-find (widget vals)
+(defun widget-checklist-match-find (widget &optional vals)
   "Find the vals which match a type in the checklist.
 Return an alist of (TYPE MATCH)."
+  (or vals (setq vals (widget-get widget :value)))
   (let ((greedy (widget-get widget :greedy))
        (args (copy-sequence (widget-get widget :args)))
        found)
@@ -2341,7 +2360,7 @@ Return an alist of (TYPE MATCH)."
     result))
 
 (defun widget-checklist-validate (widget)
-  ;; Ticked chilren must be valid.
+  ;; Ticked children must be valid.
   (let ((children (widget-get widget :children))
        child button found)
     (while (and children (not found))
@@ -2378,7 +2397,7 @@ Return an alist of (TYPE MATCH)."
   :off "( )"
   :off-glyph "radio0")
 
-(defun widget-radio-button-notify (widget child &optional event)
+(defun widget-radio-button-notify (widget _child &optional event)
   ;; Tell daddy.
   (widget-apply (widget-get widget :parent) :action widget event))
 
@@ -2431,7 +2450,7 @@ Return an alist of (TYPE MATCH)."
      ;; Parse % escapes in format.
      (while (re-search-forward "%\\([bv%]\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?b)
@@ -2547,7 +2566,7 @@ Return an alist of (TYPE MATCH)."
   :help-echo "Insert a new item into the list at this position."
   :action 'widget-insert-button-action)
 
-(defun widget-insert-button-action (widget &optional event)
+(defun widget-insert-button-action (widget &optional _event)
   ;; Ask the parent to insert a new item.
   (widget-apply (widget-get widget :parent)
                :insert-before (widget-get widget :widget)))
@@ -2560,7 +2579,7 @@ Return an alist of (TYPE MATCH)."
   :help-echo "Delete this item from the list."
   :action 'widget-delete-button-action)
 
-(defun widget-delete-button-action (widget &optional event)
+(defun widget-delete-button-action (widget &optional _event)
   ;; Ask the parent to insert a new item.
   (widget-apply (widget-get widget :parent)
                :delete-at (widget-get widget :widget)))
@@ -2607,7 +2626,7 @@ Return an alist of (TYPE MATCH)."
   (let* ((value (widget-get widget :value))
         (type (nth 0 (widget-get widget :args)))
         children)
-    (widget-put widget :value-pos (copy-marker (point)))
+    (widget-put widget :value-pos (point-marker))
     (set-marker-insertion-type (widget-get widget :value-pos) t)
     (while value
       (let ((answer (widget-match-inline type value)))
@@ -2710,7 +2729,7 @@ Return an alist of (TYPE MATCH)."
      ;; Parse % escapes in format.
      (while (re-search-forward "%\\(.\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?i)
@@ -2783,10 +2802,10 @@ Return an alist of (TYPE MATCH)."
   ;; Get the default of the components.
   (mapcar 'widget-default-get (widget-get widget :args)))
 
-(defun widget-group-match (widget values)
+(defun widget-group-match (widget vals)
   ;; Match if the components match.
-  (and (listp values)
-       (let ((match (widget-group-match-inline widget values)))
+  (and (listp vals)
+       (let ((match (widget-group-match-inline widget vals)))
         (and match (null (cdr match))))))
 
 (defun widget-group-match-inline (widget vals)
@@ -2795,11 +2814,10 @@ Return an alist of (TYPE MATCH)."
        argument answer found)
     (while args
       (setq argument (car args)
-           args (cdr args)
-           answer (widget-match-inline argument vals))
-      (if answer
-         (setq vals (cdr answer)
-               found (append found (car answer)))
+           args     (cdr args))
+      (if (setq answer (widget-match-inline argument vals))
+         (setq found (append found (car answer))
+               vals (cdr answer))
        (setq vals nil
              args nil)))
     (if answer
@@ -2808,33 +2826,25 @@ Return an alist of (TYPE MATCH)."
 ;;; The `visibility' Widget.
 
 (define-widget 'visibility 'item
-  "An indicator and manipulator for hidden items."
+  "An indicator and manipulator for hidden items.
+
+The following properties have special meanings for this widget:
+:on-glyph  Image filename or spec to display when the item is visible.
+:on        Text shown if the \"on\" image is nil or cannot be displayed.
+:off-glyph Image filename or spec to display when the item is hidden.
+:off       Text shown if the \"off\" image is nil cannot be displayed."
   :format "%[%v%]"
   :button-prefix ""
   :button-suffix ""
+  :on-glyph "down"
   :on "Hide"
+  :off-glyph "right"
   :off "Show"
   :value-create 'widget-visibility-value-create
   :action 'widget-toggle-action
-  :match (lambda (widget value) t))
-
-(defun widget-visibility-value-create (widget)
-  ;; Insert text representing the `on' and `off' states.
-  (let ((on (widget-get widget :on))
-       (off (widget-get widget :off)))
-    (if on
-       (setq on (concat widget-push-button-prefix
-                        on
-                        widget-push-button-suffix))
-      (setq on ""))
-    (if off
-       (setq off (concat widget-push-button-prefix
-                         off
-                         widget-push-button-suffix))
-      (setq off ""))
-    (if (widget-value widget)
-       (widget-image-insert widget on "down" "down-pushed")
-      (widget-image-insert widget off "right" "right-pushed"))))
+  :match (lambda (_widget _value) t))
+
+(defalias 'widget-visibility-value-create 'widget-toggle-value-create)
 
 ;;; The `documentation-link' Widget.
 ;;
@@ -2846,7 +2856,7 @@ Return an alist of (TYPE MATCH)."
   :help-echo "Describe this symbol"
   :action 'widget-documentation-link-action)
 
-(defun widget-documentation-link-action (widget &optional event)
+(defun widget-documentation-link-action (widget &optional _event)
   "Display documentation for WIDGET's value.  Ignore optional argument EVENT."
   (let* ((string (widget-get widget :value))
         (symbol (intern string)))
@@ -2900,15 +2910,7 @@ link for that string."
              (push (widget-convert-button widget-documentation-link-type
                                           begin end :value name)
                    buttons)))))
-      (widget-put widget :buttons buttons)))
-  (let ((indent (widget-get widget :indent)))
-    (when (and indent (not (zerop indent)))
-      (save-excursion
-       (save-restriction
-         (narrow-to-region from to)
-         (goto-char (point-min))
-         (while (search-forward "\n" nil t)
-           (insert-char ?\s indent)))))))
+      (widget-put widget :buttons buttons))))
 
 ;;; The `documentation-string' Widget.
 
@@ -2927,35 +2929,51 @@ link for that string."
        (start (point)))
     (if (string-match "\n" doc)
        (let ((before (substring doc 0 (match-beginning 0)))
-             (after (substring doc (match-beginning 0)))
-             button)
-         (when (and indent (not (zerop indent)))
-           (insert-char ?\s indent))
+             (after (substring doc (match-end 0)))
+             button end)
+         (widget-documentation-string-indent-to indent)
          (insert before ?\s)
          (widget-documentation-link-add widget start (point))
          (setq button
                (widget-create-child-and-convert
                 widget (widget-get widget :visibility-widget)
                 :help-echo "Show or hide rest of the documentation."
-                :on "Hide Rest"
+                :on "Hide"
                 :off "More"
                 :always-active t
                 :action 'widget-parent-action
                 shown))
          (when shown
+           (insert ?\n)
            (setq start (point))
            (when (and indent (not (zerop indent)))
              (insert-char ?\s indent))
            (insert after)
-           (widget-documentation-link-add widget start (point)))
+           (setq end (point))
+           (widget-documentation-link-add widget start end)
+           ;; Indent the subsequent lines.
+           (when (and indent (> indent 0))
+             (save-excursion
+               (save-restriction
+                 (narrow-to-region start end)
+                 (goto-char (point-min))
+                 (while (search-forward "\n" nil t)
+                   (widget-documentation-string-indent-to indent))))))
          (widget-put widget :buttons (list button)))
-      (when (and indent (not (zerop indent)))
-       (insert-char ?\s indent))
+      (widget-documentation-string-indent-to indent)
       (insert doc)
       (widget-documentation-link-add widget start (point))))
   (insert ?\n))
 
-(defun widget-documentation-string-action (widget &rest ignore)
+(defun widget-documentation-string-indent-to (col)
+  (when (and (numberp col)
+            (> col 0))
+    (let ((opoint (point)))
+      (indent-to col)
+      (put-text-property opoint (point)
+                        'display `(space :align-to ,col)))))
+
+(defun widget-documentation-string-action (widget &rest _ignore)
   ;; Toggle documentation.
   (let ((parent (widget-get widget :parent)))
     (widget-put parent :documentation-shown
@@ -2993,7 +3011,7 @@ Optional ARGS specifies additional keyword arguments for the
   :prompt-value 'widget-const-prompt-value
   :format "%t\n%d")
 
-(defun widget-const-prompt-value (widget prompt value unbound)
+(defun widget-const-prompt-value (widget _prompt _value _unbound)
   ;; Return the value of the const.
   (widget-value widget))
 
@@ -3031,21 +3049,6 @@ as the value."
   :complete-function 'ispell-complete-word
   :prompt-history 'widget-string-prompt-value-history)
 
-(defvar widget)
-
-(defun widget-string-complete ()
-  "Complete contents of string field.
-Completions are taken from the :completion-alist property of the
-widget.  If that isn't a list, it's evalled and expected to yield a list."
-  (interactive)
-  (let* ((completion-ignore-case (widget-get widget :completion-ignore-case))
-        (alist (widget-get widget :completion-alist))
-        (_ (unless (listp alist)
-             (setq alist (eval alist)))))
-    (completion-in-region (widget-field-start widget)
-                          (max (point) (widget-field-text-end widget))
-                          alist)))
-
 (define-widget 'regexp 'string
   "A regular expression."
   :match 'widget-regexp-match
@@ -3054,7 +3057,7 @@ widget.  If that isn't a list, it's evalled and expected to yield a list."
   ;; :value-face 'widget-single-line-field
   :tag "Regexp")
 
-(defun widget-regexp-match (widget value)
+(defun widget-regexp-match (_widget value)
   ;; Match valid regexps.
   (and (stringp value)
        (condition-case nil
@@ -3073,20 +3076,13 @@ widget.  If that isn't a list, it's evalled and expected to yield a list."
 (define-widget 'file 'string
   "A file widget.
 It reads a file name from an editable text field."
-  :complete-function 'widget-file-complete
+  :completions #'completion-file-name-table
   :prompt-value 'widget-file-prompt-value
   :format "%{%t%}: %v"
   ;; Doesn't work well with terminating newline.
   ;; :value-face 'widget-single-line-field
   :tag "File")
 
-(defun widget-file-complete ()
-  "Perform completion on file name preceding point."
-  (interactive)
-  (completion-in-region (widget-field-start widget)
-                        (max (point) (widget-field-text-end widget))
-                        'completion-file-name-table))
-
 (defun widget-file-prompt-value (widget prompt value unbound)
   ;; Read file from minibuffer.
   (abbreviate-file-name
@@ -3125,16 +3121,16 @@ It reads a directory name from an editable text field."
   :value nil
   :tag "Symbol"
   :format "%{%t%}: %v"
-  :match (lambda (widget value) (symbolp value))
-  :complete-function 'lisp-complete-symbol
+  :match (lambda (_widget value) (symbolp value))
+  :completions obarray
   :prompt-internal 'widget-symbol-prompt-internal
   :prompt-match 'symbolp
   :prompt-history 'widget-symbol-prompt-value-history
-  :value-to-internal (lambda (widget value)
+  :value-to-internal (lambda (_widget value)
                       (if (symbolp value)
                           (symbol-name value)
                         value))
-  :value-to-external (lambda (widget value)
+  :value-to-external (lambda (_widget value)
                       (if (stringp value)
                           (intern value)
                         value)))
@@ -3154,9 +3150,8 @@ It reads a directory name from an editable text field."
 
 (define-widget 'function 'restricted-sexp
   "A Lisp function."
-  :complete-function (lambda ()
-                      (interactive)
-                      (lisp-complete-symbol 'fboundp))
+  :completions (apply-partially #'completion-table-with-predicate
+                                obarray #'fboundp 'strict)
   :prompt-value 'widget-field-prompt-value
   :prompt-internal 'widget-symbol-prompt-internal
   :prompt-match 'fboundp
@@ -3178,9 +3173,8 @@ It reads a directory name from an editable text field."
   "A Lisp variable."
   :prompt-match 'boundp
   :prompt-history 'widget-variable-prompt-value-history
-  :complete-function (lambda ()
-                      (interactive)
-                      (lisp-complete-symbol 'boundp))
+  :completions (apply-partially #'completion-table-with-predicate
+                                obarray #'boundp 'strict)
   :tag "Variable")
 
 (define-widget 'coding-system 'symbol
@@ -3191,9 +3185,8 @@ It reads a directory name from an editable text field."
   :prompt-history 'coding-system-value-history
   :prompt-value 'widget-coding-system-prompt-value
   :action 'widget-coding-system-action
-  :complete-function (lambda ()
-                      (interactive)
-                      (lisp-complete-symbol 'coding-system-p))
+  :completions (apply-partially #'completion-table-with-predicate
+                                obarray #'coding-system-p 'strict)
   :validate (lambda (widget)
              (unless (coding-system-p (widget-value widget))
                (widget-put widget :error (format "Invalid coding system: %S"
@@ -3202,7 +3195,7 @@ It reads a directory name from an editable text field."
   :value 'undecided
   :prompt-match 'coding-system-p)
 
-(defun widget-coding-system-prompt-value (widget prompt value unbound)
+(defun widget-coding-system-prompt-value (widget prompt value _unbound)
   "Read coding-system from minibuffer."
   (if (widget-get widget :base-only)
       (intern
@@ -3292,7 +3285,7 @@ It reads a directory name from an editable text field."
        (key-description value))
     value))
 
-(defun widget-key-sequence-value-to-external (widget value)
+(defun widget-key-sequence-value-to-external (_widget value)
   (if (stringp value)
       (if (string-match "\\`[[:space:]]*\\'" value)
          widget-key-sequence-default-value
@@ -3306,13 +3299,13 @@ It reads a directory name from an editable text field."
   :format "%{%t%}: %v"
   :value nil
   :validate 'widget-sexp-validate
-  :match (lambda (widget value) t)
+  :match (lambda (_widget _value) t)
   :value-to-internal 'widget-sexp-value-to-internal
-  :value-to-external (lambda (widget value) (read value))
+  :value-to-external (lambda (_widget value) (read value))
   :prompt-history 'widget-sexp-prompt-value-history
   :prompt-value 'widget-sexp-prompt-value)
 
-(defun widget-sexp-value-to-internal (widget value)
+(defun widget-sexp-value-to-internal (_widget value)
   ;; Use pp for printer representation.
   (let ((pp (if (symbolp value)
                (prin1-to-string value)
@@ -3330,7 +3323,7 @@ It reads a directory name from an editable text field."
     (insert (widget-apply widget :value-get))
     (goto-char (point-min))
     (let (err)
-      (condition-case data
+      (condition-case data ;Note: We get a spurious byte-compile warning here.
          (progn
            ;; Avoid a confusing end-of-file error.
            (skip-syntax-forward "\\s-")
@@ -3419,15 +3412,16 @@ To use this type, you must define :match or :match-alternatives."
   :format "%{%t%}: %v\n"
   :valid-regexp "\\`.\\'"
   :error "This field should contain a single character"
-  :value-to-internal (lambda (widget value)
+  :value-get (lambda (w) (widget-field-value-get w t))
+  :value-to-internal (lambda (_widget value)
                       (if (stringp value)
                           value
                         (char-to-string value)))
-  :value-to-external (lambda (widget value)
+  :value-to-external (lambda (_widget value)
                       (if (stringp value)
                           (aref value 0)
                         value))
-  :match (lambda (widget value)
+  :match (lambda (_widget value)
           (characterp value)))
 
 (define-widget 'list 'group
@@ -3440,8 +3434,8 @@ To use this type, you must define :match or :match-alternatives."
   :tag "Vector"
   :format "%{%t%}:\n%v"
   :match 'widget-vector-match
-  :value-to-internal (lambda (widget value) (append value nil))
-  :value-to-external (lambda (widget value) (apply 'vector value)))
+  :value-to-internal (lambda (_widget value) (append value nil))
+  :value-to-external (lambda (_widget value) (apply 'vector value)))
 
 (defun widget-vector-match (widget value)
   (and (vectorp value)
@@ -3453,9 +3447,9 @@ To use this type, you must define :match or :match-alternatives."
   :tag "Cons-cell"
   :format "%{%t%}:\n%v"
   :match 'widget-cons-match
-  :value-to-internal (lambda (widget value)
+  :value-to-internal (lambda (_widget value)
                       (list (car value) (cdr value)))
-  :value-to-external (lambda (widget value)
+  :value-to-external (lambda (_widget value)
                       (apply 'cons value)))
 
 (defun widget-cons-match (widget value)
@@ -3468,14 +3462,14 @@ To use this type, you must define :match or :match-alternatives."
 ;; Recursive datatypes.
 
 (define-widget 'lazy 'default
-  "Base widget for recursive datastructures.
+  "Base widget for recursive data structures.
 
 The `lazy' widget will, when instantiated, contain a single inferior
 widget, of the widget type specified by the :type parameter.  The
 value of the `lazy' widget is the same as the value of the inferior
 widget.  When deriving a new widget from the 'lazy' widget, the :type
 parameter is allowed to refer to the widget currently being defined,
-thus allowing recursive datastructures to be described.
+thus allowing recursive data structures to be described.
 
 The :type parameter takes the same arguments as the defcustom
 parameter with the same name.
@@ -3485,7 +3479,7 @@ not allow recursion.  That is, when you define a new widget type, none
 of the inferior widgets may be of the same type you are currently
 defining.
 
-In Lisp, however, it is custom to define datastructures in terms of
+In Lisp, however, it is custom to define data structures in terms of
 themselves.  A list, for example, is defined as either nil, or a cons
 cell whose cdr itself is a list.  The obvious way to translate this
 into a widget type would be
@@ -3508,7 +3502,7 @@ example:
     :type '(choice (const nil) (cons :value (nil) sexp sexp-list)))"
   :format "%{%t%}: %v"
   ;; We don't convert :type because we want to allow recursive
-  ;; datastructures.  This is slow, so we should not create speed
+  ;; data structures.  This is slow, so we should not create speed
   ;; critical widgets by deriving from this.
   :convert-widget 'widget-value-convert-widget
   :value-create 'widget-type-value-create
@@ -3616,7 +3610,7 @@ example:
   :button-suffix 'widget-push-button-suffix
   :prompt-value 'widget-choice-prompt-value)
 
-(defun widget-choice-prompt-value (widget prompt value unbound)
+(defun widget-choice-prompt-value (widget prompt value _unbound)
   "Make a choice."
   (let ((args (widget-get widget :args))
        (completion-ignore-case (widget-get widget :case-fold))
@@ -3684,7 +3678,7 @@ example:
   :on "on (non-nil)"
   :off "off (nil)")
 
-(defun widget-boolean-prompt-value (widget prompt value unbound)
+(defun widget-boolean-prompt-value (_widget prompt _value _unbound)
   ;; Toggle a boolean.
   (y-or-n-p prompt))
 \f
@@ -3694,21 +3688,35 @@ example:
 (define-widget 'color 'editable-field
   "Choose a color name (with sample)."
   :format "%{%t%}: %v (%{sample%})\n"
+  :value-create 'widget-color-value-create
   :size 10
   :tag "Color"
   :value "black"
-  :complete 'widget-color-complete
+  :completions (or facemenu-color-alist (defined-colors))
   :sample-face-get 'widget-color-sample-face-get
   :notify 'widget-color-notify
   :action 'widget-color-action)
 
-(defun widget-color-complete (widget)
-  "Complete the color in WIDGET."
-  (require 'facemenu)                  ; for facemenu-color-alist
-  (completion-in-region (widget-field-start widget)
-                        (max (point) (widget-field-text-end widget))
-                        (or facemenu-color-alist
-                            (sort (defined-colors) 'string-lessp))))
+(defun widget-color-value-create (widget)
+  (widget-field-value-create widget)
+  (widget-insert " ")
+  (widget-create-child-and-convert
+   widget 'push-button
+   :tag " Choose " :action 'widget-color--choose-action)
+  (widget-insert " "))
+
+(defun widget-color--choose-action (widget &optional _event)
+  (list-colors-display
+   nil nil
+   `(lambda (color)
+      (when (buffer-live-p ,(current-buffer))
+       (widget-value-set ',(widget-get widget :parent) color)
+       (let* ((buf (get-buffer "*Colors*"))
+              (win (get-buffer-window buf 0)))
+         (bury-buffer buf)
+         (and win (> (length (window-list)) 1)
+              (delete-window win)))
+       (pop-to-buffer ,(current-buffer))))))
 
 (defun widget-color-sample-face-get (widget)
   (let* ((value (condition-case nil
@@ -3722,8 +3730,6 @@ example:
   "Prompt for a color."
   (let* ((tag (widget-apply widget :menu-tag-get))
         (prompt (concat tag ": "))
-        (value (widget-value widget))
-        (start (widget-field-start widget))
         (answer (facemenu-read-color prompt)))
     (unless (zerop (length answer))
       (widget-value-set widget answer)