Daotin

vscode二次开发(草稿)

前端

vscode 源码本地运行和打包

先决条件

下载源码

javascript
// 只现在最近一次 commit 的代码
git clone --depth 1 https://github.com/microsoft/vscode.git

遇到的问题

1、Nodejs 开启 ‘Tools for Native Modules’ 后,安装报错

plain text
Error 0x8013153b: [0e54:001a][2023-08-28T14:32:58] Could not update channel "<https://aka.ms/vs/16/release/channel>"

解决方案:

2、安装 tree-sitter 失败

plain text
error <https://github.com/joaomoreno/node-tree-sitter/releases/download/v0.20.0/tree-sitter-0.20.0.tgz:> connect ETIMEDOUT 192.30.255.113:443

解决办法:registry 切换到 npm,关闭代理,清空 chche 缓存,重新安装

3、使用 yarn gulp vscode-win32-x64 可以打包,没有失败,但是在 vscode 项目中只发现了out-vscode 文件夹。

解决办法:其实已经生成了VSCode-win32-x64文件夹,只不过不在 vscode 文件夹里面,而是跟 vscode 同级。。。

Ref:https://github.com/microsoft/vscode/issues/49424

参考文档

vscode 源码分析

项目结构

Visual Studio Code 的源代码组织结构由多个层次和模块组成,其核心位于 src/vs 目录下。这个核心可以通过扩展来进行扩展。扩展在一个称为扩展主机的单独进程中运行。扩展是通过使用扩展 API 来实现的。内置的扩展可以在 extensions 文件夹中找到。

核心层次

  1. base:提供通用的实用程序和用户界面构建块,可以在任何其他层中使用。
  2. platform:定义服务注入支持和 VS Code 的基础服务,这些服务在诸如工作台和代码的各个层之间共享。
  3. editor:“Monaco” 代码编辑器层。作为一个单独的可下载组件提供。
  4. workbench:托管“Monaco”编辑器、notebooks 和自定义编辑器,并为资源管理器、状态栏或菜单栏等面板提供框架,利用 Electron 实现 VS Code 桌面应用程序和浏览器 API 来提供用于 Web 的 VS 代码。
  5. code:桌面应用的入口点,将所有内容整合在一起。例如包括 Electron 主文件、共享进程和 CLI
  6. server:我们的远程开发服务器应用的入口点。

image

image
image

目标环境:

  • common:只需要基本的 JavaScript API 的源代码。
  • browser:需要 Web API 的源代码,例如 DOM。
  • 可以使用 common 代码
  • node:需要 Node.JS API 的源代码。
  • 可以使用 common 代码
  • electron-sandbox:需要浏览器 API 和一部分与 Electron 主进程通信的 API 的源代码。
  • 可以使用 common、 browser、 electron-sandbox 代码
  • electron-main:需要 Electron 主进程 API 的源代码。
  • 可以使用 common、 node 代码

image

image
image
plain text
├── build         # gulp编译构建脚本
├── extensions    # 内置插件
├── gulpfile.js   # gulp task
├── out           # 编译输出目录
├── resources     # 平台相关静态资源,图标等
├── scripts       # 工具脚本,开发/测试
├── src           # 源码目录
├── test          # 测试套件
└── product.json  # App meta信息

src 下文件目录结构,如下图:

