Как я могу поменять местами двух открытых файлов (в расколах) в vim?
Предположим, что у меня есть произвольная раскладка расколов в vim.
____________________
| one | two |
| | |
| |______|
| | three|
| | |
|___________|______|
Есть ли способ обменять one
и two
и поддерживать тот же макет? В этом примере это просто, но я ищу решение, которое поможет в более сложных макетах.
UPDATE:
Думаю, я должен быть более ясным. В моем предыдущем примере было упрощено фактическое использование. С фактическим примером:
![IRL example 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