Як шукати шаблон у певних регіонах синтаксису?


10

Я використовую vim для редагування документів з латексу. Часто мені хочеться змінити ім’я змінної на щось інше. Однак мені трохи прикро, коли я шукаю ім'я змінної, потрібно перебирати невідповідні відповідники. Я хотів би шукати лише в "математичних зонах", визначених у текстовому файлі синтаксису. Чи є простий спосіб обмежити пошук певним регіоном синтаксису?


1
Я думаю, що відповідь - ні: немає простого способу обмежити пошук певним синтаксичним регіоном.
Карл Інгве Лервег

2
Це відображення використовує synIDattr()для отримання груп синтаксису для символу під курсором. Ви можете написати функцію, яка виконує пошук (або робить normal n), а потім використовувати, synIDattr()щоб вирішити, чи залишатись у цьому місці, або продовжувати пошук вперед.
joeytwiddle

@joeytwiddle Я побачив ваш коментар саме зараз після публікації відповіді з такою функцією. Це як те, що ви мали на увазі?
jjaderberg

@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/

(Примітка: ці два шаблони можуть бути в різних лініях!)

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


Примітка: ISTR, що в попередніх версіях 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) візерунок.

Пояснення:

: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.