1 ;;; rmc.el --- read from a multiple choice question -*- lexical-binding: t -*-
3 ;; Copyright (C) 2016-2018 Free Software Foundation, Inc.
5 ;; Maintainer: emacs-devel@gnu.org
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
29 (defun read-multiple-choice (prompt choices
)
30 "Ask user a multiple choice question.
31 PROMPT should be a string that will be displayed as the prompt.
33 CHOICES is an alist where the first element in each entry is a
34 character to be entered, the second element is a short name for
35 the entry to be displayed while prompting (if there's room, it
36 might be shortened), and the third, optional entry is a longer
37 explanation that will be displayed in a help buffer if the user
40 This function translates user input into responses by consulting
41 the bindings in `query-replace-map'; see the documentation of
42 that variable for more information. In this case, the useful
43 bindings are `recenter', `scroll-up', and `scroll-down'. If the
44 user enters `recenter', `scroll-up', or `scroll-down' responses,
45 perform the requested window recentering or scrolling and ask
48 When `use-dialog-box' is t (the default), this function can pop
49 up a dialog window to collect the user input. That functionality
50 requires `display-popup-menus-p' to return t. Otherwise, a text
53 The return value is the matching entry from the CHOICES list.
57 \(read-multiple-choice \"Continue connecting?\"
61 (let* ((altered-names nil
)
68 (let* ((name (cadr elem
))
69 (pos (seq-position name
(car elem
)))
72 ;; Not in the name string.
74 (format "[%c] %s" (car elem
) name
))
75 ;; The prompt character is in the name, so highlight
76 ;; it on graphical terminals...
77 ((display-supports-face-attributes-p
78 '(:underline t
) (window-frame))
79 (setq name
(copy-sequence name
))
80 (put-text-property pos
(1+ pos
)
81 'face
'read-multiple-choice-face
84 ;; And put it in [bracket] on non-graphical terminals.
87 (substring name
0 pos
)
89 (upcase (substring name pos
(1+ pos
)))
91 (substring name
(1+ pos
)))))))
92 (push (cons (car elem
) altered-name
)
95 (append choices
'((??
"?")))
97 tchar buf wrong-char answer
)
98 (save-window-excursion
107 (if (and (display-popup-menus-p)
108 last-input-event
; not during startup
109 (listp last-nonmenu-event
)
116 (cons (capitalize (cadr elem
))
120 (let ((cursor-in-echo-area t
))
123 (setq answer
(lookup-key query-replace-map
(vector tchar
) t
))
126 ((eq answer
'recenter
)
128 ((eq answer
'scroll-up
)
129 (ignore-errors (scroll-up-command)) t
)
130 ((eq answer
'scroll-down
)
131 (ignore-errors (scroll-down-command)) t
)
132 ((eq answer
'scroll-other-window
)
133 (ignore-errors (scroll-other-window)) t
)
134 ((eq answer
'scroll-other-window-down
)
135 (ignore-errors (scroll-other-window-down)) t
)
140 ;; The user has entered an invalid choice, so display the
142 (when (and (not (eq tchar nil
))
143 (not (assq tchar choices
)))
144 (setq wrong-char
(not (memq tchar
'(?? ?\C-h
)))
148 (with-help-window (setq buf
(get-buffer-create
149 "*Multiple Choice Help*"))
150 (with-current-buffer buf
153 (insert prompt
"\n\n")
154 (let* ((columns (/ (window-width) 25))
158 (dolist (elem choices
)
160 (unless (zerop times
)
161 (if (zerop (mod times columns
))
162 ;; Go to the next "line".
163 (goto-char (setq start
(point-max)))
167 (insert (make-string (max (- (* (mod times columns
)
173 (setq times
(1+ times
))
179 (cdr (assq (car elem
) altered-names
))))
180 (fill-region (point-min) (point-max))
182 (let ((start (point)))
183 (insert (nth 2 elem
))
186 (fill-region start
(point-max))))
189 (dolist (line (split-string text
"\n"))
194 (forward-line 1)))))))))))
195 (when (buffer-live-p buf
)
197 (assq tchar choices
)))