我有一个用于TeX和Markdown文件的autocmd以自动保存文件。没什么异常:

autocmd CursorHold *.tex,*.md w


但是,随着这些文件的自定义设置的增加,我将它们拆分为ftplugin/tex.vimftplugin/markdown.vim

" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w


现在,这些文件仅作为适当文件的来源,因此模式匹配是多余的。显然,autocmd可以是局部于缓冲区的。来自: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.vimftplugin/markdown.vim都可以拥有:担心*.md*.markdown以及适用于Markdown的其他任何扩展名。

<buffer>的这种用法正确吗?我应该注意哪些陷阱?如果我擦除缓冲区并打开另一个缓冲区,事情会变得凌乱吗(希望数字不会冲突,但是…)?

评论

我很确定如果您擦除缓冲区,所有本地缓冲区autocmds也会被擦除。

确实是@ Tumbler41。它确实在帮助中说了几段。

并非完全符合您的要求,但up(自动更新:的缩写)比autocmd中的w更好(避免不必要的写入)。
@mMontu尼斯。它甚至解决了我的autocmd为我从git历史记录中检查的文件激活时遇到的问题。缓冲区是只读的,并且w失败。反复。 :up在这种情况下不执行任何操作。 :)

很高兴您喜欢:)顺便说一句,您还可以找到'autowrite'选项很有用(根据您的动机,可以删除autocmds)。

#1 楼


的这种用法正确吗?确保每次执行重新加载相同缓冲区的命令时都不会复制autocmd。

正如您所解释的,特殊模式<buffer>允许您依靠内置的文件类型检测机制来实现在文件$VIMRUNTIME/filetype.vim中。在该文件中,您可以找到Vim的内置autocmds,它们负责为任何给定的缓冲区设置正确的文件类型。例如,对于markdown:

" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  setf markdown


在文件类型插件中,您可以为安装的每个autocmd复制相同的模式。例如,要在几秒钟内光标没有移动时自动保存缓冲区,请执行以下操作:

/>
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  update


此外,如果某天另一扩展名有效,并且<buffer>已更新为包含该扩展名,则不会通知您的autocmds。而且,您必须在文件类型插件中更新其所有模式。



如果我擦除缓冲区并打开另一个缓冲区(希望
,数字不会冲突,但是...)?


我不确定,但我不认为Vim可以重用已擦除缓冲区的缓冲区号。 >我从帮助中找不到相关的部分,但是我从vim.wikia.com找到了该段:已删除的缓冲区,用于
新缓冲区。 Vim将始终为新缓冲区分配下一个顺序号。


此外,如@ Tumbler41所述,擦除缓冲区时,其autocmds也将被删除。来自$VIMRUNTIME/filetype.vim


清除缓冲区后,其缓冲区本地自动命令当然也
不见了。


如果要检查自己,可以通过将Vim的详细级别提高到6来进行。您可以使用:h autocmd-buflocal修饰符仅针对一个命令临时进行检查。因此,可以在markdown缓冲区内执行:

au CursorHold <buffer> update


然后,如果您查看Vim的消息: br />您应该会看到这样的一行:

:6verbose bwipe

其中:verbose是减价缓冲区的编号。 >
我应该注意任何陷阱吗?


有3种情况我会被视为陷阱,并且涉及特殊模式42。在其中两个中,<buffer>可能是一个问题,在另一个中,这是一个解决方案。


首先,您应谨慎使用以下方法清除augroup您的本地缓冲区autocmds。您必须熟悉以下代码段:

:messages


因此,您可能会想将其用于未经修改的本地缓冲区autocmds,如下所示:

auto-removing autocommand: CursorHold <buffer=42>


但这会产生不良影响。第一次加载降价缓冲区时,我们将其称为<buffer>,其autocmd将被正确安装。然后,当您重新加载A时,将删除autocmd(由于A),然后重新安装。因此,augroup将正确地防止autocmd的重复。 augroup的所有autocmds将被清除:即autocmd!的autocmd和B的autocmd之一。然后,将为A安装SINGLE autocmd。

因此,当您对B进行一些更改并等待几秒钟以触发B时,它将被自动保存。但是,如果返回B并执行相同的操作,则不会保存该缓冲区。这是因为上次加载降价缓冲区时,删除的内容和添加的内容之间不平衡。您删除的内容比添加的内容要多。 >
augroup your_group_name
    autocmd!
    autocmd Event pattern command
augroup END


请注意,您可以用星号替换CursorHold以匹配删除autocmds的行中的任何事件:您不需要指定要清除augroup时autocmds监听的所有事件。但是这次不是问题,而是解决方案。

当在文件类型插件中包含本地选项时,您可能会这样做:

/>
这将对缓冲区本地选项按预期工作,但对窗口本地选项并非始终如此。为了说明问题,您可以尝试以下实验。创建文件A,并在其中写入:

augroup my_markdown
    autocmd!
    autocmd CursorHold <buffer> update
augroup END


此文件将自动为扩展名为<buffer>的任何文件设置文件类型:autocmd!。您不需要将其包装在augroup中,因为对于这种特定类型的文件,Vim会自动执行它(请参阅CursorHold)。您可以创建它们。

接下来,创建文件类型插件<buffer>,并在其中写入:

augroup my_markdown
    autocmd! CursorHold <buffer>
    autocmd CursorHold <buffer> update
augroup END


默认情况下,在~/.vim/after/ftdetect/potion.vim文件中,此设置将导致制表符显示为potion,行尾显示为.pn。现在,创建一个最小的:h ftdetect;在~/.vim/after/ftplugin/potion.vim内写:

augroup my_markdown
    autocmd! * <buffer>
    autocmd CursorHold <buffer> update
augroup END