plain text
├── bootstrap-amd.js    # 子进程实际入口
├── bootstrap-fork.js   #
├── bootstrap-window.js #
├── bootstrap.js        # 子进程环境初始化
├── buildfile.js        # 构建config
├── cli.js              # CLI入口
├── main.js             # 主进程入口
├── paths.js            # AppDataPath与DefaultUserDataPath
├── typings             # 这个目录包含了VS Code项目中使用的所有TypeScript类型定义文件
└── vs                  # 分层且模块化的 core
    ├── base            # 提供可在任何其他层中使用的基础的工具方法和基础的 DOM UI 控件
    │   ├── browser     # 基础UI组件,DOM操作、交互事件、DnD等
    │   ├── common      # diff描述,markdown解析器,worker协议,各种工具函数
    │   ├── node        # Node工具函数
    │   ├── parts       # IPC协议(Electron、Node),quickopen、tree组件
    │   ├── test        # base单测用例
    │   └── worker      # Worker factory 和 main Worker(运行IDE Core:Monaco)
    ├── code            # VSCode 主运行窗口:桌面应用程序的入口点,将所有内容缝合在一起,例如包括 Electron 主文件、共享进程和 CLI
    │   ├── browser # 需要 Electron 渲染器处理API的源代码(可以使用 common, browser, node)
    │   ├── electron-main    # 需要Electron主进程API的源代码(可以使用 common, node)
    │   ├── electron-sandbox
    │   ├── node        # 需要Electron主进程API的源代码(可以使用 common, node)
    │   ├── test
    │   └── code.main.ts
    ├── editor          # Monaco Editor Web代码编辑器:作为单独的可下载组件提供。
    │   ├── browser     # 代码编辑器核心
    │   ├── common      # 代码编辑器核心
    │   ├── contrib     # vscode 与独立 IDE共享的代码
    │   ├── standalone  # 独立 IDE 独有的代码
    │   ├── test
    │   ├── editor.all.ts
    │   ├── editor.api.ts
    │   ├── editor.main.ts
    │   └── editor.worker.ts
    ├── platform        # 定义服务注入支持和跨层(如workbench 和 code)共享的 VS Code 基本服务
    ├── workbench       # 托管“Monaco”编辑器、notebooks 和自定义编辑器,并为资源管理器、状态栏或菜单栏等面板提供框架,利用 Electron 实现 VS Code 桌面应用程序和浏览器 API 来提供用于 Web 的 VS 代码。
    │   ├── api              # 工作区与服务端调用的接口
    │   ├── browser          # 工作区布局 UI 界面
    │   ├── common           # 工作区 UI 通用部件
    │   ├── contrib          #
    │   ├── electron-sandbox # 桌面端沙盒渲染进程
    │   ├── services         # 工作区依赖和使用的对象及服务接口定义
    │   └── test             # 工作区相关的测试用例
    ├── server/              # 用于远程开发的服务器应用程序的入口点。
    ├── buildunit.json
    ├── css.build.js    # 用于插件构建的CSS loader
    ├── css.js          # CSS loader
    ├── loader.js       # AMD loader(用于异步加载AMD模块,类似于require.js)
    ├── nls.build.js    # 用于插件构建的 NLS loader
    └── nls.js          # NLS(National Language Support)多语言loader

依赖注入

依赖注入是一种设计模式,它允许一个对象从外部接收其依赖项,而不是自己创建它们。这种方法有助于实现反转控制原则,其中对象不再负责查找其依赖项或管理它们的生命周期。

在 Visual Studio Code 中,代码是围绕服务组织的,其中大多数服务在platform层中定义。这些服务通过构造函数注入的方式传递给它们的客户端。

消费服务:

  1. 服务定义分为两部分:(1) 服务的接口,和 (2) 服务标识符。后者是必需的,因为 TypeScript 使用结构化而不是名义化的类型系统。服务标识符是一个装饰器,并应该与服务接口同名。
  2. 通过在构造函数参数上添加相应的装饰来声明服务依赖。例如,@IModelService 是服务标识符装饰,而 IModelService 是此参数的类型注解。
  3. 使用实例化服务来为服务消费者创建实例,例如 instantiationService.createInstance(Client)。通常,当您作为贡献(如视图或语言)注册时,这会为您完成。

提供服务:

  1. 向其他人或您自己的组件提供服务的最佳方式是使用 registerSingleton 函数。它接受一个服务标识符和一个服务构造函数。
  2. 在模块范围内添加此调用,以便在启动时执行。然后,工作台将知道此服务并能够将其传递给消费者。

VS Code 编辑器源代码组织:

  • vs/editor 文件夹不应有任何 node 或 electron-* 依赖。
  • vs/editor/common 和 vs/editor/browser - 代码编辑器核心。
  • vs/editor/contrib - 代码编辑器贡献。
  • vs/editor/standalone - 仅与独立编辑器一起提供的代码。
  • vs/workbench/contrib/codeEditor - 在 VS Code 中提供的代码编辑器贡献。

VS Code 工作台源代码组织

在 Visual Studio Code 的 “Workbench source organisation” 中,工作台(vs/workbench)是为了提供丰富的开发体验而组成的,例如全文搜索、集成的 git 和调试。

