4

How to write a function in Emacs Lisp that interactively would give the opportunity to choose one of the options?

Choose your animal: Cow Rabbit Dog

You have to press 1 to select Cow, 2 to select Rabbit and 3 to select Dog

Drew
  • 75,699
  • 9
  • 109
  • 225
Valeriy
  • 377
  • 4
  • 16

2 Answers2

6
(defun foo (choice)
  "..."
  (interactive
   (list (completing-read "Choose: "
                          '(("1" . "Cow") ("2" . "Rabbit") ("3" . "Dog")) nil t)))
  (message "You chose `%s'" choice)
  choice)

Or if you want to let the input be the first letter (or another prefix):

(defun foo (choice)
  "..."
  (interactive
   (let ((completion-ignore-case  t))
     (list (completing-read "Choose: " '("Cow" "Rabbit" "Dog") nil t))))
  (message "You chose `%s'" choice)
  choice)
Drew
  • 75,699
  • 9
  • 109
  • 225
6

The function you are looking for is read-char-choice. I cite the corresponding documentation:

(read-char-choice PROMPT CHARS &optional INHIBIT-KEYBOARD-QUIT)

Read and return one of CHARS, prompting for PROMPT. Any input that is not one of CHARS is ignored.

If optional argument INHIBIT-KEYBOARD-QUIT is non-nil, ignore keyboard-quit events while waiting for a valid input.

A usage example:

(defvar valeriy-alist '((?1 "Cow" (lambda () (message "I am a cow") 'cow))
            (?2 "Rabbit" (lambda () (message "I am a lion") 'lion))
            (?3 "Dog" (lambda () (message "I am a wolf") 'wolf)))
  "List that associates number letters to descriptions and actions.")

(defun valeriy-choose ()
  "Lets the user choose the animal and takes the corresponding action.
Returns whatever the action returns."
  (interactive)
  (let ((choice (read-char-choice (mapconcat (lambda (item) (format "%c: %s" (car item) (cadr item))) valeriy-alist "; ")
                  (mapcar #'car valeriy-alist))))
    (funcall (nth 2 (assoc choice valeriy-alist)))))
Tobias
  • 32,569
  • 1
  • 34
  • 75