根据垂直分割的数量自动调整vim gui的大小

时间:2013-08-07 12:05:28

标签: events vim buffer

我正在为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 - 类似的事件,保证在窗口被销毁/删除后执行?

让我的插件使用映射是微不足道的,但是我无法使用:only:close之类的ex命令使其可靠地工作。

2 个答案:

答案 0 :(得分:1)

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

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

更新问题后编辑

我认为没有办法拦截你所描述的角落案例。特别是:only可能很棘手。我只能建议在CursorHoldCursorMoved上使用其他autocmds解决此问题。这样,不正确的状态只会持续很短的时间。

答案 1 :(得分:1)

我找到了一个似乎运作良好的解决方案。首先,我重写了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

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

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>

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