vim에서 두 개의 열린 파일 (스플릿 단위)의 위치를 ​​바꾸려면 어떻게해야합니까?


313

vim에 임의의 분할 레이아웃이 있다고 가정합니다.

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

교환 할 수있는 방법이 있나요 onetwo동일한 레이아웃과 유지는? 이 예제에서는 간단하지만보다 복잡한 레이아웃에 도움이되는 솔루션을 찾고 있습니다.

최신 정보:

나는 더 분명해야한다고 생각합니다. 이전 예제는 실제 사용 사례를 단순화 한 것입니다. 실제 인스턴스의 경우 : 대체 텍스트

동일한 레이아웃을 유지하면서 두 분할을 어떻게 바꿀 수 있습니까?

최신 정보! 3 년 이상 후 ...

나는 당신이 쉽게 설치할 수있는 Vim 플러그인에 sgriffin의 솔루션을 넣었습니다! 자주 사용하는 플러그인 관리자로 설치하고 사용해보십시오 : WindowSwap.vim

작은 데모


14
2 분 전에 " 정말 플러그인이 필요합니까?"라는 궁금한 점이 있으면 망설이지 말고 설치하십시오. 기본적으로 하나의 명령이 있습니다 : <leader> ww 각 창에서 한 번 두 번 눌러 교환합니다. 이것은 매우 쉽고 30 초 후에 실행됩니다.
mdup

답변:


227

게시물에 조금 늦었지만이 다른 것을 찾고 있습니다. 창을 표시하고 창간에 버퍼를 교환하기 위해 두 가지 기능을 다시 작성했습니다. 이것은 당신이 요구하는 것 같습니다.

.vimrc에서 이것들을 때리고 함수가 어떻게 보이는지 매핑하십시오.

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>

사용하려면 (당신의 mapleader가 \로 설정되어 있다고 가정) :

  1. ctrl-w 이동을 통해 스왑을 표시하려면 창으로 이동
  2. \ mw를 입력하십시오
  3. 교환하려는 창으로 이동
  4. 유형 \ pw

짜잔! 창 레이아웃을 방해하지 않고 버퍼를 교체했습니다!


17
나는 당신을 열 번 투표 할 수 있기를 바랍니다! 나는 noremap그것을 작동시키기 위해 매핑 에 사용해야 했다. 왜 그런지 확실하지 않지만 나중에 이것을 찾는 사람에게 도움이되기를 바랍니다. : D
wes

6
귀하의 솔루션을 첫 번째 Vim 플러그인 : WindowSwap.vim에 넣었습니다 . 이 질문과 귀하의 답변을 readme : D
wes

몇 년 전에 Sgriffin의 솔루션을 .vimrc에 넣고 현재 청소 중이며 플러그인으로 모두 옮기기로 결정했습니다. 추출을 수행하고 번들로 여전히 작동하는지 테스트하기 위해 창을 여러 번 분할하고 0r!figlet one[2, 3 등]을 실행 한 다음 테스트했습니다. 더 나아 가기 전에 github을 확인하고 애니메이션 figlet 창 스왑과 동일한 답변에 대한 링크 (내 .vimrc에 의견이 있음)가있는 (wes ') 플러그인을 찾았습니다. 이미 만들고 업로드 한 것 같은 느낌이 들었습니다. 어쨌든, 잘 했어! 나에게 약간의 작업을 저장 :)
Gary Fixler

293

이것으로 시작 :

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

'three'를 활성 창으로 만든 다음 ctrl+ 명령을 실행하십시오 w J. 현재 창을 이동하여 화면 하단을 채 웁니다.

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

이제 '1'또는 '2'를 활성 창으로 만든 다음 ctrl+ 명령을 실행하십시오 w r. 이것은 현재 행의 창을 '회전'하여 다음을 남깁니다.

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

이제 '2'를 활성 창으로 만들고 ctrl+ 명령을 실행하십시오 w H. 현재 창을 이동하여 화면 왼쪽을 채우고 다음을 수행합니다.

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

보시다시피, manouevre는 약간 섞입니다. 3 개의 창으로, 그것은 '타일 게임'퍼즐 중 하나와 조금 비슷합니다. 4 개 이상의 창이있는 경우이 작업을 권장하지 않습니다. 창을 닫고 원하는 위치에서 다시 여는 것이 좋습니다.

Vim에서 분할 창으로 작업하는 방법을 보여주는 스크린 캐스트를 만들었습니다 .


2
당신은 스크린 캐스트, 넬 스트롬을 만들기 위해 여분의 마일을 갔지만, 내가 실제로 찾고있는 것은 아닙니다. 기본 이동 명령으로 분할 작업을 할 수 있지만 궁금한 점은 임의의 복잡한 레이아웃에서 분할 위치를 바꿀 수있는 방법이 있는지입니다.
wes

95
나를 좋아하는 사람들을 위해 두 개의 창을 바꾸는 방법을 배우고 ctrl-w r싶습니다. 매력처럼 작동합니다. 팁 주셔서 감사합니다! 여기 내 +1이 있습니다.
ereOn

나는 \mw/ \pw와 이것 둘 다를 upvoted 하고 각각 일주일 동안 둘 다 사용해 보았습니다. 서버와 원격 컴퓨터, 데스크톱, 랩톱, 태블릿 및 기타 모든 장치에 설치된 십여 개의 vim 설치에 플러그인을 계속 설치할 필요가 없기 때문에이 "기본"솔루션을 사용하는 것이 가장 효과적이라는 것을 알았습니다. IOW, 이러한 기본 명령 (예 :)을 배우는 ctrl-w r것은 실제로 메모리 근육에 전념하고 수행하는 데 필요한 전부입니다.
eduncan911

96

:h ctrl-w_ctrl-x및 / 또는 살펴보십시오 :h ctrl-w_ctrl-r. 이 명령을 사용하면 현재 레이아웃에서 창을 교환하거나 회전 할 수 있습니다.

편집 : 실제로 이것은 현재 열이나 행에서만 교환하기 때문에이 상황에서는 작동하지 않습니다. 대신 각 창으로 이동하여 대상 버퍼를 선택할 수 있지만 매우 장황합니다.


30

랜디가 맞습니다CTRL-W x 열 / 행에없는 창을 바꾸고 싶지 것이 .

CTRL-W HJKL창을 조작 할 때 키가 가장 유용 하다는 것을 알았습니다 . 현재 창을 현재 위치 밖으로 강제로 밀고 누른 키 방향으로 표시된 전체 가장자리를 차지하도록 지시합니다. 보다:help window-moving 은 참조하십시오.

위의 예에서 "하나"창에서 시작하면 원하는 작업을 수행합니다.

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

편의상 키 매핑에 필요한 시퀀스를 할당 할 수 있습니다 (참조 :help mapping).


10

나는 sgriffin의 솔루션에서 약간 향상된 버전을 가지고 있으며 두 개의 명령을 사용하지 않고 직관적 인 HJKL 명령으로 창을 바꿀 수 있습니다.

다음은 그 방법입니다.

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>

일반 노드에서 대문자 HJKL을 사용하여 창을 이동하면 정말 멋집니다 :)


