代码之家  ›  专栏  ›  技术社区  ›  JPFrancoia

VIM:保存和退出时更换字符串

vim
  •  0
  • JPFrancoia  · 技术社区  · 6 年前

    在我的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 回复  |  直到 6 年前
        1
  •  0
  •   user938271    6 年前

    您可以尝试以下代码:

    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
    

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

        2
  •  1
  •   Ingo Karkat    6 年前

    问题

    这里的问题是当事件 BufWritePre 总是在当前缓冲区处于活动状态时触发(因为您当前正在 :write ),像这样的事件 VimLeave 是否触发(或者更确切地说,可能触发,取决于如何退出VIM)在当前缓冲区范围之外。您可以在选项卡、参数列表、拆分窗口等中编辑多个(python或其他)文件。 维姆莱特 ,您将必须再次定位所有这些缓冲区,并显式地对它们进行迭代;以及 :autocmd 机制不会帮你做到这一点。

    更好的触发方式是 BufUnload BufDelete ,因为每个缓冲区都会触发一次。然而,即使有并发症,如 :help BufUnload 解释:

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

    但这是不可能的 另一个缓冲区不切换到它,您可以很好地退出其他缓冲区(例如通过 :[N]bdelete :qall )因为不允许切换到受影响(死亡)的缓冲区,请使用 :substitute 是不可能的。你可以用低层 readfile() writefile() ,缓冲区的filespec通过 expand('<afile>:p') 以及通过 substitute() . 或者在VIM之外通过 system() 以及一个外部shell命令。

    讨论

    正如您所看到的,从每次保存时的更新切换到只保留vim/时的更新听起来很简单,但很难实现(例如,如果您只在vim会话中编辑单个文件,则可以将某些内容拼凑在一起)。我宁愿保留原来的设计,在“烦人”的部分工作。通过一个强大的实现(例如,它不会像您的简单解决方案那样破坏当前的搜索模式和窗口视图),这是非常自然的,许多人使用这种功能。实际上,你可以用我的 AutoAdapt plugin 或其插件页上列出的任何备选方案(或其他我不知道的插件 vim.org 或其他地方)。