364 Stimmen

Wie kann ich die Positionen von zwei geöffneten Dateien (in Splits) in Vim vertauschen?

Angenommen, ich habe eine beliebige Anordnung von Splits in Vim.

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

Gibt es eine Möglichkeit zum Tausch von one y two und das gleiche Layout beibehalten? In diesem Beispiel ist es einfach, aber ich suche nach einer Lösung, die für komplexere Layouts hilfreich ist.

UPDATE:

Ich denke, ich sollte mich klarer ausdrücken. Mein vorheriges Beispiel war eine Vereinfachung des tatsächlichen Anwendungsfalls. Mit einer tatsächlichen Instanz: alt text

Wie kann ich zwei beliebige dieser Splits austauschen, ohne dass das Layout verändert wird?

Aktualisieren! Mehr als 3 Jahre später...

Ich habe sgriffin's Lösung in ein Vim-Plugin gepackt, das Sie mit Leichtigkeit installieren können! Installieren Sie es mit Ihrem bevorzugten Plugin-Manager und probieren Sie es aus: WindowSwap.vim

a little demo

3voto

Geoff Catlin Punkte 33

Gebäude schwer auf @sgriffin's Antwort, hier ist etwas, das noch näher an dem ist, was Sie fragen:

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.

3voto

tpo Punkte 31

Basierend auf sgriffin's Lösung, gehen Sie zu dem Fenster, das Sie austauschen wollen, drücken Sie CTRL-w m gehen Sie zu dem Fenster, mit dem Sie tauschen möchten, und drücken Sie CTRL-w m wieder.

CTRL-w m ist eine schlechte Wahl für eine Eselsbrücke. Wenn jemandem eine bessere einfällt, bitte diesen Text bearbeiten.

Außerdem würde ich gerne eine Rückmeldung vom Skript aka "Fenster markiert. Bitte wiederholen Sie auf Ziel", aber da ich ein Vimscript-Noob bin, weiß ich nicht, wie man das macht.

Abgesehen davon funktioniert das Skript so, wie es ist, 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>

1voto

lesnik Punkte 2179

Der folgende Ansatz kann praktisch sein, wenn Funktionen aus irgendeinem Grund nicht verfügbar sind (z.B. weil es nicht Ihr Vim ist).

使用する :buffers um die IDs der offenen Puffer herauszufinden, navigieren Sie zum gewünschten Fenster und verwenden Sie einen Befehl wie :b 5 um einen Puffer zu öffnen (in diesem Fall Puffer Nummer 5). Wiederholen Sie dies zweimal und der Inhalt von Windows wird ausgetauscht.

Ich habe diese Methode "erfunden", nachdem ich mehrere Versuche unternommen hatte, mir etwas einzuprägen ctrl-w-something Sequenzen sogar für sehr einfache Layouts wie eins-zwei-drei in der ursprünglichen Frage.

1voto

rking Punkte 1522

Wirklich cool, aber mein Vorschlag für die Zuordnung ist, ^W^J anstelle von J zu verwenden (weil alle H J K L bereits Bedeutungen haben), und ich würde auch in den neuen Puffer, denn wenn Sie den Puffer wechseln wollen, wollen Sie wahrscheinlich nicht mehr den Puffer bearbeiten, in dem Sie sich bereits befinden. So geht's:

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>

1voto

Tom Stock Punkte 888

Alle oben genannten Antworten sind großartig, leider funktionieren diese Lösungen nicht gut in Kombination mit QuickFix oder LocationList Windows (ich bin auf dieses Problem gestoßen, als ich versucht habe, den Ale-Fehlermeldungspuffer damit zum Laufen zu bringen).

Lösung

Deshalb habe ich eine zusätzliche Codezeile hinzugefügt, um alle diese Fenster vor dem Tausch zu schließen.

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

Der gesamte Code sieht wie folgt aus;

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

Kredite für die Swap-Funktion an Brandon Orther

Warum sie gebraucht wird

Der Grund, warum die Swap-Funktionen nicht richtig funktionieren, ohne vorher alle QuickFix (QF)- und LocationList (LL)-Fenster zu entfernen, liegt darin, dass, wenn der übergeordnete QF/LL-Puffer ausgeblendet wird (und nirgendwo in einem Fenster angezeigt wird), das mit ihm verbundene QF/LL-Fenster entfernt wird. Dies ist an sich kein Problem, aber wenn das Fenster ausgeblendet wird, werden alle Fensternummern neu zugewiesen, und der Tausch wird durcheinander gebracht, da die gespeicherte Nummer des ersten markierten Fensters (möglicherweise) nicht mehr existiert.

Um dies in die richtige Perspektive zu rücken:

Erste Fenstermarkierung

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

Zweite Fenstermarkierung

____________________
| 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 Pufferwechsel, Fenster eins wird mit dem Puffer von Fenster drei gefüllt. Somit wird das QF-Fenster 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 existiert.

____________________
| 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 Fenster curNum auszuwählen, das nicht mehr existiert. Also wird es erstellt und der Puffer umgeschaltet, was dazu führt, dass ein unerwünschtes Fenster noch offen ist.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X