以下是文件夹的组织方式:

  1. vs/workbench/{common|browser|electron-sandbox}:这是工作台的核心,尽可能地保持最小化。
  2. vs/workbench/api:这是 vscode.d.ts API 的提供者,包括扩展主机和工作台实现。
  3. vs/workbench/services:工作台核心服务。这里不应该包括只在 vs/workbench/contrib 中使用的服务。
  4. vs/workbench/contrib:工作台贡献。这是大部分代码应该存在的地方。vs/workbench/contrib 文件夹有一些规则:
  • 不能有任何从 vs/workbench/contrib 外部到 vs/workbench/contrib 内部的依赖。
  • 每个贡献都应该有一个单独的 .contribution.ts 文件,例如 vs/workbench/contrib/search/browser/search.contribution.ts,这应该被添加到产品的主要入口点。
    • 如果你添加了一个新的服务,它只从一个贡献中使用,而不是从其他组件或工作台核心中使用,建议从贡献入口文件中注册该服务。
  • 每个贡献都应该从一个单独的文件中公开其内部 API,例如 vs/workbench/contrib/search/common/search.ts。
  • 贡献可以依赖于另一个贡献的内部 API。
  • 贡献不应该深入到另一个贡献的内部(内部是贡献内部不在单一公共 API 文件中的任何内容)。
  • 在让一个贡献依赖于另一个贡献之前要三思:这真的是必要的吗?这有意义吗?是否可以通过使用工作台的可扩展性故事来避免这种依赖?

这种组织方式确保了工作台的核心不直接依赖于所有这些贡献。相反,它使用了一个内部机制(与真正的扩展 API 相对)来为工作台贡献这些内容。

VS Code for Desktop / VS Code for Web

我们既向桌面提供 Electron,也向 Web 提供,目标是在两种环境中尽可能多地共享代码。

  1. 两种环境:
  • VS Code for Desktop:这是大多数人熟悉的版本,它是一个桌面应用程序,使用 Electron 构建,可以在 Windows、macOS 和 Linux 上运行。
  • VS Code for Web:这是一个运行在浏览器中的版本,允许用户在没有安装任何东西的情况下访问和使用 VS Code。
  1. 代码共享:VS Code 的目标是在这两种环境中尽可能多地共享代码。只在一个环境中运行的代码应该是例外,而不是常规。理想情况下,相同的代码可以在这两种环境中运行。
  2. 入口文件:为了区分在产品构建中的环境,有几个入口文件定义了所有的依赖,这些依赖取决于环境:
  • src/vs/workbench/workbench.sandbox.main.ts:仅用于桌面的依赖。
  • src/vs/workbench/workbench.web.main.ts:仅用于Web的依赖。
  • src/vs/workbench/workbench.common.main.ts:共享的依赖,无论是桌面还是Web。
  1. 一些规则:
  • 共享的代码应该放入 workbench.common.main.ts。
  • 仅用于Web的代码应该放入 workbench.web.main.ts。
  • 仅用于桌面的代码应该放入 workbench.desktop.main.ts。

    当为桌面引入一个服务而不为Web引入时,需要特别小心:在Web中运行需要该服务的代码将无法执行,除非你为Web提供了一个相关的服务。如果根据环境使用不同的策略,可以为一个服务提供两种不同的实现。

  1. 注意事项:只有从主入口文件引用的代码才会加载到产品中。如果你有一个文件在你的代码中没有被引用,确保将导入添加到你的 .contribution.ts 文件中。

技术架构

首先,Electron 应用的运行原理与浏览器类似,它有一个主进程和多个渲染进程。

  • 主进程:负责运行 Electron 应用的主要代码,它可以创建和控制浏览器窗口、处理系统事件等。(可以访问 Node 及 Native API;)
  • 渲染进程:每个 Electron 的浏览器窗口都在其自己的渲染进程中运行。这些进程负责运行窗口的 Web 页面。(可以访问 Browser API 和 Node API 及一部分 Native API。)

主进程和渲染进程之间可以通过 IPC(Inter-Process Communication,进程间通信)进行通信。这意味着你可以在渲染进程中执行某些操作(例如点击按钮),然后通知主进程来执行其他任务(例如打开一个新窗口)

VSC 采用多进程架构,VSC 启动后主要有下面的几个进程:

  • 主进程
  • 渲染进程
  • 插件进程
  • Debug进程
  • Search进程

image

image
image

主进程

相当于后台服务,后台进程是 VSC 的入口,主要负责多窗体管理(创建/切换)、编辑器生命周期管理,进程间通信(IPC Server),自动更新,工具条菜单栏注册等。

我们启动 VSC 的时候,后台进程会首先启动,读取各种配置信息和历史记录,然后将这些信息和主窗口 UI 的 HTML 主文件路径整合成一个 URL,启动一个浏览器窗口来显示编辑器的 UI。后台进程会一直关注 UI 进程的状态,当所有 UI 进程被关闭的时候,整个编辑器退出。

