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跳来跳去(如$1表示第一个Tab Stop,$2第二个,特别的,$0是最后一个,${1:text}表示第一个占位符中有预设的文本)。
举例:
snippet hello "greeting"
Welcome to ${1:HyperSnips}!
endsnippet
snippet和endsnippet标志了片段的开始和结束,hello是触发字符。"greeting"是片段名称(没什么用)。第二行就是要展开的片段。如果用 VSCode 内置片段的写法(json),就是:
{
"greeting":{
"perfix":"hello",
"body":"Welcome to ${1:HyperSnips}!"
}
}
基本的功能都有的。输入片段(或者其中的几个字母),按下 Tab ,你可以得到:

自动展开
使用 A 标记,可以自动展开:
snippet hello "greeting" A
Welcome to HyperSnips!
endsnippet
这样只要输入触发字符,整个片段就会立即展开。上面的快速输入,几乎都是使用了A标记。另外还有i、w、M等标记,详见帮助文档( @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.
- 只对非正则表达式有效
内嵌代码、动态片段、正则识别
HyperSnips支持在片段中使用JavaScript代码。如下面可以返回当前日期:
snippet dategreeting "Gives you the current date!"
Hello from your hsnip at ``rv = new Date().toDateString()``!
endsnippet

其中,JavaScript片段使用四个 ` 括起来,其中rv表示返回的片段。
- 一开始那个小盒子,是插件中的示例代码:
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
效果就是:a1⇨a_1 。m[1]表示正则识别处的第一个组合。除此之外还有t变量,用的不多。
- 自动展开分数 会麻烦一些。

//⇨\frac{}{} 最容易,直接写就行;
如果要实现1/⇨\frac{1}{}:
snippet `((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/` "Fraction no ()" A
\frac{``rv = m[1]``}{$1}$0
endsnippet
而如果要实现(1+2)/⇨\frac{1+2}{} ,可能还需要借助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。
全局程序
在.hsnips文件开头加入如下片段:
global
endglobal
即可在其中定义全局函数。这里定义的函数可以在当前文件中的任何片段中使用。
比如生成矩阵的函数:
// 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
则bmat33 就能给出一个3*3 的\bmatrix 矩阵:

环境/作用域
有时我们希望片段只有在数学环境中展开,或者只在文本环境中展开。比如,你不希望在正文中写“green”的时候突然展开成“gr_en"吧(下标自动展开)。HyperSnips提供了这一方法:
在开头的global 中,定义如下:
function math(context) {
return context.scopes.some(s => s.includes("math"));
}
这个作用是,检查当前文本的标记和作用域(token & scope),如果其中含有math,判断为数学环境并返回true。然后再我们需要的片段前面加上:
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());
}
你就得到了一个在状态栏显示时间的小插件!

- 再比如,在global 中加入如下函数
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插件没有提供
{VISUAL}变量(当前选中的文本),不妨利用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~
欢迎关注、点赞、交流~~~
HyperSnips:VSCode上的自动补全神器的更多相关文章
- Vim自动补全神器YouCompleteMe的配置
简介:YouCompleteMe号称Vim的自动补全神器,该项目在github的地址:YouCompleteMe:以下在10.0.1 build-1379776平台配置完成 插件安装操作: 1.确保V ...
- Vim自动补全神器:YouCompleteMe
第一次听说这个插件还是在偶然的情况下看到别人的博客,听说了这个插件的大名.本来打算在实训期间来完成安装的,无奈网实在不给力,也就拖到了回家的时候.在开始准备工作的时候就了解到这个插件不是很容易安装,安 ...
- Vim自动补全神器:YouCompleteMe(转)
转自:http://blog.jobbole.com/58978/ 可能会有一段时间写linxu,免不了用vim,留着,找时间实操之 原文出处: marchtea 的博客 第一次听说这个插件还是在偶然 ...
- (转)Vim自动补全神器:YouCompleteMe
原文出处:http://blog.jobbole.com/58978/ 第一次听说这个插件还是在偶然的情况下看到别人的博客,听说了这个插件的大名.本来打算在实训期间来完成安装的,无奈网实在不给力,也就 ...
- 这个 Python 代码自动补全神器搞得我卧槽卧槽的
是时候跟你说说这个能让你撸代码撸得舒服得不要不要的神器了——kite. ! 简单来说,它是一款 IDE 的插件,能做到代码自动补全,可能你会说了,这有什么牛逼的?一般的编辑器不都有这个功能么 ...
- Vim自动补全神器–YouCompleteMe
一.简介 YouCompleteMe是Vim的自动补全插件,与同类插件相比,具有如下优势 1.基于语义补全 2.整合实现了多种插件 clang_complete.AutoComplPop .Super ...
- Vim自动补全神器–YouCompleteMe
YouCompleteMe的特别之处 基于语义补全 总所周知,Vim是一款文本编辑器.也就是说,其最基础的工作就是编辑文本,而不管该文本的内容是什么.在Vim被程序员所使用后,其慢慢的被肩负了与IDE ...
- [视频教程] 配置vscode的PHP自动补全提示与使用Xdebug进行远程调试debug
默认下载安装完的vscode并不能准确提示和检测PHP的语法错误,需要手动指定一下本机的PHP程序路径.按下面的操作配置完后就能在文件保存的时候检测语法有无错误.打开文件->首选项->se ...
- vscode golang 不能自动补全问题
问题描述: 使用vscode编辑go语言时,有时候会莫名其妙的代码不能自动补全,struct的属性值不能自动提示,这时候如果重新启动vscode也没有效果,就可能是gocode插件出了问题或者有了更新 ...
随机推荐
- php多域名跳转nginx
当web服务器nginx已经配置好了网站根目录时,需要增加另外的域名.但是由于限制必须在原来的网站根目录下面,nginx已经无法实现.只能通过php index页面进行调试.如下面: define(' ...
- C#-WPF数据绑定基础(一)
前言:WPF数据绑定技术有效的提高了程序的容错率,可以最大程度的保持程序的健壮性,从而降低程序在使用过程中崩掉的可能性. 接下来,我将分享一下我在写测量程序过程中所用到的数据绑定方面的知识 首先,我所 ...
- [hdu7032]Command and Conquer: Red Alert 2
令$(x,y,z)$为狙击手的坐标,其攻击范围即以$(x,y,z)$为中心的$(2k)^{3}$的立方体 为了避免$k$的影响(二分答案会多一个$\log$),不妨将其变为以$(x,y,z)$为左下 ...
- [atARC070F]HonestOrUnkind
考虑当$a\le b$时,构造两种方案,满足诚实的人不交,接下来要求对于任意询问,这两种方案的答案都有可能相同 考虑询问$(i,j)$,若$i$在两种方案中有一种不诚实,那么总可以让答案相同,又因为诚 ...
- es插件安装
首先安装找到一样版本的地址: Release v7.6.1 · medcl/elasticsearch-analysis-ik (github.com) 下载最上面的编译版 将文件解压到plugins ...
- 洛谷 P6031 - CF1278F Cards 加强版(推式子+递推)
洛谷题面传送门 u1s1 这个推式子其实挺套路的吧,可惜有一步没推出来看了题解 \[\begin{aligned} res&=\sum\limits_{i=0}^ni^k\dbinom{n}{ ...
- curl实现SFTP上传下载文件
摘自:https://blog.csdn.net/swj9099/article/details/85292444 #include <stdio.h> #include <stdl ...
- Linux系统编程之命名管道与共享内存
在上一篇博客中,我们已经熟悉并使用了匿名管道,这篇博客我们将讲述进程间通信另外两种常见方式--命名管道与共享内存. 1.命名管道 管道是使用文件的方式,进行进程之间的通信.因此对于管道的操作,实际上还 ...
- javaSE高级篇2 — 流技术 — 更新完毕
1.先认识一个类----File类 前言:IO相关的一些常识 I / O----输入输出 I 输入 input 0 输出 output I / o 按数据的流动方向来分- ...
- TensorFlow 2.0 深度学习实战 —— 浅谈卷积神经网络 CNN
前言 上一章为大家介绍过深度学习的基础和多层感知机 MLP 的应用,本章开始将深入讲解卷积神经网络的实用场景.卷积神经网络 CNN(Convolutional Neural Networks,Conv ...