Как получить буферы (не только файлы), чтобы соблюдать auto-mode-alist?

13

Q: как я могу получить новые буферы для соответствия отображению auto-mode-alist?

При поиске файла Emacs сравнивает расширение файла с тем, auto-mode-alistчтобы определить, какой основной режим использовать для буфера файла. Есть ли способ использовать информацию auto-mode-alistдля определения режима для буфера, с которым (пока) не связан файл?

То есть: если я открою новый буфер , имя которого имеет нечто, похожее на расширение файла, могу ли я заставить его автоматически открываться в ожидаемом режиме? Например, если бы я должен был открыть новый буфер, a-new-buffer.elкоторый еще не связан с файлом, я хочу, чтобы он открывался, emacs-lisp-modeа не в режиме по умолчанию.

Дэн
источник
2
Просто любопытно: какой вариант использования? IOW, почему / когда / в каком контексте вы хотите это сделать? Как правило, если вы хотите, чтобы буфер был связан с файлом и выбирал его режим auto-mode-alist, вы заставляете буфер « посещать » файл (и это обо всем позаботится).
Дрю
5
Примеры типичных вариантов использования для меня: a) временный orgбуфер для тестирования новых функций, в которых я пишу для использования org-mode; б) временный Rбуфер для быстрых статистических манипуляций; в) временный текстовый буфер для создания электронного письма. В каждом случае я не хочу создавать файл для посещения, я просто хочу одноразовый буфер, который, тем не менее, открывается в соответствующем режиме.
Дан
2
Файловые посещения команды , такие как C-x C-fбы не « создать файл для посещения ». Это фундаментальное недоразумение. Они просто делают именно то, что вы ищете. Это только если и когда вы пытаетесь сохранить буфер , что файл будет создан. Если вы не попытаетесь сохранить буфер, файл не будет создан. Насколько я понимаю, вы хотите «посетить файл» (что в действительности означает открыть буфер в правильном режиме).
Дрю
8
Как и Дэн, я все время создаю временные буферы, которые я не хочу связывать с реальным путем к файлу. Посещение фиктивного пути к файлу будет работать, но при выборе каталога (или при принятии текущего) есть, по крайней мере, небольшое трение. Могут быть другие побочные эффекты в зависимости от остальной части вашей конфигурации: поведение автосохранения? Ибуффер групп или снарядов проектов определяется путем? Идо подтверждения подсказок? Так как буферы должны иметь имя в любом случае, использование имени для автоматической установки режима для временного буфера имеет смысл для меня.
glucas
@ Дрю, да, это имеет смысл и будет самым простым ответом на этот вопрос - не могли бы вы опубликовать его как ответ, пожалуйста? Это заслуживает обновления.
Дан

Ответы:

8

Команды посещения файла, такие как C-x C-f не создавать файл для посещения. Они делают то, что вы ищете.

Только если и когда вы попытаетесь сохранить буфер , файл будет создан .

Если вы не попытаетесь сохранить буфер, файл не будет создан. Насколько я понимаю, вы хотите « посетить файл » (что в действительности означает открыть буфер в правильном режиме).

Нарисовалась
источник
4
Что если у вас есть гиперактивный палец, который постоянно сохраняет текущий файл каждые 3 секунды независимо от того, что вы хотите?
Малабарба
1
@Malabarba: На самом деле, у меня есть этот палец! ;-) Может быть, большинство из нас, старых пукающих, так и делают - привычка уходит в прошлое, когда что-то рушится все время. Но в любом случае я делаю только то, что предложил: редактировать в одноразовом буфере посещаемых файлов. Если моя сверхактивная мышечная память мешает и пытается сохранить, пусть будет так: либо я нажму, nчтобы не сохранить, либо (часто) просто сохраняю буфер. А потом я кидаю созданный файл ... или нет.)
Дрю
1
@Malabarba Именно для того, чтобы предотвратить беспорядок временных файлов, я начал использовать специальные временные буферы основного режима. Если скретч заслуживает файла, вы всегда можете сохранить его как один позже.
Каушал Моди
1
@kaushalmodi: Ничто не противоречит вашим буферам, зависящим от режима, но « беспорядок временных файлов » так же легко убирается, как беспорядок буферов . ;-) И гиперактивный палец в специфичном для режима скретч-буфере представляет собой ту же проблему, предположительно - такую ​​же, как и в *scratch*: вам предлагается сохранить, когда этот палец автоматически ударится C-x C-s.
Дрю
9

Если бы использовали решение Юрия Линкова в течение многих лет.

Я создаю временные буферы с чем-то вроде C-x b test.org C-j. major-modeОпределяется расширением файла через auto-mode-alist.

;; http://thread.gmane.org/gmane.emacs.devel/115520/focus=115794
(setq-default major-mode
              (lambda () (if buffer-file-name
                          (fundamental-mode)
                            (let ((buffer-file-name (buffer-name)))
                          (set-auto-mode)))))

Чтобы проверить эффект вы можете попробовать (prog1 (and (switch-to-buffer "my-new.org") major-mode) (kill-buffer "my-new.org")) => org-mode. В чистом виде emacs -qтест вернется fundamental-mode.

Расмус
источник
1
Это очень умно! Это также аккуратнее, чем adviceвариант, который я использовал. Не уверен, что я понимаю, для чего эта (prog1...)часть, но (setq-default major-mode ...)она довольно приятная.
Дан
1
Не стесняйтесь проверить сайт Juma's Emacs . Тест- prog1просто показывает, что вы получаете ожидаемое major-modeпри переключении в буфер. Оцените setq-defaultдеталь и запустите тест. Он вернется org-mode без того, setq-defaultчто он вернется fundamental-mode.
Расм
Это намного элегантнее, чем мой буфер-список-обновление-хук. Благодарность!
glucas
это должен быть принятый ответ, так как он на самом деле отвечает на вопрос, а не говорит нам, почему мы ошибаемся, задавая его :)
Shlomi
6

