Чи правильне використання <buffer> правильного?
Я думаю, що це правильно, але вам просто потрібно загорнути його всередину augroup і очистити останню, щоб переконатися, що autocmd не буде дублюватися кожного разу, коли ви виконуєте команду, яка перезавантажує той самий буфер.
Як ви пояснили, спеціальна схема <buffer>
дозволяє покластися на вбудований механізм виявлення файлів, реалізований всередині файлу $VIMRUNTIME/filetype.vim
.
У цьому файлі ви можете знайти вбудовані autocmds Vim, які відповідають за встановлення правильного файлу для будь-якого буфера. Наприклад, для розмітки:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
Всередині вашого модуля файлів ви можете скопіювати однакові шаблони для кожного встановленого autocmd. Наприклад, щоб автоматично зберегти буфер, коли курсор не перемістився протягом декількох секунд:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
Але <buffer>
чи менш дослівно:
au CursorHold <buffer> update
Крім того, якщо якийсь день діє інше розширення та $VIMRUNTIME/filetype.vim
оновиться для його включення, ваші autocmds не будуть повідомлені. І вам доведеться оновити всі їх візерунки всередині ваших плагінів файлів.
Чи стануть брудні речі, якщо я витерю буфер і відкрию інший (сподіваюся, цифри не зіткнуться, але ...)?
Я не впевнений, але не думаю, що Vim може повторно використовувати номер буфера стертого буфера. Я не зміг знайти відповідний розділ у довідці, але я знайшов цей пункт на сайті vim.wikia.com :
Ні. Vim не повторно використовувати номер буфера видаленого буфера для нового буфера. Vim завжди присвоює наступний послідовний номер для нового буфера.
Крім того, як пояснив @ Tumbler41 , коли ви стираєте буфер, його autocmds видаляються. Від :h autocmd-buflocal
:
Коли буфер видаляється, його локальні автокоманди також втрачаються, звичайно.
Якщо ви хочете перевірити себе, ви можете зробити це, збільшивши рівень багатомовності Vim до 6. Ви можете це зробити тимчасово, лише за одну команду, використовуючи :verbose
модифікатор. Отже, всередині вашого буфера відмітки ви можете виконати:
:6verbose bwipe
Потім, якщо ви перевірите повідомлення Vim:
:messages
Ви повинні побачити такий рядок:
auto-removing autocommand: CursorHold <buffer=42>
Де 42
була номер вашого буфера відмітки.
Чи є якісь підводні камені, про які я маю знати?
Є 3 ситуації, які я б розглядав як підводні камені і які передбачають особливий зразок <buffer>
. У двох з них це <buffer>
може бути проблемою, в іншому - рішенням.
Падіння 1
По-перше, ви повинні бути обережними з тим, як очистити аугрупи своїх буферних локальних autocmds. Ви повинні бути знайомі з цим фрагментом:
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
Отже, ви можете спокуситись використовувати його для локальних autocmds буфера, незмінених, як це:
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
Але це матиме небажаний ефект. Перший раз, коли ви завантажуєте буфер A
розмітки , назвемо його , його autocmd буде правильно встановлено. Потім, коли ви перезавантажите A
, autocmd буде видалений (через autocmd!
) і знову встановлений. Отже, augroup правильно запобіжить дублювання autocmd.
Тепер, припустимо, ви завантажуєте другий буфер розмітки, давайте назвемо його B
, у другому вікні. ВСІ autocmds аугрупи будуть очищені: це autocmd A
та one of B
. Потім буде встановлено SINGLE autocmd для B
.
Отже, коли ви внесете певні зміни B
та зачекаєте кілька секунд, CursorHold
щоб вас звільнили, це буде автоматично збережено. Але якщо ви повернетесь A
і зробите те саме, буфер не буде збережено. Це тому, що востаннє, коли ви завантажували буфер відмітки, спостерігався дисбаланс між тим, що ви видалили, і тим, що ви додали. Ви видалили більше, ніж додали.
Рішення полягає в тому, щоб не видалити ВСЕ autocmds, але тільки ті з поточного буфера, передаючи спеціальний шаблон <buffer>
для :autocmd!
:
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
Зауважте, що ви можете замінити CursorHold
зірочку, щоб відповідати будь-якій події в рядку, який видаляє autocmds:
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
Таким чином, вам не потрібно вказувати всі події, до яких слухаються ваші автосмс, коли ви хочете очистити аугруппу.
Падіння 2
Є ще одна помилка, але на цей раз <buffer>
це не питання, це рішення.
Коли ви додаєте локальний параметр у плагін файлу, ви, ймовірно, робите це так:
setlocal option1=value
setlocal option2
Це буде працювати, як очікувалося, для локальних буферних параметрів, але не завжди для локальних вікон. Для ілюстрації проблеми можна спробувати наступний експеримент. Створіть файл ~/.vim/after/ftdetect/potion.vim
, а всередині нього напишіть:
autocmd BufNewFile,BufRead *.pn setfiletype potion
Цей файл автоматично встановить тип файлу potion
для будь-якого файлу, розширенням якого є .pn
. Вам не потрібно загортати його всередину augroup, тому що для цього конкретного типу файл Vim зробить це автоматично (див. :h ftdetect
).
Якщо проміжних каталогів у вашій системі немає, ви можете їх створити.
Далі створіть плагін файлу ~/.vim/after/ftplugin/potion.vim
, а всередині нього напишіть:
setlocal list
За замовчуванням у potion
файлі цей параметр призведе до того, що символи вкладки відображатимуться як, ^I
а кінці рядків як $
.
Тепер створіть мінімум vimrc
; всередині /tmp/vimrc
напишіть:
filetype plugin on
... щоб увімкнути плагіни файлів.
Також створіть файл зілля /tmp/pn.pn
та довільний файл /tmp/file
. У файл зілля напишіть щось:
foo
bar
baz
У випадковий файл запишіть шлях до файлу зілля /tmp/pn.pn
:
/tmp/pn.pn
Тепер почніть Vim з мінімальними ініціалізаціями, просто знайдіть vimrc
і відкрийте обидва файли у вертикальних вікнах перегляду:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
Ви повинні побачити два вертикальних вікна перегляду. Файл зілля зліва відображає кінець рядків із знаками долара, випадковий файл праворуч взагалі не відображає їх.
Наведіть фокус на випадковий файл і натисніть, gf
щоб відобразити файл зілля, шлях якого знаходиться під курсором. Тепер ви бачите той самий буфер зілля у правій області перегляду, але цього разу кінець рядків не відображається із знаками долара. А якщо ви введете :setlocal list?
, Vim повинен відповісти nolist
:
Весь ланцюжок подій:
BufRead event → set 'filetype' option → load filetype plugins
... не сталося, тому що перший із них BufRead
не відбувся при натисканні gf
. Буфер вже завантажений.
Це може здатися несподіваним, оскільки, додавши setlocal list
всередину плагін філейного зілля, ви, можливо, подумали, що він включить 'list'
параметр у будь-якому вікні, де відображається буфер зілля.
Питання не характерне для цього нового potion
файлетипу. Ви можете також відчути це з markdown
файлом.
Це також не є специфічним для 'list'
варіанту. Ви можете випробувати його з іншого віконної локальної налаштуванням, як 'conceallevel'
, 'foldmethod'
, 'foldexpr'
, 'foldtitle'
, ...
Це не характерно і для gf
команди. Ви можете відчути це з іншими командами, які можуть змінити буфер, відображений у поточному вікні: глобальна позначка, C-o
(переміщення назад у вікні переліку вікон),, :b {buffer_number}
...
Підводячи підсумок, параметри локальних вікон будуть правильно встановлені, якщо і лише якщо:
- файл не був прочитаний під час поточного сеансу Vim (тому що
BufRead
його потрібно буде випустити)
- файл відображається у вікні, де параметри локальних вікон вже були правильно встановлені
- нове вікно створюється з такою командою, як
:split
(у цьому випадку воно має успадкувати параметри локального вікна з вікна, де виконувалася команда)
Інакше параметри локальних вікон можуть бути неправильно встановлені.
Можливим рішенням було б встановити їх не безпосередньо з плагіну філейного типу, а з встановленого в останньому autocmd, який би слухав BufWinEnter
. Цю подію потрібно запускати кожного разу, коли буфер відображається у вікні.
Так, наприклад, замість цього писати:
setlocal list
Ви б написали це:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
І тут ви знову знайдете особливий візерунок <buffer>
.
Падіння 3
Якщо ви зміните тип файлу буфера, autocmds залишиться. Якщо ви хочете їх видалити, вам потрібно налаштувати b:undo_ftplugin
(див. :h undo_ftplugin
) І включити в нього цю команду:
exe 'au! my_markdown * <buffer>'
Однак не намагайтеся видалити саму augroup, оскільки все ще можуть бути буфери для розмітки, у яких всередині є autocmds.
FWIW, це фрагмент UltiSnips, який я використовую для встановлення b:undo_ftplugin
:
snippet undo "undo ftplugin settings" bm
" teardown {{{1
let b:undo_ftplugin = get(b:, 'undo_ftplugin', '')
\ .(empty(get(b:, 'undo_ftplugin', '')) ? '' : '|')
\ ."${1:
\ setl ${2:option}<}${3:
\ | exe '${4:n}unmap <buffer> ${5:lhs}'}${6:
\ | exe 'au! ${7:group_name} * <buffer>'}${8:
\ | unlet! b:${9:variable}}${10:
\ | delcommand ${11:Cmd}}
\ "
$0
endsnippet
Ось приклад цінності, яку я маю ~/.vim/after/ftplugin/awk.vim
:
let b:undo_ftplugin = get(b:, 'undo_ftplugin', '')
\ .(empty(get(b:, 'undo_ftplugin', '')) ? '' : '|')
\ ."
\ setl cms< cocu< cole< fdm< fdt< tw<
\| exe 'nunmap <buffer> K'
\| exe 'au! my_awk * <buffer>'
\| exe 'au! my_awk_format * <buffer>'
\ "
Як зауваження, я розумію, чому ви задали це питання, тому що коли я шукав усі рядки, де використовується спеціальний шаблон <buffer>
у файлах за замовчуванням Vim:
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
Я знайшов лише 9 збігів (ви можете знайти більше чи менше, я використовую Vim версії 8.0, з виправленнями до 134
). І серед 9 матчів 7 - у документації, лише 2 - насправді. Ви повинні знайти їх у $ VIMRUNTIME / syntax / dircolors.vim :
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
Я не знаю , якщо це може викликати проблеми, але вони не всередині augroup, що означає кожен раз , коли ви перезавантажувати буфер якого є Filetype dircolors
(це відбувається , якщо ви редагуєте файл з ім'ям .dircolors
, .dir_colors
або чий шлях кінці з /etc/DIR_COLORS
), синтаксичний плагін додасть новий буфер-локальний autocmd.
Ви можете перевірити так:
$ vim ~/.dir_colors
:au * <buffer>
Остання команда повинна відображати це:
CursorHold
<buffer=1>
call s:reset_colors()
CursorHoldI
<buffer=1>
call s:reset_colors()
CursorMoved
<buffer=1>
call s:preview_color('.')
CursorMovedI
<buffer=1>
call s:preview_color('.')
Тепер перезавантажте буфер і знову запитайте, що таке локальні autocmds для поточного буфера:
:e
:au * <buffer>
Цього разу ви побачите:
CursorHold
<buffer=1>
call s:reset_colors()
call s:reset_colors()
CursorHoldI
<buffer=1>
call s:reset_colors()
call s:reset_colors()
CursorMoved
<buffer=1>
call s:preview_color('.')
call s:preview_color('.')
CursorMovedI
<buffer=1>
call s:preview_color('.')
call s:preview_color('.')
Після кожної перезавантаження файлу, s:reset_colors()
і s:preview_color('.')
буде називатися ще один раз, кожен раз , коли один з події CursorHold
, CursorHoldI
, CursorMoved
, CursorMovedI
обпалюють.
Це, мабуть, не є великою проблемою, тому що навіть після dircolors
декількох завантажень файлу я не бачив помітного уповільнення або несподіваної поведінки від Vim.
Якщо це проблема для вас, ви можете зв’язатися з обслуговуючим модулем синтаксису, але тим часом, якщо ви хочете запобігти дублюванню autocmds, ви можете створити власний синтаксичний плагін для dircolors
файлів, використовуючи файл ~/.vim/syntax/dircolors.vim
. Всередині нього ви імпортуєте вміст вихідного синтаксичного плагіна:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
Потім, в останньому, ви просто загорнете autocmds всередину augroup, яку ви очистите. Отже, ви б замінили ці рядки:
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
... з цими:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
Зауважте, що якщо ви створили свій dircolors
синтаксичний плагін з файлом ~/.vim/after/syntax/dircolors.vim
, він не працюватиме, тому що плагін синтаксису за замовчуванням був би використаний раніше. Використовуючи ~/.vim/syntax/dircolors.vim
ваш синтаксичний плагін, буде встановлено раніше за замовчуванням, і він встановить локальну змінну буфера b:current_syntax
, що запобіжить виведенню модуля синтаксису за замовчуванням, оскільки він містить цей захист:
if exists("b:current_syntax")
finish
endif
Загальним правилом здається: використовувати каталоги ~/.vim/ftplugin
та ~/.vim/syntax
каталоги для створення користувальницького модуля файлів / синтаксису та запобігати появі наступного плагіна (для того ж типу файлів) у шляху виконання (включаючи типові). І використовуйте ~/.vim/after/ftplugin
, ~/.vim/after/syntax
не для того, щоб не використовувати інші плагіни, а просто мати останнє слово про значення деяких налаштувань.