Schnellsuche, beschränkt auf eine C ++ - Funktion

13

Ich arbeite an einem ziemlich großen C ++ - Projekt. Einer der frustrierendsten Aspekte seiner Organisation sind sehr große Funktionen, die in lächerlich großen Dateien gespeichert werden.

Ich möchte oft nach einer Instanz einer bestimmten globalen Variablen oder eines Funktionsaufrufs suchen, der auf die aktuelle Funktion beschränkt ist. Gibt es eine einigermaßen einfache Formel, um dies zu erreichen?

(Ich habe ctags installiert und benutze Tagbar ... das könnte hilfreich sein)

jkerian
quelle

Antworten:

9

So würde ich es machen. Fügen Sie dieses Ihrem hinzu.vimrc

vnoremap if [[O][

Erklärung: vnoremap bedeutet, dass Sie im visuellen Modus die linke Seite ifauf die rechte Seite abbilden [[mO][. ifbedeutet in Funktion , obwohl Sie dies umbenennen können, wenn Sie möchten. [[springt an den Anfang der Funktion. OBewegt sich zum anderen Ende des visuell ausgewählten Texts und dann ][zum Ende der Funktion.

Wenn Sie also in einer Funktion suchen möchten, rufen Sie jetzt mit den visuellen Modus auf vund wählen mit die gesamte Funktion aus if. Beenden Sie nun den visuellen Modus mit <esc>und suchen Sie mit /\%V. \%Vschränkt Ihre Suche auf den zuvor ausgewählten Text ein. Wenn Sie nicht treffen müssen möchten, können <esc>/\%VSie dies auch zu Ihrem hinzufügen .vimrc:

vnoremap / <esc>/\%V

Dann würde Ihre Folge von Tastenanschlägen wie folgt aussehen:

vif/foo<enter>

und dies findet alle Vorkommen von foo in der aktuellen Funktion.


Der einzige Nachteil dieser Methode besteht darin, dass erwartet wird, dass die öffnenden und schließenden Klammern beide einen Einzug von 0 haben. Wenn Sie regelmäßig mit Code arbeiten, der diesen nicht enthält, z

int foo() {
    bar()
}

dann wird diese etwas kompliziertere Version funktionieren:

vnoremap if ][ma%O'a

Dies setzt nur voraus, dass die schließende Klammer einen Einzug von 0 aufweist. Wenn die öffnende Klammer Einrückungen aufweist, funktioniert sie weiterhin, obwohl sie eine Marke einnimmt. Wenn Sie regelmäßig die Markierung 'a' verwenden, können Sie diese verschieben, z

vnoremap if ][mb%O'b
vnoremap if ][mc%O'c
...
DJMcMayhem
quelle
Leider funktioniert dies nicht gut mit C ++ - Funktionen. Im Gegensatz zu C-Funktionen werden sie wahrscheinlich eingerückt (dies ist bei Inline-Member-Funktionen der Fall, die in ihrer Klassendefinition definiert sind, und bei der Standardeinrückung von Funktionen in Namespaces der Fall). Ihre Idee kann jedoch dank des Funktionsdefinitionsbereichs, der mit ctags abgerufen werden kann, weiterentwickelt werden. Ich mache es in der Funktion lh#dev#find_function_boundariesvon lh-dev
Luc Hermitte
3
Netter Ansatz. Wenn Sie die oberste Zeile der Funktion zuverlässig finden, können Sie zur untersten Zeile wechseln {und diese dann verwenden %. Ich vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
bin
1
Bezüglich deiner letzten Bearbeitung. CTRL-]Springt zum Tag unter dem Cursor. Nicht zum Start der aktuellen Funktion. Es wird nicht helfen.
Luc Hermitte
Bezüglich der neuen Bearbeitung. So einfach ist das nicht. Die Schwierigkeit besteht darin, die aktuelle Funktion zu kennen. Wenn die Informationen vorhanden wären, würde die Hilfe von ctags nicht benötigt. Die einzige Möglichkeit, die Informationen (von ctags) abzurufen, besteht darin, die von ctags erzeugten Befehle zum Wechseln zur Deklaration zu analysieren . Wenn diese Befehle vorhanden :linenumberwären, könnte vim das tun, was ich in meinem Plugin tue. Es gibt jedoch keine Garantie, und diese Befehle können stattdessen durchsucht werden. /patternVim kann nicht alle Muster testen, um zu ermitteln, welche der aktuellen Funktionen entsprechen. Ich kenne keine vim-Aktion, um zum Beginn der aktuellen zu springen Funktion
Luc Hermitte
6

Die Lösung von DJ McMayhem hat mich dazu inspiriert, meine eigene zu schreiben, die sich auf ctags und matchit stützt, um eine ordnungsgemäße Analyse der Funktionsgrenzen durchzuführen.

Der schwierige Teil wird bereits seit einigen Jahren von lh-dev und lh-tags erledigt :

  • Die aktuelle Datei wird durch ctags mit den richtigen Optionen analysiert
  • Wir suchen nach allen Funktionsdefinitionen in der Tags-Datenbank, die auf die für die aktuelle Datei erhaltenen Tags beschränkt sind
  • dank der DB haben wir die Startzeilennummern für alle Funktionen (auch der templateund inlineTeil kann von ctags übersehen werden)
  • mit einer einfachen iterativen Suche (eine binäre Suche hätte durchgeführt werden können, aber Dateien sollten "kurz" sein) wird der Anfang der aktuellen Funktion gefunden
  • Und dank des Matchit-Plugins wird auch die letzte Zeile gefunden - ich sehe, dass universal ctags ein endFeld anbietet , das mit C, C ++, Python und Vim verwendet werden kann, um auch das Ende einer Funktion zu finden.

Beachten Sie, dass Teile dieses Algorithmus auf Dateitypbasis überschrieben werden können. dh die Erkennung der Grenzen von Python-Funktionen könnte nach defEinrückungen suchen und diese analysieren, wir könnten nur functionin Javascript suchen und so weiter - Mit anderen Worten, die aktuelle Version funktioniert auch mit Java, Vim und einigen anderen Sprachen (ich habe noch etwas Arbeit) für Python zu tun)

Daher definiere ich jetzt zwei neue Zuordnungen: eine visuelle Moduszuordnung und eine vom Bediener ausstehende Moduszuordnung:

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

Welche stützen sich auf:

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

Ich erspare Ihnen die mehreren hundert Codezeilen von lh#dev#find_function_boundaries()

Und dank DJ McMayhem's Mapping

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

Wir können in der aktuellen Funktion vif/patternnach a suchen pattern.

Wir können auch Funktionen mit löschen, mit difziehen yifusw.

So sieht es aus, wenn es auf eine realistische C ++ - Funktion angewendet wird (dh nicht mit 0 eingerückt):Screencast: Wählen Sie die C ++ - Funktion

Luc Hermitte
quelle
4

Das Finden von Anfang und Ende einer Funktion kann schwierig sein, insbesondere in einer Sprache ohne functionSchlüsselwort… und in vielen unterschiedlichen Einrückungsstilen.

Wenn Ihre Funktion mit einer schließenden Klammer in einer eigenen Zeile endet (wie in 10 der 13 hier aufgelisteten Stile ), können Sie sie visuell wie folgt auswählen:

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

Von dort aus ist die Suche fooinnerhalb Ihrer Funktion nur noch eine Frage von:

:'<,'>g/foo/#

Wenn wir alles zusammenfassen, erhalten wir ein ziemlich schönes Mapping:

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

suche in funktion

Das heißt, das Mapping des visuellen Modus würde wahrscheinlich leicht von einem whileoder mehreren getäuscht werden if, und es würde wahrscheinlich von etwas Polieren profitieren. Auch die visuelle Auswahl beizubehalten, ist möglicherweise keine gute Idee…

romainl
quelle
Dies wählt nur den nächsten Block aus, den es finden kann. Es ist nicht funktionieren , wenn Sie hinzufügen if, for, whileetc.
DJMcMayhem
3

Eine unvollständige Lösung ist die Verwendung von Falten . Falten Sie alles:

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

Weisen Sie Vim an, keine gefalteten Bereiche für Suchergebnisse zu öffnen:

set foldopen-=search

Und dann öffne die Klappe für die betreffende Funktion ( zO).

Jetzt führen alle Treffer für den gesuchten Text in einem gefalteten Bereich dazu, dass Vim einmal zur Faltlinie springt und dann zum nächsten Treffer weitergeht.

Zum Beispiel im folgenden Fall:

Bildbeschreibung hier eingeben

Die gefaltete Funktion hat viele Verwendungsmöglichkeiten size, nführt mich aber nicht um jede Verwendung sizein dieser Funktion herum .

muru
quelle
3

Ein anderer Weg:

  • benutze ctags etc. um die Zielfunktion zu finden, gehe dorthin
  • Bewegen Sie den Cursor innerhalb des Funktionskörpers nach vorne
  • Verwenden Sie den Suchoperator von Osyo Manga (abhängig vom vim-operator-user ), um nur innerhalb des aktuellen Blocks zu suchen. Z.B:

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

... jetzt können Sie Ihren Suchbegriff an der angegebenen Eingabeaufforderung eingeben; Klicken Sie nauf, um zu sehen, wie die Suchergebnisse auf das aktuell bereitgestellte Bewegungs- / Textobjekt beschränkt sind. Da dies ein Vim-Operator (dh ein komponierbarer Operator) ist, müssen Sie, wenn Sie ein Textobjekt mit guter Funktion haben, vor der Suche nicht einmal innerhalb des Definitionskörpers navigieren, sondern direkt smthing like g/ifoder ähnliches verwenden.

VanLaser
quelle