Di chuyển toàn bộ dòng lên và xuống trong Vim


311

Trong Notepad ++, tôi có thể sử dụng Ctrl+ Shift+ Up/ Downđể di chuyển dòng hiện tại lên và xuống. Có một lệnh tương tự như thế này trong Vim? Tôi đã xem qua các hướng dẫn vô tận, nhưng không tìm thấy gì.

Nếu không có, làm thế nào tôi có thể liên kết hành động với tổ hợp phím đó?

Chỉnh sửa: Câu trả lời của Mykola hoạt động cho tất cả các dòng, ngoài những câu ở đầu và cuối bộ đệm. Di chuyển dòng đầu tiên lên hoặc dòng dưới cùng xóa dòng, và khi di chuyển dòng dưới lên, nó nhảy hai khoảng trống ban đầu, giống như một con tốt! Bất cứ ai có thể cung cấp bất kỳ tinh chỉnh?


Tôi không có lựa chọn nào khác ngoài thực hiện giải pháp kịch bản. Tôi hy vọng nó là sạch sẽ và có thể áp dụng cho nhu cầu của bạn.
Mykola Golubyev

31
Dành cho các con của tương lai: vim.wikia.com/wiki/Moving_lines_up_or_down
súng

Tôi không chắc tại sao bạn cần một kịch bản, các ví dụ bài viết Wikia hoạt động. Tôi đã đăng bên dưới một phiên bản đơn giản hóa, vì ví dụ của Wikia với 3 chế độ ánh xạ khác nhau có thể khá khó khăn (và không thực sự cần thiết. Nếu bạn chỉ sử dụng ánh xạ chọn khối, thì bạn có thể chỉ cần nhớ chọn khối (Shift V) và sử dụng các phím tắt này (xem câu trả lời của tôi bên dưới).

Screencast về chủ đề: vimcasts.org/e/26
glts

Cũng trên vi SE
cfi

Câu trả lời:


81

Đặt phần sau vào .vimrc của bạn để thực hiện công việc

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

Biến mất của dòng trông giống như một lỗi Vim. Tôi đặt một hack để tránh nó. Có lẽ có một số giải pháp chính xác hơn.

Cập nhật

Có rất nhiều khó khăn không giải thích được khi chỉ sử dụng kết hợp Vim. Đây là dòng thiếu và nhảy dòng bổ sung.

Vì vậy, đây là giải pháp kịch bản có thể được đặt bên trong .vimrc hoặc ~ / .vim / plugin / exchange_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
Phải đổi thành <cj> và <ck> vì dường như có một cuộc đụng độ với thiết lập của tôi, nhưng câu trả lời tuyệt vời! Cảm ơn rất nhiều
user4812

1
Cảm ơn, tuyệt vời cho git rebase - tương tác. Phải liên kết với <cj> và <ck>. cs-up / down không hoạt động.
Lari Hotari

2
Nếu ai đó muốn một phím tắt khác: c là để điều khiển, A là cho alt, tôi sử dụng <A-up>như được sử dụng trong nhật thực.
Tháng Một

1
Dòng biến mất không phải là lỗi Vim! Nó khá là do thực hiện ddkPtrên dòng cuối cùng của tài liệu. Hãy thử nó cho chính mình trên một tập tin 3 dòng. Để tránh những vấn đề như vậy, hãy sử dụng các :mánh xạ dễ dàng hơn nhiều như được đưa ra trên wiki Vim .
Serge Stroobandt

1
Tôi đã thay đổi các dòng cuối cùng thành <A-up><A-down>khi tôi thử các phím đó trong vim trong hình ảnh đang chạy trong tmux , lựa chọn sẽ biến mất và con trỏ di chuyển thẳng hàng; mà không di chuyển các dòng đã chọn.
Konrad

574

Nếu tôi muốn hoán đổi một dòng với dòng trên, tôi thường làm như sau

ddkP

Giải trình

  • dd sẽ xóa dòng và thêm nó vào thanh ghi mặc định.
  • k sẽ di chuyển lên một dòng (j sẽ di chuyển xuống một dòng)
  • P sẽ dán phía trên dòng hiện tại

5
Và nó luôn luôn có sẵn, quá. :-)
Henno

71
ddpđể di chuyển một dòng xuống (xóa dòng và dán bên dưới dòng hiện tại)
bcoughlan

2
Để di chuyển một loạt các dòng, nói 4, 4 ddvà sau đó di chuyển đến, nói 2 dòng, sau đó :2nơi bạn muốn dán và P.
Đạo sư

2
@Guru có nên 4ddthay thế 4 dd?
Patrick McDonald

3
dd<number>jpđể di chuyển dòng hiện tại <number> +1 của dòng xuống. Và dd<number>kpđể di chuyển dòng hiện tại <number> của dòng lên.
egelev

230

Giả sử con trỏ nằm trên dòng bạn muốn di chuyển.

Di chuyển lên và xuống: :mđể di chuyển

:m +1 - di chuyển xuống 1 dòng

:m -2 - di chuyển lên 1 dòng

