Bagaimana cara menggunakan perintah eksternal di Vim untuk memodifikasi kata dan baris yang dipilih?

22

Sesuatu yang saya temukan berguna di editor lain adalah kemampuan untuk:

  • ambil teks yang dipilih
  • menjalankan perintah eksternal dan meneruskan seleksi ke stdin
  • ambil perintah eksternal stdoutdan ganti pilihan saat ini dengannya.

Dengan cara ini Anda dapat menulis alat teks berguna yang beroperasi pada seleksi menggunakan bahasa apa pun yang dapat melakukan io dasar.

Bagaimana ini bisa dilakukan dengan vim menggunakan pilihan? ... satu karakter, kata, paragraf ... dll.

(Langsung di baris perintah, atau melalui pengikatan kunci?)


Catatan

Perintah seperti !sortbekerja pada level-line, alasan saya mengajukan pertanyaan ini adalah karena saya ingin beroperasi pada seleksi. (Yaitu, teks yang akan dihapus jika xditekan).

gagasanman42
sumber

Jawaban:

17

Saya menemukan bahwa seringkali cara termudah adalah dengan menggunakan mode visual dengan v(atau modal Vuntuk memilih seluruh garis), dan pilih teks yang ingin Anda pipa.

Kemudian ketik:

:!cat

Ini tidak melakukan apa pun yang bermanfaat. Perintah berguna yang sering saya gunakan adalah:

:!python -m json.tool

untuk memformat JSON.

Anda juga dapat mengetik (tanpa mode visual):

:<range>!command

Misalnya, untuk seluruh file:

:%!python -m json.tool

Atau untuk baris saat ini:

:.!python -m json.tool
Martin Tournoij
sumber
Alat lain yang sangat berguna untuk digunakan dengan ini adalah sortperintah.
Polling Cody
4
@CodyPoll Apa yang salah dengan Vim :sort?
Martin Tournoij
5
@Carpetsmoker Perintah sortir eksternal memiliki lebih banyak opsi dan (tergantung pada lokal, dll.) Menghasilkan urutan yang berbeda.
derobert
1
Ini tidak berfungsi untuk memilih satu kata dalam satu baris. (lihat pertanyaan menyebutkan pemilihan tingkat kata)
ideasman42
@ ideasman42 Benar ... Saya pikir saya awalnya membaca pertanyaan ini sebagai "baris atau kata - kata" bukannya "baris dan kata - kata" ... Dalam hal apapun, melakukan ini dengan kata-kata tidak jelas, program UNIX bekerja pada baris, dan Vim tidak terkecuali. Saya melakukan beberapa percobaan dan semacam punya solusi, tetapi tidak berfungsi dengan baik ... Mungkin pendekatan saya salah, jadi saya akan membiarkannya selama beberapa hari dan kembali lagi nanti.
Martin Tournoij
7

Saya menulis sebuah plugin bernama express.vim yang dapat membantu dengan ini. Plugin mendefinisikan operator g=yang memungkinkan Anda mengevaluasi ekspresi VimScript atas gerakan (atau pemilihan Visual). Ini meminta ekspresi, di mana Anda dapat menggunakan v:valsebagai pengganti untuk teks yang dicakup oleh gerakan (atau, sekali lagi, pemilihan Visual).

Dalam kasus ini, ekspresi yang berguna akan menggunakan system()fungsi, yang menjalankan perintah eksternal.

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

(Di sini saya digunakan trsebagai contoh sederhana perintah eksternal.)

Cara menggunakan express.vim untuk masalah ini adalah dengan memilih teks dengan mode Visual, lalu ketik g=diikuti oleh ekspresi itu, lalu tekan Enter:

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

Saya akui, itu tidak mudah digunakan. (Faktanya, saya jarang menggunakan plugin ini sendiri!) Saya sedang mempertimbangkan untuk menambahkan jalan pintas untuk menjalankan perintah eksternal, seperti memulai ekspresi dengan !. Saya akan memposting pembaruan di sini jika saya akhirnya melakukan itu.

EDIT

Saya telah memodifikasi express.vim untuk memperlakukan ekspresi yang diawali dengan !perintah eksternal. Jadi, tetap dengan trcontoh, hal di atas menjadi jauh lebih sederhana. Setelah pemilihan Visual, ketikkan yang berikut:

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

Penjelasan:

  1. Meminta operator ekspres dengan g=
  2. Masukkan !tr a-z A-Zsebagai ekspresi
  3. tekan Enter
tommcdo
sumber
4

Anda mencari perintah filter di Vim. Lihat :help filter. Berikut dokumentasi yang relevan:

!{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]

Jadi mengetik 5!!sortakan mengurutkan 5 baris berikutnya mulai dari kursor.

Sameer
sumber
Apakah mungkin untuk memfilter satu kata? (bukan tingkat garis)
ideasman42
Iya nih. Opsi ketiga (mode visual) berfungsi untuk apa pun yang disorot (kata-kata, garis parsial, banyak garis, blok persegi panjang, dll.).
Sameer
1
Opsi ketiga juga menyaring seluruh baris. Jika Anda memilih satu kata dan memfilternya, misalnya, melalui tr [:lower:] [:upper], maka vim tidak hanya akan menghapus kata ini tetapi juga seluruh baris.
maria s
0

Perhatikan bahwa hal itu dapat dilakukan dengan:

  1. pilih secara visual apa pun yang Anda inginkan
  2. s^R=system('tr a-z A-Z', @")[:-2]^M(dengan ^Rmenjadi CTRL + R, dan ^ M menjadi ENTER)

Bisa juga bekerja dengan apa pun yang tidak seperti seleksi + ganti ci"^R=....

Luc Hermitte
sumber
Saat menjalankan ini pada pemilihan teks multi-baris (setelah menekan vdan memindahkan kursor) saya mendapatkan kesalahan E16: Invalid range\nE16: Invalid range\nE476: Invalid command(di Linux begitu trdan ada perintah dasar lainnya).
ideasman42
Sudahkah Anda menekan syang masuk ke mode insert atau :sperintah?
Luc Hermitte
Dugaan tidak, tetapi juga tidak yakin maksud Anda, mungkin contohnya dapat menunjukkan cara mengikat ini ke kunci?
ideasman42
Apakah Anda menekan langsung sdari mode visual, atau Anda menekan :terlebih dahulu? Tidak ada yang :terlibat dalam urutan tombol yang saya tulis. Pemetaan A akan menjadi: vnoremap µ s<c-r>=system('tr a-z A-Z', @")[:-2]<cr>.
Luc Hermitte