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)
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
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
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>
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…
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:
Die gefaltete Funktion hat viele Verwendungsmöglichkeiten size, nführt mich aber nicht um jede Verwendung sizein dieser Funktion herum .
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.
lh#dev#find_function_boundaries
von lh-dev{
und diese dann verwenden%
. Ichvnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
CTRL-]
Springt zum Tag unter dem Cursor. Nicht zum Start der aktuellen Funktion. Es wird nicht helfen.:linenumber
wä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./pattern
Vim 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 FunktionDie 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 :
template
undinline
Teil kann von ctags übersehen werden)end
Feld 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
def
Einrückungen suchen und diese analysieren, wir könnten nurfunction
in 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:
Welche stützen sich auf:
Ich erspare Ihnen die mehreren hundert Codezeilen von
lh#dev#find_function_boundaries()
Und dank DJ McMayhem's Mapping
Wir können in der aktuellen Funktion
vif/pattern
nach a suchenpattern
.Wir können auch Funktionen mit löschen, mit
dif
ziehenyif
usw.So sieht es aus, wenn es auf eine realistische C ++ - Funktion angewendet wird (dh nicht mit 0 eingerückt):
quelle
Das Finden von Anfang und Ende einer Funktion kann schwierig sein, insbesondere in einer Sprache ohne
function
Schlü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:
Von dort aus ist die Suche
foo
innerhalb Ihrer Funktion nur noch eine Frage von:Wenn wir alles zusammenfassen, erhalten wir ein ziemlich schönes Mapping:
Das heißt, das Mapping des visuellen Modus würde wahrscheinlich leicht von einem
while
oder mehreren getäuscht werdenif
, und es würde wahrscheinlich von etwas Polieren profitieren. Auch die visuelle Auswahl beizubehalten, ist möglicherweise keine gute Idee…quelle
if
,for
,while
etc.Eine unvollständige Lösung ist die Verwendung von Falten . Falten Sie alles:
Weisen Sie Vim an, keine gefalteten Bereiche für Suchergebnisse zu öffnen:
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:
Die gefaltete Funktion hat viele Verwendungsmöglichkeiten
size
,n
führt mich aber nicht um jede Verwendungsize
in dieser Funktion herum .quelle
Ein anderer Weg:
Verwenden Sie den Suchoperator von Osyo Manga (abhängig vom vim-operator-user ), um nur innerhalb des aktuellen Blocks zu suchen. Z.B:
... jetzt können Sie Ihren Suchbegriff an der angegebenen Eingabeaufforderung eingeben; Klicken Sie
n
auf, 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 likeg/if
oder ähnliches verwenden.quelle