Vim'de iki açık dosyanın (bölünme cinsinden) konumlarını nasıl değiştirebilirim?


313

Vim'de bazı bölünmüş bölünmeler düzenim olduğunu varsayın.

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

Takas için bir yol var mı oneve twoaynı düzeni ve bakımı? Bu örnekte basit, ancak daha karmaşık düzenlere yardımcı olacak bir çözüm arıyorum.

GÜNCELLEME:

Sanırım daha açık olmalıyım. Önceki örneğim, gerçek kullanım senaryosunun basitleştirilmesiydi. Gerçek bir örnekle: alternatif metin

Aynı düzeni koruyarak bu bölünmelerden ikisini nasıl değiştirebilirim?

Güncelleme! 3+ yıl sonra ...

Sgriffin'ın çözümünü kolaylıkla yükleyebileceğiniz bir Vim eklentisine koydum! Favori eklenti yöneticinizle kurun ve deneyin: WindowSwap.vim

biraz demo


14
Benim gibi iki dakika önce " Gerçekten bunun için bir eklentiye ihtiyacım var mı?" Diye merak ediyorsanız , tereddüt etmeyi bırakın ve yükleyin. Temel olarak sadece bir komut vardır: takas etmek için her pencerede bir kez iki kez bastığınız <leader> ww. Bu çok kolay ve 30 saniye içinde koşacaksınız.
mdup

Yanıtlar:


227

Gönderinin biraz geç, ama başka bir şey aramak için bu rastladı. Bir pencereyi işaretlemek ve pencereler arasında arabellekleri değiştirmek için bir süre önce iki işlev yazdım. Bu senin istediğin gibi görünüyor.

Bunları .vimrc'nize tokatlayın ve işlevleri nasıl gördüğünüzü haritalayın:

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>

