vscode

vscode的官方源码下载地址:https://github.com/microsoft/vscode

 

我们可以将vscode源码运行起来看演示效果,假设我们将vscode源码下载到这个目录下:

D:\new-vscode\vscode-master,那么运行步骤如下:

 

vscode运行

1.打开cmd命令行,进入到D:\new-vscode\vscode-master,执行监听命令;

 

 

  1. 再打开一个cmd命令行,执行运行命令;

 

 

  1. 等待片刻,我们可以看到运行效果了。

 

vscode开发

在开发之前,我们需要对vsocde有一个整体的认识,事实上,vscode是一个html页面,如图:

 

 

界面大致可以分为六部分:

1.标题栏titlebar 包含其中左边的(包括文件~帮助)为菜单栏menubar

2.活动栏activitybar

3.侧边栏sidebar

4.编辑器editor

5.终端及输出等panel

6.状态栏statusbar

 

可以通过"切换开发人员工具",快捷键为Ctrl+Shift+I打开查看,效果相当于在浏览器的F12;

所以当我们需要修改vsocde界面的时候,往往就是修改相关的html和css,但vscode界面的元素一般不写在html,而是在ts文件中动态生成的,所以vscode的界面一般有ts和css组成,如下图是部分源码截图:

 

 

在工作上,我们都是按照需求来进行开发的,下面我们增加一个需求,在vscode的标题栏上增加一个登录按钮。首先我们先找到标题栏的ts和css,分别为titlebarPart.ts和titlebarPart.css,我们是如何确定titlebarPart.ts文件的呢?

首先我们通过Ctrl+Shift+I,如下图:

 

 

找到标题栏的class,然后在官方vscode中打开我们要修改的源码,然后根据class也就是titlebar去搜索此关键字,打开搜索结果的文件,对ts文件的代码查看,而上图中的class为titlebar,是和搜索结果中的css文件定义的样式对应的,如下图中红框;所以最终我们确定为titlebarPart.ts和titlebarPart.css的代码是对标题栏进行操作的。

 

 

我们仿照右上角的按钮来进行修改,增加如图代码,我们在titlebarpart.css中.part.titlebar的里面增加.window-custom-login元素;

 

 

当我们增加了css样式的时候,还需要在titlebarPart.ts中渲染出来,代码如下:

 

private windowControls_login: HTMLElement;

 

 

至此,我们就实现了在标题栏中增加登录按钮功能了。效果如下图:

 

 

vscode快捷方式

通过 设置-> 键盘快捷方式,可以打开查看所有的vsocde命令

 

 

这些命令在vscode源码中经常出现,像打开文件或者保存功能,我们可能在别的地方需要用上这些功能,通过拷贝命令即可得到,如拷贝打开文件命令得到

workbench.action.files.openFile

 

vscode命令注册和使用

在源码中调用上方的命令:

import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';

export class test

{

constructor(

        @ICommandService private readonly commandService: ICommandService,

    )

}

this.commandService.executeCommand('workbench.action.files.openFile'));

 

这样我们就可以调用vscode中所有的命令了。

 

在vscode插件:

 

const vscode = require("vscode");

/* 注册 */