Придумал способ, основанный на советах, используя идеи, которые исходили из комментариев @ Drew и ответа @ glucas, которые я запишу здесь на случай, если они пригодятся кому-либо.

Краткая версия: используйте afterрекомендацию, чтобы узнать, имеет ли буфер имя файла, временно установите его, если его нет, а затем позвольте остальной части set-auto-modeоборудования позаботиться о деталях. После небольшого тестирования (не обширного), кажется, работает нормально.

Для ido-switch-bufferи ванили switch-to-bufferдва совета будут:

(defadvice ido-switch-buffer (after set-mode activate)
  (unless buffer-file-name
    (let ((buffer-file-name (buffer-name)))
      (set-auto-mode t))))

(defadvice switch-to-buffer (after set-mode activate)
  (unless buffer-file-name
    (let ((buffer-file-name (buffer-name)))
      (set-auto-mode t))))

Я нахожу этот вариант полезным в дополнение к тому, find-fileчто поднял @Drew, потому что мои пальцы могут опередить мой мозг: мышечная память часто выводит меня на территорию переключения на буфер до того, как я полностью осознаю, что find-fileбуду делать то, что мне нужно. Теперь оба варианта доступны.

ОБНОВЛЕНИЕ: небольшая, но потенциально раздражающая ошибка в приведенном выше коде: он будет повторно запускать ловушку режима для буфера каждый раз, когда вы переключаетесь на него. Следующее дает ему фактическое имя файла вне /tmpкаталога и позволяет избежать этой проблемы:

(defadvice ido-switch-buffer (after set-mode activate)
  (unless buffer-file-name
    (setq buffer-file-name (concat "/tmp/" (buffer-name)))
    (set-auto-mode t)))
Дэн
источник
Выглядит хорошо, и убирает суть, мой ответ накопился за пару итераций. :-) Я просто повторю здесь, что если вы по какой-то причине не хотите устанавливать фактический путь к файлу, вы можете использовать локальную переменную буфера, чтобы избежать многократной установки режима.
глюкас
5

set-auto-modeФункция устанавливает режим , основанный на файл , связанный с буфером. Вот функция, которая временно устанавливается buffer-file-nameиз имени буфера для установки режима:

(defun my/set-buffer-mode (buffer &optional again)
  "Set the mode for BUFFER from the name.  
When called repeatedly for the same buffer only set the mode the first
time, unless the optional argument AGAIN is specified.
Does nothing if the buffer is associated with a file."

  (with-current-buffer buffer
    (when again (kill-local-variable 'my/buffer-mode-set))
    (unless (or buffer-file-name 
            (local-variable-p 'my/buffer-mode-set))
      (let ((buffer-file-name (buffer-name)))
        (set-auto-mode t)
        (setq-local my/buffer-mode-set t)))))

Вы можете запустить это, когда буфер переименован, используя advice:

(defadvice rename-buffer (after my/rename-update-mode activate)
  (my/set-buffer-mode (current-buffer) 'again))

Я не уверен в том, какое место лучше всего использовать для создания новых буферов. Здесь я использую buffer-list-update-hook, но это вызывается в большем количестве случаев, чем нам нужно.

(add-hook 'buffer-list-update-hook
      '(lambda ()
         (my/set-buffer-mode (car (buffer-list)))))
glucas
источник
Приведенный выше ответ был пересмотрен для решения некоторых вопросов. В частности, я вернулся к использованию, buffer-list-update-hookпотому что change-major-mode-hookне вызывался с ожидаемым текущим буфером. Для записи, вероятно, имеет смысл посоветовать вашу функцию переключателя буфера, как @Dan в своем ответе.
glucas
3

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

Вот ответ Emacs SE, который может решить вашу проблему:

Как я могу быстро переключаться между файлом и буфером * scratch * с одинаковым основным режимом?

Упомянутый вопрос и ответ были опубликованы мной. Ответ в функции делает следующее:

  • Если вы работаете в мажорном режиме X в файле, то при вызове этой функции создается новый рабочий буфер с именем *scratch-X-mode* который вызывается, если он еще не существует, и переключается на этот вновь созданный буфер.
  • Если он *scratch-X-mode*уже существует, он просто переключается на этот буфер.
  • Повторный вызов этой функции в то время как в этом чистом буфере вернет вас в буфер файлов, над которым вы изначально работали.
Каушал Моди
источник
0

Здесь есть несколько хороших ответов, но я хотел бы добавить еще одну вещь. Emacs имеет множество функций, и часто есть несколько способов что-то сделать. Вы можете добавить теги вверху любого файла, которые сообщают emacs, какой тип он имеет, независимо от расширения. Например, добавив это:

# -*-Python-*-

В верхней части файла emacs узнает, что это файл Python, даже без .pyрасширения. Обратите внимание, что #в начале строки находится комментарий в стиле Python. Для разных типов файлов вы можете использовать разные комментарии. Например, чтобы указать файл Lisp, который вы используете ;для запуска строки комментария и установить режим в emacs, например:

; -*- mode: Lisp;-*-

См. Определение файловых переменных и Выбор режимов файла .

jcoffland
источник
Да, но вопрос здесь конкретно о создании нового временного буфера (например, с switch-buffer) и о том, чтобы режим автоматически устанавливался на что-то отличное от fundamental-mode.
glucas