visual-studio-code - VSCode 高级自定义代码段
问题描述
语境
在过去的 18 个月里,我一直在使用 VSCode 的 LaTeX Workshop 扩展来满足我所有的 LaTeXing 需求。到目前为止,我主要将它用于长篇文章和报告,偶尔用于课堂笔记。到目前为止,我已经能够通过几个自定义宏(线性代数排版非常容易)使其实时工作得很好。然而,随着我进入不同的课程,我希望通过在 VSCode 中实现Gilles Castel 出色的基于 Vim 的工作流来扩展我的实时能力。不幸的是,VSCode 似乎隐藏或缺少(默认情况下)Castel 使用的大量功能(尤其是与代码片段相关的)。
我的问题
出于这篇文章的目的,我想把重点放在他的分数宏上(我相信如果我能让这个工作正常,我就能让剩下的大部分工作正常工作)。基本上,问题似乎是 VSCode 的片段功能相当有限,尤其是与 Vim 的UltiSnips相比。使用 UltiSnips,Castel 定义了一个自动扩展宏(我不确定 VSCode 是否支持自动扩展片段),当/
输入 a 时,它会获取前面的单词(或者如果存在括号则使用单词)并将其转换为 LaTeX分数格式。例如:
// --> \frac{}{}
3/ --> \frac{3}{}
4\pi^2/ --> \frac{4\pi^2}{}
(1 + 2 + 3)/ --> \frac{1 + 2 + 3}{}
(1 + (2 + 3)/) --> (1 + \frac{2 + 3}{})
(1 + (2 + 3))/ --> \frac{1 + (2 + 3)}{}
如何在 VSCode 中实现此行为?
我的线索
我花了很多时间研究这个,我有充分的理由相信这是可能的,同样有充分的理由相信我的问题的任何成功答案都必须通过 ELI5 给我——这种软件定制并不是我的菜,但我绝对愿意学习!
首先,有两个很有前途的 VSCode 扩展可以实现 UltiSnips:Vsnips和HyperSnips。Vsnips 看起来不错,但它似乎依赖于对 UltiSnips 的现有熟悉程度以及如何为您的特定计算机配置 UltiSnips(如果这确实很重要,我使用 2019 MacBook Pro 并且我的软件是最新的 [macOS Catalina 10.15 .5截至本文])。关于 HyperSnips,我什至无法弄清楚——两者都没有很好的文档记录,而且没有任何文档是为我这个级别的读者编写的。
虽然我说 VSCode 的内部片段引擎似乎相当有限,但我可能错了。它似乎与另一个名为TextMate的片段引擎交互。
这就是我现在能想到的。如果我可以提供任何进一步的信息,请告诉我!谢谢!
解决方案
安装HyperSnips后,使用它的命令HyperSnips: Open snippets directory
打开您将放置代码片段的目录。
片段在all.hsnips
所有语言文件中都可用。您也可以将您的代码片段放入类似目录latex.hsnips
或Latex.hsnips
同一目录中,这两个版本都适用于我。
修改Castel 指南中的代码,将其放入您选择的<language>.hsnips
文件中:
snippet // "Fraction simple" A
\frac{$1}{$2}$0
endsnippet
snippet `((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/` "Fraction no ()" A
\frac{``rv = m[1]``}{$1}$0
endsnippet
请注意,内插代码进入双反引号“``”,并且该代码的值必须分配给rv
(返回值)。分配给的任何内容都rv
将出现在代码段输出中。另请注意,上述代码段中还有其他制表$1, $2 and $0
位 - 数组中的插值代码可以访问这些值,t
但您在这里不需要。
然后这是最后一个片段,它适用于您的“前缀”中嵌入括号的更难的情况,例如(1 + (2 + 3))/
. 我认为(1 + (2 + 3))/
就像传统的 vscode 片段前缀一样,除了您可以使用正则表达式作为前缀!正则表达式前缀/触发器必须在反引号内。
snippet `^.*\)/` "Fraction with ()" A
``
let str = m[0];
str = str.slice(0, -1);
let lastIndex = str.length - 1;
let depth = 0;
let i = str.length - 1;
while (true) {
if (str[i] == ')') depth += 1;
if (str[i] == '(') depth -= 1;
if (depth == 0) break;
i -= 1;
}
let results = str.slice(0, i) + "\\frac{" + str.slice(i+1, -1) + "}";
results += "{$1}$0";
rv = results;
``
endsnippet
这^.*\)/
是前缀/触发器。扩展程序会在您键入该模式时查看您的所有代码,该模式基本上至少)
在 a 之前有一个/
,然后将这些之前的所有内容与前一个单词边界匹配。然后该匹配信息在匹配的代码中可用m[0]
. 您可以使用您的前缀/触发器获取捕获组并在m[1]
等中访问它们,但这里不需要。
如您所见,要插入的代码必须是 javascript 才能使此扩展工作。
第一组反引号的位置很重要!这里
snippet `^.*\)/` "Fraction with ()" A
``
<other code indented here>
`` <indented or flush left, didn't seem to matter in my testing>
endsnippet
缩进的代码更容易阅读 IMO,但输出也将缩进,除非第一组反引号没有缩进(当然,除非您希望输出缩进)。如果那是“怪癖”或按计划进行,我不会那样做。但是第一组反引号的位置似乎决定了输出的位置。
最后一个片段的主体(同样是您链接到的指南中的代码,但我从他的 python 代码中翻译成 javascript)只是计算出要回溯多远(逐个字符)以获得偶数个括号。输入前缀/触发器的任何前面部分都在该\frac
部分之前。
对此文件进行更改后,请始终运行命令HyperSnips: Reload Snippets
以确保它们可以立即进行测试。
实际演示:
推荐阅读
- python - 如何在 python 中查找/阅读有关方法和模块的文档?
- java - 推送通知未显示 - 为什么?
- php - Codeigniter 在 get from view 中传递参数导致 404 错误
- coldfusion - 无法从 Lucee Mail Listener 功能获得预期结果
- lisp - 如何返回特定列表
- node.js - 如何根据请求调用中间件并在 Node.js 中发送响应
- ios - 移动 Safari 中的文件上传和 EXIF
- c# - Linq:根据属性获取我所有的子对象
- php - 如何检查变量是否等于数组中的另一个变量
- c# - 迁移超过 5,000 个节点后发生以下异常: System.OutOfMemoryException