it-swarm.com.de

Wie kann ich die Positionen von zwei offenen Dateien (in Splits) in vim austauschen?

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.

AKTUALISIEREN:

Ich denke ich sollte klarer sein. Mein vorheriges Beispiel war eine Vereinfachung des tatsächlichen Anwendungsfalls. Mit einer tatsächlichen Instanz: alt text

Wie könnte ich zwei dieser Splits austauschen und dabei das gleiche Layout beibehalten?

Aktualisieren! 3 Jahre später ...

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

a little demo

291
wes

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: 

  1. Bewegen Sie sich in das Fenster, um den Swap über ctrl-w zu markieren
  2. Geben Sie\mw ein.
  3. Wechseln Sie zu dem Fenster, das Sie austauschen möchten
  4. Geben Sie\pw ein.

Voila! Tauschen Sie die Puffer aus, ohne Ihr Fensterlayout zu beeinträchtigen!

217
sgriffin

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 .

273
nelstrom

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.

91
Randy Morris

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 ).

29
MikeSep

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 :)

10
Pencilcheck

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.

3
Geoff Catlin

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.

1
lesnik

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

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).

Lösung

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

Warum ist es nötig?

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.

Um dies inperspektivisch zu machen:

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
|__________________|
1
Tom Stock

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

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