Mueve toda la línea hacia arriba y hacia abajo en Vim


311

En Notepad ++, puedo usar Ctrl+ Shift+ Up/ Downpara mover la línea actual hacia arriba y hacia abajo. ¿Hay un comando similar a esto en Vim? He buscado en interminables guías, pero no he encontrado nada.

Si no lo hay, ¿cómo podría vincular la acción a esa combinación de teclas?

Editar: la respuesta de Mykola funciona para todas las líneas, excepto las del principio y el final del búfer. Mover la primera línea hacia arriba o la línea inferior hacia abajo elimina la línea, y cuando mueve la línea inferior hacia arriba, salta inicialmente dos espacios, ¡como un peón! ¿Alguien puede ofrecer algún refinamiento?


No tuve más remedio que implementar una solución de secuencias de comandos. Espero que sea limpio y adoptable para sus necesidades.
Mykola Golubyev

31
Para vosotros, hijos del futuro: vim.wikia.com/wiki/Moving_lines_up_or_down
armas

No estoy seguro de por qué necesita un script, los ejemplos de artículos de Wikia funcionan. He publicado a continuación una versión simplificada, porque el ejemplo de Wikia con 3 modos de mapeo diferentes puede ser bastante desalentador (y no realmente necesario. Si usa solo las asignaciones de selección de bloque, entonces simplemente puede recordar bloquear selección (Shift V) y usar estos atajos (ver mi respuesta a continuación).

Screencast sobre el tema: vimcasts.org/e/26
glts

También en vi SE
cfi

Respuestas:


81

Ponga lo siguiente en su .vimrc para hacer el trabajo

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

La desaparición de la línea parece un error de Vim. Puse un truco para evitarlo. Probablemente hay una solución más precisa.

Actualizar

Hay muchas dificultades inexplicables con solo usar combinaciones de Vim. Estas son líneas faltantes y saltos de línea adicionales.

Así que aquí está la solución de secuencias de comandos que se puede colocar dentro de .vimrc o ~ / .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
Tuve que cambiar a <cj> y <ck> ya que parece haber un choque con mi configuración, ¡pero respuesta fantástica! Muchas gracias
User4812

1
Gracias, genial por git rebase --interactive. Tuve que enlazar a <cj> y <ck>. cs-up / down no funcionó.
Lari Hotari

2
Si alguien quiere un atajo diferente: c es para control, A es para alt, yo uso <A-up>como se usa en eclipse.
enero

1
¡La línea que desaparece no es un error de Vim! Es más bien debido al desempeño ddkPen la última línea del documento. Pruébelo usted mismo en un archivo de 3 líneas. Para evitar tales problemas, utilice las :masignaciones mucho más fáciles que figuran en el wiki de Vim .
Serge Stroobandt

1
Cambié las últimas líneas a <A-up>y, <A-down>pero cuando pruebo esas teclas en vim en ejecución visual en tmux, la selección desaparece y el cursor se mueve en línea; sin mover las líneas seleccionadas.
Konrad

574

Si quiero intercambiar una línea con la línea de arriba, generalmente hago lo siguiente

ddkP

Explicación

  • dd eliminará la línea y la agregará al registro predeterminado.
  • k se moverá hacia arriba una línea (j se movería hacia abajo una línea)
  • P pegará sobre la línea actual

55
Y siempre está disponible también. :-)
Henno

71
Y ddppara mover una línea hacia abajo (eliminar línea y pegar debajo de la línea actual)
bcoughlan

2
Para mover un montón de líneas, diga 4 4 ddy luego muévase a, diga 2 líneas, luego :2donde quiera pegar y P.
Gurú

2
@Guru debería ser 4ddeso en lugar de 4 dd?
Patrick McDonald

3
Y dd<number>jppara mover la línea actual <número> +1 de líneas hacia abajo. Y dd<number>kppara mover la línea actual <número> de líneas hacia arriba.
egelev

230

Suponiendo que el cursor esté en la línea que desea mover.

Moviéndose hacia arriba y hacia abajo: :mpara moverse

:m +1 - baja 1 línea

:m -2 - subir 1 líneas

