Mengomentari banyak baris kode, ditentukan oleh nomor baris, menggunakan vi atau vim

20

Saya telah belajar dari pertanyaan Stack Overflow ini bahwa adalah mungkin untuk menggunakan vi/ vimuntuk mengomentari kisaran nomor baris yang ditentukan. Misalnya, anggap saya memiliki skrip bash berikut:

#!/bin/bash

This
is
my
very
very
great
script

Sekarang anggaplah bahwa saya ingin komentar dari nomor baris 6 sampai 8 (yang berisi kata-kata very, verydan great) menggunakan #karakter komentar. Di vi/ vim, saya cukup mengetik :6,8s/^/#untuk mendapatkan yang berikut ini:

#!/bin/bash

This
is
my
#very
#very
#great
script

yang mengomentari baris 6 hingga 8.

Pertanyaan saya adalah, apakah mungkin untuk mengetik yang sama salah satu kapal yang akan menghapus satu #karakter komentar dari baris 6 sampai 8 (tapi tidak setiap baris berkomentar lain di file)?

Setelah mengatakan ini, saya menyadari bahwa ada beberapa perdebatan tentang apakah saya benar-benar menggunakan viatau vim. Dalam praktiknya, saya membuka file script.shdengan perintah vi script.sh. Juga, ketika saya mengetik perintah which vi, saya memperoleh /usr/bin/vi. Namun demikian, ketika saya cukup mengetik vidan menekan Enter, saya memperoleh ini:

~                              VIM - Vi IMproved
~
~                               version 7.2.330
~                           by Bram Moolenaar et al.
~                 Vim is open source and freely distributable
~
~                           Sponsor Vim development!
~                type  :help sponsor<Enter>    for information
~
~                type  :q<Enter>               to exit
~                type  :help<Enter>  or  <F1>  for on-line help
~                type  :help version7<Enter>   for version info

yang tampaknya menyarankan bahwa saya benar-benar menggunakan vim. Saya mengakses cluster Linux Ubuntu jarak jauh menggunakan SSH dari PC saya. Saya tidak menggunakan GUI Ubuntu Linux.

Andrew
sumber

Jawaban:

22

Anda dapat gunakan:

:6,8s/^#//

Tetapi jauh lebih mudah adalah dengan menggunakan mode pilihan Blok Visual: Pergi ke awal baris 6, tekan Ctrl-v, turun ke baris 8 dan tekan x.

Ada juga plugin "The NERD Commenter" .

Jofel
sumber
2
NERD Commenteradalah cara untuk pergi ke sini menurut saya! +1 untuk itu
user1146332
7

Saya tahu pertanyaan Anda menentukan menggunakan viatau vimtetapi di sini ada beberapa opsi lain untuk melakukan ini tanpa harus membuka file secara manual:

  • Perl

    perl -ne 'if($. <=8 && $. >= 6){s/^\s*#//;}print' foo.sh 
    
  • Versi perl> = 5.10

    perl -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    

    Ini akan mencetak isi file, Anda dapat mengalihkan ke yang lain ( > new_file.sh) atau gunakan iuntuk mengedit file di tempat:

    perl -i -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    
  • sed

    sed '6,8 s/^ *#//' foo.sh
    

    Sekali lagi, untuk membuat ini mengedit file asli di tempat, gunakan i:

    sed -i '6,8 s/^ *#//' foo.sh
    
  • awk/ gawketc:

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Murni bash:

    c=1; while read line; do 
      if [ $c -ge 6 ] && [ $c -le 8 ]; then 
         echo "${line/\#/}"
      else 
         echo $line 
      fi
      let c++; done < foo.sh
    
terdon
sumber
1
Ini bukan masalah "harus membuka file secara manual", karena biasanya Anda memutuskan baris mana yang akan dikomentari setelah inspeksi visual, saat mengedit :) Tapi tentu saja, itu jawaban yang bagus untuk kelengkapan.
Paulo Almeida
2
@PauloAlmeida Anda benar tentu saja. Saya hanya berpikir itu bisa berguna karena OP sudah tahu nomor baris (karena perintah pertama yang digunakan untuk berkomentar) dan, dalam hal apa pun, alat yang saya tunjukkan dapat diterapkan pada berbagai masalah.
terdon
4

viadalah tautan simbolis ke vimdalam sebagian besar distribusi GNU / Linux sehingga Anda memang menggunakannya vimsaat mengetik vi.

Untuk menghapus komentar, Anda dapat mengetik: :6,8s/^#//atau :6,8s/^\s*#//membuang beberapa ruang utama sebelum # simbol.

lororget
sumber
1
Terima kasih banyak. Tampaknya mungkin ada kesalahan ketik. Mungkin harus :6,8s/^#//dan 6,8s/^\s*#//?
Andrew
3

Anda mungkin menggunakan vim.tiny. Bagaimanapun, Anda dapat menghapus komentar awal dengan:

:6,8s/^#//

