如何在vim中交换两个打开文件(在拆分中)的位置?
本文翻译自:How can I swap positions of two open files (in splits) in vim?
Assume I've got some arbitrary layout of splits in vim. 假设我在vim中有一些任意分割布局。
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
Is there a way to swap one
and two
and maintain the same layout? 有没有办法交换one
和two
并保持相同的布局? It's simple in this example, but I'm looking for a solution that will help for more complex layouts. 在这个例子中它很简单,但我正在寻找一种有助于更复杂布局的解决方案。
UPDATE: 更新:
I guess I should be more clear. 我想我应该更清楚。 My previous example was a simplification of the actual use-case. 我之前的例子是对实际用例的简化。 With an actual instance: 使用实际的实例:
How could I swap any two of those splits, maintaining the same layout? 我怎么能交换任何两个分裂,保持相同的布局?
Update! 更新! 3+ years later... 3年多以后......
I put sgriffin's solution in a Vim plugin you can install with ease! 我把sgriffin的解决方案放在你可以轻松安装的Vim插件中! Install it with your favorite plugin manager and give it a try: WindowSwap.vim 使用您喜欢的插件管理器安装它并尝试一下: WindowSwap.vim
#1楼
参考:https://stackoom.com/question/AqzY/如何在vim中交换两个打开文件-在拆分中-的位置
#2楼
Building heavily on @sgriffin's answer, here's something even closer to what you're asking for: 在@ 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>
Please let me know if the behavior doesn't match your expectations. 如果行为与您的期望不符,请告诉我。
#3楼
The following approach may be convenient if functions are not available for some reason (fe it's not your vim). 如果功能由于某种原因不可用,则以下方法可能很方便(因为它不是你的vim)。
Use :buffers
command to find out id's of open buffers, navigate to desired window and use command like :b 5
to open a buffer (buffer number 5 in this case). 使用:buffers
命令查找打开缓冲区的id,导航到所需的窗口并使用如下命令:b 5
打开缓冲区(在这种情况下为缓冲区编号5)。 Repeate two times and contents of windows are swapped. 重复两次,交换窗口内容。
I "invented" this method after several attempts to memorise ctrl-w-something
sequences even for very simple layouts like one-two-three in original question. 经过多次尝试记忆ctrl-w-something
序列后,我“发明了”这种方法,即使对于非常简单的布局,如原始问题中的一两三。
#4楼
I have a slightly enhanced version from sgriffin's solution, you can swap windows without using two commands, but with intuitive HJKL commands. 我从sgriffin的解决方案中获得了一个略微增强的版本,您可以在不使用两个命令的情况下交换窗口,但使用直观的HJKL命令。
So here is how it goes: 所以这是怎么回事:
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> <C-w>h :call DoWindowSwap()<CR>
nnoremap J :call MarkWindowSwap()<CR> <C-w>j :call DoWindowSwap()<CR>
nnoremap K :call MarkWindowSwap()<CR> <C-w>k :call DoWindowSwap()<CR>
nnoremap L :call MarkWindowSwap()<CR> <C-w>l :call DoWindowSwap()<CR>
Try to move your window by using capital HJKL in normal node, it is really cool :) 尝试在正常节点中使用大写HJKL移动窗口,这真的很酷:)
#5楼
Really cool, but my proposal for the mapping is to use ^W^J instead of J (because all of HJKL already have meanings), plus also I'd pull in the new buffer, because by the time you want to swap around you probably don't want to continue editing the buffer you are already on. 真的很酷,但我对映射的建议是使用^ W ^ J而不是J(因为所有的HJKL已经有意义),而且我还会拉入新缓冲区,因为当你想要在你周围交换时可能不想继续编辑你已经在的缓冲区。 Here goes: 开始:
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>
#6楼
Also based on sgriffin's solution, go to the window you want to swap, press CTRL-w m
, go to the window you want to swap with and press CTRL-w m
again. 同样基于sgriffin的解决方案,转到要交换的窗口,按CTRL-w m
,转到要交换的窗口,然后再次按CTRL-w m
。
CTRL-w m
is a poor mnemonic choice, so if anybody comes up with a better one, please edit this. CTRL-w m
是一个很差的助记符选择,所以如果有人想出一个更好的助记符,请编辑它。
Also, I'd like to receive a feedback from the script aka "Window marked. Please repeat on target", however being a vimscript noob, I do not know how to do that. 此外,我想收到脚本的反馈,即“标记窗口。请重复目标”,但是作为vimscript noob,我不知道该怎么做。
All that said, the script works well as is 总而言之,脚本运行良好
" <CTRL>-w m : mark first window
" <CTRL>-w m : 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 <C-w>m :call WindowSwapping()<CR>