Pesquisa rápida, limitada a uma função C ++


13

Eu trabalho em um projeto C ++ bastante grande. Um dos aspectos mais frustrantes de sua organização são as funções muito grandes inseridas em arquivos ridiculamente grandes.

Muitas vezes, quero procurar qualquer instância de uma variável global específica ou chamada de função, restrita à função atual. Existe uma fórmula razoavelmente simples para fazer isso?

(Eu tenho ctags instalado e uso o Tagbar ... o que pode ser útil para isso)

Respostas:


9

Aqui está como eu faria isso. Adicione isto ao seu.vimrc

vnoremap if [[O][

Explicação: vnoremap significa mapear o lado esquerdo ifpara o lado direito [[mO][enquanto você estiver no modo visual. ifsignifica Em Função , embora você possa renomear isso, se quiser. [[pula para o início da função. Omove para a outra extremidade do texto selecionado visualmente e depois ][para o final da função.

Portanto, se você deseja pesquisar em uma função, agora entra no modo visual com ve seleciona a função inteira com if. Agora saia do modo visual com <esc>e pesquise com /\%V. \%Vrestringe sua pesquisa ao texto selecionado anteriormente. Se você não quer bater, <esc>/\%Vtambém pode adicionar isso ao seu .vimrc:

vnoremap / <esc>/\%V

Em seguida, sua sequência de pressionamentos de teclas seria semelhante a:

vif/foo<enter>

e isso encontrará todas as ocorrências de foo na função atual.


A única desvantagem desse método é que ele espera que as chaves de abertura e fechamento tenham 0 recuo. Se você trabalha regularmente com código que não possui isso, por exemplo,

int foo() {
    bar()
}

então esta versão um pouco mais complicada funcionará:

vnoremap if ][ma%O'a

Isso espera apenas que a chave de fechamento tenha 0 recuo. Se a chave de abertura tiver recuos, ela ainda funcionará, embora ocupe uma marca. Se você usa regularmente a marca 'a', pode movê-la, por exemplo

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

Infelizmente, isso não funciona bem com funções C ++. Diferentemente das funções C, é provável que elas sejam recuadas (é o caso das funções de membros embutidas definidas em sua definição de classe e com o recuo padrão de funções nos espaços para nome). No entanto, sua ideia pode ser aproveitada graças ao intervalo de definição de função que pode ser obtido com ctags. Eu faço isso na função lh#dev#find_function_boundariesde lh-dev
Luc Hermitte

3
Boa abordagem. Se você puder encontrar com segurança a linha superior da função, poderá ir para a {e usar %para alcançar a linha inferior. Não tenho certeza de como você pode encontrar a função iniciar em C ++, mas isso funciona bem para Javascript:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle 24/16/16

1
Em relação à sua última edição. CTRL-]pula para a tag abaixo do cursor. Não é para o início da função atual. Isso não vai ajudar.
Luc Hermitte 25/05

Em relação à nova edição. Não é assim tão simples. A dificuldade é que o vim conheça a função atual. Se tivesse a informação, não exigiria ajuda das ctags. A única maneira de obter as informações (de ctags) é analisar os comandos de salto para declaração produzidos por ctags. Se esses comandos fossem :linenumber, o vim poderia fazer o que eu faço no meu plugin. Mas não há garantia, e esses comandos podem ser pesquisados /pattern- o Vim não pode testar todos os padrões para saber qual deles corresponde à função atual. função
Luc Hermitte

6

A solução do DJ McMayhem me inspirou a escrever minha própria, que depende de ctags e matchit, para fazer uma análise adequada dos limites das funções.

A parte difícil já foi feita pelo lh-dev e lh-tags por vários anos:

  • o arquivo atual é analisado através de ctags com as opções corretas
  • procuramos todas as definições de funções no banco de dados de tags, restritas às tags obtidas para o arquivo atual
  • graças ao DB, temos os números da linha de partida para todas as funções (bem, a parte templatee inlinepode ser perdida por ctags)
  • com uma pesquisa iterativa simples (uma pesquisa binária poderia ter sido feita, mas os arquivos devem ser "curtos"), o início da função atual é encontrado
  • E graças ao plug-in matchit, sua linha final também é encontrada - vejo que ctags universais estão oferecendo um endcampo que pode ser usado com C, C ++, Python e Vim, que também pode ser usado para encontrar o fim de uma função.

Observe que qualquer parte desse algoritmo pode ser substituída com base no tipo de arquivo. ou seja, a detecção de limites das funções python poderia procurar defe analisar a indentação, poderíamos procurar apenas functionem javascript e assim por diante - Em outras palavras, a versão atual também funciona com Java, Vim e outras linguagens (ainda tenho algum trabalho fazer pelo Python)

Portanto, defino agora dois novos mapeamentos: um mapeamento de modo visual e um mapeamento de modo pendente de operador:

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

Que contam com:

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

Eu poupo as várias centenas de linhas de código de lh#dev#find_function_boundaries()

E graças ao mapeamento do DJ McMayhem

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

podemos fazer um vif/patternpara procurar patternna função atual.

Também podemos excluir funções com dif, puxá-las com yif, etc.

Aqui está o que parece quando aplicado em uma função C ++ realista (ou seja, não recuada com 0):Screencast: selecione a função C ++


4

Encontrar o início e o fim de uma função pode ser difícil, especialmente em um idioma sem uma functionpalavra - chave ... e muitos estilos de recuo conflitantes.

Se sua função terminar com uma chave de fechamento sozinha em sua própria linha (como em 10 dos 13 estilos listados aqui ), você poderá selecioná-la visualmente com algo como isto:

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

A partir daí, pesquisar foona sua função é apenas uma questão de:

:'<,'>g/foo/#

Juntando tudo, podemos obter um mapeamento bastante agradável:

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

pesquisa em função

Dito isto, o mapeamento do modo visual provavelmente seria facilmente enganado por um whileou outro, ifpor isso provavelmente se beneficiaria de um pouco de polimento. Além disso, manter a seleção visual pode não ser uma boa ideia…


Isso apenas seleciona o próximo bloco que pode encontrar. Ele não funciona em todos, uma vez que você adiciona if, for, while, etc.
James

3

Uma solução imperfeita é usar dobras . Dobre tudo:

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

Diga ao Vim para não abrir áreas dobradas para os resultados da pesquisa:

set foldopen-=search

E abra a dobra na função em questão ( zO).

Agora, todos os hits para o texto pesquisado em uma região dobrada resultarão no Vim pulando para a linha de dobra uma vez e depois para o próximo hit.

Por exemplo, no caso abaixo:

insira a descrição da imagem aqui

A função dobrada tem muitos usos size, mas nnão me leva a todos os usos sizenessa função.


3

Outra maneira:

  • use ctags etc. para encontrar a função alvo, vá lá
  • mover o cursor para frente dentro do corpo da função
  • use o operador de pesquisa do Osyo Manga (depende do vim-operator-user ) para pesquisar apenas dentro do bloco atual. Por exemplo:

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

... agora você pode inserir seu termo de pesquisa no prompt fornecido; clique npara ver como os resultados da pesquisa são limitados ao movimento / objeto de texto fornecido atualmente. Como esse é um operador Vim (ou seja, compostável), se você possui uma boa função objeto de texto, nem precisa se mover dentro do corpo da definição antes de pesquisar, mas usar diretamente algo parecido g/ifou semelhante.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.