(Lưu ý bạn có thể thay thế +1 bằng bất kỳ số nào tùy thuộc vào số lượng dòng bạn muốn di chuyển lên hoặc xuống, tức là +2 sẽ di chuyển xuống 2 dòng, -3 sẽ di chuyển lên 2 dòng)

Để di chuyển đến dòng cụ thể

:set number - hiển thị các dòng số (dễ dàng hơn để xem nơi bạn đang di chuyển đến)

:m 3 - di chuyển dòng sau dòng thứ 3 (thay thế 3 thành bất kỳ dòng nào bạn muốn)

Di chuyển nhiều dòng:

V(tức là Shift- V) và di chuyển courser lên và xuống để chọn nhiều dòng trong VIM

một khi được chọn nhấn :và chạy các lệnh trên, m +1vv


14
đối với tôi: m -2 chỉ di chuyển lên một dòng.
Hermann Ingjaldsson

2
tôi đặt phương thức này trong vimrc của mình nhưng sau đó tôi không thể lặp lại lệnh bằng cách sử dụng '.'. Có ai biết tại sao không?
Hermann Ingjaldsson

Rất đẹp! Không thoải mái như giải pháp trong Notepad ++, nhưng vẫn - thực tế và đang hoạt động.
Arturas M

Hermann, Xin lỗi, lỗi đánh máy / lỗi từ phía tôi, bạn đã đúng ,: m -2 sẽ di chuyển nó lên một dòng. Tôi đã thay đổi nó. Cũng xin lỗi vì đã trả lời rất muộn (không chắc chắn về phần .vimrc) Chúc mừng
Serg

2
Di chuyển bằng lệnh hoạt động, nếu bạn muốn sử dụng nó trong các liên kết như các liên kết từ Notepad ++ như OP đã yêu cầu, bạn cần nhập thông tin sau vào .vimrc:noremap <c-s-up> :m -2<CR> noremap <c-s-down> :m +1<CR>
kap

74

Di chuyển một dòng lên: ddkP

Di chuyển một dòng xuống: ddp


1
có điều này trong vimrc không cho phép lặp lại lệnh bằng cách sử dụng '.'
Hermann Ingjaldsson

@HermannIngjaldsson, tôi cho rằng bạn có thể gói lệnh trong một hàm nếu bạn muốn có thể sử dụng .để lặp lại.
jacobsimeon

Yess, .. và nếu bạn cần di chuyển nhiều dòng hơn, bạn có thể sử dụng V thay vì dd.
cảm biến

15

Điều này làm việc cho tôi:

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

BTW, nếu bạn muốn sử dụng ALT + some_key và thiết bị đầu cuối của bạn (urxvt làm điều này) từ chối tuân thủ, bạn nên nhập một cái gì đó như thế này trong .vimrc của bạn:

" 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

trong đó ^] là một ký tự đại diện cho phím ALT. Để nhập ký tự đó, sử dụng C+v, Esctrong Vim ( C+q, Esctrên Windows).


1
Điều này là tốt, sử dụng lệnh tích hợp của Vim để di chuyển một dòng. Nó có nhiều khả năng cư xử độc đáo khi đối mặt với hoàn tác hoặc lỗi.
Josh Lee

1
Tại sao bạn không nhập Esc dưới dạng <kbd> Cv <kbd /> <kbd> Esc </ kbd> (linux). Windows thay thế <kbd> Cv <kbd /> bằng <kbd> Cq <kbd /> trên bảng nhưng có cùng cách để nhập bất kỳ khóa đặc biệt nào trong chế độ chèn / lệnh
sehe

@sehe: Cảm ơn, lúc đó tôi không biết điều đó. Tôi đã cập nhật câu trả lời.
emil.p.stanchev

1
@RafaelRinaldi, [niv]noremaplà bản remaps cho chế độ hình ảnh bình thường | chèn | <CR>Carriage Return( Enterchính).
vp_arth

1
@vp_arth Không có không
sehe

13

thêm tệp sau vào tệp ~ / .vimrc (đảm bảo bạn không có ánh xạ cho n, m)

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

bây giờ nhấn nphím sẽ di chuyển một dòng xuống và msẽ di chuyển một dòng lên.


12

Trong chế độ lệnh, vị trí con trỏ trên dòng bạn muốn di chuyển xuống, và sau đó

ddp

Giải thích: dd xóa dòng hiện tại vào bộ đệm chung p đặt nó trở lại SAU vị trí con trỏ hoặc trong trường hợp toàn bộ dòng, một dòng bên dưới.

Có một số nhầm lẫn liên quan đến lệnh p và P trong nhiều tài liệu. Trong thực tế, p dán con trỏ SAU và con trỏ P AT.


8

