#1 楼
这是您可以尝试的功能。我只测试了一点,但似乎工作正常。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的
search()
函数。有关该功能的工作原理,请参见:help search()
。第二个参数是要在其上过滤这些匹配项的语法项的名称。这也可以是模式,并且可以作为不区分大小写的正则表达式进行比较。要在数学区域中找到模式'alpha',可以执行
:JJSyntaxSearch alpha texMathZone.
最后的
.
是任何单个字符的模式原子,请参阅:help /.
。这是因为存在许多数学区域语法项,分别称为texMathZoneA
,texMathZoneB
等。search()
函数将光标移至下一个“普通”匹配项。然后,我们的函数使用synstack()
获取该新光标位置的所有语法项ID。遍历它们,它依次检索每个项目的名称,并根据syntaxitem
参数对其进行测试。请参阅:help synstack()
和:help synIDattr()
。如果存在“限定”匹配,则返回行号。如果到达缓冲区末尾而没有找到任何“合格”匹配,则返回0
。该函数的重点是使光标移至下一个“限定”匹配,因此您可以在那里进行一些操作,但是返回“行号或0”以指示再次调用该函数是否有意义是很有用的,例如例如,如果要从另一个函数或宏重复调用该函数。我选择对
W
使用search()
标志,因为它可以防止“包装”缓冲区的末尾。否则该函数可能会卡住,因为它会继续查找相同的“普通”匹配项,但找不到“合格”匹配项。评论
谢谢你的帮助!我还没有尝试过此功能,但是看起来像我想要的。
– RobF。
15年8月18日在0:46
有关语法查找的vimtips Wiki :。
– joeytwiddle
15年8月18日在0:52
注意:Vim 8.2以后的版本支持search()函数的跳过表达式
–克里斯蒂安·布拉班特(Christian Brabandt)
20年8月26日在14:53
#2 楼
这也许应该是一条评论,但似乎我没有声誉。作为创建vim插件的一种练习,我基于jjaderberg的答案创建了一个插件,您可以在这里找到:https://github.com/AckslD/vim-sisr评论
欢迎来到Vi和Vim!
–filbranden♦
20年8月26日在17:40
#3 楼
如果您的“数学区域”由某种语法模式(例如字符串“ math”)限定,那么您至少可以使用模式序列来查找具有匹配模式的行,如::/math//your pattern/
(注意:这两种模式可能在不同的行上!)
这可能不会将您的比赛限制在区域内-因为您需要确定终点区域-,但仅显示初始模式/ math /之后的匹配项。您可以使用ex-mode历史记录(
:
up-arrow
enter
)重复搜索下一次出现。注意:ISTR在早期的vim / vi版本中我也可以使用该方法直接作为搜索命令(而不是ex-mode命令)作为
/math//your pattern/
,其优点是较少键入和使用n
和N
命令,但是我无法确认当前的vim版本。#4 楼
如果您要在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
)评论
这当然是一个开始,但是我经常使用等式,对齐和IEEEeqnarray环境,并且我不想从搜索中排除它们。
– RobF。
15年7月28日在18:23
@RobF .:很可能在多种环境中进行匹配,但是除非编写脚本,否则这并不容易。但是,如果始终在变量名周围使用\ mathit,则查找它们会容易得多。
– Peter Lewerin
15年7月28日在18:33
#5 楼
从8.2.0915开始,search()
支持第五个可选参数,在其他类型的表达式中,该参数可以是lambda。假设您要查找文字字符串
pat
,则可以运行::call search('pat', '', 0, 0, {-> synstack('.', col('.'))->map({_, v -> synIDattr(v, 'name')})->match('\ctexmathzone') == -1})
可以将其转换为自定义命令:
com -nargs=1 SearchInMathZone call s:SearchInMathZone(<q-args>)
fu s:SearchInMathZone(pat) abort
call search(a:pat, '', 0, 0, {->
"\ get the stack of syntax items under the cursor
\ synstack('.', col('.'))
"\ translate the IDs into names
\ ->map({_, v -> synIDattr(v, 'name')})
"\ skip the match if no syntax item under the cursor contains "texmathzone" in its name
\ ->match('\ctexmathzone') == -1})
endfu
Vim9脚本中的代码更具可读性,因为行连续性是隐式的,并且您可以摆脱前面的反斜杠: />
vim9
com -nargs=1 SearchInMathZone SearchInMathZone(<q-args>)
def SearchInMathZone(pat: string)
search(pat, '', 0, 0, () =>
# get the stack of syntax items under the cursor
synstack('.', col('.'))
# translate the IDs into names
->mapnew((_, v) => synIDattr(v, 'name'))
# skip the match if no syntax item under the cursor contains "texmathzone" in its name
->match('\ctexmathzone') == -1)
enddef
它需要最新的Vim版本;它适用于8.2.2332。一旦编译了skip表达式,它也应该更快。
注意:只要函数需要行地址,只要该函数只能在当前缓冲区上工作(而不是其他缓冲区)。
line('.')
就是其中之一:synstack(line('.'), col('.'))
⇔
synstack('.', col('.'))
有关更多信息,请参见
'.'
。支持跳过表达式。#6 楼
如果要在文件中搜索字符串'morning'/morning
,请输入并按n向前移动评论
这个问题说我只想在“数学区域”中搜索,您的方法会搜索不限制研究区域的整个文件。
–statox♦
16年5月6日在15:51
#7 楼
除了为此写一个专用函数外,别无选择。我写了一个函数搜索所需的字符串,并且只有在以下情况之一时才停止:
匹配项用尽
在数学环境中有一个匹配项(匹配项将停止在匹配项上)
您只需使用要搜索的字符串来调用它。
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写一个类似的函数,该函数仅在数学之外的语法错误时停止。
评论
我认为答案是否定的:没有简单的方法将搜索限制在特定的语法区域。此映射使用synIDattr()获得光标下字符的语法组。您可以编写一个执行搜索(或执行正常n运算)的函数,然后使用synIDattr()决定是保留在该位置还是继续向前搜索。
@joeytwiddle在发布具有此类功能的答案后,我才看到您的评论。就像您的想法一样吗?
@jjaderberg是的。辛苦了!
只是为了完整性(我找到了一个很好的答案):stackoverflow.com/a/2696143/5000478