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.
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:
Comment puis-je échanger deux de ces fractionnements tout en conservant la même présentation?
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
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:
Voila! Permutez les tampons sans visser votre disposition de fenêtre!
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 .
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é.
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
).
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 :)
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.
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.
É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>
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).
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
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).
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
|__________________|
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>
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>