Bagaimana cara memeriksa apakah buffer mengunjungi file?

9

Saya ingin memeriksa apakah beberapa (misalnya, saat ini) buffer mengunjungi file atau tidak. Saya bisa mengatakan:

(if (buffer-file-name) ...)

tetapi tampaknya tidak terlalu elegan - yang saya tertarik hanyalah nilai boolean, bukan nama sebenarnya dari buffer yang dimaksud. Jika buffer-file-namefungsi tersebut ditulis dalam Elisp, saya dapat melihat ke sumbernya untuk mengetahui apa yang digunakan - tetapi ditulis dalam C, dan sementara saya dapat menginstal sumber Emacs, saya takut bahwa saya tidak akan menemukan nama elisp untuk fungsi yang memeriksa apa yang saya cari setelah itu.

Yang saya butuhkan adalah saya ingin membuat direktori berdasarkan nama file buffer saat ini, dan saat ini saya melakukan lebih atau kurang ini:

(make-directory (if (buffer-file-name) (file-name-base) "default-dir"))

Jadi, apa cara Elisp-idiomatis untuk melakukan ini?

mbork
sumber
2
Tidak yakin mengapa Anda keberatan menggunakan buffer-file-namebenar - benar, itu cara yang tepat untuk melakukannya (jika Anda benar-benar ingin t, lakukan (and (buffer-file-name) t)tapi itu IMO lebih buruk). Implementasinya adalah membaca filenamebidang buffer C struct, yang toh tidak dapat diakses langsung dari Elisp. Pada akhirnya, itu hanya sebuah pointer yang bernilai null atau tidak.
Sigma
Nah, jika ini cara yang benar, itu tidak masalah bagi saya. Seperti yang saya katakan - saya tidak tahu implementasi C, dan akal sehat mengatakan bahwa meminta nama file ketika saya hanya ingin tahu apakah ada yang mungkin berlebihan.
mbork
Dan saya setuju itu (and (buffer-file-name) t)terlihat aneh.
mbork
Jika Anda tidak berpikir itu (if (buffer-file-name) ... )elegan, maka Anda belum lama mengkode di elisp. Hanya mendapat lebih buruk dari sini.
nispio

Jawaban:

12

Saya berpendapat bahwa penggunaan Anda adalah idiot elisp, karena nama buffer adalah nilai boolean yang sangat tepat. Mengutip dari manual :

Ada aspek penting dalam tes kebenaran dalam ekspresi if. Sejauh ini, kita telah berbicara tentang `benar 'dan` salah' sebagai nilai predikat seolah-olah mereka adalah jenis baru objek Emacs Lisp. Sebenarnya, `false 'hanyalah teman lama kita nil. Apa pun — apa pun — adalah `benar '.

Untuk lebih lanjut, lihat kode untuk clone-buffer. Saya berharap Anda akan melihat yang berikut:

(interactive
 (progn
   (if buffer-file-name
       (error "Cannot clone a file-visiting buffer"))
...

Perhatikan bahwa ini sedang menguji pengikatan variabel buffer-file-namealih - alih memanggil fungsi tanpa argumen (buffer-file-name),, tetapi keduanya harus selalu berperilaku sama.

purple_arrows
sumber
8

Anda dapat menggunakan (buffer-file-name)(dengan argumen buffer opsional) atau buffer-file-namevariabel buffer-local . Keduanya mengevaluasi dengan nilai yang sama untuk buffer yang diberikan.

Itu adalah cara idiomatis untuk melakukan ini di Elisp, jadi kode Anda baik-baik saja. Jika Anda sangat menginginkannya, Anda selalu bisa membuat buffer-has-file-pfungsi pembungkus.

phils
sumber
Terima kasih. Apakah ada perbedaan signifikan untuk memilih fungsi atau variabel?
mbork
1
Saya kira tidak. Jika Anda perlu menunjukkan argumen buffer maka (buffer-file-name BUFFER)tentu saja lebih baik daripada (with-current-buffer BUFFER buffer-file-name), tetapi sebaliknya saya tidak berpikir itu penting yang mana yang Anda gunakan (dan karena fungsi ditulis dalam C, saya ragu bahkan ada banyak perbedaan dalam kinerja).
phils
3

Gunakan saja buffer-file-name. Dalam Lisp kita sering menggunakan nilnilai- tidak untuk berarti benar .

Satu-satunya waktu Anda mungkin ingin menghindari ini adalah jika fungsinya mahal atau memiliki efek samping yang tidak diinginkan.

Drew
sumber
Saya melihat. Saya tahu bahwa sesuatu yang tidak nilbenar itu benar, saya hanya berpikir untuk mengambil nama itu ketika saya hanya ingin tahu apakah ada nama itu "mahal" - tetapi sepertinya tidak.
mbork
1

Dari bab "Daftar Penyangga" dokumentasi:

Daftar yang dikembalikan oleh buffer-list dibuat secara khusus; itu bukan struktur data Emacs internal , dan memodifikasinya tidak berpengaruh pada urutan buffer.

Jadi, Anda harus menemukan cara untuk mencari dalam daftar buffer langsung. Ini dia:

  (if (string-match-p (regexp-quote "My buffer name") (format "%s" (buffer-list)))
      (message "Open")
    (message "Not open"))
yPhil
sumber