From bf1e60e0e624f1f19b143a57e1e12704a1e9c067 Mon Sep 17 00:00:00 2001 From: yunpeng Date: Mon, 20 May 2024 00:44:21 +0800 Subject: [PATCH] docs: Add missing documentation comments to multiple utility functions --- .hintrc | 21 +++ pre-download-build.js | 20 ++- src/context.ts | 20 +++ src/editor/editor-api/VSCodeAction.ts | 138 +++++++++++++++++- .../webview/AutoDevWebviewViewProvider.ts | 29 ++++ src/extension.ts | 43 ++++++ 6 files changed, 262 insertions(+), 9 deletions(-) create mode 100644 .hintrc diff --git a/.hintrc b/.hintrc new file mode 100644 index 00000000..6e0e14f6 --- /dev/null +++ b/.hintrc @@ -0,0 +1,21 @@ +{ + "extends": [ + "development" + ], + "hints": { + "axe/text-alternatives": [ + "default", + { + "image-alt": "off" + } + ], + "disown-opener": "off", + "axe/forms": [ + "default", + { + "label": "off" + } + ], + "typescript-config/strict": "off" + } +} \ No newline at end of file diff --git a/pre-download-build.js b/pre-download-build.js index 6ed0789b..6c119bb8 100644 --- a/pre-download-build.js +++ b/pre-download-build.js @@ -45,17 +45,25 @@ for (const target of targets) { const downloadUrl = `https://github.com/TryGhost/node-sqlite3/releases/download/v5.1.7/sqlite3-v5.1.7-napi-v6-${ target === "win32-arm64" ? "win32-ia32" : target }.tar.gz`; - execSync(`curl -L -o ${targetDir}/build.tar.gz ${downloadUrl}`); + // 检查下载文件是否存在 + const filePath = `${targetDir}/build.tar.gz`; + if (fs.existsSync(filePath)) { + console.log(`[info] File already exists: ${filePath}`); + } else { + // 如果文件不存在,下载文件 + console.log(`[info] Downloading ${target}...`); + execSync(`curl -L -o ${targetDir}/build.tar.gz ${downloadUrl}`); + } execSync(`cd ${targetDir} && tar -xvzf build.tar.gz`); fs.copyFileSync( `${targetDir}/build/Release/node_sqlite3.node`, `${targetDir}/node_sqlite3.node`, ); - fs.unlinkSync(`${targetDir}/build.tar.gz`); - fs.rmSync(`${targetDir}/build`, { - recursive: true, - force: true, - }); + // fs.unlinkSync(`${targetDir}/build.tar.gz`); + // fs.rmSync(`${targetDir}/build`, { + // recursive: true, + // force: true, + // }); } console.log("[info] Downloading prebuilt lancedb..."); diff --git a/src/context.ts b/src/context.ts index d848787c..37e1ca85 100644 --- a/src/context.ts +++ b/src/context.ts @@ -2,19 +2,39 @@ import * as vscode from "vscode"; let _context: vscode.ExtensionContext | undefined; +/** + * 设置扩展上下文 + * + * @param context 扩展上下文对象 + */ export function setExtensionContext(context: vscode.ExtensionContext) { _context = context; } +/** + * 获取扩展程序的URI。 + * + * @returns 返回扩展程序的URI。 + */ export function getExtensionUri() { return _context?.extensionUri!; } +/** + * 获取扩展上下文对象 + * + * @returns 扩展上下文对象 + */ export function getExtensionContext() { return _context!; } +/** + * 移除扩展上下文 + * + * 将扩展上下文 `_context` 设置为 `undefined`,以清除扩展上下文信息。 + */ export function removeExtensionContext() { _context = undefined; } diff --git a/src/editor/editor-api/VSCodeAction.ts b/src/editor/editor-api/VSCodeAction.ts index 3beee324..861c1247 100644 --- a/src/editor/editor-api/VSCodeAction.ts +++ b/src/editor/editor-api/VSCodeAction.ts @@ -10,53 +10,98 @@ import { defaultIgnoreFile } from "../util/ignore"; export class VSCodeAction implements IdeAction { git: GitAction = new GitAction(); + /** + * 执行命令 + * + * @param command 命令字符串 + * @returns Promise 无返回值 + */ async runCommand(command: string): Promise { + // 如果有已打开的终端 if (vscode.window.terminals.length) { + // 显示第一个终端 vscode.window.terminals[0].show(); + // 在终端中发送命令 vscode.window.terminals[0].sendText(command, false); } else { + // 创建一个新的终端 const terminal = vscode.window.createTerminal(); + // 显示新创建的终端 terminal.show(); + // 在新创建的终端中发送命令 terminal.sendText(command, false); } } // getTerminalContents: [undefined, string]; + /** + * 获取终端内容 + * + * @param commands 要选择的命令数量,默认为-1,表示选择所有内容 + * @returns 返回终端内容的Promise对象 + */ async getTerminalContents(commands: number = -1): Promise { + // 读取剪贴板的内容到临时变量tempCopyBuffer const tempCopyBuffer = await vscode.env.clipboard.readText(); + + // 如果commands小于0 if (commands < 0) { + // 执行命令选择终端中的所有内容 await vscode.commands.executeCommand( "workbench.editor-api.terminal.selectAll" ); } else { + // 遍历执行命令选择上一个命令的内容,循环次数为commands for (let i = 0; i < commands; i++) { await vscode.commands.executeCommand( "workbench.editor-api.terminal.selectToPreviousCommand" ); } } + + // 执行命令复制选中的终端内容 await vscode.commands.executeCommand( "workbench.editor-api.terminal.copySelection" ); + + // 执行命令清除选中的终端内容 await vscode.commands.executeCommand( "workbench.editor-api.terminal.clearSelection" ); + + // 读取剪贴板的内容到terminalContents变量 const terminalContents = await vscode.env.clipboard.readText(); + + // 将临时变量tempCopyBuffer的内容写回剪贴板 await vscode.env.clipboard.writeText(tempCopyBuffer); + // 如果临时变量tempCopyBuffer与终端内容terminalContents相同 if (tempCopyBuffer === terminalContents) { - // This means there is no terminal open to select text from + // 这意味着没有打开的终端可以从中选择文本 return ""; } + + // 返回终端内容 return terminalContents; } + /** + * 获取工作区目录列表 + * + * @returns 返回工作区目录的路径数组,若获取失败则返回空数组 + */ getWorkspaceDirectories(): string[] { return (vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath) || []); } private static MAX_BYTES = 100000; + /** + * 获取文件路径的绝对路径 + * + * @param filepath 文件路径 + * @returns 返回绝对路径字符串 + */ getAbsolutePath(filepath: string): string { const workspaceDirectories = this.getWorkspaceDirectories(); if (!path.isAbsolute(filepath) && workspaceDirectories.length === 1) { @@ -66,50 +111,81 @@ export class VSCodeAction implements IdeAction { } } + /** + * 异步读取文件内容 + * + * @param filepath 文件路径 + * @returns 返回文件内容的Promise对象 + */ async readFile(filepath: string): Promise { try { + // 获取文件的绝对路径 filepath = this.getAbsolutePath(filepath); + // 将文件路径转换为 URI const uri = this.uriFromFilePath(filepath); - // Check first whether it's an open document + // 首先检查是否是已打开的文档 const openTextDocument = vscode.workspace.textDocuments.find( (doc) => doc.uri.fsPath === uri.fsPath, ); if (openTextDocument !== undefined) { + // 如果是已打开的文档,直接返回文档内容 return openTextDocument.getText(); } + // 获取文件状态信息 const fileStats = await vscode.workspace.fs.stat( this.uriFromFilePath(filepath), ); + // 如果文件大小超过最大限制,返回空字符串 if (fileStats.size > 10 * VSCodeAction.MAX_BYTES) { return ""; } + // 读取文件内容 const bytes = await vscode.workspace.fs.readFile(uri); - // Truncate the buffer to the first MAX_BYTES + // 截取缓冲区的前 MAX_BYTES 字节 const truncatedBytes = bytes.slice(0, VSCodeAction.MAX_BYTES); + // 将字节解码为字符串 const contents = new TextDecoder().decode(truncatedBytes); + // 返回文件内容 return contents; } catch { + // 如果发生异常,返回空字符串 return ""; } } + /** + * 根据文件路径获取vscode.Uri对象 + * + * @param filepath 文件路径 + * @returns 返回一个vscode.Uri对象 + */ uriFromFilePath(filepath: string): vscode.Uri { + // 如果当前环境是远程环境 if (vscode.env.remoteName) { + // 如果当前环境是Windows本地环境但不是远程环境 if (this.isWindowsLocalButNotRemote()) { + // 将文件路径从Windows格式转换为POSIX格式 filepath = this.windowsToPosix(filepath); } + // 根据远程环境名称和文件路径构造VSCode的URI对象 return vscode.Uri.parse( `vscode-remote://${vscode.env.remoteName}${filepath}`, ); } else { + // 如果当前环境不是远程环境,则构造本地文件的VSCode URI对象 return vscode.Uri.file(filepath); } } + /** + * 判断当前环境是否为 Windows 本地环境且非远程环境。 + * + * @returns 返回一个布尔值,表示当前环境是否为 Windows 本地环境且非远程环境。 + */ isWindowsLocalButNotRemote(): boolean { return ( vscode.env.remoteName !== undefined && @@ -120,6 +196,11 @@ export class VSCodeAction implements IdeAction { ); } + /** + * 获取路径分隔符 + * + * @returns 如果当前环境是本地Windows环境但不是远程Windows环境,返回 "/";否则返回 path.sep + */ getPathSep(): string { return this.isWindowsLocalButNotRemote() ? "/" : path.sep; } @@ -133,10 +214,22 @@ export class VSCodeAction implements IdeAction { return posixPath; } + /** + * 获取指定目录下的分支信息 + * + * @param dir 指定的目录路径 + * @returns 返回分支信息的字符串 + */ async getBranch(dir: string): Promise { return this.getBranchForUri(vscode.Uri.file(dir)); } + /** + * 根据目录URI获取分支名 + * + * @param forDirectory 目录URI + * @returns 分支名,如果获取失败则返回"NONE" + */ async getBranchForUri(forDirectory: vscode.Uri) { let repo = await this.git.getRepo(forDirectory); if (repo?.state?.HEAD?.name === undefined) { @@ -153,32 +246,65 @@ export class VSCodeAction implements IdeAction { return repo?.state?.HEAD?.name || "NONE"; } + /** + * 获取指定目录下所有文件的最后修改时间 + * + * @param directory 目录路径 + * @returns 返回文件路径到最后修改时间的映射对象 + */ async getStats(directory: string): Promise<{ [path: string]: number }> { + // 获取工作区第一个文件夹的 URI scheme const scheme = vscode.workspace.workspaceFolders?.[0].uri.scheme; + + // 列出目录中的文件列表 const files = await this.listWorkspaceContents(directory); + + // 创建一个对象,用于存储每个文件的最后修改时间 const pathToLastModified: { [path: string]: number } = {}; + await Promise.all( files.map(async (file) => { + // 获取文件的统计信息 let stat = await vscode.workspace.fs.stat(this.uriFromFilePath(file)); + // 将文件路径和最后修改时间存入对象中 pathToLastModified[file] = stat.mtime; }), ); + // 返回包含文件最后修改时间的对象 return pathToLastModified; } + /** + * 列出工作区的内容 + * + * @param directory 目录路径,可选 + * @returns 返回工作区内容的文件路径数组 + */ async listWorkspaceContents(directory?: string): Promise { + // 如果提供了目录参数 if (directory) { + // 调用获取目录内容的函数,并返回结果 return await this.getDirectoryContents(directory, true); } else { + // 获取工作区所有目录 const contents = await Promise.all( this.getWorkspaceDirectories() + // 对每个目录调用获取目录内容的函数,并返回结果的数组 .map((dir) => this.getDirectoryContents(dir, true)), ); + // 将所有目录的内容合并成一个数组并返回 return contents.flat(); } } + /** + * 异步获取目录内容 + * + * @param directory 目录路径 + * @param recursive 是否递归搜索子目录 + * @returns 目录内容(文件路径数组) + */ async getDirectoryContents( directory: string, recursive: boolean, @@ -213,6 +339,12 @@ export class VSCodeAction implements IdeAction { return allFiles; } + /** + * 获取仓库名称 + * + * @param dir 仓库目录 + * @returns 仓库名称,若无法获取则返回 undefined + */ getRepoName(dir: string): Promise { return this.git.getRepoName(vscode.Uri.file(dir)); } diff --git a/src/editor/webview/AutoDevWebviewViewProvider.ts b/src/editor/webview/AutoDevWebviewViewProvider.ts index 5c1fff8f..9c8e105b 100644 --- a/src/editor/webview/AutoDevWebviewViewProvider.ts +++ b/src/editor/webview/AutoDevWebviewViewProvider.ts @@ -10,16 +10,35 @@ export class AutoDevWebviewViewProvider implements vscode.WebviewViewProvider { public webviewProtocol!: AutoDevWebviewProtocol; + /** + * 构造函数 + * + * @param _context vscode扩展上下文 + * @param windowId 窗口ID,默认为空字符串 + */ constructor( private readonly _context: vscode.ExtensionContext, private readonly windowId: string = "" ) {} + /** + * 获取 webview 对象 + * + * @returns 返回 webview 对象 + */ get webview() { return this._webview; } public static readonly viewType = "autodev.autodevGUIView"; + /** + * 解析Webview视图 + * + * @param webviewView Webview视图对象 + * @param _context Webview视图解析上下文 + * @param _token 取消令牌 + * @returns 无返回值 + */ async resolveWebviewView( webviewView: vscode.WebviewView, _context: vscode.WebviewViewResolveContext, @@ -36,6 +55,16 @@ export class AutoDevWebviewViewProvider implements vscode.WebviewViewProvider { ); } + /** + * 获取侧边栏内容的 HTML 字符串 + * + * @param context VSCode 扩展上下文 + * @param panel WebviewPanel 或 WebviewView 对象 + * @param page 页面名称,默认为 undefined + * @param edits 编辑操作,默认为 undefined + * @param isFullScreen 是否全屏显示,默认为 false + * @returns 侧边栏内容的 HTML 字符串 + */ async getSidebarContent( context: vscode.ExtensionContext | undefined, panel: vscode.WebviewPanel | vscode.WebviewView, diff --git a/src/extension.ts b/src/extension.ts index 19222b90..9acd32d0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -26,49 +26,92 @@ import { LocalEmbeddingProvider } from "./code-search/embedding/LocalEmbeddingPr (globalThis as any).self = globalThis; +/** + * 激活插件函数 + * + * @param context 插件上下文 + * @returns 无返回值 + */ export async function activate(context: vscode.ExtensionContext) { + // 设置扩展上下文 setExtensionContext(context); + + // 创建侧边栏视图提供者 const sidebar = new AutoDevWebviewViewProvider(context); + + // 创建 VSCode 动作对象 const action = new VSCodeAction(); + // 创建最近文档管理器 const documentManager = new RecentlyDocumentManager(); + + // 创建差异管理器 const diffManager = new DiffManager(); + // 创建 AutoDev 扩展对象 const extension = new AutoDevExtension( sidebar, action, documentManager, diffManager, context, ); + // 初始化解析器 Parser.init().then(async () => { + // 注册代码透镜提供者 registerCodeLensProviders(extension); + + // 注册 AutoDev 提供者 registerAutoDevProviders(extension); + + // 注册快速修复提供者 registerQuickFixProvider(extension); + + // 注册命令 registerCommands(extension); + // 如果设置服务中启用了重命名功能 if (SettingService.instance().isEnableRename()) { + // 注册重命名动作 registerRenameAction(extension); } + + // 当配置发生更改时 vscode.workspace.onDidChangeConfiguration(() => { if (SettingService.instance().isEnableRename()) { + // 如果启用了重命名功能,则注册重命名动作(待优化) // todo: make it works better registerRenameAction(extension); } else { + // 否则不做任何操作 } }); + // 获取 TreeSitter 文件管理器实例 TreeSitterFileManager.getInstance(); + + // 启动构建工具观察者 await new BuildToolObserver().startWatch(); + // 初始化本地嵌入提供者 LocalEmbeddingProvider.getInstance().init(context.extensionPath); }); + // 注册 WebView 视图提供者 registerWebViewProvider(extension); + + // 绑定文档更改事件 documentManager.bindChanges(); + // 创建 AutoDev 状态管理器实例 AutoDevStatusManager.instance.create(); + // 显示通道 channel.show(); } +/** + * 停用扩展上下文 + * + * 该函数用于移除扩展上下文 + */ export function deactivate() { removeExtensionContext(); }