Переместить всю строку вверх и вниз в Vim


311

В Notepad ++ я могу использовать Ctrl+ Shift+ Up/ Downдля перемещения текущей строки вверх и вниз. Есть ли подобная команда в Vim? Я просмотрел бесконечные путеводители, но ничего не нашел.

Если нет, как я могу связать действие с этой комбинацией клавиш?

Изменить: ответ Николая работает для всех строк, кроме тех, в начале и в конце буфера. Перемещение первой линии вверх или нижней строки приводит к удалению линии, а при перемещении нижней строки вверх изначально прыгает два пробела, как пешка! Кто-нибудь может предложить какие-либо уточнения?


У меня не было выбора, кроме как реализовать решение сценариев. Я надеюсь, что это чисто и приемлемо для ваших нужд.
Николай Голубев

31
Для детей будущего: vim.wikia.com/wiki/Moving_lines_up_or_down
оружие

Я не уверен, зачем вам нужен скрипт, примеры из статьи в Викии работают. Ниже я опубликовал упрощенную версию, потому что пример Викии с 3 различными режимами отображения может быть довольно пугающим (и не очень необходимым. Если вы используете только отображения выбора блоков, то вы можете просто не забыть заблокировать выбор (Shift V) и использовать эти ярлыки (см. мой ответ ниже).

Скринкаст на тему: vimcasts.org/e/26
glts

Также на ви SE
Cfi

Ответы:


81

Поместите следующее в ваш .vimrc, чтобы сделать работу

noremap <c-s-up> :call feedkeys( line('.')==1 ? '' : 'ddkP' )<CR>
noremap <c-s-down> ddp

Исчезновение линии выглядит как ошибка Vim. Я положил взлом, чтобы избежать этого. Возможно, есть более точное решение.

Обновить

Есть много необъяснимых трудностей с использованием только комбинаций Vim. Это пропущенные строки и дополнительные прыжки.

Итак, вот решение для сценариев, которое можно разместить внутри .vimrc или ~ / .vim / plugin / swap_lines.vim

function! s:swap_lines(n1, n2)
    let line1 = getline(a:n1)
    let line2 = getline(a:n2)
    call setline(a:n1, line2)
    call setline(a:n2, line1)
endfunction

function! s:swap_up()
    let n = line('.')
    if n == 1
        return
    endif

    call s:swap_lines(n, n - 1)
    exec n - 1
endfunction

function! s:swap_down()
    let n = line('.')
    if n == line('$')
        return
    endif

    call s:swap_lines(n, n + 1)
    exec n + 1
endfunction

noremap <silent> <c-s-up> :call <SID>swap_up()<CR>
noremap <silent> <c-s-down> :call <SID>swap_down()<CR>

1
Пришлось сменить на <cj> и <ck>, так как, похоже, конфликт с моей настройкой, но фантастический ответ! Большое спасибо
user4812

1
Спасибо, отлично подходит для git rebase --interactive. Пришлось связать с <cj> и <ck>. CS-Up / Down не работает.
Лари Хотари

2
Если кто-то хочет другой ярлык: c для контроля, A для alt, я использую <A-up>как в eclipse.
Янв

1
Исчезающая строка не является ошибкой Vim! Это скорее из-за выполнения ddkPв последней строке документа. Попробуйте сами на 3-строчном файле. Чтобы избежать таких проблем, используйте гораздо более простые :mсопоставления, как указано в вики Vim .
Серж Строобандт

1
Я изменил последние строки на <A-up>и, <A-down>но когда я пытаюсь использовать эти клавиши в vim в визуальном режиме в tmux, выбор исчезает, и курсор перемещается вверх; без перемещения выбранных линий.
Конрад

574

Если я хочу поменять одну строку на строку выше, я обычно делаю следующее

ddkP

объяснение

  • dd удалит строку и добавит ее в регистр по умолчанию.
  • k будет двигаться вверх по линии (j будет двигаться вниз по линии)
  • P вставит над текущей строкой

5
И это всегда доступно тоже. :-)
Хенно

