Comment lire un seul caractère du mini-tampon?

12

Lorsqu'elle fait partie d'un defun,

(interactive "c(C)hoose (A)n (O)ption")

demandera à l'utilisateur un seul caractère; RETn'est pas requis. Comment puis-je reproduire ce comportement de lecture sans avoir besoin de interactive?

Sean Allred
la source

Réponses:

7

Plutôt que read-charje ne le recommande read-key. La différence est qu'il read-keyobéit à tous les remappages habituels tels que input-decode-mapet function-key-map, il fonctionnera donc correctement dans un tty.

Stefan
la source
Jumelé avec les informations d' une autre réponse , cela semble être la réponse la plus précise à la question posée :) le commentaire de glucas fournit cependant une bonne fonction :)read-char-choice
Sean Allred
5

En plus des moyens intégrés de lire des événements uniques tels que read-charet read-char-exclusive, voici une option pour lire un seul caractère, mais spécifiez également quels caractères sont des entrées acceptables:

(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)))

Ainsi, tous les éléments suivants accepteront "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))

Et voici un exemple de boucle pour l'entrée correcte dans une responsevariable:

(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)
Dan
la source
2
Il y a aussi read-char-choicequi lit l'un d'un ensemble de caractères donné.
glucas
@glucas: ah, noix, vous avez raison. On dirait que j'ai réinventé la roue.
Dan
4

call-interactivelyest ce qui interprète la (interactive "cPROMPT")spécification, l' coption est envoyée à read-char. Par conséquent, les éléments suivants devraient fonctionner dans un contexte non interactif:

(read-char "(C)hoose (A)n (O)ption")
wasamasa
la source
3

La question a été répondue il y a longtemps, mais cette réponse supplémentaire peut fournir une aide aux autres chercheurs.

read-char-choicevous permet de spécifier une liste de choix. Le fn ne reviendra que lorsque l'utilisateur aura sélectionné l'une de ces options valides.

(read-char-choice "prompt here (A, B, or C)? " '(?A ?B ?C))

Dans le cas dégénéré où les options sont simplement Y ou N (insensible à la casse), il y en a y-or-n-p.

Les deux read-char-choiceet y-or-n-psont rigides, et d' insister sur une réponse valable. Dans le premier cas, il doit être l'une des options que vous spécifiez (comme A, B ou C dans mon exemple), et dans ce dernier cas, il doit être Y ou N. Si l'utilisateur appuie sur Entrée ou sur toute autre touche, le y-or-n-pdemande à nouveau. La read-char-choicevolonté restera assise là, silencieuse. Aucun des deux ne permet de renvoyer simplement une valeur par défaut. Pour obtenir ce comportement, je pense que vous devez créer votre propre interaction avec read-charou read-key.

D'après mon expérience, le problème avec read-charet read-keyseul, c'est que pendant qu'ils affichent l'invite dans le mini-tampon, le curseur reste dans le tampon d'édition principal. Cela désoriente l'utilisateur et est également différent du comportement de read-string.

Pour éviter cela, vous pouvez laisser la variable cursor-in-echo-areaavant d'appeler read-keypour afficher le curseur dans le mini-tampon.

(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)))
Cheeso
la source