(Tenga en cuenta que puede reemplazar +1 con cualquier número dependiendo de cuántas líneas desee moverlo hacia arriba o hacia abajo, es decir, +2 lo movería hacia abajo 2 líneas, -3 lo movería hacia arriba 2 líneas)

Para moverse a una línea específica

:set number - mostrar líneas de números (más fácil ver a dónde lo está moviendo)

:m 3 - mueva la línea después de la tercera línea (reemplace 3 por cualquier línea que desee)

Moviendo múltiples líneas:

V(es decir, Shift- V) y mueva el cursor hacia arriba y hacia abajo para seleccionar varias líneas en VIM

una vez seleccionado, presione :y ejecute los comandos anteriores, m +1etc.


14
para mí: m -2 solo se mueve hacia arriba una línea.
Fzs2

2
puse este método en mi vimrc pero luego no puedo repetir el comando usando '.'. ¿Alguien sabe por qué es eso?
Fzs2

¡Muy agradable! No es tan cómodo como la solución en Notepad ++, pero sigue siendo real y funcional.
Arturas M

Hermann, lo siento, error tipográfico / error de mi parte, tienes razón: m -2 lo moverá una línea hacia arriba. Lo cambie. También lo siento por una respuesta muy tardía (no estoy seguro acerca de la parte .vimrc) Saludos
Serg

2
Mover usando el comando funciona, si desea usarlo en enlaces como los de Notepad ++ como lo solicitó el OP, debe ingresar lo siguiente en .vimrc:noremap <c-s-up> :m -2<CR> noremap <c-s-down> :m +1<CR>
kap

74

Mover una línea hacia arriba: ddkP

Mueve una línea hacia abajo: ddp


1
tener esto en vimrc no permite repetir el comando usando '.'
Fzs2

@HermannIngjaldsson, supongo que podría ajustar el comando en una función si quisiera poder .repetir.
jacobsimeon

Sí, ... y si necesita mover más líneas, puede usar V en lugar de dd.
sensorario

15

Esto funcionó para mí:

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

Por cierto, si desea usar ALT + some_key y su terminal (urxvt hace esto) se niega a cumplir, debe ingresar algo como esto en su .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

donde ^] es un solo carácter que representa la tecla ALT. Para ingresar ese carácter, C+v, Escúselo en Vim ( C+q, Escen Windows).


1
Esto es bueno, usando el comando incorporado de Vim para mover una línea. Es más probable que se comporte bien frente a deshacer o un error.
Josh Lee

1
¿Por qué no ingresas Esc como <kbd>Cv<kbd/> <kbd> Esc </kbd> (linux). Windows reemplaza <kbd> Cv <kbd /> por <kbd> Cq <kbd /> a través del tablero, pero tiene la misma forma de entrar en cualquier tecla especial en el modo de inserción / comando
sehe

@sehe: Gracias, no lo sabía en ese momento. He actualizado la respuesta.
emil.p.stanchev

1
@RafaelRinaldi, [niv]noremapson remapeos para los modos normales | insert | visual. <CR>es Carriage Return( Enterclave)
vp_arth

1
@vp_arth No, no hay
sehe

13

agregue lo siguiente al archivo ~ / .vimrc (asegúrese de no tener asignación para n, m)

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

ahora presionando la ntecla se moverá una línea hacia abajo y mse moverá una línea hacia arriba.


12

En el modo de comando, coloque el cursor en la línea que desea mover hacia abajo y luego

ddp

Explicación: dd elimina la línea actual al búfer general p la vuelve a colocar DESPUÉS de la posición del cursor, o en el caso de líneas enteras, una línea debajo.

Existe cierta confusión con respecto a los comandos p y P en muchos documentos. En realidad, p pega el cursor DESPUÉS y el cursor P AT.


8