Tentu saja, jika Anda memasukkannya dengan cara yang berbeda (misalnya, dengan ruang ekstra), Anda mungkin perlu menghapus apa pun yang ada di sana. Dengan vim penuh, memilih kolom secara visual dan menyisipkan / menghapus karakter adalah cara yang lebih mudah untuk melakukan hal yang sama.

Paulo Almeida
sumber
3

Secara pribadi cara Favorit saya menggunakan mode blok visual

ctrl+ vuntuk masuk ke mode blok visual, gunakan tombol panah atau hjkl untuk memilih garis dan tekan xatau del.

Ingin mereka kembali?

ctrl+ vbuat seleksi, lalu I(modal i)#Esc

exussum
sumber
3

AFAIK, vi biasanya merupakan symlink dari vim saat ini (coba which viatau type vikemudian ikuti symlinks). Mungkin, bahkan /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Secara pribadi, untuk menghapus beberapa baris komentar, saya lebih suka memilih blok vertikal melalui CtrlVdan menghapusnya. Jika Anda perlu menambahkan simbol komentar ke beberapa baris, Anda bisa CtrlV, lalu ShiftI, ketik #dan Esc, dan komentar akan ditambahkan ke beberapa baris.

Boris Burkov
sumber
2

Jawaban di atas, menggunakan

:6,8s/^#//

adalah solusi sempurna, tetapi sedikit rumit untuk mengetik. Ini dapat disederhanakan dengan mendefinisikan perintah baru di ~/.vimrc.

command -range=% C :<line1>,<line2>s/^/#/
command -range=% D :<line1>,<line2>s/^#//

Dan Anda bisa mengetik

:6,8C
:6,8D

untuk menempatkan / menghapus perintah.

Jika Anda menyukai mode visual, Anda dapat menentukan peta

map <F7> :s/^/#/<CR>
map <F8> :s/^#//<CR>

Sedemikian rupa sehingga Anda hanya perlu memilih rentang garis dalam mode visual, dan tekan F7dan F8untuk menempatkan dan menghapus komentar masing-masing.

Bernhard
sumber
1

Ada plugin yang mengubah hidup ini dengan tpopemeneleponvim-commentary

https://github.com/tpope/vim-commentary

Plugin ini menyediakan :

  • Kewarasan
  • Komentar yang diindentasi dengan benar
  • Tidak mengomentari baris kosong / tidak perlu

Penggunaan :

  • Instal melalui Vundle (atau saya kira Patogen).
  • Sorot teks Anda dan tekan :yang akan ditampilkan sebagai:<,'>
  • Ketik Komentar di sini :<,'>Commentarydan tekan enter.
  • Bom Tunas Anda sudah selesai.
Weston Ganger
sumber
1

Jawaban ini ada di sini untuk 1) menunjukkan kode yang benar untuk ditempel ke dalam .vimrcuntuk vim 7.4+melakukan blok komentar / komentar sambil menjaga tingkat lekukan dengan 1 pintasan dalam mode visual dan 2) untuk menjelaskannya.

Ini kodenya:

let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.[ch]    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.cpp    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.py    let b:commentChar='#'
autocmd BufNewFile,BufReadPost *.*sh    let b:commentChar='#'
function! Docomment ()
  "make comments on all the lines we've grabbed
  execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e'
endfunction
function! Uncomment ()
  "uncomment on all our lines
  execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e'
endfunction
function! Comment ()
  "does the first line begin with a comment?
  let l:line=getpos("'<")[1]
  "if there's a match
  if match(getline(l:line), '^\s*'.b:commentChar)>-1
    call Uncomment()
  else
    call Docomment()
  endif
endfunction
vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>

