layout - vertical - ¿Cómo puedo intercambiar posiciones de dos archivos abiertos(en splits) en vim?




vim tabs (8)

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 .

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


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.


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>

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


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:

  1. Mover a la ventana para marcar para el intercambio a través del movimiento ctrl-w
  2. Escriba \ mw
  3. Mueve a la ventana que quieres intercambiar.
  4. Tipo \ pw

Voila! Intercambiar buffers sin estropear el diseño de su ventana!





vim