Recherche rapide, limitée à une fonction C ++

13

Je travaille sur un projet C ++ assez volumineux. L'un des aspects les plus frustrants de son organisation est les très grandes fonctions placées dans des fichiers ridiculement volumineux.

Je souhaite souvent rechercher n'importe quelle instance d'une variable globale ou d'un appel de fonction particulier, limité à la fonction actuelle. Existe-t-il une formule raisonnablement simple pour y parvenir?

(J'ai des ctags installés et j'utilise Tagbar ... ce qui pourrait être utile pour cela)

jkerian
la source

Réponses:

9

Voici comment je le ferais. Ajoutez ceci à votre.vimrc

vnoremap if [[O][

Explication: vnoremap signifie mapper le côté gauche ifvers le côté droit [[mO][lorsque vous êtes en mode visuel. ifsignifie In Function , bien que vous puissiez le renommer si vous le souhaitez. [[saute au début de la fonction. Ose déplace à l'autre extrémité de votre texte sélectionné visuellement, puis ][se déplace à la fin de la fonction.

Donc, si vous souhaitez rechercher dans une fonction, vous entrez maintenant en mode visuel avec vet sélectionnez la fonction entière avec if. Quittez maintenant le mode visuel avec <esc>et recherchez avec /\%V. \%Vrestreint votre recherche au texte précédemment sélectionné. Si vous ne voulez pas avoir à frapper, <esc>/\%Vvous pouvez également l'ajouter à votre .vimrc:

vnoremap / <esc>/\%V

Ensuite, votre séquence de touches ressemblerait à ceci:

vif/foo<enter>

et cela trouvera toutes les occurrences de foo dans la fonction actuelle.


Le seul inconvénient de cette méthode est qu'elle s'attend à ce que les accolades d'ouverture et de fermeture aient toutes deux une indentation de 0. Si vous travaillez régulièrement avec du code qui n'en a pas, par exemple

int foo() {
    bar()
}

alors cette version légèrement plus compliquée fonctionnera:

vnoremap if ][ma%O'a

Cela n'attend que l'accolade fermante à 0 indentation. Si l'accolade ouvrante a des retraits, elle fonctionne toujours, bien qu'elle prenne une marque. Si vous utilisez régulièrement la marque «a», vous pouvez la déplacer par exemple

vnoremap if ][mb%O'b
vnoremap if ][mc%O'c
...
James
la source
Hélas, cela ne fonctionne pas bien avec les fonctions C ++. Contrairement aux fonctions C, elles sont susceptibles d'être indentées (c'est le cas des fonctions membres inline définies dans leur définition de classe et de l'indentation par défaut des fonctions dans les espaces de noms). Cependant, votre idée peut être développée grâce à la plage de définition de fonction qui peut être obtenue avec ctags. Je le fais dans la fonction lh#dev#find_function_boundariesde lh-dev
Luc Hermitte
3
Belle approche. Si vous pouvez trouver de manière fiable la ligne supérieure de la fonction, vous pouvez vous déplacer vers le {puis utiliser %pour atteindre la ligne inférieure. Je ne sais pas comment vous pourriez trouver la fonction démarrer en C ++, mais cela fonctionne bien pour Javascript:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle
1
Concernant votre dernier montage. CTRL-]saute à la balise sous le curseur. Pas au début de la fonction actuelle. Ça n'aidera pas.
Luc Hermitte
Concernant la nouvelle édition. Ce n'est pas si simple. La difficulté est de faire connaître à vim la fonction actuelle. S'il avait les informations, il n'aurait pas besoin d'aide pour ctags. La seule façon d'obtenir les informations (à partir de ctags) est d'analyser les commandes de saut vers déclaration produites par ctags. Si ces commandes l'étaient :linenumber, vim pourrait faire ce que je fais dans mon plugin. Mais il n'y a aucune garantie, et ces commandes peuvent à la place être des recherches /pattern- s - Vim ne peut pas tester tous les modèles pour savoir lequel correspond à la fonction en cours. fonction
Luc Hermitte
6

La solution de DJ McMayhem m'a inspiré pour écrire le mien qui s'appuie sur ctags et sur matchit pour faire une analyse appropriée des limites de fonctions.

La partie difficile est déjà réalisée par lh-dev et lh-tags depuis plusieurs années:

  • le fichier actuel est analysé par ctags avec les bonnes options
  • nous recherchons toutes les définitions de fonction dans la base de données de balises qui est limitée aux balises obtenues pour le fichier courant
  • grâce à la DB, nous avons les numéros de ligne de départ pour toutes les fonctions (bien la templateet une inlinepartie peut MANQUER par ctags)
  • avec une recherche itérative simple (une recherche binaire aurait pu être faite, mais bon, les fichiers sont supposés être "courts"), le début de la fonction courante est trouvé
  • Et grâce au plugin matchit, sa ligne finale est également trouvée - je vois que les ctags universels offrent un endchamp qui peut être utilisé avec C, C ++, Python et Vim qui pourrait également être utilisé pour trouver la fin d'une fonction.

Notez que toutes les parties de cet algorithme peuvent être remplacées par type de fichier. c'est-à-dire que la détection des limites des fonctions python pourrait rechercher defet analyser l'indentation, nous pourrions simplement rechercher functionen javascript, etc. - En d'autres termes, la version actuelle fonctionne également avec Java, Vim et d'autres langages (j'ai encore du travail à faire pour Python)

Je définis donc maintenant deux nouveaux mappages: un mappage de mode visuel et un mappage de mode en attente d'opérateur:

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

Qui s'appuient sur:

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

Je vous épargne les quelques centaines de lignes de code de lh#dev#find_function_boundaries()

Et grâce à la cartographie de DJ McMayhem

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

nous pouvons faire une vif/patternrecherche patterndans la fonction actuelle.

Nous pouvons également supprimer des fonctions avec dif, les tirer avec yif, etc.

Voici à quoi cela ressemble lorsqu'il est appliqué sur une fonction C ++ réaliste (c'est-à-dire non en retrait 0):Screencast: Sélectionnez la fonction C ++

Luc Hermitte
la source
4

Trouver le début et la fin d'une fonction peut être difficile, surtout dans une langue sans functionmot - clé… et dans de nombreux styles de retrait conflictuels.

Si votre fonction se termine par une accolade fermante seule sur sa propre ligne (comme dans 10 des 13 styles répertoriés ici ), vous pouvez la sélectionner visuellement avec quelque chose comme ceci:

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

A partir de là, la recherche au foosein de votre fonction n'est plus qu'une question de:

:'<,'>g/foo/#

En mettant tout cela ensemble, nous pouvons obtenir une cartographie plutôt sympa:

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

recherche en fonction

Cela dit, la cartographie du mode visuel serait probablement facilement trompée par un whileou un ifdonc elle bénéficierait probablement d'un peu de polissage. De plus, conserver la sélection visuelle peut ne pas être une très bonne idée…

romainl
la source
Cela sélectionne simplement le bloc suivant qu'il peut trouver. Il ne fonctionne pas du tout une fois que vous ajoutez if, for, while, etc.
James
3

Une solution imparfaite utilise des plis . Pliez tout:

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

Dites à Vim de ne pas ouvrir les zones pliées pour les résultats de recherche:

set foldopen-=search

Et puis ouvrez le pli sur la fonction en question ( zO).

Maintenant, tous les hits pour le texte recherché dans une région pliée entraîneront Vim sauter à la ligne de pliage une fois, puis passer au hit suivant.

Par exemple, dans le cas ci-dessous:

entrez la description de l'image ici

La fonction pliée a de nombreux usages size, mais nne me guidera pas autour de chaque utilisation de sizecette fonction.

muru
la source
3

Autrement:

  • utilisez ctags etc. pour trouver la fonction cible, allez-y
  • déplacer le curseur vers l'avant à l'intérieur du corps de la fonction
  • utilisez l' opérateur de recherche d' Osyo Manga (dépend de vim-operator-user ) pour rechercher uniquement à l'intérieur du bloc actuel. Par exemple:

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

... vous pouvez maintenant insérer votre terme de recherche à l'invite donnée; cliquez npour voir comment les résultats de la recherche sont limités à l'objet de mouvement / texte actuellement fourni. Comme il s'agit d'un opérateur Vim (c'est-à-dire composable), si vous avez un bon objet texte de fonction, vous n'avez même pas besoin de vous déplacer à l'intérieur du corps de définition avant de rechercher, mais utilisez directement smthing like g/ifou similaire.

VanLaser
la source