Jak mogę odczytać pojedynczy znak z minibufora?

12

Po części defun,

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

poprosi użytkownika o pojedynczy znak; RETNie jest wymagane. Jak mogę powtórzyć to zachowanie podczas czytania bez potrzeby interactive?

Sean Allred
źródło

Odpowiedzi:

7

Zamiast read-charpolecam read-key. Różnica polega na tym, że read-keystosuje się wszystkie zwykłe zmiany mapowania, takie jak input-decode-mapi function-key-map, więc będzie działać poprawnie w tty.

Stefan
źródło
W połączeniu z informacjami zawartymi w innej odpowiedzi wydaje się, że jest to najdokładniejsza odpowiedź na zadane pytanie :) Komentarz glucas zapewnia jednak dobrą funkcję :)read-char-choice
Sean Allred
5

Oprócz wbudowanych sposobów odczytywania pojedynczych zdarzeń, takich jak read-chari read-char-exclusive, tutaj jest możliwość odczytania pojedynczego znaku, ale także określ, które znaki są dopuszczalne:

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

Tak więc wszystkie poniższe elementy zaakceptują „C”, „A” lub „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))

A oto przykładowy sposób zapętlenia poprawnego wejścia do responsezmiennej:

(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
źródło
2
Jest też taki, read-char-choicektóry czyta jeden z danego zestawu znaków.
glucas,
@glucas: ah, nuts, masz rację. Wygląda na to, że wymyśliłem koło na nowo.
Dan
4

call-interactivelyinterpretuje (interactive "cPROMPT")specyfikację, do której cwysyłana jest opcja read-char. Dlatego poniższe elementy powinny działać w kontekście nieinteraktywnym:

(read-char "(C)hoose (A)n (O)ption")
wasamasa
źródło
4

Odpowiedzi na pytanie udzielono dawno temu, ale ta dodatkowa odpowiedź może stanowić pomoc dla innych osób poszukujących.

read-char-choicepozwala określić listę opcji. Fn nie powróci, dopóki użytkownik nie wybierze jednej z tych prawidłowych opcji.

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

W zdegenerowanym przypadku, w którym opcjami są po prostu Y lub N (przypadek insenstive), jest y-or-n-p.

Zarówno read-char-choicei y-or-n-psą sztywne i nalegają na ważnej odpowiedzi. W pierwszym przypadku musi to być jedna z opcji, które określisz (np. A, B lub C w moim przykładzie), a w drugim przypadku musi to być Y lub N. Jeśli użytkownik naciśnie klawisz Enter lub jakikolwiek inny klawisz, y-or-n-pzapyta ponownie. read-char-choiceBędzie po prostu siedzieć, cisza. Żadna z tych metod nie pozwala na przywrócenie wartości domyślnej. Aby uzyskać takie zachowanie, myślę, że musisz zbudować własną interakcję z read-charlub read-key.

Z mojego doświadczenia wynika, problem z read-chari read-keyspokoju, jest to, że podczas gdy wyświetli monit w minibuforze, kursor pozostaje w głównym buforze edycji. Jest to dezorientujące dla użytkownika, a także różni się od zachowania read-string.

Aby tego uniknąć, możesz pozwolić zmiennej cursor-in-echo-areaprzed wywołaniem, read-keyaby wyświetlić kursor w minibuforze.

(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
źródło