vscode.commands.registerCommand('extension.newCourseDir', function (data) {

 

}

 

/* 使用 */

vscode.commands.executeCommand("extension.newCourseDir");

 

vscode插件

vscode插件属于vscode源码的一个扩展功能,有时候我们需要在vscode中增加一个功能的时候,我们可以写成一个插件,在插件里面进行编码,插件代码可以是JavaScript或者是typescript语言。

vscode插件开发可参考官方文档:

https://code.visualstudio.com/api

 

  1. 安装node.js和Git

在本主题中,我们将教您构建扩展的基本概念。确保安装了Node.jsGit,然后安装YeomanVS Code Extension Generator

npm install -g yo generator-code

  1. 创建插件的模板

右击打开Git Bash Here,输入

yo code

输入后如图所示

 

  1. 选择插件语言

这里我推荐使用第二个(JavaScript),按一下 下箭头,然后回车,注意按下箭头的时候,界面不会出现变化,但是实际已经选择了。出现下图(红框是语言类型)

 

 

提示我们输入插件的名字,这里我们输入test,回车;

提示我们输入插件唯一id,这里我们输入test,回车;

提示我们输入插件描述,这里我们输入test,回车;

提示我们是否启用“jsconfig.json”中的JavaScript类型检查?这里我们输入y,回车;

提示我们是否初始化git仓库,这里我们输入n,回车;

 

  1. 创建插件完成

当出现下图的时候,那插件创建完成了。

 

如何创建一个vscode插件呢?

图A

 

图A

 

如上图A,我们如何写一个课程功能,在1234每个区域显示我们需要的数据。

 

  1. 我们在vscode中打开这个test文件夹,在vscode上开发修改将比较方便;

 

  1. 首先如何显示图A中的1区域显示一个按钮呢?

打开package.json,我们在“contibutes”节点下增加如下代码:

 

"viewsContainers": {

            "activitybar": [

                {

                    "id": "test_id",

                    "title": "测试",

                    "icon": "images/todo-tree-container1.svg"

                }

            ]

        },

        "views": {

            "test_id": [

                {

                    "id": "test_ID",

                    "name": "测试列表"

                }

            ]

        }

我们F5运行,会出现下图多了一个按钮,看,这就是我们上面代码加的图标

 

 

  1. 接下来我们在图A增加2区域的数据

这里说一下,2区域的数据其实就是树视图的数据,官方文档介绍的了两个方法registerTreeDataProvider和createTreeView。

 

https://code.visualstudio.com/api/references/vscode-api

 

registerTreeDataProvider,顾名思义就是注册树视图数据提供者,我们传入一个树视图的ID,然后在创建一个树视图的类,在类中写我们想要显示在树视图的数据,这样我们就可以将树视图数据显示出来。也就是在图A的2区域显示数据。如果不理解,我们写一段代码看看。

我们先创建一个CourseTreeProvider.js作为TreeDataProvider,我们再看看TreeDataProvider有哪些方法?

 

https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider

 

我们通过官方文档了解这个TreeDataProvider有了哪些方法,方法都有什么用了,接下来我们贴出实现的代码:

CourseTreeProvider.js

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });

const vscode = require("vscode");

 

class MyTreeProvider {

constructor() { }

static initMyTreeList() {

let myTreeProvider = new MyTreeProvider();

vscode.window.registerTreeDataProvider("test_ID", myTreeProvider);

}

 

getTreeItem(element) {

return element;

}

 

getChildren(element) {

let trees = [];

let temp1 = new vscode.TreeItem("测试1");

let temp2 = new vscode.TreeItem("测试2");

let temp3 = new vscode.TreeItem("测试3");

trees.push(temp1);

trees.push(temp2);

trees.push(temp3);

 

return new Promise(resolve => {

return resolve(trees);

});

}

}

exports.MyTreeProvider = MyTreeProvider;

//# sourceMappingURL=CourseTreeProvider.js.map

 

我们在initMyTreeList()方法中注册树视图对象,test_ID是package.json中视图容器的id。

我们还实现了TreeDataProvider对象的getTreeItem()和getChildren(),我们在getChildren显示我们想要显示的数据,这里我们简单的显示数据,就使用vscode.TreeItem(),这个TreeItem第一个属性label是树视图中每一个Item的名字。

 

最后,我们打开extension.js文件,我们先将activate()函数里面的代码删除,activate()是插件激活后执行的方法,其实就是插件入口,在这可以做一些初始化的操作,调用CourseTreeProvider.js的MyTreeProvider中的initMyTreeList()方法,完整代码如下图:

F5运行,最终我们发现树视图没有显示数据,为什么呢?我们看package.json中activationEvents节点,这个是插件在什么时候激活,默认创建的插件是当extension.helloWorld调用时激活,这里我们改为“*”即为插件启动就激活。

再次按F5运行,我们发现终于显示数据了。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

  1. 实际上,我们想要在树视图中显示的数据是比较多元化的,可能是树结构等;

具体看课程插件的代码,这里我们给出实现的思路:

重点在getChildren(element)方法中,我们自定义一个myTreeNode继承vscode.TreeItem,

我们可以给myTreeNode添加一个标识,比如树结构第一节点是a,第二节点是b,第三节点是c,那么在getChildren(element)中先new myTreeNode(“a”),注意这里的myTreeNode里面还有其他属性,“a”只是其中的一个属性,我们判断如果是当前element的标识是a,那么就再new myTreeNode(“b”),如果新创建的element的标识是b,那么在创建new myTreeNode(“c”),这样当我们点击a标识的元素时,就会显示b标识的元素,点击b标识的元素就会显示c标识的元素。从而达到树结构的目的。

 

  1. 接下来还是回归我们的主题,创建4个区域。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