此外后台进程还会开启一个本地的 Socket,当有新的 VSC 进程启动的时候,会尝试连接这个 Socket,并将启动的参数信息传递给它,由已经存在的 VSC 来执行相关的动作,这样能够保证 VSC 的唯一性,避免出现多开文件夹带来的问题。

渲染进程

编辑器窗口进程负责整个 UI 的展示,也就是我们所见的部分。UI 全部用 HTML 编写没有太多需要介绍的部分。

项目文件的读取和保存由主进程的 NodeJS API 完成,因为全部是异步操作,即便有比较大的文件,也不会对 UI 造成阻塞。IO 跟 UI 在一个进程,并采用异步操作,在保证 IO 性能的基础上也保证了 UI 的响应速度。

插件进程

每一个 UI 窗口会启动一个 NodeJS 子进程作为插件的宿主进程。所有的插件会共同运行在这个进程中。

Debug 进程

Debugger 插件跟普通的插件有一点区别,它不运行在插件进程中,而是在每次 debug 的时候由 UI 单独新开一个进程。

搜索进程

搜索是一个十分耗时的任务,VSC 也使用的单独的进程来实现这个功能,保证主窗口的效率。将耗时的任务分到多个进程中,有效的保证了主进程的响应速度。

vscode魔改

扩展ActivityBar

ActivityBar显示一个icon,点击后,在侧边栏显示树形视图,并且有刷新按钮。

Person:

  • 你现在是一名经验丰富的vscode extension工程师。我现在想要编写一个插件,在ActivityBar显示一个icon,当点击icon时,侧边栏显示“hello”字符串。

请从创建工程开始,教我一步步如何操作。

ChatGPT:

  • 当然可以!以下是创建一个VS Code插件的步骤,该插件会在Activity Bar上显示一个图标,点击后在侧边栏显示“hello”字符串:

1. 准备工作

确保你已经安装了以下工具:

bash

npm install -g yo generator-code

2. 创建新的插件项目

  1. 打开终端或命令提示符。
  2. 输入以下命令来创建一个新的插件项目:
bash

yo code
  1. 选择New Extension (TypeScript)。
  2. 输入你的插件名称,例如:HelloSidebar。
  3. 选择一个位置来保存你的插件项目。
  4. 打开该项目文件夹在VS Code中。

3. 定义Activity Bar图标和侧边栏视图

  1. 打开package.json文件。
  2. 在contributes部分,添加以下代码来定义一个Activity Bar图标和一个侧边栏视图:
json

"viewsContainers": {
    "activitybar": [
        {
            "id": "helloSidebar",
            "title": "Hello Sidebar",
            "icon": "media/icon.svg"
        }
    ]
},
"views": {
    "helloSidebar": [ // 叫做helloSidebar的视图容器
        {
            "id": "helloView", // 这个视图的唯一标识。其他部分的代码可能会使用这个ID来引用这个视图。
            "name": "Hello View" // 该视图的显示名称。在VS Code中,当用户看到这个视图时,他们会看到“主界面”作为视图的名称。
                        "icon": "./resource/images/CEC-IDE.svg": // 这是该视图的图标路径。该图标会在VS Code的边栏或其他地方展示给用户。
                        "type": "webview": 这表示这个视图的类型是webview。Webview在VS Code中是一个特殊的视图,它允许开发者在视图内部加载一个完整的Web页面或应用。当你在views配置中省略type字段时,它默认会被视为一个文件树视图(tree view)
                        "contextualTitle": "主界面": contextualTitle是VS Code视图定义中的一个可选字段,用于提供备用标题,该标题仅在特定上下文中使用,而不是通常的侧边栏或面板视图。
        }
    ]
}
  1. 在media文件夹中,添加一个名为icon.svg的SVG图标。这将是Activity Bar上的图标。

4. 显示“hello”字符串

  1. 打开src/extension.ts文件。
  2. 在activate函数中,添加以下代码来创建一个新的TreeView并显示“hello”字符串:
typescript

const helloDataProvider = {
    getTreeItem: (element: any) => element,
    getChildren: () => {
        return [new vscode.TreeItem('hello')];
    }
};

vscode.window.createTreeView('helloView', { treeDataProvider: helloDataProvider });

Person:

  • 我看有人通过下面这种方式增加图标文字的,那么我应该在哪里修改:
plain text
.activitybar .composite-bar li.action-item[title^="资源管理器"]::after,
.activitybar .composite-bar li.action-item[title^="Explorer"]::after {
  content: "代码";
}

