У меня есть autocmd для файлов TeX и Markdown для автоматического сохранения файла. Ничего необычного
autocmd CursorHold *.tex,*.md w
Однако, поскольку пользовательские настройки для этих файлов увеличились, я разделил их на ftplugin/tex.vim
и ftplugin/markdown.vim
:
" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w
Теперь эти файлы поставляются только для соответствующих файлов, поэтому сопоставление с образцом является избыточным. Очевидно, autocmd
s может быть локальным по отношению к буферу. От :h autocmd-buffer-local
:
Buffer-local autocommands are attached to a specific buffer. They are useful
if the buffer does not have a name and when the name does not match a specific
pattern. But it also means they must be explicitly added to each buffer.
Instead of a pattern buffer-local autocommands use one of these forms:
<buffer> current buffer
<buffer=99> buffer number 99
<buffer=abuf> using <abuf> (only when executing autocommands)
<abuf>
Это, кажется, предназначено для такого использования. Теперь оба ftplugin/tex.vim
и ftplugin/markdown.vim
могут иметь:
autocmd CursorHold <buffer> w
Я не очень обеспокоен фактическое расширение до тех пор , как Filetype правильно, так что это избавляет меня от необходимости беспокоиться о *.md
и *.markdown
и любых других расширениях действительны для Markdown.
Это использование <buffer>
правильное? Есть ли какие-либо подводные камни, о которых я должен знать? Будет ли что-то запутаться, если я вытираю буфер и открываю другой (надеюсь, числа не будут сталкиваться, но…)?
up
(сокращенно:update
) будет лучше, чемw
в вашем autocmd (избегайте ненужных записей).w
вышел из строя. Несколько раз.:up
ничего не делает в этом случае. :)Ответы:
Я думаю, что это правильно, но вам просто нужно обернуть его внутри группы и очистить последнюю, чтобы убедиться, что autocmd не будет дублироваться при каждом выполнении команды, которая перезагружает один и тот же буфер.
Как вы объяснили, специальный шаблон
<buffer>
позволяет вам полагаться на встроенный механизм обнаружения типов файлов, реализованный внутри файла$VIMRUNTIME/filetype.vim
.В этом файле вы можете найти встроенные в Vim autocmds, которые отвечают за установку правильного типа файла для любого данного буфера. Например, для уценки:
Внутри вашего плагина filetype вы можете копировать одни и те же шаблоны для каждого устанавливаемого вами autocmd. Например, чтобы автоматически сохранить буфер, когда курсор не двигался в течение нескольких секунд:
Но
<buffer>
это гораздо менее многословно:Кроме того, если однажды другое расширение будет действительным и
$VIMRUNTIME/filetype.vim
будет обновлено, чтобы включить его, ваши autocmds не будут проинформированы. И вам придется обновить все их шаблоны внутри ваших плагинов файловых типов.Я не уверен, но я не думаю, что Vim может повторно использовать номер буфера стертого буфера. Я не смог найти соответствующий раздел из справки, но нашел этот параграф с vim.wikia.com :
Кроме того, как объяснил @ Tumbler41 , когда вы стираете буфер, его autocmds удаляются. От
:h autocmd-buflocal
:Если вы хотите проверить себя, вы можете сделать это, увеличив уровень детализации Vim до 6. Вы можете сделать это временно, только для одной команды, используя
:verbose
модификатор. Итак, внутри вашего буфера уценки вы можете выполнить:Затем, если вы проверите сообщения Vim:
Вы должны увидеть строку, похожую на эту:
Где
42
был номер вашего буфера уценки.Есть 3 ситуации, которые я бы назвал подводными камнями и которые связаны с особой схемой
<buffer>
. В двух из них<buffer>
может быть проблема, в другом - решение.Ловушка 1
Во-первых, вы должны быть осторожны с тем, как очищать augroups ваших локальных буферов autocmds. Вы должны быть знакомы с этим фрагментом:
Таким образом, у вас может возникнуть соблазн использовать его для ваших локальных буферов autocmds, без изменений, например:
Но это будет иметь нежелательный эффект. При первой загрузке буфера уценки, давайте назовем его
A
, его autocmd будет правильно установлен. Затем, когда вы перезагрузите компьютерA
, autocmd будет удален (из-заautocmd!
) и переустановлен. Таким образом, augroup правильно предотвратит дублирование autocmd.Теперь предположим, что вы загружаете второй буфер уценки, давайте назовем его
B
во втором окне. ВСЕ autocmds augroup будут очищены: это autocmd изA
и один изB
. Затем будет установлен одиночный autocmdB
.Поэтому, когда вы вносите какие-либо изменения
B
и ждете несколько секундCursorHold
, пока не произойдет выстрел, он будет автоматически сохранен. Но если вы вернетесьA
и сделаете то же самое, буфер не будет сохранен. Это потому, что в последний раз, когда вы загружали буфер уценки, был дисбаланс между тем, что вы удалили, и тем, что вы добавили. Вы удалили больше, чем добавили.Решение состоит в том, чтобы не удалить ВСЕ autocmds, но только те из текущего буфера, передавая специальный шаблон
<buffer>
для:autocmd!
:Обратите внимание, что вы можете заменить
CursorHold
звездочкой, чтобы соответствовать любому событию в строке, которая удаляет autocmds:Таким образом, вам не нужно указывать все события, которые слушает ваш autocmds, когда вы хотите очистить группу.
Ловушка 2
Есть еще одна ловушка, но на этот раз
<buffer>
это не проблема, а решение.Когда вы включаете локальный параметр в плагин filetype, вы, вероятно, делаете это следующим образом:
Это будет работать, как и ожидалось, для локальных параметров буфера, но не всегда для локальных окон. Чтобы проиллюстрировать проблему, вы можете попробовать следующий эксперимент. Создайте файл
~/.vim/after/ftdetect/potion.vim
и внутри него напишите:Этот файл автоматически устанавливает тип
potion
файла для любого файла с расширением.pn
. Вам не нужно заключать его в группу augroup, потому что для этого конкретного типа файлов Vim сделает это автоматически (см.:h ftdetect
).Если промежуточные каталоги не существуют в вашей системе, вы можете их создать.
Затем создайте плагин filetype
~/.vim/after/ftplugin/potion.vim
и внутри него напишите:По умолчанию в
potion
файле этот параметр приводит к тому, что символы табуляции отображаются как,^I
а конец строк как$
.Теперь создайте минимум
vimrc
; внутри/tmp/vimrc
написать:... чтобы включить плагины файловых типов.
Кроме того, создайте файл зелья
/tmp/pn.pn
и случайный файл/tmp/file
. В файле зелья напишите что-нибудь:В случайном файле напишите путь к файлу зелья
/tmp/pn.pn
:Теперь запустите Vim с минимумом инициализаций, просто загрузите
vimrc
и откройте оба файла в вертикальных окнах просмотра:Вы должны увидеть 2 вертикальных видовых экрана. Файл зелья слева отображает конец строк со знаками доллара, случайный файл справа не отображает их вообще.
Установите фокус на случайный файл и нажмите,
gf
чтобы отобразить файл зелья, путь которого находится под курсором. Теперь вы видите тот же буфер зелья в правом окне просмотра, но на этот раз, конец строки не отображается со знаками доллара. И если вы напечатаете:setlocal list?
, Vim должен ответитьnolist
:Вся цепочка событий:
... не произошло, потому что первое из них
BufRead
не произошло, когда вы нажалиgf
. Буфер уже загружен.Это может показаться неожиданным, потому что, когда вы добавляете
setlocal list
в свой плагин типа файла зелья, вы, возможно, думали, что он включит'list'
опцию в любом окне, отображающем буфер зелья.Проблема не связана с этим новым
potion
типом файла. Вы можете испытать это и сmarkdown
файлом.Это не специфично для
'list'
варианта. Вы можете испытать его с другой оконной локальной настройкой, как'conceallevel'
,'foldmethod'
,'foldexpr'
,'foldtitle'
, ...Это не специфично для
gf
команды. Вы можете испытать это с другими командами, которые могут изменить буфер, отображаемый в текущем окне: глобальная метка,C-o
(переместиться назад в локальном списке переходов),,:b {buffer_number}
...Подводя итог, локальные параметры окна будут правильно установлены, если и только если:
BufRead
что должен быть запущен):split
(в этом случае оно должно наследовать локальные параметры окна от окна, в котором была выполнена команда)В противном случае локальные параметры окна могут быть установлены неправильно.
Возможным решением было бы установить их не напрямую из плагина filetype, а из autocmd, установленного в последнем, который будет слушать
BufWinEnter
. Это событие должно запускаться каждый раз, когда в окне отображается буфер.Так, например, вместо того, чтобы писать это:
Вы бы написали это:
И здесь вы снова обнаруживаете особый узор
<buffer>
.Ловушка 3
Если вы измените тип файла вашего буфера, autocmds останется. Если вы хотите удалить их, вам нужно настроить
b:undo_ftplugin
(см.:h undo_ftplugin
) И включить в него следующую команду:Однако не пытайтесь удалить саму группу, потому что все еще могут быть некоторые буферы уценки, в которых есть autocmds.
Кстати, это фрагмент кода UltiSnips, который я использую для установки
b:undo_ftplugin
:И вот пример значения, которое я имею в
~/.vim/after/ftplugin/awk.vim
:В качестве примечания, я понимаю, почему вы задали вопрос, потому что, когда я искал все строки, где использовался специальный шаблон
<buffer>
в файлах Vim по умолчанию:Я нашел только 9 совпадений (вы можете найти более или менее, я использую Vim версии 8.0, с исправлениями до
134
). И среди 9 матчей 7 находятся в документации, только 2 фактически получены. Вы должны найти их в $ VIMRUNTIME / syntax / dircolors.vim :Я не знаю , если это может вызвать проблемы, но они не внутри augroup, что означает каждый раз , когда вы перезагружать буфер которого является Filetype
dircolors
(это происходит , если вы редактируете файл с именем.dircolors
,.dir_colors
или чей путь концы с/etc/DIR_COLORS
), плагин синтаксиса добавит новый локальный буфер autocmd.Вы можете проверить это так:
Последняя команда должна отобразить это:
Теперь перезагрузите буфер и снова спросите, каковы локальные для буфера autocmds для текущего буфера:
На этот раз вы увидите:
После каждой перезагрузки файла,
s:reset_colors()
иs:preview_color('.')
будет называться еще один раз, каждый раз , когда один из событияCursorHold
,CursorHoldI
,CursorMoved
,CursorMovedI
обжигают.Вероятно, это не большая проблема, потому что даже после перезагрузки
dircolors
файла несколько раз я не заметил заметного замедления или неожиданного поведения Vim.Если это проблема для вас, вы можете связаться с разработчиком модуля синтаксиса, но в то же время, если вы хотите предотвратить дублирование autocmds, вы можете создать свой собственный модуль синтаксиса для
dircolors
файлов, используя файл~/.vim/syntax/dircolors.vim
. Внутри него вы импортируете содержимое исходного синтаксического плагина:Затем в последнем случае вы просто оборачиваете autocmds в группу augroup, которую очищаете. Итак, вы бы заменили эти строки:
... с этими:
Обратите внимание, что если вы создали
dircolors
плагин синтаксиса с файлом~/.vim/after/syntax/dircolors.vim
, он не будет работать, потому что плагин синтаксиса по умолчанию будет поставлен раньше. При использовании~/.vim/syntax/dircolors.vim
, ваш синтаксический плагин будет получен раньше, чем по умолчанию, и он установит локальную переменную буфераb:current_syntax
, которая предотвратит источник синтаксического плагина по умолчанию, потому что он содержит этот сторож:Общее правило выглядит следующим образом: используйте каталоги
~/.vim/ftplugin
and~/.vim/syntax
для создания пользовательского подключаемого модуля типа / синтаксиса и предотвращайте выбор следующего подключаемого модуля (для того же типа файла) в пути времени выполнения (включая стандартные). И используйте~/.vim/after/ftplugin
,~/.vim/after/syntax
не для того, чтобы другие источники плагинов были получены, а просто чтобы иметь последнее слово в значении некоторых настроек.источник
autocmd!
сautocmd! CursorHold <buffer>
in вaugroup
блоках является особенно важной ошибкой - и должна была быть выдвинута на первый план. Тем не менее ... это явно удивительное вложение времени, усилий и кровавых слез.