首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Vim中标记为语法错误的大括号

在Vim中标记为语法错误的大括号
EN

Stack Overflow用户
提问于 2020-04-02 03:24:09
回答 1查看 437关注 0票数 1

我正在使用vim8.1,在编写C代码时,我注意到我所有的花括号都使用白色前景的红色背景。经过一番挖掘,我在我的主题中找到了这个设置:call s:hi('Error', { 'fg': s:white, 'bg': s:red }),我已经通过修改这里的颜色来确认这是颜色的来源。

由于这是一个语法错误,并且我在vimrc中有syntax on,所以我不明白为什么我的大括号显示为语法错误。即使在非常简单的代码中也会发生这种情况,例如:

代码语言:javascript
复制
int main(int argc, char **argv) 
{
    return 0;
}

我不明白为什么这是一个错误。如果我把开式大括号放在主定义的末尾或后面,就会发生这种情况。如果我运行clist,vim告诉我没有错误。vimrc可在以下网址查看:https://pastebin.com/LukL8MBg

编辑1:进一步挖掘,问题似乎与我正在使用的色彩主题。有一个包含此语法的文件:

代码语言:javascript
复制
syn keyword cDeclarationOverwrite var const type 
syn match cBraces       "[{}\[\]]"
syn match cParens       "[()]"
syn match cOpSymbols    "=\{1,2}\|!=\|<\|>\|>=\|<=\|++\|+=\|--\|-="
syn match cEndColons    "[,]"
syn match cLogicSymbols "\(&&\)\|\(||\)\|\(!\)"

编辑2:根据用户@filbranden的建议,我运行了:scriptnames,并看到了以下内容:

代码语言:javascript
复制
1: /usr/share/vim/vimrc
  2: ~/.vimrc
  3: ~/.vim/autoload/plug.vim
  4: /usr/share/vim/vim81/filetype.vim
  5: /usr/share/vim/vim81/ftplugin.vim
  6: /usr/share/vim/vim81/indent.vim
  7: /usr/share/vim/vim81/syntax/syntax.vim
  8: /usr/share/vim/vim81/syntax/synload.vim
  9: /usr/share/vim/vim81/syntax/syncolor.vim
 10: ~/.vim/plugins/purify/vim/colors/purify.vim
 11: ~/.vim/plugins/purify/vim/autoload/purify.vim
 12: /usr/share/vim/vim81/plugin/getscriptPlugin.vim
 13: /usr/share/vim/vim81/plugin/gzip.vim
 14: /usr/share/vim/vim81/plugin/logiPat.vim
 15: /usr/share/vim/vim81/plugin/manpager.vim
 16: /usr/share/vim/vim81/plugin/matchparen.vim
 17: /usr/share/vim/vim81/plugin/netrwPlugin.vim
 18: /usr/share/vim/vim81/plugin/rrhelper.vim
 19: /usr/share/vim/vim81/plugin/spellfile.vim
 20: /usr/share/vim/vim81/plugin/tarPlugin.vim
 21: /usr/share/vim/vim81/plugin/tohtml.vim
 22: /usr/share/vim/vim81/plugin/vimballPlugin.vim
 23: /usr/share/vim/vim81/plugin/zipPlugin.vim
 24: /usr/share/vim/vim81/autoload/dist/ft.vim
 25: /usr/share/vim/vim81/ftplugin/c.vim
 26: /usr/share/vim/vim81/indent/c.vim
 27: ~/.vim/plugins/purify/vim/syntax/c.vim
 28: /usr/share/vim/vim81/syntax/c.vim
Press ENTER or type command to continue

从这里的情况来看,purify插件中的c.vim是在vim的语法/c.vim最后加载之前加载的。

:set rtp?的输出显示:

代码语言:javascript
复制
runtimepath=~/.vim,~/.vim/plugins/purify/vim,/usr/share/vim/vimfiles,/usr/share/vim/vim81,/usr/share/vim/vimfiles/after,~/.vim/after

有人能解释一下为什么会发生这种事吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-04 04:42:11

因此,在我看来,这似乎是kyoz/purify插件设置的语法规则中的一个缺陷,特别是关于规则与Vim运行时规则的顺序有关的问题。

当插件管理器添加插件时,它会将插件的目录添加到'runtimepath',并将其添加到Vim运行时目录之前。这样做是为了让插件能够覆盖Vim运行时中提供的文件,方法是有机会更早地运行。