ChatGPT:

  • 这段代码是使用CSS伪元素来在Activity Bar的图标后添加文字的方法。这种方法是通过修改VS Code的自定义样式来实现的。但是,VS Code默认不支持自定义样式和JS,所以你需要使用一个名为“Custom CSS and JS Loader”的插件来加载自定义样式。

以下是步骤:

1. 安装“Custom CSS and JS Loader”插件

在VS Code中打开扩展视图并搜索“Custom CSS and JS Loader”,然后安装它。

2. 创建自定义CSS文件

  1. 在你的插件项目或其他位置创建一个新的CSS文件,例如custom-style.css。
  2. 将上面提供的CSS代码复制到这个文件中。
  3. 修改content属性的值为你想要的文字,例如”HELLO”:
css

content: "HELLO";

3. 配置VS Code使用自定义CSS

  1. 打开VS Code的设置(可以使用快捷键Ctrl + ,)。
  2. 在设置中搜索“Custom CSS and JS”。
  3. 在“Custom CSS Path”设置中,点击“编辑”并输入你的CSS文件的路径,例如:file:///path_to_your_file/custom-style.css。
  4. 保存设置。

4. 重新加载自定义样式

为了让自定义样式生效,你需要使用命令面板:

  1. 打开命令面板(Ctrl + Shift + P)。
  2. 输入“Reload Custom CSS and JS”并选择这个命令。
  3. VS Code可能会提示你重新启动编辑器,确认并重新启动。

现在,你应该可以在Activity Bar的图标上看到你添加的文字了。

注意 :使用“Custom CSS and JS Loader”插件和自定义样式可能会影响VS Code的稳定性和性能,而且在VS Code更新后可能需要重新应用自定义样式。


Person:

  • 什么是TreeView?

ChatGPT:

  • TreeView 是 Visual Studio Code (VS Code) 扩展API中的一个组件,它允许开发者在VS Code的侧边栏(Side Bar)中创建自定义的树形视图。这种树形视图可以用来展示分层的数据、文件结构、项目结构或其他任何需要树状表示的信息。

TreeView 在 VS Code 中的常见应用包括:

  1. 资源管理器 :默认的文件和文件夹视图就是一个 TreeView。
  2. 源代码管理 :例如 Git 插件中展示的改动文件列表。
  3. 其他扩展 :例如 Docker 插件中展示的容器和镜像列表,或者数据库插件中展示的表和查询结果。

要在VS Code扩展中实现自定义的 TreeView,你需要:

  1. 定义数据 :创建一个实现了 TreeDataProvider 接口的对象。这个对象负责提供树的数据和响应数据变化。
  2. 注册视图 :使用 vscode.window.createTreeView 方法来创建并注册你的 TreeView。

一旦你的 TreeView 被创建和注册,VS Code 就会自动处理大部分的用户交互,例如展开和折叠树的节点。但你也可以为特定的节点或事件添加自定义的交互逻辑。


Person:

  • 将“hello”字符串改成一个tree示例

ChatGPT:

  • 当然可以。下面是如何将简单的“hello”字符串转换为一个树形结构示例的步骤:

1. 定义树节点

首先,我们需要定义一个表示树节点的类。这个类将包含节点的标签和子节点。

typescript

class TreeNode {
    constructor(
        public readonly label: string,
        public readonly children?: TreeNode[]
    ) {}
}

2. 创建树数据

接下来,我们创建一个简单的树数据示例:

typescript

const rootNode = new TreeNode('Root', [
    new TreeNode('Child 1'),
    new TreeNode('Child 2', [
        new TreeNode('Grandchild 1'),
        new TreeNode('Grandchild 2')
    ])
]);

这将创建一个树,其中有一个根节点,根节点有两个子节点,其中一个子节点还有两个子节点。

3. 实现TreeDataProvider

现在,我们需要实现TreeDataProvider接口来为TreeView提供数据:

typescript

class TreeDataProviderExample implements vscode.TreeDataProvider<TreeNode> {
    private _onDidChangeTreeData: vscode.EventEmitter<TreeNode | undefined> = new vscode.EventEmitter<TreeNode | undefined>();
    readonly onDidChangeTreeData: vscode.Event<TreeNode | undefined> = this._onDidChangeTreeData.event;

