vscode二次开发(草稿)

Daotin 于 2025-02-06 发布 编辑
  1. vscode 源码本地运行和打包
    1. 先决条件
    2. 下载源码
    3. 遇到的问题
    4. 参考文档
  2. vscode 源码分析
    1. 项目结构
    2. 依赖注入
    3. VS Code 编辑器源代码组织:
    4. VS Code for Desktop / VS Code for Web
  3. 技术架构
    1. 主进程
    2. 渲染进程
    3. 插件进程
    4. Debug 进程
    5. 搜索进程
  4. vscode魔改
  5. 扩展ActivityBar
    1. 1. 准备工作
    2. 2. 创建新的插件项目
    3. 3. 定义Activity Bar图标和侧边栏视图
    4. 4. 显示“hello”字符串
    5. 1. 安装“Custom CSS and JS Loader”插件
    6. 2. 创建自定义CSS文件
    7. 3. 配置VS Code使用自定义CSS
    8. 4. 重新加载自定义样式
    9. 1. 定义树节点
    10. 2. 创建树数据
    11. 3. 实现TreeDataProvider
    12. 4. 注册TreeView
    13. 1. 类定义和属性
    14. 2. 事件发射器和事件
    15. 3. getTreeItem 方法
    16. 4. getChildren 方法
    17. 1. vscode.window.registerTreeDataProvider:
    18. 2. vscode.window.createTreeView:
    19. 总结:
    20. 1. 在 package.json 中定义你的视图
    21. 2. 在 extension.ts 中使用 registerTreeDataProvider
    22. 1. 在 package.json 中定义命令和按钮
    23. 2. 在 extension.ts 中实现命令
    24. 3. 添加图标(可选)
    25. 1. 在 TreeDataProviderExample 类中添加 refresh 方法
    26. 2. 在树的数据真正更改时调用 refresh 方法
  6. 扩展StatusBar
    1. 1. 在 package.json 中定义命令和按钮
    2. 2. 在 extension.ts 中实现命令
    3. 3. 设置按钮的外观(可选)
    4. 4. 测试你的扩展
  7. 欢迎页

vscode 源码本地运行和打包

先决条件

下载源码

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

遇到的问题

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

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

解决方案:

2、安装 tree-sitter 失败

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

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

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

├── 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 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。
  2. 代码共享:VS Code 的目标是在这两种环境中尽可能多地共享代码。只在一个环境中运行的代码应该是例外,而不是常规。理想情况下,相同的代码可以在这两种环境中运行。
  3. 入口文件:为了区分在产品构建中的环境,有几个入口文件定义了所有的依赖,这些依赖取决于环境:
    • src/vs/workbench/workbench.sandbox.main.ts:仅用于桌面的依赖。
    • src/vs/workbench/workbench.web.main.ts:仅用于Web的依赖。
    • src/vs/workbench/workbench.common.main.ts:共享的依赖,无论是桌面还是Web。
  4. 一些规则
    • 共享的代码应该放入 workbench.common.main.ts
    • 仅用于Web的代码应该放入 workbench.web.main.ts
    • 仅用于桌面的代码应该放入 workbench.desktop.main.ts

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

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

技术架构

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

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

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

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:

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

ChatGPT:

1. 准备工作

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


npm install -g yo generator-code

2. 创建新的插件项目

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

yo code

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

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

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

"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”字符串:

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

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


Person:

.activitybar .composite-bar li.action-item[title^="资源管理器"]::after,
.activitybar .composite-bar li.action-item[title^="Explorer"]::after {
  content: "代码";
}

ChatGPT:

以下是步骤:

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”:

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:

ChatGPT:

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

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

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

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

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


Person:

ChatGPT:

1. 定义树节点

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


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

2. 创建树数据

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


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提供数据:


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


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

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


Person:

ChatGPT:

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

1. 类定义和属性


class TreeDataProviderExample implements vscode.TreeDataProvider<TreeNode> {

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

2. 事件发射器和事件


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

3. getTreeItem 方法


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;
}

4. getChildren 方法


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

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


Person:

ChatGPT:

1. vscode.window.registerTreeDataProvider:

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

优点 :

缺点 :

2. vscode.window.createTreeView:

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

优点 :

缺点 :

总结:

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


Person:

ChatGPT:

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

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

例如:


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

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

2. 在 extension.ts 中使用 registerTreeDataProvider

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


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

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


Person:

ChatGPT:

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

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


"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 文件中实现这个命令,例如:


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();
    }));
}

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

3. 添加图标(可选)

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


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

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


Person:

ChatGPT:

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

1. 在 TreeDataProviderExample 类中添加 refresh 方法

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


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

接下来,添加 refresh 方法:


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

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

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

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

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


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 文件中,定义一个新的命令和一个状态栏按钮:

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

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

2. 在 extension.ts 中实现命令

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

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。例如:

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:\whty-code\vscode\src\vs\workbench\contrib\welcomeGettingStarted\browser\gettingStarted.ts