Как я могу поменять местами двух открытых файлов (в расколах) в vim?

Предположим, что у меня есть произвольная раскладка расколов в vim.

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

Есть ли способ обменять one и two и поддерживать тот же макет? В этом примере это просто, но я ищу решение, которое поможет в более сложных макетах.

UPDATE:

Думаю, я должен быть более ясным. В моем предыдущем примере было упрощено фактическое использование. С фактическим примером: alt text

Как я могу поменять местами два из этих разделов, сохраняя один и тот же макет?

Обновление! 3+ года спустя...

Я установил решение sgriffin в плагин Vim, который вы можете установить с легкостью! Установите его с помощью своего любимого менеджера плагинов и попробуйте: WindowSwap.vim

a little demo

Ответ 1

Немного поздно, но наткнулся на это, ища что-то еще. Я написал две функции некоторое время назад, чтобы пометить окно, а затем сменить буферы между окнами. Кажется, это то, о чем вы просите.

Просто пощелкайте их в своем .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>

Чтобы использовать (при условии, что ваш клендер установлен в \), вы должны:

  • Перейдите в окно, чтобы отметить для свопа через ctrl-w движение
  • Тип \mw
  • Перейдите в окно, которое вы хотите обменять
  • Тип \pw

Voila! Перепутаны буферы, не закручивая расположение вашего окна!

Ответ 2

Начиная с этого:

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

Сделайте "три" активным окном, затем выполните команду ctrl + w J. Это перемещает текущее окно, чтобы заполнить нижнюю часть экрана, оставив вас с:

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

Теперь сделайте "одно" или "два" активным окном, затем выполните команду ctrl + w r. Это "поворачивает" окна в текущей строке, оставляя вас с:

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

Теперь сделайте "два" активным окном и выполните команду ctrl + w H. Это перемещает текущее окно, чтобы заполнить левую часть экрана, оставив вас:

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

Как вы можете видеть, manouevre немного перетасован. С 3 окнами, это немного похоже на одну из этих головоломок. Я не рекомендую попробовать это, если у вас 4 или более окон - вам лучше закрыть их, а затем снова открыть их в желаемых местах.

Я сделал скринкаст, демонстрирующий как работать с разделенными окнами в Vim.

Ответ 3

Взгляните на :h ctrl-w_ctrl-x и/или :h ctrl-w_ctrl-r. Эти команды позволяют вам обменивать или поворачивать окна в текущем макете.

Изменить: на самом деле, это не сработает в этой ситуации, потому что оно будет заменяться только текущим столбцом или строкой. Вместо этого вы можете перейти к каждому окну и выбрать целевой буфер, но это довольно подробный.

Ответ 4

Randy's верно в том, что 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).

Ответ 5

У меня немного улучшенная версия из решения 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 в обычном node, это действительно здорово:)

Ответ 6

Настроить тяжело на ответ @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>

Пожалуйста, дайте мне знать, если поведение не соответствует вашим ожиданиям.

Ответ 7

Следующий подход может быть удобным, если функции по какой-либо причине недоступны (т.е. это не ваш vim).

Используйте команду :buffers, чтобы узнать идентификатор открытых буферов, перейдите к нужному окну и используйте команду типа :b 5, чтобы открыть буфер (в этом случае, например, номер буфера 5). Повторяйте два раза и содержимое окон обменивается.

Я "изобрел" этот метод после нескольких попыток запомнить ctrl-w-something последовательности даже для очень простых макетов, например, один-два-три в оригинальном вопросе.

Ответ 8

На самом деле круто, но мое предложение для сопоставления - использовать ^ W ^ J вместо 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>

Ответ 9

Также на основе решения sgriffin перейдите в окно, которое вы хотите поменять местами, нажмите CTRL-w m, перейдите в окно, которое вы хотите поменять, и снова нажмите CTRL-w m.

CTRL-w m - это бедный мнемонический выбор, поэтому, если кто-нибудь придумает лучший, отредактируйте это.

Кроме того, я хотел бы получить обратную связь от script aka "Окно с пометкой. Повторите попытку", однако, будучи vimscript noob, я не знаю, как это сделать.

Все, что сказано, script работает хорошо, как

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

Ответ 10

Аналогичный подход к методу 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>

Ответ 11

Вы также можете использовать диспетчер оконной панели, такой как X-monad