Kullanmak için (mapleader'ınızın \ olarak ayarlandığını varsayarsak):

  1. Takas için ctrl-w hareketi ile işaretlemek üzere pencereye gidin
  2. Tip \ mw
  3. Değiştirmek istediğiniz pencereye gidin
  4. Tip \ pw

İşte bu kadar! Pencere düzeninizi bozmadan değiştirilen tamponlar!


17
Keşke seni on kere yükseltebilseydim! noremapHaritalamalarda çalışmasını sağlamak için kullanmak zorunda kaldım. Neden olduğundan emin değilim ama umarım bunu daha sonra bulan herkese yardımcı olur. : D
wes

6
Çözümünüzü ilk Vim eklentime koydum : WindowSwap.vim . Bu soruyu ve cevabınızı benioku ile bağladım: D
wes

Birkaç yıl önce sgriffin'in çözümünü .vimrc'ime koydum ve şu anda temizliyorum ve hepsini bir eklentiye taşımaya karar verdim. Çıkarmayı yaptım ve hala bir paket olarak çalıştığını test etmek için pencereyi birçok kez böldüm ve bazı 0r!figlet one[iki, üç vb.] Koştum, sonra test ettim. Daha ileri gitmeden önce github'u kontrol ettim, (wes ') eklentinizi, animasyonlu pencere penceresi takasları ve aynı cevaba bir bağlantı (ki benim .vimrc'de bir yorum olarak buldum) ile buldum. Zaten yaptım ve yüklediğimi hissettim ve sonra unuttum. Her neyse, iyi iş çıkardın! Bana biraz iş kazandırır :)
Gary Fixler

293

Bununla başlayarak:

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

Etkin pencereyi 'üç' yapın, sonra ctrl+ komutunu verin w J. Bu, geçerli pencereyi ekranın altını dolduracak şekilde hareket ettirerek sizi aşağıdakilerle terk eder:

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

Şimdi aktif pencereyi 'bir' veya 'iki' yapın, sonra ctrl+ komutunu verin w r. Bu, geçerli satırdaki pencereleri 'döndürür' ve sizi şöyle bırakır:

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

Şimdi aktif pencereyi 'iki' yapın ve ctrl+ komutunu verin w H. Bu, geçerli pencereyi ekranın solunu dolduracak şekilde hareket ettirerek sizi aşağıdakilerle terk eder:

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

Gördüğünüz gibi, manouevre biraz karışık. 3 pencere ile, bu 'kiremit oyunu' bulmaca biri gibi biraz. 4 veya daha fazla pencereniz varsa bunu denemeyi tavsiye etmiyorum - onları kapatıp daha sonra istenen konumlarda tekrar açmanız daha iyi olur.

Vim'de bölünmüş pencerelerle nasıl çalışılacağını gösteren bir screencast yaptım .


2
Screencast yapmak için fazladan bir yol kat ettin, nelstrom, ama gerçekten aradığım şey bu değildi. Temel hareket komutlarıyla böler ile çalışabilirim, ancak merak ettiğim şey, bölünmüş yerleri rastgele karmaşıklık düzeninde değiştirmenin bir yolu varsa.
wes

95
Benden hoşlanan insanlar için, sadece iki pencereyi nasıl değiştireceğinizi öğrenmek istersiniz: ctrl-w rbir cazibe gibi çalışır. Bahşiş için teşekkürler! İşte + 1'im.
2013

Ben \mw/ \pwve bu bir upvoted ve her biri bir hafta boyunca her ikisini de kullanmayı denedim. Sunucular ve uzak makineler ve masaüstleri, dizüstü bilgisayarlar, tabletler ve diğer tüm cihazlarda sahip olduğum on düzine vim yüklemesi boyunca eklentileri yüklemeye devam etmek zorunda olmadığım için bu "doğal" çözümü kullanmanın en iyi sonucu buldum. IOW, bu Yerel komutları (örn. ctrl-w r) Öğrenmek , hafıza kasına bağlı kalmak ve yapılması gereken şeydir.
eduncan911

96

Bir göz atın :h ctrl-w_ctrl-xve / veya :h ctrl-w_ctrl-r. Bu komutlar, geçerli düzende pencereleri değiştirmenize veya döndürmenize izin verir.

Düzenleme: Aslında, bu yalnızca geçerli sütun veya satır takas olacaktır çünkü bu durumda çalışmaz. Bunun yerine pencerelerin her birine gidip hedef arabelleği seçebilirsiniz, ancak bu oldukça ayrıntılı.


30

Randy doğru CTRL-W x, aynı sütun / satırda olmayan pencereleri değiştirmek istemiyor.

CTRL-W HJKLAnahtarları en çok pencereleri işlerken yararlı buldum . Geçerli pencerenizi geçerli konumdan çıkarmaya zorlar ve bastığınız tuşun yönü ile belirtilen tüm kenarı işgal etmesini söylerler. Daha :help window-movingfazla ayrıntı için bakınız.

Yukarıdaki örneğiniz için, "bir" penceresinde başlıyorsanız, istediğinizi yapın:

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

Kolaylık için, anahtar eşlemelerine ihtiyacınız olan dizileri atayabilirsiniz (bkz. :help mapping).


10

Sgriffin'ın çözümünden biraz gelişmiş bir versiyonum var, iki komut kullanmadan pencereleri değiştirebilirsiniz, ancak sezgisel HJKL komutları ile.

İşte böyle:

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>

Normal düğümde büyük HJKL kullanarak pencerenizi hareket ettirmeye çalışın, gerçekten harika :)


3

Bina ağır @ sgriffin cevabı üzerine, burada bir şey daha yakın size soran şeyle var:

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>

Davranışın beklentilerinize uygun olup olmadığını lütfen bize bildirin.


2

Ayrıca sgriffin'ın çözümüne dayanarak, değiştirmek istediğiniz pencereye gidin, düğmesine basın CTRL-w m, değiştirmek istediğiniz pencereye gidin ve CTRL-w mtekrar basın .

CTRL-w m kötü bir anımsatıcı seçimdir, bu yüzden daha iyisi varsa lütfen bunu düzenleyin.

