Apa yang salah dengan `find-file-noselect`?

11

Dalam jawaban terakhir oleh lunaryorn , dia menyatakan:

Namun, saya akan merekomendasikan terhadap sebagian besar bagian lain dari Org, karena alasan yang sudah dinyatakan dalam komentar: Ini sudah tua, dan penuh dengan warisan dan praktik yang berbahaya (mis. Find-file-noselect untuk membaca file secara non-interaktif).

Adakah yang bisa menjelaskan mengapa find-file-noselectide buruk untuk membaca file di program Elisp? Apakah ada cara yang lebih baik? Saya bertanya karena saya berpikir untuk menggunakannya di salah satu proyek saya.

mbork
sumber
Tampaknya, tidak ada good-practicestag sebelumnya; apakah itu ide yang bagus untuk menggunakannya?
mbork
Saya pikir itu good-practicesakan jatuh di bawah kategori "meta tag," yang disukai oleh SE.
nispio
1
@nispio Saya pikir ini adalah tag yang valid, tetapi kita dapat membawa ini ke meta tentu saja.
Malabarba
1
@nsipio: Saya membaca sekilas artikel itu, dan saya tidak setuju. Tapi bukan aku yang memutuskan. ;-)
mbork

Jawaban:

14

TL; DR : Dengan find-file-noselectAnda tidak memiliki kendali tentang apa yang sebenarnya terjadi, dan Anda dapat berakhir dengan mode minor sembarang yang diaktifkan di buffer, tergantung pada apa yang diaktifkan pengguna di dalamnya init.el. Juga, pembersihan itu sulit.

Gunakan with-temp-bufferdan insert-file-contentssebagai gantinya. Jika Anda memerlukan mode utama atau minor tertentu dalam buffer, aktifkan secara eksplisit . Untuk menulis file, gunakan with-temp-filesebaliknya, yang — meski namanya — memungkinkan Anda menulis ke file sewenang-wenang.

Efek samping

find-file-noselectmemiliki banyak efek samping, termasuk

  • mengajukan pertanyaan secara interaktif (itu saja tidak boleh digunakan non-interaktif),
  • secara otomatis mengaktifkan mode tampilan untuk file hanya baca,
  • memasuki mode normal jika tidak,
  • dan berlari find-file-hook.

Mode Normal itu sendiri

  • secara otomatis memilih mode utama yang tepat untuk buffer saat ini,
  • menjalankan semua mode kait utama dan minor yang sesuai,
  • dan membaca semua variabel lokal untuk buffer saat ini, yaitu variabel file dan variabel direktori, yang lagi-lagi dapat mengajukan pertanyaan interaktif tentang variabel lokal yang tidak aman.

Karena semua kait dijalankan, Anda mendapatkan semua mode minor dan fungsi kait yang diaktifkan pengguna di init.eldalamnya, yang dapat menyebabkan semuanya, mulai dari ketidaknyamanan kecil (jika mode minor yang tidak diinginkan diaktifkan) hingga kekacauan besar (jika pengguna menambahkan fungsi kait yang berharap untuk dipanggil dari konteks interaktif).

Lihat https://github.com/flycheck/flycheck/issues/366 untuk contoh. Penggunaan find-file-noselectfile data menyebabkan sintaks-diperiksa oleh Flycheck, dan karena itu terjadi di Emacs shut-down, tidak ada waktu untuk membersihkan dengan baik lagi, meninggalkan file sementara di belakang.

Membersihkan

Dengan find-file-noselectAnda harus ekstra hati-hati untuk membunuh buffer lagi. find-file-noselecttidak melakukan itu untukmu.

Anda perlu mengingat buffer di suatu tempat, dan gunakan dengan hati-hati unwind-protectuntuk memastikan bahwa buffer terbunuh bahkan dalam kasus keluar non-lokal.

Alternatif

Untuk membaca file, gunakan with-temp-bufferdan insert-file-contents, yang hanya melakukan hal-hal paling mendasar, misalnya mengkode konversi sistem, tetapi tidak mengajukan pertanyaan, mengaktifkan kait, atau mengatur variabel lokal:

(with-temp-buffer
  (insert-file-contents (locate-user-emacs-file "foo.el"))
  ;; Enter the major mode explicitly
  (emacs-lisp-mode)
  ;; …
  )

with-temp-buffer berhati-hati untuk membunuh buffer sementara di ujung tubuhnya.

Untuk menulis file, gunakan with-temp-file, yang membuat buffer sementara dan menulis konten ke nama file yang diberikan di akhir tubuhnya:

(with-temp-file  (locate-user-emacs-file "foo.el")
  (prin1 (list 'my 'data) (current-buffer)))
lunaryorn
sumber
10

Dari bagian 24.3 dalam manual Elisp:

Untuk menyalin konten file ke dalam buffer, gunakan fungsi ini insert-file-contents. (Jangan gunakan perintah insert-filedalam program Lisp, karena itu menetapkan tanda.)

Mencari dokumentasi Elisp untuk find-file-noselectitu jelas bahwa ia melakukan lebih dari sekadar membaca file ke buffer. Mungkin orang yang berpikir menggunakan fungsi ini adalah ide buruk yang berpikir tentang efek samping yang mungkin tidak diinginkan? Saya kira itu tergantung pada apa yang ingin Anda capai. Jika Anda ingin memiliki konten penyangga bersih / tersentuh mungkin, mungkin ide yang baik untuk menggunakan yang lama dan terpercaya with-temp-buffer+ insert-file-contentskombinasi. Jika Anda ingin isi buffer untuk menjadi seperti dekat dengan apa yang find-filemenghasilkan, mungkin Anda lakukan ingin digunakan find-file-noselect? Atau mungkin dia sedang memikirkan find-file;)

Mathias Dahl
sumber
3
Jika ada sesuatu yang dilakukan secara non-interaktif saya tidak dapat melihat skenario di mana Anda ingin "isi buffer dekat dengan apa yang akan ditemukan file-file" . find-file lambat karena melakukan banyak hal yang tidak perlu, termasuk semua jenis kait. Satu-satunya "fitur" dari file-menemukan yang mungkin Anda inginkan adalah mode-utama, tetapi kemudian Anda harus mengaktifkannya sendiri (Anda bahkan tidak dapat menjamin file-menemukan akan mengaktifkan mode yang Anda inginkan).
Malabarba
Malabarba: Jika Anda ingin buffer tetap tersedia untuk diedit oleh pengguna, maka Anda mungkin ingin meniru find-fileprosesnya.
phils