Как проверить, посещает ли буфер файл?

9

Я хотел бы проверить, посещает ли какой-нибудь (скажем, текущий) буфер файл или нет. Я мог бы сказать:

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

но это кажется не очень элегантным - меня интересует только логическое значение, а не фактическое имя рассматриваемого буфера. Если бы buffer-file-nameфункция была написана на Elisp, я мог бы заглянуть в ее источник, чтобы выяснить, что она использует - но она написана на C, и, хотя я мог бы установить исходники Emacs, я боюсь, что не смогу найти имя elisp для функции, которая проверяет, что я там после в любом случае.

Для этого мне нужно создать каталог на основе имени файла текущего буфера, и в настоящее время я делаю более или менее это:

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

Итак, каков будет Elisp-идиоматический способ сделать это?

mbork
источник
2
Не уверен, почему вы возражаете против использования на buffer-file-nameсамом деле, это правильный способ сделать это (если вы действительно хотите t, делайте, (and (buffer-file-name) t)но это уродливее ИМО). Его реализация читает filenameполе структуры C буфера, которое в любом случае недоступно непосредственно из Elisp. В конце концов, это просто указатель, который либо нулевой, либо нет.
Сигма
Ну, если это правильный путь, это нормально для меня. Как я уже сказал, я не знал реализации C, и здравый смысл говорит, что запрос имени файла, когда я только хочу знать, может ли это быть излишним.
mbork
И я согласен, что (and (buffer-file-name) t)выглядит странно.
mbork
Если вы не думаете, что (if (buffer-file-name) ... )это элегантно, значит, вы давно не пишете в elisp. Отсюда становится только хуже.
Nispio

Ответы:

12

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

В выражении if есть важный аспект теста на истинность. До сих пор мы говорили о «true» и «false» как о значениях предикатов, как если бы они были новыми видами объектов Emacs Lisp. На самом деле, «ложь» - это просто наш старый друг nil. Все остальное - вообще что-либо - это «правда».

Чтобы продвинуться дальше, проверьте код для clone-buffer. Я ожидаю, что вы увидите следующее:

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

Обратите внимание, что это тестирование привязки переменной buffer-file-nameвместо вызова функции без аргумента (buffer-file-name), но они всегда должны вести себя одинаково.

purple_arrows
источник
8

Вы можете использовать либо (buffer-file-name)(с необязательным аргументом buffer), либо локальную buffer-file-nameпеременную buffer . Оба оценивают одно и то же значение для данного буфера.

То есть идиоматический способ сделать это в Elisp, хотя, так что ваш код является штрафом. Если вы отчаянно хотите, вы всегда можете сделать функцию- buffer-has-file-pобертку.

Phils
источник
Спасибо. Есть ли существенная разница в выборе функции или переменной?
mbork
1
Я так не думаю. Если вам нужно указать аргумент буфера, то (buffer-file-name BUFFER)он, конечно, лучше (with-current-buffer BUFFER buffer-file-name), но в остальном я не думаю, что это имеет значение, какой из них вы используете (и поскольку функция написана на C, я сомневаюсь, что есть даже большая разница в производительности).
Фил
3

Просто используйте buffer-file-name. В Лиспе мы часто используем ненулевое nilзначение для обозначения истины .

Единственный раз, когда вы можете избежать этого, это если функция дорогая или имеет нежелательные побочные эффекты.

Нарисовалась
источник
Понимаю. Я знаю, что все, что не nilявляется правдой, я просто думал, что схватить имя, когда я только хочу знать, существует ли какое-либо имя, «дорого» - но, похоже, это не так.
mbork
1

Из главы «Список буферов» документации:

Список, возвращаемый буферным списком, строится специально; это не внутренняя структура данных Emacs , и ее изменение не влияет на порядок буферов.

Таким образом, вы должны найти способ поиска в списке живых буферов. Вот один из них:

  (if (string-match-p (regexp-quote "My buffer name") (format "%s" (buffer-list)))
      (message "Open")
    (message "Not open"))
yPhil
источник