Cline源码分析

Cline源码分析 --- vscode插件开发与cline的界面系统

  • vscode插件开发基础知识
    • 开发基础‌
    • 核心概念
    • 核心API
    • 调试与发布
      • 调试
    • 学习路线
    • React开发界面
    • 前端代码分析
      • package.json
      • view/title(视图标题栏菜单)‌
      • editor/title(编辑器标题栏菜单)‌
      • editor/context(编辑器右键菜单)‌
      • terminal/context(终端右键菜单)‌
      • extension.ts
        • 视图加载机制:
        • 注册菜单点击对应的命令

vscode插件开发基础知识

开发基础‌

‌语言要求‌

主语言:TypeScript(推荐)或 JavaScript
配置文件:JSON(package.json)
‌必备工具‌

Node.js(≥ 16.x)
VS Code(建议最新版)
脚手架工具:

npm install -g yo generator-code

‌## 项目初始化

‌创建项目‌

yo code

选择插件类型(例如:“New Extension (TypeScript)”)

‌项目结构‌
├── .vscode # VS Code 调试配置
├── src
│ └── extension.ts # 插件入口文件
├── package.json # 插件清单文件
├── tsconfig.json # TypeScript 配置
└── node_modules

核心概念

  1. ‌激活事件(Activation Events)‌
    定义插件何时被加载
"activationEvents": ["onCommand:myExtension.helloWorld", // 命令触发加载"onLanguage:javascript",            // 打开JS文件时加载"*"                                  // 启动即加载(不推荐)
]
  1. ‌贡献点(Contribution Points)‌
    通过 package.json 扩展 VS Code 功能:
"contributes": {"commands": [{"command": "myExtension.helloWorld","title": "Hello World"}],"menus": {"editor/context": [{"command": "myExtension.helloWorld","group": "navigation"}]}
}
  1. ‌命令(Commands)‌
    注册命令:
vscode.commands.registerCommand('myExtension.helloWorld', () => {vscode.window.showInformationMessage('Hello World!');
});
  1. ‌生命周期‌
    ‌激活‌:activate() 函数
    ‌销毁‌:返回 deactivate() 清理资源
export function activate(context: vscode.ExtensionContext) {// 初始化代码
}

核心API

‌模块‌ ‌功能‌ ‌常用方法‌
vscode.window 界面交互 showInformationMessage createWebview
vscode.workspace 文件/编辑器操作 openTextDocument onDidChangeTextDocument
vscode.languages 语言支持 registerHoverProvider registerCompletionItemProvider
vscode.debug 调试相关 startDebugging onDidTerminateDebugSession

调试与发布

调试

按 F5 启动调试实例
使用 VS Code 的调试断点
‌发布‌

npm install -g vsce
vsce package  # 生成 .vsix 文件
vsce publish  # 发布到市场

学习路线

‌官方资源‌

插件API文档
示例代码库
‌实战建议‌

从修改官方示例开始
优先使用 TypeScript 获得更好类型提示
善用 Ctrl+Space 查看 API 自动补全

React开发界面

前端代码分析

package.json

		"viewsContainers": {"activitybar": [{"id": "claude-dev-ActivityBar","title": "Cline","icon": "assets/icons/icon.svg"}]},"views": {"claude-dev-ActivityBar": [{"type": "webview","id": "claude-dev.SidebarProvider","name": ""}]}

定义插件的视图id:claude-dev-ActivityBar,以及插件显示图标。插件视图提供者ID:claude-dev.SidebarProvider
菜单注册的代码如下:

"menus": {"view/title": [{"command": "cline.plusButtonClicked","group": "navigation@1","when": "view == claude-dev.SidebarProvider"},{"command": "cline.mcpButtonClicked","group": "navigation@2","when": "view == claude-dev.SidebarProvider"},{"command": "cline.historyButtonClicked","group": "navigation@3","when": "view == claude-dev.SidebarProvider"},{"command": "cline.popoutButtonClicked","group": "navigation@4","when": "view == claude-dev.SidebarProvider"},{"command": "cline.accountButtonClicked","group": "navigation@5","when": "view == claude-dev.SidebarProvider"},{"command": "cline.settingsButtonClicked","group": "navigation@6","when": "view == claude-dev.SidebarProvider"}],"editor/title": [{"command": "cline.plusButtonClicked","group": "navigation@1","when": "activeWebviewPanelId == claude-dev.TabPanelProvider"},{"command": "cline.mcpButtonClicked","group": "navigation@2","when": "activeWebviewPanelId == claude-dev.TabPanelProvider"},{"command": "cline.historyButtonClicked","group": "navigation@3","when": "activeWebviewPanelId == claude-dev.TabPanelProvider"},{"command": "cline.popoutButtonClicked","group": "navigation@4","when": "activeWebviewPanelId == claude-dev.TabPanelProvider"},{"command": "cline.accountButtonClicked","group": "navigation@5","when": "activeWebviewPanelId == claude-dev.TabPanelProvider"},{"command": "cline.settingsButtonClicked","group": "navigation@6","when": "activeWebviewPanelId == claude-dev.TabPanelProvider"}],"editor/context": [{"command": "cline.addToChat","group": "navigation","when": "editorHasSelection"}],"terminal/context": [{"command": "cline.addTerminalOutputToChat","group": "navigation"}]}