Chỉ cần thêm mã này vào .vimrc (hoặc .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
Theo vim.wikia.com/wiki/ đá hãy xem đó để được giải thích toàn diện.
Serge Stroobandt

Trên máy Mac <A-Something> không hoạt động, tôi không biết tại sao. Tôi đã thay thế bằng <Cj> <Ck> và hoạt động tốt bằng phím Ctrl.
Cédric NICOLAS



3

Tôi đặt phần sau vào cuối tệp .vimrc của mình:

noremap H ddkkp
noremap N ddp

Vì vậy, bây giờ 'H' và 'N' di chuyển dòng hiện tại lên và xuống tương ứng.


H và N thực sự là các lệnh hữu ích (H di chuyển con trỏ lên trên cùng và bắt đầu màn hình, N di chuyển đến kết quả tìm kiếm trước đó), vì vậy tôi khuyên bạn nên sử dụng các khóa khác nhau
Villapx

Tôi hiểu rồi. Tôi cũng đã cấu hình lại chúng. Để lên trên cùng của màn hình, tôi nhấn a và sau đó lên. A luôn luôn có nghĩa là tất cả các cách trong sách của tôi. Và để tìm kiếm thông qua kết quả trước đó, tôi nhấn f và sau đó rời đi. F sau đó là viết tắt của find. Nhưng đối với những người không có nó như vậy thì ừ .. nó hợp lệ.
Hermann Ingjaldsson

1

Đây là phiên bản đơn giản hóa, dành cho MacVim, sử dụng các ví dụ về bài viết Wikia (xem liên kết từ nhận xét của súng ).

" 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

Tôi chỉ sử dụng biến thể chọn khối, vì tất cả chỉ cần Shift-V để chọn dòng hiện tại và tùy chọn con trỏ lên / xuống để chọn thêm một số dòng.

Theo các phím tắt ở trên, nhấn Cmd-Shift-Up / Down sẽ thay đổi lựa chọn khối lên / xuống. "D" là phím Lệnh trong MacVim, đối với Windows, hãy thử "C" (Điều khiển) hoặc "A" (Alt) (ví dụ: <CAf> sẽ là Control Alt f).

Bài viết Wikia thêm "= gv" vào những điều này, có tác dụng điều chỉnh độ thụt của khối sau khi di chuyển, dựa trên văn bản xung quanh. Điều này gây nhầm lẫn vì vậy tôi đã xóa nó và thêm các phím tắt để nhanh chóng thụt vào lựa chọn.

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

Lưu ý, điều tương tự cũng có thể được thực hiện với << và >> nhưng lựa chọn sẽ bị mất, vì vậy các phím tắt ở trên cho phép thụt lề nhiều lần và vẫn di chuyển khối xung quanh vì lựa chọn được duy trì.

MacVim của tôi được cấu hình để chuyển Tab bằng Cmd-Shift-Left / Right vì vậy tôi đã sử dụng Cmd-Alt-Left / Right.

Đây là Tab chuyển đổi cho MacVim (đặt .gvimrc với phần còn lại ở trên):

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

1

vim plugin unimpaired.vim [e và] e


2
Điều này có vẻ như quá mức cần thiết, tôi không nghĩ rằng bạn thực sự cần một plugin đầy đủ cho việc này. 2 dòng trong vimrc thực hiện chính xác những gì OP muốn
Daniel Gratzer

1

Khi bạn nhấn lệnh :help movein vim, đây là kết quả:

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

Ví dụ: Di chuyển dòng hiện tại xuống một dòng => :m+1 .

Ví dụ: Di chuyển dòng có số 100 bên dưới dòng có số 80 => :100 m 80 .

Ví dụ: Di chuyển dòng có số 100 bên dưới dòng có số 200 => :100 m 200 .

Ví dụ: Di chuyển các dòng có số trong [100, 120] bên dưới dòng có số 200 => :100,120 m 200 .


1

Đây là một giải pháp hoạt động trên máy của tôi : MacBook Pro chạy VIM 8.1

Các lệnh này sẽ không xóa các dòng của bạn ở đầu hoặc cuối bộ đệm của bạn.

Sử dụng các ký hiệu thực tế mà đầu ra Alt-J và Alt-K là một cách giải quyết cho các mã khóa của chúng không ánh xạ đúng trong môi trường của tôi.

Ném cái này vào .vimrc cũ và xem nếu nó hoạt động cho bạn.

" 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

1

Đối với tôi, ddkkpđã làm điều đó (thay vì ddkPvới chữ P viết hoa, nó cũng sẽ hoạt động).


0

: m. + 1 hoặc: m.-2 sẽ làm gì nếu bạn di chuyển một dòng. Đây là kịch bản của tôi để di chuyển nhiều dòng. Trong chế độ trực quan, Alt-up / Alt-down sẽ di chuyển các dòng chứa lựa chọn trực quan lên / xuống theo một dòng. Trong chế độ chèn hoặc chế độ bình thường, Alt-up / Alt-down sẽ di chuyển dòng hiện tại nếu không có tiền tố đếm được đưa ra. Nếu có tiền tố đếm, Alt-up / Alt-down sẽ di chuyển nhiều dòng bắt đầu từ dòng hiện tại lên / xuống theo một dòng.

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

Trong trường hợp bạn muốn làm điều này trên nhiều dòng khớp với một tìm kiếm cụ thể:

  • Lên: :g/Your query/ normal ddphoặc:g/Your query/ m -1
  • Xuống :g/Your query/ normal ddphoặc:g/Your query/ m +1
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.