Nhận xét nhiều dòng mã, được chỉ định bởi số dòng, sử dụng vi hoặc vim


20

Tôi đã học được từ câu hỏi Stack Overflow này rằng có thể sử dụng vi/ vimđể nhận xét một phạm vi số dòng được chỉ định. Ví dụ: giả sử tôi có tập lệnh bash sau:

#!/bin/bash

This
is
my
very
very
great
script

Bây giờ giả sử rằng tôi muốn nhận xét ra số dòng 6 đến 8 (trong đó chứa các từ very, verygreat) sử dụng các #nhân vật nhận xét. Trong vi/ vim, tôi chỉ có thể gõ :6,8s/^/#để có được những điều sau đây:

#!/bin/bash

This
is
my
#very
#very
#great
script

trong đó nhận xét các dòng 6 đến 8.

Câu hỏi của tôi là, là nó có thể gõ một tương tự một liner rằng sẽ loại bỏ các #nhân vật bình luận từ dòng 6 đến 8 (nhưng không phải bất kỳ dòng nhận xét khác trong hồ sơ)?

Khi nói điều này, tôi nhận ra rằng có một số tranh luận về việc tôi thực sự đang sử dụng vihay vim. Trong thực tế, tôi mở một tập tin script.shvới lệnh vi script.sh. Ngoài ra, khi tôi gõ lệnh which vi, tôi có được /usr/bin/vi. Tuy nhiên, khi tôi chỉ cần gõ vivà nhấn Enter, tôi có được điều này:

~                              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

có vẻ như gợi ý rằng tôi đang thực sự sử dụng vim. Tôi đang truy cập một cụm Ubuntu Linux từ xa bằng SSH từ PC của tôi. Tôi không sử dụng GUI Ubuntu Linux.

Câu trả lời:


22

Bạn có thể dùng:

:6,8s/^#//

Nhưng dễ dàng hơn nhiều là sử dụng chế độ lựa chọn Block Visual: Đi đến đầu dòng 6, nhấn Ctrl-v, đi xuống dòng 8 và nhấn x.

Ngoài ra còn có plugin "The NERD Commenter" .


2
NERD CommenterTheo ý kiến ​​của tôi là cách để đi đến đây! +1 cho điều đó
user1146332

7

Tôi biết câu hỏi của bạn chỉ định sử dụng vihoặc vimnhưng đây là một vài tùy chọn khác để thực hiện việc này mà không cần phải mở tệp theo cách thủ công:

  • Perl

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

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

    Điều này sẽ in ra nội dung của tệp, bạn có thể chuyển hướng đến một ( > new_file.sh) khác hoặc sử dụng iđể chỉnh sửa tệp tại chỗ:

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

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

    Một lần nữa, để thực hiện chỉnh sửa tệp gốc này, sử dụng i:

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

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Tinh khiết 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
    

1
Đây không phải là vấn đề "phải mở tệp theo cách thủ công", bởi vì thông thường bạn quyết định dòng nào sẽ nhận xét khi kiểm tra trực quan, trong khi chỉnh sửa :) Nhưng chắc chắn, đó là một câu trả lời tốt cho sự hoàn chỉnh.
Paulo Almeida

2
@PauloAlmeida bạn đúng tất nhiên. Tôi chỉ nghĩ rằng nó có thể hữu ích vì OP đã biết các số dòng (vì lệnh đầu tiên được sử dụng để nhận xét chúng) và, trong mọi trường hợp, các công cụ tôi hiển thị có thể được áp dụng cho nhiều vấn đề khác nhau.
terdon

4

vilà một liên kết tượng trưng vimtrong hầu hết các bản phân phối GNU / Linux để bạn thực sự sử dụng vimkhi bạn nhập vi.

Để xóa các nhận xét, bạn có thể nhập: :6,8s/^#//hoặc :6,8s/^\s*#//loại bỏ một số khoảng trắng ở trước # biểu tượng.


1
Cám ơn rất nhiều. Dường như có thể có lỗi chính tả. Có lẽ nó nên :6,8s/^#//6,8s/^\s*#//?
Andrew

3

Bạn có thể đang sử dụng vim.tiny. Trong mọi trường hợp, bạn có thể xóa các nhận xét ban đầu bằng:

:6,8s/^#//

Tất nhiên, nếu bạn chèn chúng theo một cách khác (ví dụ: có thêm dung lượng), bạn có thể cần phải xóa bất cứ thứ gì khác ở đó. Với vim đầy đủ, chọn trực quan các cột và chèn / xóa các ký tự là một cách dễ dàng hơn để làm điều tương tự.


3

