工欲善其事,必先利其器。vscode是一个值得花费时间去掌握精通的编辑器。
好文档不必远求
打开vscode,把菜单看上三遍,仔细思考每个菜单项的作用,思考为啥要这样归类每个菜单项。
配置是系统的核心
"文件/首选项"这个菜单至关重要,它包括如下四大块配置功能:
- 设置
- 快捷键
快捷键设置分为两类:1)系统提供的菜单项的快捷键;2)使用现有的keymap映射,如vim、idea、sublime等流行编辑器
vscode的快捷键必然是从快捷键到command的映射,而command并不是可执行文件,而是可以在ctrl+shift+p中看到的命令。 - 代码片段snippets
snippets是一些代码片段,这些代码片段可以通过前缀来触发。可以给不同的语言设置不同的代码片段,下面的文件就是给java设置的代码片段。
{
"sout": {
"prefix": "sout",
"body": [
"System.out.println($1);",
"$2"
],
"description": "打印"
},
"cla": {
"prefix": "class",
"body": [
"public class $1 {\n\t$2\n}"
],
"description": "定义类"
},
"main": {
"prefix": "main",
"body": [
"public static void main(String[]args){\n\t$1\n}"
],
"description": "定义main函数"
}
}
prefix就是触发条件,body就是插入的代码片段,description是一些提示性内容。在body中可以使用$数字
的形式表示光标位置,使用tab键可以逐个到达$数字
所在的位置。
- 主题:包括整体样式主题和文件图标主题两部分。样式主题有浅色、深色、高对比度三大类,每个大类又包含若干小类。
牢记常用快捷键
ctrl+P:打开文件
ctrl+shift+P:打开命令面板,这个快捷键堪称最有用的快捷键。快捷键的缺点在于1)键少容易冲突;2)难于记忆。使用命令面板,我们只需要记忆简短的命令,既快又准。
ctrl+shift+E:打开文件资源管理器(Exploerer)
ctrl+shift+D:打开调试窗口(Debug)
ctrl+shift+G:代开Git窗口
ctrl+shift+X:打开包管理工具
ctrl+B:隐藏侧边栏
ctrl+`:打开控制台
把界面布局中无关的视图全部关闭,当需要某些视图时使用快捷键调出。
vscode相关的目录
/Program Files/Microsoft VS Code
vscode默认的安装位置。
- bin:一些命令
- locale:一些语言包
- resources:包括vscode自带的插件,界面所需要的一些资源,vscode所需要的其它node模块(vscode是用nodejs运行的)
- 其它文件是一些动态链接库和exe
.vscode
每个打开的文件夹都可以有单独的配置,存放在.vscode中,主要包括launch.json、tasks.json、settings.json,分别是调试器设置、任务设置、项目本身的设置(会覆盖全局的settings.json)。
~/.vscode
在~/.vscode目录下,extensions存放了已安装的扩展,想要学习如何编写扩展,直接看这个文件夹就可以了。
~/AppData/Roaming/Code
在~/AppData/Roaming/Code下,文件夹包括备份、缓存、日志、cookie、用户配置等信息,其中用户配置文件件User是最重要的,它包括:
- snippets:为各种语言设定的snnippets,每种语言都对应一个json文件
- keybindings.json:用户自定义的命令和快捷键
- locale.json:语言设置
- settings.json:用户修改之后的配置
portable模式
vscode意识到了有太多文件夹不够简洁清晰,于是vscode提供了portable(便携)模式,这种模式把所有数据文件都集中放在一个文件夹中。好处是便于移动,换环境之后免于重新配置(即便不是便携模式,也能够通过复制相关文件夹的方式实现复制vscode配置);坏处是注册表、路径需要自己手动更新,需要手动设置许多文件关联。
关于portable的模式的安装方法详见:https://code.visualstudio.com/docs/editor/portable
大概步骤如下:
- 下载zip安装包
- 把当前的~/.vscode和
%APP_DATA%/Code
复制到解压后的安装包的data目录
修改主题
vscode内置了许多主题,这些主题都是通过json文件指定的。vscode在界面上并没有提供修改主题文件的功能,但我们可以通过修改文本文件的方式来修改细节,例如:把注释颜色调为较亮的绿色。只需要修改vscode安装目录下的主题文件即可:C:\Program Files\Microsoft VS Code\resources\app\extensions\theme-monokai\themes
修改内置界面
vscode的设置并没有提供菜单栏、侧边栏的字体设置。但是我们可以通过修改C:\Program Files\Microsoft VS Code\resources\app\out\vs\workbench\workbench.main.css
文件来实现界面定制。
其中文件导航侧边栏的css选择器为:
.monaco-workbench>.part>.content{
font-size:16px;
font-family:"微软雅黑";
line-height: 18px;
}
自定义task
好的系统都是开放的,vscode通过task和extension两种方式向用户开放。
一个例子
打开命令面板,configure task命令设置task,会在当前目录的.vscode目录下生成一个tasks.json。再次打开命令面板,task run build命令会执行build过程,这个命令的快捷键为ctrl+shift+B。这是会自动打开控制台执行设定的命令。
task自动探测
如果为每个项目都设置很多task,那将会非常费事。而现有的一些构建工具如make、npm、maven等已经包含了很多命令,vscode正在和这些工具集成起来。例如使用npm时,在package.json中定义了run命令,就可以直接通过命令面板执行run命令,不需要更改tasks.json。
目前vscode只把前端的npm、gulp、grunt等工具的可执行任务集成进来了。
使用自定义的命令
假设在scripts文件夹下有一个test命令,我们需要运行这个命令。
{
"version": "2.0.0",
"tasks": [
{
"label": "Run tests",
"type": "shell",
"command": "./scripts/test.sh"
}
]
}
task中的部分字段的含义如下:
- label:命令的名称,用于在界面中展示
- type:命令的类型,可取值为shell和process。shell会打开控制台并打印信息,process则只启动一个进程执行并不打印信息。
- command:实际上需要执行的命令,可以是各种可执行文件。
- windows、osx、linux:这三个都是是字典类型的字段,在不同的操作系统下task的配置可能有差异,解析时会使用操作系统定义的字段中的内容覆盖掉task其它字段。
- group:任务也是有组的,把任务分成若干个组更加清晰。最常见的组是生命周期,maven中的构建过程分为compile、build、test、deploy等生命周期,每个生命周期包含若干个命令。
- problemMatcher:将此字段设为[]可以避免每次选择是否查看输出
关于task.json的配置细节,参考:https://code.visualstudio.com/docs/editor/tasks-appendix
把若干个小命令组合起来
有向无环图DAG在工程界很受欢迎,似乎任何项目中都无法避开有向无环图。原因是因为:好项目必定复杂,复杂必定很大,大则需要拆分,拆分之后会得到一堆小组件,小组件之间必有依赖,有依赖的项目必然构成一个有向无环图,如果有环就变成死循环了。
vscode中的若干个task也可以组合起来。这通过task的dependOn字段来实现。利用这个字段就能够把一系列task串联起来实现逐步构建。
{
"version": "2.0.0",
"tasks": [
{
"label": "Client Build",
"command": "gulp",
"args": ["build"],
"options": {
"cwd": "${workspaceRoot}/client"
}
},
{
"label": "Server Build",
"command": "gulp",
"args": ["build"],
"options": {
"cwd": "${workspaceRoot}/server"
}
},
{
"label": "Build",
"dependsOn": ["Client Build", "Server Build"]
}
]
}
然而,我认为这个功能很鸡肋,这已经超出了vscode的职责范围了,没有dependOn我们照样写出逐步构建的代码,完全可以把depend的一些命令写在一个shell脚本中。
problem matcher
vscode task的一个重要作用就是语法检测,在编辑代码时,这些问题检测程序一直在执行,vscode需要读取这些语法检测程序的输出并可视化的展示给用户。
problem matcher相关的内容较多,设计也很复杂,详见参考资料。
给任务绑定快捷键
{
"key": "ctrl+h",
"command": "workbench.action.tasks.runTask",
"args": "Run tests"
}
给任务绑定的快捷键command都是相同的,只有args不同,args参数对应task的label字段。
在vscode中,最好不要给task绑定快捷键,因为keybinding.json是一个全局文件,.vscode文件夹中tasks.json是项目特有的文件。
变量替换
在配置task时,我们需要给命令行传递一些参数,如当前文件、当前文件夹。
例如:
-
${file}
表示当前文件名 -
${workspaceFolder}
表示当前工作空间的名字 -
${lineNumber}
当前文件的行号
掌握这三个变量替换足够用了,vscode还定义了许多并无卵用的变量,此处是一份详细的变量列表。https://code.visualstudio.com/docs/editor/variables-reference
编写一个有用的task
使用vscode经常编写一些单文件程序,使用的语言有多种:
- java:先使用javac命令编译,然后执行
- cpp:先使用g++命令编译,然后执行
- python:使用python命令运行
- js:使用node运行
- html:打开浏览器查看
tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "lang",
"args": [
// Ask msbuild to generate full paths for file names.
"${file}"
],
"group": "build",
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher": [],
"promptOnClose": true
}
]
}
将lang.cmd这个命令放在全局变量PATH下
python %~dp0\lang.py %*
主体程序使用python实现
import sys
import os
import tempfile
"""
使用单文件运行
"""
if len(sys.argv) <= 1:
print("usage : lang filename")
exit(0)
filename = sys.argv[1]
print("正在运行", filename, "\n")
if filename.endswith('.js'):
os.system('node ' + filename)
elif filename.endswith('.py'):
os.system("python " + filename)
elif filename.endswith('.java'):
os.system("javac {} -d {}".format(filename, tempfile.gettempdir()))
os.system("java -cp {} {}".format(tempfile.gettempdir(),
os.path.basename(filename[:-5])))
elif filename.endswith('.cpp'):
os.system("g++ {} -o {}/a.exe".format(filename, tempfile.gettempdir()))
os.system(os.path.join(tempfile.gettempdir(), "a.exe"))
elif filename.endswith(".html"):
os.startfile(filename)
else:
print(filename, "是什么文件?")
经过以上配置,就可以快速实现对单文件的测试了。
在使用java语言编写单文件程序时,每次运行总是弹出提示“Classpath is incomplete”,这个提示官方已经说明了,这个问题不是事,可以直接设置java.errors.incompleteClasspath.severity
忽略掉这个问题。
编写扩展
扩展提供的功能
vscode将哪些接口暴露给了扩展?扩展能够实现哪些功能?
- vscode负责激活扩展。每个扩展运行的时候都以独立进程运行,vscode负责监视进程执行情况。扩展激活有如下几种情况:文件类型被检测到;目录下包含某种文件;命令面板触发;某种按键组合触发。
- 读取、写入编辑器内容。
- 工作空间。获取工作空间目录,状态栏信息,界面布局情况等。
- 事件。例如打开、关闭、更改某个文件。
- 编辑交互。包括代码提示、悬浮提示、错误提示等。
vscode的扩展的两种特殊类型
- Language Server,语言服务器,用于代码提示、定义跳转、错误检测等。
- Debugger,调试器,用于代码调试。调试器都是语言必备的组件,扩展的作用就是遵循vscode调试器适配协议在vscode和调试器之间搭建一座桥梁。
这两种类型的扩展遵循同一套vscode扩展基础架构。这些类型的扩展都和外界工具松耦合,通过某种协议进行交流,vscode提供了调试器适配器协议用来和不同语言的调试器进行交流,提供了语言服务器协议和语言服务器进行交互。
参考资料
vscode技巧,内容全面丰富,涉及vscode功能各个方面
https://code.visualstudio.com/docs/getstarted/tips-and-tricks
为vscode编写task
https://code.visualstudio.com/docs/editor/tasks
vscode插件体系概览
https://code.visualstudio.com/docs/extensions/overview
LSP(language server protocol)协议是微软提出的一种协议,功能包括代码提示、查找引用等功能。
https://microsoft.github.io/language-server-protocol/