Ayrıca, komut dosyası aka "Pencere işaretli. Lütfen hedef üzerinde tekrarlayın" bir geribildirim almak istiyorum, ancak bir vimscript noob olmak, bunu nasıl yapacağımı bilmiyorum.

Tüm söylenenler, senaryo olduğu gibi iyi çalışıyor

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

İşlevler bir nedenden dolayı kullanılamıyorsa (yaklaşım sizin viminiz değilse) aşağıdaki yaklaşım uygun olabilir.

:buffersAçık arabelleklerin kimliklerini bulmak için command komutunu kullanın , istenen pencereye gidin ve :b 5buffer açmak için komut kullanın (bu durumda buffer 5 sayısı). İki kez tekrarlayın ve pencerelerin içeriği değiştirilir.

ctrl-w-somethingOrijinal soru bir-iki-üç gibi çok basit düzenleri için bile dizileri ezberlemek için birkaç denemeden sonra bu yöntemi "icat" .


1

Gerçekten serin ama haritalama bir önerim kullanmaktır ^ W yerine J ^ J (hjkl tüm zaten anlamlara sahip olduğundan), artı da ben çekip ediyorum içinde zaman çevrenizdeki takas etmek istiyorum, çünkü, yeni tampon muhtemelen üzerinde bulunduğunuz arabelleği düzenlemeye devam etmek istemezsiniz. İşte gidiyor:

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

Yukarıdaki yanıtların hepsi harika, ne yazık ki bu çözümler QuickFix veya LocationList pencereleri ile birlikte iyi çalışmıyor (Ale hata mesajı arabelleği bununla çalışmak için çalışırken bu sorunla karşılaştım).

Çözüm

Bu yüzden takas yapmadan önce tüm bu pencereleri kapatmak için ekstra bir kod satırı ekledim.

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

Toplam kod şuna benzer;

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

Brandon Orther'e takas fonksiyonu kredileri

Neden gerekli?

Takas işlevlerinin önce tüm QuickFix (QF) ve LocationList (LL) pencerelerini kaldırmadan düzgün çalışmamasının nedeni, QF / LL'nin üst öğesi arabelleğin gizlenmesi (ve hiçbir yerde bir pencerede gösterilmemesi), QF'nin / LL penceresi ona bağlı olarak kaldırılır. Bu kendi başına bir sorun değildir, ancak pencere gizlendiğinde tüm pencere numaraları yeniden atanır ve ilk işaretli pencerenin kaydedilen numarası (potansiyel olarak) artık mevcut olmadığından takas bozulur.

Bunu yanlış anlamak için:

İlk pencere işareti

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

İkinci pencere işareti

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

Birinci tampon anahtarı, birinci pencere üçüncü pencerenin tamponu ile doldurulur. Böylece QF penceresi artık üst penceresi olmadığından kaldırılır. Bu, pencere numaralarını yeniden düzenler. CurNum'un (ikinci olarak seçilen pencerenin sayısı) artık var olmayan bir pencereyi gösterdiğini unutmayın.

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

Bu nedenle, ikinci arabelleği değiştirirken, artık bulunmayan curNum penceresini seçmeye çalışır. Böylece onu oluşturur ve arabelleği değiştirerek istenmeyen bir pencerenin hareketsiz kalmasını sağlar.

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

0

Benzer işaret-pencere-sonra-takas-tampon yaklaşımı, ama aynı zamanda son takas yeniden kullanabilirsiniz.

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>

Zaten set hidden.vimrc içinde bulunduğum için, arabellekleri manuel olarak gizlemeye gerek yok.
qeatzy

-5

X-monad gibi bir döşeme penceresi yöneticisini de kullanabilirsiniz


Doğru olsa da, bu cevap OP'nin sorusuyla ilgisizdir. Mac veya Windows makinesinde vim kullanılıyor olabilir. Vim tabletlerde ve hatta hiçbirinde pencere yöneticinizi değiştirme yeteneği olmayan telefonlarda kullanılabilir.
nsfyn55
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.