特别是,这意味着在加载C类型文件时,kyoz/purity插件中的语法规则将在Vim运行时的语法规则之前添加。

现在,事实证明,这引发了规则之间如何相互作用的冲突。

例如,让我们检查cParen (来自Vim运行时)和cParens (来自kyoz/purify)之间的交互。为了简单起见,让我们假设我们使用的是let g:c_no_curly_error = 1,这样我们就不必讨论有两个end=组了,但是同样的理由也适用于全局变量未设置的情况。

有了当前的排序,kyoz/purify就会出现在从Vim运行时之前。

代码语言:javascript
复制
" From kyoz/purify:
syn match cParens       "[()]"
" From Vim runtime:
syn region  cParen      transparent start='(' end=')' contains=ALLBUT,...

现在语法规则的第一件事是,在获胜之后的规则。因此,当Vim遇到(时,它会选择cParen (从Vim运行时),因为这是后来的事,所以两者都可以匹配( cParens匹配,或者cParenstart(完全匹配)。

一切都很好..。但是为什么我们在)有个问题

由于cParen是一个“区域”,Vim将继续尝试与它的end部分匹配。在这样做的同时,它还将尝试匹配contains中的组。但是在这里,containsALLBUT开头,这意味着它将尝试匹配除显式列表中的组之外的每个组。这意味着它也将匹配该组中的cParens

现在,这就是导致问题的原因,因为如果cParens)匹配,那么这意味着)不会被识别为cParen的结束。这实际上是在:help :syn-keepend下面描述的

默认情况下,包含的匹配可能会模糊对结束模式的匹配。这对筑巢很有用。例如,以{开头,以}结尾的区域可以包含另一个区域。遇到的}将结束包含的区域,而不是外部区域。 如果您不想这样做,keepend参数将使外部区域的结束模式的匹配也结束任何包含的项。这使得不可能嵌套相同的区域,但允许包含的项突出显示结束模式的部分,而不会导致跳过与结束模式的匹配。

因此,如果我们从Vim运行时对区域规则进行了keepend,这实际上将结束cParen规则,这不会导致问题。但是,由于情况并非如此,让cParens匹配)意味着cParen将一直运行到文件的末尾,这将导致大括号触发错误(因为在C中,它们不允许在括号内)。

如果我们有keepend,情况会稍微好一点,因为cParen将看到它的终结。但这仍然不太理想,因为kyov/purifycParens只匹配),不匹配( (您需要像matchgroup这样的东西来匹配分隔符,但这是另一个主题)。

所以这应该可以解释为什么会发生这种情况。

那我们能做什么呢?

在我看来,在这里按相反的顺序装载规则会更好。

代码语言:javascript
复制
" From Vim runtime:
syn region  cParen      transparent start='(' end=')' contains=ALLBUT,...
" From kyoz/purify:
syn match cParens       "[()]"

因为,当有多个匹配时,Vim将使用最后一个规则,这总是只触发((,所以我们对失控组没有问题。)也将只匹配cParens (在这种情况下,这不再是与cParen的冲突,因为这将只匹配组的结束)。

这将使来自kyov/purify的规则如预期的那样工作。

但它确实有副作用!Vim运行时的cParen规则将被这个插件完全遮蔽。(以及与相同字符匹配的类似规则,例如,cBlock

这有问题吗?也许吧。这些规则中的大多数似乎都被标记为transparent (它们不会直接影响高亮显示),并且主要用于标记不平衡或不匹配的大括号等情况,将它们标记为错误(与您看到的类似,但针对实际的语法问题)。

如果您认为来自kyov/purify的用例(用于大括号的颜色)比Vim运行时中的用例更可取,那么您可以在Vim运行时中隐藏规则。

这可以通过将语法规则移到after/子目录下来实现。插件管理器将识别插件中的after/目录,并将其添加到Vim运行时之后。这是一个既定的机制,允许插件决定他们是希望自己的规则先于Vim运行时的规则(这是最常见的情况),还是以后再来。

因为我相信这是kyov/purify中的一个bug,所以我打开了拉扯请求,将C和C++的规则移到after/目录中。在本地测试它,它似乎解决了上面报告的问题,而没有真正引入任何不利的问题。(拉请求被迅速合并,因此作者似乎同意这是一个bug。)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60983778

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档