Zusammenführen von Blöcken durch Verschachteln von Linien


15

Gibt es eine spezielle Methode, um zwei Textblöcke durch Verschachteln von Zeilen zusammenzuführen, wie z.

a1
a2
a3
a4
  b1
  b2
  b3
  b4

dazu:

a1
  b1
a2
  b2
a3
  b3
a4
  b4

in ein paar befehlen?

EDIT : Die Lösung von Sato Katsura gefällt mir sehr gut. So habe ich sie implementiert:

function! Interleave()
    " retrieve last selected area position and size
    let start = line(".")
    execute "normal! gvo\<esc>"
    let end = line(".")
    let [start, end] = sort([start, end], "n")
    let size = (end - start + 1) / 2
    " and interleave!
    for i in range(size - 1)
        execute (start + size + i). 'm' .(start + 2 * i)
    endfor
endfunction

" Select your two contiguous, same-sized blocks, and use it to Interleave ;)
vnoremap <pickYourMap> <esc>:call Interleave()<CR>

Jetzt bin ich gespannt - was ist Ihr Anwendungsfall? Blockieren Sie die Umbenennung von Untertiteln für eine Fernsehsaison?
VanLaser

@ VanLaser Haha, bin ich nicht. Meistens analysiere ich die Ausgabe eines Programms, das auf Konsistenz hinsichtlich der Erstellungsreihenfolge und des verzögerten Lesens von Objekten überprüft werden muss. Das Verschachteln von Blöcken erleichtert das Anpassen entsprechender Zeilen in verzögerten Ausgabeblöcken. Manchmal muss ich auch Codezeilen mit wiederholten, ähnlichen Anweisungen für die Protokollierung oder das Benchmarking verschachteln. Diese Anweisungen zu erzeugen ist einfach , mit Makros und sie dann mit den tatsächlichen Code Verschachtelung jetzt nur ein paar Tastenanschläge mit dieser Funktion entfernt, die fühlt sich großartig :)
iago-lito

1
@ Lago-Lito - Danke für die Antwort! Ja, Vim ist sehr vielseitig :) Ihr Ausdruck "Eye-Parsing" hat mich auch dazu gebracht, an scroll-bindingzwei Vim-Fenster zu denken .
VanLaser

Ich habe Probleme damit. Wie wählen Sie die beiden aufeinander folgenden Blöcke aus? Müssen sie nebeneinander sein?
cbcoutinho

@cbcoutinho Ja, sie haben :) Ich bin mir nicht sicher, ob Sie sie ansonsten beide auswählen könnten. Im Beispiel habe ich zeigen, habe ich meinen Cursor auf (sagen wir) b1, dann traf ich vipdie ganze Brocken aus, und ,itwas die ist <map-I've-Picked>. Funktioniert es nicht auf Ihrer Seite?
iago-lito

Antworten:


8

Es gibt keine spezielle Möglichkeit, dies zu tun (soweit ich weiß), aber ja, dies kann mit ein paar Befehlen erreicht werden:

function! Interleave(start, end, where)
    if a:start < a:where
        for i in range(0, a:end - a:start)
            execute a:start . 'm' . (a:where + i)
        endfor
    else
        for i in range(a:end - a:start, 0, -1)
            execute a:end . 'm' . (a:where + i)
        endfor
    endif
endfunction

Sie können es mit ausführen :call Interleave(5, 8, 1). Der erste Parameter ist die erste Zeile, die zweite Zeile die letzte und die dritte Zeile, in die sie verschoben werden sollen. Sie möchten wahrscheinlich die Zeilennummern einschalten, um zu sehen, was Sie tun ( :set number).

Dies setzt voraus, dass sich die Blöcke nicht überlappen. Sehen :help :moveund :help range()verstehen Sie, wie die Funktion funktioniert.

Es gibt wahrscheinlich bessere Möglichkeiten, die beiden Blöcke aufzunehmen. Es gibt ein Plugin, mit dem Sie zwei Blöcke tauschen können. Ich kann mich nicht an den Namen des Plugins erinnern, aber der Autor (vielleicht der berühmte Dr. Chip?) Hat mehr darüber nachgedacht, ein Interface zu finden als ich. :)


Süss! Ich brauche nur zwei Argumente, da die beiden Blöcke zusammenhängend sind und dieselbe Größe haben: startund size. Mit einer Homebrew-Funktion, die diese Werte aus einer Auswahl abruft, ist sie einfach perfekt. Ich arbeite dran. :)
iago-lito

Interessante Vernetzung ? ;)
iago-lito

13

Hier ist eine andere Alternative:

:g/^a/+4t .
:+,+5d 

