Como procurar padrões em determinadas regiões de sintaxe?

10

Estou usando o vim para editar documentos de látex. Muitas vezes, vou querer mudar o nome de uma variável para outra coisa. No entanto, é um pouco chato ter que percorrer correspondências irrelevantes quando procuro o nome da variável. Eu gostaria de pesquisar apenas em "zonas matemáticas", conforme definido no arquivo de sintaxe tex. Existe uma maneira fácil de limitar uma pesquisa a uma região de sintaxe específica?

Rob F.
fonte
11
Acho que a resposta é não: não há uma maneira fácil de limitar uma pesquisa a uma região de sintaxe específica.
Karl Yngve Lervåg
2
Esse mapeamento usa synIDattr()para obter grupos de sintaxe para o caractere sob o cursor. Você pode escrever uma função que realiza a pesquisa (ou faz normal n) e depois usa synIDattr()para decidir se deve permanecer nesse local ou continuar a pesquisa adiante.
Joeytwiddle
@joeytwiddle Vi seu comentário agora mesmo depois de postar uma resposta com essa função. É como o que você tinha em mente?
Jjaderberg 11/08
@jjaderberg Sim, é. Bom trabalho!
Joeytwiddle
Apenas para a completude (eu achei uma boa resposta): stackoverflow.com/a/2696143/5000478
VanLaser

Respostas:

4

Aqui está uma função que você pode tentar. Eu só testei um pouco, mas parece funcionar bem.

function! JJSyntaxSearch(pattern, syntaxitem)
  while search(a:pattern, 'W') > 0
    for id in synstack(line("."),col("."))
      if synIDattr(id,"name") =~? a:syntaxitem
        return line(".")
      endif
    endfor
  endwhile
  return 0
endfunc

command! -nargs=* JJSyntaxSearch call JJSyntaxSearch(<f-args>)

A função chama a função de pesquisa do Vim em um loop até encontrar uma correspondência 'comum' que também é uma correspondência 'qualificada' para um item de sintaxe específico ou até chegar ao final do buffer.

São necessários dois argumentos. O primeiro é o padrão de pesquisa e é passado inalterado para a search()função do Vim . Veja :help search()como essa função funciona. O segundo argumento é o nome do item de sintaxe no qual você deseja filtrar essas correspondências. Isso também pode ser um padrão e é comparado como uma expressão regular que não diferencia maiúsculas de minúsculas.

Para encontrar o padrão 'alfa' nas zonas matemáticas, você pode fazer

:JJSyntaxSearch alpha texMathZone.

O .no final é o átomo padrão para qualquer caractere único, veja :help /.. Isso ocorre porque há muitos itens de sintaxe zona matemática chamada texMathZoneA, texMathZoneBetc.

A search()função move o cursor para a próxima correspondência 'comum'. Em seguida, nossa função obtém todos os IDs de item de sintaxe para essa nova posição do cursor synstack(). Dando um loop neles, ele recupera o nome de cada item e o testa contra o syntaxitemargumento. Veja :help synstack()e :help synIDattr(). Se houver uma correspondência 'qualificada', ele retornará o número da linha. Se atingir o final do buffer sem encontrar nenhuma correspondência 'qualificada', ele retornará 0. O objetivo da função é levar o cursor para a próxima correspondência 'qualificada', para que você possa fazer alguma operação lá, mas é útil retornar "número da linha ou 0" para indicar se é significativo chamar a função novamente, por exemplo, se você quiser chamar a função repetidamente de outra função ou macro.

Eu escolhi usar o Wsinalizador para search()isso porque ele evita 'envolver' o final do buffer. Caso contrário, a função poderá ficar paralisada, pois continua encontrando as mesmas correspondências "comuns", mas nenhuma correspondência "qualificada".

jjaderberg
fonte
Obrigado pela ajuda! Ainda não tentei essa função, mas parece que eu queria.
Rob F.
1

Caso suas "zonas matemáticas" sejam qualificadas por algum padrão sintático, por exemplo, a string "math", você pode pelo menos usar sequências de padrões para encontrar uma linha com o padrão correspondente, como em:

:/math//your pattern/

(Nota: os dois padrões podem estar em linhas diferentes!)

Isso pode não restringir suas correspondências às zonas - para isso você precisa identificar o final da zona -, mas exibirá apenas essas correspondências após um padrão inicial / math /. Você pode repetir a pesquisa para a próxima ocorrência usando o histórico do modo ex ( : up-arrow enter).


Nota: ISTR que nas versões anteriores do vim / vi eu também era capaz de usar esse método diretamente como um comando de pesquisa (em oposição a um comando ex-mode) /math//your pattern/com a vantagem de menos digitação e uso dos comandos ne N, mas não posso confirmar isso para a minha versão atual do vim.

Janis
fonte
1

Se você estiver procurando pela string foodentro $...$ou $$...$$, isso deve funcionar:

\$.*\zsfoo

Isso ancora a correspondência em um $caractere, mas seleciona apenas a sequência foo.

Não é realmente uma solução fácil, mas é possível usar um :global+ :substitutepara encontrar "zonas matemáticas" e pesquisar dentro delas:

:global /\v\\begin\{%(align|alignat|displaymath)\}/ +1,/\\end/-1 s/foo/&/gc

Fingindo que :substituteé um comando de pesquisa, você pode ir para a próxima ocorrência com ne sair com q. Se você confirmar uma substituição por engano, não deverá haver nenhum problema.

Você terá que definir a lista dentro de %(... )com os nomes dos ambientes matemáticos que você usa (a lista completa é um pouco pesada:) align|alignat|displaymath|eqnarray|equation|flalign|gather|math|multline|subequations|xalignat|xxalignat. Observe que estou usando um \vpadrão muito mágico ( ) aqui.

Explicação:

:globalexecutar um comando Ex ( :s) em cada linha onde os jogos padrão ( :help :global)
/\viniciar um padrão muito mágico ( :h /, :h pattern, :h magic)
\\begin\{corresponder a um literal \begin{
%(align|alignat|displaymath)jogo qualquer uma destas palavras ( :h /\%(, :h /bar)
\}/corresponder a um literal }e acabar com o padrão.

+1,/\\end/-1um intervalo que consiste na próxima linha (contando desde a encontrada por :global) até a linha anterior à encontrada pelo padrão de pesquisa /\\end. Dentro desse intervalo,

s/foo/&/gcpesquise e substitua todas as ocorrências do literal foopor si mesmo, após confirmação ( :h :substitute)

Peter Lewerin
fonte
Isso certamente é um começo, mas uso frequentemente os ambientes de equação, alinhamento e IEEEeqnarray, e não quero excluir os da minha pesquisa.
Rob F.
@RobF .: é bem possível combinar dentro de uma variedade de ambientes, mas não será fácil, a menos que se faça um script. Se, no entanto, você sempre usa \mathitnomes de variáveis, é muito mais fácil encontrá-los.
Peter Lewerin
0

Se você estiver procurando a string 'manhã' dentro do arquivo /morning, em seguida, entere pressione npara mover direção para frente

Arvind Gangwar
fonte
11
A pergunta dizia que I would like to search only in "math zones"seu método procura o arquivo inteiro e não delimita uma zona de pesquisa.
statox
0

Não há opção a não ser escrever uma função dedicada para isso. Eu escrevi uma função que pesquisa a string que você deseja e só para se:

  1. fica sem correspondências
  2. há uma correspondência dentro do ambiente matemático (ela será interrompida)

Você acabou de chamá-lo com a string que deseja pesquisar.

function! Finmath(nextstr)
    while 1
        if search(a:nextstr)==0
            break
        endif
        if searchpairpos('\(', '','\)','n')!=[0,0]
            break
        endif
        if searchpairpos('\[', '','\]','n')!=[0,0]
            break
        endif
        let a = getcurpos() 
        if count(strpart(getline('.'),0,a[2]),'$')%2==1
            break
        endif 
    endwhile 
endfunction

Pretendo escrever uma função semelhante para o GrammerousCheck que só para com erros gramaticais fora da matemática.

eyal karni
fonte