Vimに任意の分割レイアウトがあると仮定します。
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
one
とtwo
を交換して同じレイアウトを維持する方法はありますか?この例では簡単ですが、より複雑なレイアウトに役立つソリューションを探しています。
もっと明確にすべきだと思う。私の前の例は、実際のユースケースの単純化でした。実際のインスタンスの場合:
同じレイアウトを維持しながら、これらのスプリットの2つをどのように交換できますか?
簡単にインストールできるVimプラグインにsgriffinのソリューションを追加しました!お気に入りのプラグインマネージャーでインストールして、試してみてください: WindowSwap.vim
投稿に少し遅れましたが、何か他のものを探していることに出くわしました。ウィンドウをマークし、ウィンドウ間でバッファを交換するために、しばらく前に2つの関数を書きました。これはあなたが求めているもののようです。
これらを.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>
(マップリーダーが\に設定されていると仮定して)使用するには:
出来上がり!ウィンドウレイアウトを台無しにすることなく、バッファを交換します。
これから始めます:
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
「3」をアクティブウィンドウにし、コマンドを発行します ctrl+wJ。これにより、現在のウィンドウが移動して画面の下部に表示され、次のようになります。
____________________
| one | two |
| | |
|___________|______|
| three |
| |
|__________________|
「1」または「2」のいずれかをアクティブウィンドウにして、コマンドを発行します ctrl+wr。これにより、現在の行のウィンドウが「回転」し、次のようになります。
____________________
| two | one |
| | |
|___________|______|
| three |
| |
|__________________|
ここで「2」をアクティブウィンドウにして、コマンドを発行します ctrl+wH。これにより、現在のウィンドウが画面の左いっぱいに移動し、次のようになります。
____________________
| two | one |
| | |
| |______|
| | three|
| | |
|___________|______|
ご覧のとおり、この操作はちょっとしたシャッフルです。 3つのウィンドウがあるため、「タイルゲーム」パズルの1つに少し似ています。 4つ以上のウィンドウがある場合は、これを試してみることはお勧めしません。ウィンドウを閉じてから、目的の位置で再度開くことをお勧めします。
Vimで分割ウィンドウを操作する方法 を示すスクリーンキャストを作成しました。
:h ctrl-w_ctrl-x
および/または:h ctrl-w_ctrl-r
をご覧ください。これらのコマンドを使用すると、現在のレイアウトでウィンドウを交換または回転できます。
編集:実際、これは現在の列または行でのみスワップするため、この状況では機能しません。代わりに、各ウィンドウに移動してターゲットバッファを選択することもできますが、これはかなり冗長です。
Randy's は、CTRL-W x
が同じ列/行にないウィンドウをスワップしたくないという点で正しいです。
CTRL-W HJKL
キーは、ウィンドウを操作するときに最も役立つことがわかりました。現在のウィンドウを強制的に現在の場所から移動させ、押したキーの方向によって示されるEdge全体を占有するように指示します。詳細については、 :help window-moving
を参照してください。
上記の例では、ウィンドウ「one」で開始すると、これはあなたが望むことをします:
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
を参照)。
私はスグリフィンのソリューションからわずかに強化されたバージョンを持っています、あなたは2つのコマンドを使用せずに、直感的な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> <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>
通常のノードで大文字のHJKLを使用してウィンドウを移動してみてください。本当にクールです:)
@ -sgriffinの答えにheavilyを構築すると、あなたが求めているものにさらに近いものがあります:
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)を開きます。 2回繰り返して、ウィンドウの内容を交換します。
私は、元の質問の1〜2〜3のような非常に単純なレイアウトであっても、ctrl-w-something
シーケンスを数回記憶しようと試みた後、この方法を「発明」しました。
また、sgriffinのソリューションに基づいて、交換するウィンドウに移動し、CTRL-w m
を押し、交換したいウィンドウに移動して、CTRL-w m
をもう一度押します。
CTRL-w m
はニーモニックの選択肢としては適切ではないため、誰かがより良いニーモニックを選択した場合は、これを編集してください。
また、スクリプトから別名「ウィンドウにマークが付いています。ターゲット上で繰り返してください」からフィードバックを受け取りたいのですが、vimscript noobであるため、その方法はわかりません。
とは言っても、スクリプトはそのままでうまく機能します
" <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>
上記の答えはすべて素晴らしいです、残念ながら、これらのソリューションはQuickFixまたはLocationListウィンドウと組み合わせてうまく機能しません(これでAleエラーメッセージバッファーを取得しようとしてこの問題を実行しました)。
そのため、スワップを実行する前にこれらのすべてのウィンドウを閉じるコードの追加行を追加しました。
exe ':windo if &buftype == "quickfix" || &buftype == "locationlist" | lclose | endif'
合計コードは次のようになります。
" Making swapping windows easy
function! SwapWindowBuffers()
exe ':windo if &buftype == "quickfix" || &buftype == "locationlist" | lclose | endif'
if !exists("g:markedWinNum")
" set window marked for swap
let g:markedWinNum = winnr()
:echo "window marked for swap"
else
" mark destination
let curNum = winnr()
let curBuf = bufnr( "%" )
if g:markedWinNum == curNum
:echo "window unmarked for swap"
else
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
:echo "windows swapped"
endif
" unset window marked for swap
unlet g:markedWinNum
endif
endfunction
nmap <silent> <leader>mw :call SwapWindowBuffers()<CR>
Brandon Ortherへのスワップ関数のクレジット
最初にすべてのQuickFix(QF)ウィンドウとLocationList(LL)ウィンドウを削除しないとスワップ関数が適切に機能しない理由は、QF/LLの親がgetを非表示(ウィンドウのどこにも表示されない)にバッファリングすると、QF結合された/ LLウィンドウは削除されます。これ自体は問題ではありませんが、ウィンドウが非表示になると、すべてのウィンドウ番号が再割り当てされ、最初にマークされたウィンドウの保存された番号が(潜在的に)もう存在しないため、スワップがめちゃくちゃになります。
最初のウィンドウマーク
____________________
| one | -> winnr = 1 marked first g:markedWinNum=1
| | -> bufnr = 1
|__________________|
| two (QF window | -> winnr = 2
| coupled to one |
|__________________|
| three | -> winnr = 3
| | -> bufnr = 2
|__________________|
2番目のウィンドウマーク
____________________
| one | -> winnr = 1 g:markedWinNum=1
| | -> bufnr = 1
|__________________|
| two (QF window | -> winnr = 2
| coupled to one) |
|__________________|
| three | -> winnr = 3 marked second curNum=3
| | -> bufnr = 2 curBuf=2
|__________________|
最初のバッファ切り替え、ウィンドウ1はウィンドウ3のバッファで満たされます。したがって、親ウィンドウがないため、QFウィンドウは削除されます。これにより、ウィンドウ番号が再配置されます。 curNum(2番目に選択されたウィンドウの数)は、もう存在しないウィンドウを指していることに注意してください。
____________________
| three | -> winnr = 1 g:markedWinNum=1
| | -> bufnr = 2
|__________________|
| three | -> winnr = 2 curNum=3
| | -> bufnr = 2 curBuf=2
|__________________|
したがって、2番目のバッファーを切り替えると、現在存在しないcurNumウィンドウを選択しようとします。したがって、それを作成し、バッファを切り替えて、1つの不要なウィンドウをまだ開いたままにします。
____________________
| three | -> winnr = 1 g:markedWinNum=1
| | -> bufnr = 2
|__________________|
| three | -> winnr = 2
| | -> bufnr = 2
|__________________|
| one | -> winnr = 3 curNum=3
| | -> bufnr = 1 curBuf=2
|__________________|
本当にクールですが、マッピングの私の提案は、Jの代わりに^ W ^ Jを使用することです(HJKLのすべてにすでに意味があるため)。さらに、in新しいバッファースワップしたいときは、おそらく既にバッファにあるものの編集を続けたくないでしょう。ここに行く:
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>
同様のmark-window-then-swap-bufferアプローチですが、最後のスワッピングも再利用できます。
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>