    getTreeItem(element: TreeNode): vscode.TreeItem {
        const treeItem = new vscode.TreeItem(element.label);
        treeItem.collapsibleState = element.children && element.children.length > 0 ?
            vscode.TreeItemCollapsibleState.Collapsed :
            vscode.TreeItemCollapsibleState.None;
        return treeItem;
    }

    getChildren(element?: TreeNode): TreeNode[] {
        if (element) {
            return element.children || [];
        } else {
            return [rootNode];
        }
    }
}

4. 注册TreeView

最后,在activate函数中,我们需要创建和注册TreeView:

typescript

export function activate(context: vscode.ExtensionContext) {
    const treeDataProvider = new TreeDataProviderExample();
    vscode.window.createTreeView('helloView', { treeDataProvider });
}

现在,当你运行你的插件并点击Activity Bar上的图标时,你应该会看到一个树形结构,其中包含一个根节点、两个子节点以及一个子节点的两个子节点。


Person:

  • 详细解释一下TreeDataProviderExample类

ChatGPT:

  • 当然可以。TreeDataProviderExample 类是一个实现了 vscode.TreeDataProvider 接口的类,用于为 TreeView 提供数据。这个类是创建自定义树形视图的核心部分。

让我们逐步深入了解 TreeDataProviderExample 类的每个部分:

1. 类定义和属性

typescript

class TreeDataProviderExample implements vscode.TreeDataProvider<TreeNode> {

这里,我们定义了一个名为 TreeDataProviderExample 的类,它实现了 vscode.TreeDataProvider 接口。这个接口期望一个泛型参数,我们使用了我们自定义的 TreeNode 类型。

2. 事件发射器和事件

typescript

private _onDidChangeTreeData: vscode.EventEmitter<TreeNode | undefined> = new vscode.EventEmitter<TreeNode | undefined>();
readonly onDidChangeTreeData: vscode.Event<TreeNode | undefined> = this._onDidChangeTreeData.event;
  • _onDidChangeTreeData 是一个私有的事件发射器,用于在树数据发生变化时通知 VS Code。
  • onDidChangeTreeData 是一个公开的只读事件,它是 TreeDataProvider 接口的一部分。当你想要通知 VS Code 树的数据已经更改时,你可以使用 _onDidChangeTreeData 事件发射器来触发这个事件。

3. getTreeItem 方法

typescript

getTreeItem(element: TreeNode): vscode.TreeItem {
    const treeItem = new vscode.TreeItem(element.label);
    treeItem.collapsibleState = element.children && element.children.length > 0 ?
        vscode.TreeItemCollapsibleState.Collapsed :
        vscode.TreeItemCollapsibleState.None;
    return treeItem;
}
  • getTreeItem 方法是用于将我们的自定义 TreeNode 对象转换为 VS Code 可以理解的 TreeItem 对象。
  • 这个方法接收一个 TreeNode 元素作为参数,并返回一个 TreeItem 对象。
  • 我们设置 TreeItem 的 collapsibleState 属性,以确定该项是否可以折叠和展开。如果该节点有子节点,我们将其设置为 Collapsed,否则设置为 None。

4. getChildren 方法

typescript

getChildren(element?: TreeNode): TreeNode[] {
    if (element) {
        return element.children || [];
    } else {
        return [rootNode];
    }
}
  • getChildren 方法用于获取给定 TreeNode 元素的子节点。
  • 如果提供了一个 TreeNode 元素,该方法将返回其子节点;如果没有提供元素(即请求根节点),它将返回我们之前定义的 rootNode。
  • 这个方法是递归的,因为当用户点击一个可折叠的节点时,VS Code 会再次调用这个方法,传入被点击的节点,以获取其子节点。

总的来说,TreeDataProviderExample 类为 VS Code 提供了一个自定义的树形数据结构,使得我们可以在 TreeView 中展示我们自己的数据。


Person:

  • 是否可以通过registerTreeDataProvider 替代createTreeView?有啥区别?

ChatGPT:

  • 是的,你可以使用 vscode.window.registerTreeDataProvider 方法来注册一个 TreeDataProvider,而不是使用 vscode.window.createTreeView。这两种方法都允许你在 VS Code 中创建和显示一个树形视图,但它们的用途和功能有所不同。

1. vscode.window.registerTreeDataProvider:

这是一个更简单的方法,用于将你的 TreeDataProvider 与一个在 package.json 文件中预定义的视图关联起来。

优点 :

  • 更简单,只需一行代码。
  • 不需要手动管理 TreeView 实例。

缺点 :

