Error[8]: Undefined offset: 54, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

HyperSnips:VSCode上的自动补全神器

发现一个小众但是巨好用的VSCode自动补全插件HyperSnips


作者显然受到了 这位小哥 的启发,将 Vim Ultisnips 的大部分功能搬到了VSCode上。


并用 JavaScript 重写了 Python 的部分程序。


有了这个插件,你不需要使用令人望而生畏的Vim,就能愉快地写 LaTeX/markdown,甚至在数学课上用 markdown/LaTeX 做笔记。


更有趣的是,由于这个插件具有可编程能力,你甚至可以拿到 VSCode 的 API 接口,用这个插件写“插件”,或者干一些有趣的事情。


你可以实现 这篇文章 中的几乎所有功能,足以看出其强大:

以上演示使用markdown完成(不是LaTeX,但是LaTeX同样可以使用该插件),预览是Markdown Preview Enhanced插件。


这是非常好用的markdown同步预览插件,只是更新有些慢。


使用方法 安装

基本用法

输入片段的方法基本按照 Vim Ultisnips 的方法,参照帮助文档。


这和VSCode自带的片段是对应的。


同样也可以使用占位符,可以使用Tab跳来跳去(如表示第一个Tab Stop,第二个,特别的,${1:text}是最后一个,snippet表示第一个占位符中有预设的文本)。


举例:

snippet hello "greeting"
Welcome to ${1:HyperSnips}!
endsnippet

endsnippetA标志了片段的开始和结束,hello是触发字符。


"greeting"是片段名称(没什么用)。


第二行就是要展开的片段。


如果用 VSCode 内置片段的写法(json),就是:

{
"greeting":{
"perfix":"hello",
"body":"Welcome to ${1:HyperSnips}!"
}
}

基本的功能都有的。


输入片段(或者其中的几个字母),按下 Tab ,你可以得到:

自动展开

使用 A 标记,可以自动展开:

snippet hello "greeting" A
Welcome to HyperSnips!
endsnippet

这样只要输入触发字符,整个片段就会立即展开。


上面的快速输入,几乎都是使用了i标记。


