Déplacer toute la ligne de haut en bas dans Vim

311

Dans Notepad ++, je peux utiliser Ctrl+ Shift+ Up/ Downpour déplacer la ligne actuelle de haut en bas. Existe-t-il une commande similaire à celle-ci dans Vim? J'ai parcouru des guides sans fin, mais je n'ai rien trouvé.

Si ce n'est pas le cas, comment pourrais-je lier l'action à cette combinaison de touches?

Edit: la réponse de Mykola fonctionne pour toutes les lignes, à l'exception de celles au début et à la fin du tampon. Déplacer la première ligne vers le haut ou la ligne du bas vers le bas supprime la ligne, et lorsque vous déplacez la ligne du bas vers le haut, elle saute initialement de deux espaces, comme un pion! Quelqu'un peut-il apporter des améliorations?

user4812
la source
Je n'avais pas d'autre choix que d'implémenter une solution de script. J'espère qu'il est propre et adaptable à vos besoins.
Mykola Golubyev, le
31
Pour vous les enfants du futur: vim.wikia.com/wiki/Moving_lines_up_or_down
guns
Je ne sais pas pourquoi vous avez besoin d'un script, les exemples d'articles Wikia fonctionnent. J'ai posté ci-dessous une version simplifiée, car l'exemple de Wikia avec 3 modes de mappage différents peut être assez intimidant (et pas vraiment nécessaire. Si vous utilisez uniquement les mappages de sélection de bloc, vous pouvez simplement vous rappeler de bloquer la sélection (Shift V) et d'utiliser ces raccourcis (voir ma réponse ci-dessous).
Screencast sur le sujet: vimcasts.org/e/26
glts
Également sur vi SE
cfi

Réponses:

81

Mettez ce qui suit dans votre .vimrc pour faire le travail

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

La disparition de la ligne ressemble à un bug de Vim. J'ai mis un hack pour l'éviter. Il existe probablement une solution plus précise.

Mettre à jour

Il y a beaucoup de difficultés inexpliquées à utiliser uniquement des combinaisons Vim. Ce sont des lignes manquantes et des sauts de ligne supplémentaires.

Voici donc la solution de script qui peut être placée à l'intérieur de .vimrc ou ~ / .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>
Mykola Golubyev
la source
1
J'ai dû changer en <cj> et <ck> car il semble y avoir un conflit avec ma configuration, mais une réponse fantastique! Merci beaucoup
user4812
1
Merci, super pour git rebase - interactif. A dû se lier à <cj> et <ck>. cs-up / down n'a pas fonctionné.
Lari Hotari
2
Si quelqu'un veut un raccourci différent: c est pour le contrôle, A est pour alt, j'utilise <A-up>comme utilisé dans eclipse.
janvier
1
La ligne qui disparaît n'est pas un bug Vim! C'est plutôt dû à la performance ddkPsur la dernière ligne du document. Essayez-le par vous-même sur un fichier de 3 lignes. Pour éviter de tels problèmes, utilisez plutôt les :mmappages beaucoup plus faciles donnés sur le wiki Vim .
Serge Stroobandt
1
J'ai changé les dernières lignes en <A-up>et <A-down>mais quand j'essaie ces touches dans vim en visual running dans tmux, la sélection disparaît et le curseur se déplace vers le haut; sans déplacer les lignes sélectionnées.
Konrad
574

Si je veux échanger une ligne avec la ligne ci-dessus, je fais généralement ce qui suit

ddkP

Explication

  • dd supprimera la ligne et l'ajoutera au registre par défaut.
  • k se déplacera d'une ligne (j se déplacera d'une ligne)
  • P va coller au-dessus de la ligne actuelle
JaredPar
la source
5
Et c'est toujours disponible aussi. :-)
Henno
71
Et ddppour déplacer une ligne vers le bas (supprimer la ligne et la coller sous la ligne actuelle)
bcoughlan
2
Pour déplacer un groupe de lignes, dites 4, 4 ddpuis passez à, disons 2 lignes, puis à l' :2endroit où vous souhaitez coller et P.
Guru
2
@Guru devrait-il être 4ddau lieu de 4 dd?
Patrick McDonald
3
Et dd<number>jppour déplacer la ligne actuelle <numéro> +1 de lignes vers le bas. Et dd<number>kppour déplacer la ligne actuelle <numéro> de lignes vers le haut.
egelev
230

En supposant que le curseur se trouve sur la ligne que vous souhaitez déplacer.

Monter et descendre: :mpour se déplacer

:m +1 - descend d'une ligne

:m -2 - remonter de 1 lignes

(Notez que vous pouvez remplacer +1 par n'importe quel nombre en fonction du nombre de lignes que vous souhaitez déplacer vers le haut ou vers le bas, c'est-à-dire que +2 le déplacerait vers le bas de 2 lignes, -3 le déplacerait vers le haut de 2 lignes)

