Bagaimana saya bisa membaca satu karakter dari minibuffer?

12

Ketika bagian dari defun,

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

akan meminta pengguna untuk satu karakter; RETtidak diperlukan. Bagaimana saya bisa meniru perilaku membaca ini tanpa perlu interactive?

Sean Allred
sumber

Jawaban:

7

Daripada read-charsaya rekomendasikan read-key. Perbedaannya adalah bahwa read-keymematuhi semua remapping biasa seperti input-decode-mapdan function-key-map, sehingga akan berfungsi dengan baik dalam tty.

Stefan
sumber
Dipasangkan dengan informasi dalam jawaban lain , ini tampaknya menjadi jawaban yang paling tepat untuk pertanyaan yang diajukan :) komentar glucas menyediakan fungsi yang baik :)read-char-choice
Sean Allred
5

Selain cara bawaan untuk membaca peristiwa tunggal seperti read-chardan read-char-exclusive, berikut adalah opsi untuk membaca karakter tunggal, tetapi juga menentukan karakter mana yang dapat dimasukkan:

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

Jadi semua yang berikut ini akan menerima "C", "A", atau "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))

Dan inilah contoh cara untuk mengulang masukan yang benar ke dalam responsevariabel:

(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
sumber
2
Ada juga read-char-choiceyang membaca salah satu dari serangkaian karakter yang diberikan.
glucas
@glucas: ah, gila, kau benar. Sepertinya saya menemukan kembali kemudi.
Dan
4

call-interactivelyadalah apa yang menginterpretasikan (interactive "cPROMPT")spesifikasi, copsi dikirim ke read-char. Oleh karena itu, berikut ini harus berfungsi dalam konteks non-interaktif:

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

Pertanyaan itu telah dijawab sejak lama, tetapi jawaban tambahan ini dapat memberikan bantuan kepada pencari lain.

read-char-choicememungkinkan Anda menentukan daftar pilihan. Fn tidak akan kembali sampai pengguna memilih salah satu opsi yang valid.

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

Dalam kasus degenerasi di mana opsi hanya Y atau N (case insenstive), ada y-or-n-p.

Baik read-char-choicedan y-or-n-pkaku, dan menuntut jawaban yang valid. Dalam kasus sebelumnya, itu harus salah satu opsi yang Anda tentukan (seperti A, B atau C dalam contoh saya), dan dalam kasus terakhir, itu harus Y atau N. Jika pengguna menekan tombol enter atau lainnya, y-or-n-pakan ditanyakan lagi. The read-char-choicehanya akan duduk di sana, diam. Tidak ada yang menyediakan cara untuk hanya mengembalikan default. Untuk mendapatkan perilaku itu, saya pikir Anda harus membangun interaksi Anda sendiri dengan read-charatau read-key.

Dalam pengalaman saya, masalah dengan read-chardan read-keysendirian, adalah bahwa sementara mereka menampilkan prompt di minibuffer, kursor tetap berada di buffer pengeditan utama. Ini membingungkan pengguna, dan juga tidak seperti perilaku read-string.

Untuk menghindari ITU, Anda dapat membiarkan variabel cursor-in-echo-areasebelum memanggil read-keyuntuk menampilkan kursor di 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)))
Cheeso
sumber