Come usare un comando esterno in Vim per modificare le parole e le linee selezionate?


22

Qualcosa che ho trovato utile in altri editor è la possibilità di:

  • prendi il testo selezionato
  • eseguire un comando esterno e passare la selezione al suo stdin
  • prendere i comandi esterni stdoute sostituire la selezione corrente con esso.

In questo modo è possibile scrivere utili strumenti di testo che operano sulla selezione utilizzando qualsiasi lingua in grado di eseguire io di base.

Come si può fare con vim usando la selezione? ... un singolo carattere, parola, paragrafo ... ecc.

(Direttamente nella riga di comando o tramite un'associazione di tasti?)


Nota

Comandi come il !sortlavoro a livello di linea, il motivo per cui sto ponendo questa domanda è perché vorrei operare sulla selezione. (ovvero, il testo che verrebbe rimosso se xfosse premuto).

Risposte:


17

Trovo che spesso il modo più semplice sia utilizzare la modalità visiva con v(o maiuscola Vper selezionare intere righe) e selezionare il testo che si desidera eseguire il pipe.

Quindi digitare:

:!cat

Questo non fa nulla di utile, come tale. Un comando utile che uso spesso è:

:!python -m json.tool

per formattare JSON.

Puoi anche solo digitare (senza modalità visiva):

:<range>!command

Ad esempio, per l'intero file:

:%!python -m json.tool

O per la riga corrente:

:.!python -m json.tool

Un altro strumento davvero utile da utilizzare con questo è il sortcomando.
Cody Poll

4
@CodyPoll Cosa c'è che non va in Vim's :sort?
Martin Tournoij,

5
@Carpetsmoker Il comando di ordinamento esterno ha molte più opzioni e (a seconda delle impostazioni locali, ecc.) Produce un ordine diverso.
derobert,

1
Questo non funziona per la selezione di una sola parola in una riga. (vedi la domanda menziona la selezione del livello di parole)
ideasman42

@ ideasman42 Giusto ... Penso di aver letto inizialmente questa domanda come "linee o parole" invece di "linee e parole" ... In ogni caso, farlo con le parole non è ovvio, i programmi UNIX funzionano su linee e Vim non fa eccezione. Ho fatto alcuni esperimenti e in qualche modo ho una soluzione, ma non funziona molto bene ... Forse il mio approccio è sbagliato, quindi lo lascerò per qualche giorno e ci tornerò più tardi.
Martin Tournoij,

7

Ho scritto un plugin chiamato express.vim che può aiutare in questo. Il plug-in definisce un operatore g=che consente di valutare un'espressione VimScript su un movimento (o selezione Visual). Richiede un'espressione, in cui è possibile utilizzare v:valcome segnaposto per il testo coperto dal movimento (o, di nuovo, Selezione visiva).

In questo caso, un'espressione utile userebbe la system()funzione, che esegue un comando esterno.

system('tr a-z A-Z', v:val)

(Qui ho usato trcome semplice esempio un comando esterno.)

Il modo di utilizzare express.vim per questo problema sarebbe selezionare il testo con la modalità Visual, quindi digitare g=seguito da quell'espressione, quindi premere Enter:

g=system('tr a-z A-Z', v:val)<CR>

Lo ammetto, non è facile da usare. (In effetti, uso raramente questo plugin da solo!) Sto considerando di aggiungere un collegamento per invocare un comando esterno, come avviare l'espressione con !. Pubblicherò un aggiornamento qui se finisco per farlo.

MODIFICARE

Ho modificato express.vim per trattare le espressioni che iniziano con !come comandi esterni. Quindi, attenendosi trall'esempio, quanto sopra diventa molto più semplice. Dopo una selezione visiva, digitare quanto segue:

g=!tr a-z A-Z<CR>

Spiegazione:

  1. Richiamare l'operatore express con g=
  2. Inserisci !tr a-z A-Zcome espressione
  3. stampa Enter

4

Stai cercando i comandi di filtro in Vim. Vedere :help filter. Ecco la documentazione pertinente:

!{motion}{filter}   Filter {motion} text lines through the external
                    program {filter}.
!!{filter}          Filter [count] lines through the external program
                    {filter}.
{Visual}!{filter}   Filter the highlighted lines through the external
                    program {filter} (for {Visual} see |Visual-mode|).
                    {not in Vi}

:{range}![!]{filter} [!][arg]               *:range!*
                    Filter {range} lines through the external program
                   {filter}.  ...[See documentation for details]

Quindi la digitazione 5!!sortordinerà le 5 righe successive a partire dal cursore.


È possibile filtrare una sola parola? (non a livello di riga)
ideasman42

Sì. La terza opzione (modalità visiva) funziona per qualsiasi cosa sia evidenziata (parole, linea parziale, linee multiple, blocco rettangolare, ecc.).
Sameer,

1
La terza opzione filtra anche intere righe. Se selezioni una sola parola e la filtra, ad esempio, attraverso tr [:lower:] [:upper], allora vim non inserirà solo questa parola ma l'intera riga.
maria s,

0

Si noti che può essere fatto con:

  1. seleziona visivamente ciò che desideri
  2. s^R=system('tr a-z A-Z', @")[:-2]^M(con ^Ressere CTRL + R e ^ M essendo INVIO)

Potrebbe anche funzionare con qualsiasi cosa che selezioni + sostituisca come ci"^R=....


Quando eseguo questo su una selezione di testo su più righe (dopo aver premuto ve spostato il cursore) ottengo l'errore E16: Invalid range\nE16: Invalid range\nE476: Invalid command(su Linux, quindi tresistono altri comandi di base).
ideasman42

Hai premuto sper accedere alla modalità di inserimento o :sal comando?
Luc Hermitte,

Non sospetti, ma non sei sicuro di come intendi, forse l'esempio potrebbe mostrare come associarlo a una chiave?
ideasman42

Colpisci direttamente sdalla modalità visiva o colpisci per :primo? Non è :coinvolto nella sequenza di chiavi che ho scritto. Una mappatura potrebbe essere: vnoremap µ s<c-r>=system('tr a-z A-Z', @")[:-2]<cr>.
Luc Hermitte,
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.