|
|
@ -1,101 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 导入 ConfigLocation 和 FileSystemConfig 类型,这些类型定义了文件系统配置的相关属性
|
|
|
|
import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig';
|
|
|
|
import type { ConfigLocation, FileSystemConfig } from 'common/fileSystemConfig';
|
|
|
|
|
|
|
|
// 导入 Message、MessageTypes、PromptPathResultMessage 和 SaveConfigResultMessage 类型,这些类型定义了与 WebView 通信相关的消息格式
|
|
|
|
import type { Message, MessageTypes, PromptPathResultMessage, SaveConfigResultMessage } from 'common/webviewMessages';
|
|
|
|
import type { Message, MessageTypes, PromptPathResultMessage, SaveConfigResultMessage } from 'common/webviewMessages';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 定义了与 VSCode 进行通信的 API 方法
|
|
|
|
|
|
|
|
*/
|
|
|
|
interface VSCodeAPI {
|
|
|
|
interface VSCodeAPI {
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 向 VSCode 发送消息
|
|
|
|
|
|
|
|
* @param msg - 要发送的消息
|
|
|
|
|
|
|
|
*/
|
|
|
|
postMessage(msg: Message): void;
|
|
|
|
postMessage(msg: Message): void;
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 设置 VSCode 的状态
|
|
|
|
|
|
|
|
* @param state - 要设置的状态
|
|
|
|
|
|
|
|
*/
|
|
|
|
setState(state: any): void;
|
|
|
|
setState(state: any): void;
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取 VSCode 的状态
|
|
|
|
|
|
|
|
* @returns 当前的状态,如果没有则返回 undefined
|
|
|
|
|
|
|
|
*/
|
|
|
|
getState<T>(): T | undefined;
|
|
|
|
getState<T>(): T | undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 声明一个函数 acquireVsCodeApi,用于获取 VSCode API
|
|
|
|
declare const acquireVsCodeApi: () => VSCodeAPI;
|
|
|
|
declare const acquireVsCodeApi: () => VSCodeAPI;
|
|
|
|
|
|
|
|
// 导出一个常量 API,它是通过调用 acquireVsCodeApi 函数获取到的 VSCode API
|
|
|
|
export const API: VSCodeAPI = acquireVsCodeApi();
|
|
|
|
export const API: VSCodeAPI = acquireVsCodeApi();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 定义了一个监听器函数,用于处理特定类型的消息
|
|
|
|
|
|
|
|
* @typeparam T - 消息的类型,默认为 Message 类型
|
|
|
|
|
|
|
|
*/
|
|
|
|
export type Listener<T extends Message = Message> = (message: T) => void;
|
|
|
|
export type Listener<T extends Message = Message> = (message: T) => void;
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 定义了一个过滤器类型,可以是字符串或者一个函数,用于过滤消息
|
|
|
|
|
|
|
|
*/
|
|
|
|
export type Filter = string | ((message: Message) => boolean);
|
|
|
|
export type Filter = string | ((message: Message) => boolean);
|
|
|
|
|
|
|
|
// 初始化一个数组,用于存储监听器和过滤器
|
|
|
|
let LISTENERS: [Listener, Filter | undefined][] = [];
|
|
|
|
let LISTENERS: [Listener, Filter | undefined][] = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 添加一个监听器,用于处理特定类型的消息
|
|
|
|
|
|
|
|
* @param listener - 监听器函数
|
|
|
|
|
|
|
|
* @param filter - 过滤器,可以是消息类型字符串或者一个函数
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function addListener(listener: Listener): void;
|
|
|
|
export function addListener(listener: Listener): void;
|
|
|
|
export function addListener<K extends Message['type']>(listener: Listener<MessageTypes[K]>, filter: K): void;
|
|
|
|
export function addListener<K extends Message['type']>(listener: Listener<MessageTypes[K]>, filter: K): void;
|
|
|
|
export function addListener<T extends Message = Message>(listener: Listener<T>, filter: Exclude<Filter, string>): void;
|
|
|
|
export function addListener<T extends Message = Message>(listener: Listener<T>, filter: Exclude<Filter, string>): void;
|
|
|
|
export function addListener(listener: Listener, filter?: Filter) {
|
|
|
|
export function addListener(listener: Listener, filter?: Filter) {
|
|
|
|
|
|
|
|
// 将监听器和过滤器添加到 LISTENERS 数组中
|
|
|
|
LISTENERS.push([listener, filter]);
|
|
|
|
LISTENERS.push([listener, filter]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 移除一个监听器
|
|
|
|
|
|
|
|
* @param listener - 要移除的监听器函数
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function removeListener<T extends Message = Message>(listener: Listener<T>) {
|
|
|
|
export function removeListener<T extends Message = Message>(listener: Listener<T>) {
|
|
|
|
|
|
|
|
// 从 LISTENERS 数组中移除指定的监听器
|
|
|
|
LISTENERS = LISTENERS.filter(([l]) => l !== listener);
|
|
|
|
LISTENERS = LISTENERS.filter(([l]) => l !== listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 监听窗口的 message 事件,处理来自 VSCode 的消息
|
|
|
|
|
|
|
|
* @param event - 窗口的 message 事件
|
|
|
|
|
|
|
|
*/
|
|
|
|
window.addEventListener('message', event => {
|
|
|
|
window.addEventListener('message', event => {
|
|
|
|
|
|
|
|
// 打印接收到的消息事件
|
|
|
|
console.log('MESSAGE', event);
|
|
|
|
console.log('MESSAGE', event);
|
|
|
|
|
|
|
|
// 从事件中获取消息数据,并断言其为 Message 类型
|
|
|
|
const message: Message = event.data;
|
|
|
|
const message: Message = event.data;
|
|
|
|
|
|
|
|
// 如果消息不存在或没有类型,则忽略该消息
|
|
|
|
if (!message || !message.type) return;
|
|
|
|
if (!message || !message.type) return;
|
|
|
|
|
|
|
|
// 遍历监听器列表
|
|
|
|
for (const [listener, filter] of LISTENERS) {
|
|
|
|
for (const [listener, filter] of LISTENERS) {
|
|
|
|
|
|
|
|
// 如果过滤器是字符串类型
|
|
|
|
if (typeof filter === 'string') {
|
|
|
|
if (typeof filter === 'string') {
|
|
|
|
|
|
|
|
// 如果过滤器字符串与消息类型不匹配,则继续下一个监听器
|
|
|
|
if (filter !== message.type) continue;
|
|
|
|
if (filter !== message.type) continue;
|
|
|
|
|
|
|
|
// 如果过滤器是函数类型
|
|
|
|
} else if (filter && !filter(message)) {
|
|
|
|
} else if (filter && !filter(message)) {
|
|
|
|
|
|
|
|
// 如果过滤器函数返回 false,则继续下一个监听器
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 尝试调用监听器函数处理消息
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
listener(message);
|
|
|
|
listener(message);
|
|
|
|
} catch (e) {
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
// 如果在处理消息时发生错误,打印错误信息
|
|
|
|
console.error('Error in message handler', e, message);
|
|
|
|
console.error('Error in message handler', e, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 创建一个新的文件系统配置,并将其保存到 VSCode 的配置中
|
|
|
|
|
|
|
|
* @param name - 配置的名称
|
|
|
|
|
|
|
|
* @param location - 配置的位置
|
|
|
|
|
|
|
|
* @returns 一个 Promise,成功时解析为新创建的文件系统配置
|
|
|
|
|
|
|
|
* @throws 如果保存配置失败,则抛出错误
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function createConfig(name: string, location: ConfigLocation): Promise<FileSystemConfig> {
|
|
|
|
export function createConfig(name: string, location: ConfigLocation): Promise<FileSystemConfig> {
|
|
|
|
|
|
|
|
// 返回一个 Promise,用于处理异步操作
|
|
|
|
return new Promise<FileSystemConfig>((resolve, reject) => {
|
|
|
|
return new Promise<FileSystemConfig>((resolve, reject) => {
|
|
|
|
|
|
|
|
// 生成一个唯一的 ID,用于标识当前的配置请求
|
|
|
|
const uniqueId = `${name}-${Date.now()};`
|
|
|
|
const uniqueId = `${name}-${Date.now()};`
|
|
|
|
|
|
|
|
// 定义一个处理函数,用于处理来自 VSCode 的保存配置结果消息
|
|
|
|
function handler(message: SaveConfigResultMessage) {
|
|
|
|
function handler(message: SaveConfigResultMessage) {
|
|
|
|
|
|
|
|
// 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
|
|
|
|
// 从监听器列表中移除当前的处理函数
|
|
|
|
removeListener(handler);
|
|
|
|
removeListener(handler);
|
|
|
|
|
|
|
|
// 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
|
|
|
|
// 如果消息中包含新创建的配置,则解析 Promise,并将配置信息传递给调用者
|
|
|
|
resolve(message.config);
|
|
|
|
resolve(message.config);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 添加处理函数到监听器列表中,用于监听 saveConfigResult 类型的消息
|
|
|
|
addListener(handler, 'saveConfigResult');
|
|
|
|
addListener(handler, 'saveConfigResult');
|
|
|
|
|
|
|
|
// 创建一个新的文件系统配置对象,包含名称和位置信息
|
|
|
|
const config: FileSystemConfig = { name, _location: location, _locations: [location] };
|
|
|
|
const config: FileSystemConfig = { name, _location: location, _locations: [location] };
|
|
|
|
|
|
|
|
// 向 VSCode 发送一个消息,请求保存新创建的配置,并附带唯一 ID
|
|
|
|
API.postMessage({ type: 'saveConfig', config, uniqueId });
|
|
|
|
API.postMessage({ type: 'saveConfig', config, uniqueId });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 保存一个文件系统配置到 VSCode 的配置中
|
|
|
|
|
|
|
|
* @param config - 要保存的文件系统配置
|
|
|
|
|
|
|
|
* @param name - 配置的名称,如果未提供,则使用配置对象中的名称
|
|
|
|
|
|
|
|
* @returns 一个 Promise,成功时解析为 undefined
|
|
|
|
|
|
|
|
* @throws 如果保存配置失败,则抛出错误
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function saveConfig(config: FileSystemConfig, name?: string): Promise<void> {
|
|
|
|
export function saveConfig(config: FileSystemConfig, name?: string): Promise<void> {
|
|
|
|
|
|
|
|
// 返回一个 Promise,用于处理异步操作
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
|
|
// 生成一个唯一的 ID,用于标识当前的配置保存请求
|
|
|
|
const uniqueId = `${config.name}-${Date.now()};`
|
|
|
|
const uniqueId = `${config.name}-${Date.now()};`
|
|
|
|
|
|
|
|
// 定义一个处理函数,用于处理来自 VSCode 的保存配置结果消息
|
|
|
|
function handler(message: SaveConfigResultMessage) {
|
|
|
|
function handler(message: SaveConfigResultMessage) {
|
|
|
|
|
|
|
|
// 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
|
|
|
|
// 从监听器列表中移除当前的处理函数
|
|
|
|
removeListener(handler);
|
|
|
|
removeListener(handler);
|
|
|
|
|
|
|
|
// 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
|
|
|
|
// 如果消息中没有错误信息,则解析 Promise,并将 undefined 传递给调用者
|
|
|
|
resolve();
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 添加处理函数到监听器列表中,用于监听 saveConfigResult 类型的消息
|
|
|
|
addListener(handler, 'saveConfigResult');
|
|
|
|
addListener(handler, 'saveConfigResult');
|
|
|
|
|
|
|
|
// 向 VSCode 发送一个消息,请求保存配置,并附带唯一 ID 和配置名称
|
|
|
|
API.postMessage({ type: 'saveConfig', config, uniqueId, name });
|
|
|
|
API.postMessage({ type: 'saveConfig', config, uniqueId, name });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 从 VSCode 的配置中删除一个文件系统配置
|
|
|
|
|
|
|
|
* @param config - 要删除的文件系统配置
|
|
|
|
|
|
|
|
* @returns 一个 Promise,成功时解析为 undefined
|
|
|
|
|
|
|
|
* @throws 如果删除配置失败,则抛出错误
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function deleteConfig(config: FileSystemConfig): Promise<void> {
|
|
|
|
export function deleteConfig(config: FileSystemConfig): Promise<void> {
|
|
|
|
|
|
|
|
// 返回一个 Promise,用于处理异步操作
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
|
|
// 生成一个唯一的 ID,用于标识当前的配置删除请求
|
|
|
|
const uniqueId = `${config.name}-${Date.now()};`
|
|
|
|
const uniqueId = `${config.name}-${Date.now()};`
|
|
|
|
|
|
|
|
// 定义一个处理函数,用于处理来自 VSCode 的保存配置结果消息
|
|
|
|
function handler(message: SaveConfigResultMessage) {
|
|
|
|
function handler(message: SaveConfigResultMessage) {
|
|
|
|
|
|
|
|
// 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
|
|
|
|
// 从监听器列表中移除当前的处理函数
|
|
|
|
removeListener(handler);
|
|
|
|
removeListener(handler);
|
|
|
|
|
|
|
|
// 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
|
|
|
|
// 如果消息中没有错误信息,则解析 Promise,并将 undefined 传递给调用者
|
|
|
|
resolve();
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 添加处理函数到监听器列表中,用于监听 saveConfigResult 类型的消息
|
|
|
|
addListener(handler, 'saveConfigResult');
|
|
|
|
addListener(handler, 'saveConfigResult');
|
|
|
|
|
|
|
|
// 向 VSCode 发送一个消息,请求删除配置,并附带唯一 ID 和删除标志
|
|
|
|
API.postMessage({ type: 'saveConfig', config, uniqueId, remove: true });
|
|
|
|
API.postMessage({ type: 'saveConfig', config, uniqueId, remove: true });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 显示一个文件选择对话框,提示用户选择一个路径
|
|
|
|
|
|
|
|
* @returns 一个 Promise,成功时解析为用户选择的文件路径,如果用户取消选择,则解析为 undefined
|
|
|
|
|
|
|
|
* @throws 如果在获取路径过程中发生错误,则抛出错误
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function promptPath(): Promise<string | undefined> {
|
|
|
|
export function promptPath(): Promise<string | undefined> {
|
|
|
|
|
|
|
|
// 返回一个 Promise,用于处理异步操作
|
|
|
|
return new Promise<string | undefined>((resolve, reject) => {
|
|
|
|
return new Promise<string | undefined>((resolve, reject) => {
|
|
|
|
|
|
|
|
// 生成一个唯一的 ID,用于标识当前的路径选择请求
|
|
|
|
const uniqueId = Date.now().toString();
|
|
|
|
const uniqueId = Date.now().toString();
|
|
|
|
|
|
|
|
// 定义一个处理函数,用于处理来自 VSCode 的路径选择结果消息
|
|
|
|
function handler(message: PromptPathResultMessage) {
|
|
|
|
function handler(message: PromptPathResultMessage) {
|
|
|
|
|
|
|
|
// 如果消息的唯一 ID 与当前请求的唯一 ID 不匹配,则忽略该消息
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
if (message.uniqueId !== uniqueId) return;
|
|
|
|
|
|
|
|
// 从监听器列表中移除当前的处理函数
|
|
|
|
removeListener(handler);
|
|
|
|
removeListener(handler);
|
|
|
|
|
|
|
|
// 如果消息中包含错误信息,则拒绝 Promise,并将错误信息传递给调用者
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
if (message.error) return reject(message.error);
|
|
|
|
|
|
|
|
// 如果消息中包含用户选择的路径,则解析 Promise,并将路径信息传递给调用者
|
|
|
|
resolve(message.path);
|
|
|
|
resolve(message.path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 添加处理函数到监听器列表中,用于监听 promptPathResult 类型的消息
|
|
|
|
addListener(handler, 'promptPathResult');
|
|
|
|
addListener(handler, 'promptPathResult');
|
|
|
|
|
|
|
|
// 向 VSCode 发送一个消息,请求显示文件选择对话框,并附带唯一 ID
|
|
|
|
API.postMessage({ type: 'promptPath', uniqueId });
|
|
|
|
API.postMessage({ type: 'promptPath', uniqueId });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|