diff --git a/tools/rst-optimizer/src/config.ts b/tools/rst-optimizer/src/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4d79a030ee4388207b36437e1c6c3284ec40f33 --- /dev/null +++ b/tools/rst-optimizer/src/config.ts @@ -0,0 +1,65 @@ +import * as vscode from 'vscode'; +import { OptimizationConfig } from './types'; + +export class ConfigManager { + private static readonly CONFIG_SECTION = 'rstOptimizer'; + + static getConfig(): OptimizationConfig { + const config = vscode.workspace.getConfiguration(this.CONFIG_SECTION); + + // 优先从环境变量读取 API Key + const apiKey = process.env.RST_OPTIMIZER_API_KEY || config.get('api.apiKey', ''); + + return { + provider: config.get('api.provider', 'openai-compatible'), + baseUrl: config.get('api.baseUrl', 'https://api.openai.com/v1'), + model: config.get('api.model', 'gpt-4o-mini'), + apiKey, + userPrompt: config.get('prompt.userPrompt',"你是一名 **RST 技术文档审校与修复专家**。\n你的任务是:在**不改变技术语义**的前提下,**严格检查并修复**给定 RST 文档在语法、结构、格式与中文排版上的问题,并**保持与 API 定义及文件名的一致性**。\n如无明确要求,**不要引入新的内容段落或编造默认值/异常**;仅在缺漏“必须存在且可从上下文直接确定”的字段时做最小增补。\n\n## 输入\n\n* 文件名:${fileName}\n* 原始 RST 文本(保持原样)\n\n## 总体原则\n\n1. **最小侵入修复**:仅修复错误或不规范之处;保留原有信息结构与术语。\n2. **禁止误改代码/公式**:`code-block`、`literalinclude`、`math` 等指令体及反引号行内代码的技术内容不得改写(仅可做空格与围栏修复)。\n3. **一致性优先**:文件名、章节标题、API 名称必须一致(见规则 2)。\n4. **中文排版**:面向中文读者的正文需优化中文标点与用语,但不得改变技术意义。\n5. **不可臆测**:若无默认值/异常/类型信息,不得凭空添加。无法确定时保持空或原状,并在总结里标注“需要人工确认”。\n\n## 必查必修规则(逐条执行)\n\n### 1)通用 RST 语法与特殊标记\n\n* 检查并修复常见指令语法:`.. note::`、`.. warning::`、`.. seealso::`、`.. include::`、`.. math::` 等的缩进与空行:\n * 指令与其内容之间需空一行(除确有嵌套要求的场景外)。\n * 指令体内容相对指令行统一缩进(建议 3–4 空格),全文保持一致。\n* 行内特殊标记规则:\n * `*斜体*`、`**加粗**`、``行内代码``:标记内部不得出现空格(确需空格时改为转义或拆分)。\n * 标记与上下文:标记前后各保留 1 个空格(句首或紧邻标点处除外)。\n* 修复多余反引号、未闭合标记、错误嵌套。\n\n### 2)文件名 / 章节标题 / API 定义名一致性\n\n* 要求:文件名、文档首个最高层级标题、正文首个 API 定义名应一致。\n* 例外:若文件名匹配 `mindspore.xxx.func_yyy.rst`,则章节标题与 API 定义名统一为 `mindspore.xxx.yyy`(去掉 `func_`)。\n* 实施:\n * 若三者不一致,以 API 定义名为准统一章节标题;遇到上述例外时按例外规则处理。\n * 若文件名与 API 命名空间明显冲突(如包路径不同),不改文件名,仅统一标题与文内 API 显示。\n\n### 3)“参数/关键字参数”模块格式(**包含关键字专用参数的严格规则**)\n\n* 目标格式(逐项以无序列表 `-` 起):\n\n```\n参数:\n- **参数名** (数据类型[, 可选]) – 参数说明。默认值:`None`,表示……\n 关键字参数:\n- **参数名** (数据类型[, 可选]) – 参数说明。默认值:`None`,表示……\n```\n\n* 严格对齐 Python 函数签名的五类参数并分流到正确模块:\n\n1) **仅位置参数(positional-only)**:位于 `/` 左侧(若签名包含 `/`)。归入“参数”模块,**不要展示 `/` 本身**。\n2) **位置或关键字参数(positional-or-keyword)**:常见的 `name` 或 `name=...`。归入“参数”模块。\n3) **可变位置参数**:`*args`。归入“参数”模块,名称保留星号前缀 `*`,类型与说明按项目规范书写。\n4) **关键字专用参数(keyword-only)**:当签名中出现 **裸 `*` 分隔符** 或 `*args` 之后的形参(直到 `**kwargs` 之前)。**这些形参必须归入“关键字参数”模块**。\n - 裸 `*` 仅是分隔符,**不出现在文档中**;其右侧的参数(如 `dtype=None`)统一移至“关键字参数”。\n5) **可变关键字参数**:`**kwargs`。根据项目约定决定是否在“关键字参数”模块列出;若列出需保留 `**` 前缀并简要说明用途,避免臆测具体键。\n\n* “参数/关键字参数”的**名称与顺序必须与函数定义完全一致**(先左后右、从签名原序列化得到)。\n* “可选/默认值”标注规则:\n* 形参**有默认值**(含 `=None`)或注解为可选类型时:在类型后补 `, 可选`,且在说明末尾追加“默认值:````,……”。\n* 形参**无默认值**:不写“可选”,不写默认值句。\n* **数据类型**需与定义一致;若原文缺失且上下文也无法确定,不要臆测,类型可暂缺省或保持原状。\n* 术语与标点:\n* 中文破折号统一使用 `–`(en dash),全文保持一致。\n* 默认值文字中的字面量使用行内代码围栏(如 ``None``、``True``、``-1``)。\n* **迁移示例(与你给的 case 对齐)**:签名 `(..., dim=None, *, dtype=None)` →\n `dim` 仍在“参数”;`dtype` 作为 **关键字专用参数** 移至“关键字参数”。\n\n### 4)“异常”模块格式\n\n* 目标格式:\n\n```\n异常:\n- **ErrorType** - 异常描述。\n```\n\n* 同类异常归并在一起,子类在前、父类在后;不得杜撰异常,无法确认时保留原状并在总结中标注需确认。\n\n### 5)“输入/输出”模块格式\n\n* 目标格式:\n\n```\n输入:\n- **输入名** (数据类型) – 描述。\n 输出:\n- **输出名** (数据类型) – 描述。\n```\n\n* 无序列表 `-`,加粗名称 + 圆括号数据类型 + `–` 描述。\n\n### 6)换行与缩进\n\n* 普通段落换行不缩进。\n* 有序/无序列表换行统一 2 个空格缩进,与上一行正文起始位置对齐。\n* 指令体(note/warning/seealso/include/math 等)内层统一缩进;子块(如代码)再按 RST 规范缩进一级。\n\n### 7)模块间空行\n\n* 各模块之间至少 1 个空行;指令与其前后段落之间保留空行,避免黏连。\n\n### 8)中文文本与排版\n\n* 修复错别字、冗余空格、英文标点混用(中文语句中使用中文标点:`,` `。` `:` `;` `( )`)。\n* 并列关系用顿号 `、` 分隔。\n* API 名、类名、参数名、代码标识符保留原文并用行内代码``包裹。\n* 句子更通顺简洁,但不得改变技术含义。\n\n## 额外一致性检查\n\n* 标题层级符号(`= - ~ ^ \" ' *` 等)长度需与标题文本长度一致;同级标题符号统一。\n* `:param:/:type:/:return:/:rtype:` 若与目标“列表式参数节”并存,应二选一统一为项目约定风格(通常统一为“参数/关键字参数”块)。\n* 交叉引用(`:class:`, `:func:`, `:mod:` 等)语法修复:角色名、目标、反引号与空格。\n* `include` 路径前后空格与相对路径的一致性。\n\n## 输出要求\n\n* 输出修复后的完整 RST 正文(不加多余说明或包裹)。\n* 如需 diff 模式,由外层系统控制;本指令默认仅产出修复后全文。\n\n## 审核自查清单(模型内部执行,无需输出)\n\n* [ ] 指令语法/缩进/空行正确\n* [ ] 行内标记无空格、边界空格正确\n* [ ] 文件名/标题/API 名一致(含 `func_` 例外)\n* [ ] 参数/关键字参数:顺序与分流严格按签名(含 `/`、裸 `*`、`*args`、`**kwargs`)\n* [ ] “可选/默认值”标注与默认值文字格式正确\n* [ ] 异常:格式统一、同类聚合、无臆测\n* [ ] 输入/输出:列表格式统一\n* [ ] 列表缩进 2 空格,段落不缩进\n* [ ] 模块间有空行(例如返回是一个模块,异常是一个模块,他们之间有空行,但是异常下面的具体异常和异常大标题之间无空行)\n* [ ] 中文标点与顿号、错别字修复\n* [ ] 代码/公式内容未被改写(仅围栏/空格修复)"), + maxTokens: config.get('generation.maxTokens', 4096), + temperature: config.get('generation.temperature', 0.3), + neverUploadIfWorkspaceTrusted: config.get('safety.neverUploadIfWorkspaceTrusted', false), + rewrapWidth: config.get('format.rewrapWidth', 0) + }; + } + + static validateConfig(config: OptimizationConfig): string[] { + const errors: string[] = []; + + if (!config.baseUrl) { + errors.push('API 基础 URL 不能为空'); + } + + if (!config.model) { + errors.push('模型名称不能为空'); + } + + if (!config.apiKey) { + errors.push('API 密钥不能为空,请在设置中配置或设置环境变量 RST_OPTIMIZER_API_KEY'); + } + + if (config.maxTokens <= 0) { + errors.push('最大 token 数量必须大于 0'); + } + + if (config.temperature < 0 || config.temperature > 2) { + errors.push('温度值必须在 0-2 之间'); + } + + return errors; + } + + static checkWorkspaceSafety(): boolean { + const workspaceTrust = vscode.workspace.isTrusted; + const config = this.getConfig(); + + if (config.neverUploadIfWorkspaceTrusted && workspaceTrust) { + vscode.window.showWarningMessage( + '安全设置阻止了在受信任工作区中上传内容到外部 API。请在设置中关闭 "neverUploadIfWorkspaceTrusted" 选项。' + ); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/tools/rst-optimizer/src/diff/diffActionCodeLensProvider.ts b/tools/rst-optimizer/src/diff/diffActionCodeLensProvider.ts new file mode 100644 index 0000000000000000000000000000000000000000..0021d9b60e5f5be6f7c22eef406d218d08a52784 --- /dev/null +++ b/tools/rst-optimizer/src/diff/diffActionCodeLensProvider.ts @@ -0,0 +1,37 @@ +import * as vscode from 'vscode'; +import { VirtualDocProvider } from './virtualDocProvider'; + + +export class DiffActionCodeLensProvider implements vscode.CodeLensProvider { + private onDidChangeCodeLensesEmitter = new vscode.EventEmitter(); + public readonly onDidChangeCodeLenses: vscode.Event = this.onDidChangeCodeLensesEmitter.event; + + provideCodeLenses(document: vscode.TextDocument): vscode.ProviderResult { + if (document.uri.scheme !== VirtualDocProvider.getScheme()) { + return []; + } + if (!document.uri.path.startsWith('/optimized/')) { + return []; + } + + const lastLine = Math.max(0, document.lineCount - 1); + const range = new vscode.Range(lastLine, 0, lastLine, 0); + + const applyLens = new vscode.CodeLens(range, { + title: '$(check) 应用优化', + command: 'rstOptimizer.applyResult' + }); + + const discardLens = new vscode.CodeLens(range, { + title: '$(x) 放弃优化', + command: 'rstOptimizer.discardResult' + }); + + return [applyLens, discardLens]; + } + + refresh(): void { + this.onDidChangeCodeLensesEmitter.fire(); + } +} + diff --git a/tools/rst-optimizer/src/diff/virtualDocProvider.ts b/tools/rst-optimizer/src/diff/virtualDocProvider.ts new file mode 100644 index 0000000000000000000000000000000000000000..8fe3859564948ada1ce4081cecc6b9a148b4c026 --- /dev/null +++ b/tools/rst-optimizer/src/diff/virtualDocProvider.ts @@ -0,0 +1,42 @@ +import * as vscode from 'vscode'; + +export class VirtualDocProvider implements vscode.TextDocumentContentProvider { + private static readonly scheme = 'rstopt'; + private contentMap = new Map(); + private _onDidChange = new vscode.EventEmitter(); + + readonly onDidChange = this._onDidChange.event; + + static createUri(type: 'original' | 'optimized', filePath: string): vscode.Uri { + const timestamp = Date.now(); + return vscode.Uri.parse(`${VirtualDocProvider.scheme}:${type}/${encodeURIComponent(filePath)}?t=${timestamp}`); + } + + provideTextDocumentContent(uri: vscode.Uri): string | undefined { + const key = this.getKeyFromUri(uri); + return this.contentMap.get(key); + } + + set(uri: vscode.Uri, content: string): void { + const key = this.getKeyFromUri(uri); + this.contentMap.set(key, content); + this._onDidChange.fire(uri); + } + + clear(uri: vscode.Uri): void { + const key = this.getKeyFromUri(uri); + this.contentMap.delete(key); + } + + clearAll(): void { + this.contentMap.clear(); + } + + private getKeyFromUri(uri: vscode.Uri): string { + return `${uri.path}${uri.query}`; + } + + static getScheme(): string { + return VirtualDocProvider.scheme; + } +} \ No newline at end of file diff --git a/tools/rst-optimizer/src/extension.ts b/tools/rst-optimizer/src/extension.ts new file mode 100644 index 0000000000000000000000000000000000000000..1e71f29b7cdc39c02b74d1afea470823847659a9 --- /dev/null +++ b/tools/rst-optimizer/src/extension.ts @@ -0,0 +1,452 @@ +import * as vscode from 'vscode'; +import { ConfigManager } from './config'; +import { LLMClient } from './llm/client'; +import { VirtualDocProvider } from './diff/virtualDocProvider'; +import { DiffActionCodeLensProvider } from './diff/diffActionCodeLensProvider'; +import { BatchResultsViewProvider } from './views/batchResultsView'; +import type { BatchResultItem } from './views/batchResultsHtml'; +import { FileUtils } from './utils/file'; +import { TextWrapper } from './utils/wrap'; +import { DiffContext } from './types'; +import { HistoryStore } from './history'; + +let outputChannel: vscode.OutputChannel; +let llmClient: LLMClient; +let virtualDocProvider: VirtualDocProvider; +let statusBarItem: vscode.StatusBarItem; +let currentDiffContext: DiffContext | undefined; +let batchResultsViewProvider: BatchResultsViewProvider; + +export function activate(context: vscode.ExtensionContext) { + outputChannel = vscode.window.createOutputChannel('RST Optimizer'); + context.subscriptions.push(outputChannel); + + llmClient = new LLMClient(outputChannel); + + HistoryStore.init(context); + + virtualDocProvider = new VirtualDocProvider(); + context.subscriptions.push( + vscode.workspace.registerTextDocumentContentProvider( + VirtualDocProvider.getScheme(), + virtualDocProvider + ) + ); + + const codeLensProvider = new DiffActionCodeLensProvider(); + context.subscriptions.push( + vscode.languages.registerCodeLensProvider( + { scheme: VirtualDocProvider.getScheme() }, + codeLensProvider + ) + ); + + batchResultsViewProvider = new BatchResultsViewProvider({ + onApplyAll: async (results) => applyAllBatchResults(results), + onApplySelected: async (results, selected) => applySelectedBatchResults(results, selected), + onViewDiffById: async (id) => { + const r = HistoryStore.getById(id); + if (r) { + await showDiffView(r.filePath, r.originalText, r.optimizedText); + } + }, + onDiscard: async () => {/* no-op, close action handled by view */} + }); + context.subscriptions.push( + vscode.window.registerWebviewViewProvider(BatchResultsViewProvider.ViewId, batchResultsViewProvider) + ); + // 命令:确保可以显式聚焦视图 + context.subscriptions.push( + vscode.commands.registerCommand('rstOptimizer.revealBatchResultsView', () => batchResultsViewProvider.reveal()) + ); + + // 创建状态栏项 + statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); + statusBarItem.text = '$(edit) RST Optimizer'; + statusBarItem.tooltip = '点击打开 RST Optimizer 命令'; + statusBarItem.command = 'rstOptimizer.showQuickPick'; + statusBarItem.show(); + context.subscriptions.push(statusBarItem); + + // 注册命令 + const commands = [ + vscode.commands.registerCommand('rstOptimizer.optimizeCurrent', optimizeCurrentFile), + vscode.commands.registerCommand('rstOptimizer.optimizePickFile', optimizePickedFile), + vscode.commands.registerCommand('rstOptimizer.applyResult', applyOptimizedResult), + vscode.commands.registerCommand('rstOptimizer.discardResult', discardOptimizedResult), + vscode.commands.registerCommand('rstOptimizer.openSettings', openSettings), + vscode.commands.registerCommand('rstOptimizer.showQuickPick', showQuickPick) + ]; + + context.subscriptions.push(...commands); + + outputChannel.appendLine('RST Optimizer 扩展已激活'); +} + +export function deactivate() { + if (virtualDocProvider) { + virtualDocProvider.clearAll(); + } + outputChannel?.appendLine('RST Optimizer 扩展已停用'); +} + +async function optimizeCurrentFile() { + const filePath = FileUtils.getCurrentRstFile(); + if (!filePath) { + vscode.window.showWarningMessage('当前编辑器不是 RST 文件,请打开一个 .rst 文件'); + return; + } + + await optimizeFile(filePath); +} + +async function optimizePickedFile() { + const filePaths = await FileUtils.pickRstFiles(); + if (filePaths.length === 0) { + return; // 用户取消了选择 + } + + // 打开选中的文件 + for (const filePath of filePaths) { + const document = await vscode.workspace.openTextDocument(filePath); + await vscode.window.showTextDocument(document, { preview: false }); + } + + if (filePaths.length === 1) { + // 单文件优化 + await optimizeFile(filePaths[0]); + } else { + // 批量优化 + await optimizeMultipleFiles(filePaths); + } +} + +async function optimizeMultipleFiles(filePaths: string[]) { + try { + // 检查工作区安全设置 + if (!ConfigManager.checkWorkspaceSafety()) { + return; + } + + // 获取配置 + const config = ConfigManager.getConfig(); + const configErrors = ConfigManager.validateConfig(config); + if (configErrors.length > 0) { + vscode.window.showErrorMessage(`配置错误:${configErrors.join(', ')}`); + return; + } + + const results: { filePath: string; originalText: string; optimizedText: string }[] = []; + + // 显示总体进度 + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: `正在批量优化 ${filePaths.length} 个 RST 文件...`, + cancellable: true + }, + async (progress, token) => { + for (let i = 0; i < filePaths.length; i++) { + const filePath = filePaths[i]; + const fileName = FileUtils.getFileName(filePath); + + if (token.isCancellationRequested) { + break; + } + + progress.report({ + message: `正在优化 ${fileName} (${i + 1}/${filePaths.length})`, + increment: (100 / filePaths.length) + }); + + try { + const originalText = await FileUtils.readFile(filePath); + if (!originalText.trim()) { + outputChannel.appendLine(`跳过空文件: ${filePath}`); + continue; + } + + const dotIdx = fileName.lastIndexOf('.'); + const fileBaseName = dotIdx > 0 ? fileName.slice(0, dotIdx) : fileName; + const fileExt = dotIdx > -1 ? fileName.slice(dotIdx + 1) : ''; + const optimizedText = await llmClient.optimizeRst( + { + text: originalText, + userPrompt: config.userPrompt, + config, + variables: { + filePath, + fileName, + relativePath: FileUtils.getRelativePath(filePath), + fileBaseName, + fileExt + } + }, + token + ); + + const finalOptimizedText = config.rewrapWidth > 0 + ? TextWrapper.wrapText(optimizedText, config.rewrapWidth) + : optimizedText; + + results.push({ + filePath, + originalText, + optimizedText: finalOptimizedText + }); + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + outputChannel.appendLine(`优化失败 ${filePath}: ${errorMessage}`); + vscode.window.showWarningMessage(`优化 ${fileName} 失败: ${errorMessage}`); + } + } + } + ); + + if (results.length > 0) { + await showBatchOptimizationResults(results); + } else { + vscode.window.showWarningMessage('没有成功优化任何文件'); + } + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`批量优化失败: ${errorMessage}`); + outputChannel.appendLine(`批量优化失败: ${errorMessage}`); + } +} + +async function optimizeFile(filePath: string) { + try { + // 检查工作区安全设置 + if (!ConfigManager.checkWorkspaceSafety()) { + return; + } + + // 获取配置 + const config = ConfigManager.getConfig(); + const configErrors = ConfigManager.validateConfig(config); + if (configErrors.length > 0) { + vscode.window.showErrorMessage(`配置错误:${configErrors.join(', ')}`); + return; + } + + // 读取文件内容 + const originalText = await FileUtils.readFile(filePath); + if (!originalText.trim()) { + vscode.window.showWarningMessage('文件内容为空'); + return; + } + + // 显示进度并执行优化 + const optimizedText = await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: `正在使用 ${config.provider}/${config.model} 优化 RST 文档...`, + cancellable: true + }, + async (progress, token) => { + const fileName = FileUtils.getFileName(filePath); + const relativePath = FileUtils.getRelativePath(filePath); + const dotIdx = fileName.lastIndexOf('.'); + const fileBaseName = dotIdx > 0 ? fileName.slice(0, dotIdx) : fileName; + const fileExt = dotIdx > -1 ? fileName.slice(dotIdx + 1) : ''; + return await llmClient.optimizeRst( + { + text: originalText, + userPrompt: config.userPrompt, + config, + variables: { filePath, fileName, relativePath, fileBaseName, fileExt } + }, + token + ); + } + ); + + // 应用文本包装(如果配置了) + const finalOptimizedText = config.rewrapWidth > 0 + ? TextWrapper.wrapText(optimizedText, config.rewrapWidth) + : optimizedText; + + // 创建 diff 视图 + await showDiffView(filePath, originalText, finalOptimizedText); + + // 记录到历史并刷新侧边栏 + await batchResultsViewProvider.showResults([{ filePath, originalText, optimizedText: finalOptimizedText }]); + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`优化失败: ${errorMessage}`); + outputChannel.appendLine(`优化失败: ${errorMessage}`); + } +} + +async function showDiffView(filePath: string, originalText: string, optimizedText: string) { + // 创建虚拟 URI + const originalUri = VirtualDocProvider.createUri('original', filePath); + const optimizedUri = VirtualDocProvider.createUri('optimized', filePath); + + // 设置虚拟文档内容 + virtualDocProvider.set(originalUri, originalText); + virtualDocProvider.set(optimizedUri, optimizedText); + + // 保存当前 diff 上下文 + currentDiffContext = { + originalUri, + optimizedUri, + filePath, + optimizedContent: optimizedText + }; + + // 打开 diff 视图 + const fileName = FileUtils.getFileName(filePath); + const title = `RST Diff: ${fileName}`; + + await vscode.commands.executeCommand( + 'vscode.diff', + originalUri, + optimizedUri, + title, + { preview: false } + ); + + // 设置上下文,确保菜单按钮在 diff 标题栏显示 + await vscode.commands.executeCommand('setContext', 'rstOptimizer.hasActiveDiff', true); +} + +async function showBatchOptimizationResults(results: { filePath: string; originalText: string; optimizedText: string }[]) { + await batchResultsViewProvider.showResults(results); +} + + +async function applyOptimizedResult() { + if (!currentDiffContext) { + vscode.window.showWarningMessage('没有可应用的优化结果'); + return; + } + + try { + await FileUtils.writeFile(currentDiffContext.filePath, currentDiffContext.optimizedContent); + + const fileName = FileUtils.getFileName(currentDiffContext.filePath); + vscode.window.showInformationMessage(`已成功应用优化结果到 ${fileName}`); + + outputChannel.appendLine(`[${new Date().toISOString()}] 已应用优化结果: ${currentDiffContext.filePath}`); + + // 清理 + await discardChanges(); + + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`应用更改失败: ${errorMessage}`); + } +} + +async function discardOptimizedResult() { + if (!currentDiffContext) { + vscode.window.showWarningMessage('没有可放弃的优化结果'); + return; + } + + const fileName = FileUtils.getFileName(currentDiffContext.filePath); + vscode.window.showInformationMessage(`已放弃对 ${fileName} 的优化结果`); + + outputChannel.appendLine(`[${new Date().toISOString()}] 已放弃优化结果: ${currentDiffContext.filePath}`); + + // 清理 + await discardChanges(); +} + +async function discardChanges() { + if (currentDiffContext) { + // 清理虚拟文档 + virtualDocProvider.clear(currentDiffContext.originalUri); + virtualDocProvider.clear(currentDiffContext.optimizedUri); + currentDiffContext = undefined; + } + // 清理上下文 + await vscode.commands.executeCommand('setContext', 'rstOptimizer.hasActiveDiff', false); +} + +async function applyAllBatchResults(results: { filePath: string; originalText: string; optimizedText: string }[]) { + let successCount = 0; + let failCount = 0; + + for (const result of results) { + try { + await FileUtils.writeFile(result.filePath, result.optimizedText); + successCount++; + outputChannel.appendLine(`[${new Date().toISOString()}] 已应用优化结果: ${result.filePath}`); + } catch (error) { + failCount++; + const errorMessage = error instanceof Error ? error.message : String(error); + outputChannel.appendLine(`[${new Date().toISOString()}] 应用失败: ${result.filePath} - ${errorMessage}`); + } + } + + vscode.window.showInformationMessage( + `批量应用完成!成功: ${successCount} 个,失败: ${failCount} 个` + ); +} + +async function applySelectedBatchResults( + results: { filePath: string; originalText: string; optimizedText: string }[], + selectedFiles: string[] +) { + let successCount = 0; + let failCount = 0; + + for (const filePath of selectedFiles) { + const result = results.find(r => r.filePath === filePath); + if (!result) continue; + + try { + await FileUtils.writeFile(result.filePath, result.optimizedText); + successCount++; + outputChannel.appendLine(`[${new Date().toISOString()}] 已应用优化结果: ${result.filePath}`); + } catch (error) { + failCount++; + const errorMessage = error instanceof Error ? error.message : String(error); + outputChannel.appendLine(`[${new Date().toISOString()}] 应用失败: ${result.filePath} - ${errorMessage}`); + } + } + + vscode.window.showInformationMessage( + `选择性应用完成!成功: ${successCount} 个,失败: ${failCount} 个` + ); +} + +// batch 结果的 HTML 已移动到 src/views/batchResultsHtml.ts + +async function openSettings() { + await vscode.commands.executeCommand('workbench.action.openSettings', 'rstOptimizer'); +} + +async function showQuickPick() { + const items = [ + { + label: '$(file-text) 优化当前 RST 文件', + description: '优化当前活动编辑器中的 RST 文件', + command: 'rstOptimizer.optimizeCurrent' + }, + { + label: '$(folder-opened) 选择 RST 文件优化', + description: '通过文件选择器选择要优化的 RST 文件', + command: 'rstOptimizer.optimizePickFile' + }, + { + label: '$(settings-gear) 打开设置', + description: '配置 RST Optimizer 设置', + command: 'rstOptimizer.openSettings' + } + ]; + + const selected = await vscode.window.showQuickPick(items, { + placeHolder: '选择要执行的操作' + }); + + if (selected) { + await vscode.commands.executeCommand(selected.command); + } +} diff --git a/tools/rst-optimizer/src/history.ts b/tools/rst-optimizer/src/history.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b007aae98006caa270cdd3d02bad7d890b3c4ba --- /dev/null +++ b/tools/rst-optimizer/src/history.ts @@ -0,0 +1,58 @@ +import * as vscode from 'vscode'; +import type { BatchResultItem } from './views/batchResultsHtml'; + + +export class HistoryStore { + private static context: vscode.ExtensionContext | undefined; + private static readonly KEY = 'rstOptimizer.history'; + + static init(context: vscode.ExtensionContext) { + this.context = context; + } + + private static ensureReady() { + if (!this.context) { + throw new Error('HistoryStore not initialized'); + } + } + + static getAll(): BatchResultItem[] { + this.ensureReady(); + const items = this.context!.globalState.get(this.KEY, []); + return Array.isArray(items) ? items.slice().sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0)) : []; + } + + static addMany(items: Omit[]): BatchResultItem[] { + this.ensureReady(); + const existing = this.getAll(); + const now = Date.now(); + const withIds: BatchResultItem[] = items.map((it, idx) => ({ + ...it, + id: `${now}-${idx}-${Math.random().toString(36).slice(2, 8)}`, + timestamp: now + idx, + })); + const next = [...withIds, ...existing]; + this.context!.globalState.update(this.KEY, next); + return withIds; + } + + static addOne(item: Omit): BatchResultItem { + return this.addMany([item])[0]; + } + + static removeById(id: string): void { + this.ensureReady(); + const next = this.getAll().filter(it => it.id !== id); + this.context!.globalState.update(this.KEY, next); + } + + static getById(id: string): BatchResultItem | undefined { + return this.getAll().find(it => it.id === id); + } + + static clearAll(): void { + this.ensureReady(); + this.context!.globalState.update(this.KEY, []); + } +} + diff --git a/tools/rst-optimizer/src/llm/client.ts b/tools/rst-optimizer/src/llm/client.ts new file mode 100644 index 0000000000000000000000000000000000000000..7985b498aae9aace355ee7194a8574d5b968fcd1 --- /dev/null +++ b/tools/rst-optimizer/src/llm/client.ts @@ -0,0 +1,117 @@ +import * as vscode from 'vscode'; +import { OptimizationRequest, LLMResponse } from '../types'; + +const DEFAULT_SYSTEM_PROMPT = `你是 reStructuredText(RST)与 Sphinx 文档优化专家。目标:在不破坏语义与构建的前提下,让文档更清晰专业。 +严格遵循: +1) 保留并尊重所有 Sphinx 角色/指令/域(如 :ref:、:class:、:func:、.. code-block::、.. note::、.. figure:: 等),不要更改其语法结构与缩进。 +2) 绝不删除或更改链接目标、交叉引用锚点(如 .. _anchor:)。 +3) 保留代码块、控制台示例与行内字面值(\`\`literal\`\`)原样;除非是修复明显拼写错误。 +4) 标题层级与下划线风格统一(如 # * = - ^ ~ 等),但不得改变层级关系。 +5) 修复语法/拼写/术语一致性,使段落更简洁、技术准确;尽量减少被动语态。 +6) 表格、列表、缩进必须合法;指令体的缩进四空格对齐。 +7) 输出**完整优化后的整篇 RST**,不要输出 diff 或注释。`; + +export class LLMClient { + private outputChannel: vscode.OutputChannel; + + constructor(outputChannel: vscode.OutputChannel) { + this.outputChannel = outputChannel; + } + + async optimizeRst( + request: OptimizationRequest, + cancellationToken?: vscode.CancellationToken + ): Promise { + const startTime = Date.now(); + const { text, userPrompt, config } = request; + + this.outputChannel.appendLine(`[${new Date().toISOString()}] 开始优化 RST 文档`); + this.outputChannel.appendLine(`提供商: ${config.provider}`); + this.outputChannel.appendLine(`模型: ${config.model}`); + this.outputChannel.appendLine(`文档长度: ${text.length} 字符`); + this.outputChannel.appendLine(`估算 token: ${Math.ceil(text.length / 4)}`); + + try { + const userContent = this.composeUserContent(text, userPrompt, request.variables); + + const requestBody = { + model: config.model, + temperature: config.temperature, + max_tokens: config.maxTokens, + messages: [ + { role: "system", content: DEFAULT_SYSTEM_PROMPT }, + { role: "user", content: userContent } + ] + }; + + const controller = new AbortController(); + + // 处理取消令牌 + if (cancellationToken) { + cancellationToken.onCancellationRequested(() => { + controller.abort(); + this.outputChannel.appendLine(`[${new Date().toISOString()}] 请求被用户取消`); + }); + } + + const response = await fetch(`${config.baseUrl}/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${config.apiKey}` + }, + body: JSON.stringify(requestBody), + signal: controller.signal + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`HTTP ${response.status}: ${errorText}`); + } + + const result = await response.json() as LLMResponse; + + if (!result.choices || result.choices.length === 0) { + throw new Error('API 返回了空的选择列表'); + } + + const optimizedText = result.choices[0].message.content; + const endTime = Date.now(); + const duration = endTime - startTime; + + this.outputChannel.appendLine(`[${new Date().toISOString()}] 优化完成`); + this.outputChannel.appendLine(`耗时: ${duration}ms`); + + if (result.usage) { + this.outputChannel.appendLine(`Token 使用: ${result.usage.prompt_tokens} + ${result.usage.completion_tokens} = ${result.usage.total_tokens}`); + } + + return optimizedText; + + } catch (error) { + const endTime = Date.now(); + const duration = endTime - startTime; + + this.outputChannel.appendLine(`[${new Date().toISOString()}] 优化失败 (${duration}ms)`); + + if (error instanceof Error) { + this.outputChannel.appendLine(`错误: ${error.message}`); + if (error.stack) { + this.outputChannel.appendLine(`堆栈: ${error.stack}`); + } + } else { + this.outputChannel.appendLine(`未知错误: ${String(error)}`); + } + + throw error; + } + } + + private composeUserContent(text: string, userPrompt: string, variables?: Record): string { + const replaced = variables + ? userPrompt.replace(/\$\{(\w+)\}/g, (_m, k) => (variables[k] ?? ` +${'${'}${k}}`)) + : userPrompt; + return `${replaced}\n\n以下是需要优化的 RST 文档内容:\n\n${text}`; + } +} diff --git a/tools/rst-optimizer/src/test/extension.test.ts b/tools/rst-optimizer/src/test/extension.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4ca0ab419826dfd117400aa7547eb48d4022d89b --- /dev/null +++ b/tools/rst-optimizer/src/test/extension.test.ts @@ -0,0 +1,15 @@ +import * as assert from 'assert'; + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as vscode from 'vscode'; +// import * as myExtension from '../../extension'; + +suite('Extension Test Suite', () => { + vscode.window.showInformationMessage('Start all tests.'); + + test('Sample test', () => { + assert.strictEqual(-1, [1, 2, 3].indexOf(5)); + assert.strictEqual(-1, [1, 2, 3].indexOf(0)); + }); +}); diff --git a/tools/rst-optimizer/src/types.ts b/tools/rst-optimizer/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..8308b4a577a71192fe49d48d46591c05815a47f5 --- /dev/null +++ b/tools/rst-optimizer/src/types.ts @@ -0,0 +1,46 @@ +import * as vscode from 'vscode'; + +export interface OptimizationConfig { + provider: string; + baseUrl: string; + model: string; + apiKey: string; + userPrompt: string; + maxTokens: number; + temperature: number; + neverUploadIfWorkspaceTrusted: boolean; + rewrapWidth: number; +} + +export interface OptimizationRequest { + text: string; + userPrompt: string; + config: OptimizationConfig; + variables?: Record; // e.g. { fileName, filePath, relativePath, fileBaseName, fileExt } +} + +export interface OptimizationResult { + optimizedText: string; + originalText: string; + filePath: string; +} + +export interface LLMResponse { + choices: Array<{ + message: { + content: string; + }; + }>; + usage?: { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; + }; +} + +export interface DiffContext { + originalUri: vscode.Uri; + optimizedUri: vscode.Uri; + filePath: string; + optimizedContent: string; +} diff --git a/tools/rst-optimizer/src/utils/file.ts b/tools/rst-optimizer/src/utils/file.ts new file mode 100644 index 0000000000000000000000000000000000000000..b487da6216c09c7a0af8cae6235b3a8ac6f59425 --- /dev/null +++ b/tools/rst-optimizer/src/utils/file.ts @@ -0,0 +1,117 @@ +import * as vscode from 'vscode'; +import * as fs from 'fs'; +import * as path from 'path'; + +export class FileUtils { + /** + * 读取文件内容 + */ + static async readFile(filePath: string): Promise { + try { + const content = await fs.promises.readFile(filePath, 'utf8'); + return content; + } catch (error) { + throw new Error(`读取文件失败: ${error instanceof Error ? error.message : String(error)}`); + } + } + + /** + * 写入文件内容 + */ + static async writeFile(filePath: string, content: string): Promise { + try { + await fs.promises.writeFile(filePath, content, 'utf8'); + } catch (error) { + throw new Error(`写入文件失败: ${error instanceof Error ? error.message : String(error)}`); + } + } + + /** + * 获取当前活动编辑器的文件路径 + */ + static getCurrentRstFile(): string | undefined { + const activeEditor = vscode.window.activeTextEditor; + if (!activeEditor) { + return undefined; + } + + const document = activeEditor.document; + if (document.languageId !== 'restructuredtext' && !document.fileName.endsWith('.rst')) { + return undefined; + } + + return document.fileName; + } + + /** + * 显示文件选择器,只选择 .rst 文件 + */ + static async pickRstFile(): Promise { + const options: vscode.OpenDialogOptions = { + canSelectMany: false, + openLabel: '选择 RST 文件', + filters: { + 'reStructuredText 文件': ['rst'], + '所有文件': ['*'] + } + }; + + const fileUri = await vscode.window.showOpenDialog(options); + if (fileUri && fileUri[0]) { + return fileUri[0].fsPath; + } + + return undefined; + } + + /** + * 显示文件选择器,支持多选 .rst 文件 + */ + static async pickRstFiles(): Promise { + const options: vscode.OpenDialogOptions = { + canSelectMany: true, + openLabel: '选择 RST 文件(支持多选)', + filters: { + 'reStructuredText 文件': ['rst'], + '所有文件': ['*'] + } + }; + + const fileUris = await vscode.window.showOpenDialog(options); + if (fileUris && fileUris.length > 0) { + return fileUris.map(uri => uri.fsPath); + } + + return []; + } + + /** + * 检查文件是否存在 + */ + static async fileExists(filePath: string): Promise { + try { + await fs.promises.access(filePath, fs.constants.F_OK); + return true; + } catch { + return false; + } + } + + /** + * 获取文件名(不含路径) + */ + static getFileName(filePath: string): string { + return path.basename(filePath); + } + + /** + * 获取相对路径(相对于工作区) + */ + static getRelativePath(filePath: string): string { + const workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(filePath)); + if (workspaceFolder) { + return path.relative(workspaceFolder.uri.fsPath, filePath); + } + return path.basename(filePath); + } +} \ No newline at end of file diff --git a/tools/rst-optimizer/src/utils/wrap.ts b/tools/rst-optimizer/src/utils/wrap.ts new file mode 100644 index 0000000000000000000000000000000000000000..5a3cd07535a46b7d1c1a7e78be0a6ede6beb7677 --- /dev/null +++ b/tools/rst-optimizer/src/utils/wrap.ts @@ -0,0 +1,112 @@ +export class TextWrapper { + /** + * 对文本进行硬换行包裹 + * @param text 原始文本 + * @param width 行宽限制 + * @returns 包裹后的文本 + */ + static wrapText(text: string, width: number): string { + if (width <= 0) { + return text; + } + + const lines = text.split('\n'); + const wrappedLines: string[] = []; + + for (const line of lines) { + // 保留空行 + if (line.trim() === '') { + wrappedLines.push(line); + continue; + } + + // 检查是否是 RST 特殊行(不应该被包裹) + if (this.shouldPreserveLine(line)) { + wrappedLines.push(line); + continue; + } + + // 对普通文本行进行包裹 + const wrapped = this.wrapLine(line, width); + wrappedLines.push(...wrapped); + } + + return wrappedLines.join('\n'); + } + + /** + * 检查行是否应该保持原样(不进行包裹) + */ + private static shouldPreserveLine(line: string): boolean { + const trimmed = line.trim(); + + // RST 指令行 + if (trimmed.startsWith('.. ')) { + return true; + } + + // 标题下划线 + if (/^[\s]*[=\-`:'~^_*+#<>"]{3,}[\s]*$/.test(trimmed)) { + return true; + } + + // 代码块内容(通过缩进判断) + if (line.startsWith(' ') || line.startsWith('\t')) { + return true; + } + + // 列表项 + if (/^[\s]*[-*+]\s/.test(line) || /^[\s]*\d+\.\s/.test(line)) { + return true; + } + + // 表格行 + if (trimmed.includes('|') && trimmed.length > 10) { + return true; + } + + // 链接定义 + if (/^[\s]*\.\. _[^:]+:/.test(line)) { + return true; + } + + return false; + } + + /** + * 包裹单行文本 + */ + private static wrapLine(line: string, width: number): string[] { + const leadingWhitespace = line.match(/^(\s*)/)?.[1] || ''; + const content = line.trim(); + + if (content.length <= width - leadingWhitespace.length) { + return [line]; + } + + const words = content.split(/\s+/); + const wrappedLines: string[] = []; + let currentLine = leadingWhitespace; + + for (const word of words) { + const testLine = currentLine === leadingWhitespace + ? currentLine + word + : currentLine + ' ' + word; + + if (testLine.length <= width) { + currentLine = testLine; + } else { + if (currentLine.trim()) { + wrappedLines.push(currentLine); + } + currentLine = leadingWhitespace + word; + } + } + + if (currentLine.trim()) { + wrappedLines.push(currentLine); + } + + return wrappedLines.length > 0 ? wrappedLines : [line]; + } +} \ No newline at end of file diff --git a/tools/rst-optimizer/src/views/batchResultsHtml.ts b/tools/rst-optimizer/src/views/batchResultsHtml.ts new file mode 100644 index 0000000000000000000000000000000000000000..bcbe9b63e6ee6138649f9679af7d37ef11e722c5 --- /dev/null +++ b/tools/rst-optimizer/src/views/batchResultsHtml.ts @@ -0,0 +1,122 @@ +import { FileUtils } from '../utils/file'; + +export interface BatchResultItem { + id: string; + timestamp: number; + filePath: string; + originalText: string; + optimizedText: string; +} + +export function getBatchResultsHtml(results: BatchResultItem[]): string { + const fileItems = results.map((result, index) => { + const fileName = FileUtils.getFileName(result.filePath); + const relativePath = FileUtils.getRelativePath(result.filePath); + const originalLength = result.originalText.length; + const optimizedLength = result.optimizedText.length; + const changePercent = Math.round(((optimizedLength - originalLength) / Math.max(1, originalLength)) * 100); + const date = new Date(result.timestamp || Date.now()); + const timeStr = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; + + return ` +
+
+ + +
+
+ ${relativePath} + ${timeStr} +
+
+ 原文: ${originalLength} 字符 + 优化后: ${optimizedLength} 字符 + + 变化: ${changePercent >= 0 ? '+' : ''}${changePercent}% + +
+
+ `; + }).join(''); + + return ` + + + + + + RST 批量优化结果 + + + +
+
RST 批量优化结果
+
成功优化了 ${results.length} 个文件,请查看结果并选择要应用的文件
+
+
+ + +
+
${fileItems}
+
+ + + + +
+ + + + `; +} diff --git a/tools/rst-optimizer/src/views/batchResultsView.ts b/tools/rst-optimizer/src/views/batchResultsView.ts new file mode 100644 index 0000000000000000000000000000000000000000..bee5b3808612723d2a99321024fc7c3ce79c51ed --- /dev/null +++ b/tools/rst-optimizer/src/views/batchResultsView.ts @@ -0,0 +1,92 @@ +import * as vscode from 'vscode'; +import { getBatchResultsHtml, BatchResultItem } from './batchResultsHtml'; +import { HistoryStore } from '../history'; + +export type BatchResultsHandlers = { + onApplyAll: (results: BatchResultItem[]) => Promise; + onApplySelected: (results: BatchResultItem[], selectedFiles: string[]) => Promise; + onViewDiffById: (id: string) => Promise; + onDiscard: () => Promise; +}; + +export class BatchResultsViewProvider implements vscode.WebviewViewProvider { + public static readonly ViewId = 'rstOptimizer.batchResults'; + + private _view?: vscode.WebviewView; + private _results: BatchResultItem[] = []; + private _handlers: BatchResultsHandlers; + + constructor(handlers: BatchResultsHandlers) { + this._handlers = handlers; + } + + resolveWebviewView(webviewView: vscode.WebviewView): void | Thenable { + this._view = webviewView; + webviewView.webview.options = { enableScripts: true }; + this._results = HistoryStore.getAll(); + this.updateHtml(); + + webviewView.webview.onDidReceiveMessage(async message => { + switch (message.command) { + case 'applyAll': + await this._handlers.onApplyAll(this._results); + break; + case 'applySelected': + await this._handlers.onApplySelected(this._results, message.selectedFiles || []); + break; + case 'viewDiff': + if (message.id) { + await this._handlers.onViewDiffById(message.id); + } + break; + case 'deleteItem': + if (message.id) { + HistoryStore.removeById(message.id); + this._results = HistoryStore.getAll(); + this.updateHtml(); + } + break; + case 'deleteSelected': + if (Array.isArray(message.ids) && message.ids.length) { + for (const id of message.ids) { + HistoryStore.removeById(id); + } + this._results = HistoryStore.getAll(); + this.updateHtml(); + } + break; + case 'discard': + await this._handlers.onDiscard(); + break; + } + }); + } + + async showResults(results: Array>) { + // Append into history store and refresh from it + if (results && results.length) { + // results may not carry id/timestamp when passed in; ensure persistence creates them + const plain = results.map(r => ({ filePath: r.filePath, originalText: r.originalText, optimizedText: r.optimizedText })); + HistoryStore.addMany(plain); + } + this._results = HistoryStore.getAll(); + this.updateHtml(); + await vscode.commands.executeCommand('workbench.view.explorer'); + await vscode.commands.executeCommand('workbench.view.extension.rstOptimizer'); // in case moved later + await vscode.commands.executeCommand('rstOptimizer.revealBatchResultsView'); + } + + private updateHtml() { + if (!this._view) return; + this._view.webview.html = getBatchResultsHtml(this._results); + } + + reveal() { + this._view?.show?.(true); + } + + refreshFromStore() { + this._results = HistoryStore.getAll(); + this.updateHtml(); + } +} diff --git a/tools/rst_optimizer/out/src/config.js b/tools/rst_optimizer/out/src/config.js new file mode 100644 index 0000000000000000000000000000000000000000..5f83a3933f0f3e68e2df6e5999d16e02e1746575 --- /dev/null +++ b/tools/rst_optimizer/out/src/config.js @@ -0,0 +1,86 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ConfigManager = void 0; +const vscode = __importStar(require("vscode")); +class ConfigManager { + static getConfig() { + const config = vscode.workspace.getConfiguration(this.CONFIG_SECTION); + // 优先从环境变量读取 API Key + const apiKey = process.env.RST_OPTIMIZER_API_KEY || config.get('api.apiKey', ''); + return { + provider: config.get('api.provider', 'openai-compatible'), + baseUrl: config.get('api.baseUrl', 'https://api.openai.com/v1'), + model: config.get('api.model', 'gpt-4o-mini'), + apiKey, + userPrompt: config.get('prompt.userPrompt', "你是一名 **RST 技术文档审校与修复专家**。\n你的任务是:在**不改变技术语义**的前提下,**严格检查并修复**给定 RST 文档在语法、结构、格式与中文排版上的问题,并**保持与 API 定义及文件名的一致性**。\n如无明确要求,**不要引入新的内容段落或编造默认值/异常**;仅在缺漏“必须存在且可从上下文直接确定”的字段时做最小增补。\n\n## 输入\n\n* 文件名:${fileName}\n* 原始 RST 文本(保持原样)\n\n## 总体原则\n\n1. **最小侵入修复**:仅修复错误或不规范之处;保留原有信息结构与术语。\n2. **禁止误改代码/公式**:`code-block`、`literalinclude`、`math` 等指令体及反引号行内代码的技术内容不得改写(仅可做空格与围栏修复)。\n3. **一致性优先**:文件名、章节标题、API 名称必须一致(见规则 2)。\n4. **中文排版**:面向中文读者的正文需优化中文标点与用语,但不得改变技术意义。\n5. **不可臆测**:若无默认值/异常/类型信息,不得凭空添加。无法确定时保持空或原状,并在总结里标注“需要人工确认”。\n\n## 必查必修规则(逐条执行)\n\n### 1)通用 RST 语法与特殊标记\n\n* 检查并修复常见指令语法:`.. note::`、`.. warning::`、`.. seealso::`、`.. include::`、`.. math::` 等的缩进与空行:\n * 指令与其内容之间需空一行(除确有嵌套要求的场景外)。\n * 指令体内容相对指令行统一缩进(建议 3–4 空格),全文保持一致。\n* 行内特殊标记规则:\n * `*斜体*`、`**加粗**`、``行内代码``:标记内部不得出现空格(确需空格时改为转义或拆分)。\n * 标记与上下文:标记前后各保留 1 个空格(句首或紧邻标点处除外)。\n* 修复多余反引号、未闭合标记、错误嵌套。\n\n### 2)文件名 / 章节标题 / API 定义名一致性\n\n* 要求:文件名、文档首个最高层级标题、正文首个 API 定义名应一致。\n* 例外:若文件名匹配 `mindspore.xxx.func_yyy.rst`,则章节标题与 API 定义名统一为 `mindspore.xxx.yyy`(去掉 `func_`)。\n* 实施:\n * 若三者不一致,以 API 定义名为准统一章节标题;遇到上述例外时按例外规则处理。\n * 若文件名与 API 命名空间明显冲突(如包路径不同),不改文件名,仅统一标题与文内 API 显示。\n\n### 3)“参数/关键字参数”模块格式(**包含关键字专用参数的严格规则**)\n\n* 目标格式(逐项以无序列表 `-` 起):\n\n```\n参数:\n- **参数名** (数据类型[, 可选]) – 参数说明。默认值:`None`,表示……\n 关键字参数:\n- **参数名** (数据类型[, 可选]) – 参数说明。默认值:`None`,表示……\n```\n\n* 严格对齐 Python 函数签名的五类参数并分流到正确模块:\n\n1) **仅位置参数(positional-only)**:位于 `/` 左侧(若签名包含 `/`)。归入“参数”模块,**不要展示 `/` 本身**。\n2) **位置或关键字参数(positional-or-keyword)**:常见的 `name` 或 `name=...`。归入“参数”模块。\n3) **可变位置参数**:`*args`。归入“参数”模块,名称保留星号前缀 `*`,类型与说明按项目规范书写。\n4) **关键字专用参数(keyword-only)**:当签名中出现 **裸 `*` 分隔符** 或 `*args` 之后的形参(直到 `**kwargs` 之前)。**这些形参必须归入“关键字参数”模块**。\n - 裸 `*` 仅是分隔符,**不出现在文档中**;其右侧的参数(如 `dtype=None`)统一移至“关键字参数”。\n5) **可变关键字参数**:`**kwargs`。根据项目约定决定是否在“关键字参数”模块列出;若列出需保留 `**` 前缀并简要说明用途,避免臆测具体键。\n\n* “参数/关键字参数”的**名称与顺序必须与函数定义完全一致**(先左后右、从签名原序列化得到)。\n* “可选/默认值”标注规则:\n* 形参**有默认值**(含 `=None`)或注解为可选类型时:在类型后补 `, 可选`,且在说明末尾追加“默认值:````,……”。\n* 形参**无默认值**:不写“可选”,不写默认值句。\n* **数据类型**需与定义一致;若原文缺失且上下文也无法确定,不要臆测,类型可暂缺省或保持原状。\n* 术语与标点:\n* 中文破折号统一使用 `–`(en dash),全文保持一致。\n* 默认值文字中的字面量使用行内代码围栏(如 ``None``、``True``、``-1``)。\n* **迁移示例(与你给的 case 对齐)**:签名 `(..., dim=None, *, dtype=None)` →\n `dim` 仍在“参数”;`dtype` 作为 **关键字专用参数** 移至“关键字参数”。\n\n### 4)“异常”模块格式\n\n* 目标格式:\n\n```\n异常:\n- **ErrorType** - 异常描述。\n```\n\n* 同类异常归并在一起,子类在前、父类在后;不得杜撰异常,无法确认时保留原状并在总结中标注需确认。\n\n### 5)“输入/输出”模块格式\n\n* 目标格式:\n\n```\n输入:\n- **输入名** (数据类型) – 描述。\n 输出:\n- **输出名** (数据类型) – 描述。\n```\n\n* 无序列表 `-`,加粗名称 + 圆括号数据类型 + `–` 描述。\n\n### 6)换行与缩进\n\n* 普通段落换行不缩进。\n* 有序/无序列表换行统一 2 个空格缩进,与上一行正文起始位置对齐。\n* 指令体(note/warning/seealso/include/math 等)内层统一缩进;子块(如代码)再按 RST 规范缩进一级。\n\n### 7)模块间空行\n\n* 各模块之间至少 1 个空行;指令与其前后段落之间保留空行,避免黏连。\n\n### 8)中文文本与排版\n\n* 修复错别字、冗余空格、英文标点混用(中文语句中使用中文标点:`,` `。` `:` `;` `( )`)。\n* 并列关系用顿号 `、` 分隔。\n* API 名、类名、参数名、代码标识符保留原文并用行内代码``包裹。\n* 句子更通顺简洁,但不得改变技术含义。\n\n## 额外一致性检查\n\n* 标题层级符号(`= - ~ ^ \" ' *` 等)长度需与标题文本长度一致;同级标题符号统一。\n* `:param:/:type:/:return:/:rtype:` 若与目标“列表式参数节”并存,应二选一统一为项目约定风格(通常统一为“参数/关键字参数”块)。\n* 交叉引用(`:class:`, `:func:`, `:mod:` 等)语法修复:角色名、目标、反引号与空格。\n* `include` 路径前后空格与相对路径的一致性。\n\n## 输出要求\n\n* 输出修复后的完整 RST 正文(不加多余说明或包裹)。\n* 如需 diff 模式,由外层系统控制;本指令默认仅产出修复后全文。\n\n## 审核自查清单(模型内部执行,无需输出)\n\n* [ ] 指令语法/缩进/空行正确\n* [ ] 行内标记无空格、边界空格正确\n* [ ] 文件名/标题/API 名一致(含 `func_` 例外)\n* [ ] 参数/关键字参数:顺序与分流严格按签名(含 `/`、裸 `*`、`*args`、`**kwargs`)\n* [ ] “可选/默认值”标注与默认值文字格式正确\n* [ ] 异常:格式统一、同类聚合、无臆测\n* [ ] 输入/输出:列表格式统一\n* [ ] 列表缩进 2 空格,段落不缩进\n* [ ] 模块间有空行(例如返回是一个模块,异常是一个模块,他们之间有空行,但是异常下面的具体异常和异常大标题之间无空行)\n* [ ] 中文标点与顿号、错别字修复\n* [ ] 代码/公式内容未被改写(仅围栏/空格修复)"), + maxTokens: config.get('generation.maxTokens', 4096), + temperature: config.get('generation.temperature', 0.3), + neverUploadIfWorkspaceTrusted: config.get('safety.neverUploadIfWorkspaceTrusted', false), + rewrapWidth: config.get('format.rewrapWidth', 0) + }; + } + static validateConfig(config) { + const errors = []; + if (!config.baseUrl) { + errors.push('API 基础 URL 不能为空'); + } + if (!config.model) { + errors.push('模型名称不能为空'); + } + if (!config.apiKey) { + errors.push('API 密钥不能为空,请在设置中配置或设置环境变量 RST_OPTIMIZER_API_KEY'); + } + if (config.maxTokens <= 0) { + errors.push('最大 token 数量必须大于 0'); + } + if (config.temperature < 0 || config.temperature > 2) { + errors.push('温度值必须在 0-2 之间'); + } + return errors; + } + static checkWorkspaceSafety() { + const workspaceTrust = vscode.workspace.isTrusted; + const config = this.getConfig(); + if (config.neverUploadIfWorkspaceTrusted && workspaceTrust) { + vscode.window.showWarningMessage('安全设置阻止了在受信任工作区中上传内容到外部 API。请在设置中关闭 "neverUploadIfWorkspaceTrusted" 选项。'); + return false; + } + return true; + } +} +exports.ConfigManager = ConfigManager; +ConfigManager.CONFIG_SECTION = 'rstOptimizer'; +//# sourceMappingURL=config.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/config.js.map b/tools/rst_optimizer/out/src/config.js.map new file mode 100644 index 0000000000000000000000000000000000000000..909bed0c0faa54f22cbef859e9867e87c1f3a0dd --- /dev/null +++ b/tools/rst_optimizer/out/src/config.js.map @@ -0,0 +1 @@ +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAGjC,MAAa,aAAa;IAGxB,MAAM,CAAC,SAAS;QACd,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAEtE,oBAAoB;QACpB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,MAAM,CAAC,GAAG,CAAS,YAAY,EAAE,EAAE,CAAC,CAAC;QAEzF,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAS,cAAc,EAAE,mBAAmB,CAAC;YACjE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAS,aAAa,EAAE,2BAA2B,CAAC;YACvE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAS,WAAW,EAAE,aAAa,CAAC;YACrD,MAAM;YACN,UAAU,EAAE,MAAM,CAAC,GAAG,CAAS,mBAAmB,EAAC,2/GAA2/G,CAAC;YAC/iH,SAAS,EAAE,MAAM,CAAC,GAAG,CAAS,sBAAsB,EAAE,IAAI,CAAC;YAC3D,WAAW,EAAE,MAAM,CAAC,GAAG,CAAS,wBAAwB,EAAE,GAAG,CAAC;YAC9D,6BAA6B,EAAE,MAAM,CAAC,GAAG,CAAU,sCAAsC,EAAE,KAAK,CAAC;YACjG,WAAW,EAAE,MAAM,CAAC,GAAG,CAAS,oBAAoB,EAAE,CAAC,CAAC;SACzD,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,MAA0B;QAC9C,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1B,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,MAAM,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,MAAM,CAAC,WAAW,GAAG,CAAC,IAAI,MAAM,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,oBAAoB;QACzB,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAEhC,IAAI,MAAM,CAAC,6BAA6B,IAAI,cAAc,EAAE,CAAC;YAC3D,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAC9B,wEAAwE,CACzE,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;;AA5DH,sCA6DC;AA5DyB,4BAAc,GAAG,cAAc,CAAC"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/diff/diffActionCodeLensProvider.js b/tools/rst_optimizer/out/src/diff/diffActionCodeLensProvider.js new file mode 100644 index 0000000000000000000000000000000000000000..3d739fd31b4c77c025476b2db1d6368d06ddf51f --- /dev/null +++ b/tools/rst_optimizer/out/src/diff/diffActionCodeLensProvider.js @@ -0,0 +1,68 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DiffActionCodeLensProvider = void 0; +const vscode = __importStar(require("vscode")); +const virtualDocProvider_1 = require("./virtualDocProvider"); +class DiffActionCodeLensProvider { + constructor() { + this.onDidChangeCodeLensesEmitter = new vscode.EventEmitter(); + this.onDidChangeCodeLenses = this.onDidChangeCodeLensesEmitter.event; + } + provideCodeLenses(document) { + if (document.uri.scheme !== virtualDocProvider_1.VirtualDocProvider.getScheme()) { + return []; + } + if (!document.uri.path.startsWith('/optimized/')) { + return []; + } + const lastLine = Math.max(0, document.lineCount - 1); + const range = new vscode.Range(lastLine, 0, lastLine, 0); + const applyLens = new vscode.CodeLens(range, { + title: '$(check) 应用优化', + command: 'rstOptimizer.applyResult' + }); + const discardLens = new vscode.CodeLens(range, { + title: '$(x) 放弃优化', + command: 'rstOptimizer.discardResult' + }); + return [applyLens, discardLens]; + } + refresh() { + this.onDidChangeCodeLensesEmitter.fire(); + } +} +exports.DiffActionCodeLensProvider = DiffActionCodeLensProvider; +//# sourceMappingURL=diffActionCodeLensProvider.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/diff/diffActionCodeLensProvider.js.map b/tools/rst_optimizer/out/src/diff/diffActionCodeLensProvider.js.map new file mode 100644 index 0000000000000000000000000000000000000000..364d006598024055d1f210846322db6108a96d8d --- /dev/null +++ b/tools/rst_optimizer/out/src/diff/diffActionCodeLensProvider.js.map @@ -0,0 +1 @@ +{"version":3,"file":"diffActionCodeLensProvider.js","sourceRoot":"","sources":["../../../src/diff/diffActionCodeLensProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AACjC,6DAA0D;AAG1D,MAAa,0BAA0B;IAAvC;QACU,iCAA4B,GAAG,IAAI,MAAM,CAAC,YAAY,EAAQ,CAAC;QACvD,0BAAqB,GAAuB,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC;IA6BtG,CAAC;IA3BC,iBAAiB,CAAC,QAA6B;QAC7C,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,KAAK,uCAAkB,CAAC,SAAS,EAAE,EAAE,CAAC;YAC3D,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACjD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAEzD,MAAM,SAAS,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC3C,KAAK,EAAE,eAAe;YACtB,OAAO,EAAE,0BAA0B;SACpC,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC7C,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,4BAA4B;SACtC,CAAC,CAAC;QAEH,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAClC,CAAC;IAED,OAAO;QACL,IAAI,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;CACF;AA/BD,gEA+BC"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/diff/virtualDocProvider.js b/tools/rst_optimizer/out/src/diff/virtualDocProvider.js new file mode 100644 index 0000000000000000000000000000000000000000..0258a65fe46e81ab8a5a7985dc055ab9d8b7acd8 --- /dev/null +++ b/tools/rst_optimizer/out/src/diff/virtualDocProvider.js @@ -0,0 +1,73 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.VirtualDocProvider = void 0; +const vscode = __importStar(require("vscode")); +class VirtualDocProvider { + constructor() { + this.contentMap = new Map(); + this._onDidChange = new vscode.EventEmitter(); + this.onDidChange = this._onDidChange.event; + } + static createUri(type, filePath) { + const timestamp = Date.now(); + return vscode.Uri.parse(`${VirtualDocProvider.scheme}:${type}/${encodeURIComponent(filePath)}?t=${timestamp}`); + } + provideTextDocumentContent(uri) { + const key = this.getKeyFromUri(uri); + return this.contentMap.get(key); + } + set(uri, content) { + const key = this.getKeyFromUri(uri); + this.contentMap.set(key, content); + this._onDidChange.fire(uri); + } + clear(uri) { + const key = this.getKeyFromUri(uri); + this.contentMap.delete(key); + } + clearAll() { + this.contentMap.clear(); + } + getKeyFromUri(uri) { + return `${uri.path}${uri.query}`; + } + static getScheme() { + return VirtualDocProvider.scheme; + } +} +exports.VirtualDocProvider = VirtualDocProvider; +VirtualDocProvider.scheme = 'rstopt'; +//# sourceMappingURL=virtualDocProvider.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/diff/virtualDocProvider.js.map b/tools/rst_optimizer/out/src/diff/virtualDocProvider.js.map new file mode 100644 index 0000000000000000000000000000000000000000..e0b8574070aa80eb27bb84fd213d256feb809cb7 --- /dev/null +++ b/tools/rst_optimizer/out/src/diff/virtualDocProvider.js.map @@ -0,0 +1 @@ +{"version":3,"file":"virtualDocProvider.js","sourceRoot":"","sources":["../../../src/diff/virtualDocProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAEjC,MAAa,kBAAkB;IAA/B;QAEU,eAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;QACvC,iBAAY,GAAG,IAAI,MAAM,CAAC,YAAY,EAAc,CAAC;QAEpD,gBAAW,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IAkCjD,CAAC;IAhCC,MAAM,CAAC,SAAS,CAAC,IAA8B,EAAE,QAAgB;QAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,MAAM,IAAI,IAAI,IAAI,kBAAkB,CAAC,QAAQ,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC;IACjH,CAAC;IAED,0BAA0B,CAAC,GAAe;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,GAAG,CAAC,GAAe,EAAE,OAAe;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,GAAe;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAEO,aAAa,CAAC,GAAe;QACnC,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;IAED,MAAM,CAAC,SAAS;QACd,OAAO,kBAAkB,CAAC,MAAM,CAAC;IACnC,CAAC;;AAtCH,gDAuCC;AAtCyB,yBAAM,GAAG,QAAQ,AAAX,CAAY"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/extension.js b/tools/rst_optimizer/out/src/extension.js new file mode 100644 index 0000000000000000000000000000000000000000..2cb3f768e5c83cd2b36635a5316830628629110a --- /dev/null +++ b/tools/rst_optimizer/out/src/extension.js @@ -0,0 +1,389 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.activate = activate; +exports.deactivate = deactivate; +const vscode = __importStar(require("vscode")); +const config_1 = require("./config"); +const client_1 = require("./llm/client"); +const virtualDocProvider_1 = require("./diff/virtualDocProvider"); +const diffActionCodeLensProvider_1 = require("./diff/diffActionCodeLensProvider"); +const batchResultsView_1 = require("./views/batchResultsView"); +const file_1 = require("./utils/file"); +const wrap_1 = require("./utils/wrap"); +const history_1 = require("./history"); +let outputChannel; +let llmClient; +let virtualDocProvider; +let statusBarItem; +let currentDiffContext; +let batchResultsViewProvider; +function activate(context) { + outputChannel = vscode.window.createOutputChannel('RST Optimizer'); + context.subscriptions.push(outputChannel); + llmClient = new client_1.LLMClient(outputChannel); + history_1.HistoryStore.init(context); + virtualDocProvider = new virtualDocProvider_1.VirtualDocProvider(); + context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(virtualDocProvider_1.VirtualDocProvider.getScheme(), virtualDocProvider)); + const codeLensProvider = new diffActionCodeLensProvider_1.DiffActionCodeLensProvider(); + context.subscriptions.push(vscode.languages.registerCodeLensProvider({ scheme: virtualDocProvider_1.VirtualDocProvider.getScheme() }, codeLensProvider)); + batchResultsViewProvider = new batchResultsView_1.BatchResultsViewProvider({ + onApplyAll: async (results) => applyAllBatchResults(results), + onApplySelected: async (results, selected) => applySelectedBatchResults(results, selected), + onViewDiffById: async (id) => { + const r = history_1.HistoryStore.getById(id); + if (r) { + await showDiffView(r.filePath, r.originalText, r.optimizedText); + } + }, + onDiscard: async () => { } + }); + context.subscriptions.push(vscode.window.registerWebviewViewProvider(batchResultsView_1.BatchResultsViewProvider.ViewId, batchResultsViewProvider)); + // 命令:确保可以显式聚焦视图 + context.subscriptions.push(vscode.commands.registerCommand('rstOptimizer.revealBatchResultsView', () => batchResultsViewProvider.reveal())); + // 创建状态栏项 + statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); + statusBarItem.text = '$(edit) RST Optimizer'; + statusBarItem.tooltip = '点击打开 RST Optimizer 命令'; + statusBarItem.command = 'rstOptimizer.showQuickPick'; + statusBarItem.show(); + context.subscriptions.push(statusBarItem); + // 注册命令 + const commands = [ + vscode.commands.registerCommand('rstOptimizer.optimizeCurrent', optimizeCurrentFile), + vscode.commands.registerCommand('rstOptimizer.optimizePickFile', optimizePickedFile), + vscode.commands.registerCommand('rstOptimizer.applyResult', applyOptimizedResult), + vscode.commands.registerCommand('rstOptimizer.discardResult', discardOptimizedResult), + vscode.commands.registerCommand('rstOptimizer.openSettings', openSettings), + vscode.commands.registerCommand('rstOptimizer.showQuickPick', showQuickPick) + ]; + context.subscriptions.push(...commands); + outputChannel.appendLine('RST Optimizer 扩展已激活'); +} +function deactivate() { + if (virtualDocProvider) { + virtualDocProvider.clearAll(); + } + outputChannel?.appendLine('RST Optimizer 扩展已停用'); +} +async function optimizeCurrentFile() { + const filePath = file_1.FileUtils.getCurrentRstFile(); + if (!filePath) { + vscode.window.showWarningMessage('当前编辑器不是 RST 文件,请打开一个 .rst 文件'); + return; + } + await optimizeFile(filePath); +} +async function optimizePickedFile() { + const filePaths = await file_1.FileUtils.pickRstFiles(); + if (filePaths.length === 0) { + return; // 用户取消了选择 + } + // 打开选中的文件 + for (const filePath of filePaths) { + const document = await vscode.workspace.openTextDocument(filePath); + await vscode.window.showTextDocument(document, { preview: false }); + } + if (filePaths.length === 1) { + // 单文件优化 + await optimizeFile(filePaths[0]); + } + else { + // 批量优化 + await optimizeMultipleFiles(filePaths); + } +} +async function optimizeMultipleFiles(filePaths) { + try { + // 检查工作区安全设置 + if (!config_1.ConfigManager.checkWorkspaceSafety()) { + return; + } + // 获取配置 + const config = config_1.ConfigManager.getConfig(); + const configErrors = config_1.ConfigManager.validateConfig(config); + if (configErrors.length > 0) { + vscode.window.showErrorMessage(`配置错误:${configErrors.join(', ')}`); + return; + } + const results = []; + // 显示总体进度 + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: `正在批量优化 ${filePaths.length} 个 RST 文件...`, + cancellable: true + }, async (progress, token) => { + for (let i = 0; i < filePaths.length; i++) { + const filePath = filePaths[i]; + const fileName = file_1.FileUtils.getFileName(filePath); + if (token.isCancellationRequested) { + break; + } + progress.report({ + message: `正在优化 ${fileName} (${i + 1}/${filePaths.length})`, + increment: (100 / filePaths.length) + }); + try { + const originalText = await file_1.FileUtils.readFile(filePath); + if (!originalText.trim()) { + outputChannel.appendLine(`跳过空文件: ${filePath}`); + continue; + } + const dotIdx = fileName.lastIndexOf('.'); + const fileBaseName = dotIdx > 0 ? fileName.slice(0, dotIdx) : fileName; + const fileExt = dotIdx > -1 ? fileName.slice(dotIdx + 1) : ''; + const optimizedText = await llmClient.optimizeRst({ + text: originalText, + userPrompt: config.userPrompt, + config, + variables: { + filePath, + fileName, + relativePath: file_1.FileUtils.getRelativePath(filePath), + fileBaseName, + fileExt + } + }, token); + const finalOptimizedText = config.rewrapWidth > 0 + ? wrap_1.TextWrapper.wrapText(optimizedText, config.rewrapWidth) + : optimizedText; + results.push({ + filePath, + originalText, + optimizedText: finalOptimizedText + }); + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + outputChannel.appendLine(`优化失败 ${filePath}: ${errorMessage}`); + vscode.window.showWarningMessage(`优化 ${fileName} 失败: ${errorMessage}`); + } + } + }); + if (results.length > 0) { + await showBatchOptimizationResults(results); + } + else { + vscode.window.showWarningMessage('没有成功优化任何文件'); + } + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`批量优化失败: ${errorMessage}`); + outputChannel.appendLine(`批量优化失败: ${errorMessage}`); + } +} +async function optimizeFile(filePath) { + try { + // 检查工作区安全设置 + if (!config_1.ConfigManager.checkWorkspaceSafety()) { + return; + } + // 获取配置 + const config = config_1.ConfigManager.getConfig(); + const configErrors = config_1.ConfigManager.validateConfig(config); + if (configErrors.length > 0) { + vscode.window.showErrorMessage(`配置错误:${configErrors.join(', ')}`); + return; + } + // 读取文件内容 + const originalText = await file_1.FileUtils.readFile(filePath); + if (!originalText.trim()) { + vscode.window.showWarningMessage('文件内容为空'); + return; + } + // 显示进度并执行优化 + const optimizedText = await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: `正在使用 ${config.provider}/${config.model} 优化 RST 文档...`, + cancellable: true + }, async (progress, token) => { + const fileName = file_1.FileUtils.getFileName(filePath); + const relativePath = file_1.FileUtils.getRelativePath(filePath); + const dotIdx = fileName.lastIndexOf('.'); + const fileBaseName = dotIdx > 0 ? fileName.slice(0, dotIdx) : fileName; + const fileExt = dotIdx > -1 ? fileName.slice(dotIdx + 1) : ''; + return await llmClient.optimizeRst({ + text: originalText, + userPrompt: config.userPrompt, + config, + variables: { filePath, fileName, relativePath, fileBaseName, fileExt } + }, token); + }); + // 应用文本包装(如果配置了) + const finalOptimizedText = config.rewrapWidth > 0 + ? wrap_1.TextWrapper.wrapText(optimizedText, config.rewrapWidth) + : optimizedText; + // 创建 diff 视图 + await showDiffView(filePath, originalText, finalOptimizedText); + // 记录到历史并刷新侧边栏 + await batchResultsViewProvider.showResults([{ filePath, originalText, optimizedText: finalOptimizedText }]); + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`优化失败: ${errorMessage}`); + outputChannel.appendLine(`优化失败: ${errorMessage}`); + } +} +async function showDiffView(filePath, originalText, optimizedText) { + // 创建虚拟 URI + const originalUri = virtualDocProvider_1.VirtualDocProvider.createUri('original', filePath); + const optimizedUri = virtualDocProvider_1.VirtualDocProvider.createUri('optimized', filePath); + // 设置虚拟文档内容 + virtualDocProvider.set(originalUri, originalText); + virtualDocProvider.set(optimizedUri, optimizedText); + // 保存当前 diff 上下文 + currentDiffContext = { + originalUri, + optimizedUri, + filePath, + optimizedContent: optimizedText + }; + // 打开 diff 视图 + const fileName = file_1.FileUtils.getFileName(filePath); + const title = `RST Diff: ${fileName}`; + await vscode.commands.executeCommand('vscode.diff', originalUri, optimizedUri, title, { preview: false }); + // 设置上下文,确保菜单按钮在 diff 标题栏显示 + await vscode.commands.executeCommand('setContext', 'rstOptimizer.hasActiveDiff', true); +} +async function showBatchOptimizationResults(results) { + await batchResultsViewProvider.showResults(results); +} +async function applyOptimizedResult() { + if (!currentDiffContext) { + vscode.window.showWarningMessage('没有可应用的优化结果'); + return; + } + try { + await file_1.FileUtils.writeFile(currentDiffContext.filePath, currentDiffContext.optimizedContent); + const fileName = file_1.FileUtils.getFileName(currentDiffContext.filePath); + vscode.window.showInformationMessage(`已成功应用优化结果到 ${fileName}`); + outputChannel.appendLine(`[${new Date().toISOString()}] 已应用优化结果: ${currentDiffContext.filePath}`); + // 清理 + await discardChanges(); + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + vscode.window.showErrorMessage(`应用更改失败: ${errorMessage}`); + } +} +async function discardOptimizedResult() { + if (!currentDiffContext) { + vscode.window.showWarningMessage('没有可放弃的优化结果'); + return; + } + const fileName = file_1.FileUtils.getFileName(currentDiffContext.filePath); + vscode.window.showInformationMessage(`已放弃对 ${fileName} 的优化结果`); + outputChannel.appendLine(`[${new Date().toISOString()}] 已放弃优化结果: ${currentDiffContext.filePath}`); + // 清理 + await discardChanges(); +} +async function discardChanges() { + if (currentDiffContext) { + // 清理虚拟文档 + virtualDocProvider.clear(currentDiffContext.originalUri); + virtualDocProvider.clear(currentDiffContext.optimizedUri); + currentDiffContext = undefined; + } + // 清理上下文 + await vscode.commands.executeCommand('setContext', 'rstOptimizer.hasActiveDiff', false); +} +async function applyAllBatchResults(results) { + let successCount = 0; + let failCount = 0; + for (const result of results) { + try { + await file_1.FileUtils.writeFile(result.filePath, result.optimizedText); + successCount++; + outputChannel.appendLine(`[${new Date().toISOString()}] 已应用优化结果: ${result.filePath}`); + } + catch (error) { + failCount++; + const errorMessage = error instanceof Error ? error.message : String(error); + outputChannel.appendLine(`[${new Date().toISOString()}] 应用失败: ${result.filePath} - ${errorMessage}`); + } + } + vscode.window.showInformationMessage(`批量应用完成!成功: ${successCount} 个,失败: ${failCount} 个`); +} +async function applySelectedBatchResults(results, selectedFiles) { + let successCount = 0; + let failCount = 0; + for (const filePath of selectedFiles) { + const result = results.find(r => r.filePath === filePath); + if (!result) + continue; + try { + await file_1.FileUtils.writeFile(result.filePath, result.optimizedText); + successCount++; + outputChannel.appendLine(`[${new Date().toISOString()}] 已应用优化结果: ${result.filePath}`); + } + catch (error) { + failCount++; + const errorMessage = error instanceof Error ? error.message : String(error); + outputChannel.appendLine(`[${new Date().toISOString()}] 应用失败: ${result.filePath} - ${errorMessage}`); + } + } + vscode.window.showInformationMessage(`选择性应用完成!成功: ${successCount} 个,失败: ${failCount} 个`); +} +// batch 结果的 HTML 已移动到 src/views/batchResultsHtml.ts +async function openSettings() { + await vscode.commands.executeCommand('workbench.action.openSettings', 'rstOptimizer'); +} +async function showQuickPick() { + const items = [ + { + label: '$(file-text) 优化当前 RST 文件', + description: '优化当前活动编辑器中的 RST 文件', + command: 'rstOptimizer.optimizeCurrent' + }, + { + label: '$(folder-opened) 选择 RST 文件优化', + description: '通过文件选择器选择要优化的 RST 文件', + command: 'rstOptimizer.optimizePickFile' + }, + { + label: '$(settings-gear) 打开设置', + description: '配置 RST Optimizer 设置', + command: 'rstOptimizer.openSettings' + } + ]; + const selected = await vscode.window.showQuickPick(items, { + placeHolder: '选择要执行的操作' + }); + if (selected) { + await vscode.commands.executeCommand(selected.command); + } +} +//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/extension.js.map b/tools/rst_optimizer/out/src/extension.js.map new file mode 100644 index 0000000000000000000000000000000000000000..33147febff74d941c0a16b3f70d90f6f80df7e2f --- /dev/null +++ b/tools/rst_optimizer/out/src/extension.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/history.js b/tools/rst_optimizer/out/src/history.js new file mode 100644 index 0000000000000000000000000000000000000000..ef2d417d79240bacb329efbcc429d29938cf2b09 --- /dev/null +++ b/tools/rst_optimizer/out/src/history.js @@ -0,0 +1,49 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.HistoryStore = void 0; +class HistoryStore { + static init(context) { + this.context = context; + } + static ensureReady() { + if (!this.context) { + throw new Error('HistoryStore not initialized'); + } + } + static getAll() { + this.ensureReady(); + const items = this.context.globalState.get(this.KEY, []); + return Array.isArray(items) ? items.slice().sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0)) : []; + } + static addMany(items) { + this.ensureReady(); + const existing = this.getAll(); + const now = Date.now(); + const withIds = items.map((it, idx) => ({ + ...it, + id: `${now}-${idx}-${Math.random().toString(36).slice(2, 8)}`, + timestamp: now + idx, + })); + const next = [...withIds, ...existing]; + this.context.globalState.update(this.KEY, next); + return withIds; + } + static addOne(item) { + return this.addMany([item])[0]; + } + static removeById(id) { + this.ensureReady(); + const next = this.getAll().filter(it => it.id !== id); + this.context.globalState.update(this.KEY, next); + } + static getById(id) { + return this.getAll().find(it => it.id === id); + } + static clearAll() { + this.ensureReady(); + this.context.globalState.update(this.KEY, []); + } +} +exports.HistoryStore = HistoryStore; +HistoryStore.KEY = 'rstOptimizer.history'; +//# sourceMappingURL=history.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/history.js.map b/tools/rst_optimizer/out/src/history.js.map new file mode 100644 index 0000000000000000000000000000000000000000..df6d75f10aac2c31a78a702c021b5e4fd145a228 --- /dev/null +++ b/tools/rst_optimizer/out/src/history.js.map @@ -0,0 +1 @@ +{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/history.ts"],"names":[],"mappings":";;;AAIA,MAAa,YAAY;IAIvB,MAAM,CAAC,IAAI,CAAC,OAAgC;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAEO,MAAM,CAAC,WAAW;QACxB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,MAAM,CAAC,MAAM;QACX,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAQ,CAAC,WAAW,CAAC,GAAG,CAAoB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7E,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3G,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,KAAkD;QAC/D,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAsB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACzD,GAAG,EAAE;YACL,EAAE,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YAC7D,SAAS,EAAE,GAAG,GAAG,GAAG;SACrB,CAAC,CAAC,CAAC;QACJ,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,OAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,IAA+C;QAC3D,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,EAAU;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,OAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,EAAU;QACvB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,CAAC,QAAQ;QACb,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,OAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;;AAnDH,oCAoDC;AAlDyB,gBAAG,GAAG,sBAAsB,CAAC"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/llm/client.js b/tools/rst_optimizer/out/src/llm/client.js new file mode 100644 index 0000000000000000000000000000000000000000..41bda8ece48350bf51656a9994d6b0470535ea49 --- /dev/null +++ b/tools/rst_optimizer/out/src/llm/client.js @@ -0,0 +1,96 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LLMClient = void 0; +const DEFAULT_SYSTEM_PROMPT = `你是 reStructuredText(RST)与 Sphinx 文档优化专家。目标:在不破坏语义与构建的前提下,让文档更清晰专业。 +严格遵循: +1) 保留并尊重所有 Sphinx 角色/指令/域(如 :ref:、:class:、:func:、.. code-block::、.. note::、.. figure:: 等),不要更改其语法结构与缩进。 +2) 绝不删除或更改链接目标、交叉引用锚点(如 .. _anchor:)。 +3) 保留代码块、控制台示例与行内字面值(\`\`literal\`\`)原样;除非是修复明显拼写错误。 +4) 标题层级与下划线风格统一(如 # * = - ^ ~ 等),但不得改变层级关系。 +5) 修复语法/拼写/术语一致性,使段落更简洁、技术准确;尽量减少被动语态。 +6) 表格、列表、缩进必须合法;指令体的缩进四空格对齐。 +7) 输出**完整优化后的整篇 RST**,不要输出 diff 或注释。`; +class LLMClient { + constructor(outputChannel) { + this.outputChannel = outputChannel; + } + async optimizeRst(request, cancellationToken) { + const startTime = Date.now(); + const { text, userPrompt, config } = request; + this.outputChannel.appendLine(`[${new Date().toISOString()}] 开始优化 RST 文档`); + this.outputChannel.appendLine(`提供商: ${config.provider}`); + this.outputChannel.appendLine(`模型: ${config.model}`); + this.outputChannel.appendLine(`文档长度: ${text.length} 字符`); + this.outputChannel.appendLine(`估算 token: ${Math.ceil(text.length / 4)}`); + try { + const userContent = this.composeUserContent(text, userPrompt, request.variables); + const requestBody = { + model: config.model, + temperature: config.temperature, + max_tokens: config.maxTokens, + messages: [ + { role: "system", content: DEFAULT_SYSTEM_PROMPT }, + { role: "user", content: userContent } + ] + }; + const controller = new AbortController(); + // 处理取消令牌 + if (cancellationToken) { + cancellationToken.onCancellationRequested(() => { + controller.abort(); + this.outputChannel.appendLine(`[${new Date().toISOString()}] 请求被用户取消`); + }); + } + const response = await fetch(`${config.baseUrl}/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${config.apiKey}` + }, + body: JSON.stringify(requestBody), + signal: controller.signal + }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`HTTP ${response.status}: ${errorText}`); + } + const result = await response.json(); + if (!result.choices || result.choices.length === 0) { + throw new Error('API 返回了空的选择列表'); + } + const optimizedText = result.choices[0].message.content; + const endTime = Date.now(); + const duration = endTime - startTime; + this.outputChannel.appendLine(`[${new Date().toISOString()}] 优化完成`); + this.outputChannel.appendLine(`耗时: ${duration}ms`); + if (result.usage) { + this.outputChannel.appendLine(`Token 使用: ${result.usage.prompt_tokens} + ${result.usage.completion_tokens} = ${result.usage.total_tokens}`); + } + return optimizedText; + } + catch (error) { + const endTime = Date.now(); + const duration = endTime - startTime; + this.outputChannel.appendLine(`[${new Date().toISOString()}] 优化失败 (${duration}ms)`); + if (error instanceof Error) { + this.outputChannel.appendLine(`错误: ${error.message}`); + if (error.stack) { + this.outputChannel.appendLine(`堆栈: ${error.stack}`); + } + } + else { + this.outputChannel.appendLine(`未知错误: ${String(error)}`); + } + throw error; + } + } + composeUserContent(text, userPrompt, variables) { + const replaced = variables + ? userPrompt.replace(/\$\{(\w+)\}/g, (_m, k) => (variables[k] ?? ` +${'${'}${k}}`)) + : userPrompt; + return `${replaced}\n\n以下是需要优化的 RST 文档内容:\n\n${text}`; + } +} +exports.LLMClient = LLMClient; +//# sourceMappingURL=client.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/llm/client.js.map b/tools/rst_optimizer/out/src/llm/client.js.map new file mode 100644 index 0000000000000000000000000000000000000000..bce1f9e3f4c29505afb4b7cdabaf37b559ea1b70 --- /dev/null +++ b/tools/rst_optimizer/out/src/llm/client.js.map @@ -0,0 +1 @@ +{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/llm/client.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/test/extension.test.js b/tools/rst_optimizer/out/src/test/extension.test.js new file mode 100644 index 0000000000000000000000000000000000000000..4951e6febaf55d7f42aa7bc8f8166168f64a3285 --- /dev/null +++ b/tools/rst_optimizer/out/src/test/extension.test.js @@ -0,0 +1,48 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +const assert = __importStar(require("assert")); +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +const vscode = __importStar(require("vscode")); +// import * as myExtension from '../../extension'; +suite('Extension Test Suite', () => { + vscode.window.showInformationMessage('Start all tests.'); + test('Sample test', () => { + assert.strictEqual(-1, [1, 2, 3].indexOf(5)); + assert.strictEqual(-1, [1, 2, 3].indexOf(0)); + }); +}); +//# sourceMappingURL=extension.test.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/test/extension.test.js.map b/tools/rst_optimizer/out/src/test/extension.test.js.map new file mode 100644 index 0000000000000000000000000000000000000000..cb3ba4c57d8869e1757af6d95b7838e4bd0ca310 --- /dev/null +++ b/tools/rst_optimizer/out/src/test/extension.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.test.js","sourceRoot":"","sources":["../../../src/test/extension.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAEjC,0DAA0D;AAC1D,8CAA8C;AAC9C,+CAAiC;AACjC,kDAAkD;AAElD,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE;IAClC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IAEzD,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/types.js b/tools/rst_optimizer/out/src/types.js new file mode 100644 index 0000000000000000000000000000000000000000..11e638d1ee44ae0dcb1feb5aef676ea74a7d4df3 --- /dev/null +++ b/tools/rst_optimizer/out/src/types.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/types.js.map b/tools/rst_optimizer/out/src/types.js.map new file mode 100644 index 0000000000000000000000000000000000000000..7b5fff867a5a8de2324d2c0521b7c2292da35535 --- /dev/null +++ b/tools/rst_optimizer/out/src/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/utils/file.js b/tools/rst_optimizer/out/src/utils/file.js new file mode 100644 index 0000000000000000000000000000000000000000..47c362c16e8ae2e05ea662f93d610309b766fbc6 --- /dev/null +++ b/tools/rst_optimizer/out/src/utils/file.js @@ -0,0 +1,144 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FileUtils = void 0; +const vscode = __importStar(require("vscode")); +const fs = __importStar(require("fs")); +const path = __importStar(require("path")); +class FileUtils { + /** + * 读取文件内容 + */ + static async readFile(filePath) { + try { + const content = await fs.promises.readFile(filePath, 'utf8'); + return content; + } + catch (error) { + throw new Error(`读取文件失败: ${error instanceof Error ? error.message : String(error)}`); + } + } + /** + * 写入文件内容 + */ + static async writeFile(filePath, content) { + try { + await fs.promises.writeFile(filePath, content, 'utf8'); + } + catch (error) { + throw new Error(`写入文件失败: ${error instanceof Error ? error.message : String(error)}`); + } + } + /** + * 获取当前活动编辑器的文件路径 + */ + static getCurrentRstFile() { + const activeEditor = vscode.window.activeTextEditor; + if (!activeEditor) { + return undefined; + } + const document = activeEditor.document; + if (document.languageId !== 'restructuredtext' && !document.fileName.endsWith('.rst')) { + return undefined; + } + return document.fileName; + } + /** + * 显示文件选择器,只选择 .rst 文件 + */ + static async pickRstFile() { + const options = { + canSelectMany: false, + openLabel: '选择 RST 文件', + filters: { + 'reStructuredText 文件': ['rst'], + '所有文件': ['*'] + } + }; + const fileUri = await vscode.window.showOpenDialog(options); + if (fileUri && fileUri[0]) { + return fileUri[0].fsPath; + } + return undefined; + } + /** + * 显示文件选择器,支持多选 .rst 文件 + */ + static async pickRstFiles() { + const options = { + canSelectMany: true, + openLabel: '选择 RST 文件(支持多选)', + filters: { + 'reStructuredText 文件': ['rst'], + '所有文件': ['*'] + } + }; + const fileUris = await vscode.window.showOpenDialog(options); + if (fileUris && fileUris.length > 0) { + return fileUris.map(uri => uri.fsPath); + } + return []; + } + /** + * 检查文件是否存在 + */ + static async fileExists(filePath) { + try { + await fs.promises.access(filePath, fs.constants.F_OK); + return true; + } + catch { + return false; + } + } + /** + * 获取文件名(不含路径) + */ + static getFileName(filePath) { + return path.basename(filePath); + } + /** + * 获取相对路径(相对于工作区) + */ + static getRelativePath(filePath) { + const workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(filePath)); + if (workspaceFolder) { + return path.relative(workspaceFolder.uri.fsPath, filePath); + } + return path.basename(filePath); + } +} +exports.FileUtils = FileUtils; +//# sourceMappingURL=file.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/utils/file.js.map b/tools/rst_optimizer/out/src/utils/file.js.map new file mode 100644 index 0000000000000000000000000000000000000000..b833255e8e4a3041ad10ff11378ff12f82498f19 --- /dev/null +++ b/tools/rst_optimizer/out/src/utils/file.js.map @@ -0,0 +1 @@ +{"version":3,"file":"file.js","sourceRoot":"","sources":["../../../src/utils/file.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/utils/wrap.js b/tools/rst_optimizer/out/src/utils/wrap.js new file mode 100644 index 0000000000000000000000000000000000000000..2e96e9299976eab31b7cb49f6bdf0707b857ef10 --- /dev/null +++ b/tools/rst_optimizer/out/src/utils/wrap.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TextWrapper = void 0; +class TextWrapper { + /** + * 对文本进行硬换行包裹 + * @param text 原始文本 + * @param width 行宽限制 + * @returns 包裹后的文本 + */ + static wrapText(text, width) { + if (width <= 0) { + return text; + } + const lines = text.split('\n'); + const wrappedLines = []; + for (const line of lines) { + // 保留空行 + if (line.trim() === '') { + wrappedLines.push(line); + continue; + } + // 检查是否是 RST 特殊行(不应该被包裹) + if (this.shouldPreserveLine(line)) { + wrappedLines.push(line); + continue; + } + // 对普通文本行进行包裹 + const wrapped = this.wrapLine(line, width); + wrappedLines.push(...wrapped); + } + return wrappedLines.join('\n'); + } + /** + * 检查行是否应该保持原样(不进行包裹) + */ + static shouldPreserveLine(line) { + const trimmed = line.trim(); + // RST 指令行 + if (trimmed.startsWith('.. ')) { + return true; + } + // 标题下划线 + if (/^[\s]*[=\-`:'~^_*+#<>"]{3,}[\s]*$/.test(trimmed)) { + return true; + } + // 代码块内容(通过缩进判断) + if (line.startsWith(' ') || line.startsWith('\t')) { + return true; + } + // 列表项 + if (/^[\s]*[-*+]\s/.test(line) || /^[\s]*\d+\.\s/.test(line)) { + return true; + } + // 表格行 + if (trimmed.includes('|') && trimmed.length > 10) { + return true; + } + // 链接定义 + if (/^[\s]*\.\. _[^:]+:/.test(line)) { + return true; + } + return false; + } + /** + * 包裹单行文本 + */ + static wrapLine(line, width) { + const leadingWhitespace = line.match(/^(\s*)/)?.[1] || ''; + const content = line.trim(); + if (content.length <= width - leadingWhitespace.length) { + return [line]; + } + const words = content.split(/\s+/); + const wrappedLines = []; + let currentLine = leadingWhitespace; + for (const word of words) { + const testLine = currentLine === leadingWhitespace + ? currentLine + word + : currentLine + ' ' + word; + if (testLine.length <= width) { + currentLine = testLine; + } + else { + if (currentLine.trim()) { + wrappedLines.push(currentLine); + } + currentLine = leadingWhitespace + word; + } + } + if (currentLine.trim()) { + wrappedLines.push(currentLine); + } + return wrappedLines.length > 0 ? wrappedLines : [line]; + } +} +exports.TextWrapper = TextWrapper; +//# sourceMappingURL=wrap.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/utils/wrap.js.map b/tools/rst_optimizer/out/src/utils/wrap.js.map new file mode 100644 index 0000000000000000000000000000000000000000..7cac468b505a514b236a99df391315123b989f52 --- /dev/null +++ b/tools/rst_optimizer/out/src/utils/wrap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"wrap.js","sourceRoot":"","sources":["../../../src/utils/wrap.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/views/batchResultsHtml.js b/tools/rst_optimizer/out/src/views/batchResultsHtml.js new file mode 100644 index 0000000000000000000000000000000000000000..3589664370c79be7206070cb0dbb6e7586589c47 --- /dev/null +++ b/tools/rst_optimizer/out/src/views/batchResultsHtml.js @@ -0,0 +1,115 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getBatchResultsHtml = getBatchResultsHtml; +const file_1 = require("../utils/file"); +function getBatchResultsHtml(results) { + const fileItems = results.map((result, index) => { + const fileName = file_1.FileUtils.getFileName(result.filePath); + const relativePath = file_1.FileUtils.getRelativePath(result.filePath); + const originalLength = result.originalText.length; + const optimizedLength = result.optimizedText.length; + const changePercent = Math.round(((optimizedLength - originalLength) / Math.max(1, originalLength)) * 100); + const date = new Date(result.timestamp || Date.now()); + const timeStr = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; + return ` +
+
+ + +
+
+ ${relativePath} + ${timeStr} +
+
+ 原文: ${originalLength} 字符 + 优化后: ${optimizedLength} 字符 + + 变化: ${changePercent >= 0 ? '+' : ''}${changePercent}% + +
+
+ `; + }).join(''); + return ` + + + + + + RST 批量优化结果 + + + +
+
RST 批量优化结果
+
成功优化了 ${results.length} 个文件,请查看结果并选择要应用的文件
+
+
+ + +
+
${fileItems}
+
+ + + + +
+ + + + `; +} +//# sourceMappingURL=batchResultsHtml.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/views/batchResultsHtml.js.map b/tools/rst_optimizer/out/src/views/batchResultsHtml.js.map new file mode 100644 index 0000000000000000000000000000000000000000..16ff781158df316cb0e28c0f669deeb02b8b2ac5 --- /dev/null +++ b/tools/rst_optimizer/out/src/views/batchResultsHtml.js.map @@ -0,0 +1 @@ +{"version":3,"file":"batchResultsHtml.js","sourceRoot":"","sources":["../../../src/views/batchResultsHtml.ts"],"names":[],"mappings":";;AAUA,kDA+GC;AAzHD,wCAA0C;AAU1C,SAAgB,mBAAmB,CAAC,OAA0B;IAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAC9C,MAAM,QAAQ,GAAG,gBAAS,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxD,MAAM,YAAY,GAAG,gBAAS,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChE,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC;QAClD,MAAM,eAAe,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;QACpD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,GAAG,cAAc,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAC3G,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,kBAAkB,EAAE,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAE5E,OAAO;;;4CAGiC,KAAK,0CAA0C,MAAM,CAAC,QAAQ,cAAc,MAAM,CAAC,EAAE;6BACpG,KAAK,0CAA0C,MAAM,CAAC,EAAE,sBAAsB,QAAQ;;;iDAGlE,YAAY;iDACZ,OAAO;;;mCAGrB,cAAc;oCACb,eAAe;8BACrB,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU;kBACxD,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,aAAa;;;;KAI1D,CAAC;IACJ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCA6CgC,OAAO,CAAC,MAAM;;;;;;iCAMtB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BvC,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/views/batchResultsView.js b/tools/rst_optimizer/out/src/views/batchResultsView.js new file mode 100644 index 0000000000000000000000000000000000000000..07bf5b6e94e3a9565f988cb8e522fca64018f19b --- /dev/null +++ b/tools/rst_optimizer/out/src/views/batchResultsView.js @@ -0,0 +1,113 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BatchResultsViewProvider = void 0; +const vscode = __importStar(require("vscode")); +const batchResultsHtml_1 = require("./batchResultsHtml"); +const history_1 = require("../history"); +class BatchResultsViewProvider { + constructor(handlers) { + this._results = []; + this._handlers = handlers; + } + resolveWebviewView(webviewView) { + this._view = webviewView; + webviewView.webview.options = { enableScripts: true }; + this._results = history_1.HistoryStore.getAll(); + this.updateHtml(); + webviewView.webview.onDidReceiveMessage(async (message) => { + switch (message.command) { + case 'applyAll': + await this._handlers.onApplyAll(this._results); + break; + case 'applySelected': + await this._handlers.onApplySelected(this._results, message.selectedFiles || []); + break; + case 'viewDiff': + if (message.id) { + await this._handlers.onViewDiffById(message.id); + } + break; + case 'deleteItem': + if (message.id) { + history_1.HistoryStore.removeById(message.id); + this._results = history_1.HistoryStore.getAll(); + this.updateHtml(); + } + break; + case 'deleteSelected': + if (Array.isArray(message.ids) && message.ids.length) { + for (const id of message.ids) { + history_1.HistoryStore.removeById(id); + } + this._results = history_1.HistoryStore.getAll(); + this.updateHtml(); + } + break; + case 'discard': + await this._handlers.onDiscard(); + break; + } + }); + } + async showResults(results) { + // Append into history store and refresh from it + if (results && results.length) { + // results may not carry id/timestamp when passed in; ensure persistence creates them + const plain = results.map(r => ({ filePath: r.filePath, originalText: r.originalText, optimizedText: r.optimizedText })); + history_1.HistoryStore.addMany(plain); + } + this._results = history_1.HistoryStore.getAll(); + this.updateHtml(); + await vscode.commands.executeCommand('workbench.view.explorer'); + await vscode.commands.executeCommand('workbench.view.extension.rstOptimizer'); // in case moved later + await vscode.commands.executeCommand('rstOptimizer.revealBatchResultsView'); + } + updateHtml() { + if (!this._view) + return; + this._view.webview.html = (0, batchResultsHtml_1.getBatchResultsHtml)(this._results); + } + reveal() { + this._view?.show?.(true); + } + refreshFromStore() { + this._results = history_1.HistoryStore.getAll(); + this.updateHtml(); + } +} +exports.BatchResultsViewProvider = BatchResultsViewProvider; +BatchResultsViewProvider.ViewId = 'rstOptimizer.batchResults'; +//# sourceMappingURL=batchResultsView.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/src/views/batchResultsView.js.map b/tools/rst_optimizer/out/src/views/batchResultsView.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a910215b943f6dfb261eb61a5e51455c703d3698 --- /dev/null +++ b/tools/rst_optimizer/out/src/views/batchResultsView.js.map @@ -0,0 +1 @@ +{"version":3,"file":"batchResultsView.js","sourceRoot":"","sources":["../../../src/views/batchResultsView.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/runTest.js b/tools/rst_optimizer/out/test/runTest.js new file mode 100644 index 0000000000000000000000000000000000000000..a23c16eed2d1120b16cb231828e07c4b63973384 --- /dev/null +++ b/tools/rst_optimizer/out/test/runTest.js @@ -0,0 +1,53 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __importStar(require("path")); +const test_electron_1 = require("@vscode/test-electron"); +async function main() { + try { + // 扩展开发文件夹路径 + const extensionDevelopmentPath = path.resolve(__dirname, '../../'); + // 测试套件路径 + const extensionTestsPath = path.resolve(__dirname, './suite/index'); + // 下载 VS Code,解压并运行集成测试 + await (0, test_electron_1.runTests)({ extensionDevelopmentPath, extensionTestsPath }); + } + catch (err) { + console.error('测试运行失败'); + process.exit(1); + } +} +main(); +//# sourceMappingURL=runTest.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/runTest.js.map b/tools/rst_optimizer/out/test/runTest.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a612a828ec18dade9fa0fa5233fe17804067abec --- /dev/null +++ b/tools/rst_optimizer/out/test/runTest.js.map @@ -0,0 +1 @@ +{"version":3,"file":"runTest.js","sourceRoot":"","sources":["../../test/runTest.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA6B;AAE7B,yDAAiD;AAEjD,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,YAAY;QACZ,MAAM,wBAAwB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEnE,SAAS;QACT,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QAEpE,uBAAuB;QACvB,MAAM,IAAA,wBAAQ,EAAC,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/suite/extension.test.js b/tools/rst_optimizer/out/test/suite/extension.test.js new file mode 100644 index 0000000000000000000000000000000000000000..6245a64e90bc0773fd05522c97d869953275a5d9 --- /dev/null +++ b/tools/rst_optimizer/out/test/suite/extension.test.js @@ -0,0 +1,95 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +const assert = __importStar(require("assert")); +const vscode = __importStar(require("vscode")); +const config_1 = require("../../src/config"); +suite('扩展测试套件', () => { + vscode.window.showInformationMessage('开始运行所有测试。'); + test('扩展应该被激活', async () => { + const extension = vscode.extensions.getExtension('undefined_publisher.rst-optimizer'); + assert.ok(extension); + if (!extension.isActive) { + await extension.activate(); + } + assert.ok(extension.isActive); + }); + test('所有命令应该被注册', async () => { + const commands = await vscode.commands.getCommands(true); + const expectedCommands = [ + 'rstOptimizer.optimizeCurrent', + 'rstOptimizer.optimizePickFile', + 'rstOptimizer.applyResult', + 'rstOptimizer.openSettings', + 'rstOptimizer.showQuickPick' + ]; + for (const command of expectedCommands) { + assert.ok(commands.includes(command), `命令 ${command} 应该被注册`); + } + }); +}); +suite('配置管理测试', () => { + test('应该能够读取默认配置', () => { + const config = config_1.ConfigManager.getConfig(); + assert.strictEqual(config.provider, 'openai-compatible'); + assert.strictEqual(config.baseUrl, 'https://api.openai.com/v1'); + assert.strictEqual(config.model, 'gpt-4o-mini'); + assert.strictEqual(config.maxTokens, 4096); + assert.strictEqual(config.temperature, 0.3); + assert.strictEqual(config.neverUploadIfWorkspaceTrusted, false); + assert.strictEqual(config.rewrapWidth, 0); + }); + test('应该验证配置错误', () => { + const invalidConfig = { + provider: 'openai-compatible', + baseUrl: '', + model: '', + apiKey: '', + userPrompt: '测试提示', + maxTokens: -1, + temperature: 3, + neverUploadIfWorkspaceTrusted: false, + rewrapWidth: 0 + }; + const errors = config_1.ConfigManager.validateConfig(invalidConfig); + assert.ok(errors.length > 0, '应该检测到配置错误'); + assert.ok(errors.some(e => e.includes('API 基础 URL')), '应该检测到空的基础 URL'); + assert.ok(errors.some(e => e.includes('模型名称')), '应该检测到空的模型名称'); + assert.ok(errors.some(e => e.includes('API 密钥')), '应该检测到空的 API 密钥'); + assert.ok(errors.some(e => e.includes('最大 token')), '应该检测到无效的最大 token'); + assert.ok(errors.some(e => e.includes('温度值')), '应该检测到无效的温度值'); + }); +}); +//# sourceMappingURL=extension.test.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/suite/extension.test.js.map b/tools/rst_optimizer/out/test/suite/extension.test.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a66457955d26aec798dc06da5d4075a9abc5f4f3 --- /dev/null +++ b/tools/rst_optimizer/out/test/suite/extension.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.test.js","sourceRoot":"","sources":["../../../test/suite/extension.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/suite/index.js b/tools/rst_optimizer/out/test/suite/index.js new file mode 100644 index 0000000000000000000000000000000000000000..4cf8e4ef30497f2bed8baf1ff8069e2f5dfd236e --- /dev/null +++ b/tools/rst_optimizer/out/test/suite/index.js @@ -0,0 +1,71 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.run = run; +const path = __importStar(require("path")); +const glob_1 = require("glob"); +function run() { + const testsRoot = path.resolve(__dirname, '..'); + return new Promise((resolve, reject) => { + (0, glob_1.glob)('**/**.test.js', { cwd: testsRoot }) + .then((files) => { + // 动态导入 Mocha + const Mocha = require('mocha'); + const mocha = new Mocha({ + ui: 'tdd', + color: true + }); + // 添加文件到测试套件 + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); + try { + // 运行 Mocha 测试 + mocha.run((failures) => { + if (failures > 0) { + reject(new Error(`${failures} 个测试失败。`)); + } + else { + resolve(); + } + }); + } + catch (err) { + console.error(err); + reject(err); + } + }) + .catch(reject); + }); +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/suite/index.js.map b/tools/rst_optimizer/out/test/suite/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..348a4591d5b05d66b4516ea440a99228c36986cc --- /dev/null +++ b/tools/rst_optimizer/out/test/suite/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../test/suite/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,kBAgCC;AAnCD,2CAA6B;AAC7B,+BAA4B;AAE5B,SAAgB,GAAG;IACjB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEhD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAA,WAAI,EAAC,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;aACtC,IAAI,CAAC,CAAC,KAAe,EAAE,EAAE;YACxB,aAAa;YACb,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YAC/B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;gBACtB,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;YAEH,YAAY;YACZ,KAAK,CAAC,OAAO,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAExE,IAAI,CAAC;gBACH,cAAc;gBACd,KAAK,CAAC,GAAG,CAAC,CAAC,QAAgB,EAAE,EAAE;oBAC7B,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;wBACjB,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,QAAQ,SAAS,CAAC,CAAC,CAAC;oBAC1C,CAAC;yBAAM,CAAC;wBACN,OAAO,EAAE,CAAC;oBACZ,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACnB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/suite/virtualDoc.test.js b/tools/rst_optimizer/out/test/suite/virtualDoc.test.js new file mode 100644 index 0000000000000000000000000000000000000000..9d5ecb32b9ee4f4fcebabf277ca4ad3646e4cb7c --- /dev/null +++ b/tools/rst_optimizer/out/test/suite/virtualDoc.test.js @@ -0,0 +1,91 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +const assert = __importStar(require("assert")); +const virtualDocProvider_1 = require("../../src/diff/virtualDocProvider"); +suite('虚拟文档提供者测试', () => { + let provider; + setup(() => { + provider = new virtualDocProvider_1.VirtualDocProvider(); + }); + test('应该能够创建 URI', () => { + const filePath = '/test/file.rst'; + const originalUri = virtualDocProvider_1.VirtualDocProvider.createUri('original', filePath); + const optimizedUri = virtualDocProvider_1.VirtualDocProvider.createUri('optimized', filePath); + assert.ok(originalUri.scheme === virtualDocProvider_1.VirtualDocProvider.getScheme()); + assert.ok(optimizedUri.scheme === virtualDocProvider_1.VirtualDocProvider.getScheme()); + assert.ok(originalUri.path.includes('original')); + assert.ok(optimizedUri.path.includes('optimized')); + assert.ok(originalUri.path.includes(encodeURIComponent(filePath))); + assert.ok(optimizedUri.path.includes(encodeURIComponent(filePath))); + }); + test('应该能够设置和获取内容', () => { + const filePath = '/test/file.rst'; + const uri = virtualDocProvider_1.VirtualDocProvider.createUri('original', filePath); + const content = '这是测试内容'; + provider.set(uri, content); + const retrievedContent = provider.provideTextDocumentContent(uri); + assert.strictEqual(retrievedContent, content); + }); + test('应该能够清除内容', () => { + const filePath = '/test/file.rst'; + const uri = virtualDocProvider_1.VirtualDocProvider.createUri('original', filePath); + const content = '这是测试内容'; + provider.set(uri, content); + assert.strictEqual(provider.provideTextDocumentContent(uri), content); + provider.clear(uri); + assert.strictEqual(provider.provideTextDocumentContent(uri), undefined); + }); + test('应该能够清除所有内容', () => { + const filePath1 = '/test/file1.rst'; + const filePath2 = '/test/file2.rst'; + const uri1 = virtualDocProvider_1.VirtualDocProvider.createUri('original', filePath1); + const uri2 = virtualDocProvider_1.VirtualDocProvider.createUri('optimized', filePath2); + provider.set(uri1, '内容1'); + provider.set(uri2, '内容2'); + assert.strictEqual(provider.provideTextDocumentContent(uri1), '内容1'); + assert.strictEqual(provider.provideTextDocumentContent(uri2), '内容2'); + provider.clearAll(); + assert.strictEqual(provider.provideTextDocumentContent(uri1), undefined); + assert.strictEqual(provider.provideTextDocumentContent(uri2), undefined); + }); + test('不存在的 URI 应该返回 undefined', () => { + const filePath = '/test/nonexistent.rst'; + const uri = virtualDocProvider_1.VirtualDocProvider.createUri('original', filePath); + const content = provider.provideTextDocumentContent(uri); + assert.strictEqual(content, undefined); + }); +}); +//# sourceMappingURL=virtualDoc.test.js.map \ No newline at end of file diff --git a/tools/rst_optimizer/out/test/suite/virtualDoc.test.js.map b/tools/rst_optimizer/out/test/suite/virtualDoc.test.js.map new file mode 100644 index 0000000000000000000000000000000000000000..d32c0589fc3ed5d2aa4c9108c0d86de0eb1f6445 --- /dev/null +++ b/tools/rst_optimizer/out/test/suite/virtualDoc.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"virtualDoc.test.js","sourceRoot":"","sources":["../../../test/suite/virtualDoc.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tools/rst_optimizer/rst-optimizer-0.0.1.vsix b/tools/rst_optimizer/rst-optimizer-0.0.1.vsix new file mode 100644 index 0000000000000000000000000000000000000000..5580a807f2d22b9ce7c7dfa4ee1f3cf9643e3980 Binary files /dev/null and b/tools/rst_optimizer/rst-optimizer-0.0.1.vsix differ