web-dev-qa-db-fra.com

Comment permuter les positions de deux fichiers ouverts (dans des divisions) dans vim?

Supposons que je dispose d'une disposition arbitraire des divisions dans vim. 

____________________
| one       | two  |
|           |      |
|           |______|
|           | three|
|           |      |
|___________|______|

Existe-t-il un moyen d'échanger one et two et de conserver la même présentation? C'est simple dans cet exemple, mais je cherche une solution qui aidera pour des mises en page plus complexes.

METTRE À JOUR:

Je suppose que je devrais être plus clair. Mon exemple précédent était une simplification du cas d'utilisation réel. Avec une instance réelle: alt text

Comment puis-je échanger deux de ces fractionnements tout en conservant la même présentation?

Mettre à jour! 3 ans et plus après ...

Je mets la solution de sgriffin dans un plugin Vim que vous pouvez installer facilement! Installez-le avec votre gestionnaire de plug-ins préféré et essayez-le: WindowSwap.vim

a little demo

291
wes

Un peu tard pour le poste, mais est tombé sur cette recherche pour autre chose. J'ai écrit deux fonctions quelque temps en arrière pour marquer une fenêtre, puis permuter les tampons entre les fenêtres. Cela semble être ce que vous demandez. 

Il suffit de les insérer dans votre fichier .vimrc et de cartographier les fonctions comme bon vous semble:

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>

Pour utiliser (en supposant que votre mapleader est défini sur \), vous devez: 

  1. Déplacez-vous vers la fenêtre pour marquer le changement via ctrl-w movement
  2. Tapez\mw
  3. Déplacer vers la fenêtre que vous voulez échanger
  4. Tapez\pw

Voila! Permutez les tampons sans visser votre disposition de fenêtre!

217
sgriffin

En commençant par ceci:

____________________
| one       | two  |
|           |      |
|           |______|
|           | three|
|           |      |
|___________|______|

Définissez "trois" comme fenêtre active, puis lancez la commande ctrl+wJ. Cela déplace la fenêtre en cours pour remplir le bas de l'écran, vous laissant avec:

____________________
| one       | two  |
|           |      |
|___________|______|
| three            |
|                  |
|__________________|

Définissez maintenant "un" ou "deux" comme fenêtre active, puis lancez la commande ctrl+wr. Ceci "fait pivoter" les fenêtres de la rangée actuelle, vous laissant avec:

____________________
| two       | one  |
|           |      |
|___________|______|
| three            |
|                  |
|__________________|

Maintenant, faites "deux" la fenêtre active et lancez la commande ctrl+wH. Cela déplace la fenêtre en cours pour remplir la gauche de l'écran, vous laissant avec:

____________________
| two       | one  |
|           |      |
|           |______|
|           | three|
|           |      |
|___________|______|

Comme vous pouvez le constater, la manoeuvre est un peu aléatoire. Avec 3 fenêtres, c'est un peu comme un de ces casse-têtes. Je ne vous recommande pas d'essayer cela si vous avez 4 fenêtres ou plus - vous feriez mieux de les fermer puis de les rouvrir aux positions désirées.

J'ai fait un screencast démontrant comment travailler avec des fenêtres divisées dans Vim .

273
nelstrom

Jetez un coup d'œil à :h ctrl-w_ctrl-x et/ou :h ctrl-w_ctrl-r. Ces commandes vous permettent d’échanger ou de faire pivoter des fenêtres dans la présentation actuelle.

Edit: En fait, cela ne fonctionnera pas dans cette situation car il ne sera échangé que dans la colonne ou la ligne actuelle. Vous pourriez plutôt aller dans chacune des fenêtres et sélectionner le tampon cible, mais c'est assez détaillé.

91
Randy Morris

Randy correct dans ce CTRL-W x ne veut pas échanger les fenêtres qui ne sont pas dans la même colonne/ligne.

J'ai trouvé que les touches CTRL-W HJKL sont les plus utiles lors de la manipulation de fenêtres. Ils forceront votre fenêtre actuelle à quitter son emplacement actuel et lui diront d'occuper tout le bord indiqué par la direction de la touche sur laquelle vous appuyez. Voir :help window-moving pour plus de détails.

Pour votre exemple ci-dessus, si vous démarrez dans la fenêtre "un", cela fait ce que vous voulez:

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

Pour plus de commodité, vous pouvez affecter les séquences dont vous avez besoin pour mapper les touches (voir :help mapping ).

29
MikeSep

J'ai une version légèrement améliorée de la solution de sgriffin, vous pouvez échanger des fenêtres sans utiliser deux commandes, mais avec des commandes intuitives HJKL.

Alors voici comment ça se passe:

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>

Essayez de déplacer votre fenêtre en utilisant la majuscule HJKL dans un noeud normal, c'est vraiment cool :)

10
Pencilcheck