view/title(视图标题栏菜单)‌

‌功能定义‌
控制自定义视图(如侧边栏、面板)标题栏的按钮或下拉菜单,常用于扩展视图操作能力。

editor/title(编辑器标题栏菜单)‌

‌功能定义‌
控制编辑器标签页(Tab)右侧的操作区域,用于扩展文件相关操作。

editor/context(编辑器右键菜单)‌

‌功能定义‌
控制代码编辑区域的右键上下文菜单项,常用于代码操作、格式化等场景。

terminal/context(终端右键菜单)‌

‌功能定义‌
控制集成终端(Terminal)的右键上下文菜单项,适用于终端操作增强。

从代码来看主要是view/title和editor/title里面分别定义了当显示为view和activeWebviewPanelId 是的6个菜单,也就是Cline的主菜单项目:新建task,mcp服务器,任务历史,在编辑器打开,Cline账号和设置面板。
以下是 activeWebviewPanelId 与 view 两个上下文条件的核心区别解析:

‌一、作用区域差异‌
‌条件表达式‌	‌作用区域‌	‌典型应用场景‌
"when": "view == claude-dev.SidebarProvider"	‌侧边栏视图容器‌	控制侧边栏自定义视图的显示逻辑(如工具栏按钮)‌
"when": "activeWebviewPanelId == claude-dev.TabPanelProvider"	‌编辑器主区域‌	控制 Webview 面板的激活状态(如标签页操作)‌
‌二、上下文键含义‌
‌view‌对应通过 package.json 的 contributes.views 注册的侧边栏视图容器 ID17
示例配置:
json
Copy Code
"contributes": {"views": {"explorer": [{"id": "claude-dev.SidebarProvider","name": "Claude 侧边栏"}]}
}
‌activeWebviewPanelId‌对应通过代码动态创建的 Webview 面板 ID(vscode.window.createWebviewPanel 的 viewType 参数)‌58
示例代码:
typescript
Copy Code
vscode.window.createWebviewPanel('claude-dev.TabPanelProvider', // 此处定义ID'Claude 面板',vscode.ViewColumn.One
);
‌三、触发场景示例‌
1. ‌侧边栏视图 (view)‌
json
Copy Code
"menus": {"view/title": [{"command": "claude-dev.refreshSidebar","when": "view == claude-dev.SidebarProvider"}]
}
仅在侧边栏的「Claude 侧边栏」视图中显示「刷新」按钮‌17
2. ‌Webview 面板 (activeWebviewPanelId)‌
json
Copy Code
"commands": [{"command": "claude-dev.closePanel","title": "关闭面板","enablement": "activeWebviewPanelId == claude-dev.TabPanelProvider"
}]
当用户聚焦在 claude-dev.TabPanelProvider 面板时,允许执行关闭命令‌58
‌四、关键注意事项‌
‌视图类型限制‌view 仅适用于侧边栏/面板等静态视图容器
activeWebviewPanelId 专用于动态创建的 Webview 交互面板‌58
‌生命周期差异‌侧边栏视图 (view) 在插件激活期间持续存在
Webview 面板 (activeWebviewPanelId) 随用户打开/关闭动态变化‌

extension.ts

这个是插件的入口文件,

方法export function activate(context: vscode.ExtensionContext)定义了插件加载时执行的代码。

视图加载机制:
	context.subscriptions.push(vscode.window.registerWebviewViewProvider(ClineProvider.sideBarId, sidebarProvider, {webviewOptions: { retainContextWhenHidden: true },}),)