3

구축 크게 @ sgriffin의 대답에, 여기에 뭔가 더 가까이 당신이 요구하는지에있다 :

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>

행동이 귀하의 기대와 일치하지 않는 경우 알려주십시오.


2

또한 sgriffin의 솔루션에 따라 교환하려는 창으로 이동하고을 누르고 교환하려는 창으로 CTRL-w m이동 한 다음을 누릅니다.CTRL-w m 다시 .

CTRL-w m 니모닉 선택이 좋지 않으므로 더 나은 사람이 있으면 수정하십시오.

또한 스크립트 "창에 표시되었습니다. 대상에 반복하십시오"라는 피드백을 받고 싶습니다.하지만 vimscript 멍청한 놈이지만 그 방법을 모르겠습니다.

말한대로 스크립트는 그대로 작동합니다.

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

어떤 이유로 기능을 사용할 수없는 경우 다음 방법이 편리 할 수 ​​있습니다 (vim이 아닌 경우).

:buffers명령을 사용 하여 열린 버퍼의 ID를 찾고 원하는 창으로 이동 :b 5한 다음 버퍼를 열 때 와 같은 명령을 사용하십시오 (이 경우 버퍼 번호 5). 두 번 반복하면 창의 내용이 바뀝니다.

나는 ctrl-w-something원래의 질문에서 1-2와 같은 매우 간단한 레이아웃조차도 시퀀스 를 암기하려는 여러 번의 시도 후에이 방법을 "발명했다" .


1

정말 멋지지만 매핑에 대한 제안은 J 대신 ^ W ^ J를 사용하는 것입니다 (모든 HJKL은 이미 의미가 있기 때문에) 또한 새로운 버퍼를 가져옵니다 . 이미있는 버퍼를 계속 편집하고 싶지 않을 것입니다. 간다 :

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

위의 모든 대답은 훌륭하지만 불행히도 이러한 솔루션은 QuickFix 또는 LocationList 창과 함께 잘 작동하지 않습니다 (Ale 오류 메시지 버퍼를 사용하려고 시도하는 동안이 문제가 발생했습니다).

해결책

따라서 스왑을 수행하기 전에 모든 창을 닫는 추가 코드 줄을 추가했습니다.

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

전체 코드는 다음과 같습니다.

" 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 로의 스왑 기능에 대한 크레딧

왜 필요한가

모든 QuickFix (QF) 및 LocationList (LL) 창을 먼저 제거하지 않고 스왑 기능이 제대로 작동하지 않는 이유는 QF / LL 버퍼의 부모가 get을 숨기면 (그리고 창에 표시되지 않음) QF이기 때문입니다. 연결된 / LL 창이 제거됩니다. 이것은 그 자체로는 문제는 아니지만 창을 숨기면 모든 창 번호가 재 할당되고 표시된 첫 번째 창에 저장된 수가 더 이상 존재하지 않기 때문에 스왑이 엉망입니다.

이것을 무관심하게하려면 :

첫 번째 창 표시

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

두 번째 창 표시

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

첫 번째 버퍼 스위치, 창 1은 창 3의 버퍼로 채워집니다. 따라서 QF 창에는 더 이상 상위 창이 없으므로 제거됩니다. 이것은 창 번호를 재정렬합니다. curNum (두 번째로 선택된 창의 수)이 더 이상 존재하지 않는 창을 가리키고 있습니다.

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

따라서 두 번째 버퍼를 전환 할 때 더 이상 존재하지 않는 curNum 창을 선택하려고합니다. 따라서 버퍼를 생성하고 버퍼를 전환하여 원치 않는 하나의 창이 계속 열립니다.

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

0

비슷한 mark-window-then-swap-buffer 접근 방식은 물론 마지막 스와핑을 재사용 할 수 있습니다.

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>

set hidden.vimrc에 이미 있으므로 버퍼를 수동으로 숨길 필요가 없습니다.
qeatzy

-5

X-monad와 같은 타일링 창 관리자를 사용할 수도 있습니다.


사실이지만이 답변은 OP의 질문과 관련이 없습니다. Mac 또는 Windows 시스템에서 vim을 사용할 수 있습니다. Vim은 태블릿과 휴대 전화에서 사용할 수 있으며 어느 것도 창 관리자를 교체 할 수 없습니다.
nsfyn55
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.