Construire fortement sur la réponse de @ sgriffin, voici quelque chose de plus proche de ce que vous demandez:

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>

S'il vous plaît laissez-moi savoir si le comportement ne correspond pas à vos attentes.

3
Geoff Catlin

L'approche suivante peut être pratique si les fonctions ne sont pas disponibles pour une raison quelconque (par exemple, ce n'est pas votre vim).

Utilisez la commande :buffers pour connaître les identifiants des tampons ouverts, accédez à la fenêtre souhaitée et utilisez la commande comme :b 5 pour ouvrir un tampon (le tampon numéro 5 dans ce cas). Répétez deux fois et le contenu des fenêtres est échangé.

J'ai "inventé" cette méthode après plusieurs tentatives de mémorisation de séquences ctrl-w-something, même pour des mises en page très simples, comme un deux trois en question.

1
lesnik

Également basé sur la solution de sgriffin, accédez à la fenêtre que vous souhaitez permuter, appuyez sur CTRL-w m, accédez à la fenêtre avec laquelle vous souhaitez permuter et appuyez à nouveau sur CTRL-w m.

CTRL-w m est un mauvais choix mnémonique, donc si quelqu'un en propose un meilleur, veuillez le modifier.

Aussi, je voudrais recevoir un retour du script aka "Fenêtre marquée. S'il vous plaît répéter sur la cible", cependant étant un noob vimscript, je ne sais pas comment faire cela.

Cela dit, le script fonctionne bien tel quel.

" <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>
1
tpo

Toutes les réponses ci-dessus sont excellentes. Malheureusement, ces solutions ne fonctionnent pas correctement en combinaison avec les fenêtres QuickFix ou LocationList (j'ai couru le problème en essayant de faire fonctionner le tampon de message d'erreur Ale).

Solution

Par conséquent, j'ai ajouté une ligne de code supplémentaire pour fermer toutes ces fenêtres avant de procéder à l'échange.

exe ':windo if &buftype == "quickfix" || &buftype == "locationlist" | lclose | endif'

Le code total ressemble à;

" 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édits pour la fonction d'échange à Brandon Orther

Pourquoi c'est nécessaire

La raison pour laquelle les fonctions de swap ne fonctionnent pas correctement sans supprimer d'abord toutes les fenêtres QuickFix (QF) et LocationList (LL) est que si le parent du tampon QF/LL tampon est caché (et affiché nulle part dans une fenêtre), le QF La fenêtre/LL qui lui est couplée est supprimée. Ce n’est pas un problème en soi, mais lorsque la fenêtre est masquée, tous les numéros de fenêtre sont réaffectés et le swap est perturbé car le numéro enregistré de la première fenêtre marquée n’existe plus (potentiellement).

Pour mettre cette inperspective:

Première marque de fenêtre

____________________
| one              | -> winnr = 1    marked first    g:markedWinNum=1
|                  | -> bufnr = 1
|__________________|
| two (QF window   | -> winnr = 2
| coupled to one   |
|__________________|
| three            | -> winnr = 3
|                  | -> bufnr = 2
|__________________|

Deuxième marque de fenêtre

____________________
| 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
|__________________|

Premier commutateur tampon, la première fenêtre est remplie avec le tampon de la troisième fenêtre. Ainsi, la fenêtre QF est supprimée car elle n’a plus de fenêtre parente. Ceci réorganise les nombres de fenêtres. Notez que curNum (le numéro de la deuxième fenêtre sélectionnée) pointe vers une fenêtre qui n’existe plus.

____________________
| three            | -> winnr = 1                    g:markedWinNum=1
|                  | -> bufnr = 2
|__________________|
| three            | -> winnr = 2                     curNum=3
|                  | -> bufnr = 2                     curBuf=2
|__________________|

Ainsi, lors de la commutation du second tampon, il essaie de sélectionner la fenêtre curNum, qui n’existe plus. Donc, il le crée et change le tampon, ce qui a pour résultat qu'une fenêtre non désirée reste ouverte.

____________________
| three            | -> winnr = 1                    g:markedWinNum=1
|                  | -> bufnr = 2
|__________________|
| three            | -> winnr = 2
|                  | -> bufnr = 2
|__________________|
| one              | -> winnr = 3                     curNum=3
|                  | -> bufnr = 1                     curBuf=2
|__________________|
1
Tom Stock

Vraiment cool, mais ma proposition pour le mappage est d’utiliser ^ W ^ J au lieu de J (parce que tous les symboles HJKL ont déjà un sens), plus je tirerais le nouveau tampon in , pour vous échanger, ne voulez probablement pas continuer à éditer le tampon sur lequel vous êtes déjà. Voici:

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>
1
rking

Même approche mark-window-then-swap-buffer, mais vous permet également de réutiliser le dernier échange.

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>
0
qeatzy