Pour passer à une ligne spécifique

:set number - afficher les lignes numériques (plus facile à voir où vous le déplacez)

:m 3 - déplacez la ligne après la 3ème ligne (remplacez 3 par la ligne de votre choix)

Déplacement de plusieurs lignes:

V(c.-à Shift- d . V) et déplacez le coursier de haut en bas pour sélectionner plusieurs lignes dans VIM

une fois sélectionné, appuyez sur :et exécutez les commandes ci-dessus, m +1etc.

Serg
la source
14
pour moi: m -2 ne monte que d'une ligne.
Fzs2
2
j'ai mis cette méthode dans mon vimrc mais je ne peux pas répéter la commande en utilisant '.'. est-ce que quelqu'un sait pourquoi c'est?
Fzs2
Très agréable! Pas aussi confortable que la solution dans Notepad ++, mais toujours - réel et fonctionnel.
Arturas M
Hermann, Désolé, faute de frappe / erreur de ma part, vous avez raison: m -2 le fera remonter d'une ligne. Je l'ai changé. Aussi désolé pour la réponse très tardive (pas sûr de la partie .vimrc) Cheers
Serg
2
Le déplacement à l'aide de la commande fonctionne, si vous souhaitez l'utiliser dans des liaisons telles que celles de Notepad ++ comme l'OP l'a demandé, vous devez saisir ce qui suit dans .vimrc:noremap <c-s-up> :m -2<CR> noremap <c-s-down> :m +1<CR>
kap
74

Déplacer une ligne vers le haut: ddkP

Déplacer une ligne vers le bas: ddp

jacobsimeon
la source
1
avoir ceci dans le vimrc ne permet pas de répéter la commande en utilisant '.'
Fzs2
@HermannIngjaldsson, je suppose que vous pouvez encapsuler la commande dans une fonction si vous voulez pouvoir la .répéter.
jacobsimeon
Oui, .. et si vous devez déplacer plus de lignes, vous pouvez utiliser V au lieu de dd.
sensorario
15

Cela a fonctionné pour moi:

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

BTW, si vous souhaitez utiliser ALT + some_key et que votre terminal (urxvt le fait) refuse de se conformer, vous devez saisir quelque chose comme ceci dans votre .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

où ^] est un caractère unique qui représente la touche ALT. Pour saisir ce caractère, utilisez-le C+v, Escdans Vim ( C+q, Escsous Windows).

emil.p.stanchev
la source
1
C'est bien, en utilisant la commande intégrée de Vim pour déplacer une ligne. Il est plus probable qu'il se comporte bien en cas d'annulation ou d'erreur.
Josh Lee
1
Pourquoi ne saisissez-vous pas Esc en tant que <kbd>Cv<kbd/> <kbd> Esc </kbd> (linux). Windows remplace <kbd> Cv <kbd /> par <kbd> Cq <kbd /> dans tous les domaines, mais a la même façon d'entrer une clé spéciale en insertion / mode de commande
sehe
@sehe: Merci, je ne le savais pas à l'époque. J'ai mis à jour la réponse.
emil.p.stanchev
1
@RafaelRinaldi, [niv]noremapsont des remappages pour les modes visuels normaux | insert |. <CR>est Carriage Return( Enterclé).
vp_arth
1
@vp_arth Non il n'y a pas
sehe
13

