diff options
| author | Lars Ingebrigtsen | 2016-07-22 11:08:13 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2016-07-22 11:08:21 +0200 |
| commit | ad90397c599034a5f2a977baf9d04802f986eee2 (patch) | |
| tree | a67db24a98de952af5db6b14dca57682ed13d1b1 | |
| parent | 431641a2ecbd787a692957bcc5e59b600f63e832 (diff) | |
| download | emacs-ad90397c599034a5f2a977baf9d04802f986eee2.tar.gz emacs-ad90397c599034a5f2a977baf9d04802f986eee2.zip | |
Move read-multiple-choice to subr-x.el
* lisp/faces.el (read-multiple-choice-face): Fix doc string.
* lisp/emacs-lisp/subr-x.el (read-multiple-choice): Move here
from subr.el.
* lisp/gnus/message.el (subr-x): Ditto.
* lisp/net/nsm.el: Require subr-x for read-multiple-choice.
read-multiple-choice doesn't need to be in the dumped Emacs, so move
it to a less central file.
| -rw-r--r-- | lisp/emacs-lisp/subr-x.el | 165 | ||||
| -rw-r--r-- | lisp/faces.el | 2 | ||||
| -rw-r--r-- | lisp/gnus/message.el | 1 | ||||
| -rw-r--r-- | lisp/net/nsm.el | 1 | ||||
| -rw-r--r-- | lisp/subr.el | 165 |
5 files changed, 168 insertions, 166 deletions
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index e8d1939865f..173cd11fba4 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el | |||
| @@ -198,6 +198,171 @@ to bind a single value, BINDINGS can just be a plain tuple." | |||
| 198 | (substring string 0 (- (length string) (length suffix))) | 198 | (substring string 0 (- (length string) (length suffix))) |
| 199 | string)) | 199 | string)) |
| 200 | 200 | ||
| 201 | (defun read-multiple-choice (prompt choices) | ||
| 202 | "Ask user a multiple choice question. | ||
| 203 | PROMPT should be a string that will be displayed as the prompt. | ||
| 204 | |||
| 205 | CHOICES is an alist where the first element in each entry is a | ||
| 206 | character to be entered, the second element is a short name for | ||
| 207 | the entry to be displayed while prompting (if there's room, it | ||
| 208 | might be shortened), and the third, optional entry is a longer | ||
| 209 | explanation that will be displayed in a help buffer if the user | ||
| 210 | requests more help. | ||
| 211 | |||
| 212 | This function translates user input into responses by consulting | ||
| 213 | the bindings in `query-replace-map'; see the documentation of | ||
| 214 | that variable for more information. In this case, the useful | ||
| 215 | bindings are `recenter', `scroll-up', and `scroll-down'. If the | ||
| 216 | user enters `recenter', `scroll-up', or `scroll-down' responses, | ||
| 217 | perform the requested window recentering or scrolling and ask | ||
| 218 | again. | ||
| 219 | |||
| 220 | The return value is the matching entry from the CHOICES list. | ||
| 221 | |||
| 222 | Usage example: | ||
| 223 | |||
| 224 | \(read-multiple-choice \"Continue connecting?\" | ||
| 225 | '((?a \"always\") | ||
| 226 | (?s \"session only\") | ||
| 227 | (?n \"no\")))" | ||
| 228 | (let* ((altered-names nil) | ||
| 229 | (full-prompt | ||
| 230 | (format | ||
| 231 | "%s (%s): " | ||
| 232 | prompt | ||
| 233 | (mapconcat | ||
| 234 | (lambda (elem) | ||
| 235 | (let* ((name (cadr elem)) | ||
| 236 | (pos (seq-position name (car elem))) | ||
| 237 | (altered-name | ||
| 238 | (cond | ||
| 239 | ;; Not in the name string. | ||
| 240 | ((not pos) | ||
| 241 | (format "[%c] %s" (car elem) name)) | ||
| 242 | ;; The prompt character is in the name, so highlight | ||
| 243 | ;; it on graphical terminals... | ||
| 244 | ((display-supports-face-attributes-p | ||
| 245 | '(:underline t) (window-frame)) | ||
| 246 | (setq name (copy-sequence name)) | ||
| 247 | (put-text-property pos (1+ pos) | ||
| 248 | 'face 'read-multiple-choice-face | ||
| 249 | name) | ||
| 250 | name) | ||
| 251 | ;; And put it in [bracket] on non-graphical terminals. | ||
| 252 | (t | ||
| 253 | (concat | ||
| 254 | (substring name 0 pos) | ||
| 255 | "[" | ||
| 256 | (upcase (substring name pos (1+ pos))) | ||
| 257 | "]" | ||
| 258 | (substring name (1+ pos))))))) | ||
| 259 | (push (cons (car elem) altered-name) | ||
| 260 | altered-names) | ||
| 261 | altered-name)) | ||
| 262 | (append choices '((?? "?"))) | ||
| 263 | ", "))) | ||
| 264 | tchar buf wrong-char answer) | ||
| 265 | (save-window-excursion | ||
| 266 | (save-excursion | ||
| 267 | (while (not tchar) | ||
| 268 | (message "%s%s" | ||
| 269 | (if wrong-char | ||
| 270 | "Invalid choice. " | ||
| 271 | "") | ||
| 272 | full-prompt) | ||
| 273 | (setq tchar | ||
| 274 | (if (and (display-popup-menus-p) | ||
| 275 | last-input-event ; not during startup | ||
| 276 | (listp last-nonmenu-event) | ||
| 277 | use-dialog-box) | ||
| 278 | (x-popup-dialog | ||
| 279 | t | ||
| 280 | (cons prompt | ||
| 281 | (mapcar | ||
| 282 | (lambda (elem) | ||
| 283 | (cons (capitalize (cadr elem)) | ||
| 284 | (car elem))) | ||
| 285 | choices))) | ||
| 286 | (condition-case nil | ||
| 287 | (let ((cursor-in-echo-area t)) | ||
| 288 | (read-char)) | ||
| 289 | (error nil)))) | ||
| 290 | (setq answer (lookup-key query-replace-map (vector tchar) t)) | ||
| 291 | (setq tchar | ||
| 292 | (cond | ||
| 293 | ((eq answer 'recenter) | ||
| 294 | (recenter) t) | ||
| 295 | ((eq answer 'scroll-up) | ||
| 296 | (ignore-errors (scroll-up-command)) t) | ||
| 297 | ((eq answer 'scroll-down) | ||
| 298 | (ignore-errors (scroll-down-command)) t) | ||
| 299 | ((eq answer 'scroll-other-window) | ||
| 300 | (ignore-errors (scroll-other-window)) t) | ||
| 301 | ((eq answer 'scroll-other-window-down) | ||
| 302 | (ignore-errors (scroll-other-window-down)) t) | ||
| 303 | (t tchar))) | ||
| 304 | (when (eq tchar t) | ||
| 305 | (setq wrong-char nil | ||
| 306 | tchar nil)) | ||
| 307 | ;; The user has entered an invalid choice, so display the | ||
| 308 | ;; help messages. | ||
| 309 | (when (and (not (eq tchar nil)) | ||
| 310 | (not (assq tchar choices))) | ||
| 311 | (setq wrong-char (not (memq tchar '(?? ?\C-h))) | ||
| 312 | tchar nil) | ||
| 313 | (when wrong-char | ||
| 314 | (ding)) | ||
| 315 | (with-help-window (setq buf (get-buffer-create | ||
| 316 | "*Multiple Choice Help*")) | ||
| 317 | (with-current-buffer buf | ||
| 318 | (erase-buffer) | ||
| 319 | (pop-to-buffer buf) | ||
| 320 | (insert prompt "\n\n") | ||
| 321 | (let* ((columns (/ (window-width) 25)) | ||
| 322 | (fill-column 21) | ||
| 323 | (times 0) | ||
| 324 | (start (point))) | ||
| 325 | (dolist (elem choices) | ||
| 326 | (goto-char start) | ||
| 327 | (unless (zerop times) | ||
| 328 | (if (zerop (mod times columns)) | ||
| 329 | ;; Go to the next "line". | ||
| 330 | (goto-char (setq start (point-max))) | ||
| 331 | ;; Add padding. | ||
| 332 | (while (not (eobp)) | ||
| 333 | (end-of-line) | ||
| 334 | (insert (make-string (max (- (* (mod times columns) | ||
| 335 | (+ fill-column 4)) | ||
| 336 | (current-column)) | ||
| 337 | 0) | ||
| 338 | ?\s)) | ||
| 339 | (forward-line 1)))) | ||
| 340 | (setq times (1+ times)) | ||
| 341 | (let ((text | ||
| 342 | (with-temp-buffer | ||
| 343 | (insert (format | ||
| 344 | "%c: %s\n" | ||
| 345 | (car elem) | ||
| 346 | (cdr (assq (car elem) altered-names)))) | ||
| 347 | (fill-region (point-min) (point-max)) | ||
| 348 | (when (nth 2 elem) | ||
| 349 | (let ((start (point))) | ||
| 350 | (insert (nth 2 elem)) | ||
| 351 | (unless (bolp) | ||
| 352 | (insert "\n")) | ||
| 353 | (fill-region start (point-max)))) | ||
| 354 | (buffer-string)))) | ||
| 355 | (goto-char start) | ||
| 356 | (dolist (line (split-string text "\n")) | ||
| 357 | (end-of-line) | ||
| 358 | (if (bolp) | ||
| 359 | (insert line "\n") | ||
| 360 | (insert line)) | ||
| 361 | (forward-line 1))))))))))) | ||
| 362 | (when (buffer-live-p buf) | ||
| 363 | (kill-buffer buf)) | ||
| 364 | (assq tchar choices))) | ||
| 365 | |||
| 201 | (provide 'subr-x) | 366 | (provide 'subr-x) |
| 202 | 367 | ||
| 203 | ;;; subr-x.el ends here | 368 | ;;; subr-x.el ends here |
diff --git a/lisp/faces.el b/lisp/faces.el index 426de3b81db..a7c4cce741f 100644 --- a/lisp/faces.el +++ b/lisp/faces.el | |||
| @@ -2749,7 +2749,7 @@ It is used for characters of no fonts too." | |||
| 2749 | (defface read-multiple-choice-face | 2749 | (defface read-multiple-choice-face |
| 2750 | '((t (:inherit underline | 2750 | '((t (:inherit underline |
| 2751 | :weight bold))) | 2751 | :weight bold))) |
| 2752 | "Face for the symbol name in Apropos output." | 2752 | "Face for the symbol name in `read-multiple-choice' output." |
| 2753 | :group 'basic-faces | 2753 | :group 'basic-faces |
| 2754 | :version "25.2") | 2754 | :version "25.2") |
| 2755 | 2755 | ||
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index c052cdfec14..85968c85b1c 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el | |||
| @@ -49,6 +49,7 @@ | |||
| 49 | (require 'mm-util) | 49 | (require 'mm-util) |
| 50 | (require 'rfc2047) | 50 | (require 'rfc2047) |
| 51 | (require 'puny) | 51 | (require 'puny) |
| 52 | (require 'subr-x) | ||
| 52 | 53 | ||
| 53 | (autoload 'mailclient-send-it "mailclient") | 54 | (autoload 'mailclient-send-it "mailclient") |
| 54 | 55 | ||
diff --git a/lisp/net/nsm.el b/lisp/net/nsm.el index 72bff66c381..5928ab303be 100644 --- a/lisp/net/nsm.el +++ b/lisp/net/nsm.el | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | ;;; Code: | 25 | ;;; Code: |
| 26 | 26 | ||
| 27 | (require 'cl-lib) | 27 | (require 'cl-lib) |
| 28 | (require 'subr-x) | ||
| 28 | 29 | ||
| 29 | (defvar nsm-permanent-host-settings nil) | 30 | (defvar nsm-permanent-host-settings nil) |
| 30 | (defvar nsm-temporary-host-settings nil) | 31 | (defvar nsm-temporary-host-settings nil) |
diff --git a/lisp/subr.el b/lisp/subr.el index cf84d8b6e4f..937a0506826 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -2286,171 +2286,6 @@ keyboard-quit events while waiting for a valid input." | |||
| 2286 | (message "%s%s" prompt (char-to-string char)) | 2286 | (message "%s%s" prompt (char-to-string char)) |
| 2287 | char)) | 2287 | char)) |
| 2288 | 2288 | ||
| 2289 | (defun read-multiple-choice (prompt choices) | ||
| 2290 | "Ask user a multiple choice question. | ||
| 2291 | PROMPT should be a string that will be displayed as the prompt. | ||
| 2292 | |||
| 2293 | CHOICES is an alist where the first element in each entry is a | ||
| 2294 | character to be entered, the second element is a short name for | ||
| 2295 | the entry to be displayed while prompting (if there's room, it | ||
| 2296 | might be shortened), and the third, optional entry is a longer | ||
| 2297 | explanation that will be displayed in a help buffer if the user | ||
| 2298 | requests more help. | ||
| 2299 | |||
| 2300 | This function translates user input into responses by consulting | ||
| 2301 | the bindings in `query-replace-map'; see the documentation of | ||
| 2302 | that variable for more information. In this case, the useful | ||
| 2303 | bindings are `recenter', `scroll-up', and `scroll-down'. If the | ||
| 2304 | user enters `recenter', `scroll-up', or `scroll-down' responses, | ||
| 2305 | perform the requested window recentering or scrolling and ask | ||
| 2306 | again. | ||
| 2307 | |||
| 2308 | The return value is the matching entry from the CHOICES list. | ||
| 2309 | |||
| 2310 | Usage example: | ||
| 2311 | |||
| 2312 | \(read-multiple-choice \"Continue connecting?\" | ||
| 2313 | '((?a \"always\") | ||
| 2314 | (?s \"session only\") | ||
| 2315 | (?n \"no\")))" | ||
| 2316 | (let* ((altered-names nil) | ||
| 2317 | (full-prompt | ||
| 2318 | (format | ||
| 2319 | "%s (%s): " | ||
| 2320 | prompt | ||
| 2321 | (mapconcat | ||
| 2322 | (lambda (elem) | ||
| 2323 | (let* ((name (cadr elem)) | ||
| 2324 | (pos (seq-position name (car elem))) | ||
| 2325 | (altered-name | ||
| 2326 | (cond | ||
| 2327 | ;; Not in the name string. | ||
| 2328 | ((not pos) | ||
| 2329 | (format "[%c] %s" (car elem) name)) | ||
| 2330 | ;; The prompt character is in the name, so highlight | ||
| 2331 | ;; it on graphical terminals... | ||
| 2332 | ((display-supports-face-attributes-p | ||
| 2333 | '(:underline t) (window-frame)) | ||
| 2334 | (setq name (copy-sequence name)) | ||
| 2335 | (put-text-property pos (1+ pos) | ||
| 2336 | 'face 'read-multiple-choice-face | ||
| 2337 | name) | ||
| 2338 | name) | ||
| 2339 | ;; And put it in [bracket] on non-graphical terminals. | ||
| 2340 | (t | ||
| 2341 | (concat | ||
| 2342 | (substring name 0 pos) | ||
| 2343 | "[" | ||
| 2344 | (upcase (substring name pos (1+ pos))) | ||
| 2345 | "]" | ||
| 2346 | (substring name (1+ pos))))))) | ||
| 2347 | (push (cons (car elem) altered-name) | ||
| 2348 | altered-names) | ||
| 2349 | altered-name)) | ||
| 2350 | (append choices '((?? "?"))) | ||
| 2351 | ", "))) | ||
| 2352 | tchar buf wrong-char answer) | ||
| 2353 | (save-window-excursion | ||
| 2354 | (save-excursion | ||
| 2355 | (while (not tchar) | ||
| 2356 | (message "%s%s" | ||
| 2357 | (if wrong-char | ||
| 2358 | "Invalid choice. " | ||
| 2359 | "") | ||
| 2360 | full-prompt) | ||
| 2361 | (setq tchar | ||
| 2362 | (if (and (display-popup-menus-p) | ||
| 2363 | last-input-event ; not during startup | ||
| 2364 | (listp last-nonmenu-event) | ||
| 2365 | use-dialog-box) | ||
| 2366 | (x-popup-dialog | ||
| 2367 | t | ||
| 2368 | (cons prompt | ||
| 2369 | (mapcar | ||
| 2370 | (lambda (elem) | ||
| 2371 | (cons (capitalize (cadr elem)) | ||
| 2372 | (car elem))) | ||
| 2373 | choices))) | ||
| 2374 | (condition-case nil | ||
| 2375 | (let ((cursor-in-echo-area t)) | ||
| 2376 | (read-char)) | ||
| 2377 | (error nil)))) | ||
| 2378 | (setq answer (lookup-key query-replace-map (vector tchar) t)) | ||
| 2379 | (setq tchar | ||
| 2380 | (cond | ||
| 2381 | ((eq answer 'recenter) | ||
| 2382 | (recenter) t) | ||
| 2383 | ((eq answer 'scroll-up) | ||
| 2384 | (ignore-errors (scroll-up-command)) t) | ||
| 2385 | ((eq answer 'scroll-down) | ||
| 2386 | (ignore-errors (scroll-down-command)) t) | ||
| 2387 | ((eq answer 'scroll-other-window) | ||
| 2388 | (ignore-errors (scroll-other-window)) t) | ||
| 2389 | ((eq answer 'scroll-other-window-down) | ||
| 2390 | (ignore-errors (scroll-other-window-down)) t) | ||
| 2391 | (t tchar))) | ||
| 2392 | (when (eq tchar t) | ||
| 2393 | (setq wrong-char nil | ||
| 2394 | tchar nil)) | ||
| 2395 | ;; The user has entered an invalid choice, so display the | ||
| 2396 | ;; help messages. | ||
| 2397 | (when (and (not (eq tchar nil)) | ||
| 2398 | (not (assq tchar choices))) | ||
| 2399 | (setq wrong-char (not (memq tchar '(?? ?\C-h))) | ||
| 2400 | tchar nil) | ||
| 2401 | (when wrong-char | ||
| 2402 | (ding)) | ||
| 2403 | (with-help-window (setq buf (get-buffer-create | ||
| 2404 | "*Multiple Choice Help*")) | ||
| 2405 | (with-current-buffer buf | ||
| 2406 | (erase-buffer) | ||
| 2407 | (pop-to-buffer buf) | ||
| 2408 | (insert prompt "\n\n") | ||
| 2409 | (let* ((columns (/ (window-width) 25)) | ||
| 2410 | (fill-column 21) | ||
| 2411 | (times 0) | ||
| 2412 | (start (point))) | ||
| 2413 | (dolist (elem choices) | ||
| 2414 | (goto-char start) | ||
| 2415 | (unless (zerop times) | ||
| 2416 | (if (zerop (mod times columns)) | ||
| 2417 | ;; Go to the next "line". | ||
| 2418 | (goto-char (setq start (point-max))) | ||
| 2419 | ;; Add padding. | ||
| 2420 | (while (not (eobp)) | ||
| 2421 | (end-of-line) | ||
| 2422 | (insert (make-string (max (- (* (mod times columns) | ||
| 2423 | (+ fill-column 4)) | ||
| 2424 | (current-column)) | ||
| 2425 | 0) | ||
| 2426 | ?\s)) | ||
| 2427 | (forward-line 1)))) | ||
| 2428 | (setq times (1+ times)) | ||
| 2429 | (let ((text | ||
| 2430 | (with-temp-buffer | ||
| 2431 | (insert (format | ||
| 2432 | "%c: %s\n" | ||
| 2433 | (car elem) | ||
| 2434 | (cdr (assq (car elem) altered-names)))) | ||
| 2435 | (fill-region (point-min) (point-max)) | ||
| 2436 | (when (nth 2 elem) | ||
| 2437 | (let ((start (point))) | ||
| 2438 | (insert (nth 2 elem)) | ||
| 2439 | (unless (bolp) | ||
| 2440 | (insert "\n")) | ||
| 2441 | (fill-region start (point-max)))) | ||
| 2442 | (buffer-string)))) | ||
| 2443 | (goto-char start) | ||
| 2444 | (dolist (line (split-string text "\n")) | ||
| 2445 | (end-of-line) | ||
| 2446 | (if (bolp) | ||
| 2447 | (insert line "\n") | ||
| 2448 | (insert line)) | ||
| 2449 | (forward-line 1))))))))))) | ||
| 2450 | (when (buffer-live-p buf) | ||
| 2451 | (kill-buffer buf)) | ||
| 2452 | (assq tchar choices))) | ||
| 2453 | |||
| 2454 | (defun sit-for (seconds &optional nodisp obsolete) | 2289 | (defun sit-for (seconds &optional nodisp obsolete) |
| 2455 | "Redisplay, then wait for SECONDS seconds. Stop when input is available. | 2290 | "Redisplay, then wait for SECONDS seconds. Stop when input is available. |
| 2456 | SECONDS may be a floating-point value. | 2291 | SECONDS may be a floating-point value. |