Kopieren Sie zuerst die 4 Zeilen darunter nach der aktuellen Zeile ( :h :t) und löschen Sie dann die aufeinander folgenden b Zeilen ( :h :d)

Noch besser ist dieser Befehl:

 :g/^a//^\s*b/m .

Das heißt, für jede Zeile, die mit a beginnt, wird die nächste Zeile gesucht, die mit 'b' beginnt, und unter die aktuelle Zeile verschoben.


1
Beim zweiten Befehl wurde "E16: Ungültiger Bereich" angezeigt. Ich habe es .+,$dstattdessen versucht , und das hat funktioniert (wie auch .+,.+4d).
Peter Lewerin

Nicht sicher, warum das passiert
Christian Brabandt

1
Nein, tut es nicht. Lesen Sie: h: range, Sie können immer die direkte Nummerierung anstelle einer regulären Suche verwenden
Christian Brabandt

2
@ iago-lito Der zweite Trick funktioniert immer, aber du musst zu /^\s*beinem anderen wechseln :range. zB: 1. Block auswählen, ausführen'<,'>g/^/'>+1m.
dedowsdi

1
@ iago-lito Es ist im Wesentlichen das Gleiche wie die Antwort von Christian. Wenn Sie den 1. Block visuell auswählen und den '>+1Beginn des 2. Blocks markieren, wird nichts fest codiert .
dedowsdi

3

Wenn Sie ein bisschen Spaß mit Makros und Markierungen haben möchten, können Sie Folgendes ausprobieren:

  • Setzen Sie zuerst eine Markierung (hier a) auf die Zeile a1mitma

  • Gehen Sie zu der Zeile mit b1und markieren Sie sie mitmb

  • Starten Sie die Aufnahme eines Makros in das gewünschte Register (hier das Register q) mitqq

  • Fügen Sie folgendes in Ihr Makro ein: ddmb'apjma'b

  • Beenden Sie die Aufzeichnung des Makros mit q

  • Spielen Sie es so oft wie nötig, X@qwobei Xdie Zeit angegeben ist, in der es gespielt werden soll.

So detaillieren Sie das Makro:

dd mb 'a p j ma 'b
 |  |  | | |    |
 |  |  | | |    go back to line marked `b`
 |  |  | | |
 |  |  | | move of one line and replace the mark `a`
 |  |  | insert the deleted line under the line marked `a`
 |  |  go to line marked `a`
 |  mark the future line to move with `b`
 delete the line to move

Bearbeiten Wie in den Kommentaren von lago-lito erwähnt, überschreibt diese Methode die Markierungen und die Puffer.

  • Für die Noten halte ich das nicht für ein wirkliches Problem: Ich verwende selten alle 26 Noten in einem Puffer und ich denke, man wird die meiste Zeit 2 freie Noten finden.

  • Für den Puffer ist es möglich, ihn in einer temporären Variablen zu speichern: Verwenden Sie vor dem Aufzeichnen des Makros :let saveReg=getreg('"'), um das Register zu speichern, und verwenden Sie, wenn die Aktion abgeschlossen ist,, :call setreg('"', saveReg)um das Register in seinen vorherigen Zustand zurückzusetzen.

Auf jeden Fall muss ich zugeben, dass diese Lösung nur eine schnelle Umgehung ist und nicht optimal: Meiner Meinung nach ist Christans Antwort die beste und sollte akzeptiert werden, da sie nicht mit Puffern und Markierungen zu tun hat und den Benutzer nicht zum Erstellen zwingt eine Funktion und zeigt die Leistung des globalen Befehls.


Interessant. Leider überschreibt dies den Inhalt der Marken und Register, die ich möglicherweise verwende;)
iago-lito

@ Lago-Lito: In der Tat überschreibt es Marken und Puffer. Für Noten verwende ich nie alle 26 Marken in meinen Puffern, damit ich nicht denke, dass das wirklich ein Problem ist. Bei Puffern ist dies möglicherweise ein größeres Problem. Ich denke, Sie finden häufig einen nicht verwendeten Puffer. Wenn dies nicht möglich ist, verwenden Sie eine temporäre Variable und die Funktionen getreg()und setreg(), um den Puffer zu speichern. Aber ich stimme zu, dass es keine optimale Lösung ist :-)
statox

1

Ich habe gerade eine ähnliche Frage gesehen und die Lösung besteht aus:

Springe zur Mitte plus eins:

Mj

Und Renn:

:,$g/./exe 'm' 2*line('.')-line('$')-1

Interessant :) Beachten Sie jedoch, dass dies Ihre gesamte Datei und nicht nur den ausgewählten Absatz verschachtelt!
iago-lito
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.