【问题标题】:How to unload a vim script after sourcing it and making changes to it?如何在获取 vim 脚本并对其进行更改后卸载它?
【发布时间】:2016-10-26 06:16:22
【问题描述】:

我正在编写一个小型 vim 插件,并在进行增量更改时:source %-ing .vim 文件。

在每次更改和:source 命令之后,似乎没有加载/应用最新的更改,所以我想以某种方式取消:source/unload 文件而不关闭并重新打开VIm。

有没有(更好的)方法来做到这一点?编写 VIm 插件并尝试新功能时,正确的工作流程应该是什么?

谢谢

【问题讨论】:

  • 没有“卸载”Vim 脚本这样的事情。您能做的最好的事情就是以这样一种方式编写您的脚本,即无论之前的状态如何,重新加载都会执行所有相关的初始化。例如。使用function! 代替functioncommand! 代替command,使用augroups 等等。
  • 谢谢。 @SatoKatsura,重新加载是指再次获取脚本文件,而不重新启动 VIm?
  • 是的。这几乎是你能做的最好的了。
  • 如果您使用函数定义字典(为了模拟 OO 编程),您还必须让成员函数指向非匿名函数。如果您使用的是反重新包含防护装置,您还必须预见到需要忽略它。最后一件事,如果你想删除东西(命令、映射等),那么你必须手动完成。覆盖以前的定义很容易。删除不是。

标签: vim plugins vim-plugin


【解决方案1】:

为了总结cmets。

  • 明确删除定义需要显式手动删除。
  • 覆盖以前的定义非常容易。请参阅以下内容。

功能和命令:

函数和命令需要定义 banged -> function!, command!

自动命令

需要清除自动命令。我通常是这样进行的:

augroup MyPluginNameOrFeature
  au! " <- this clears all autocommands defined in the group MyPluginNameOrFeature
  au Event pattern action
aug END

反再纳入警卫

需要绕过反重新包含防护措施。例如,我的插件通常是这样定义的:

" plugin/foobar.vim
let s:k_version = '100'
if &cp || (exists("g:loaded_foobar")
      \ && (g:loaded_foobar>= s:k_version)
      \ && !exists('g:force_reload_foobar'))
  finish
endif
let g:loaded_foobar= s:k_version
let s:cpo_save=&cpo
set cpo&vim
... plugin definitions (mappings, commands, autocommand, abbreviation)
... understand that functions are in autoload-plugin which don't have anti-reinclusion guards
let &cpo=s:cpo_save

这意味着您必须在保存和重新加载之前增加版本号,或者您需要在重新加载脚本之前将 g:force_reload_foobar 设置为 1。因此我的:Reload 命令(它与其他两个答案中提供的相同——尽管这个支持相对于'runtimepath' 选项的命令行自动完成)

对象(带有方法的字典)

对于我们可以创建的对象:

function! namespace#make_my_object(args)
   let res = {}
   " don't write the following if you want to be able
   " to override the member function definitions when reloading the script
   " and if you want to be able to decode which function appears in 
   " the callstack
   "    :function! res.foo() abort
   "       code
   "    :endfunction
   " Instead write:
   let res.foo = function('s:foo') " with later vim versions
   let res.foo = function(s:getSNR('s:foo')) " with older vim versions

   return res
endfunction

function! s:foo() dict abort
   code
endfunction

function! s:getSNR(...) abort
  " needed to assure compatibility with old vim versions
  if !exists("s:SNR")
    let s:SNR=matchstr(expand('<sfile>'), '<SNR>\d\+_\zegetSNR$')
  endif
  return s:SNR . (a:0>0 ? (a:1) : '')
endfunction

否则,如果您已经提取了:let o = namespace#make_my_object(42),重新采购脚本将不会更新对象方法的定义。 :Reload plugin/foobar.vim | :call o.foo()

全局变量

覆盖/重新初始化变量非常简单。只是给它一个新的价值。但是,如果您的 vim 版本不够新,您将无法更改数据的类型。很容易检查 vim 的行为:

let s:foo = 'bar'
let s:foo = {}

如果最终出现错误,您可能需要添加显式 :silent! unlet s:foo。但是,一旦提交,如果您打算通过 vim-client-server 功能和 vimrunner 在 tracis-CI 中测试它,请不要将其留在脚本中。而是测试 if exists('s:foo') |unlet s:foo | endif -- :silentredir 中使用时并不像 vimrunner 那样安静。

有时我们不想重新初始化变量,但保留以前的值。在这种情况下,请编写如下内容:

let s:foo = get(s:, 'foo', default_value)
let g:foo = get(g:, 'foo', another_default_value)

映射、缩写和菜单

在他们的情况下没有什么可做的,因为它们会自动被新定义覆盖。需要注意的主要事情是当您为 &lt;Plug&gt;mappings 提供默认和唯一的键绑定来触发它们时。

例如:

nnoremap <silent> <Plug>(some-feature) TheActionToExecute
if !hasmapto('<Plug>(some-feature)', 'n')
  nmap <silent> <unique> <leader>default-keybinding <Plug>(some-feature)
endif

&lt;unique&gt; 对于检测歧义/太多想要绑定到相同键序列的操作非常有用。

菜单也是如此:提供新定义会覆盖之前的定义。但是将操作绑定到新的菜单项(名称和优先级)就像将映射绑定到新的键序列:旧的不会被删除。充其量你暂时(在你的vim会话期间)语义上重载了一些触发器->动作定义:有几种方法可以触发语义相同的动作。通常没那么重要。

杂项

我没有特别提到 ftplugins 的情况,也没有提到其他脚本类型。我看到的唯一区别与反重新包含保护以及映射、命令和缩写在 ftplugin 的情况下是缓冲区本地的事实有关。

【讨论】:

  • 非常感谢您的详细描述。我从中学到了很多。
【解决方案2】:

一个可能的解决方案是使用 Tim Pope 编写的 vim-scriptease 插件。

插件提供了一个函数:Disarm。以下是doc 关于该命令的内容:

尝试通过删除运行时文件来禁用它 :map s、:command s 和 :autocmd s。接受 一个绝对的 (~/.vim/plugin/scriptease.vim) 或 运行时相关 (plugin/scriptease.vim) 路径。

也许这并不完美,因为它不处理初始化的变量,但仍然可以提供帮助。

【讨论】:

  • 我安装了 vim-scriptease 插件来看看它是如何完成所有这些事情的。谢谢
【解决方案3】:

您可能看不到您的更改已应用,因为插件通常具有表单的多重包含保护

if exists('g:loaded_name')
    finish
endif
let g:loaded_name = 1

我的ReloadScript plugin 使用简单的:ReloadScript 命令绕过通常的包含保护变量。

这对于不兼容的映射、重命名的 autocmd 组等仍然无济于事。对于这些情况,重新启动 Vim 比尝试在当前会话中撤消所有这些更改更容易且更健壮。

【讨论】:

  • 我正在使用重启方法,同时检查 vim-scriptease 插件的工作方式。之后我也会试试你的。谢谢
猜你喜欢
  • 2023-03-08
  • 2023-04-04
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
相关资源
最近更新 更多