Bagaimana itu bekerja:

  • let b:commentChar='//': Ini menciptakan variabel dalam vim. di bsini merujuk pada ruang lingkup, yang dalam hal ini terkandung ke buffer, yang berarti file yang sedang dibuka. Karakter komentar Anda adalah string dan perlu dibungkus dengan tanda kutip, tanda kutip itu bukan bagian dari apa yang akan diganti ketika bertukar komentar.

  • autocmd BufNewFile,BufReadPost *...: Perintah otomatis memicu pada hal-hal yang berbeda, dalam hal ini, ini memicu ketika file baru atau file baca berakhir dengan ekstensi tertentu. Setelah dipicu, jalankan perintah berikut, yang memungkinkan kita untuk mengubah commentChartergantung pada tipe file. Ada cara lain untuk melakukan ini, tetapi mereka lebih membingungkan bagi pemula (seperti saya).

  • function! Docomment(): Fungsi dideklarasikan dengan mulai functiondan diakhiri dengan endfunction. Fungsi harus dimulai dengan modal. itu !memastikan bahwa fungsi ini menimpa setiap fungsi sebelumnya yang didefinisikan Docomment()dengan versi ini Docomment(). Tanpa !, saya memiliki kesalahan, tapi itu mungkin karena saya mendefinisikan fungsi baru melalui baris perintah vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Jalankan panggilan perintah. Dalam hal ini, kami mengeksekusi substitute, yang dapat mengambil rentang (secara default ini adalah baris saat ini) seperti %untuk seluruh buffer atau '<,'>untuk bagian yang disorot. ^\s*adalah regex untuk mencocokkan awal baris diikuti oleh jumlah spasi, yang kemudian ditambahkan ke (karena &). Di .sini digunakan untuk penggabungan string, karena escape()tidak dapat dibungkus dengan tanda kutip. escape()memungkinkan Anda untuk keluar dari karakter commentCharyang cocok dengan argumen (dalam hal ini, \dan /) dengan menambahkannya dengan a \. Setelah ini, kami menyatukan lagi dengan ujung substitutesenar kami , yang memilikiebendera. Bendera ini memungkinkan kita gagal secara diam-diam, artinya jika kita tidak menemukan kecocokan pada garis yang diberikan, kita tidak akan berteriak tentang hal itu. Secara keseluruhan, baris ini memungkinkan kita menempatkan karakter komentar diikuti oleh spasi sesaat sebelum teks pertama, yang berarti kita menjaga tingkat indentasi kita.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Ini mirip dengan perintah besar terakhir kami. Unik untuk yang ini, kami punya \v, yang memastikan bahwa kami tidak harus melarikan diri dari kami (), dan 1, yang mengacu pada grup yang kami buat dengan kami (). Pada dasarnya, kami mencocokkan garis yang dimulai dengan jumlah spasi putih apa pun dan kemudian karakter komentar kami diikuti oleh jumlah spasi putih apa pun, dan kami hanya menyimpan set spasi putih pertama. Sekali lagi, emari kita gagal secara diam-diam jika kita tidak memiliki karakter komentar di baris itu.

  • let l:line=getpos("'<")[1]: ini menetapkan variabel seperti yang kami lakukan dengan karakter komentar kami, tetapi lmerujuk ke lingkup lokal (lokal ke fungsi ini). getpos()mendapatkan posisi, dalam hal ini, awal dari penyorotan kami, dan [1]sarana kami hanya peduli dengan nomor baris, bukan hal-hal lain seperti nomor kolom.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: Anda tahu cara ifkerjanya. match()memeriksa apakah hal pertama berisi hal kedua, jadi kami mengambil garis yang kami mulai sorot kami, dan memeriksa apakah itu dimulai dengan spasi putih diikuti oleh karakter komentar kami. match()mengembalikan indeks jika ini benar, dan -1jika tidak ada kecocokan yang ditemukan. Karena ifmengevaluasi semua angka bukan nol itu benar, kita harus membandingkan output kita untuk melihat apakah itu lebih besar dari -1. Perbandingan dalam vimpengembalian 0 jika salah dan 1 jika benar, yang ifingin dilihat untuk mengevaluasi dengan benar.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapberarti memetakan perintah berikut dalam mode visual, tetapi jangan memetakannya secara rekursif (artinya tidak mengubah perintah lain yang mungkin digunakan dengan cara lain). Pada dasarnya, jika Anda seorang pemula, selalu gunakan noremapuntuk memastikan Anda tidak merusak barang-barang. <silent>berarti "Saya tidak ingin kata-kata Anda, hanya tindakan Anda" dan mengatakan itu untuk tidak mencetak apa pun ke baris perintah. <C-r>adalah hal yang kami pemetaan, yaitu ctrl + r dalam hal ini (perhatikan bahwa Anda masih dapat menggunakan Cr secara normal untuk "redo" dalam mode normal dengan pemetaan ini). C-uagak membingungkan, tetapi pada dasarnya itu memastikan Anda tidak kehilangan jejak penyorotan visual Anda (menurut jawaban ini membuat perintah Anda mulai dengan '<,'>yang kami inginkan).calldi sini hanya memberitahu vim untuk menjalankan fungsi yang kita beri nama, dan <cr>mengacu pada menekan entertombol. Kita harus menekannya sekali untuk benar-benar memanggil fungsi (jika tidak kita baru saja mengetik call function()pada baris perintah, dan kita harus menekannya lagi untuk mendapatkan pengganti kita untuk pergi sepanjang jalan (tidak benar-benar yakin mengapa, tapi apa pun).

Bagaimanapun, semoga ini membantu. Ini akan mengambil apa pun yang disorot dengan v,, Vatau C-v, periksa apakah baris pertama dikomentari, jika ya, coba batalkan komentar pada semua baris yang disorot, dan jika tidak, tambahkan lapisan karakter komentar tambahan untuk setiap baris. Inilah perilaku yang saya inginkan; Saya tidak hanya ingin beralih apakah setiap baris di blok dikomentari atau tidak, jadi itu berfungsi dengan baik bagi saya setelah mengajukan beberapa pertanyaan pada subjek.

profil jeremys
sumber