假设我在vim中有一些任意的分割布局。

____________________
| one       | two  |
|           |      |
|           |______|
|           | three|
|           |      |
|___________|______|

有没有办法交换一个和两个,并保持相同的布局?在这个例子中很简单,但我正在寻找一个解决方案,将有助于更复杂的布局。

更新:

我想我应该说清楚点。我前面的例子是对实际用例的简化。有一个实际的例子:

我怎么能交换任何两个分割,保持相同的布局?

更新!3年多后……

我把sgriffin的解决方案放在一个Vim插件中,你可以轻松安装!用你最喜欢的插件管理器安装它,并尝试一下:WindowSwap.vim


当前回答

以@sgriffin的回答为基础,这里有一些更接近你要求的东西:

function! MarkWindow()
        let g:markedWinNum = winnr()
endfunction

function! SwapBufferWithMarkedWindow()
        " Capture current window and buffer
        let curWinNum = winnr()
        let curBufNum = bufnr("%")

        " Switch to marked window, mark buffer, and open current buffer
        execute g:markedWinNum . "wincmd w"
        let markedBufNum = bufnr("%")
        execute "hide buf" curBufNum

        " Switch back to current window and open marked buffer
        execute curWinNum . "wincmd w"
        execute "hide buf" markedBufNum
endfunction

function! CloseMarkedWindow()
        " Capture current window
        let curWinNum = winnr()

        " Switch to marked window and close it, then switch back to current window
        execute g:markedWinNum . "wincmd w"
        execute "hide close"
        execute "wincmd p"
endfunction

function! MoveWindowLeft()
        call MarkWindow()
        execute "wincmd h"
        if winnr() == g:markedWinNum
                execute "wincmd H"
        else
                let g:markedWinNum += 1
                execute "wincmd s"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd h"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

function! MoveWindowDown()
        call MarkWindow()
        execute "wincmd j"
        if winnr() == g:markedWinNum
                execute "wincmd J"
        else
                execute "wincmd v"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd j"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

function! MoveWindowUp()
        call MarkWindow()
        execute "wincmd k"
        if winnr() == g:markedWinNum
                execute "wincmd K"
        else
                let g:markedWinNum += 1
                execute "wincmd v"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd k"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

function! MoveWindowRight()
        call MarkWindow()
        execute "wincmd l"
        if winnr() == g:markedWinNum
                execute "wincmd L"
        else
                execute "wincmd s"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd l"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

nnoremap <silent> <Leader>wm :call MarkWindow()<CR>
nnoremap <silent> <Leader>ws :call SwapBufferWithMarkedWindow()<CR>
nnoremap <silent> <Leader>wh :call MoveWindowLeft()<CR>
nnoremap <silent> <Leader>wj :call MoveWindowDown()<CR>
nnoremap <silent> <Leader>wk :call MoveWindowUp()<CR>
nnoremap <silent> <Leader>wl :call MoveWindowRight()<CR>

如果你的行为不符合你的期望,请告诉我。

其他回答

真的很酷,但是我对映射的建议是使用^W^J而不是J(因为所有的H J K L已经有意义了),另外我还会引入新的缓冲区,因为当你想要交换的时候,你可能不想继续编辑你已经在的缓冲区。是:

function! MarkSwapAway()
    " marked window number
    let g:markedOldWinNum = winnr()
    let g:markedOldBufNum = bufnr("%")
endfunction
function! DoWindowToss()
    let newWinNum = winnr()
    let newBufNum = bufnr("%")
    " Switch focus to marked window
    exe g:markedOldWinNum . "wincmd w"
    " Load current buffer on marked window
    exe 'hide buf' newBufNum
    " Switch focus to current window
    exe newWinNum . "wincmd w"
    " Load marked buffer on current window
    exe 'hide buf' g:markedOldBufNum
    " …and come back to the new one
    exe g:markedOldWinNum . "wincmd w"
endfunction
nnoremap <C-w><C-h> :call MarkSwapAway()<CR> <C-w>h :call DoWindowToss()<CR>
nnoremap <C-w><C-j> :call MarkSwapAway()<CR> <C-w>j :call DoWindowToss()<CR>
nnoremap <C-w><C-k> :call MarkSwapAway()<CR> <C-w>k :call DoWindowToss()<CR>
nnoremap <C-w><C-l> :call MarkSwapAway()<CR> <C-w>l :call DoWindowToss()<CR>

从这个开始:

____________________
| one       | two  |
|           |      |
|           |______|
|           | three|
|           |      |
|___________|______|

将“three”设置为活动窗口,然后发出命令ctrl+w j,这将移动当前窗口以填充屏幕底部,留给你:

____________________
| one       | two  |
|           |      |
|___________|______|
| three            |
|                  |
|__________________|

现在将'one'或'two'作为活动窗口,然后发出命令ctrl+w r。这将'旋转'当前行中的窗口,留下你:

____________________
| two       | one  |
|           |      |
|___________|______|
| three            |
|                  |
|__________________|

现在将“two”设置为活动窗口,并发出ctrl+w h命令,这将移动当前窗口以填充屏幕左侧,留下:

____________________
| two       | one  |
|           |      |
|           |______|
|           | three|
|           |      |
|___________|______|

如你所见,这个动作有点乱。它有3个窗口,有点像“瓷砖游戏”谜题。如果你有4个或更多的窗口,我不建议你尝试这个方法——你最好关闭它们,然后在需要的位置重新打开它们。

我做了一个视频演示如何在Vim中使用分割窗口。

有点晚了,但在寻找其他东西时看到了这个。我写了两个函数来标记一个窗口,然后在窗口之间交换缓冲区。这似乎就是你想要的。

只要把这些放在你的.vimrc中,然后映射你认为合适的函数:

function! MarkWindowSwap()
    let g:markedWinNum = winnr()
endfunction

function! DoWindowSwap()
    "Mark destination
    let curNum = winnr()
    let curBuf = bufnr( "%" )
    exe g:markedWinNum . "wincmd w"
    "Switch to source and shuffle dest->source
    let markedBuf = bufnr( "%" )
    "Hide and open so that we aren't prompted and keep history
    exe 'hide buf' curBuf
    "Switch to dest and shuffle source->dest
    exe curNum . "wincmd w"
    "Hide and open so that we aren't prompted and keep history
    exe 'hide buf' markedBuf 
endfunction

nmap <silent> <leader>mw :call MarkWindowSwap()<CR>
nmap <silent> <leader>pw :call DoWindowSwap()<CR>

要使用(假设您的mapleader设置为\),您将:

移动到窗口以标记交换通道 ctrl-w运动 类型\兆瓦 移动到要交换的窗口 \ pw型

瞧!交换缓冲区没有搞砸你的窗口布局!

以@sgriffin的回答为基础,这里有一些更接近你要求的东西:

function! MarkWindow()
        let g:markedWinNum = winnr()
endfunction

function! SwapBufferWithMarkedWindow()
        " Capture current window and buffer
        let curWinNum = winnr()
        let curBufNum = bufnr("%")

        " Switch to marked window, mark buffer, and open current buffer
        execute g:markedWinNum . "wincmd w"
        let markedBufNum = bufnr("%")
        execute "hide buf" curBufNum

        " Switch back to current window and open marked buffer
        execute curWinNum . "wincmd w"
        execute "hide buf" markedBufNum
endfunction

function! CloseMarkedWindow()
        " Capture current window
        let curWinNum = winnr()

        " Switch to marked window and close it, then switch back to current window
        execute g:markedWinNum . "wincmd w"
        execute "hide close"
        execute "wincmd p"
endfunction

function! MoveWindowLeft()
        call MarkWindow()
        execute "wincmd h"
        if winnr() == g:markedWinNum
                execute "wincmd H"
        else
                let g:markedWinNum += 1
                execute "wincmd s"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd h"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

function! MoveWindowDown()
        call MarkWindow()
        execute "wincmd j"
        if winnr() == g:markedWinNum
                execute "wincmd J"
        else
                execute "wincmd v"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd j"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

function! MoveWindowUp()
        call MarkWindow()
        execute "wincmd k"
        if winnr() == g:markedWinNum
                execute "wincmd K"
        else
                let g:markedWinNum += 1
                execute "wincmd v"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd k"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

function! MoveWindowRight()
        call MarkWindow()
        execute "wincmd l"
        if winnr() == g:markedWinNum
                execute "wincmd L"
        else
                execute "wincmd s"
                execute g:markedWinNum . "wincmd w"
                execute "wincmd l"
                call SwapBufferWithMarkedWindow()
                call CloseMarkedWindow()
        endif
endfunction

nnoremap <silent> <Leader>wm :call MarkWindow()<CR>
nnoremap <silent> <Leader>ws :call SwapBufferWithMarkedWindow()<CR>
nnoremap <silent> <Leader>wh :call MoveWindowLeft()<CR>
nnoremap <silent> <Leader>wj :call MoveWindowDown()<CR>
nnoremap <silent> <Leader>wk :call MoveWindowUp()<CR>
nnoremap <silent> <Leader>wl :call MoveWindowRight()<CR>

如果你的行为不符合你的期望,请告诉我。

类似于标记-窗口-然后交换-缓冲区的方法,但也允许您重用上次交换。

function! MarkWindowSwap()
    unlet! g:markedWin1
    unlet! g:markedWin2
    let g:markedWin1 = winnr()
endfunction

function! DoWindowSwap()
    if exists('g:markedWin1')
        if !exists('g:markedWin2')
            let g:markedWin2 = winnr()
        endif
        let l:curWin = winnr()
        let l:bufWin1 = winbufnr(g:markedWin1)
        let l:bufWin2 = winbufnr(g:markedWin2)
        exec g:markedWin2 . 'wincmd w'
        exec ':b '.l:bufWin1
        exec g:markedWin1 . 'wincmd w'
        exec ':b '.l:bufWin2
        exec l:curWin . 'wincmd w'
    endif
endfunction

nnoremap ,v :call DoWindowSwap()<CR>
nnoremap ,z :call MarkWindowSwap()<CR>