Bewegen Sie die gesamte Linie in Vim auf und ab

311

In Notepad ++ kann ich Ctrl+ Shift+ Up/ verwenden Down, um die aktuelle Zeile nach oben und unten zu verschieben. Gibt es einen ähnlichen Befehl wie in Vim? Ich habe endlose Führer durchgesehen, aber nichts gefunden.

Wenn nicht, wie kann ich die Aktion an diese Tastenkombination binden?

Bearbeiten: Die Antwort von Mykola funktioniert für alle Zeilen, außer für die am Anfang und Ende des Puffers. Wenn Sie die erste Zeile nach oben oder unten verschieben, wird die Zeile gelöscht, und wenn Sie die untere Zeile nach oben verschieben, werden zunächst zwei Felder wie bei einem Bauern übersprungen! Kann jemand irgendwelche Verfeinerungen anbieten?

user4812
quelle
Ich hatte keine andere Wahl, als eine Skriptlösung zu implementieren. Ich hoffe, es ist sauber und für Ihre Bedürfnisse anpassbar.
Mykola Golubyev
31
Für die Kinder der Zukunft: vim.wikia.com/wiki/Moving_lines_up_or_down
Waffen
Ich bin mir nicht sicher, warum Sie ein Skript benötigen. Die Beispiele für Wikia-Artikel funktionieren. Ich habe unten eine vereinfachte Version gepostet, da das Beispiel von Wikia mit 3 verschiedenen Zuordnungsmodi ziemlich entmutigend sein kann (und nicht wirklich notwendig ist. Wenn Sie nur die Blockauswahlzuordnungen verwenden, können Sie einfach daran denken, die Blockauswahl (Shift V) zu verwenden und zu verwenden diese Verknüpfungen (siehe meine Antwort unten).
Screencast zum Thema: vimcasts.org/e/26
glts
Auch am vi SE
cfi

Antworten:

81

Stellen Sie Folgendes in Ihre .vimrc-Datei, um die Aufgabe zu erledigen

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

Das Verschwinden der Linie sieht aus wie ein Vim-Bug. Ich habe einen Hack gemacht, um das zu vermeiden. Wahrscheinlich gibt es eine genauere Lösung.

Aktualisieren

Es gibt viele ungeklärte Schwierigkeiten, nur Vim-Kombinationen zu verwenden. Dies sind fehlende Linien und zusätzliches Linienspringen.

Hier ist also die Skriptlösung, die entweder in .vimrc oder ~ / .vim / plugin / swap_lines.vim platziert werden kann

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
quelle
1
Musste zu <cj> und <ck> wechseln, da es einen Konflikt mit meinem Setup zu geben scheint, aber eine fantastische Antwort! Vielen Dank
user4812
1
Danke, großartig für Git Rebase - interaktiv. Musste an <cj> und <ck> binden. cs-up / down hat nicht funktioniert.
Lari Hotari
2
Wenn jemand eine andere Verknüpfung möchte: c ist für die Steuerung, A ist für alt, ich verwende <A-up>wie in Eclipse verwendet.
Januar
1
Die verschwindende Linie ist kein Vim-Fehler! Es liegt eher an der Ausführung ddkPin der letzten Zeile des Dokuments. Probieren Sie es selbst in einer 3-zeiligen Datei aus. Um solche Probleme zu vermeiden, verwenden Sie lieber die viel einfacheren :mZuordnungen, die im Vim-Wiki angegeben sind .
Serge Stroobandt
1
Ich änderte letzten Zeilen <A-up>und <A-down>aber wenn ich versuche , diese Schlüssel in vim in visuellen Lauf in tmux die Auswahl verschwindet und der Cursor bewegt sich in einer Reihe aufstellen; ohne die ausgewählten Linien zu verschieben.
Konrad
574

Wenn ich eine Zeile mit der obigen Zeile tauschen möchte, gehe ich normalerweise wie folgt vor

ddkP

Erläuterung

  • dd löscht die Zeile und fügt sie dem Standardregister hinzu.
  • k bewegt sich eine Linie nach oben (j bewegt sich eine Linie nach unten)
  • P wird über der aktuellen Zeile eingefügt
JaredPar
quelle
5
Und es ist auch immer verfügbar. :-)
Henno
71
Und ddpum eine Zeile nach unten zu verschieben (Zeile löschen und unter die aktuelle Zeile
einfügen
2
Um mehrere Zeilen zu verschieben, sagen Sie 4, 4 ddund bewegen Sie sich dann zu 2 Zeilen, :2wo Sie und einfügen möchten P.
Guru
2
@ Guru sollte das 4ddstatt sein 4 dd?
Patrick McDonald
3
Und dd<number>jpum die aktuelle Zeile <Nummer> +1 der Zeilen nach unten zu verschieben. Und dd<number>kpum die aktuelle Zeile <Anzahl> der Zeilen nach oben zu verschieben.
Egelev
230

Angenommen, der Cursor befindet sich auf der Linie, die Sie bewegen möchten.

Auf und ab :mbewegen : zum Bewegen

:m +1 - bewegt sich 1 Zeile nach unten

:m -2 - 1 Zeile nach oben bewegen

(Beachten Sie, dass Sie +1 durch beliebige Zahlen ersetzen können, je nachdem, wie viele Zeilen Sie nach oben oder unten verschieben möchten, dh +2 würde es um 2 Zeilen nach unten verschieben, -3 würde es um 2 Zeilen nach oben verschieben.)

Zu einer bestimmten Zeile wechseln

:set number - Zahlenzeilen anzeigen (leichter zu erkennen, wohin Sie sie verschieben)

:m 3 - Verschieben Sie die Zeile nach der 3. Zeile (ersetzen Sie 3 durch eine beliebige Zeile)

Mehrere Zeilen verschieben:

V(dh Shift- V) und bewegen Sie den Courser nach oben und unten, um mehrere Zeilen in VIM auszuwählen

Einmal ausgewählt, drücken Sie :die obigen Befehle m +1usw.

Serg
quelle
14
für mich: m -2 bewegt sich nur eine Zeile nach oben.
Hermann Ingjaldsson
2
Ich habe diese Methode in mein vimrc eingefügt, aber dann kann ich den Befehl nicht mit '.' wiederholen. Weiß jemand warum das so ist?
Hermann Ingjaldsson
Sehr schön! Nicht so komfortabel wie die Lösung in Notepad ++, aber dennoch - real und funktionsfähig.
Arturas M
Hermann, Entschuldigung, Tippfehler / Fehler meinerseits, Sie haben Recht: m -2 wird es eine Zeile nach oben verschieben. Ich habe es geändert. Entschuldigung auch für die sehr späte Antwort (nicht sicher über .vimrc Teil) Cheers
Serg
2
Das Verschieben mit dem Befehl funktioniert. Wenn Sie ihn in Bindungen wie denen von Notepad ++ verwenden möchten, wie es das OP verlangt, müssen Sie Folgendes in .vimrc eingeben:noremap <c-s-up> :m -2<CR> noremap <c-s-down> :m +1<CR>
kap
74

Verschieben Sie eine Zeile nach oben: ddkP

Bewegen Sie eine Zeile nach unten: ddp

jacobsimeon
quelle
1
Wenn Sie dies im vimrc haben, können Sie den Befehl nicht mit '.' wiederholen.
Hermann Ingjaldsson
@HermannIngjaldsson, ich nehme an, Sie könnten den Befehl in eine Funktion einschließen, wenn Sie ihn .wiederholen möchten .
Jacobsimeon
Ja, .. und wenn Sie mehr Zeilen verschieben müssen, können Sie V anstelle von dd verwenden.
Sensorario
15

Das hat bei mir funktioniert:

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

Übrigens, wenn Sie ALT + some_key verwenden möchten und Ihr Terminal (urxvt tut dies) die Einhaltung verweigert, sollten Sie Folgendes in Ihre .vimrc eingeben:

" 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

Dabei ist ^] ein einzelnes Zeichen , das die ALT-Taste darstellt. Verwenden Sie zur Eingabe dieses Zeichens C+v, EscVim ( C+q, Escunter Windows).

