layout - two - vim split vertical
¿Cómo puedo intercambiar posiciones de dos archivos abiertos(en splits) en vim? (12)
Supongamos que tengo un diseño arbitrario de splits en vim.
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
¿Hay alguna forma de intercambiar one
y two
y mantener el mismo diseño? Es simple en este ejemplo, pero estoy buscando una solución que ayude a diseños más complejos.
ACTUALIZAR:
Supongo que debería ser más claro. Mi ejemplo anterior fue una simplificación del caso de uso real. Con una instancia real:
¿Cómo podría intercambiar dos de esas divisiones, manteniendo el mismo diseño?
¡Actualizar! 3+ años después ...
¡Pongo la solución de sgriffin en un plugin Vim que puedes instalar fácilmente! Instálelo con su administrador de complementos favorito y pruébelo: WindowSwap.vim
A partir de esto:
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
Haga que ''tres'' sea la ventana activa, luego emita el comando ctrl + w J. Esto mueve la ventana actual para llenar la parte inferior de la pantalla, dejándole con:
____________________
| one | two |
| | |
|___________|______|
| three |
| |
|__________________|
Ahora haga que ''uno'' o ''dos'' sea la ventana activa, luego ejecute el comando ctrl + w r . Esto ''rota'' las ventanas en la fila actual, dejándote con:
____________________
| two | one |
| | |
|___________|______|
| three |
| |
|__________________|
Ahora haga ''dos'' la ventana activa, y ejecute el comando ctrl + w H. Esto mueve la ventana actual para llenar la parte izquierda de la pantalla, dejándole con:
____________________
| two | one |
| | |
| |______|
| | three|
| | |
|___________|______|
Como puede ver, la maniobra es un poco aleatoria. Con 3 ventanas, es un poco como uno de esos rompecabezas de "juegos de fichas". No recomiendo probar esto si tiene 4 o más ventanas. Será mejor que las cierre y las abra de nuevo en las posiciones deseadas.
Hice un screencast demostrando cómo trabajar con ventanas divididas en Vim .
Eche un vistazo a :h ctrl-w_ctrl-x
y / o :h ctrl-w_ctrl-r
. Estos comandos le permiten intercambiar o rotar ventanas en el diseño actual.
Edición: En realidad, esto no funcionará en esta situación porque solo se intercambiará en la columna o fila actual. En su lugar, podría ir a cada una de las ventanas y seleccionar el búfer de destino, pero eso es bastante detallado.
El siguiente enfoque puede ser conveniente si las funciones no están disponibles por algún motivo (si no es su vim).
Use el comando :buffers
para averiguar los ID de los buffers abiertos, navegue a la ventana deseada y use el comando como :b 5
para abrir un buffer (buffer 5 en este caso). Repetir dos veces y los contenidos de las ventanas se intercambian.
"Inventé" este método después de varios intentos de memorizar secuencias de ctrl-w-something
incluso para diseños muy simples como uno-dos-tres en la pregunta original.
Enfoque similar marca-ventana-luego-intercambio-búfer, pero también le permite reutilizar el último intercambio.
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>
Realmente genial, pero mi propuesta para el mapeo es usar ^ W ^ J en lugar de J (porque todos los HJKL ya tienen significados), además, también obtendré el nuevo búfer, porque para el momento en que quieras intercambiarte Probablemente no quiera continuar editando el búfer en el que se encuentra. Aquí va:
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>
Sobre la base de la respuesta de @ sgriffin, aquí hay algo aún más cercano a lo que estás pidiendo:
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>
Por favor, hágame saber si el comportamiento no coincide con sus expectativas.
También basado en la solución de sgriffin, vaya a la ventana que desea intercambiar, presione CTRL-w m
, vaya a la ventana con la que desea intercambiar y presione CTRL-w m
nuevamente.
CTRL-w m
es una opción mnemotécnica deficiente, por lo que si alguien encuentra una mejor, edítela.
Además, me gustaría recibir comentarios del script, también conocido como "Ventana marcada. Por favor, repita en target". Sin embargo, al ser un noob vimscript, no sé cómo hacerlo.
Todo lo dicho, el guión funciona bien como está
" <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>
También puedes usar un administrador de ventanas de mosaico como X-monad
Tengo una versión ligeramente mejorada de la solución de sgriffin, puedes cambiar ventanas sin usar dos comandos, pero con comandos intuitivos HJKL.
Así que aquí es cómo va:
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>
Intente mover su ventana usando HJKL de capital en un nodo normal, es realmente genial :)
Todas las respuestas anteriores son excelentes, desafortunadamente, estas soluciones no funcionan bien en combinación con las ventanas QuickFix o LocationList (corrí en este problema al intentar que el búfer de mensajes de error de Ale funcionara con esto).
Solución
Por lo tanto, agregué una línea de código adicional para cerrar todas estas ventanas antes de hacer el intercambio.
exe '':windo if &buftype == "quickfix" || &buftype == "locationlist" | lclose | endif''
El código total se ve como;
" 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>
Créditos para la función de intercambio a Brandon Orther
Por que se necesita
La razón por la que las funciones de intercambio no funcionan correctamente sin eliminar primero todas las ventanas de QuickFix (QF) y LocationList (LL) es porque si el principal del búfer QF / LL se oculta (y no se muestra en ninguna ventana), el QF Se quita la ventana / LL acoplada a ella. Esto no es un problema en sí mismo, pero cuando la ventana se oculta, todos los números de las ventanas se reasignan y el intercambio se desordena ya que el número guardado de la primera ventana marcada ya no existe (potencialmente).
Para poner esto en perspectiva:
Primera marca de ventana
____________________
| one | -> winnr = 1 marked first g:markedWinNum=1
| | -> bufnr = 1
|__________________|
| two (QF window | -> winnr = 2
| coupled to one |
|__________________|
| three | -> winnr = 3
| | -> bufnr = 2
|__________________|
Segunda marca de ventana
____________________
| 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
|__________________|
Primer interruptor de búfer, la ventana uno se llena con el búfer de la ventana tres. Por lo tanto, la ventana QF se elimina porque ya no tiene ninguna ventana principal. Esto reorganiza los números de las ventanas. Tenga en cuenta que curNum (el número de la segunda ventana seleccionada) apunta a una ventana que ya no existe.
____________________
| three | -> winnr = 1 g:markedWinNum=1
| | -> bufnr = 2
|__________________|
| three | -> winnr = 2 curNum=3
| | -> bufnr = 2 curBuf=2
|__________________|
Así que cuando se cambia el segundo búfer, intenta seleccionar la ventana de curNum, que ya no existe. Así que lo crea y cambia el búfer, lo que da como resultado que una ventana no deseada se abra aún.
____________________
| three | -> winnr = 1 g:markedWinNum=1
| | -> bufnr = 2
|__________________|
| three | -> winnr = 2
| | -> bufnr = 2
|__________________|
| one | -> winnr = 3 curNum=3
| | -> bufnr = 1 curBuf=2
|__________________|
Un poco tarde para el post, pero encontré esto buscando algo más. Hace un tiempo escribí dos funciones para marcar una ventana y luego intercambiar buffers entre ventanas. Esto parece ser lo que estás pidiendo.
Solo golpea estos en tu .vimrc y mapea las funciones como mejor te parezcan:
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>
Para usar (asumiendo que su mapleader está configurado en /) usted debería:
- Mover a la ventana para marcar para el intercambio a través del movimiento ctrl-w
- Escriba / mw
- Mueve a la ventana que quieres intercambiar.
- Tipo / pw
Voila! Intercambiar buffers sin estropear el diseño de su ventana!
Randy''s razón en que CTRL-W x
no quiere intercambiar ventanas que no estén en la misma columna / fila.
Descubrí que las CTRL-W HJKL
son más útiles al manipular ventanas. Forzarán su ventana actual fuera de su ubicación actual y le indicarán que ocupe todo el borde indicado por la dirección de la tecla que presiona. Ver :help window-moving
para :help window-moving
para más detalles.
Para su ejemplo anterior, si comienza en la ventana "uno", esto hace lo que quiere:
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
Para su comodidad, puede asignar las secuencias que necesita a las asignaciones de teclas (consulte :help mapping
).