Что не так с `find-file-noselect`?

11

В недавнем ответе по lunaryorn , он заявил:

Однако я рекомендовал бы против большинства других частей Org, по причинам, уже указанным в комментариях: он старый и полон устаревших и вредных методов (например, find-file-noselect для чтения файлов неинтерактивно).

Кто-нибудь может объяснить, почему find-file-noselectплохая идея читать файлы в программах Elisp? Есть ли способ лучше? Я спрашиваю, потому что я думал об использовании его в одном из моих проектов.

mbork
источник
Похоже, good-practicesраньше тега не было; это хорошая идея, чтобы использовать его?
mbork
Я думаю, что good-practicesэто подпадает под категорию «метатег», который осуждается SE.
Ниспио
1
@nispio Я думаю, что это допустимый тег, но мы можем принять это к мета конечно.
Малабарба
1
@nsipio: я пролистал эту статью и не согласен. Но не я решаю. ;-)
mbork

Ответы:

14

TL; DR : у find-file-noselectвас нет контроля над тем, что на самом деле происходит, и вы можете получить произвольные второстепенные режимы, включенные в буфере, в зависимости от того, что пользователь включил в них init.el. Кроме того, очистка это сложно.

Используйте with-temp-bufferи insert-file-contentsвместо. Если вам нужны определенные основные или второстепенные режимы в буфере, включите их явно . with-temp-fileВместо этого используйте для записи файлов, который, несмотря на его имя, позволяет писать в произвольные файлы.

Побочные эффекты

find-file-noselectимеет много побочных эффектов, в том числе

  • интерактивно задаваемые вопросы (это само по себе не допускается при неинтерактивном использовании),
  • автоматическое включение режима просмотра файлов только для чтения,
  • в противном случае вход в нормальный режим,
  • и работает find-file-hook.

Нормальный режим сам

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

Поскольку все перехваты запускаются, вы получаете все второстепенные режимы и функции перехвата, которые пользователь включил в свои функции init.el, что может вызвать все, от незначительных неудобств (если включены нежелательные второстепенные режимы) до серьезного хаоса (если пользователь добавил функцию перехвата, которая ожидает вызываться из интерактивного контекста).

См. Https://github.com/flycheck/flycheck/issues/366 для примера. В результате использования find-file-noselectфайла Flycheck была проверена синтаксическая проверка файла данных, и, поскольку это происходило при завершении работы Emacs, не было времени для правильной очистки, оставив временный файл.

уборка

С find-file-noselectвами нужно быть очень осторожным, чтобы снова убить буфер. find-file-noselectне делает это для вас.

Вам нужно запомнить буфер в каком-то месте и тщательно использовать unwind-protectего, чтобы убедиться, что буфер уничтожен даже в случае нелокальных выходов.

альтернативы

Для чтения файлов используйте with-temp-bufferи insert-file-contents, который выполняет только самые простые действия, например, преобразование системы кодирования, но не задает вопросов, не включает хуки и не устанавливает локальные переменные:

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

with-temp-buffer заботится, чтобы правильно убить временный буфер в конце его тела.

Для записи файлов используйте with-temp-fileкоманду, которая создает временный буфер и записывает содержимое в указанное имя файла в конце его тела:

(with-temp-file  (locate-user-emacs-file "foo.el")
  (prin1 (list 'my 'data) (current-buffer)))
lunaryorn
источник
10

Из раздела 24.3 руководства Elisp:

Чтобы скопировать содержимое файла в буфер, используйте функцию insert-file-contents. (Не используйте команду insert-fileв программе на Лиспе, так как она устанавливает метку.)

При поиске документации Elisp find-file-noselectочевидно, что она делает гораздо больше, чем просто читает файл в буфер. Возможно, люди, которые считают использование этой функции плохой идеей, думают о, возможно, нежелательных побочных эффектах? Я думаю, это зависит от того, чего вы хотите достичь. Если вы хотите иметь как можно более чистое / нетронутое содержимое буфера, было бы неплохо использовать старую и надежную комбинацию with-temp-buffer+ insert-file-contents. Если вы хотите , чтобы содержимое буфера , чтобы быть как можно ближе к тому , что find-fileпроизводить, возможно , вы действительно хотите использовать find-file-noselect? Или, возможно, он думал о find-file;)

Матиас Даль
источник
3
Если что-то делается неинтерактивно, я не вижу ни одного сценария, в котором вы бы хотели, чтобы «содержимое буфера было близко к тому, что выдает файл поиска» . find-file работает медленно, потому что он делает кучу ненужных вещей, включая все виды хуков. Единственная «особенность» find-file, которая вам может понадобиться, - это основной режим, но тогда вы должны просто активировать его самостоятельно (вы даже не можете гарантировать, что find-file включит нужный вам режим).
Малабарба
Малабарба: Если вы намереваетесь, чтобы буфер оставался доступным для редактирования пользователем, тогда вы вполне можете захотеть имитировать find-fileпроцесс.
phils