Unisci i blocchi per linee di interfogliatura


15

Esiste un modo dedicato per unire due blocchi di testo intercalando righe, come passare da questo:

a1
a2
a3
a4
  b1
  b2
  b3
  b4

a tale:

a1
  b1
a2
  b2
a3
  b3
a4
  b4

in pochi comandi?

EDIT : Mi piace molto la soluzione di Sato Katsura , ecco come l'ho implementata:

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>

Ora sono curioso: qual è il tuo caso d'uso? Stai rinominando i sottotitoli per una stagione TV?
VanLaser,

@VanLaser Haha, non lo sono. Principalmente, sto analizzando l'output di un programma, che devo verificare la coerenza relativa all'ordine di creazione / quindi ritardare la lettura degli oggetti. I blocchi di interfogliatura facilitano l'abbinamento delle linee corrispondenti nei blocchi di uscita ritardati. A volte ho anche bisogno di intercalare righe di codici con ripetute istruzioni simili per la registrazione o il benchmarking. Generare queste istruzioni è facile con le macro, quindi interfogliarle con il codice effettivo ora è solo un paio di sequenze di tasti con questa funzione, che è fantastico :)
iago-lito

1
@ lago-lito - grazie per la risposta! Sì, Vim è abbastanza versatile :) La tua espressione "eye-parsing" mi ha fatto pensare anche a scroll-bindingdue finestre di Vim.
VanLaser,

Sto riscontrando problemi con questo, come stai selezionando i due blocchi consecutivi? Devono essere adiacenti?
cbcoutinho,

@cbcoutinho Sì, hanno :) Non sono sicuro che potresti selezionarli entrambi. Nell'esempio che ho mostrato, ho posizionato il cursore su (diciamo) b1, quindi ho premuto vipper selezionare l'intero blocco, quindi ,itquale è il <map-I've-Picked>. Non funziona dalla tua parte?
iago-lito,

Risposte:


8

Non esiste un modo dedicato per farlo (per quanto ne so), ma sì, può essere fatto con alcuni comandi:

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

Puoi eseguirlo con :call Interleave(5, 8, 1). Il primo parametro è la prima riga da spostare, la seconda l'ultima riga e la terza dove spostarli. Probabilmente vuoi attivare i numeri di riga per vedere cosa stai facendo ( :set number).

Questo presuppone che i blocchi non si sovrappongano. Vedi :help :movee :help range()capisci come funziona la funzione.

Probabilmente ci sono modi migliori per raccogliere i due blocchi. C'è un plug-in mobile che dovrebbe permetterti di scambiare due blocchi. Non riesco a ricordare il nome del plug-in, ma l'autore (forse il famoso Dr. Chip?) Ha pensato più alla ricerca di un'interfaccia di me. :)


Dolce! Ho solo bisogno di due argomenti poiché i due blocchi sono contigui e hanno le stesse dimensioni: starte size. Con una funzione homebrew che recupera quei valori da una selezione, sarà semplicemente perfetto. Ci sto lavorando. :)
iago-lito,

Crosslink interessante ? ;)
iago-lito,

13

Ecco un'altra alternativa:

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

Prima copia le righe che sono 4 righe sotto alla riga corrente ( :h :t), quindi elimina le righe b consecutive ( :h :d)

Ancora meglio è questo comando:

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

Ciò significa che per ogni riga che inizia con a trova la riga successiva che inizia con 'b' e la sposta sotto la riga corrente.


1
Ho ricevuto "E16: intervallo non valido" sul secondo comando. Ho provato .+,$dinvece, e ha funzionato (come ha fatto .+,.+4d).
Peter Lewerin,

Non sono sicuro del perché ciò accada
Christian Brabandt,

1
no non lo fa. Leggi: h: range, puoi sempre usare la numerazione diretta invece di una ricerca regex
Christian Brabandt,

2
@ iago-lito Il secondo trucco funziona sempre, ma devi passare /^\s*ba un altro :range. es: selezionare il 1 ° blocco, eseguire'<,'>g/^/'>+1m.
dedowsdi

1
@ iago-lito È essenzialmente la stessa della risposta di Christian. Nulla è hardcoded se si seleziona visivamente il 1 ° blocco, '>+1segna l'inizio del 2 ° blocco.
dedowsdi

3

Se vuoi divertirti un po 'con macro e segni puoi provare qualcosa del genere:

  • Per prima cosa metti un segno (qui a) sulla riga contenente a1conma

  • Vai alla riga contenente b1e contrassegnalo conmb

  • Inizia a registrare una macro nel registro desiderato (qui il registro q) conqq

  • Inserisci il folowing nella tua macro: ddmb'apjma'b

  • Interrompere la registrazione della macro con q

  • Gioca tutte le volte che è necessario con X@qdov'è Xil numero di volte per giocare.

Per dettagliare la macro:

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

Modifica Come menzionato da lago-lito nei commenti, questo metodo sovrascriverà i segni e i buffer.

  • Per i marchi non penso che sia un vero problema: uso raramente tutti i 26 marchi in un buffer e penso che uno di essi trovi il più delle volte 2 voti gratuiti.

  • Per il buffer è possibile salvarlo in una variabile temporanea: prima di registrare la macro utilizzare :let saveReg=getreg('"')per salvare il registro e, una volta eseguita l'azione, utilizzare :call setreg('"', saveReg)per riportare il registro al suo stato precedente.

Ad ogni modo, devo ammettere che questa soluzione è solo una soluzione rapida e non ottimale: secondo me la risposta di Christan è la migliore e dovrebbe essere accettata perché non si scherza con buffer e segni, non costringe l'utente a creare una funzione e mostra la potenza del comando globale.


Interessante. Sfortunatamente, questo sovrascrive il contenuto di marchi e registri, che potrei usare;)
iago-lito

@ lago-lito: infatti sovrascrive marchi e buffer. Per i marchi non uso mai tutti i 26 marchi nei miei buffer, quindi non credo che sia davvero un problema. Per i buffer potrebbe essere più un problema, penso che puoi spesso trovare un buffer inutilizzato o, se proprio non puoi, utilizzare una variabile temporanea e le funzioni getreg()e setreg()per salvare il buffer. Ma sono d'accordo che non è una soluzione ottimale :-)
statox

1

Ho appena visto un'altra domanda simile e la soluzione consiste in:

Vai al centro più uno:

Mj

E corri:

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

Interessante :) Attenzione, però, questo interlaccia l'intero file e non solo il paragrafo selezionato!
iago-lito,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.