  • 提供的控制较少。你不能动态地更新或刷新整个视图,除非通过触发 onDidChangeTreeData 事件。

2. vscode.window.createTreeView:

这个方法不仅注册了你的 TreeDataProvider,还返回了一个 TreeView 对象,该对象提供了更多的控制和管理视图的方法。

优点 :

  • 提供了更多的控制。例如,你可以使用 TreeView.reveal 方法来滚动到并高亮显示特定的节点。
  • 允许你动态地更新或刷新整个视图。

缺点 :

  • 使用起来稍微复杂一些,因为你需要管理返回的 TreeView 实例。

总结:

  • 如果你只是想简单地显示一个树形视图,并且不需要额外的控制或功能,那么 registerTreeDataProvider 可能是更好的选择。
  • 如果你需要更多的控制,例如动态地滚动到特定的节点或刷新整个视图,那么 createTreeView 会更有用。

在大多数情况下,registerTreeDataProvider 足以满足需求。但如果你的扩展需要更复杂的交互或功能,createTreeView 可能是更好的选择。


Person:

  • 如果将上面使用createTreeView 的树形视图改成使用registerTreeDataProvider 应该怎么改?

ChatGPT:

  • 如果你想使用 registerTreeDataProvider 替代 createTreeView,你需要进行以下更改:

1. 在 package.json 中定义你的视图

首先,确保你在 package.json 文件的 contributes 部分中已经定义了你的视图。这是 registerTreeDataProvider 方法所需的。

例如:

json

"contributes": {
    "views": {
        "helloSidebar": [
            {
                "id": "helloView",
                "name": "Hello View"
            }
        ]
    }
}

这里,helloSidebar 是你的 Activity Bar 的 ID,而 helloView 是你的树形视图的 ID。

2. 在 extension.ts 中使用 registerTreeDataProvider

替换 createTreeView 的调用为 registerTreeDataProvider 的调用:

typescript

export function activate(context: vscode.ExtensionContext) {
    const treeDataProvider = new TreeDataProviderExample();
    vscode.window.registerTreeDataProvider('helloView', treeDataProvider);
}

注意:你不再需要保存 createTreeView 返回的 TreeView 实例,因为 registerTreeDataProvider 不返回任何内容。


Person:

  • 我想要在侧边栏树形视图的右上角增加一个刷新按钮,应该怎么做?

ChatGPT:

  • 要在侧边栏的树形视图的右上角添加一个刷新按钮,你需要在你的扩展的 package.json 文件中使用 view/title 贡献点来定义一个命令。以下是具体步骤:

1. 在 package.json 中定义命令和按钮

在 package.json 的 contributes 部分,你需要定义一个命令和一个与该命令关联的按钮:

json

"contributes": {
    "commands": [
        {
            "command": "extension.refreshTreeView",
            "title": "Refresh TreeView"
        }
    ],
    "views": {
        "helloSidebar": [
            {
                "id": "helloView",
                "name": "Hello View"
            }
        ]
    },
    "menus": {
        "view/title": [
            {
                "command": "extension.refreshTreeView",
                "when": "view == helloView",
                "group": "navigation"
            }
        ]
    }
}

这里,我们定义了一个命令 extension.refreshTreeView,并将其添加到 helloView 视图的标题栏中。

2. 在 extension.ts 中实现命令

接下来,你需要在 extension.ts 文件中实现这个命令,例如:

typescript

export function activate(context: vscode.ExtensionContext) {
    const treeDataProvider = new TreeDataProviderExample();
    vscode.window.registerTreeDataProvider('helloView', treeDataProvider);

    context.subscriptions.push(vscode.commands.registerCommand('extension.refreshTreeView', () => {
        // 这里实现刷新逻辑
        // 例如,你可以触发 TreeDataProvider 的 onDidChangeTreeData 事件来刷新整个树
        treeDataProvider.refresh();
    }));
}

在这个示例中,当用户点击刷新按钮时,我们调用 treeDataProvider 的 refresh 方法。你可能需要在 TreeDataProviderExample 类中实现这个 refresh 方法,它通常会触发 onDidChangeTreeData 事件来通知 VS Code 刷新树的数据。

3. 添加图标(可选)

如果你想为你的刷新按钮添加一个图标,你可以在 package.json 的 contributes.commands 部分为你的命令添加 icon 属性,并提供一个图标的路径。

json

"commands": [
    {
        "command": "extension.refreshTreeView",
        "title": "Refresh TreeView",
        "icon": {
            "light": "path_to_light_theme_icon.svg",
            "dark": "path_to_dark_theme_icon.svg"
        }
    }
]

这样,当用户点击侧边栏的树形视图的右上角的刷新按钮时,你的扩展就会执行相应的刷新逻辑。


Person:

