Как я могу прочитать один символ из минибуфера?

12

Когда часть defun,

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

предложит пользователю ввести один символ; RETне требуется. Как я могу повторить это поведение при чтении без необходимости interactive?

Шон Оллред
источник

Ответы:

7

Вместо того, чтобы read-charрекомендовать read-key. Разница в том, что он read-keyподчиняется всем обычным переназначениям, таким как input-decode-mapи function-key-map, поэтому он будет работать правильно в tty.

Стефан
источник
В сочетании с информацией в другом ответе , это, кажется, самый точный ответ на заданный вопрос :) Комментарий glucas обеспечивает хорошую функцию :)read-char-choice
Шон Оллред
5

В дополнение к встроенным способам чтения отдельных событий, таким как read-charи read-char-exclusive, здесь есть возможность прочитать один символ, но также указать, какие символы являются допустимыми для ввода:

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

Таким образом, все последующие будут принимать «C», «A» или «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))

И вот пример способа зацикливания для правильного ввода в responseпеременную:

(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
Существует также, read-char-choiceкоторый читает один из заданного набора символов.
glucas
@glucas: ах, орехи, ты прав. Похоже, я заново изобрел колесо.
Дан
4

call-interactivelyэто то, что интерпретирует (interactive "cPROMPT")спецификацию, cкоторой отправляется опция read-char. Следовательно, следующее должно работать в неинтерактивном контексте:

(read-char "(C)hoose (A)n (O)ption")
wasamasa
источник
3

На вопрос был дан ответ давно, но этот дополнительный ответ может оказать некоторую помощь другим искателям.

read-char-choiceпозволяет указать список вариантов. Fn не вернется, пока пользователь не выберет одну из этих допустимых опций.

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

В вырожденном случае, когда варианты просто Y или N (без учета регистра), есть y-or-n-p.

Оба read-char-choiceи y-or-n-pжестки, и настаивают на правильном ответе. В первом случае это должна быть одна из указанных вами опций (например, A, B или C в моем примере), а во втором - это Y или N. Если пользователь нажимает клавишу ввода или любую другую клавишу, y-or-n-pзапрос будет повторен. read-char-choiceБудет просто сидеть, молчать. Ни один из них не предоставляет способ просто вернуть значение по умолчанию. Чтобы получить такое поведение, я думаю, вы должны создать свое собственное взаимодействие с read-charили read-key.

По моему опыту, проблема с read-charи в read-keyодиночку заключается в том, что, хотя они отображают подсказку в минибуфере, курсор остается в основном буфере редактирования. Это дезориентирует пользователя, а также отличается от поведения read-string.

Чтобы избежать ТО, вы можете позволить переменной cursor-in-echo-areaдо вызова read-keyотображать курсор в минибуфере.

(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
источник