From 04ab67470706f1c66bdf08e4078ea3dffd79b41e Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Sun, 10 Nov 2019 00:21:26 +0200 Subject: [PATCH] Add CHARS arg to read-char-from-minibuffer compatible with read-char-choice. * lisp/simple.el (read-char-history): Rename from read-char-from-minibuffer-history. (Bug#38076) (read-char-from-minibuffer-insert-char): Rename from read-char-from-minibuffer-self-insert. (read-char-from-minibuffer-map-hash): New defconst. (read-char-from-minibuffer-insert-other): New command. (read-char-from-minibuffer): Add optional args CHARS and HISTORY. (zap-to-char): Use 'read-char-history as HISTORY arg of read-char-from-minibuffer. * lisp/emacs-lisp/map-ynp.el (read-answer): Use sit-for instead of sleep-for. Replace short answer history yes-or-no-p-history with read-char-history. --- lisp/emacs-lisp/map-ynp.el | 6 +-- lisp/simple.el | 79 ++++++++++++++++++++++++++++---------- 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/lisp/emacs-lisp/map-ynp.el b/lisp/emacs-lisp/map-ynp.el index a688330b74a..5c0e28eac9c 100644 --- a/lisp/emacs-lisp/map-ynp.el +++ b/lisp/emacs-lisp/map-ynp.el @@ -341,7 +341,7 @@ When `use-dialog-box' is t, pop up a dialog window to get user input." (delete-minibuffer-contents) (beep) (message message) - (sleep-for 2))) + (sit-for 2))) map) read-answer-map--memoize)))) answer) @@ -361,7 +361,7 @@ When `use-dialog-box' is t, pop up a dialog window to get user input." (short (read-from-minibuffer prompt nil short-answer-map nil - 'yes-or-no-p-history)) + 'read-char-history)) (t (read-from-minibuffer prompt nil nil nil @@ -381,7 +381,7 @@ When `use-dialog-box' is t, pop up a dialog window to get user input." ".\n"))) (beep) (message message) - (sleep-for 2))) + (sit-for 2))) answer)) ;;; map-ynp.el ends here diff --git a/lisp/simple.el b/lisp/simple.el index 6677291ebab..6dc4e5666da 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -5174,46 +5174,83 @@ and KILLP is t if a prefix arg was specified." ;; Avoid warning about delete-backward-char (with-no-warnings (delete-backward-char n killp)))) -(defvar read-char-from-minibuffer-history nil +(defvar read-char-history nil "The default history for the `read-char-from-minibuffer' function.") (defvar read-char-from-minibuffer-map (let ((map (make-sparse-keymap))) (set-keymap-parent map minibuffer-local-map) (define-key map [remap self-insert-command] - 'read-char-from-minibuffer-self-insert) + 'read-char-from-minibuffer-insert-char) map) "Keymap for the `read-char-from-minibuffer' function.") -(defun read-char-from-minibuffer-self-insert () - "Insert the character you type in the minibuffer." +(defconst read-char-from-minibuffer-map-hash + (make-hash-table :weakness 'key :test 'equal)) + +(defun read-char-from-minibuffer-insert-char () + "Insert the character you type in the minibuffer and exit. +Discard all previous input before inserting and exiting the minibuffer." (interactive) (delete-minibuffer-contents) - (insert (event-basic-type last-command-event)) + (insert last-command-event) (exit-minibuffer)) -(defun read-char-from-minibuffer (prompt) - "Read a character from the minibuffer, prompting with string PROMPT. -Like `read-char', but allows navigating in a history. The navigation -commands are `M-p' and `M-n', with `RET' to select a character from -history." - (let ((result - (read-from-minibuffer prompt nil - read-char-from-minibuffer-map nil - 'read-char-from-minibuffer-history))) - (if (> (length result) 0) - ;; We have a string (with one character), so return the first one. - (elt result 0) - ;; The default value is RET. - (push "\r" read-char-from-minibuffer-history) - ?\r))) +(defun read-char-from-minibuffer-insert-other () + "Handle inserting of a character other than allowed. +Display an error on trying to insert a disallowed character. +Also discard all previous input in the minibuffer." + (interactive) + (delete-minibuffer-contents) + (ding) + (minibuffer-message "Wrong answer") + (sit-for 2)) + +(defvar empty-history) + +(defun read-char-from-minibuffer (prompt &optional chars history) + "Read a character from the minibuffer, prompting for PROMPT. +Like `read-char', but uses the minibuffer to read and return a character. +When CHARS is non-nil, any input that is not one of CHARS is ignored. +When HISTORY is a symbol, then allows navigating in a history. +The navigation commands are `M-p' and `M-n', with `RET' to select +a character from history." + (discard-input) + (let* ((empty-history '()) + (map (if (consp chars) + (or (gethash chars read-char-from-minibuffer-map-hash) + (puthash chars + (let ((map (make-sparse-keymap))) + (set-keymap-parent map read-char-from-minibuffer-map) + (dolist (char chars) + (define-key map (vector char) + 'read-char-from-minibuffer-insert-char)) + (define-key map [remap self-insert-command] + 'read-char-from-minibuffer-insert-other) + map) + read-char-from-minibuffer-map-hash)) + read-char-from-minibuffer-map)) + (result + (read-from-minibuffer prompt nil map nil + (or history 'empty-history))) + (char + (if (> (length result) 0) + ;; We have a string (with one character), so return the first one. + (elt result 0) + ;; The default value is RET. + (when history (push "\r" (symbol-value history))) + ?\r))) + ;; Display the question with the answer. + (message "%s%s" prompt (char-to-string char)) + char)) (defun zap-to-char (arg char) "Kill up to and including ARGth occurrence of CHAR. Case is ignored if `case-fold-search' is non-nil in the current buffer. Goes backward if ARG is negative; error if CHAR not found." (interactive (list (prefix-numeric-value current-prefix-arg) - (read-char-from-minibuffer "Zap to char: "))) + (read-char-from-minibuffer "Zap to char: " + nil 'read-char-history))) ;; Avoid "obsolete" warnings for translation-table-for-input. (with-no-warnings (if (char-table-p translation-table-for-input) -- 2.39.5