vim - Vim-在自动命令上定义缓冲区变量

标签 vim

我想执行以下操作:

autocmd BufAdd * let b:foo = 1


但是正如文档所描述的,此时缓冲区仍然是旧缓冲区,只能由<abuf>访问,这是新缓冲区号的作用。


注意:执行此自动命令时,当前缓冲区“%”可能与正在创建的缓冲区“ ”不同。


测试表明,就我而言,它永远不是新缓冲区,并且始终为先前缓冲区定义变量。因此,我尝试找出如何使用<afile><abuf>设置缓冲区范围的变量。


编辑:
从上面的最小示例来看,问题可能还不清楚。设置此变量还有其他条件。因此,并非将要输入的每个缓冲区都获得此变量(因此我能够区分它们)。


编辑2:
因为@DoktorOSwaldo需要更多上下文。
我经常使用预览窗口显示标签等。不幸的是,所有显示的缓冲区都被添加到缓冲区列表中,并且(理论上)浪费了内存的使用。因此,简单的想法是定义一个自动命令,该命令会影响预览窗口中新打开的缓冲区。它必须是新的,因为期望用户自己使用的缓冲区已经打开。如果预览窗口中的缓冲区切换,这些缓冲区将获得不监听的本地选项(setlocal nobuflisted),应将其清除。
对于工作流情况,尚未打开的缓冲区会在预览窗口中打开,并导致某些情况,用户现在希望编辑该缓冲区并在其他窗口中打开它。如果发生这种情况,我必须将缓冲区设置为再次列出,并且如果不可见就不要擦除。简单检查缓冲区是否已列出的原因,然后也会由许多特殊的缓冲区触发,例如文件浏览器或标签查看器...因此,简单的解决方案应该是将本地变量设置为缓冲区加载到预览窗口中。然后,如果此缓冲区在此窗口之外加载,则可以通过此局部变量对其进行标识。
一些代码行的想法:

augroup PreviewWindow
   autocmd!
   autocmd BufAdd * if &previewwindow | setlocal nobuflisted |
           \ setlocal bufhidden = 'wipe' | let b:preview = v:true | endif

   autocmd BufEnter * if ! &previewwindow && exists('b:preview') &&
           \ b:preview | setlocal buflisted | setlocal bufhidden = '' |
           \ let b:preview = v:false | endif
augroup END




最终解决方案:
这是我的最终实现(现在似乎可以正常运行),通过使用一个标志将两个事件串联在一起。

augroup PreviewWindow
  autocmd!

  " Global flag for event composition, if a new buffer has been added into the preview window.
  let g:new_preview = 0

  " -> a buffer is shown in the preview window, that does not exits so far
  " In this case the the buffer is not already loaded and setting local variables does not work.
  " Set a global flag that mark this event to handle it later on when the buffer is loaded.
  autocmd BufAdd * nested if &previewwindow |
        \ let g:new_preview = v:true |
        \ endif

  " -> event that should follow after a (new) buffer has entered to the preview window
  " Check if the global flag has been set, that this is a new preview buffer.
  " The buffer is now available and local settings and variables can be defined.
  " Make sure the buffer gets cleared after it loose its window.
  " Set a buffer variable to mark it for further events.
  autocmd BufWinEnter * nested if &previewwindow && g:new_preview |
    \ let g:new_preview = v:false |
    \ setlocal nobuflisted |
    \ setlocal bufhidden=wipe |
    \ let b:previewonly = v:true |
    \ endif

  " -> the buffer in the preview window will be opened anywhere else
  " In case a buffer is entered, that has the buffer variable to be a 'previewony ' buffer,
  " it will be remove from there, added to the buffer list again and will not
  " be deleted when not displayed anymore.
  autocmd BufEnter * nested 
     \ try |
     \   if b:previewonly |
     \     unlet b:previewonly |
     \     setlocal buflisted |
     \     setlocal bufhidden= |
     \   endif |
     \ catch |
     \ endtry

augroup END



