Function: widget-choose

widget-choose is a byte-compiled function defined in wid-edit.el.gz.

Signature

(widget-choose TITLE ITEMS &optional EVENT)

Documentation

Choose an item from a list.

First argument TITLE is the name of the list. Second argument ITEMS should be a menu, either with simple item definitions, or with extended item definitions. When ITEMS has simple item definitions, it is a list whose members are either
 (NAME . VALUE), to indicate selectable items, or just strings to
 indicate unselectable items.

When ITEMS is a menu that uses an extended format, then ITEMS should be a keymap, and each binding should look like this:
 (menu-item ITEM-NAME REAL-BINDING . ITEM-PROPERTY-LIST)
or like this: (menu-item ITEM-NAME) to indicate a non-selectable item. REAL-BINDING should be a symbol, and should not be a keymap, because submenus are not supported.

Optional third argument EVENT is an input event.

If EVENT is a mouse event, and the number of elements in items is less than widget-menu-max-size, a popup menu will be used, otherwise the minibuffer.

The user is asked to choose between each NAME from ITEMS. If ITEMS has simple item definitions, then this function returns the VALUE of the chosen element. If ITEMS is a keymap, then the return value is the symbol in the key vector, as in the argument of define-key.

Probably introduced at or before Emacs version 28.1.

Source Code

;; Defined in /usr/src/emacs/lisp/wid-edit.el.gz
(defun widget-choose (title items &optional event)
  "Choose an item from a list.

First argument TITLE is the name of the list.
Second argument ITEMS should be a menu, either with simple item definitions,
or with extended item definitions.
When ITEMS has simple item definitions, it is a list whose members are either
 (NAME . VALUE), to indicate selectable items, or just strings to
 indicate unselectable items.

When ITEMS is a menu that uses an extended format, then ITEMS should be a
keymap, and each binding should look like this:
 (menu-item ITEM-NAME REAL-BINDING . ITEM-PROPERTY-LIST)
or like this: (menu-item ITEM-NAME) to indicate a non-selectable item.
REAL-BINDING should be a symbol, and should not be a keymap, because submenus
are not supported.

Optional third argument EVENT is an input event.

If EVENT is a mouse event, and the number of elements in items is less than
`widget-menu-max-size', a popup menu will be used, otherwise the
minibuffer.

The user is asked to choose between each NAME from ITEMS.
If ITEMS has simple item definitions, then this function returns the VALUE of
the chosen element.  If ITEMS is a keymap, then the return value is the symbol
in the key vector, as in the argument of `define-key'."
  (cond ((and (< (length items) widget-menu-max-size)
	      event (display-popup-menus-p))
	 ;; Mouse click.
         (if (keymapp items)
             ;; Modify the keymap prompt, and then restore the old one, if any.
             (let ((prompt (keymap-prompt items)))
               (unwind-protect
                   (progn
                     (setq items (delete prompt items))
                     (push title (cdr items))
                     ;; Return just the first element of the list of events.
                     (car (x-popup-menu event items)))
                 (setq items (delete title items))
                 (when prompt
                   (push prompt (cdr items)))))
	   (x-popup-menu event (list title (cons "" items)))))
	((or widget-menu-minibuffer-flag
	     (> (length items) widget-menu-max-shortcuts))
         (when (keymapp items)
           (setq items (widget--simplify-menu items)))
	 ;; Read the choice of name from the minibuffer.
	 (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)))
		 (when (stringp try)
		   (setq val try))
		 (cdr (assoc val items))))))
	(t
         (when (keymapp items)
           (setq items (widget--simplify-menu items)))
	 ;; Construct a menu of the choices
	 ;; and then use it for prompting for a single character.
	 (let* ((next-digit ?0)
		alist choice some-choice-enabled value)
	   (with-current-buffer (get-buffer-create " widget-choose")
	     (erase-buffer)
	     (insert "Available choices:\n\n")
	     (while items
	       (setq choice (pop items))
	       (when (consp choice)
                 (let* ((name (substitute-command-keys (car choice)))
                        (function (cdr choice)))
                   (insert (format "%c = %s\n" next-digit name))
                   (push (cons next-digit function) alist)
                   (setq some-choice-enabled t)))
	       ;; 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")
	     (goto-char (point-min))
	     (forward-line))
	   (or some-choice-enabled
	       (error "None of the choices is currently meaningful"))
	   (save-window-excursion
             ;; Select window to be able to scroll it from minibuffer
             (with-selected-window
                 (display-buffer (get-buffer " widget-choose")
                                 '(display-buffer-in-direction
                                   (direction . bottom)
                                   (window-height . fit-window-to-buffer)))
               (setq value (read-char-choice
                            (format "%s: " title)
                            (mapcar #'car alist)))))
	   (cdr (assoc value alist))))))