Vim:保存并退出时替换字符串

时间:2018-11-27 09:49:14

标签: vim

在我的vimrc中,此刻我有以下自动命令:

autocmd Bufwritepre,filewritepre *.py exe ":silent! 1," . 20 . "g/Last Modified :.*/s/Last Modified :.*/Last Modified : " .strftime("%Y-%m-%d %H:%M:%S %z(%Z)")

基本上,替换我标题中的某个字符串。它将最后一次修改的日期写在文件的标题中。

它可以工作,但是很烦人,因为每次我保存文件时都会触发它。我只想在保存并离开文件时触发它。

此问题:autocmd event to execute a command on :wq - vimscript?

我有类似的东西:

:autocmd BufWritePost *.py :autocmd VimLeave *.py :! exe ":silent! 1," . 20 . "g/Last Modified :.*/s/Last Modified :.*/Last Modified : " .strftime("%Y-%m-%d %H:%M:%S %z(%Z)")

它不起作用,退出vim时收到一些错误消息。可能是因为字符串替换最初是使用vim命令在“内部”完成的,而现在我尝试使用bash命令进行替换?

您能帮我解决这个问题吗?

编辑:

这是我的标题的样子:

#!/usr/bin/python
# coding: utf-8

"""
------------------------------------------------------------------------------
* Creation Date : 2018-11-27 14:55:00 +0100(CET)

* Last Modified : 2018-11-27 15:52:57 +0100(CET)

* Created By : JPFrancoia https://github.com/JPFrancoia

* Description :
------------------------------------------------------------------------------
"""

2 个答案:

答案 0 :(得分:1)

问题

这里的问题是,当当前缓冲区处于活动状态时(如您目前处于BufWritePre的情况下,总是触发:write之类的事件,而VimLeave之类的事件却被触发) (或更确切地说,取决于您退出Vim的方式)在当前缓冲区范围之外触发​​。您可能已经在选项卡,参数列表,分割窗口等中编辑了多个(Python或其他)文件。在VimLeave上,您将不得不再次找到所有这些缓冲区,并显式地遍历它们; :autocmd机制不会为您做到这一点。

更好的触发器是BufUnloadBufDelete,因为每个缓冲区都会触发一次。但是,甚至有些并发症,如:help BufUnload所述:

  

注意:执行此自动命令时,当前缓冲区%可能与正在卸载的缓冲区<afile>不同。不要更改到另一个缓冲区或窗口,这会导致问题!

虽然无法:write而不切换到另一个缓冲区,但是您可以很好地退出其他缓冲区(例如,通过:[N]bdelete:qall)。由于不允许切换到受影响的(即将死去的)缓冲区,因此无法使用:substitute。您可以使用较低级别的readfile()writefile(),并通过expand('<afile>:p')获取缓冲区的文件规范,并通过substitute()进行操作。或完全通过system()和外部shell命令在Vim外部进行时间戳操作。

讨论

如您所见,从每次保存的更新切换到仅在离开Vim时才更新/听起来听起来很简单,但是很难实现(正确完成-如果您只在其中编辑单个文件,则可以将某些东西捆绑在一起)例如Vim会话)。我宁愿保留原始设计,而是从事“烦人”的工作。有了可靠的实现(例如,不会像您的简单解决方案那样破坏当前的搜索模式和窗口视图),这是很自然的,许多人都在使用这种功能。实际上,您可以使用我的AutoAdapt plugin或其插件页面上列出的任何替代方法(或在vim.org或其他地方找不到的其他插件)。

答案 1 :(得分:0)

您可以尝试以下代码:

augroup monitor_python_change
    au!
    au QuitPre *.py call s:update_timestamp('now', 'on_QuitPre')
    au BufWritePre,FileWritePre *.py call s:update_timestamp('later', 'on_BufLeave')
augroup END

fu! s:update_timestamp(when, on_what) abort
    if a:when is# 'now'
        sil! au! update_timestamp
        sil! aug! update_timestamp
        if a:on_what is# 'on_QuitPre' && !&l:modified
            return
        endif
        sil! 1/Last Modified : \zs.*/s//\=strftime('%Y-%m-%d %H:%M:%S %z(%Z)')/
    else
        augroup update_timestamp
            au!
            au BufLeave * call s:update_timestamp('now', 'on_BufLeave')
        augroup END
    endif
endfu

如果代码未更新您的时间戳,则可能需要更改替换命令:

"      ┌ pattern used in the next substitution command (`//` = last used pattern)
"      ├───────────────────┐
sil! 1/Last Modified : \zs.*/s//\=strftime("%Y-%m-%d %H:%M:%S %z(%Z)")/
"    ├──────────────────────┘
"    └ range of the substitution command
"      (after the first line of the buffer,
"       look for the next line containing `Last Modified : `)

也许会替换其样式和/或其范围。

如果代码有时会更新您的时间戳,而实际上不会,则您可能需要更改s:update_timestamp()中的条件:

if a:on_what is# 'on_QuitPre' && !&l:modified
    return
endif

当前条件阻止从QuitPrea:on_what is# 'on_QuitPre')调用函数并且未修改缓冲区(!&l:modified)时执行替换。