71
И ddpпереместить строку вниз (удалить строку и вставить ниже текущей строки)
bcoughlan

2
Для перемещения группы строк, скажем, 4, 4 ddа затем перейдите к, скажем, 2 строки, то :2куда вы хотите вставить и P.
Гуру

2
@ Гуру это должно быть 4ddвместо 4 dd?
Патрик Макдональд

3
И dd<number>jpпереместить текущую строку <число> +1 строк вниз. И dd<number>kpпереместить текущую строку на <число> строк вверх.
Эгелев

230

Предполагая, что курсор находится на линии, которую вы хотели бы переместить.

Перемещение вверх и вниз: :mдля перемещения

:m +1 - движется вниз на 1 строку

:m -2 - двигаться вверх на 1 строку

(Обратите внимание, что вы можете заменить +1 на любое число в зависимости от того, на сколько строк вы хотите переместить его вверх или вниз, т.е. +2 переместит его на 2 строки, -3 переместит его на 2 строки)

Чтобы перейти к конкретной строке

:set number - отображать номера строк (легче увидеть, куда вы их перемещаете)

:m 3 - переместите строку после 3-й строки (замените 3 на любую, какую хотите)

Перемещение нескольких строк:

V(т.е. Shift- V) и перемещайте курсор вверх и вниз, чтобы выбрать несколько строк в VIM

как только выберете, нажмите :и запустите команды выше, и m +1т. д.


14
для меня: м -2 движется только вверх на одну строку.
Fzs2

2
я поместил этот метод в мой vimrc, но затем я не могу повторить команду, используя «.». Кто-нибудь знает, почему это так?
Fzs2

Очень хорошо! Не так удобно, как решение в Notepad ++, но все же - реально и работает.
Arturas M

Герман, извините, опечатка / ошибка с моей стороны, вы правы: m -2 переместит его на одну строчку вверх. Я изменил это. Также извините за очень поздний ответ (не уверен насчет части .vimrc) Приветствия
Серж

2
Перемещение с помощью этой команды работает, если вы хотите использовать ее в привязках, таких как в Notepad ++, как было указано в запросе OP, вам нужно ввести в .vimrc следующее:noremap <c-s-up> :m -2<CR> noremap <c-s-down> :m +1<CR>
kap

74

Переместить строку вверх: ddkP

Переместить строку вниз: ddp


1
наличие этого в vimrc запрещает повторять команду, используя '.'
Fzs2

@HermannIngjaldsson, я полагаю, вы можете заключить команду в функцию, если хотите использовать ее .для повторения.
jacobsimeon

Да, и если вам нужно переместить больше строк, вы можете использовать V вместо dd.
sensorario

15

Это сработало для меня:

http://vim.wikia.com/wiki/Moving_lines_up_or_down_in_a_file

Кстати, если вы хотите использовать ALT + some_key и ваш терминал (urxvt делает это) отказывается соблюдать, вы должны ввести что-то подобное в ваш .vimrc:

" For moving lines (^] is a special character; use <M-k> and <M-j> if it works)
nnoremap ^]k mz:m-2<CR>`z==
inoremap ^]j <Esc>:m+<CR>==gi
inoremap ^]k <Esc>:m-2<CR>==gi
vnoremap ^]j :m'>+<CR>gv=`<my`>mzgv`yo`z
nnoremap ^]j mz:m+<CR>`z==
vnoremap ^]k :m'<-2<CR>gv=`>my`<mzgv`yo`z

где ^] - один символ , представляющий клавишу ALT. Чтобы ввести этот символ, используйте C+v, Escв Vim ( C+q, Escв Windows).


1
Это хорошо, используя встроенную команду Vim для перемещения строки. Скорее всего, он будет вести себя хорошо перед лицом отмены или ошибки.
Джош Ли

