Wie kann ich ein einzelnes Zeichen aus dem Minibuffer lesen?

11

Wenn ein Teil von defun,

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

fordert den Benutzer zur Eingabe eines einzelnen Zeichens auf; RETist nicht nötig. Wie kann ich dieses Leseverhalten replizieren, ohne dass dies erforderlich ist interactive?

Sean Allred
quelle

Antworten:

6

Eher als read-charich empfehle read-key. Der Unterschied besteht darin, dass read-keyalle üblichen Neuzuordnungen wie input-decode-mapund befolgt werden function-key-map, sodass es in einem tty ordnungsgemäß funktioniert.

Stefan
quelle
Gepaart mit den Informationen in einer anderen Antwort scheint dies die genaueste Antwort auf die gestellte Frage zu sein :) Glucas 'Kommentar bietet jedoch eine gute Funktion :)read-char-choice
Sean Allred
5

Zusätzlich zu den integrierten Möglichkeiten zum Lesen einzelner Ereignisse wie read-charund read-char-exclusivekönnen Sie hier ein einzelnes Zeichen lesen, aber auch angeben, welche Zeichen als Eingabe zulässig sind:

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

Alle folgenden Optionen akzeptieren entweder "C", "A" oder "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))

Und hier ist ein Beispiel für eine Schleife für die korrekte Eingabe in eine 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
quelle
2
Es gibt auch read-char-choiceeinen, der einen bestimmten Zeichensatz liest.
Glucas
@ Glucas: Ah, verrückt, du hast recht. Sieht so aus, als hätte ich das Rad neu erfunden.
Dan
4

call-interactivelyinterpretiert die (interactive "cPROMPT")Spezifikation, wird die cOption an gesendet read-char. Daher sollte Folgendes in einem nicht interaktiven Kontext funktionieren:

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

Die Frage wurde vor langer Zeit beantwortet, aber diese zusätzliche Antwort kann anderen Suchenden helfen.

read-char-choiceMit dieser Option können Sie eine Liste mit Auswahlmöglichkeiten angeben. Das fn wird erst zurückgegeben, wenn der Benutzer eine dieser gültigen Optionen ausgewählt hat.

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

In dem entarteten Fall, in dem die Optionen einfach Y oder N sind (case insenstive), gibt es y-or-n-p.

Beide read-char-choiceund y-or-n-psind starr und bestehen auf einer gültigen Antwort. Im ersten Fall muss es eine der von Ihnen angegebenen Optionen sein (wie in meinem Beispiel A, B oder C), und im zweiten Fall muss es Y oder N sein. Wenn der Benutzer die Eingabetaste oder eine andere Taste drückt, y-or-n-pwird er erneut gefragt. Der read-char-choicewird einfach still da sitzen. Beides bietet keine Möglichkeit, nur einen Standardwert zurückzugeben. Ich denke, um dieses Verhalten zu erreichen, müssen Sie Ihre eigene Interaktion mit read-charoder aufbauen read-key.

Nach meiner Erfahrung besteht das Problem mit read-charund read-keyallein darin, dass der Cursor im Hauptbearbeitungspuffer verbleibt, während die Eingabeaufforderung im Minibuffer angezeigt wird. Dies ist für den Benutzer desorientiert und unterscheidet sich auch vom Verhalten von read-string.

Um dies zu vermeiden, können Sie die Variable cursor-in-echo-areavor dem Aufruf read-keyden Cursor im Minibuffer anzeigen lassen.

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