Eu tenho um autocmd para arquivos TeX e Markdown para salvar o arquivo automaticamente. Nada incomum:
autocmd CursorHold *.tex,*.md w
No entanto, como configurações personalizadas para esses arquivos aumentou, eu dividi-los para dentro ftplugin/tex.vim
e ftplugin/markdown.vim
:
" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w
Agora, esses arquivos são originários apenas dos arquivos apropriados, portanto, a correspondência de padrões é redundante. Aparentemente, autocmd
s pode ser local de buffer. De :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>
Isso parece destinado a esse uso. Agora, ambos ftplugin/tex.vim
e ftplugin/markdown.vim
podem ter:
autocmd CursorHold <buffer> w
Eu realmente não estou preocupado com a extensão real enquanto o filetype está correta, então isso me poupa de ter que se preocupar *.md
e *.markdown
e quaisquer outras extensões são válidos para Markdown.
Esse uso está <buffer>
correto? Existem armadilhas das quais devo estar ciente? As coisas ficarão confusas se eu limpar um buffer e abrir outro (espero que os números não colidam, mas ...)?
up
(abreviação:update
) seria melhor do quew
no seu autocmd (evite gravações desnecessárias).w
falhou. Repetidamente.:up
não faz nada nesse caso. :)Respostas:
Eu acho que está correto, mas você só precisa envolvê-lo dentro de um augroup e limpar o último, para garantir que o autocmd não seja duplicado toda vez que você executar um comando que recarrega o mesmo buffer.
Como você explicou, o padrão especial
<buffer>
permite confiar no mecanismo de detecção de tipo de arquivo interno, implementado dentro do arquivo$VIMRUNTIME/filetype.vim
.Nesse arquivo, você pode encontrar os autocmds internos do Vim, responsáveis por definir o tipo de arquivo correto para qualquer buffer. Por exemplo, para remarcação:
Dentro do seu plugin de tipo de arquivo, você pode copiar os mesmos padrões para cada autocmd instalado. Por exemplo, para salvar automaticamente o buffer quando o cursor não se mover durante alguns segundos:
Mas
<buffer>
é bem menos detalhado:Além disso, se algum dia outra extensão for válida e
$VIMRUNTIME/filetype.vim
for atualizada para incluí-la, seus autocmds não serão informados. E você terá que atualizar todos os seus padrões dentro dos plugins do tipo de arquivo.Não tenho certeza, mas não acho que o Vim possa reutilizar o número do buffer de um buffer limpo. Não encontrei a seção relevante na ajuda, mas encontrei este parágrafo em vim.wikia.com :
Além disso, como o @ Tumbler41 explicou, quando você limpa um buffer, seus autocmds são removidos. De
:h autocmd-buflocal
:Se você quiser verificar a si mesmo, poderá fazê-lo aumentando o nível de verbosidade do Vim para 6. Você pode fazê-lo temporariamente, apenas para um comando, usando o
:verbose
modificador. Portanto, dentro do seu buffer de remarcação, você pode executar:Então, se você verificar as mensagens do Vim:
Você deve ver uma linha parecida com esta:
Onde
42
estava o número do seu buffer de remarcação.Existem três situações que eu consideraria armadilhas e que envolvem um padrão especial
<buffer>
. Em dois deles,<buffer>
pode ser um problema, no outro, é uma solução.Armadilha 1
Primeiro, você deve ter cuidado com a maneira de limpar os augroups de seus autocmds locais de buffer. Você deve estar familiarizado com este trecho:
Portanto, você pode ser tentado a usá-lo para seus autocmds locais de buffer, sem modificação, assim:
Mas isso terá um efeito indesejado. Na primeira vez que você carregar um buffer de redução, vamos chamá-lo
A
, seu autocmd será instalado corretamente. Então, quando você recarregarA
, o autocmd será excluído (por causa deautocmd!
) e reinstalado. Portanto, o augroup impedirá corretamente a duplicação do autocmd.Agora, suponha que você carregue um segundo buffer de redução, vamos chamá-lo
B
, em uma segunda janela. TODOS os autocmds do augroup serão limpos: esse é o autocmd deA
e esse deB
. Em seguida, um único autocmd será instalado paraB
.Portanto, quando você fizer alguma alteração
B
e esperar alguns segundos paraCursorHold
ser acionado, ele será salvo automaticamente. Mas se você voltarA
e fizer a mesma coisa, o buffer não será salvo. Isso ocorre porque na última vez em que você carregou um buffer de redução, houve um desequilíbrio entre o que você removeu e o que adicionou. Você removeu mais do que adicionou.A solução é não remover TODOS os autocmds, mas apenas os do buffer atual, passando o padrão especial
<buffer>
para:autocmd!
:Observe que você pode substituir
CursorHold
por uma estrela para corresponder a qualquer evento na linha que remova autocmds:Dessa forma, você não precisa especificar todos os eventos que seus autocmds estão ouvindo quando deseja limpar o augroup.
Armadilha 2
Há outra armadilha, mas desta vez
<buffer>
não é o problema, é a solução.Ao incluir uma opção local em um plug-in de tipo de arquivo, você provavelmente faz o seguinte:
Isso funcionará conforme o esperado para opções locais de buffer, mas nem sempre para opções locais de janelas. Para ilustrar o problema, você pode tentar o seguinte experimento. Crie o arquivo
~/.vim/after/ftdetect/potion.vim
e, dentro dele, escreva:Este arquivo definirá automaticamente o tipo
potion
de arquivo para qualquer arquivo cuja extensão seja.pn
. Você não precisa agrupá-lo dentro de um augroup porque, para esse tipo específico de arquivo, o Vim o fará automaticamente (consulte:h ftdetect
).Se os diretórios intermediários não existirem no seu sistema, você poderá criá-los.
Em seguida, crie o plugin do tipo de arquivo
~/.vim/after/ftplugin/potion.vim
e, dentro dele, escreva:Por padrão, em um
potion
arquivo, essa configuração fará com que os caracteres de tabulação sejam exibidos como^I
e o final das linhas como$
.Agora, crie um mínimo
vimrc
; dentro de/tmp/vimrc
escrever:... para ativar os plugins de tipo de arquivo.
Além disso, crie um arquivo de poção
/tmp/pn.pn
, e um arquivo aleatório/tmp/file
. No arquivo de poções, escreva algo:No arquivo aleatório, escreva o caminho para o arquivo de poção
/tmp/pn.pn
:Agora, inicie o Vim com um mínimo de inicializações, apenas localizando
vimrc
e abra os dois arquivos em viewports verticais:Você deve ver duas viewports verticais. O arquivo de poção à esquerda exibe o final das linhas com cifrões, o arquivo aleatório à direita não os exibe.
Concentre o foco no arquivo aleatório e pressione
gf
para exibir o arquivo de poção cujo caminho está sob o cursor. Agora você vê o mesmo buffer de poção na janela de exibição correta, mas desta vez o final das linhas não é exibido com cifrões. E se você digitar:setlocal list?
, o Vim deverá responder comnolist
:Toda a cadeia de eventos:
... não ocorreu, porque o primeiro deles,
BufRead
não ocorreu quando você pressionougf
. O buffer já estava carregado.Pode parecer inesperado, porque quando você adicionou
setlocal list
dentro do seu plug-in de tipo de arquivo de poção, pode ter pensado que ele habilitaria a'list'
opção em qualquer janela que exibisse um buffer de poção.O problema não é específico para este novo
potion
tipo de arquivo. Você pode experimentar isso com ummarkdown
arquivo também.Também não é específico para a
'list'
opção. Você pode experimentá-lo com outras definições da janela-local, como'conceallevel'
,'foldmethod'
,'foldexpr'
,'foldtitle'
, ...Também não é específico para o
gf
comando. Você pode experimentar com outros comandos que podem alterar o buffer exibido na janela atual: marca global,C-o
(retroceder no jumplist local da janela),,:b {buffer_number}
...Para resumir, as opções locais da janela serão definidas corretamente, se e somente se:
BufRead
precisará ser acionado):split
(nesse caso, ele deve herdar as opções locais da janela da janela em que o comando foi executado)Caso contrário, as opções locais da janela podem não estar definidas corretamente.
Uma solução possível seria configurá-los não diretamente a partir de um plug-in de tipo de arquivo, mas a partir de um autocmd instalado no último, que seria escutado
BufWinEnter
. Este evento deve ser acionado toda vez que um buffer for exibido em uma janela.Então, por exemplo, em vez de escrever isso:
Você escreveria isto:
E aqui, você encontra novamente o padrão especial
<buffer>
.Armadilha 3
Se você alterar o tipo de arquivo do seu buffer, os autocmds permanecerão. Se você deseja removê-los, é necessário configurar
b:undo_ftplugin
(consulte:h undo_ftplugin
) e incluir este comando:No entanto, não tente remover o augroup em si, porque ainda pode haver alguns buffers de remarcação que possuem autocmds dentro dele.
FWIW, este é o trecho UltiSnips que estou usando para definir
b:undo_ftplugin
:E aqui está um exemplo de valor que eu tenho
~/.vim/after/ftplugin/awk.vim
:Como observação, entendo por que você fez a pergunta, porque quando procurei todas as linhas em que o padrão especial
<buffer>
foi usado nos arquivos padrão do Vim:Encontrei apenas 9 correspondências (você pode encontrar mais ou menos, estou usando o Vim versão 8.0, com correções de até
134
). E entre as 9 correspondências, 7 estão na documentação, apenas 2 são realmente fornecidas. Você deve encontrá-los em $ VIMRUNTIME / syntax / dircolors.vim :Eu não sei se isso pode causar um problema, mas eles não estão dentro de um augroup, o que significa que cada vez que você recarregar um tampão cujo filetype é
dircolors
(acontece se você editar um arquivo chamado.dircolors
,.dir_colors
ou cujas extremidades caminho com/etc/DIR_COLORS
), o plug-in de sintaxe adicionará um novo autocmd local de buffer.Você pode verificá-lo assim:
O último comando deve exibir isso:
Agora, recarregue o buffer e pergunte novamente quais são os autocmds locais do buffer para o buffer atual:
Desta vez, você verá:
Após cada recarga do arquivo,
s:reset_colors()
es:preview_color('.')
será chamado uma vez adicional, cada vez que um dos eventosCursorHold
,CursorHoldI
,CursorMoved
,CursorMovedI
é acionado.Provavelmente não é um grande problema, porque mesmo depois de recarregar um
dircolors
arquivo várias vezes, não vi uma desaceleração perceptível ou comportamento inesperado do Vim.Se é um problema para você, você poderia entrar em contato com o mantenedor do plugin sintaxe, mas ao mesmo tempo, se você queria evitar a duplicação de autocmds, você pode criar seu próprio plugin sintaxe para
dircolors
arquivos, usando o arquivo~/.vim/syntax/dircolors.vim
. Dentro dele, você importaria o conteúdo do plug-in de sintaxe original:Então, no último, você apenas colocaria os autocmds dentro de um augroup que você limparia. Então, você substituiria estas linhas:
... com estes:
Observe que, se você criou seu
dircolors
plug-in de sintaxe com o arquivo~/.vim/after/syntax/dircolors.vim
, ele não funcionaria, porque o plug-in de sintaxe padrão seria originário antes. Ao usar~/.vim/syntax/dircolors.vim
, seu plug-in de sintaxe será originado antes do padrão e definirá a variável buffer-localb:current_syntax
, o que impedirá que o plug-in de sintaxe padrão seja originado porque contém esta proteção:A regra geral parece ser: use os diretórios
~/.vim/ftplugin
e~/.vim/syntax
para criar um plug-in de tipo de arquivo / sintaxe personalizado e impedir que o próximo plug-in (para o mesmo tipo de arquivo) no caminho de tempo de execução seja originado (incluindo os padrão). E uso~/.vim/after/ftplugin
,~/.vim/after/syntax
e não para evitar que outros plugins de ser originária, mas apenas para ter a última palavra sobre o valor de alguns ajustes.fonte
autocmd!
comautocmd! CursorHold <buffer>
emaugroup
blocos é uma questão particularmente crítica - e deveria ter sido destacada antecipadamente. No entanto ... este é um investimento surpreendentemente incrível de tempo, esforço e lágrimas de sangue.