1
Почему бы вам не ввести Esc как <kbd> Cv <kbd /> <kbd> Esc </ kbd> (linux). Windows заменяет <kbd> Cv <kbd /> на <kbd> Cq <kbd /> по всей доске, но имеет такой же способ ввода любой специальной клавиши в режиме вставки / команды
сэх

@sehe: Спасибо, я не знал этого в то время. Я обновил ответ.
emil.p.stanchev

1
@RafaelRinaldi - [niv]noremapэто переназначения для нормального | insert | визуального режима. <CR>есть Carriage Return( Enterключ).
vp_arth

1
@vp_arth Нет, нет
сехе

13

добавьте следующее в файл ~ / .vimrc (убедитесь, что у вас нет отображения для n, m)

nmap n :m +1<CR>
nmap m :m -2<CR>

Теперь нажатие nклавиши переместит линию вниз и mпереместит линию вверх.


12

В командном режиме поместите курсор на строку, которую вы хотите переместить вниз, а затем

ddp

Пояснение: dd удаляет текущую строку в общий буфер, p помещает ее обратно ПОСЛЕ позиции курсора или, в случае целых строк, на одну строку ниже.

Существует некоторая путаница в отношении команд p и P во многих документах. В действительности p вставляет ПОСЛЕ курсора, а P AT - курсор.


8

Просто добавьте этот код в .vimrc (или .gvimrc)

nnoremap <A-j> :m+<CR>==
nnoremap <A-k> :m-2<CR>==
inoremap <A-j> <Esc>:m+<CR>==gi
inoremap <A-k> <Esc>:m-2<CR>==gi
vnoremap <A-j> :m'>+<CR>gv=gv
vnoremap <A-k> :m-2<CR>gv=gv

1
Согласно vim.wikia.com/wiki/… см. Там для всестороннего объяснения.
Серж Строобандт

На Mac <A-что-то> не работает, я не знаю почему. Я заменил <Cj> <Ck>, и хорошо работает, используя клавишу Ctrl.
Седрик НИКОЛАС



3

Я положил следующее в конец моего файла .vimrc:

noremap H ddkkp
noremap N ddp

Так что теперь «H» и «N» перемещают текущую строку вверх и вниз соответственно.


H и N на самом деле являются полезными командами (H перемещает курсор в верхнюю и верхнюю часть экрана, N перемещает к предыдущему результату поиска), поэтому я бы порекомендовал использовать разные клавиши
villapx

Понимаю. Я также перенастроил их. Чтобы перейти к верхней части экрана, я нажимаю а затем вверх. A всегда означает все пути в моих книгах. И для поиска по предыдущим результатам я нажимаю f и затем ухожу. F тогда обозначает находку. Но для тех, у кого этого нет, тогда да .. это действительно.
Fzs2

1

Вот упрощенная версия для MacVim, использующая примеры из статьи Wikia (см. Ссылку из комментария Gun ).

" Move selection up/down (add =gv to reindent after move)
:vmap <D-S-Up> :m-2<CR>gv
:vmap <D-S-Down> :m'>+<CR>gv

Я использую только вариант выбора блока, потому что все, что требуется, это Shift-V, чтобы выбрать текущую строку, и, при необходимости, курсор вверх / вниз, чтобы выбрать еще несколько строк.

В соответствии с указаниями выше, нажатие Cmd-Shift-Up / Down сместит выбор блока вверх / вниз. «D» - это клавиша «Command» в MacVim, для Windows попробуйте «C» (Control) или «A» (Alt) (например, <CAf> будет Control Alt f).

Статья Wikia добавляет к ним «= gv», что позволяет настроить отступ блока после перемещения на основе окружающего текста. Это сбивает с толку, поэтому я удалил его и добавил вместо него ярлыки для быстрого отступа выделения.

" Indent selection left/right (Cmd Shift Left/Right is used for Tab switching)
:vmap <D-A-Left> <gv
:vmap <D-A-Right> >gv

