如何在某些语法区域中搜索模式?


10

我正在使用vim编辑乳胶文档。通常,我会想要将变量的名称更改为其他名称。但是,当我搜索变量名称时,必须经过不相关的匹配项有点烦人。我只想在tex语法文件中定义的“数学区域”中搜索。有没有一种简单的方法可以将搜索限制到特定的语法区域?


1
我认为答案是否定的:没有简单的方法可以将搜索限制在特定的语法区域。
Karl YngveLervåg2015年

2
此映射用于synIDattr()获取光标下字符的语法组。您可以编写一个函数来执行搜索(或执行normal n),然后使用该函数synIDattr()确定是停留在该位置还是继续搜索。
joeytwiddle

@joeytwiddle我刚刚在发布具有此类功能的答案后看到了您的评论。就像您的想法吗?
jjaderberg 2015年

@jjaderberg是的。做得好!
joeytwiddle

只是为了完整性(我发现这是一个很好的答案):stackoverflow.com/a/2696143/5000478
VanLaser

Answers:


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的搜索函数,直到找到与特定语法项也“合格”匹配的“普通”匹配,或者直到到达缓冲区末尾为止。

它有两个参数。第一个是搜索模式,它不变地传递给Vim的search()函数。请参阅:help search()以了解该功能的工作原理。第二个参数是要在其上过滤这些匹配项的语法项的名称。这也可以是模式,并作为不区分大小写的正则表达式进行比较。

要在数学区域中找到模式“ alpha”,您可以执行

:JJSyntaxSearch alpha texMathZone.

所述.在端部为任何单个字符的图案原子,见:help /.。这是因为有许多数学区域语法项目叫texMathZoneAtexMathZoneB等。

search()功能将光标移至下一个“普通”匹配项。然后,我们的函数使用来获取该新光标位置的所有语法项ID synstack()。遍历它们,它依次检索每个项目的名称,并根据syntaxitem参数对其进行测试。请参阅:help synstack():help synIDattr()。如果存在“限定”匹配,则返回行号。如果到达缓冲区末尾而没有找到任何“限定”匹配,则返回0。该函数的重点是使光标移至下一个“限定”匹配,因此您可以在那里进行一些操作,但是返回“行号或0”以指示再次调用该函数是否有意义,对于此操作很有用。实例,如果您想从另一个函数或宏重复调用该函数。

我选择将W标志用于,search()因为它可以防止“缠绕”缓冲区的末端。否则,该函数可能会卡住,因为它会不断查找相同的“普通”匹配项,但找不到“合格”的匹配项。


谢谢你的帮助!我还没有尝试过此功能,但是看起来像我想要的。
Rob F.


1

如果您的“数学区域”通过某种语法模式(例如字符串“ math”)来限定,那么您至少可以使用模式序列来查找具有匹配模式的行,例如:

:/math//your pattern/

(注意:这两种模式可能在不同的行上!)

这可能不会将您的比赛限制在区域内-因为您需要标识区域的末端-但是它只会在初始模式/ math /之后显示那些比赛。您可以使用ex-mode历史记录(: up-arrow enter)重复搜索下一次出现的情况。


注:ISTR在早期的vim / VI版本我也可以直接使用该方法作为搜索命令(而不是一名前模式命令)/math//your pattern/用更少的打字优势和使用的nN命令,但我无法证实对于我当前的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/&/gcfoo确认(:h :substitute)后,用文字本身搜索并替换每次出现的文字


这当然是一个开始,但是我经常使用等式,对齐和IEEEeqnarray环境,并且我不想从搜索中排除它们。
Rob F.

@RobF .:很可能在多种环境中进行匹配,但是除非编写脚本,否则这并不容易。但是,如果您始终\mathit围绕变量名使用,则查找它们会容易得多。
Peter Lewerin

0

如果你的字符串“早晨”内部文件检索 /morning,然后entern前进方向


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写一个类似的函数,该函数仅在数学之外的语法错误时停止。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.