Simplemente agregue este código a .vimrc (o .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
Según vim.wikia.com/wiki/…, consulte allí para obtener una explicación completa.
Serge Stroobandt

En una Mac, <A-algo> no funciona, no sé por qué. He reemplazado con <Cj> <Ck>, y funciona bien con la tecla Ctrl.
Cédric NICOLAS



3

Puse lo siguiente al final de mi archivo .vimrc:

noremap H ddkkp
noremap N ddp

Así que ahora 'H' y 'N' mueven la línea actual hacia arriba y hacia abajo respectivamente.


H y N son en realidad comandos útiles (H mueve el cursor a la parte superior y al comienzo de la pantalla, N mueve al resultado de búsqueda anterior), por lo que recomendaría usar diferentes teclas
villapx

Veo. También los he reconfigurado. Para ir a la parte superior de la pantalla, presiono ay luego hacia arriba. A siempre significa todo el camino en mis libros. Y para buscar en los resultados anteriores, presiono f y luego me fui. F entonces significa encontrar. Pero para aquellos que no lo tienen así, sí ... es válido.
Fzs2

1

Aquí hay una versión simplificada, para MacVim, usando los ejemplos del artículo de Wikia (véase el enlace del comentario de 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

Estoy usando solo la variante de selección de bloque, porque todo lo que se necesita es Shift-V para seleccionar la línea actual, y opcionalmente el cursor hacia arriba / abajo para seleccionar algunas líneas más.

De acuerdo con los atajos anteriores, presionar Cmd-Shift-Up / Down desplazará la selección de bloque hacia arriba / abajo. "D" es la tecla Comando en MacVim, para Windows intente con "C" (Control) o "A" (Alt) (por ejemplo, <CAf> sería Control Alt f).

El artículo de Wikia agrega "= gv" a estos, lo que tiene el efecto de ajustar la sangría del bloque después del movimiento, según el texto circundante. Esto es confuso, así que lo eliminé y agregué accesos directos para sangrar rápidamente la selección.

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

Tenga en cuenta que lo mismo se puede hacer con << y >>, pero la selección se perdería, por lo que estos accesos directos anteriores permiten sangrar varias veces y aún mover el bloque porque la selección se mantiene.

Mi MacVim está configurado para cambiar las pestañas con Cmd-Shift-Izquierda / Derecha, así que usé Cmd-Alt-Izquierda / Derecha.

Aquí está el cambio de Tab para MacVim (poner en .gvimrc con el resto de arriba):

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

1

vim plugin unimpaired.vim [e y] e


2
Esto parece excesivo, no creo que realmente necesites un complemento completo para esto. 2 líneas en un vimrc hace exactamente lo que quiere el OP
Daniel Gratzer

1

Al llegar a comandos :help moveen vim, aquí está el resultado:

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

Por ejemplo: mover la línea actual una línea hacia abajo => :m+1 .

Por ejemplo: mover la línea con el número 100 debajo de la línea con el número 80 => :100 m 80 .

Por ejemplo: mover la línea con el número 100 debajo de la línea con el número 200 => :100 m 200 .

Por ejemplo: mover líneas con número dentro de [100, 120] debajo de la línea con número 200 => :100,120 m 200 .


1

Aquí hay una solución que funciona en mi máquina : MacBook Pro con VIM 8.1

Estos comandos no eliminarán sus líneas en la parte superior o inferior de su búfer.

El uso de los símbolos reales que Alt-J y Alt-K generan es una solución alternativa para que sus códigos clave no se asignen correctamente en mi entorno.

Lance esto en el viejo .vimrc y vea si funciona para usted.

" 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 o: m.-2 lo harían si estás moviendo una sola línea. Aquí está mi script para mover varias líneas. En modo visual, Alt-arriba / Alt-abajo moverá las líneas que contienen la selección visual arriba / abajo en una línea. En modo de inserción o modo normal, Alt-arriba / Alt-abajo moverá la línea actual si no se proporciona el prefijo de conteo. Si hay un prefijo de conteo, Alt-up / Alt-down moverá esa cantidad de líneas comenzando desde la línea actual hacia arriba / abajo en una línea.

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

En caso de que quiera hacer esto en varias líneas que coincidan con una búsqueda específica:

  • Arriba: :g/Your query/ normal ddpo:g/Your query/ m -1
  • Abajo :g/Your query/ normal ddpo:g/Your query/ m +1
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.