Cuando parte de un defun
,
(interactive "c(C)hoose (A)n (O)ption")
le pedirá al usuario un solo carácter; RET
no es requerido. ¿Cómo puedo replicar este comportamiento de lectura sin la necesidad de hacerlo interactive
?
Cuando parte de un defun
,
(interactive "c(C)hoose (A)n (O)ption")
le pedirá al usuario un solo carácter; RET
no es requerido. ¿Cómo puedo replicar este comportamiento de lectura sin la necesidad de hacerlo interactive
?
Respuestas:
Además de las formas integradas para leer eventos individuales como read-char
y read-char-exclusive
, aquí hay una opción para leer un solo carácter, pero también especificar qué caracteres son de entrada aceptable:
(defun read-char-picky (prompt chars &optional inherit-input-method seconds)
"Read characters like in `read-char-exclusive', but if input is
not one of CHARS, return nil. CHARS may be a list of characters,
single-character strings, or a string of characters."
(let ((chars (mapcar (lambda (x)
(if (characterp x) x (string-to-char x)))
(append chars nil)))
(char (read-char-exclusive prompt inherit-input-method seconds)))
(when (memq char chars)
char)))
Por lo tanto, todo lo siguiente aceptará "C", "A" u "O":
(read-char-picky "(C)hoose (A)n (O)ption: " "CAO")
(read-char-picky "(C)hoose (A)n (O)ption: " '("C" "A" "O"))
(read-char-picky "(C)hoose (A)n (O)ption: " '(?C ?A ?O))
Y aquí hay una forma de ejemplo de bucle para la entrada correcta en una response
variable:
(let (response)
(while (null (setq response
(read-char-picky "(C)hoose (A)n (O)ption: " "CAO")))
(message "Please pick one of \"C\", \"A\", or \"O\"!")
(sit-for .5))
response)
read-char-choice
uno que lee uno de un conjunto de caracteres dado.
La pregunta fue respondida hace mucho tiempo, pero esta respuesta adicional puede proporcionar alguna ayuda a otros buscadores.
read-char-choice
le permite especificar una lista de opciones. El fn no volverá hasta que el usuario seleccione una de esas opciones válidas.
(read-char-choice "prompt here (A, B, or C)? " '(?A ?B ?C))
En el caso degenerado en el que las opciones son simplemente Y o N (no distingue entre mayúsculas y minúsculas), existe y-or-n-p
.
Ambos read-char-choice
y y-or-n-p
son rígidos, e insisten en una respuesta válida. En el primer caso, debe ser una de las opciones que especifique (como A, B o C en mi ejemplo), y en el último caso, debe ser Y o N. Si el usuario presiona Intro o cualquier otra tecla, y-or-n-p
volverá a preguntar. El read-char-choice
solo se sentará allí, en silencio. Ninguno de los dos proporciona una manera de devolver un valor predeterminado. Para obtener ese comportamiento, creo que debes construir tu propia interacción con read-char
o read-key
.
En mi experiencia, el problema con read-char
y read-key
solo es que, si bien muestran la solicitud en el minibúfer, el cursor permanece en el búfer de edición principal. Esto es desorientador para el usuario y también es diferente al comportamiento de read-string
.
Para evitar ESO, puede dejar que la variable cursor-in-echo-area
antes de llamar read-key
muestre el cursor en el minibúfer.
(defun my-y-or-n-with-default (raw-prompt &optional default-yes)
"displays PROMPT in the minibuffer, prompts for a y or n,
returns t or nil accordingly. If neither Y or N is entered, then
if DEFAULT-YES, returns t, else nil."
(let* ((options-string (if default-yes "Y or n" "y or N"))
(prompt (concat raw-prompt "(" options-string ")? "))
(cursor-in-echo-area t)
(key (read-key (propertize prompt 'face 'minibuffer-prompt)))
(isyes (or (eq key ?y) (eq key ?Y)))
(isno (or (eq key ?n) (eq key ?N))))
(if (not (or isyes isno))
default-yes
isyes)))
read-char-choice