对 Vim 的 sed 语法着色文件的这种更改是好的还是破坏性的?

Posted

技术标签:

【中文标题】对 Vim 的 sed 语法着色文件的这种更改是好的还是破坏性的?【英文标题】:Is this change to Vim's syntax coloring file for sed good or disrupting? 【发布时间】:2020-07-26 09:29:26 【问题描述】:

总结

我不是在询问您对提议的更改是好、坏、惊人或什么的看法。 我只是请求您帮助回答这个问题:我为 cmets 的语法着色提出的更改是否打破其他事物的语法着色(关键字、字符串、语法错误,...)? 上述问题不是基于意见的,因为我的更改要么确实破坏了某些东西,要么没有。就是这样。

原问题

我已经在 Vim 的 GitHub 页面上创建了 issue #5876 来提议对 vim/runtime/syntax/sed.vim 进行更改,但它没有受到太多关注,所以我正在考虑为更改创建一个 PR。

事实上,我创建了一个问题而不是 PR,因为我不完全相信更改不会造成破坏,因此提出了这个问题。

问题在于第 20 行:

syn match sedComment    "^\s*#.*$"

因为只有“全线”cmets 被着色为 cmets。在命令之后使用尾随 cmets(例如 GNU sed 允许)会刺激一些红色背景着色(因为我猜它被语法着色逻辑认为是错误)。

我认为放宽 cmets 的定义以允许 GNU sed 样式的 cmets 是合理的,原因很简单,因为该规则限制较少。

在这方面,我注意到将该行更改为

syn match sedComment    "\s*#.*$"

即只需移除锚^,似乎就足够了。我还尝试通过将一些 # 放在搜索中并在 sed 脚本中替换字符串来对其进行测试,看起来还不错。

但是我对 Vim 语法着色文件没有信心,所以我想确保我编辑的正则表达式不会导致误报。

为了证明我对此没有信心,请使用这个单行 sed 脚本

s/aaa/bbb/#ccc

这里# 没有作为评论着色,ccc 的背景是红色的(就像一个错误?),而只是添加一个空格,给出正确的着色:

s/aaa/bbb/ #ccc

因此,我认为我的编辑工作(或似乎工作)是因为几个语法着色指令之间的优先规则(关于s/aaa/bbb/#ccc 的这个特定示例,我认为# 就在结束分隔符之后s 命令在语言中是有含义的,但我不知道;GNU Sed man 页面对此没有任何说明)。

编辑

cmets 中建议的另一个示例如下,其语法着色没有被提议的更改破坏

s/#if !defined(\([^)]*)/#ifndef \1/ # with or without this comment is fine

【问题讨论】:

\s*#.*$\s*#.* 基本相同,但请记住,它可以匹配0+ 个空格、# 以及一行中任意位置的其余行。例如。它将匹配text="This is a string #abc"; # SOME COMMENT中的#abc"; # SOME COMMENT 是的,@WiktorStribiżew,我知道该正则表达式匹配什么,但语法文件似乎没有给它机会。例如,如果我将 # 放在 sed 脚本中的某个位置,它不会像注释那样着色,即使 \s*#.*$ 会匹配,我也会写 would 因为我很确定它永远不会应用于它,可能是因为其他一些语法规则优先。这就是我问这个问题的原因。 @WiktorStribiżew,我试图澄清我为什么要问这个问题以及我在寻找什么。 我不明白为什么它被关闭为opinion-based。没有意见。我提出的改变要么很好,要么破坏了某些东西,我正在寻求帮助以了解是哪种情况。而已。相反,如果有人认为这是题外话,因为我应该将其发布到 Vi and Vim Beta,那就是另一回事了。 你的建议对s/#if !defined(\([^)]*)/#ifndef \1/有什么作用?我认为这可能是一个问题——该代码中没有注释,但是您的更改会将其视为注释,不是吗?此外,全世界都不使用 GNU sed 【参考方案1】:

我的研究

我终于找到了一些时间来研究:h E410,现在我有了答案。

从那里我读到了

1. Keyword
    [...] It will only match with a complete word [...]
2. Match
    This is a match with a single regexp pattern.
3. Region
    This starts at a match of the "start" regexp pattern and ends with a match with the
    "end" regexp pattern.  Any other text can appear in between.  A "skip" regexp
    pattern can be used to avoid matching the "end" pattern.

由于我要更改的行使用语法 2.,

第 1 点不相关, 第 3 点。相关的,因为通常syn matchsyn region 匹配之间可能存在重叠。

(顺便说一句,我验证了syn region 使用了惰性正则表达式,可能是\_.\- 之后查看了一些示例,以匹配startend 正则表达式模式之间的内容。)

然后来自:h :syn-priority

An item that starts in an earlier position has priority over items that start in later positions.

答案

因此,改变

syn match sedComment    "^\s*#.*$"

syn match sedComment    "\s*#.*$"

不应该引入任何语法错误,原因是如果匹配上述正则表达式的文本实际上不是注释(例如命令s/#/hash/的情况),那么它必须被一些非注释语法放在之前,这些语法将被其他syn match/syn region 组匹配。由于本场比赛在sedComment组开始比赛之前开始,因此前者优先于后者。

总而言之,除非 sed.vim 已经出现问题,否则建议的更改不会导致语法着色错误。

进一步观察

其实sed.vim中已经有问题了,我提议的编辑并没有解决(我应该编辑sed.vim中的其他行来修复它,但我现在有点懒)。

例如,在下面的行中,这是非法的,因为a 不是有效标志,a 没有得到Error 着色。

s/x/y/a

我提议的修改没有解决这个错误。

出于同样的原因,由于某些其他语法规则在替换命令中的第三个分隔符后吃 1 个字符,因此以下命令中的 GNU-sed-valid 注释颜色不正确

s/x/y/#hello
#     │└───┴─── colored as Error
#     └─ not colored

即使对于不允许尾随 cmets 的旧版本 sed,着色也会出错,因为 Error 着色也应该包括 #。 我提议的修改也没有解决这个错误。

再观察

我提出的更改会导致单字母命令被突出显示为Error,如果它们后跟注释

p # this is a comment
│ └─────────────────┴─── colored as Comment (ok)
└────── colored as Error (bad)

这又不是恶化,因为当前的sed.vim 几乎将上面的整行都涂成了Error

【讨论】:

以上是关于对 Vim 的 sed 语法着色文件的这种更改是好的还是破坏性的?的主要内容,如果未能解决你的问题,请参考以下文章

sed替换

Vim编辑器简单使用入门教程

sed命令及vim的末行命令

shell编程之行编辑器 - sed 对文件进行操作

shell编程之行编辑器 - sed 对文件进行操作

如何在Vim插件输出中为单词着色