Cá nhân tôi thích cách sử dụng chế độ khối trực quan

ctrl+ vđể vào chế độ khối trực quan, sử dụng các phím mũi tên hoặc hjkl để chọn các dòng và nhấn xhoặc del.

Muốn họ trở lại?

ctrl+ vthực hiện lựa chọn, sau đó I(vốn i)#Esc


3

AFAIK, vi thường là một liên kết tượng trưng của vim ngày nay (thử which vihoặc type visau đó theo các liên kết tượng trưng). Có thể, thậm chí /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Cá nhân, để xóa nhiều dòng nhận xét, tôi thích chọn một khối dọc thông qua CtrlVvà xóa nó. Nếu bạn cần thêm một biểu tượng nhận xét cho nhiều dòng, bạn có thể CtrlV, sau đó ShiftI, nhập #Esc, và một nhận xét sẽ được thêm vào nhiều dòng.


2

Các câu trả lời trên, sử dụng

:6,8s/^#//

là giải pháp hoàn hảo, nhưng một chút rườm rà để gõ. Điều này có thể được đơn giản hóa bằng cách xác định các lệnh mới trong ~/.vimrc.

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

Và bạn chỉ có thể gõ

:6,8C
:6,8D

để đặt / xóa lệnh.

Nếu bạn thích chế độ trực quan, bạn có thể xác định bản đồ

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

Như vậy, bạn chỉ phải chọn một phạm vi dòng trong chế độ trực quan, và nhấn F7F8để đặt và xóa nhận xét tương ứng.


1

Có plugin thay đổi cuộc sống này bằng cách tpopegọivim-commentary

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

Plugin này cung cấp :

  • Sự tỉnh táo
  • Nhận xét thụt lề đúng cách
  • Không bình luận ra những dòng trống / không cần thiết

Cách sử dụng :

  • Cài đặt qua Vundle (hoặc Pathogen tôi đoán).
  • Đánh dấu văn bản của bạn và nhấn :sẽ hiển thị như:<,'>
  • Nhập bình luận ở đây :<,'>Commentaryvà nhấn enter.
  • Bom. Nụ của bạn đã hoàn thành

1

Câu trả lời này là ở đây để 1) hiển thị mã chính xác để dán vào một .vimrcđể có được vim 7.4+để làm khối cho ý kiến / uncommenting trong khi vẫn giữ mức thụt đầu dòng với 1 phím tắt trong chế độ trực quan và 2) để giải thích nó.

Đây là mã:

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>