更多背景
由于某些人对于为什么要实现此行为感到困惑,如编辑2中所述,我想对此进行更详尽的解释。也许事实证明我是错的,或者只是一个特别的案例。因此,让我们开始吧:
假设您正在处理三个文件
档案A:

include <File B> as B
include <File C> as C

function main() {
  call B.foo()
  call B.bar()
}


档案B:

function foo() {
  return "foo"
}


文件C:

function bar() {
  return "bar"
}


因此,假设我们还有一些工具可以为项目中的每个功能(例如gutentags)生成一个标签。
没想到下面的窗口结构,是什么使得谈论它变得更加容易。
+ ------------------------------------------------- -------------- +
| |
|预览预览
+ ------------------------------ + ------------------ ------------- +
| | |
|档案A文件B
| | |
+ ------------------------------ + ------------------ ------------- +

1.案例
假设使用文件A在左侧窗口中工作。在foo函数调用上移动光标,然后在预览窗口中打开光标标签下的单词。由此,文件B显示在预览窗口中,但仍显示在右侧窗口中。对于这种情况,我不想在预览窗口中为缓冲区设置任何属性,因为这会影响我正在积极处理的缓冲区。因此,我的自动命令不应用在预览窗口中打开的新缓冲区。

2.案例
继续并对bar函数执行相同的操作。因此,将在新缓冲区中打开文件C,该缓冲区将显示在预览窗口中。现在,我想将我的属性应用于此缓冲区。因为文件C的缓冲区不应该在列表中,所以使用bnbp切换缓冲区不会跳转到该缓冲区。此外,我希望该缓冲区在不显示在预览窗口中时立即删除(实际上,在预览窗口中打开其他内容,例如另一个文件中的另一个标签)。这是第二种情况。

3.案例
现在的最后一种情况是,如果我使用文件C打开新缓冲区以预览标签并随后确定(它在预览窗口中显示),则必须调整功能bar。因此,我手动打开了文件C(在新的拆分中/在文件A / ...的窗口中)。现在,以前隐藏的(不再显示时应删除)将得到我正在处理的“活动”缓冲区。因此,我想决定何时保存此缓冲区,或者关闭或隐藏或...。因此,我必须删除之前添加到该缓冲区的所有属性。

另外,我必须承诺使用CursorHold事件尝试在光标下方将当前单词作为预览窗口中的标签打开。这是Vims文档/帮助本身的建议,节省了时间,因为它使查找变得更快,并且只有在我停止工作时才生效(例如,考虑当前使用的此函数/对象)。

希望这使我的观点更加清楚。

最佳答案

通常,您可以使用expand()将提到的特殊<afile> / <abuf>转换为缓冲区名称/编号。 setbufvar()函数可以访问其他缓冲区中的变量。结合起来,这样的事情看起来像是一种可能的方法:

autocmd BufAdd * call setbufvar(expand('<abuf>'), 'foo', 1)


不幸的是,我得到E94: No matching buffer for 16;显然,当BufAdd触发时,尚未为缓冲区变量设置数据结构。

备择方案

至少,您获得了缓冲区号,并且可以将其用作(全局)字典中的键来存储您的标志:

let g:foo = {} " Maps buffer numbers to boolean flags
autocmd BufAdd * let g:foo[expand('<abuf>')] = 1

" To check buffer "nr":
if get(g:foo, nr, 0) ...

关于vim - Vim-在自动命令上定义缓冲区变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49492787/

相关文章:

vim - 打开文件类型还是关闭文件类型?

vim - 'cs' 命令在 vim 中有什么作用,为什么我不能将它映射为做其他事情?

javascript - vim格式化JS错误

vim - Quickfix 列表,如何添加和删除条目

r - 如何在 vim 中使用模板

ios - clang_complete : Vim autocompletion for iOS

vim - 如何使用 Vim 查看带颜色的 Rails 日志

Vim 语法隐藏密码

Vim:在空行上进入插入模式时智能缩进?

sql - 如何将视觉上选择的文本通过管道传输到 UNIX 命令并将输出附加到 Vim 中的当前缓冲区