Come posso leggere un singolo personaggio dal minibuffer?


12

Quando fa parte di un defun,

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

chiederà all'utente un singolo carattere; RETnon è richiesto. Come posso replicare questo comportamento di lettura senza necessità interactive?

Risposte:


7

Piuttosto che read-charraccomando read-key. La differenza è che read-keyobbedisce a tutti i soliti rimappaggi come input-decode-mape function-key-map, quindi funzionerà correttamente in un attimo.


Abbinata alle informazioni contenute in un'altra risposta , questa sembra essere la risposta più precisa alla domanda posta :) il commento di glucas offre comunque una buona funzione :)read-char-choice
Sean Allred,

5

Oltre ai modi integrati per leggere singoli eventi come read-chare read-char-exclusive, ecco un'opzione per leggere un singolo carattere, ma specificare anche quali caratteri sono accettabili come input:

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

Quindi tutte le seguenti accetteranno "C", "A" o "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))

Ed ecco un modo di esempio per eseguire il loop per l'input corretto in una responsevariabile:

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

2
C'è anche quello read-char-choiceche legge uno di un determinato set di caratteri.
Glucas,

@glucas: ah, noccioline, hai ragione. Sembra che abbia reinventato la ruota.
Dan

4

call-interactivelyè ciò che interpreta la (interactive "cPROMPT")specifica, l' copzione viene inviata a read-char. Pertanto, dovrebbero funzionare in un contesto non interattivo:

(read-char "(C)hoose (A)n (O)ption")

3

Alla domanda è stata data risposta molto tempo fa, ma questa risposta aggiuntiva può fornire assistenza ad altri utenti.

read-char-choiceti permette di specificare un elenco di scelte. Il fn non tornerà finché l'utente non selezionerà una di quelle opzioni valide.

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

Nel caso degenerato in cui le opzioni sono semplicemente Y o N (senza distinzione tra maiuscole e minuscole), c'è y-or-n-p.

Entrambi read-char-choicee y-or-n-psono rigidi e insistono su una risposta valida. Nel primo caso, deve essere una delle opzioni specificate (come A, B o C nel mio esempio) e in quest'ultimo caso, deve essere Y o N. Se l'utente preme invio o qualsiasi altro tasto, y-or-n-pverrà richiesto nuovamente. La read-char-choicevolontà siederà lì, in silenzio. Nessuno dei due fornisce un modo per restituire un valore predefinito. Per ottenere quel comportamento, penso che devi costruire la tua interazione con read-charo read-key.

Nella mia esperienza, il problema con read-chare read-keysolo, è che mentre visualizzano il prompt nel minibuffer, il cursore rimane nel buffer di modifica principale. Questo è disorientante per l'utente ed è anche diverso dal comportamento di read-string.

Per evitarlo, è possibile consentire alla variabile cursor-in-echo-areaprima di chiamare read-keydi visualizzare il cursore nel 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)))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.