...启用文件类型插件。

还要创建一个药水文件potion和一个随机文件^I。在药水文件中,写一些东西:

setlocal option1=value
setlocal option2


在随机文件中,写药水文件的路径$

autocmd BufNewFile,BufRead *.pn setfiletype potion


现在,以最少的初始化启动Vim,仅采购vimrc,然后在垂直视口中打开两个文件:

setlocal list


您应该看到2垂直视口。左侧的药水文件显示带有美元符号的行的结尾,右侧的随机文件完全不显示它们。

将焦点移至随机文件,然后按/tmp/vimrc显示路径位于光标下的药水文件。现在,您会在右侧视口中看到相同的药水缓冲液,但是这次,行尾没有显示美元符号。如果键入/tmp/pn.pn,Vim应该回答/tmp/file



整个事件链: /> ...没有发生,因为当您按下/tmp/pn.pn时没有出现第一个vimrc。缓冲区已被加载。

这似乎是意外的,因为当您在药水文件类型插件中添加gf时,您可能认为它会在任何显示药水缓冲区的窗口中启用:setlocal list?选项。 br />
问题不是特定于此新的nolist文件类型的。您也可以通过BufRead文件来体验它。

也不仅仅针对gf选项。您可以通过其他本地窗口设置来体验它,例如setlocal list'list'potionmarkdown,...您可以通过其他命令来更改当前窗口中显示的缓冲区,以体验它:全局标记,'list'(在窗口本地跳转列表中向后移动),'conceallevel',...

总而言之,在以下情况下,将正确设置窗口本地选项:


在当前Vim会话期间未读取文件(因为必须启动'foldmethod') )
文件显示在已经正确设置了窗口本地选项的窗口中
使用诸如'foldexpr'之类的命令创建新窗口(在这种情况下,它应该继承窗口本地选项

否则,可能无法正确设置窗口本地选项。

可能的解决方案是不直接从窗口设置它们一个文件类型插件,但来自后者中安装的autocmd,它将监听'foldtitle'。每次在窗口中显示缓冲区时都会触发此事件。

因此,例如,不要编写以下代码:

filetype plugin on


您会这​​样写:

foo
bar
baz


在这里,您再次找到特殊模式gf
陷阱3

如果更改缓冲区的文件类型,则autocmds将保留。如果要删除它们,则需要配置C-o(请参阅:b {buffer_number}),并在其中包括以下命令:

/tmp/pn.pn


但是,请勿尝试删除它们。 augroup本身,因为里面仍然会有一些带有autocmd的markdown缓冲区。

FWIW,这是我用来设置BufRead的UltiSnips代码段:

这是我在:split中拥有的价值的一个示例:问这个问题,因为当我查找在Vim的默认文件中使用特殊模式BufWinEnter的所有行时:

$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file


我只找到9个匹配项(您可能会发现或多或少的情况,我使用的是Vim版本8.0,补丁版本高达<buffer>)。在9项匹配中,有7项在文档中,只有2项是实际来源。您应该在$ VIMRUNTIME / syntax / dircolors.vim中找到它们:

BufRead event → set 'filetype' option → load filetype plugins


我不知道它是否会引起问题,但它们不在内部augroup,这意味着每次重新加载文件类型为b:undo_ftplugin的缓冲区(如果您编辑名为:h undo_ftpluginb:undo_ftplugin或路径以~/.vim/after/ftplugin/awk.vim结尾的文件时都会发生),语法插件将添加一个新的本地缓冲区autocmd。 >
您可以像这样检查它:

setlocal list


最后一条命令应该显示以下内容: br />现在,重新加载缓冲区,然后再次询问当前缓冲区的本地缓冲区autocmds是什么: />
augroup my_potion
    au! * <buffer>
    au BufWinEnter <buffer> setlocal list
augroup END


每次重新加载文件后,每次触发事件<buffer>134dircolors.dircolors之一时,都会再次调用.dir_colors/etc/DIR_COLORS。 />
这可能不是什么大问题,因为即使重新加载了q4312079 q文件几次,我没有看到Vim的明显速度下降或意外行为。 ,如果要防止autocmds重复,则可以使用文件s:reset_colors()s:preview_color('.')文件创建自己的语法插件。在其中,您将导入原始语法插件的内容:

exe 'au! my_markdown * <buffer>'


然后,在后者中,您只需将autocmd包装在要清除的augroup中。因此,您可以将这些行替换为:

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}}
\                      "
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>'
                    \  "
endsnippet


...,替换为:

:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*


请注意,如果您使用文件CursorHold创建了CursorHoldI语法插件,则它将无法正常工作,因为默认语法插件将在之前获得。通过使用CursorMoved,您的语法插件将在默认插件之前获取,并且将设置局部缓冲区变量CursorMovedI,这将阻止源默认语法插件,因为它包含以下防护:

autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI   <buffer> call s:reset_colors()


一般规则似乎是:使用dircolorsdircolors目录创建自定义文件类型/语法插件,并防止在运行时路径中获取下一个插件(对于相同文件类型)(包括默认的)。并使用~/.vim/syntax/dircolors.vimdircolors,不是要阻止其他插件的来源,而只是要对某些设置的值有最后的认识。

评论


我希望我能更努力地投票。

–丰富
17年11月22日在11:31



@Rich我为您争取了更大的努力。我唯一的抱怨是缺少摘要“ tl; dr”。文本细节的页面无论对理解至关重要,都使我衰老的灵魂难以磨灭。更换autocmd!用autocmd! augroup块中的CursorHold 是一个特别关键的陷阱–应该预先突出显示。尽管如此,这是对时间,精力和流血的眼泪的惊人投资。

– Cecil咖喱
18年2月7日在7:00