Есть ли способ для событий AND в autocmd?

21

Я хотел бы вызвать autocmd два события, но не так, как это обычно делается, т. Е. Если какое-либо из событий произошло, то вызвать autocmd. Я хочу вызвать его, если оба события произошли.

Например:
обычный способ сделать это

autocmd BufWrite,BufRead *.c *.py *.h :call StripTrailingWhitespaces()

Этот код будет вызывать StripTrailingWhiteSpaces () для BufWrite или BufRead.

Я хотел бы сделать что-то вроде:

autocmd Filetype c,cpp,python AND BufWrite :call StripTrailingWhiteSpaces()

Другими словами, инициируйте, autcmdкогда тип файла является одним из c, cpp, python и происходит запись в этот буфер.

Любая помощь приветствуется.

flashburn
источник

Ответы:

14

Команда автокоманды выполняется, когда происходит одно событие. Вы хотите, чтобы команда была выполнена после того, как произошла последовательность событий. Один из способов сделать это так:

autocmd FileType c,cpp,python
    \ autocmd BufWritePre <buffer> call StripTrailingWhiteSpaces()

<buffer>Модели приводят к тому , автокоманде быть срабатывать , когда текущий буфер записываются. Видеть

:help autocmd-buflocal

Обновить

Решение выше довольно просто и имеет некоторые недостатки, которые обсуждались в комментариях. Вот более полное решение, которое устраняет некоторые из этих недостатков. Он помещает автокоманды в группу и удаляет автокоманду BufWritePre, если она существует, перед созданием новой. Он по-прежнему создает одну автокоманду на буфер, но только одну.

augroup TrailSpace
    autocmd FileType c,cpp,python
        \ autocmd! TrailSpace BufWritePost <buffer> call SkipTrailingWhiteSpaces()
augroup END

Другое решение, похожее на ответ, опубликованный lcd047, который теперь удален, заключается в распознавании того, что при возникновении события FileType устанавливается опция 'filetype'. Затем вы можете обусловить ответ на событие BufWritePost значением 'filetype', как в следующем примере. Он имеет преимущество перед другими решениями в том, что создается только одна автокоманда.

autocmd BufWritePre * if count(['c','cpp','python'],&filetype)
    \ | call SkipTrailingWhiteSpaces()
    \ | endif
garyjohn
источник
Что делать, если я хочу запустить это на всех файлах, которые в данный момент открыты, т.е. я выполняю: wa?
вспышка
Если файлы были открыты с правильным FileTypeтипом файла , autocmd в ответе уже настроил бы второй autocmd ( BufWritePre) для запуска при сохранении их.
VanLaser
1
FileTypeAutocmd выше будет срабатывать для каждого файла, открыть с помощью правильного типа файла и настройки Уиллу буфера локального события для каждого из этих файлов. Поэтому, если вы запустите :wa, vim запустит зарегистрированные события для каждого буфера, прежде чем сохранить в файл.
VanLaser
1
Так что, если вы откроете 5 файлов Python, у вас будет 5 autocmdсекунд вместо одного, все на записи. Затем, если, скажем, 3 из этих файлов будут скрыты, то снова FileTypeотобразятся, снова сработают, и вы получите еще 3 autocmdс, также при записи. Это замечательно, мне интересно, почему я не придумал это решение. :)
lcd047
1
Производительность не проблема. Запуск функции stripTrailingWhiteSpaces()несколько раз для одного и того же файла может иметь непредвиденные последствия. Кроме того, чем больше у autocmdвас одного и того же события для одного и того же файла, тем выше вероятность того, что вы столкнетесь с некоторыми действительно гоночными условиями. Попробуйте поискать в архивах vim_dev, чтобы получить представление. Опять же, что я знаю, это может просто сработать для вас, верно?
lcd047
4

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

function StripTrailingWhiteSpacesIfReady(event) abort
  if !exists('b:events_for_whitespace')
    let b:events_for_whitespace = {}
  endif
  let b:events_for_whitespace[a:event] = 1
  if has_key(b:events_for_whitespace, 'FileType') && has_key(b:events_for_whitespace, 'Buf')
    " Strip trailing whitespace
    %s/\m\s\+$//
  endif
endfunction
autocmd Filetype c,cpp,python call StripTrailingWhiteSpacesIfReady('FileType')
autocmd BufWrite,BufRead * StripTrailingWhiteSpacesIfReady('Buf')
Му Разум
источник