Как искать шаблон в определенных синтаксических регионах?


10

Я использую vim для редактирования латексных документов. Часто я хочу изменить имя переменной на другое. Тем не менее, немного раздражает, когда приходится искать нерелевантные совпадения, когда я ищу имя переменной. Я хотел бы искать только в «математических зонах», как это определено в файле синтаксиса tex. Есть ли простой способ ограничить поиск определенной областью синтаксиса?


1
Я думаю, что ответ - нет: нет простого способа ограничить поиск определенной синтаксической областью.
Карл Ингве Лервог,

2
Это отображение используется synIDattr()для получения синтаксических групп для символа под курсором. Вы можете написать функцию, которая выполняет поиск (или выполняет normal n), а затем использует ее, synIDattr()чтобы решить, оставаться ли в этом месте или продолжить поиск вперед.
Joeytwiddle

@joeytwiddle Я видел твой комментарий только сейчас после публикации ответа с такой функцией. Это похоже на то, что вы имели в виду?
Джадерберг

@jjaderberg Да, это так. Отличная работа!
Joeytwiddle

Просто для полноты (я нашел хороший ответ): stackoverflow.com/a/2696143/5000478
VanLaser

Ответы:


4

Вот функция, которую вы можете попробовать. Я только немного проверил это, но, кажется, работает нормально.

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>)

Функция вызывает функцию поиска Vim в цикле, пока не найдет «обычное» совпадение, которое также является «квалифицированным» совпадением с конкретным элементом синтаксиса, или пока оно не достигнет конца буфера.

Требуется два аргумента. Первый - это шаблон поиска, и он передается без изменений в search()функцию Vim . Посмотрите, :help search()как работает эта функция. Второй аргумент - это имя элемента синтаксиса, по которому вы хотите фильтровать эти совпадения. Это также может быть шаблон и сравнивается как регистрозависимое регулярное выражение.

Чтобы найти шаблон «альфа» в математических зонах вы можете сделать

:JJSyntaxSearch alpha texMathZone.

В .конце - атом образца для любого отдельного символа, см :help /.. Это происходит потому , что многие элементы синтаксиса математики зоны называется texMathZoneA, и texMathZoneBт.д.

search()Функция перемещает курсор к следующему «обычному» матчу. Затем наша функция получает все идентификаторы синтаксического элемента для этой новой позиции курсора synstack(). Перебирая их, он по очереди извлекает имя каждого элемента и проверяет его на соответствие syntaxitemаргументу. Смотрите :help synstack()и :help synIDattr(). Если есть «квалифицированное» совпадение, возвращается номер строки. Если он достигает конца буфера, не найдя «подходящего» соответствия, он возвращается 0. Смысл функции заключается в том, чтобы перевести курсор к следующему «квалифицированному» совпадению, чтобы вы могли выполнить там некоторую операцию, но полезно возвращать «номер строки или 0», чтобы указать, имеет ли смысл повторно вызывать функцию, для Например, если вы хотите повторно вызвать функцию из другой функции или макроса.

Я решил использовать Wфлаг для, search()потому что он предотвращает «обтекание» конца буфера. В противном случае функция может застрять, поскольку она продолжает находить одинаковые «обычные» совпадения, но не «квалифицированные» совпадения.


Спасибо за вашу помощь! Я еще не пробовал эту функцию, но похоже, что я хотел.
Роб Ф.


1

В случае, если ваши «математические зоны» определены каким-либо синтаксическим шаблоном, скажем, строкой «математика», вы можете по крайней мере использовать последовательности шаблонов, чтобы найти строку с соответствующим шаблоном, как в:

:/math//your pattern/

(Примечание: два шаблона могут быть на разных линиях!)

Это может не ограничивать ваши совпадения зонами - для этого вам нужно будет определить конец зоны - но оно будет отображать только те совпадения после исходного шаблона / математика /. Вы можете повторить поиск следующего вхождения, используя историю ex-mode ( : up-arrow enter).


Примечание: Истр , что в более раннем VIM / VI версии я также был в состоянии использовать этот метод непосредственно в качестве команды поиска (в отличие от команды экс-режим) /math//your pattern/с преимуществом меньшего набора текста и использованием из nи Nкоманд, но я не могу подтвердить что для моей текущей версии VIM.


1

Если вы ищете строку fooвнутри $...$или $$...$$, это должно работать:

\$.*\zsfoo

Это привязывает совпадение к $символу, но выбирает только строку foo.

Это не очень простое решение, но можно использовать :global+, :substituteчтобы найти «математические зоны» и искать внутри них:

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

Притворившись, что :substituteэто команда поиска, вы можете перейти к следующему вхождению nи выйти q. Если вы подтвердите замену по ошибке, проблем не должно быть.

Вам придется установить список внутри %(... )с именами математических сред, которые вы используете (полный список немного здоровен:) align|alignat|displaymath|eqnarray|equation|flalign|gather|math|multline|subequations|xalignat|xxalignat. Обратите внимание, что здесь я использую \vшаблон magic ( ).

Объяснение:

:globalвыполнить команду Ex ( :s) в каждой строке , где шаблон матчи ( :help :global)
/\vначинают очень волшебный рисунок ( :h /, :h pattern, :h magic)
\\begin\{соответствует буквальном \begin{
%(align|alignat|displaymath)соответствуют ни одному из этих слов ( :h /\%(, :h /bar)
\}/соответствует буквальному }и закончить картину.

+1,/\\end/-1диапазон, состоящий из следующей строки (считая от найденной :global) до строки, найденной по шаблону поиска /\\end. В этом диапазоне

s/foo/&/gcпоиск и замена каждого вхождения литерала fooна себя, после подтверждения ( :h :substitute)


Это, конечно, начало, но я часто использую среды уравнений, выравнивания и IEEEeqnarray, и я не хочу исключать их из своего поиска.
Роб Ф.

@RobF .: вполне возможно сопоставить в различных средах, но это будет непросто, если не будет написано сценарий. Однако, если вы постоянно используете \mathitимена переменных, найти их гораздо проще.
Питер Леверин

0

Если вы ищете строку «утром» внутри файла /morningзатем enterи нажмите , nчтобы двигаться вперед направление


1
В вопросе сказано, что I would like to search only in "math zones"ваш метод ищет весь файл, но не ограничивает исследовательскую зону.
statox

0

Нет другого выбора, кроме как написать для этого отдельную функцию. Я написал функцию, которая ищет строку, которую вы хотите, и останавливается, только если:

  1. кончились спички
  2. есть совпадение, которое находится в математической среде (оно остановится на матче)

Вы просто называете это строкой, которую хотите найти.

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

Я намерен написать аналогичную функцию для GrammerousCheck, которая останавливается только на грамматических ошибках вне математики.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.