emil.p.stanchev
quelle
1
Dies ist gut, wenn Sie den integrierten Befehl von Vim zum Verschieben einer Linie verwenden. Es ist wahrscheinlicher, dass es sich angesichts von Rückgängigmachen oder Fehlern gut verhält.
Josh Lee
1
Warum geben Sie Esc nicht als <kbd> CV <kbd/> <kbd> Esc </ kbd> (Linux) ein? Windows ersetzt <kbd> Cv <kbd /> durch <kbd> Cq <kbd /> auf der ganzen Linie, hat aber die gleiche Möglichkeit, einen Sonderschlüssel im Einfüge- / Befehlsmodus
einzugeben
@sehe: Danke, das wusste ich damals noch nicht. Ich habe die Antwort aktualisiert.
emil.p.stanchev
1
@ RafaelRinaldi, [niv]noremapsind Remaps für normale | Einfüge | visuelle Modi. <CR>ist Carriage Return( EnterSchlüssel).
vp_arth
1
@vp_arth Nein, gibt es nicht
sehe
13

Fügen Sie der Datei ~ / .vimrc Folgendes hinzu (stellen Sie sicher, dass Sie keine Zuordnung für n, m haben).

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

Durch Drücken der nTaste wird eine Linie nach unten und meine Linie nach oben verschoben.

