2

我正在为 gvim 编写一个小插件,它会根据垂直分割的数量自动增加或减少 gui 的宽度。该插件的工作原理是这样的

if has("gui_running")
  augroup resize
    autocmd WinEnter * call <SID>ResizeSplits()
    autocmd WinLeave * call <SID>ResizeSplits()
    autocmd BufLeave * call <SID>ResizeSplits()
  augroup END
endif

ResizeSplits()是调整 gui 窗口大小的函数:

function! s:ResizeSplits()
  let l:count = 0
  windo   if winwidth(winnr()) < &columns | 
        \   let l:count += 1              |
        \ endif
  if l:count > 0
    let l:totwidth = l:count - 1 + l:count*80
  else
    let l:totwidth = 80
  endif
  if &columns != l:totwidth
    execute 'set co=' . l:totwidth
  endif
endfunction

该插件几乎可以按我的意愿工作,但并不完全。似乎BufLeave事件(和类似事件)有时会在窗口关闭之前执行。这是一个问题,例如当我做<c-w>o:only. 问题是该ResizeSplits功能不起作用,因为它仍然计算旧的窗口数量。

是否有另一个自动命令可用于检测窗口数量何时更改,或者BufLeave在窗口被销毁/删除后保证执行的类似事件?

让我的插件与映射一起工作是微不足道的,但我无法让它可靠地与 ex 命令(如:onlyand )一起工作:close

4

2 回答 2

2

我找到了一个似乎效果很好的解决方案。首先,我重写了ResizeSplits函数:

function! s:ResizeSplits()
  let l:curwin = winnr()
  let l:colwidth = 80 + &foldcolumn
  if &number
    let l:colwidth += &numberwidth
  endif

  let l:count = 0
  windo   if winwidth(winnr()) < &columns |
        \   let l:count += getwinvar(winnr(), 'count') |
        \ endif
  if l:count > 0
    let l:totwidth = l:count - 1 + l:count*l:colwidth
  else
    let l:totwidth = l:colwidth
  endif

  if &columns != l:totwidth
    silent! execute 'set co=' . l:totwidth
    silent! execute 'wincmd ='
  endif
  silent! execute l:curwin . 'wincmd w'
endfunction

重要的变化是我定义了一个w:count0 或 1 的变量。该函数与以下自动命令一起使用:

if has("gui_running")
  augroup vimrc_autocommands
    autocmd WinEnter    * let w:count = 1 | call <SID>ResizeSplits()
    autocmd BufEnter    * let w:count = 1 | call <SID>ResizeSplits()
    autocmd WinLeave    * call <SID>ResizeSplits()
    autocmd BufHidden   * let w:count = 0 | call <SID>ResizeSplits()
    autocmd BufWinLeave * let w:count = 0 | call <SID>ResizeSplits()
  augroup END
endif

这似乎在我尝试过的几乎所有情况下都有效。只有一种情况:only仍然<c-w>o不起作用:如果窗口具有相同的缓冲区。一个简单的映射可以解决<c-w>o

nnoremap <c-w>o <c-w>o:call <sid>ResizeSplits()<cr>

如果有人找到更好的解决方案,我当然会很高兴。

于 2013-08-07T14:31:57.807 回答
1

:close/没有确切的事件:quit;最接近的是BufWinLeave,但是当缓冲区在另一个缓冲区中仍然可见时不会触发。您可以将其与 结合使用BufLeave,但随后必须检查缓冲区是否实际上不再可见。

要仅处理未列出的缓冲区,您可以'buflisted'在执行的 autocmd 中添加条件检查。

问题更新后编辑

我认为没有办法拦截您描述的极端情况。特别是:only可能很棘手。我只能建议在CursorHold和上使用额外的自动命令来解决这个问题CursorMoved。这样,不正确的状态只会持续很短的时间。

于 2013-08-07T12:20:11.677 回答