另外还有wM

  • 只对非正则表达式有效
  • 等标记,详见帮助文档( @infinity1900 翻译,感谢!):

    A:自动展开。


    默认是按下tab时触发代码段,Flag 设置为 A,代码段将在 Trigger 匹配后立即激活,这对于 regex 正则表达式代码段特别有用。


    i: 词内展开*。


    默认情况下,触发器仅在前面带有空格字符时才匹配触发。


    如果设置 为 i,则不管前面的字符如何,都会触发带有此选项的代码段,例如,可以在单词的中间触发代码段。


    w: 单词边界*。


    使用此选项时,触发器将在单词边界处匹配。


    M: Multi-line mode - By default, regex matches will only match content on the current line, when this option is enabled the last hsnips.multiLineContext lines will be available for matching.

      rv
    内嵌代码、动态片段、正则识别

    HyperSnips支持在片段中使用JavaScript代码。


    如下面可以返回当前日期:

    snippet dategreeting "Gives you the current date!"
    Hello from your hsnip at ``rv = new Date().toDateString()``!
    endsnippet

    其中,JavaScript片段使用四个 ` 括起来,其中

  • 一开始那个小盒子,是插件中的示例代码:
  • 表示返回的片段。


    snippet box "Box" A
    ``rv = '┌' + '─'.repeat(t[0].length + 2) + '┐'``
    │ $1 │
    ``rv = '└' + '─'.repeat(t[0].length + 2) + '┘'``
    endsnippet

    同样支持正则表达式。


    如“自动数字下标”的片段是这样写的:

    snippet `(?<=[A-Za-z])(\d)` "auto subscript" iA
    _``rv = m[1]``
    endsnippet

    效果就是:a_1m[1]


    t表示正则识别处的第一个组合。


    除此之外还有//变量,用的不多。


    \frac{}{}1/ 最容易,直接写就行;

    如果要实现\frac{1}{}(1+2)/:

    snippet `((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/` "Fraction no ()" A
    \frac{``rv = m[1]``}{$1}$0
    endsnippet

    而如果要实现\frac{1+2}{}.hsnips ,可能还需要借助JavaScript:

    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

    这和原作者的逻辑是一样的,但是转写成了JavaScript。


    全局程序

    矩阵文件开头加入如下片段:

    global
    
    endglobal

    即可在其中定义全局函数。


    这里定义的函数可以在当前文件中的任何片段中使用。




    比如生成bmat33的函数:

    // generate matrix
    
    function gen_matrix(nrow, ncol, index) {
    let results = "\n";
    let order = 1;
    for (var i=0; i<nrow; i++){
    results += ' ';
    for(var j = 0;j <ncol;j++){
    results += "$" +(order ).toString() + ((j == ncol -1) ? " \\\\\\" : " & ");
    order ++;
    }
    results += index ? "\n" : "";
    }
    return results;
    }

    再使用以下片段:

    snippet `(bm|pm|m|vm)at([1-9])([1-9])` "matrix" iA
    \begin{``rv = m[1]``atrix}``
    rv = gen_matrix(m[2],m[3],1);
    ``\end{``rv = m[1]``atrix}$0
    endsnippet

    \bmatrix 就能给出一个3*3 的math 矩阵:

    环境/作用域

    有时我们希望片段只有在数学环境中展开,或者只在文本环境中展开。


    比如,你不希望在正文中写“green”的时候突然展开成“gr_en"吧(下标自动展开)。


    HyperSnips提供了这一方法:

    在开头的global 中,定义如下:

    function math(context) {
    return context.scopes.some(s => s.includes("math"));
    }

    这个作用是,检查当前文本的标记和作用域(token & scope),如果其中含有true,判断为数学环境并返回global


    然后再我们需要的片段前面加上:

    context math(context)

    就可以让片段只在数学环境中展开。


    如前面片段如果写成:

    context math(context)
    snippet // "frac" A
    \frac{$1}{$2}
    endsnippet

    效果:

    检查哪一种环境,可以按下Ctrl+Shift+P ,使用开发人员: 检查编辑器标记和作用域(Inspect Editor Tokens and Scopes) 命令,得到如下窗口,框中就是作用域(scope)。


    这个标志了当前所处的环境。


    更多玩法

    上述我们提到,HyperSnips支持Javascript,且放在global中的函数可以全局通用。


    考虑到VSCode插件本质上也是JavaScript写的,那么一些小插件能做的事情,HyperSnips为什么不能做?

    在global区域中放置如下代码:

    const vscode = require("vscode");
    var editor=vscode.window.activeTextEditor
    var document=editor.document

    然后发现,你可以使用 VSCode 的 API 接口了!

    可能只需要几行代码,你就能做出一个“插件”!

    好么,既然能够编程了,那就……没有什么好怕的了( ̄︶ ̄*))

    setInterval(function(){myTimer()},1000);
    function myTimer(){
    vscode.window.setStatusBarMessage(new Date().toLocaleTimeString());
    }

    你就得到了一个在状态栏显示时间的小插件!

    function cycle(arr,str){
    let count = 0 ;
    while (str!=arr[++count]&&count<arr.length);
    return arr[(count+1)%arr.length]
    }

    然后考虑到分号;在LaTeX中几乎用不到,而且Tab太容易和其他快捷键冲突,于是放一些类似于这样的片段

    snippet `(\\rightarrow|\\Rightarrow|\\longrightarrow|\\Longrightarrow|\\to|\\implies)(| );` "change ⇨" Ai
    ``
    let r=["\\rightarrow","\\Rightarrow","\\longrightarrow","\\Longrightarrow","\\to","\\implies"];
    rv=cycle(r,m[1])+m[2];
    ``
    endsnippet

    然后有趣的就来了:

    按下分号,可以换一个样式。


    虽然没什么用,但是很好玩啊哈哈哈哈 灵感来自 @张同学

    甚至括号也不在话下(当然程序就更长一些):

    // get ActiveTextEditor
    
    vscode.window.onDidChangeActiveTextEditor((e) => {
    editor=vscode.window.activeTextEditor;
    document=editor.document
    }); let selectedText = ""; // get selected text vscode.window.onDidChangeTextEditorSelection((e) => {
    const newSelectedText = e.textEditor.document.getText(e.selections[0]);
    if (newSelectedText) {
    selectedText = newSelectedText;
    }
    }); // return text function VISUAL() {
    let sText=selectedText.replace(/\\\\/g,"\\\\\\ ").replace(/\}/g,"\\}");
    selectedText="";
    return sText;
    }

    然后比如配置如下的片段:

    context math(context)
    snippet `Aln` "align" iA
    \begin{aligned}
    ``rv = VISUAL();``$0
    \end{aligned}
    endsnippet

    就可以使用了

    尽管有时有bug,但是至少管用啊

  • 偶尔的环境/作用域识别错误,需要重开一下文件
  • Bug 参考:

    [+++]

    )
    File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
    File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
    File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
    HyperSnips:VSCode上的自动补全神器_随笔_内存溢出

    HyperSnips:VSCode上的自动补全神器

    HyperSnips:VSCode上的自动补全神器,第1张

    HyperSnips:VSCode上的自动补全神器

    发现一个小众但是巨好用的VSCode自动补全插件HyperSnips


    作者显然受到了 这位小哥 的启发,将 Vim Ultisnips 的大部分功能搬到了VSCode上。


    并用 JavaScript 重写了 Python 的部分程序。


    有了这个插件,你不需要使用令人望而生畏的Vim,就能愉快地写 LaTeX/markdown,甚至在数学课上用 markdown/LaTeX 做笔记。


    更有趣的是,由于这个插件具有可编程能力,你甚至可以拿到 VSCode 的 API 接口,用这个插件写“插件”,或者干一些有趣的事情。


    你可以实现 这篇文章 中的几乎所有功能,足以看出其强大:

    • 一个自动变大的盒子:

    • 可以自动给\(\LaTeX\)的命令加斜杠\

    • 可以自动展开分数(//\frac{}{}1/\frac{1}{})

    • 使用后缀片段修改字母样式(Ecal\mathcal{E}q_idot\dot{q_i}等等);

    • 自动生成m*n矩阵:

    以上演示使用markdown完成(不是LaTeX,但是LaTeX同样可以使用该插件),预览是Markdown Preview Enhanced插件。


    这是非常好用的markdown同步预览插件,只是更新有些慢。


    使用方法 安装
    • 下载VSCode,在插件市场安装 HyperSnips。




      注意安装后右键插件选择“安装另一个版本”,安装0.2.3版本。


      最新的0.2.4有严重的bug,会导致无法使用,暂时不要更新。


      (2021/12/16)

    • 按下 Ctrl+Shift+P ,搜索 Open Snippets Directory ,打开存放代码片段的文件夹

      新建 *.hsnips 文件,如希望在LaTeX补全就建立latex.hsnips,希望补全markdown就建立markdown.hsnips


      如果希望使用全局片段,则建立 all.hsnips




      然后就可以输入片段了。


    基本用法

    输入片段的方法基本按照 Vim Ultisnips 的方法,参照帮助文档。


    这和VSCode自带的片段是对应的。


    同样也可以使用占位符,可以使用Tab跳来跳去(如表示第一个Tab Stop,第二个,特别的,${1:text}是最后一个,snippet表示第一个占位符中有预设的文本)。


    举例:

    snippet hello "greeting"
    Welcome to ${1:HyperSnips}!
    endsnippet

    endsnippetA标志了片段的开始和结束,hello是触发字符。


    "greeting"是片段名称(没什么用)。


    第二行就是要展开的片段。


    如果用 VSCode 内置片段的写法(json),就是:

    {
    "greeting":{
    "perfix":"hello",
    "body":"Welcome to ${1:HyperSnips}!"
    }
    }

    基本的功能都有的。


    输入片段(或者其中的几个字母),按下 Tab ,你可以得到:

    自动展开

    使用 A 标记,可以自动展开:

    snippet hello "greeting" A
    Welcome to HyperSnips!
    endsnippet

    这样只要输入触发字符,整个片段就会立即展开。


    上面的快速输入,几乎都是使用了i标记。


    另外还有wM

  • 只对非正则表达式有效
  • 等标记,详见帮助文档( @infinity1900 翻译,感谢!):

    A:自动展开。


    默认是按下tab时触发代码段,Flag 设置为 A,代码段将在 Trigger 匹配后立即激活,这对于 regex 正则表达式代码段特别有用。


    i: 词内展开*。


    默认情况下,触发器仅在前面带有空格字符时才匹配触发。


    如果设置 为 i,则不管前面的字符如何,都会触发带有此选项的代码段,例如,可以在单词的中间触发代码段。


    w: 单词边界*。


    使用此选项时,触发器将在单词边界处匹配。


    M: Multi-line mode - By default, regex matches will only match content on the current line, when this option is enabled the last hsnips.multiLineContext lines will be available for matching.

      rv
    内嵌代码、动态片段、正则识别

    HyperSnips支持在片段中使用JavaScript代码。


    如下面可以返回当前日期:

    snippet dategreeting "Gives you the current date!"
    Hello from your hsnip at ``rv = new Date().toDateString()``!
    endsnippet

    其中,JavaScript片段使用四个 ` 括起来,其中

  • 一开始那个小盒子,是插件中的示例代码:
  • 表示返回的片段。


      a1
    snippet box "Box" A
    ``rv = '┌' + '─'.repeat(t[0].length + 2) + '┐'``
    │ $1 │
    ``rv = '└' + '─'.repeat(t[0].length + 2) + '┘'``
    endsnippet

    同样支持正则表达式。


    如“自动数字下标”的片段是这样写的:

    snippet `(?<=[A-Za-z])(\d)` "auto subscript" iA
    _``rv = m[1]``
    endsnippet

    效果就是:a_1m[1]


    t表示正则识别处的第一个组合。


    除此之外还有//变量,用的不多。


    • 自动展开分数 会麻烦一些。


    \frac{}{}1/ 最容易,直接写就行;

    如果要实现\frac{1}{}(1+2)/:

    snippet `((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/` "Fraction no ()" A
    \frac{``rv = m[1]``}{$1}$0
    endsnippet

    而如果要实现\frac{1+2}{}.hsnips ,可能还需要借助JavaScript:

    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

    这和原作者的逻辑是一样的,但是转写成了JavaScript。


    全局程序

    矩阵文件开头加入如下片段:

    global
    
    endglobal

    即可在其中定义全局函数。


    这里定义的函数可以在当前文件中的任何片段中使用。




    比如生成bmat33的函数:

    // generate matrix
    
    function gen_matrix(nrow, ncol, index) {
    let results = "\n";
    let order = 1;
    for (var i=0; i<nrow; i++){
    results += ' ';
    for(var j = 0;j <ncol;j++){
    results += "$" +(order ).toString() + ((j == ncol -1) ? " \\\\\\" : " & ");
    order ++;
    }
    results += index ? "\n" : "";
    }
    return results;
    }

    再使用以下片段:

    snippet `(bm|pm|m|vm)at([1-9])([1-9])` "matrix" iA
    \begin{``rv = m[1]``atrix}``
    rv = gen_matrix(m[2],m[3],1);
    ``\end{``rv = m[1]``atrix}$0
    endsnippet

    \bmatrix 就能给出一个3*3 的math 矩阵:

    环境/作用域

    有时我们希望片段只有在数学环境中展开,或者只在文本环境中展开。


    比如,你不希望在正文中写“green”的时候突然展开成“gr_en"吧(下标自动展开)。


    HyperSnips提供了这一方法:

    在开头的global 中,定义如下:

    function math(context) {
    return context.scopes.some(s => s.includes("math"));
    }

    这个作用是,检查当前文本的标记和作用域(token & scope),如果其中含有true,判断为数学环境并返回global


    然后再我们需要的片段前面加上:

    context math(context)

    就可以让片段只在数学环境中展开。


    如前面片段如果写成:

    context math(context)
    snippet // "frac" A
    \frac{$1}{$2}
    endsnippet

    效果:

    检查哪一种环境,可以按下Ctrl+Shift+P ,使用开发人员: 检查编辑器标记和作用域(Inspect Editor Tokens and Scopes) 命令,得到如下窗口,框中就是作用域(scope)。


    这个标志了当前所处的环境。


    更多玩法

    上述我们提到,HyperSnips支持Javascript,且放在global中的函数可以全局通用。


    考虑到VSCode插件本质上也是JavaScript写的,那么一些小插件能做的事情,HyperSnips为什么不能做?

    在global区域中放置如下代码:

    const vscode = require("vscode");
    var editor=vscode.window.activeTextEditor
    var document=editor.document

    然后发现,你可以使用 VSCode 的 API 接口了!

    可能只需要几行代码,你就能做出一个“插件”!

    好么,既然能够编程了,那就……没有什么好怕的了( ̄︶ ̄*))

    • 比如,四行代码加在
    • 再比如,在global 中加入如下函数
    • 区域中:
    setInterval(function(){myTimer()},1000);
    function myTimer(){
    vscode.window.setStatusBarMessage(new Date().toLocaleTimeString());
    }

    你就得到了一个在状态栏显示时间的小插件!

      {VISUAL}
    function cycle(arr,str){
    let count = 0 ;
    while (str!=arr[++count]&&count<arr.length);
    return arr[(count+1)%arr.length]
    }

    然后考虑到分号;在LaTeX中几乎用不到,而且Tab太容易和其他快捷键冲突,于是放一些类似于这样的片段

    snippet `(\\rightarrow|\\Rightarrow|\\longrightarrow|\\Longrightarrow|\\to|\\implies)(| );` "change ⇨" Ai
    ``
    let r=["\\rightarrow","\\Rightarrow","\\longrightarrow","\\Longrightarrow","\\to","\\implies"];
    rv=cycle(r,m[1])+m[2];
    ``
    endsnippet

    然后有趣的就来了:

    按下分号,可以换一个样式。


    虽然没什么用,但是很好玩啊哈哈哈哈 灵感来自 @张同学

    甚至括号也不在话下(当然程序就更长一些):

    • 再比如,原生的hyperSnips插件没有提供所以现在,仅剩的限制就是想象力了吧 变量(当前选中的文本),不妨利用API写一个:在global里加上:
    // get ActiveTextEditor
    
    vscode.window.onDidChangeActiveTextEditor((e) => {
    editor=vscode.window.activeTextEditor;
    document=editor.document
    }); let selectedText = ""; // get selected text vscode.window.onDidChangeTextEditorSelection((e) => {
    const newSelectedText = e.textEditor.document.getText(e.selections[0]);
    if (newSelectedText) {
    selectedText = newSelectedText;
    }
    }); // return text function VISUAL() {
    let sText=selectedText.replace(/\\\\/g,"\\\\\\ ").replace(/\}/g,"\\}");
    selectedText="";
    return sText;
    }

    然后比如配置如下的片段:

    context math(context)
    snippet `Aln` "align" iA
    \begin{aligned}
    ``rv = VISUAL();``$0
    \end{aligned}
    endsnippet

    就可以使用了

    尽管有时有bug,但是至少管用啊

  • 偶尔的环境/作用域识别错误,需要重开一下文件
  • Bug
    • 当叠加了太多的占位符时,可能出现多光标。


      这是VSCode自身的Bug

    • 欢迎关注、点赞、交流~~~
    参考:
    • HyperSnips作者Github:draivin/hsnips

    • @infinity1900 一位师兄的经验,之前似乎是知乎上唯一一篇关于Hypersnips的介绍,受他的启发,才发现了这个插件。




      师兄也用JavaScript实现了许多片段,包括上述引用的部分片段。


      再次表示感谢。


      infinity1900:【LaTeX 编辑环境搭建】TeX Live+VS code+HyperSnips(for math)插件

    • @一只方橙 君的markdown笔记,非常感谢这位同学,提供了大量片段,而且一同折腾了不少奇奇怪怪的HyperSnips使用方法.

      一只方橙:教程向: 在 VSCode 中用 Markdown 做「数字化」学习笔记

      • 他的片段配置:

        OrangeX4/OrangeX4-HyperSnips
      • 他之前仿照Hypersnips写过一个Hypersnips For Math插件,在原来的插件上实现了{VISUAL}变量和数学环境支持,但是此后官方也实现了这些。


        在插件市场可以很容易搜到这个插件。


    • 自己的(markdown)配置,有的片段写得很呆,但也是能用就行。


      欢迎Star~

      yfzhao20/Hsnips-Snippets

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/zaji/586466.html

    (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    上一篇 2022-04-12
    下一篇 2022-04-12

    发表评论

    登录后才能评论

    评论列表(0条)

    保存