ajoutez ce qui suit au fichier ~ / .vimrc (assurez-vous que vous n'avez pas de mappage pour n, m)

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

maintenant, appuyez sur la ntouche pour déplacer une ligne vers le bas et mpour déplacer une ligne vers le haut.

Gajendra Jena
la source
12

En mode commande, placez le curseur sur la ligne que vous souhaitez déplacer vers le bas, puis

ddp

Explication: dd supprime la ligne courante dans le tampon général p la remet APRÈS la position du curseur, ou dans le cas de lignes entières, une ligne en dessous.

Il existe une certaine confusion concernant les commandes p et P dans de nombreux documents. En réalité, p colle APRES le curseur et P AT le curseur.

szg
la source
8

Ajoutez simplement ce code à .vimrc (ou .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
alexkv
la source
1
Selon vim.wikia.com/wiki/…, voir là pour une explication complète.
Serge Stroobandt
Sur un Mac, <A-quelque chose> ne fonctionne pas, je ne sais pas pourquoi. J'ai remplacé par <Cj> <Ck>, et fonctionne bien en utilisant la touche Ctrl.
Cédric NICOLAS
5

Exactement ce que vous recherchez dans ce plugin génial: https://github.com/vim-scripts/upAndDown

timoxley
la source
1
Il prend également en charge plusieurs lignes, ce qui est bien.
studgeek
Que signifie la touche <S>?
UsamaMan
@UsamaMan Shift modifier
mazunki
5

Une solution simple est de mettre dans vos .vimrclignes:

nmap <C-UP> :m-2<CR>  
nmap <C-DOWN> :m+1<CR>
Geraldo Luis da Silva Ribeiro
la source
3

J'ai mis ce qui suit à la fin de mon fichier .vimrc:

noremap H ddkkp
noremap N ddp

Alors maintenant, «H» et «N» déplacent la ligne actuelle de haut en bas respectivement.

Fzs2
la source
H et N sont en fait des commandes utiles (H déplace le curseur vers le haut et le début de l'écran, N déplace vers le résultat de recherche précédent), donc je recommanderais d'utiliser des touches différentes
villapx
Je vois. Je les ai également reconfigurés. Pour aller en haut de l'écran, j'appuie sur a puis sur. A signifie toujours tout le chemin dans mes livres. Et pour rechercher les résultats précédents, j'appuie sur f, puis à gauche. F signifie alors trouver. Mais pour ceux qui ne l'ont pas comme ça, alors oui ... c'est valable.
Fzs2
1

Voici une version simplifiée, pour MacVim, utilisant les exemples d'articles de Wikia (cf. lien du commentaire 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

J'utilise uniquement la variante de sélection de bloc, car tout ce qu'il faut, c'est Shift-V pour sélectionner la ligne actuelle, et éventuellement le curseur haut / bas pour sélectionner d'autres lignes.

Selon les raccourcis ci-dessus, appuyez sur Cmd-Shift-Up / Down pour déplacer la sélection de bloc vers le haut / bas. "D" est la clé de commande dans MacVim, pour Windows, essayez "C" (Contrôle) ou "A" (Alt) (par exemple. <CAf> serait Contrôle Alt f).

L'article de Wikia ajoute "= gv" à ceux-ci, ce qui a pour effet d'ajuster l'indentation du bloc après le déplacement, en fonction du texte environnant. C'est déroutant, je l'ai donc supprimé et j'ai ajouté des raccourcis pour indenter rapidement la sélection à la place.

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

Attention, la même chose peut être faite avec << et >> mais la sélection serait perdue, donc ces raccourcis ci-dessus permettent de mettre plusieurs fois en retrait et de déplacer le bloc car la sélection est maintenue.

Mon MacVim est configuré pour changer d'onglet avec Cmd-Maj-Gauche / Droite, j'ai donc utilisé Cmd-Alt-Gauche / Droite.

Voici le changement d'onglet pour MacVim (mis en .gvimrc avec le reste ci-dessus):

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

la source
1

plugin vim unimpaired.vim [e et] e

Baranina
la source
2
Cela semble exagéré, je ne pense pas que vous ayez vraiment besoin d'un plugin complet pour cela. 2 lignes dans un vimrc font exactement ce que l'OP veut
Daniel Gratzer
1

Lorsque vous appuyez sur commande :help movedansvim , voici le résultat:

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

Par exemple: Déplacer la ligne actuelle d'une ligne vers le bas => :m+1 .

Par exemple: déplacer la ligne avec le numéro 100 en dessous de la ligne avec le numéro 80 => :100 m 80 .

Par exemple: déplacer la ligne avec le numéro 100 en dessous de la ligne avec le numéro 200 => :100 m 200 .

Par exemple: déplacer les lignes avec un nombre entre [100, 120] en dessous de la ligne avec le numéro 200 => :100,120 m 200 .

ako
la source
1

Voici une solution qui fonctionne sur ma machine : MacBook Pro sous VIM 8.1

Ces commandes ne supprimeront pas vos lignes en haut ou en bas de votre tampon.

L'utilisation des symboles réels produits par Alt-J et Alt-K est une solution de contournement pour leurs codes-clés qui ne correspondent pas correctement dans mon environnement.

Jetez-le dans l'ancien .vimrc et voyez si cela fonctionne pour vous.

" 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
Nick Sugar
la source
1

Pour moi, l'a ddkkpfait (au lieu d' ddkPun P majuscule, qui fonctionnerait aussi).

Guillaume Chevalier
la source
0

: m. + 1 ou: m.-2 ferait l'affaire si vous déplacez une seule ligne. Voici mon script pour déplacer plusieurs lignes. En mode visuel, Alt-up / Alt-down déplace les lignes contenant la sélection visuelle vers le haut / bas d'une ligne. En mode insertion ou en mode normal, Alt-up / Alt-down déplacera la ligne actuelle si aucun préfixe de comptage n'est donné. S'il y a un préfixe de comptage, Alt-up / Alt-down déplacera ce nombre de lignes à partir de la ligne actuelle vers le haut / bas d'une ligne.

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
Ji Han
la source
0

Si vous souhaitez effectuer cette opération sur plusieurs lignes correspondant à une recherche spécifique:

  • Up: :g/Your query/ normal ddpou:g/Your query/ m -1
  • Vers le bas :g/Your query/ normal ddpou:g/Your query/ m +1
Gleb Sabirzyanov
la source