Gajendra Jena
quelle
12

Positionieren Sie im Befehlsmodus den Cursor auf der Zeile, die Sie nach unten bewegen möchten, und dann

ddp

Erläuterung: dd löscht die aktuelle Zeile in den allgemeinen Puffer. P setzt sie NACH der Cursorposition oder bei ganzen Zeilen eine Zeile darunter zurück.

In vielen Dokumenten gibt es einige Verwirrung hinsichtlich der Befehle p und P. In Wirklichkeit fügt p AFTER cursor und P AT cursor ein.

szg
quelle
8

Fügen Sie diesen Code einfach zu .vimrc (oder .gvimrc) hinzu.

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
quelle
1
Wie pro vim.wikia.com/wiki/... sehen für eine umfassende Erklärung gibt.
Serge Stroobandt
Auf einem Mac funktioniert <A-something> nicht, ich weiß nicht warum. Ich habe durch <Cj> <Ck> ersetzt und funktioniert gut mit der Strg-Taste.
Cédric NICOLAS
5

Genau das, wonach Sie in diesem fantastischen Plugin suchen : https://github.com/vim-scripts/upAndDown

Timoxley
quelle
1
Es unterstützt auch mehrere Zeilen, was sehr schön ist.
Studgeek
Wofür steht die Taste <S>?
UsamaMan
@UsamaMan Shift Modifikator
Mazunki
5

Eine einfache Lösung besteht darin, folgende .vimrcZeilen einzugeben:

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

Ich habe Folgendes am Ende meiner .vimrc-Datei eingefügt:

noremap H ddkkp
noremap N ddp

Jetzt bewegen 'H' und 'N' die aktuelle Linie nach oben bzw. unten.

Hermann Ingjaldsson
quelle
H und N sind eigentlich nützliche Befehle (H bewegt den Cursor nach oben und an den Anfang des Bildschirms, N bewegt sich zum vorherigen Suchergebnis), daher würde ich empfehlen, verschiedene Tasten zu verwenden
villapx
Aha. Ich habe sie auch neu konfiguriert. Um zum oberen Bildschirmrand zu gelangen, drücke ich a und dann nach oben. A bedeutet in meinen Büchern immer den ganzen Weg. Und um frühere Ergebnisse zu durchsuchen, drücke ich f und dann links. F steht dann für find. Aber für diejenigen, die es nicht so haben, dann ja ... es ist gültig.
Hermann Ingjaldsson
1

Hier ist eine vereinfachte Version für MacVim unter Verwendung der Wikia-Artikelbeispiele (siehe Link aus dem Kommentar der Waffe ).

" 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

Ich verwende nur die Blockauswahlvariante, da nur Umschalt-V erforderlich ist, um die aktuelle Zeile auszuwählen, und optional Cursor nach oben / unten, um weitere Zeilen auszuwählen.

