From 0ab21852c41f94f5cfd2ad837613e436221ea931 Mon Sep 17 00:00:00 2001 From: yetao Date: Thu, 31 Oct 2024 13:31:16 +0800 Subject: [PATCH] =?UTF-8?q?refactor=F0=9F=8E=A8:=20=20=20(=E9=98=85?= =?UTF-8?q?=E8=AF=BB=E4=BB=A3=E7=A0=81)=EF=BC=9Avscode.ts=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webview/src/vscode.ts | 117 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/webview/src/vscode.ts b/webview/src/vscode.ts index cbfbc5c..4a215ae 100644 --- a/webview/src/vscode.ts +++ b/webview/src/vscode.ts @@ -1,101 +1,218 @@ +// 导入 ConfigLocation 和 FileSystemConfig 类型,这些类型定义了文件系统配置的相关属性 import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig'; +// 导入 Message、MessageTypes、PromptPathResultMessage 和 SaveConfigResultMessage 类型,这些类型定义了与 WebView 通信相关的消息格式 import type { Message, MessageTypes, PromptPathResultMessage, SaveConfigResultMessage } from 'common/webviewMessages'; + +/** + * 定义了与 VSCode 进行通信的 API 方法 + */ interface VSCodeAPI { + /** + * 向 VSCode 发送消息 + * @param msg - 要发送的消息 + */ postMessage(msg: Message): void; + /** + * 设置 VSCode 的状态 + * @param state - 要设置的状态 + */ setState(state: any): void; + /** + * 获取 VSCode 的状态 + * @returns 当前的状态,如果没有则返回 undefined + */ getState(): T | undefined; } + +// 声明一个函数 acquireVsCodeApi,用于获取 VSCode API declare const acquireVsCodeApi: () => VSCodeAPI; +// 导出一个常量 API,它是通过调用 acquireVsCodeApi 函数获取到的 VSCode API export const API: VSCodeAPI = acquireVsCodeApi(); +/** + * 定义了一个监听器函数,用于处理特定类型的消息 + * @typeparam T - 消息的类型,默认为 Message 类型 + */ export type Listener = (message: T) => void; +/** + * 定义了一个过滤器类型,可以是字符串或者一个函数,用于过滤消息 + */ export type Filter = string | ((message: Message) => boolean); +// 初始化一个数组,用于存储监听器和过滤器 let LISTENERS: [Listener, Filter | undefined][] = []; +/** + * 添加一个监听器,用于处理特定类型的消息 + * @param listener - 监听器函数 + * @param filter - 过滤器,可以是消息类型字符串或者一个函数 + */ export function addListener(listener: Listener): void; export function addListener(listener: Listener, filter: K): void; export function addListener(listener: Listener, filter: Exclude): void; export function addListener(listener: Listener, filter?: Filter) { + // 将监听器和过滤器添加到 LISTENERS 数组中 LISTENERS.push([listener, filter]); } + +/** + * 移除一个监听器 + * @param listener - 要移除的监听器函数 + */ export function removeListener(listener: Listener) { + // 从 LISTENERS 数组中移除指定的监听器 LISTENERS = LISTENERS.filter(([l]) => l !== listener); } +/** + * 监听窗口的 message 事件,处理来自 VSCode 的消息 + * @param event - 窗口的 message 事件 + */ window.addEventListener('message', event => { + // 打印接收到的消息事件 console.log('MESSAGE', event); + // 从事件中获取消息数据,并断言其为 Message 类型 const message: Message = event.data; + // 如果消息不存在或没有类型,则忽略该消息 if (!message || !message.type) return; + // 遍历监听器列表 for (const [listener, filter] of LISTENERS) { + // 如果过滤器是字符串类型 if (typeof filter === 'string') { + // 如果过滤器字符串与消息类型不匹配,则继续下一个监听器 if (filter !== message.type) continue; + // 如果过滤器是函数类型 } else if (filter && !filter(message)) { + // 如果过滤器函数返回 false,则继续下一个监听器 continue; } + // 尝试调用监听器函数处理消息 try { listener(message); } catch (e) { + // 如果在处理消息时发生错误,打印错误信息 console.error('Error in message handler', e, message); } } }); +/** + * 创建一个新的文件系统配置,并将其保存到 VSCode 的配置中 + * @param name - 配置的名称 + * @param location - 配置的位置 + * @returns 一个 Promise,成功时解析为新创建的文件系统配置 + * @throws 如果保存配置失败,则抛出错误 + */ export function createConfig(name: string, location: ConfigLocation): Promise { + // 返回一个 Promise,用于处理异步操作 return new Promise((resolve, reject) => { + // 生成一个唯一的 ID,用于标识当前的配置请求 const uniqueId = `${name}-${Date.now()};` + // 定义一个处理函数,用于处理来自 VSCode 的保存配置结果消息 function handler(message: SaveConfigResultMessage) { + // 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息 if (message.uniqueId !== uniqueId) return; + // 从监听器列表中移除当前的处理函数 removeListener(handler); + // 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者 if (message.error) return reject(message.error); + // 如果消息中包含新创建的配置,则解析 Promise,并将配置信息传递给调用者 resolve(message.config); } + // 添加处理函数到监听器列表中,用于监听 saveConfigResult 类型的消息 addListener(handler, 'saveConfigResult'); + // 创建一个新的文件系统配置对象,包含名称和位置信息 const config: FileSystemConfig = { name, _location: location, _locations: [location] }; + // 向 VSCode 发送一个消息,请求保存新创建的配置,并附带唯一 ID API.postMessage({ type: 'saveConfig', config, uniqueId }); }); } +/** + * 保存一个文件系统配置到 VSCode 的配置中 + * @param config - 要保存的文件系统配置 + * @param name - 配置的名称,如果未提供,则使用配置对象中的名称 + * @returns 一个 Promise,成功时解析为 undefined + * @throws 如果保存配置失败,则抛出错误 + */ export function saveConfig(config: FileSystemConfig, name?: string): Promise { + // 返回一个 Promise,用于处理异步操作 return new Promise((resolve, reject) => { + // 生成一个唯一的 ID,用于标识当前的配置保存请求 const uniqueId = `${config.name}-${Date.now()};` + // 定义一个处理函数,用于处理来自 VSCode 的保存配置结果消息 function handler(message: SaveConfigResultMessage) { + // 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息 if (message.uniqueId !== uniqueId) return; + // 从监听器列表中移除当前的处理函数 removeListener(handler); + // 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者 if (message.error) return reject(message.error); + // 如果消息中没有错误信息,则解析 Promise,并将 undefined 传递给调用者 resolve(); } + // 添加处理函数到监听器列表中,用于监听 saveConfigResult 类型的消息 addListener(handler, 'saveConfigResult'); + // 向 VSCode 发送一个消息,请求保存配置,并附带唯一 ID 和配置名称 API.postMessage({ type: 'saveConfig', config, uniqueId, name }); }); } +/** + * 从 VSCode 的配置中删除一个文件系统配置 + * @param config - 要删除的文件系统配置 + * @returns 一个 Promise,成功时解析为 undefined + * @throws 如果删除配置失败,则抛出错误 + */ export function deleteConfig(config: FileSystemConfig): Promise { + // 返回一个 Promise,用于处理异步操作 return new Promise((resolve, reject) => { + // 生成一个唯一的 ID,用于标识当前的配置删除请求 const uniqueId = `${config.name}-${Date.now()};` + // 定义一个处理函数,用于处理来自 VSCode 的保存配置结果消息 function handler(message: SaveConfigResultMessage) { + // 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息 if (message.uniqueId !== uniqueId) return; + // 从监听器列表中移除当前的处理函数 removeListener(handler); + // 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者 if (message.error) return reject(message.error); + // 如果消息中没有错误信息,则解析 Promise,并将 undefined 传递给调用者 resolve(); } + // 添加处理函数到监听器列表中,用于监听 saveConfigResult 类型的消息 addListener(handler, 'saveConfigResult'); + // 向 VSCode 发送一个消息,请求删除配置,并附带唯一 ID 和删除标志 API.postMessage({ type: 'saveConfig', config, uniqueId, remove: true }); }); } +/** + * 显示一个文件选择对话框,提示用户选择一个路径 + * @returns 一个 Promise,成功时解析为用户选择的文件路径,如果用户取消选择,则解析为 undefined + * @throws 如果在获取路径过程中发生错误,则抛出错误 + */ export function promptPath(): Promise { + // 返回一个 Promise,用于处理异步操作 return new Promise((resolve, reject) => { + // 生成一个唯一的 ID,用于标识当前的路径选择请求 const uniqueId = Date.now().toString(); + // 定义一个处理函数,用于处理来自 VSCode 的路径选择结果消息 function handler(message: PromptPathResultMessage) { + // 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息 if (message.uniqueId !== uniqueId) return; + // 从监听器列表中移除当前的处理函数 removeListener(handler); + // 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者 if (message.error) return reject(message.error); + // 如果消息中包含用户选择的路径,则解析 Promise,并将路径信息传递给调用者 resolve(message.path); } + // 添加处理函数到监听器列表中,用于监听 promptPathResult 类型的消息 addListener(handler, 'promptPathResult'); + // 向 VSCode 发送一个消息,请求显示文件选择对话框,并附带唯一 ID API.postMessage({ type: 'promptPath', uniqueId }); }); }