以上代码是注册试图提供者的代码,下面是对应vscode机制的解析:
‌一、代码执行阶段的作用‌
typescript
Copy Code
context.subscriptions.push(vscode.window.registerWebviewViewProvider(ClineProvider.sideBarId, sidebarProvider, { webviewOptions: { retainContextWhenHidden: true } })
)1. 注册阶段‌
操作	结果
注册视图类型	将 ClineProvider.sideBarId 加入 VS Code 的可用视图列表
配置持久化选项	retainContextWhenHidden 控制视图隐藏时是否保持 Webview 实例
‌未创建 Webview 实例‌	此时仅注册元信息,不分配任何 DOM 资源
‌2. 触发加载的条件‌
场景	加载时机
用户手动激活视图	点击侧边栏对应图标时创建 Webview
插件主动调用 reveal()	通过 vscode.commands.executeCommand('workbench.view.extension.viewId')
VS Code 恢复上次会话状态	当用户重新打开包含该视图的工作区时自动加载(需配置 "visible": true)
‌二、生命周期控制参数解析‌
‌retainContextWhenHidden 的作用‌
typescript
Copy Code
{ retainContextWhenHidden: true }
值	内存管理策略	适用场景
true	视图隐藏时保留 Webview 的 DOM 状态,再次显示时无需重新初始化	包含复杂表单/图表的交互式视图
false	视图隐藏后立即销毁 Webview 实例,再次显示时触发 resolveWebviewView 重新创建	简单静态内容视图
‌三、视图加载流程验证方法‌
‌1. 调试技巧‌
typescript
Copy Code
// 在 WebviewViewProvider 实现中增加日志
class SidebarProvider implements vscode.WebviewViewProvider {resolveWebviewView(webviewView: vscode.WebviewView) {console.log('Webview 实例化:', Date.now()); // 首次加载时触发}
}2. 行为观察‌
执行注册代码后检查 VS Code 内存占用(无明显增长)
首次点击侧边栏图标时观察到:
内存占用上升
开发者工具中可见新 Webview 的 DOM 元素
‌四、强制预加载的实现方式‌
typescript
Copy Code
// 注册后立即尝试显示视图(不推荐)
setTimeout(() => {vscode.commands.executeCommand('workbench.view.extension.' + ClineProvider.sideBarId);
}, 1000);
方案	优点	缺点
主动显示	确保视图即时可用	破坏用户体验,可能导致界面闪烁
按需加载	节省资源,自然交互	首次显示有短暂延迟(通常 100-300ms)
通过这种机制,VS Code 实现了插件视图的高效资源管理,开发者需要根据具体场景平衡即时性和性能消耗^^
注册菜单点击对应的命令
context.subscriptions.push(vscode.commands.registerCommand("cline.plusButtonClicked", async () => {Logger.log("Plus button Clicked")const visibleProvider = ClineProvider.getVisibleInstance()if (!visibleProvider) {Logger.log("Cannot find any visible Cline instances.")return}await visibleProvider.clearTask()await visibleProvider.postStateToWebview()await visibleProvider.postMessageToWebview({type: "action",action: "chatButtonClicked",})}),)context.subscriptions.push(vscode.commands.registerCommand("cline.mcpButtonClicked", () => {const visibleProvider = ClineProvider.getVisibleInstance()if (!visibleProvider) {Logger.log("Cannot find any visible Cline instances.")return}visibleProvider.postMessageToWebview({type: "action",action: "mcpButtonClicked",})}),)const openClineInNewTab = async () => {Logger.log("Opening Cline in new tab")// (this example uses webviewProvider activation event which is necessary to deserialize cached webview, but since we use retainContextWhenHidden, we don't need to use that event)// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.tsconst tabProvider = new ClineProvider(context, outputChannel)//const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefinedconst lastCol = Math.max(...vscode.window.visibleTextEditors.map((editor) => editor.viewColumn || 0))// Check if there are any visible text editors, otherwise open a new group to the rightconst hasVisibleEditors = vscode.window.visibleTextEditors.length > 0if (!hasVisibleEditors) {await vscode.commands.executeCommand("workbench.action.newGroupRight")}const targetCol = hasVisibleEditors ? Math.max(lastCol + 1, 1) : vscode.ViewColumn.Twoconst panel = vscode.window.createWebviewPanel(ClineProvider.tabPanelId, "Cline", targetCol, {enableScripts: true,retainContextWhenHidden: true,localResourceRoots: [context.extensionUri],})// TODO: use better svg icon with light and dark variants (see https://stackoverflow.com/questions/58365687/vscode-extension-iconpath)panel.iconPath = {light: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "robot_panel_light.png"),dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "robot_panel_dark.png"),}tabProvider.resolveWebviewView(panel)// Lock the editor group so clicking on files doesn't open them over the panelawait setTimeoutPromise(100)await vscode.commands.executeCommand("workbench.action.lockEditorGroup")}context.subscriptions.push(vscode.commands.registerCommand("cline.popoutButtonClicked", openClineInNewTab))context.subscriptions.push(vscode.commands.registerCommand("cline.openInNewTab", openClineInNewTab))context.subscriptions.push(vscode.commands.registerCommand("cline.settingsButtonClicked", () => {//vscode.window.showInformationMessage(message)const visibleClineProvider = ClineProvider.getVisibleInstance()if (!visibleClineProvider) {Logger.log("Cannot find any visible Cline instances.")return}visibleClineProvider.postMessageToWebview({type: "action",action: "settingsButtonClicked",})}),)context.subscriptions.push(vscode.commands.registerCommand("cline.historyButtonClicked", () => {const visibleProvider = ClineProvider.getVisibleInstance()if (!visibleProvider) {Logger.log("Cannot find any visible Cline instances.")return}visibleProvider.postMessageToWebview({type: "action",action: "historyButtonClicked",})}),)context.subscriptions.push(vscode.commands.registerCommand("cline.accountButtonClicked", () => {const visibleProvider = ClineProvider.getVisibleInstance()if (!visibleProvider) {Logger.log("Cannot find any visible Cline instances.")return}visibleProvider.postMessageToWebview({type: "action",action: "accountButtonClicked",})}),)

这里主要是注册了6个菜单对应的命令处理逻辑。大部分与视图相关的代码基本上就在这里了,active函数剩余的部分在下一篇内容中分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s EmptyDir(空目录)详解

1. 定义与特性 emptyDir 是 Kubernetes 中一种临时存储卷类型,其生命周期与 Pod 完全绑定。当 Pod 被创建时,emptyDir 会在节点上生成一个空目录;当 Pod 被删除时,该目录及其数据会被永久清除。它主要用于同一 Pod 内多个容器间的…

【idea】实用插件

SonarLint SonarLint:代码质量扫描工具 使用 SonarLint 可以帮助我们发现代码的问题,并且还提供了相应的解决方案. 对于每一个问题,SonarLint 都给出了示例,还有相应的解决方案,教我们怎么修改,极大的方便了我们的开发…

【mysql 的安装及使用】

MySQL 9.0 一、下载MySQL[MySQL 9.0 下载] [(https://dev.mysql.com/downloads/mysql/)选择自定义,选择合适安装路径二、检查安装情况配置环境变量打开命令行查看版本创建数据库在MySQL中,可以使用create database语句来创建数据库。以下是创建一个名为my_db的数据库的示例:…

leetcode118.杨辉三角

思路源自 【LeetCode 每日一题】118. 杨辉三角 | 手写图解版思路 代码讲解 class Solution {public List<List<Integer>> generate(int numRows) {List<List<Integer>> result new ArrayList<>();for (int i 0; i < numRows; i) {List<…

【git】git pull 和 git rebase

git pull 和 git rebase 都是 Git 中用于同步代码的命令&#xff0c;但它们的工作方式和适用场景有显著区别。以下是两者的详细对比&#xff1a; 1. 核心区别 特性git pullgit rebase本质git fetch git merge&#xff08;默认&#xff09;将当前分支的提交“重新播放”到目标…

DIY搭建网站(学术个人介绍主页)

本教程介绍了如何创建并管理一个基于GitHub Pages的个人网站。首先&#xff0c;需要在GitHub上创建一个遵循特定命名规则的新仓库&#xff0c;例如用户名.github.io&#xff0c;以便建立个人站点。接着&#xff0c;通过Fork一个开源模板代码仓库并添加index.html文件来构建主页…

数据结构初阶:二叉树的前中后序三种遍历(递归的暴力美学)

想要实现二叉树的遍历可以创建一个链式结构的二叉树 回顾一下二叉树的概念&#xff0c;二叉树分为空树和非空二叉树&#xff0c;非空二叉树由根节点、根节点的左子树和根节点的右子树组成。 typedef char BTDataType; // 数据类型 typedef struct BinaryTreeNode {B…

WebUI问题总结

修改WebUI代码时遇到的一些问题以及解决办法 1. thttpd服务器环境的搭建 可参考《thttpd安装与启动流程》这一篇文章 其中遇到的问题有 thttpd版本问题&#xff1a;版本过旧会导致安装失败&#xff0c;尽量安装新版本thttpd的启动命令失败的话要加上sudo修改文件权限&#…

【C++重点】deque

C queue 容器介绍 queue 是 C 标准库中的一个容器适配器&#xff0c;它实现了先进先出&#xff08;FIFO&#xff09;数据结构。即&#xff0c;元素按照插入的顺序排队&#xff0c;首先插入的元素最先出队。queue 适用于需要排队处理任务的场景&#xff0c;比如消息队列、任务调…

透过 /proc 看见内核:Linux 虚拟文件系统与 systemd 初始化初探

当我们在终端中输入 ps、top、cat /proc/cpuinfo 等命令时&#xff0c;是否思考过这些信息来自哪里&#xff1f;为什么无需启动任何守护进程&#xff0c;就能实时读取系统负载、内存占用&#xff0c;甚至内核版本&#xff1f;这一切的答案&#xff0c;都藏在 Linux 系统中的一个…

操作系统(中断 异常 陷阱) ─── linux第28课

目录 1.硬件中断 2. 时钟中断 3. OS本质 4. 软件中断 缺页中断&#xff1f;内存碎片处理&#xff1f;除零野指针错误&#xff1f; 操作系统本质总结 操作系统是对软件硬件资源管理的软件 1.硬件中断 中断向量表(IDT)就是操作系统的⼀部分&#xff0c;启动就加载到内存中了…

文件分片上传

1前端 <inputtype"file"accept".mp4"ref"videoInput"change"handleVideoChange"style"display: none;">2生成hash // 根据整个文件的文件名和大小组合的字符串生成hash值&#xff0c;大概率确定文件的唯一性fhash(f…

机器学习的一百个概念(5)数据增强

前言 本文隶属于专栏《机器学习的一百个概念》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见[《机器学习的一百个概念》 ima 知识库 知识库广场搜索&…

基于微信小程序的智慧乡村旅游服务平台【附源码】

基于微信小程序的智慧乡村旅游服务平台&#xff08;源码L文说明文档&#xff09; 目录 4系统设计 4.1系统功能设计 4.2系统结构 4.3.数据库设计 4.3.1数据库实体 4.3.2数据库设计表 5系统详细实现 5.1 管理员模块的实现 5.1.1旅游景点管理…

数据驱动的智能BMS革新:机器学习赋能电池健康预测与安全协同优化

传统电池管理系统&#xff08;BMS&#xff09;依赖等效电路模型和固定参数算法&#xff0c;面临电化学机理复杂、老化行为非线性、多工况适应性差等瓶颈。例如&#xff0c;健康状态&#xff08;SOH&#xff09;和荷电状态&#xff08;SOC&#xff09;估算易受温度、循环次数及电…

使用JSON.stringify报错:Uncaught TypeError: cyclic object value

具体错误 Uncaught TypeError: cyclic object valueonMouseOver Amap.vue:125renderMarker Amap.vue:84emit maps:1emit maps:1ci maps:1ui maps:1fireEvent maps:1jL maps:1Xt maps:1T maps:1<anonymous> amap.vue:49promise callback*nextTick runtime-core.esm-bundl…

Spring Boot 工程创建详解

2025/4/2 向全栈工程师迈进&#xff01; 一、SpingBoot工程文件的创建 点击Project Structure 然后按着如下点击 最后选择Spring Boot &#xff0c;同时记得选择是Maven和jar&#xff0c;而不是war。因为Boot工程内置了Tomcat&#xff0c;所以不需要war。 紧接着选择Spring We…

Java 8 的流(Stream API)简介

Java 8 引入的 Stream API 是一个强大的工具&#xff0c;用于处理集合&#xff08;如 List、Set&#xff09;中的元素。它支持各种操作&#xff0c;包括过滤、排序、映射等&#xff0c;并且能够以声明式的方式表达复杂的查询操作。流操作可以是中间操作&#xff08;返回流以便进…

4. Flink SQL访问HiveCatalog

一. 实验环境 Flink版本: 1.19.1 Hive版本: 2.1.3 Hadoop版本: 3.2.4二. 操作步骤 1.上传所需的jar包到Flink lib目录下 [roothadoop3 ~]# mv flink-sql-connector-hive-3.1.3_2.12-1.19.1.jar /www/flink-1.19.1/lib [roothadoop3 ~]# mv hadoop-mapreduce-client-core-3.2…

虚拟试衣间-云尚衣橱小程序-衣橱管理实现

衣橱管理实现 目标 (Goal): 用户 (User): 能通过 UniApp 小程序上传衣服图片。 后端 (Backend): 接收图片,存到云存储,并将图片信息(URL、用户ID等)存入数据库。 用户 (User): 能在小程序里看到自己上传的所有衣服图片列表。 技术栈细化 (Refined Tech Stack for this Pha…