Gemäß den obigen Verknüpfungen wird durch Drücken von Cmd-Shift-Up / Down die Blockauswahl nach oben / unten verschoben. "D" ist die Befehlstaste in MacVim, für Windows versuchen Sie "C" (Steuerelement) oder "A" (Alt) (z. B. <CAf> wäre Steuerelement Alt f).

Der Wikia-Artikel fügt diesen "= gv" hinzu, wodurch die Einrückung des Blocks nach dem Verschieben basierend auf dem umgebenden Text angepasst wird. Das ist verwirrend, deshalb habe ich es entfernt und stattdessen Verknüpfungen hinzugefügt, um die Auswahl schnell einzurücken.

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

Beachten Sie, dass dies auch mit << und >> möglich ist, die Auswahl jedoch verloren geht. Mit diesen Verknüpfungen können Sie den Block mehrmals einrücken und den Block trotzdem verschieben, da die Auswahl beibehalten wird.

Mein MacVim ist so konfiguriert, dass Tabs mit Cmd-Shift-Left / Right gewechselt werden, also habe ich Cmd-Alt-Left / Right verwendet.

Hier ist die Tab-Umschaltung für MacVim (geben Sie .gvimrc mit dem Rest oben ein):

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

quelle
1

vim plugin unimpaired.vim [e und] e

Baranina
quelle
2
Das scheint übertrieben, ich glaube nicht, dass Sie wirklich ein vollständiges Plugin dafür brauchen. 2 Zeilen in einem vimrc machen genau das, was das OP will
Daniel Gratzer
1

Wenn Sie den Befehl :help moveeingeben vim, ist hier das Ergebnis:

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

Beispiel: Verschieben Sie die aktuelle Zeile um eine Zeile nach unten => :m+1 .

Beispiel: Verschieben Sie die Zeile mit der Nummer 100 unter die Zeile mit der Nummer 80 => :100 m 80 .

Beispiel: Verschieben Sie die Zeile mit der Nummer 100 unter die Zeile mit der Nummer 200 => :100 m 200 .

Beispiel: Verschieben Sie Zeilen mit der Nummer innerhalb von [100, 120] unter die Zeile mit der Nummer 200 => :100,120 m 200 .

ako
quelle
1

Hier ist eine Lösung, die auf meinem Computer funktioniert : MacBook Pro mit VIM 8.1

Diese Befehle löschen Ihre Zeilen am oberen oder unteren Rand Ihres Puffers nicht.

Die Verwendung der tatsächlichen Symbole, die Alt-J und Alt-K ausgeben, ist eine Problemumgehung für ihre Schlüsselcodes, die in meiner Umgebung nicht richtig zugeordnet sind.

Werfen Sie dies in die alte .vimrc und sehen Sie, ob es für Sie funktioniert.

" 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
quelle
1

Für mich ddkkptat es (anstatt ddkPmit einem Großbuchstaben P, das auch funktionieren würde).

Guillaume Chevalier
quelle
0

: m. + 1 oder: m.-2 würde ausreichen, wenn Sie eine einzelne Linie verschieben. Hier ist mein Skript zum Verschieben mehrerer Zeilen. Im visuellen Modus werden die Zeilen mit der visuellen Auswahl durch Alt-Auf / Alt-Ab um eine Zeile nach oben / unten verschoben. Im Einfügemodus oder im normalen Modus verschiebt Alt-Up / Alt-Down die aktuelle Zeile, wenn kein Zählpräfix angegeben ist. Wenn es ein Zählpräfix gibt, verschiebt Alt-up / Alt-down so viele Zeilen, beginnend mit der aktuellen Zeile, um eine Zeile nach oben / unten.

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
quelle
0

Wenn Sie dies in mehreren Zeilen tun möchten, die einer bestimmten Suche entsprechen:

  • Oben: :g/Your query/ normal ddp oder:g/Your query/ m -1
  • Runter :g/Your query/ normal ddpoder:g/Your query/ m +1
Gleb Sabirzyanov
quelle