C ++ işleviyle sınırlı hızlı arama


13

Oldukça büyük bir C ++ projesi üzerinde çalışıyorum. Kuruluşunun daha sinir bozucu yönlerinden biri, gülünç derecede büyük dosyaların içine yerleştirilen çok büyük işlevlerdir.

Sıklıkla geçerli işlevle sınırlı belirli bir genel değişken veya işlev çağrısının herhangi bir örneğini aramak istiyorum. Bunu başarmak için oldukça basit bir formül var mı?

(Yüklü ctags var ve bunun için yararlı olabilir Tagbar ... kullanın)

Yanıtlar:


9

İşte böyle yapardım. Bunu.vimrc

vnoremap if [[O][

Açıklama: vnoremap , görsel moddayken sol tarafı ifsağ tarafa eşlemek anlamına gelir [[mO][. İsterseniz bunu yeniden adlandırabilirsiniz, ancak İşlev içindeif anlamına gelir . işlevin başlangıcına atlar. görsel olarak seçtiğiniz metnin diğer ucuna gider ve ardından işlevin sonuna gider.[[O][

Dolayısıyla, bir işlevde arama yapmak istiyorsanız, şimdi ile görsel moda girersiniz vve ile tüm işlevi seçersiniz if. Şimdi ile görsel moddan çıkın <esc>ve ile arama yapın /\%V. \%Varamanızı daha önce seçilen metinle sınırlar. Vurmak istemiyorsanız, bunu aşağıdakilere <esc>/\%Vde ekleyebilirsiniz .vimrc:

vnoremap / <esc>/\%V

Ardından, tuş vuruşları diziniz şöyle görünecektir:

vif/foo<enter>

ve bu, mevcut işlevdeki tüm foo oluşumlarını bulur.


Bu yöntemin tek dezavantajı, açılış ve kapanış parantezlerinin her ikisinin de 0 girinti olmasını beklemesidir. Düzenli olarak buna sahip olmayan bir kodla çalışıyorsanız, ör.

int foo() {
    bar()
}

o zaman bu biraz daha karmaşık sürüm çalışacaktır:

vnoremap if ][ma%O'a

Bu, yalnızca kapama ayracı 0 girinti olmasını bekler. Açılış ayracı girintilere sahipse, bir işaret almasına rağmen hala çalışır. Düzenli olarak 'a' işaretini kullanıyorsanız, bunu örneğin

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

Ne yazık ki bu C ++ fonksiyonları ile iyi çalışmıyor. C işlevlerinden farklı olarak, girintili olmaları muhtemeldir (sınıf tanımlarında tanımlanan satır içi üye işlevlerinde ve ad alanları içindeki işlevlerin varsayılan girintisinde olduğu gibi). Bununla birlikte, fikriniz ctags ile elde edilebilen fonksiyon tanımı aralığı sayesinde oluşturulabilir. Bunu lh#dev#find_function_boundarieslh-
dev'den

3
Güzel yaklaşım. Fonksiyonun üst satırını güvenilir bir şekilde bulabilirseniz , alt satıra ulaşmak için {öğesine gidebilir ve kullanabilirsiniz %. Bu işlevi C ++ ile nasıl başlatacağınızdan emin değilsiniz, ancak bu Javascript için uygun çalışıyor:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle

1
Son düzenlemenizle ilgili. CTRL-]imlecin altındaki etikete atlar. Geçerli işlevin başlangıcına değil. Yardımcı olmaz.
Luc Hermitte

Yeni düzenleme ile ilgili. Bu o kadar basit değil. Zorluk vim'in mevcut işlevi bilmesini sağlamaktır. Bilgiye sahip olsaydı, ctags yardımı gerektirmezdi. Bilgiyi elde etmenin tek yolu (ctags'ten), ctags tarafından üretilen atlamadan bildirime komutlarını analiz etmektir . Bu komutlar olsaydı :linenumber, vim eklentimde yaptığımı yapabilirdi. Ancak garanti yoktur ve bu komutlar /patternaramalar olabilir - Vim, geçerli işlevle hangisinin eşleştiğini bilmek için tüm desenleri test edemez. işlevi
Luc Hermitte

6

DJ McMayhem'in çözümü , ctags'a ve matchit'e dayanan ve fonksiyon sınırlarının uygun bir analizini yapmam için bana ilham verdi.

Zor kısım birkaç yıldır lh-dev ve lh-tags tarafından yapılmıştır:

  • geçerli dosya doğru seçeneklerle ctags aracılığıyla ayrıştırılır
  • geçerli veri için elde edilen etiketlerle kısıtlı olan etiketler veritabanında tüm işlev tanımlarını ararız
  • DB sayesinde, tüm işlevler için başlangıç ​​satırı numaralarımız var ( templateve inlineparçası ctags tarafından atlanabilir)
  • basit bir yinelemeli arama ile (bir ikili arama yapılmış olabilir, ancak dosyaların "kısa" olması gerekiyordu), mevcut fonksiyonun başlangıcı bulunur
  • Ve matchit eklentisi sayesinde, son satırı da bulunur - Evrensel ctags'ın, endbir fonksiyonun sonunu bulmak için de kullanılabilecek C, C ++, Python ve Vim ile kullanılabilecek bir alan sunduğunu görüyorum .

Bu algoritmanın herhangi bir bölümünün dosya türü temelinde geçersiz kılınabileceğini unutmayın. yani python fonksiyonlarının sınır tespiti defgirintiyi arayabilir ve analiz edebilir, sadece functionjavascript içinde arayabiliriz , vb. - Başka bir deyişle, mevcut sürüm ayrıca Java, Vim ve diğer bazı dillerle de çalışır Python için yapmak)

Şimdi iki yeni eşleme tanımlarım: görsel mod eşlemesi ve operatör bekleyen mod eşlemesi:

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

Hangi güveniyor:

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

Sana birkaç yüz kod satırı ekliyorum lh#dev#find_function_boundaries()

DJ McMayhem'in haritalaması sayesinde

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

geçerli işlevde vif/patternaramak için bir yapabiliriz pattern.

Ayrıca dif, işlevleri silebilir , yanlarına alabilir yifvb.

Gerçekçi bir C ++ işlevine uygulandığında (ör. 0 girintili değil) şöyle görünür :Ekran Kaydı: C ++ işlevini seçin


4

Bir fonksiyonun başlangıcını ve sonunu bulmak, özellikle functionanahtar kelime içermeyen bir dilde … ve birçok çelişkili girinti stilinde zor olabilir .

İşleviniz kendi satırında tek başına bir kapanış ayracı ile bitiyorsa ( burada listelenen 13 stilin 10'unda olduğu gibi ), görsel olarak böyle bir şeyle seçebilirsiniz:

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

Oradan, fooişlevinizde arama yapmak sadece bir konudur:

:'<,'>g/foo/#

Hepsini bir araya getirerek, oldukça güzel bir harita elde edebiliriz:

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

işlevde arama

Bununla birlikte, görsel mod eşlemesi muhtemelen bir whileya da bir tarafından kolayca kandırılacaktır, ifbu nedenle muhtemelen biraz parlatmadan faydalanacaktır. Ayrıca, görsel seçimi korumak çok iyi bir fikir olmayabilir…


Bu sadece bulabileceği bir sonraki bloğu seçer. Eklemek kez O hiç çalışmıyor if, for, whilevb
James

3

Kusursuz bir çözüm kıvrımlar kullanıyor . Her şeyi katlayın:

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

Vim'e arama sonuçları için katlanmış alanlar açmamasını söyleyin:

set foldopen-=search

Ve sonra ( zO) işlevindeki katlamayı açın .

Şimdi, katlanmış bir bölgedeki aranan metne yapılan tüm isabetler, Vim'in katlama çizgisine bir kez atlamasına ve ardından bir sonraki isabete ilerlemesine neden olur.

Örneğin, aşağıdaki durumda:

resim açıklamasını buraya girin

Katlanmış işlevin birçok kullanımı vardır size, ancak nbeni sizebu işlevin her kullanımı etrafında yönlendirmez .


3

Diğer yol:

  • hedef işlevi bulmak için ctags vb. kullanın, oraya gidin
  • imleci işlev gövdesi içinde ileriye taşı
  • yalnızca geçerli blok içinde arama yapmak için Osyo Manga'nın arama operatörünü ( vim-operatörü-kullanıcıya bağlıdır ) kullanın. Örneğin:

    " 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{
    

... şimdi arama teriminizi verilen bilgi istemine ekleyebilirsiniz; narama sonuçlarının sağlanan mevcut hareket / metin nesnesi ile nasıl sınırlı olduğunu görmek için tuşuna basın. Bu bir Vim (yani oluşturulabilir) operatörü olduğundan, iyi bir işlev metin nesnesine sahipseniz, arama yapmadan önce tanım gövdesinin içinde hareket etmeniz bile gerekmez, ancak doğrudan g/ifbenzer veya benzeri bir şey kullanmanız gerekir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.