如何在vim中交换两个打开文件的位置(分割)?

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

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

有办法交换onetwo并保持相同的布局? 这个例子很简单,但我正在寻找一个解决scheme来帮助更复杂的布局。

更新:

我想我应该更清楚。 我之前的例子是对实际使用情况的简化。 用一个实际的例子: alt text

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

更新! 3年以上…

我把sgriffin的解决scheme放在一个Vim插件中,你可以轻松安装! 安装它与你最喜欢的插件pipe理器,并试试看: WindowSwap.vim

一个小演示

有点迟到的post,但遇到了这个寻找别的东西。 我写了两个函数来标记窗口,然后在窗口之间交换缓冲区。 这似乎是你所要求的。

只需掌握这些在你的.vimrc中,并映射你认为合适的function:

 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被设置为\),你将会:

  1. 移动到窗口,通过ctrl-w移动标记交换
  2. 键入\ mw
  3. 移到你想交换的窗口
  4. 键入\ pw

瞧! 交换缓冲区而不用拧你的窗口布局!

从这开始:

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

使'三'活动窗口,然后发出命令ctrl + w J。 这将移动当前窗口来填充屏幕的底部,留下:

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

现在使“one”或“two”为活动窗口,然后发出命令ctrl + w r 。 这会“旋转”当前行中的窗口,让您留下:

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

现在使'两'活动窗口,并发出命令CTRL + W H。 这会移动当前窗口以填充屏幕的左侧,并留下以下内容:

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

正如你所看到的,manouevre是一个有点shuffle。 有3个窗口,这有点像那些“瓦片游戏”谜题之一。 如果你有4个或更多的窗口,我不build议这样做 – 你最好closures它们,然后再打开它们在所需的位置。

我做了一个截屏video,演示如何在Vim中使用分割窗口 。

看看:h ctrl-w_ctrl-x和/或:h ctrl-w_ctrl-r 。 这些命令允许您在当前布局中交换或旋转窗口。

编辑:其实,这不会在这种情况下工作,因为它只会交换当前列或行。 你可以转到每个窗口并select目标缓冲区,但是这非常冗长。

兰迪正确的是, CTRL-W x不想交换不在同一列/行的窗口。

我发现CTRL-W HJKL键在操作窗口时非常有用。 他们将强制当前窗口移出当前位置,并告诉它占据您按下的按键方向所指示的整个边缘。 请参阅:help window-moving以获取更多详细信息。

对于上面的例子,如果你在窗口“一”开始,这是你想要的:

 CTRL-W K # moves window "one" to be topmost, # stacking "one", "two", "three" top to bottom CTRL-W j # moves cursor to window "two" CTRL-W H # moves window "two" to be leftmost, # leaving "one" and "three" split at right 

为了方便起见,您可以将所需的序列分配给键映射(请参阅:help mapping )。

我从sgriffin的解决scheme中有一个稍微增强的版本,可以在不使用两个命令的情况下交换窗口,但是使用直观的HJKL命令。

所以这是怎么回事:

 function! MarkWindowSwap() " marked window number let g:markedWinNum = winnr() let g:markedBufNum = bufnr("%") endfunction function! DoWindowSwap() let curWinNum = winnr() let curBufNum = bufnr("%") " Switch focus to marked window exe g:markedWinNum . "wincmd w" " Load current buffer on marked window exe 'hide buf' curBufNum " Switch focus to current window exe curWinNum . "wincmd w" " Load marked buffer on current window exe 'hide buf' g:markedBufNum endfunction nnoremap H :call MarkWindowSwap()<CR> <Cw>h :call DoWindowSwap()<CR> nnoremap J :call MarkWindowSwap()<CR> <Cw>j :call DoWindowSwap()<CR> nnoremap K :call MarkWindowSwap()<CR> <Cw>k :call DoWindowSwap()<CR> nnoremap L :call MarkWindowSwap()<CR> <Cw>l :call DoWindowSwap()<CR> 

尝试在正常节点中使用大写的HJKL来移动窗口,这真的很酷:)

严重依赖 @ 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> 

请让我知道,如果行为不符合您的期望。

如果函数由于某种原因而不可用(以下不是你的vim),下面的方法可能会很方便。

使用:buffers命令查找打开的缓冲区的ID,导航到所需的窗口并使用如下命令:b 5打开一个缓冲区(在这种情况下,缓冲区号为5)。 重复两次,窗口的内容被交换。

即使对于原始问题中的非常简单的布局,如“一二三”,我经过几次尝试记住ctrl-w-something序列后“发明”了这种方法。

真的很酷,但是我的提议是使用^ W ^ J而不是J(因为所有的HJKL已经有了意义),再加上我会把新的缓冲区放进去,因为当你想要在你周围交换的时候可能不想继续编辑已经在的缓冲区。 开始:

 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 <Cw><Ch> :call MarkSwapAway()<CR> <Cw>h :call DoWindowToss()<CR> nnoremap <Cw><Cj> :call MarkSwapAway()<CR> <Cw>j :call DoWindowToss()<CR> nnoremap <Cw><Ck> :call MarkSwapAway()<CR> <Cw>k :call DoWindowToss()<CR> nnoremap <Cw><Cl> :call MarkSwapAway()<CR> <Cw>l :call DoWindowToss()<CR> 

同样基于sgriffin的解决scheme,进入你想要交换的窗口,按下CTRL-w m ,进入你想要交换的窗口并再次按下CTRL-w m

CTRL-w m是一个不好的助记符select,所以如果有人提出更好的select,请编辑它。

另外,我想收到一个脚本的反馈,也就是“标记的窗口,请重复目标”,不过是一个vim脚本noob,我不知道该怎么做。

尽pipe如此,剧本运作良好

 " <CTRL>-wm : mark first window " <CTRL>-wm : swap with that window let s:markedWinNum = -1 function! MarkWindowSwap() let s:markedWinNum = winnr() endfunction function! DoWindowSwap() "Mark destination let curNum = winnr() let curBuf = bufnr( "%" ) exe s: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 function! WindowSwapping() if s:markedWinNum == -1 call MarkWindowSwap() else call DoWindowSwap() let s:markedWinNum = -1 endif endfunction nnoremap <Cw>m :call WindowSwapping()<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> 

你也可以使用像X-monad这样的平铺窗口pipe理器