Quando parte de um defun
,
(interactive "c(C)hoose (A)n (O)ption")
solicitará ao usuário um único caractere; RET
não é necessário. Como posso replicar esse comportamento de leitura sem a necessidade interactive
?
Quando parte de um defun
,
(interactive "c(C)hoose (A)n (O)ption")
solicitará ao usuário um único caractere; RET
não é necessário. Como posso replicar esse comportamento de leitura sem a necessidade interactive
?
Respostas:
Além das maneiras internas de ler eventos únicos como read-char
e read-char-exclusive
, aqui está uma opção para ler um único caractere, mas também especificar quais caracteres são aceitáveis de entrada:
(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)))
Portanto, todos os itens a seguir aceitarão "C", "A" ou "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))
E aqui está um exemplo de maneira de fazer o loop da entrada correta em uma response
variável:
(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
que lê um de um determinado conjunto de caracteres.
A pergunta foi respondida há muito tempo, mas essa resposta adicional pode ajudar alguns outros usuários.
read-char-choice
permite especificar uma lista de opções. O fn não retornará até que o usuário selecione uma dessas opções válidas.
(read-char-choice "prompt here (A, B, or C)? " '(?A ?B ?C))
No caso degenerado em que as opções são simplesmente Y ou N (não diferencia maiúsculas de minúsculas), existe y-or-n-p
.
Ambos read-char-choice
e y-or-n-p
são rígidas, e insistem em uma resposta válida. No primeiro caso, ele deve ser uma das opções especificadas (como A, B ou C no meu exemplo) e, no último caso, deve ser Y ou N. Se o usuário pressionar enter ou qualquer outra tecla, a y-or-n-p
solicitação será novamente. O read-char-choice
vai apenas ficar lá, em silêncio. Nenhum dos dois fornece uma maneira de retornar apenas um padrão. Para obter esse comportamento, acho que você precisa criar sua própria interação com read-char
ou read-key
.
Na minha experiência, o problema com read-char
e read-key
sozinho é que, enquanto eles exibem o prompt no minibuffer, o cursor permanece no buffer de edição principal. Isso é desorientador para o usuário e também é diferente do comportamento de read-string
.
Para evitar isso, você pode deixar a variável cursor-in-echo-area
antes da chamada read-key
exibir o cursor no minibuffer.
(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