Перемістити всю лінію вгору та вниз по Vim


311

У Блокноті ++ я можу використовувати Ctrl+ Shift+ Up/ Downдля переміщення поточної лінії вгору та вниз. Чи схожа команда на цю у Vim? Я переглянув нескінченні посібники, але нічого не знайшов.

Якщо цього немає, як я можу прив’язати дію до цієї комбінації клавіш?

Редагувати: Відповідь Миколи працює для всіх рядків, окрім тих на початку та в кінці буфера. Переміщення першого рядка вгору або нижнього рядка вниз видаляє лінію, а при переміщенні нижньої лінії вгору вона стрибає два пробіли спочатку, як пішак! Чи може хтось запропонувати якісь уточнення?


У мене не було іншого вибору, як застосувати сценарій рішення. Я сподіваюся, що він чистий і прийнятний для ваших потреб.
Микола Голубєв

31
Для дітей майбутнього: vim.wikia.com/wiki/Moving_lines_up_or_down
гармати

Я не впевнений, навіщо вам потрібен сценарій, приклади статей Wikia працюють. Я розмістив нижче спрощену версію, тому що приклад Wikia з трьома різними режимами відображення може бути досить непростим (і не дуже потрібним. Якщо ви використовуєте лише відображення блоку вибору блоків, ви можете просто запам'ятати, щоб заблокувати вибір (Shift V) та використовувати ці ярлики (див. мою відповідь нижче).


Також на vi 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 - інтерактивна. Довелося прив’язати до <cj> і <ck>. cs-up / down не спрацювало.
Ларі Хотарі

2
Якщо хтось хоче іншого ярлика: c - для контролю, A - для alt, я використовую, <A-up>як використовується у затемненні.
січень

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
@Guru це має бути 4ddзамість 4 dd?
Патрік Макдональд

3
І dd<number>jpперемістити поточний рядок <число> +1 рядків вниз. І dd<number>kpщоб перемістити поточний рядок <число> рядків вгору.
egelev

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
для мене: m -2 рухається лише на одну лінію.
Герман Інгяльдссон

2
Я поклав цей метод у свій vimrc, але потім я не можу повторити команду, використовуючи '.' хтось знає, чому це?
Герман Інгяльдссон

Дуже хороший! Не так зручно, як рішення в Notepad ++, але все ж - справжнє та робоче.
Артурас М

Герман, Вибачте, помилка друку / помилки з мого боку, ви праві,: m -2 перемістить її на одну лінію. Я це змінив. Також вибачте за дуже пізню відповідь (не впевнений у .vimrc part) Ура
Серг

2
Переміщення за допомогою команди працює, якщо ви хочете використовувати її в прив'язках, таких як з Notepad ++ за запитом ОП, вам потрібно ввести наступне в .vimrc:noremap <c-s-up> :m -2<CR> noremap <c-s-down> :m +1<CR>
kap

74

Перемістити лінію вгору: ddkP

Перемістіть лінію вниз: ddp


1
маючи це у vimrc, відключає повторення команди за допомогою '.'
Герман Інгяльдссон

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

Так, .. і якщо вам потрібно перемістити більше рядків, ви можете використовувати V замість dd.
sensorario

15

Це працювало для мене:

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

BTW, якщо ви хочете використовувати 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, EscVim ( 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є перенастроєм для нормальних | вставних | візуальних режимів. <CR>є Carriage Return( Enterключ).
vp_arth

1
@vp_arth Ні там немає
14:18

13

додайте у файл ~ / .vimrc файл (переконайтесь, що у вас немає відображення для n, m)

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

тепер натискання nклавіші перемістить лінію вниз і mперемістить лінію вгору.


12

У командному режимі розташуйте курсор на лінії, яку потрібно рухати вниз, а потім

ddp

Пояснення: dd видаляє поточний рядок із загального буфера;

Існує деяка плутанина щодо команд 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 тоді означає знахідку. Але для тих, хто цього не має, то так ... так, це справедливо.
Герман Інгяльдссон

1

Ось спрощена версія для MacVim, використовуючи приклади статті Wikia (див. Посилання з коментаря гармати ).

" 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" - це командна клавіша в 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.

Ось переключення Tab для 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 і] 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-вгору / Alt-вниз перемістить поточний рядок, якщо не вказаний префікс підрахунку. Якщо є префікс підрахунку, Alt-вгору / Alt-вниз перемістить стільки рядків, починаючи з поточного рядка вгору / вниз по одному рядку.

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

Якщо ви хочете зробити це в декількох рядках, які відповідають певному пошуку:

  • Вгору: :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.