Как мне поменять местами два открытых файла (в разделениях) в vim? - PullRequest
296 голосов
/ 06 апреля 2010

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

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

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

ОБНОВЛЕНИЕ:

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

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

Обновить!Спустя 3 года ...

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

a little demo

Ответы [ 12 ]

274 голосов
/ 07 апреля 2010

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

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

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

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

Теперь сделайте активным окно «один» или «два», затем выполните команду ctrl + ш г .Это «вращает» окна в текущей строке, оставляя вас с:

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

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

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

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

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

218 голосов
/ 05 февраля 2011

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

Просто добавьте их в свой .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

Вуаля! Поменяйте местами буферы, не портя расположение окон!

95 голосов
/ 06 апреля 2010

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

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

29 голосов
/ 07 апреля 2010

Рэнди правильно в том, что 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 голосов
/ 13 октября 2012

У меня немного улучшенная версия решения 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 голосов
/ 24 июля 2012

Построение в значительной степени по ответу @ 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>

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

1 голос
/ 22 октября 2018

Все вышеприведенные ответы великолепны, к сожалению, эти решения не работают в сочетании с окнами 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>

Кредиты для функции обмена на Брэндон Ортер

Зачем это нужно

Причина, по которой функции подкачки не работают должным образом, не удаляя сначала все окна 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
|__________________|

Первый переключатель буфера, первое окно заполняется буфером третьего окна. Таким образом, окно 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
|__________________|
1 голос
/ 19 марта 2013

Также на основе решения 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 голос
/ 13 октября 2012

Действительно круто, но мое предложение для отображения состоит в том, чтобы использовать ^ 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>
1 голос
/ 06 сентября 2012

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

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

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

...