Làm thế nào nó hoạt động:

  • let b:commentChar='//': Điều này tạo ra một biến trong vim. các bđây đề cập đến phạm vi, mà trong trường hợp này được chứa vào bộ đệm, có nghĩa là tập tin hiện đang mở. Các ký tự nhận xét của bạn là các chuỗi và cần được gói trong dấu ngoặc kép, các trích dẫn không phải là một phần của những gì sẽ được thay thế khi bật các bình luận.

  • autocmd BufNewFile,BufReadPost *...: Autocommands kích hoạt những thứ khác nhau, trong trường hợp này, đây là những kích hoạt khi một tệp mới hoặc tệp đọc kết thúc với một phần mở rộng nhất định. Sau khi được kích hoạt, thực thi lệnh sau, cho phép chúng ta thay đổi commentChartùy thuộc vào filetype. Có nhiều cách khác để làm điều này, nhưng chúng khó hiểu hơn đối với người mới (như tôi).

  • function! Docomment(): Hàm được khai báo bằng cách bắt đầu bằng functionvà kết thúc bằng endfunction. Chức năng phải bắt đầu bằng một vốn. các !Đảm bảo rằng chức năng này ghi đè bất kỳ chức năng trước đó định nghĩa là Docomment()với phiên bản này của Docomment(). Không có !, tôi có lỗi, nhưng đó có thể là do tôi đang xác định các hàm mới thông qua dòng lệnh vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Thực thi cuộc gọi một lệnh. Trong trường hợp này, chúng tôi đang thực thi substitute, có thể lấy một phạm vi (theo mặc định đây là dòng hiện tại) như %cho toàn bộ bộ đệm hoặc '<,'>cho phần được tô sáng. ^\s*là regex để khớp với bắt đầu của một dòng theo sau bởi bất kỳ khoảng trắng nào, sau đó được thêm vào (do &). Ở .đây được sử dụng để nối chuỗi, vì escape()không thể được gói trong dấu ngoặc kép. escape()cho phép bạn thoát ký tự commentCharphù hợp với các đối số (trong trường hợp này \/) bằng cách thêm chúng vào a \. Sau đó, chúng tôi nối lại một lần nữa với phần cuối của substitutechuỗi, trong đó cóecờ. Cờ này cho phép chúng tôi thất bại trong âm thầm, có nghĩa là nếu chúng tôi không tìm thấy kết quả khớp trên một dòng nhất định, chúng tôi sẽ không hét lên về nó. Nhìn chung, dòng này cho phép chúng ta đặt một ký tự nhận xét theo sau là khoảng trắng ngay trước văn bản đầu tiên, nghĩa là chúng ta giữ mức thụt lề.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Điều này tương tự như lệnh dài lớn cuối cùng của chúng tôi. Duy nhất với cái này, chúng tôi có \v, đảm bảo rằng chúng tôi không phải trốn thoát (), và 1, đề cập đến nhóm chúng tôi đã thực hiện với chúng tôi (). Về cơ bản, chúng tôi khớp một dòng bắt đầu với bất kỳ khoảng trắng nào và sau đó là ký tự nhận xét của chúng tôi theo sau bởi bất kỳ khoảng trắng nào và chúng tôi chỉ giữ bộ khoảng trắng đầu tiên. Một lần nữa, echúng ta hãy âm thầm thất bại nếu chúng ta không có một nhân vật bình luận trên dòng đó.

  • let l:line=getpos("'<")[1]: điều này đặt một biến giống như chúng ta đã làm với ký tự nhận xét của mình, nhưng lđề cập đến phạm vi cục bộ (cục bộ cho hàm này). getpos()trong trường hợp này, bắt đầu đánh dấu của chúng tôi và [1]có nghĩa là chúng tôi chỉ quan tâm đến số dòng, không phải những thứ khác như số cột.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: bạn biết cách làm ifviệc match()kiểm tra xem thứ thứ nhất có chứa thứ thứ hai không, vì vậy chúng tôi lấy dòng mà chúng tôi đã bắt đầu tô sáng và kiểm tra xem nó có bắt đầu bằng khoảng trắng theo sau là ký tự nhận xét của chúng tôi không. match()trả về chỉ mục nơi điều này là đúng và -1nếu không tìm thấy kết quả khớp nào. Vì ifđánh giá tất cả các số khác không là đúng, chúng tôi phải so sánh đầu ra của chúng tôi để xem nó có lớn hơn -1 không. So sánh vimtrả về 0 nếu sai và 1 nếu đúng, đó là điều ifmuốn xem để đánh giá chính xác.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapcó nghĩa là ánh xạ lệnh sau trong chế độ trực quan, nhưng không ánh xạ đệ quy (có nghĩa là không thay đổi bất kỳ lệnh nào khác có thể sử dụng theo các cách khác). Về cơ bản, nếu bạn là người mới làm quen với vim, hãy luôn sử dụng noremapđể đảm bảo bạn không phá vỡ mọi thứ. <silent>có nghĩa là "Tôi không muốn lời nói của bạn, chỉ là hành động của bạn" và bảo nó không được in bất cứ điều gì lên dòng lệnh. <C-r>là thứ chúng tôi lập bản đồ, đó là ctrl + r trong trường hợp này (lưu ý rằng bạn vẫn có thể sử dụng Cr bình thường để "làm lại" trong chế độ bình thường với ánh xạ này). C-uhơi khó hiểu, nhưng về cơ bản, nó đảm bảo bạn không bị mất dấu của việc làm nổi bật hình ảnh của bạn (theo câu trả lời này, nó làm cho lệnh của bạn bắt đầu với '<,'>đó là những gì chúng ta muốn).callỞ đây chỉ nói với vim để thực thi chức năng mà chúng ta đã đặt tên và <cr>đề cập đến việc nhấn enternút. Chúng ta phải nhấn nó một lần để thực sự gọi hàm (nếu không chúng ta vừa gõ call function()vào dòng lệnh, và chúng ta phải nhấn nó một lần nữa để thay thế chúng ta đi suốt (không thực sự chắc chắn tại sao, nhưng bất cứ điều gì).

Dù sao, hy vọng điều này sẽ giúp. Điều này sẽ lấy bất cứ điều gì được tô sáng bằng v, Vhoặc C-v, kiểm tra xem dòng đầu tiên có được nhận xét hay không, nếu có, cố gắng bỏ ghi chú tất cả các dòng được tô sáng và nếu không, hãy thêm một lớp ký tự nhận xét cho mỗi dòng. Đây là hành vi mong muốn của tôi; Tôi không chỉ muốn nó chuyển đổi xem mỗi dòng trong khối có được nhận xét hay không, vì vậy nó hoạt động hoàn hảo với tôi sau khi hỏi nhiều câu hỏi về chủ đề này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.