  • refresh 方法如何写?

ChatGPT:

  • refresh 方法的主要目的是通知 VS Code 树的数据已经更改,从而触发树的刷新。为此,我们通常使用 onDidChangeTreeData 事件发射器来发送一个事件。

以下是如何在 TreeDataProviderExample 类中实现 refresh 方法的步骤:

1. 在 TreeDataProviderExample 类中添加 refresh 方法

首先,确保你的类中有一个 onDidChangeTreeData 事件发射器。我们将使用这个发射器来触发树的刷新。

typescript

private _onDidChangeTreeData: vscode.EventEmitter<TreeNode | undefined> = new vscode.EventEmitter<TreeNode | undefined>();
readonly onDidChangeTreeData: vscode.Event<TreeNode | undefined> = this._onDidChangeTreeData.event;

接下来,添加 refresh 方法:

typescript

refresh(): void {
    this._onDidChangeTreeData.fire();
}

这个方法简单地触发了 onDidChangeTreeData 事件,通知 VS Code 树的数据可能已经更改,从而刷新整个树。

2. 在树的数据真正更改时调用 refresh 方法

当你的数据源(例如一个数组、数据库或外部API)发生更改时,你可以调用这个 refresh 方法来更新树的显示。

例如,如果你有一个方法来添加一个新的树节点,你可以在添加节点后调用 refresh 方法:

typescript

addNode(newNode: TreeNode): void {
    // 假设你有一个表示树数据的数组
    this.data.push(newNode);
    this.refresh();
}

这样,每当你添加一个新的节点时,树就会自动刷新以显示新的数据。

总之,refresh 方法提供了一种简单的方式来通知 VS Code 树的数据已经更改,从而触发树的刷新。你可以根据你的数据源和应用逻辑来决定何时调用这个方法。

扩展StatusBar

扩展StatusBar,增加一个debug按钮,点击后执行F5指令

要在 VS Code 的 StatusBar 中添加一个 “debug” 按钮并使其执行 F5 指令(即启动调试),你可以按照以下步骤操作:

1. 在 package.json 中定义命令和按钮

首先,在你的扩展的 package.json 文件中,定义一个新的命令和一个状态栏按钮:

json
"contributes": {
    "commands": [
        {
            "command": "extension.startDebugging",
            "title": "Start Debugging"
        }
    ],
    "menus": {
        "statusBar": [
            {
                "command": "extension.startDebugging",
                "when": "debuggersAvailable"
            }
        ]
    }
}

这里,我们定义了一个命令 extension.startDebugging 并将其添加到状态栏。when 条件确保只有当有可用的调试器时,按钮才会显示。

2. 在 extension.ts 中实现命令

接下来,在 extension.ts 文件中,你需要实现这个命令:

typescript
export function activate(context: vscode.ExtensionContext) {
    context.subscriptions.push(vscode.commands.registerCommand('extension.startDebugging', () => {
        vscode.commands.executeCommand('workbench.action.debug.start');
    }));
}

这里,当 extension.startDebugging 命令被触发时,我们简单地执行内置的 workbench.action.debug.start 命令,这与按 F5 键的效果相同。

3. 设置按钮的外观(可选)

如果你想为你的状态栏按钮设置一个特定的文本、颜色或图标,你可以使用 VS Code 的 StatusBarItem API。例如:

typescript
export function activate(context: vscode.ExtensionContext) {
    const statusBarBtn = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
    statusBarBtn.text = "$(debug-start) Debug";
    statusBarBtn.command = 'extension.startDebugging';
    statusBarBtn.show();
    context.subscriptions.push(statusBarBtn);

    context.subscriptions.push(vscode.commands.registerCommand('extension.startDebugging', () => {
        vscode.commands.executeCommand('workbench.action.debug.start');
    }));
}

在上述代码中,我们创建了一个新的 StatusBarItem,设置了其文本、图标和命令,并使其显示在状态栏中。$(debug-start) 是一个内置的图标,表示一个调试图标。

4. 测试你的扩展

保存你的更改并运行你的扩展(通常是按 F5 键)。你应该会在 VS Code 的状态栏中看到一个新的 “Debug” 按钮。点击这个按钮应该会启动调试会话,就像按 F5 键一样。 ## 欢迎页

修改路径:E:-code.ts

Related posts