区域3是vscode编辑器,主要是通过打开文件的方式显示所需要的东西,如打开一个cpp文件可在上面写代码然后在区域4中点击提交到后台;

 

区域4是一个webview,你可当成是html,接下来我们看如何生成这个webview的,vscode给我们提供了方法。

前面我们说过“vscode命令注册和使用”,接下来我们再来温习一遍。

我们在extension.js的activate中注册一个命令,然后在显示树视图时调用命令,代码:

在activate里:

context.subscriptions.push(vscode.commands.registerCommand('extension.demo.openWebview', function (uri) {

        //创建webview

        createCourseWebview(uri);

    }));

 

function createCourseWebview(uri){

        if (flag) {

return;

}

        var panel = vscode.window.createWebviewPanel('testWebview', "课程内容", vscode.ViewColumn.Two, {

enableScripts: true,

retainContextWhenHidden: true,

enableFindWidget: true,

        });

        

        flag = true;

        panel.webview.html = getWebViewContent(context, 'src/test-webview.html');

        panel.onDidDispose(() => {

flag = false;

}, null, context.subscriptions);

}

 

function getWebViewContent(context, templatePath) {

const resourcePath = util.getExtensionFileAbsolutePath(context, templatePath);

const dirPath = path.dirname(resourcePath);

let html = fs.readFileSync(resourcePath, 'utf-8');

html = html.replace(/(<link.+?href="|<script.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => {

return $1 + vscode.Uri.file(path.resolve(dirPath, $2)).with({

scheme: 'vscode-resource'

}).toString() + '"';

});

return html;

}

createCourseWebview

是创建webview的方法,通过vscode.window.createWebviewPanel方法创建并显示新的Webview面板,panel.webview.html是给网页视图添加添加html文档。getWebViewContent是对html进行处理最终返回一个字符串的html内容。flag是我们对webview进行控制,如果创建一个就不创建了,关闭的时候将flag标识更改。

我们在src目录下增加一个html,名为test-webview.html。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

然后我们在CourseTreeProvider.js中getChildren里增加调用命令:

vscode.commands.executeCommand('extension.demo.openWebview');

 

最后按F5运行,当点击test按钮时,弹出webview。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

最终代码如图:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

test-webview.html:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

</head>

<body>

    <div id="app" class="container-fluid">

        <h3 class="page-title" id="page-title">课程实战</h3>

        <div id="courseContent">

            <p class="alert2 alert-warning" style="width: 95%" id="inputDescription">欢迎来到编程训练营!<br>

                界面说明:左边是课程列表、中间是代码编辑区、右边是课程内容区。<br>

                课程列表:显示老师给我们的课程题目列表<br>

                代码编辑区:提供给我们写代码的区域<br>

                课程内容区:显示我们的课程题目内容<br>

            </p>

            <form class="form-horizontal">

                <div class="form-group">

                    <div class="col-sm-6">

                        <button class="btn btn-sm btn-primary" οnclick="openPrev()">上一题</button>

                        <button class="btn btn-sm btn-danger" οnclick="openNext()">下一题</button>

                        <button id='submitButton' class="btn btn-sm btn-success" style="margin-left:20px;width: 60px"

                        οnclick="openCheckClick()">提交</button> <!--margin-left:20px;-->

                    </div>

                </div>

            </form>

        </div>

    </div>

    <script type="text/javascript"></script>

</body>

</html>

关于4个区域之间的联动?

点击课程左侧栏中的其中一项,弹出右侧webview;

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

注意每一个课程列表都有着不同的arguments的值,当传入不同的值的时候,右侧栏webview(区域4)就会跟着去更换数据,实现在

test-webview.html中window.addEventListener('message', event => {})中,对不同的courseId进行后台数据请求从而更换html页面显示。

 

同时当选择在发生改变时,按情况去创建课程目录和课程cpp文件,实现在extension.js中

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

当创建完cpp文件之后,我们执行了exports.p(),其实就是调用打开cpp文件命令,也就是显示区域3。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

上图代码就是打开cpp文件的实现。

 

所以,当我们点击课程列表时,webview(区域4)发生变化,编辑器(区域3)也跟着打开不同的cpp文件,从而达到课程联动。

关于插件源码:https://github.com/zhouhangzooo/test

 

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