From 4501fe40d0f2dad30fe216cd374efd991e0ed480 Mon Sep 17 00:00:00 2001 From: yetao Date: Thu, 31 Oct 2024 10:35:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor=F0=9F=8E=A8:=20=20(=E9=98=85=E8=AF=BB?= =?UTF-8?q?=E4=BB=A3=E7=A0=81)treeViewManager..ts=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/treeViewManager.ts | 99 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 6 deletions(-) diff --git a/src/treeViewManager.ts b/src/treeViewManager.ts index 849f636..f42c8b0 100644 --- a/src/treeViewManager.ts +++ b/src/treeViewManager.ts @@ -1,84 +1,171 @@ +// 导入 common/fileSystemConfig 模块中的 FileSystemConfig 类型和 getGroups 函数 import { FileSystemConfig, getGroups } from 'common/fileSystemConfig'; +// 导入 vscode 模块 import * as vscode from 'vscode'; +// 从./config 模块中导入 getConfigs 函数和 UPDATE_LISTENERS 数组 import { getConfigs, UPDATE_LISTENERS } from './config'; +// 从./connection 模块中导入 Connection 和 ConnectionManager 类型 import type { Connection, ConnectionManager } from './connection'; +// 从./pseudoTerminal 模块中导入 SSHPseudoTerminal 类型 import type { SSHPseudoTerminal } from './pseudoTerminal'; +// 从./sshFileSystem 模块中导入 SSHFileSystem 类型 import type { SSHFileSystem } from './sshFileSystem'; +// 从./ui-utils 模块中导入 formatItem 函数 import { formatItem } from './ui-utils'; +// 表示一个待处理的连接,包含连接的名称和文件系统配置(可选)。 type PendingConnection = [string, FileSystemConfig | undefined]; + +// 表示树形视图中的数据项,可以是连接、待处理的连接、SSH 文件系统或 SSH 伪终端。 type TreeData = Connection | PendingConnection | SSHFileSystem | SSHPseudoTerminal; + +// 表示一个树形视图的数据提供器,用于管理连接、待处理的连接、SSH 文件系统和 SSH 伪终端。 export class ConnectionTreeProvider implements vscode.TreeDataProvider { + // 定义一个事件发射器,用于通知树形视图数据发生变化 protected onDidChangeTreeDataEmitter = new vscode.EventEmitter(); + // 定义一个事件,当树形视图数据发生变化时触发 public onDidChangeTreeData: vscode.Event = this.onDidChangeTreeDataEmitter.event; + /** + * 构造函数,初始化连接管理器。 + * @param manager - 连接管理器实例。 + */ constructor(protected readonly manager: ConnectionManager) { + // 监听连接添加事件,当有新连接添加时,触发树形视图数据更新 manager.onConnectionAdded(() => this.onDidChangeTreeDataEmitter.fire()); + // 监听连接移除事件,当有连接移除时,触发树形视图数据更新 manager.onConnectionRemoved(() => this.onDidChangeTreeDataEmitter.fire()); + // 监听连接更新事件,当有连接更新时,触发树形视图数据更新 manager.onConnectionUpdated(con => this.onDidChangeTreeDataEmitter.fire(con)); } + + /** + * 刷新树形视图数据。 + * 当调用此方法时,会触发 onDidChangeTreeData 事件,通知树形视图数据发生变化。 + */ public refresh() { + // 触发树形视图数据更新事件 this.onDidChangeTreeDataEmitter.fire(); } + /** + * 获取指定元素的树形视图项。 + * @param element - 要获取树形视图项的元素。 + * @returns 树形视图项或 Promise 包裹的树形视图项。 + */ public getTreeItem(element: TreeData): vscode.TreeItem | Thenable { - if ('onDidChangeFile' in element || 'handleInput' in element) { // SSHFileSystem | SSHPseudoTerminal - return { ...formatItem(element), collapsibleState: vscode.TreeItemCollapsibleState.None } - } else if (Array.isArray(element)) { // PendingConnection + // 判断元素是否包含 onDidChangeFile 或 handleInput 属性,如果是,则为 SSHFileSystem 或 SSHPseudoTerminal + if ('onDidChangeFile' in element || 'handleInput' in element) { + // 返回格式化后的元素,折叠状态为 None + return { ...formatItem(element), collapsibleState: vscode.TreeItemCollapsibleState.None }; + } + // 判断元素是否为数组,如果是,则为 PendingConnection + else if (Array.isArray(element)) { // PendingConnection + // 解构赋值,获取数组中的名称和配置 const [name, config] = element; + // 如果没有配置,则返回名称和描述为 Connecting... 的树形视图项 if (!config) return { label: name, description: 'Connecting...' }; + // 返回格式化后的配置,上下文值为 pendingconnection,折叠状态为 Collapsed,图标为加载中 return { - ...formatItem(config), + ...formatItem(config), contextValue: 'pendingconnection', collapsibleState: vscode.TreeItemCollapsibleState.Collapsed, // Doesn't seem to actually spin, but still gets rendered properly otherwise + // 似乎没有实际旋转,但仍然可以正确渲染 iconPath: new vscode.ThemeIcon('loading~spin'), }; } // Connection + // 否则,元素为 Connection + // 返回格式化后的元素,折叠状态为 Collapsed return { ...formatItem(element), collapsibleState: vscode.TreeItemCollapsibleState.Collapsed }; } + /** + * 获取指定元素的子元素。 + * @param element - 要获取子元素的元素。 + * @returns 子元素数组或 Promise 包裹的子元素数组。 + */ public getChildren(element?: TreeData): vscode.ProviderResult { + // 如果没有指定元素,则返回所有活动连接和待处理连接 if (!element) return [ - ...this.manager.getActiveConnections(), - ...this.manager.getPendingConnections(), + ...this.manager.getActiveConnections(), + ...this.manager.getPendingConnections(), ]; + // 判断元素是否包含 onDidChangeFile 属性,如果是,则为 SSHFileSystem,返回空数组 if ('onDidChangeFile' in element) return []; // SSHFileSystem + // 判断元素是否包含 handleInput 属性,如果是,则为 SSHPseudoTerminal,返回空数组 if ('handleInput' in element) return []; // SSHPseudoTerminal + // 判断元素是否为数组,如果是,则为 PendingConnection,返回空数组 if (Array.isArray(element)) return []; // PendingConnection + // 否则,元素为 Connection,返回其终端和文件系统 return [...element.terminals, ...element.filesystems]; // Connection } } +/** + * 表示一个树形视图的数据提供器,用于管理文件系统配置和组。 + */ export class ConfigTreeProvider implements vscode.TreeDataProvider { + // 定义一个事件发射器,用于通知树形视图数据发生变化 protected onDidChangeTreeDataEmitter = new vscode.EventEmitter(); + // 定义一个事件,当树形视图数据发生变化时触发 public onDidChangeTreeData: vscode.Event = this.onDidChangeTreeDataEmitter.event; + + /** + * 构造函数,初始化配置树提供器。 + * 它会监听配置更新事件,并在配置更改时刷新树形视图。 + */ constructor() { // Would be very difficult (and a bit useless) to pinpoint the exact // group/config that changes, so let's just update the whole tree + // 监听配置更新事件,当配置更新时,触发树形视图数据更新 UPDATE_LISTENERS.push(() => this.onDidChangeTreeDataEmitter.fire()); // ^ Technically a memory leak, but there should only be one ConfigTreeProvider that never gets discarded + // 从技术上讲,这可能会导致内存泄漏,但实际上应该只有一个 ConfigTreeProvider 实例,且它不会被丢弃。 } + + /** + * 获取指定元素的树形视图项。 + * @param element - 要获取树形视图项的元素。 + * @returns 树形视图项或 Promise 包裹的树形视图项。 + */ public getTreeItem(element: FileSystemConfig | string): vscode.TreeItem | Thenable { + // 如果元素是字符串,则表示它是一个组 if (typeof element === 'string') { + // 返回一个树形视图项,标签为组名(去除前缀),上下文值为 group,折叠状态为 Collapsed,图标为文件夹 return { label: element.replace(/^.+\./, ''), contextValue: 'group', collapsibleState: vscode.TreeItemCollapsibleState.Collapsed, iconPath: vscode.ThemeIcon.Folder, }; } + // 如果元素是 FileSystemConfig 类型,则返回格式化后的配置项 return { ...formatItem(element), collapsibleState: vscode.TreeItemCollapsibleState.None }; } + + /** + * 获取指定元素的子元素。 + * @param element - 要获取子元素的元素。 + * @returns 子元素数组或 Promise 包裹的子元素数组。 + */ public getChildren(element: FileSystemConfig | string = ''): vscode.ProviderResult<(FileSystemConfig | string)[]> { + // 如果元素不是字符串,则返回空数组,因为配置项没有子元素 if (typeof element !== 'string') return []; // Configs don't have children + // 获取所有配置项 const configs = getConfigs(); + // 过滤出属于指定组的配置项 const matching = configs.filter(({ group }) => (group || '') === element); + // 对匹配的配置项进行排序 matching.sort((a, b) => a.name > b.name ? 1 : -1); + // 获取所有组 let groups = getGroups(configs, true); + // 如果指定了元素,则过滤出以该元素为前缀的组 if (element) { groups = groups.filter(g => g.startsWith(element) && g[element.length] === '.' && !g.includes('.', element.length + 1)); } else { + // 如果没有指定元素,则过滤出顶级组(不包含点号的组) groups = groups.filter(g => !g.includes('.')); } + // 返回匹配的配置项和组的数组 return [...matching, ...groups.sort()]; } } \ No newline at end of file