Angenommen, ich habe ein beliebiges Layout von Splits in vim.
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
Gibt es eine Möglichkeit, one
und two
zu tauschen und dasselbe Layout beizubehalten? In diesem Beispiel ist es einfach, aber ich suche nach einer Lösung, die für komplexere Layouts hilfreich ist.
Ich denke ich sollte klarer sein. Mein vorheriges Beispiel war eine Vereinfachung des tatsächlichen Anwendungsfalls. Mit einer tatsächlichen Instanz:
Wie könnte ich zwei dieser Splits austauschen und dabei das gleiche Layout beibehalten?
Ich habe die Lösung von sgriffin in ein Vim-Plugin gesteckt, das Sie problemlos installieren können! Installieren Sie es mit Ihrem bevorzugten Plugin-Manager und probieren Sie es aus: WindowSwap.vim
Ein bisschen zu spät zum Post, stieß jedoch auf die Suche nach etwas anderem. Ich habe vor einiger Zeit zwei Funktionen geschrieben, um ein Fenster zu markieren und Puffer zwischen den Fenstern auszutauschen. Dies scheint das zu sein, wonach Sie fragen.
Fügen Sie diese einfach in Ihre .vimrc ein und ordnen Sie die Funktionen so zu, wie Sie es für richtig halten:
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>
Um zu verwenden (vorausgesetzt, Ihr Mapleader ist auf\gesetzt), würden Sie:
Voila! Tauschen Sie die Puffer aus, ohne Ihr Fensterlayout zu beeinträchtigen!
Beginnen Sie damit:
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
Machen Sie 'drei' zum aktiven Fenster und geben Sie den Befehl aus ctrl+wJ. Dadurch wird das aktuelle Fenster so verschoben, dass es den unteren Bildschirmrand ausfüllt.
____________________
| one | two |
| | |
|___________|______|
| three |
| |
|__________________|
Machen Sie nun entweder 'Eins' oder 'Zwei' zum aktiven Fenster und geben Sie den Befehl aus ctrl+wr. Dies 'dreht' die Fenster in der aktuellen Zeile und lässt Sie mit:
____________________
| two | one |
| | |
|___________|______|
| three |
| |
|__________________|
Machen Sie nun 'zwei' zum aktiven Fenster und geben Sie den Befehl aus ctrl+wH. Dadurch wird das aktuelle Fenster so verschoben, dass es den linken Bildschirmrand ausfüllt.
____________________
| two | one |
| | |
| |______|
| | three|
| | |
|___________|______|
Wie Sie sehen können, ist das Manöver ein bisschen mischen. Mit 3 Fenstern ist es ein bisschen wie eines dieser Puzzlespiele. Ich empfehle nicht, dies zu versuchen, wenn Sie 4 oder mehr Fenster haben - Sie sollten diese besser schließen, als sie an den gewünschten Positionen wieder zu öffnen.
Ich habe einen Screencast gemacht, der zeigt wie man mit geteilten Fenstern in Vim arbeitet .
Schau dir :h ctrl-w_ctrl-x
und/oder :h ctrl-w_ctrl-r
an. Mit diesen Befehlen können Sie Fenster im aktuellen Layout austauschen oder drehen.
Bearbeiten: Eigentlich funktioniert das in dieser Situation nicht, da nur die aktuelle Spalte oder Zeile ausgetauscht wird. Sie können stattdessen zu jedem der Fenster gehen und den Zielpuffer auswählen, aber das ist ziemlich ausführlich.
Randys correct, CTRL-W x
möchte Fenster nicht austauschen, die sich nicht in derselben Spalte/Zeile befinden.
Ich habe festgestellt, dass die CTRL-W HJKL
-Tasten bei der Bearbeitung von Fenstern am nützlichsten sind. Sie zwingen Ihr aktuelles Fenster aus seiner aktuellen Position heraus und weisen es an, den gesamten Rand zu belegen, der durch die Richtung der gedrückten Taste angegeben wird. Siehe :help window-moving
für weitere Details.
Für Ihr Beispiel oben, wenn Sie in Fenster "Eins" beginnen, ist dies das, was Sie möchten:
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
Zur Vereinfachung können Sie die benötigten Sequenzen Tastenzuordnungen zuordnen (siehe :help mapping
).
Ich habe eine etwas verbesserte Version von sgriffins Lösung. Sie können Fenster austauschen, ohne zwei Befehle zu verwenden, sondern mit intuitiven HJKL-Befehlen.
So geht es also:
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>
Versuchen Sie, Ihr Fenster mit Hilfe von HJKL im normalen Knoten zu verschieben. Es ist wirklich cool :)
Wenn Sie schwer auf @ sgriffins Antwort aufbauen, kommen Sie noch näher an das, was Sie wollen:
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>
Bitte lassen Sie mich wissen, wenn das Verhalten nicht Ihren Erwartungen entspricht.
Der folgende Ansatz kann nützlich sein, wenn Funktionen aus irgendeinem Grund nicht verfügbar sind (z. B. ist dies nicht Ihr vim).
Verwenden Sie den Befehl :buffers
, um die IDs von geöffneten Puffern herauszufinden, navigieren Sie zum gewünschten Fenster und verwenden Sie den Befehl :b 5
, um einen Puffer zu öffnen (in diesem Fall Puffer Nummer 5). Zweimal wiederholen, und der Inhalt der Fenster wird ausgetauscht.
Ich habe diese Methode nach mehreren Versuchen "erfunden", ctrl-w-something
-Sequenzen auch für sehr einfache Layouts wie Eins-Zwei-Drei in der ursprünglichen Frage zu speichern.
Basierend auf der Lösung von sgriffin gehen Sie zu dem Fenster, das Sie austauschen möchten, drücken Sie CTRL-w m
, gehen Sie zu dem Fenster, mit dem Sie wechseln möchten, und drücken Sie erneut CTRL-w m
.
CTRL-w m
ist eine schlechte Erinnerungswahl. Wenn also jemand eine bessere findet, bearbeiten Sie dies bitte.
Außerdem möchte ich eine Rückmeldung aus dem Skript erhalten, das "Fenster markiert ist. Bitte wiederholen", jedoch als vimscript noob. Ich weiß nicht, wie das geht.
Alles in allem funktioniert das Skript gut
" <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>
Alle obigen Antworten sind großartig. Leider funktionieren diese Lösungen nicht gut in Kombination mit QuickFix- oder LocationList-Fenstern (ich habe dieses Problem ausgeführt, als ich versuchte, den Ale-Fehlermeldungenpuffer dazu zu bringen, damit zu arbeiten).
Daher habe ich eine zusätzliche Codezeile hinzugefügt, um alle diese Fenster zu schließen, bevor der Swap ausgeführt wird.
exe ':windo if &buftype == "quickfix" || &buftype == "locationlist" | lclose | endif'
Der gesamte Code sieht aus wie:
" 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>
Credits für die Swap-Funktion an Brandon Orther
Der Grund, warum die Auslagerungsfunktionen nicht ordnungsgemäß funktionieren, ohne zuerst alle QuickFix- (QF) und LocationList (LL) -Fenster zu entfernen, ist, dass, wenn der übergeordnete Benutzer des QF/LL-Puffers den get versteckt (und nirgendwo in einem Fenster angezeigt), der QF angezeigt wird/Das damit verbundene LL-Fenster wird entfernt. Dies ist an sich kein Problem, aber wenn das Fenster ausgeblendet wird, werden alle Fensternummern neu zugewiesen und der Swap ist durcheinander, da die gespeicherte Nummer des ersten markierten Fensters (möglicherweise) nicht mehr existiert.
Erste Fenstermarke
____________________
| one | -> winnr = 1 marked first g:markedWinNum=1
| | -> bufnr = 1
|__________________|
| two (QF window | -> winnr = 2
| coupled to one |
|__________________|
| three | -> winnr = 3
| | -> bufnr = 2
|__________________|
Zweite Fenstermarke
____________________
| 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
|__________________|
Erster Pufferschalter, Fenster eins wird mit dem Puffer von Fenster drei gefüllt. Das QF-Fenster wird daher entfernt, da es kein übergeordnetes Fenster mehr hat. Dadurch werden die Fensternummern neu angeordnet. Beachten Sie, dass curNum (die Nummer des zweiten ausgewählten Fensters) auf ein Fenster zeigt, das nicht mehr vorhanden ist.
____________________
| three | -> winnr = 1 g:markedWinNum=1
| | -> bufnr = 2
|__________________|
| three | -> winnr = 2 curNum=3
| | -> bufnr = 2 curBuf=2
|__________________|
Beim Umschalten des zweiten Puffers wird also versucht, das curNum-Fenster auszuwählen, das nicht mehr vorhanden ist. Es erstellt es also und wechselt den Puffer, wodurch ein unerwünschtes Fenster geöffnet bleibt.
____________________
| three | -> winnr = 1 g:markedWinNum=1
| | -> bufnr = 2
|__________________|
| three | -> winnr = 2
| | -> bufnr = 2
|__________________|
| one | -> winnr = 3 curNum=3
| | -> bufnr = 1 curBuf=2
|__________________|
Wirklich cool, aber mein Vorschlag für das Mapping ist, ^ W ^ J anstelle von J zu verwenden (weil alle HJKL bereits Bedeutungen haben), und außerdem würde ich in den neuen Puffer ziehen, weil man das mal will Um sich zu vertauschen, möchten Sie möglicherweise nicht den Puffer bearbeiten, in dem Sie sich bereits befinden. Hier geht:
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>
Ein ähnlicher Ansatz für das Markieren von Fenstern und das Wechseln des Puffers, aber Sie können den letzten Wechsel auch wiederverwenden.
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>