Tìm kiếm nhanh, giới hạn ở chức năng C ++


13

Tôi làm việc trên một dự án C ++ khá lớn. Một trong những khía cạnh khó chịu hơn của tổ chức của nó là các hàm rất lớn được đặt bên trong các tệp lớn lố bịch.

Tôi thường muốn tìm kiếm bất kỳ trường hợp nào của một lệnh gọi hàm hoặc biến toàn cục cụ thể, bị giới hạn ở hàm hiện tại. Có một công thức hợp lý đơn giản để thực hiện điều này?

(Tôi đã cài đặt ctags và sử dụng Tagbar ... có thể hữu ích cho việc này)

Câu trả lời:


9

Đây là cách tôi sẽ làm điều đó. Thêm cái này vào.vimrc

vnoremap if [[O][

Giải thích: vnoremap có nghĩa là ánh xạ phía bên trái ifsang phía bên phải [[mO][trong khi bạn đang ở chế độ trực quan. ifcó nghĩa là trong Chức năng , mặc dù bạn có thể đổi tên này nếu bạn muốn. [[nhảy đến đầu hàm. Odi chuyển đến đầu kia của văn bản được chọn trực quan của bạn và sau đó ][di chuyển đến cuối chức năng.

Vì vậy, nếu bạn muốn tìm kiếm trong một chức năng, bây giờ bạn vào chế độ trực quan với vvà chọn toàn bộ chức năng với if. Bây giờ thoát khỏi chế độ trực quan với <esc>, và tìm kiếm với /\%V. \%Vhạn chế tìm kiếm của bạn vào văn bản đã chọn trước đó. Nếu bạn không muốn phải đánh, <esc>/\%Vbạn cũng có thể thêm nó vào .vimrc:

vnoremap / <esc>/\%V

Sau đó, chuỗi các lần nhấn phím của bạn sẽ như sau:

vif/foo<enter>

và điều này sẽ tìm thấy tất cả sự xuất hiện của foo trong chức năng hiện tại.


Nhược điểm duy nhất của phương pháp này là nó hy vọng niềng răng mở và đóng sẽ có 0 vết lõm. Nếu bạn thường xuyên làm việc với mã không có mã này, vd

int foo() {
    bar()
}

sau đó phiên bản phức tạp hơn một chút này sẽ hoạt động:

vnoremap if ][ma%O'a

Điều này chỉ mong đợi niềng răng đóng cửa có 0 thụt. Nếu nẹp mở có vết lõm, nó vẫn hoạt động, mặc dù nó chiếm một dấu. Nếu bạn thường xuyên sử dụng dấu 'a', bạn có thể di chuyển cái này, vd

vnoremap if ][mb%O'b
vnoremap if ][mc%O'c
...

Than ôi điều này không hoạt động tốt với các chức năng C ++. Không giống như các hàm C, chúng có khả năng được thụt lề (đó là trường hợp các hàm thành viên nội tuyến được định nghĩa trong định nghĩa lớp của chúng và với thụt lề mặc định của các hàm trong không gian tên). Tuy nhiên, ý tưởng của bạn có thể được xây dựng nhờ vào phạm vi định nghĩa chức năng có thể thu được bằng ctags. Tôi làm điều đó trong chức năng lh#dev#find_function_boundariestừ lh-dev
Luc Hermitte

3
Cách tiếp cận tốt đẹp. Nếu bạn có thể tìm thấy dòng trên cùng của hàm một cách đáng tin cậy, thì bạn có thể di chuyển đến {và sau đó sử dụng %để đạt đến dòng dưới cùng. Không chắc chắn làm thế nào bạn có thể tìm thấy chức năng bắt đầu trong C ++, nhưng điều này hoạt động tốt với Javascript:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle

1
Về chỉnh sửa cuối cùng của bạn. CTRL-]nhảy đến thẻ dưới con trỏ Không bắt đầu chức năng hiện tại. Nó sẽ không giúp.
Luc Hermitte

Về chỉnh sửa mới. Nó không đơn giản. Khó khăn là có vim biết chức năng hiện tại. Nếu nó có thông tin, nó sẽ không cần sự giúp đỡ của ctags. Cách duy nhất để có được thông tin (từ ctags) là phân tích các lệnh nhảy để khai báo được tạo bởi ctags. Nếu các lệnh này là :linenumber, vim có thể làm những gì tôi làm trong plugin của mình. Nhưng không có gì đảm bảo và thay vào đó, các lệnh này có thể được tìm kiếm /pattern- Vim không thể kiểm tra tất cả các mẫu để biết mẫu nào phù hợp với chức năng hiện tại. Tôi không biết bất kỳ hành động vim nào để bắt đầu dòng điện chức năng
Luc Hermitte

6

Giải pháp của DJ McMayhem đã truyền cảm hứng cho tôi viết bài của riêng mình dựa trên ctags và trên matchit để phân tích chính xác ranh giới chức năng.

Phần khó đã được thực hiện bởi lh-dev và lh-tags trong vài năm:

  • tập tin hiện tại được phân tích cú pháp thông qua ctags với các tùy chọn phù hợp
  • chúng tôi tìm kiếm tất cả các định nghĩa hàm trong cơ sở dữ liệu thẻ được giới hạn ở các thẻ thu được cho tệp hiện tại
  • nhờ DB, chúng tôi có số dòng bắt đầu cho tất cả các chức năng (tốt templateinlinephần nào có thể được bỏ qua bởi ctags)
  • với một tìm kiếm lặp đơn giản (một tìm kiếm nhị phân có thể đã được thực hiện, nhưng tốt, các tệp được cho là "ngắn"), bắt đầu tìm thấy hàm hiện tại
  • Và nhờ có plugin matchit, dòng cuối cùng của nó cũng được tìm thấy - Tôi thấy rằng các ctags phổ quát đang cung cấp một endtrường có thể được sử dụng với C, C ++, Python và Vim cũng có thể được sử dụng để tìm phần cuối của hàm.

Lưu ý rằng bất kỳ phần nào của thuật toán này có thể được ghi đè trên cơ sở loại tệp. tức là phát hiện ranh giới của các hàm python có thể tìm kiếm defvà phân tích thụt lề, chúng ta chỉ có thể tìm kiếm functiontrong javascript, v.v. - Nói cách khác, phiên bản hiện tại cũng hoạt động với Java, Vim và một số ngôn ngữ khác (tôi vẫn còn một số ngôn ngữ khác để làm cho Python)

Vì vậy, bây giờ tôi xác định hai ánh xạ mới: ánh xạ chế độ trực quan và ánh xạ chế độ chờ toán tử:

onoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr>
xnoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr><esc>gv

Mà dựa vào:

function! lh#dev#_select_current_function() abort
  let fn = lh#dev#find_function_boundaries(line('.'))
  exe fn.lines[0]
  normal! v
  exe fn.lines[1]
endfunction

Tôi dành cho bạn hàng trăm dòng mã lh#dev#find_function_boundaries()

Và cảm ơn bản đồ của DJ McMayhem

" Note that my vim settings requires two backslashes here instead of one
vnoremap / <esc>/\\%V

chúng ta có thể làm một vif/patternđể tìm kiếm patterntrong chức năng hiện tại.

Chúng ta cũng có thể xóa các chức năng với dif, kéo chúng với yif, v.v.

Đây là giao diện khi được áp dụng trên hàm C ++ thực tế (nghĩa là không thụt lề 0):Screencast: Chọn chức năng C ++


4

Việc tìm kiếm điểm bắt đầu và kết thúc của một chức năng có thể khó khăn, đặc biệt là trong một ngôn ngữ không có functiontừ khóa LỚN và nhiều kiểu thụt lề mâu thuẫn.

Nếu chức năng của bạn kết thúc bằng một dấu ngoặc đơn trên dòng riêng của nó (như trong 10 trong số 13 kiểu được liệt kê ở đây ), bạn có thể chọn trực quan nó với một cái gì đó như thế này:

xnoremap if /^\s*}<CR><Esc>V%

Từ đó, tìm kiếm footrong chức năng của bạn chỉ là vấn đề:

:'<,'>g/foo/#

Đặt tất cả lại với nhau, chúng ta có thể có được một bản đồ khá đẹp:

xnoremap if /^\s*}<CR><Esc>V%
nmap <key> vif:g//#<Left><Left>

tìm kiếm trong chức năng

Điều đó nói rằng, ánh xạ chế độ trực quan có thể dễ dàng bị đánh lừa bởi một whilehoặc ifvì vậy nó có thể sẽ được hưởng lợi từ một chút đánh bóng. Ngoài ra, giữ lựa chọn trực quan có thể không phải là một ý tưởng hay


Điều này chỉ cần chọn khối tiếp theo nó có thể tìm thấy. Nó không làm việc ở tất cả một khi bạn thêm if, for, whilevv
DJMcMayhem

3

Một giải pháp không hoàn hảo là sử dụng nếp gấp . Gấp mọi thứ:

set foldmethod=syntax
set foldlevel=0
set foldminlines=0

Yêu cầu Vim không mở các khu vực gấp cho kết quả tìm kiếm:

set foldopen-=search

Và sau đó mở nếp gấp trên hàm trong câu hỏi ( zO).

Bây giờ, tất cả các lần truy cập cho văn bản được tìm kiếm trong một vùng được gấp sẽ dẫn đến việc Vim nhảy đến đường gấp một lần, sau đó tiến hành lần truy cập tiếp theo.

Ví dụ: trong trường hợp dưới đây:

nhập mô tả hình ảnh ở đây

Hàm gấp có nhiều cách sử dụng size, nhưng nsẽ không dẫn tôi đến mọi cách sử dụng sizehàm đó.


3

Cách khác:

  • sử dụng ctags, vv để tìm chức năng đích, đi đến đó
  • di chuyển con trỏ về phía trước trong cơ thể chức năng
  • sử dụng toán tử tìm kiếm của Osyo Manga (phụ thuộc vào người dùng vim-toán tử ) để chỉ tìm kiếm bên trong khối hiện tại. Ví dụ:

    " configure the plugin (once, vimrc):
     map g/ <Plug>(operator-search)
    
    " 1. use ctags etc. to jump to the beginning of the target function;
    " 2. move cursor inside the function definition, then:
    g/i{
    

... bây giờ bạn có thể chèn cụm từ tìm kiếm của mình tại dấu nhắc đã cho; nhấn nđể xem kết quả tìm kiếm được giới hạn như thế nào đối với chuyển động / đối tượng văn bản được cung cấp hiện tại. Vì đây là toán tử Vim (tức là có thể kết hợp), nếu bạn có một đối tượng văn bản chức năng tốt, bạn thậm chí không cần phải di chuyển bên trong thân định nghĩa trước khi tìm kiếm, nhưng trực tiếp sử dụng smthing like g/ifhoặc tương tự.

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.