Имейте в виду, то же самое можно сделать с << и >>, но выбор будет потерян, поэтому вышеупомянутые ярлыки позволяют многократно отступать и по-прежнему перемещать блок, потому что выбор поддерживается.

Мой MacVim настроен для переключения вкладок с помощью Cmd-Shift-Left / Right, поэтому я использовал Cmd-Alt-Left / Right.

Вот переключение вкладок для MacVim (поместите в .gvimrc вместе с остальными выше):

:macm Window.Select\ Previous\ Tab key=<D-S-Left>
:macm Window.Select\ Next\ Tab key=<D-S-Right>

1

плагин vim unimpaired.vim [e and] e


2
Это кажется излишним, я не думаю, что вам действительно нужен полный плагин для этого. 2 строки в vimrc делают именно то, что хочет ОП
Даниэль Гратцер,

1

Когда вы нажмете команду :help moveв vim, и вот результат:

:[range]m[ove] {address} *:m* *:mo* *:move* *E134* Move the lines given by [range] to below the line given by {address}.

Например: переместить текущую строку на одну строку вниз => :m+1 .

Например: переместите строку с номером 100 ниже линии с номером 80 => :100 m 80 .

Например: переместите строку с номером 100 ниже линии с номером 200 => :100 m 200 .

Например: переместите строки с номером в пределах [100, 120] ниже строки с номером 200 => :100,120 m 200 .


1

Вот решение, которое работает на моей машине : MacBook Pro под управлением VIM 8.1

Эти команды не будут удалять ваши строки вверху или внизу буфера.

Использование фактических символов, которые выводят Alt-J и Alt-K, является обходным решением для их кодов клавиш, которые не отображаются должным образом в моей среде.

Добавьте это в старый .vimrc и посмотрите, работает ли он для вас.

" Maps Alt-J and Alt-K to macros for moving lines up and down
" Works for modes: Normal, Insert and Visual
nnoremap ∆ :m .+1<CR>==
nnoremap ˚ :m .-2<CR>==
inoremap ∆ <Esc>:m .+1<CR>==gi
inoremap ˚ <Esc>:m .-2<CR>==gi
vnoremap ∆ :m '>+1<CR>gv=gv
vnoremap ˚ :m '<-2<CR>gv=gv


0

: m. + 1 или: m.-2 будет делать, если вы перемещаете одну строку. Вот мой скрипт для перемещения нескольких строк. В визуальном режиме Alt-up / Alt-down переместит строки, содержащие визуальный выбор, вверх / вниз на одну строку. В режиме вставки или обычном режиме Alt-up / Alt-down переместит текущую строку, если не указан префикс счета. Если есть префикс count, Alt-up / Alt-down переместит столько строк, начиная с текущей строки вверх / вниз на одну строку.

function! MoveLines(offset) range
    let l:col = virtcol('.')
    let l:offset = str2nr(a:offset)
    exe 'silent! :' . a:firstline . ',' . a:lastline . 'm'
        \ . (l:offset > 0 ? a:lastline + l:offset : a:firstline + l:offset)
    exe 'normal ' . l:col . '|'
endf

imap <silent> <M-up> <C-O>:call MoveLines('-2')<CR>
imap <silent> <M-down> <C-O>:call MoveLines('+1')<CR>
nmap <silent> <M-up> :call MoveLines('-2')<CR>
nmap <silent> <M-down> :call MoveLines('+1')<CR>
vmap <silent> <M-up> :call MoveLines('-2')<CR>gv
vmap <silent> <M-down> :call MoveLines('+1')<CR>gv

0

Если вы хотите сделать это на нескольких строках, которые соответствуют определенному поиску:

  • Up: :g/Your query/ normal ddp или:g/Your query/ m -1
  • Вниз :g/Your query/ normal ddpили:g/Your query/ m +1
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.