From be0555d6bc18d2a032237343485be9f62f5a941c Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Fri, 6 Mar 2026 08:59:02 +0800 Subject: [PATCH] feat:codeToChat --- docs/code-to-chat-feature.md | 42 ++++++++++++++ package.json | 22 ++++++++ src/extension.ts | 85 ++++++++++++++++++++++++++++- src/panels/ICHelperPanel.ts | 3 + src/providers/codeActionProvider.ts | 26 +++++++++ src/views/contextDisplay.ts | 20 ++++++- 6 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 docs/code-to-chat-feature.md create mode 100644 src/providers/codeActionProvider.ts diff --git a/docs/code-to-chat-feature.md b/docs/code-to-chat-feature.md new file mode 100644 index 0000000..56b673f --- /dev/null +++ b/docs/code-to-chat-feature.md @@ -0,0 +1,42 @@ +# 代码快速添加到对话功能 + +## 功能说明 + +选中代码后,通过右键菜单/小灯泡/快捷键(Ctrl+Shift+I),将代码作为上下文添加到聊天面板输入框上方。 + +## 实现方式 + +### 1. Code Action Provider +`src/providers/codeActionProvider.ts` - 提供小灯泡菜单选项 + +### 2. 命令注册 +`src/extension.ts` - 注册 `ic-coder.addCodeToChat` 命令,发送消息到 webview + +### 3. 全局引用 +`src/panels/ICHelperPanel.ts` - 保存 panel 到 `(global as any).currentICHelperPanel` + +### 4. 上下文显示 +`src/views/contextDisplay.ts` - 添加 `code` 类型支持和 `addCodeContext` 消息处理 + +### 5. 配置 +`package.json` - 配置命令、右键菜单、快捷键 + +## 用户体验 + +1. 选中代码 +2. 右键/小灯泡/Ctrl+Shift+I +3. 代码显示为上下文项:`文件名.v:10-25` 📄 +4. 输入问题发送(代码自动作为上下文) + +## 数据结构 + +代码上下文存储为 JSON: +```json +{ + "fileName": "路径", + "startLine": 10, + "endLine": 25, + "code": "代码内容", + "languageId": "verilog" +} +``` diff --git a/package.json b/package.json index a4b969d..e01c66e 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,28 @@ "command": "ic-coder.testNotification", "title": "测试系统通知", "category": "IC Coder" + }, + { + "command": "ic-coder.addCodeToChat", + "title": "添加到 IC Coder 对话", + "category": "IC Coder" + } + ], + "menus": { + "editor/context": [ + { + "command": "ic-coder.addCodeToChat", + "when": "editorHasSelection", + "group": "9_cutcopypaste" + } + ] + }, + "keybindings": [ + { + "command": "ic-coder.addCodeToChat", + "key": "ctrl+l", + "mac": "cmd+l", + "when": "editorTextFocus && editorHasSelection" } ], "viewsContainers": { diff --git a/src/extension.ts b/src/extension.ts index 1517e52..5307e02 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -10,10 +10,42 @@ import { initCreditsService } from "./services/creditsService"; import { isTokenExpired } from "./utils/jwtUtils"; import { NotificationService } from "./services/notificationService"; import { InvitationService } from "./services/invitationService"; +import { ICCoderCodeActionProvider } from "./providers/codeActionProvider"; export async function activate(context: vscode.ExtensionContext) { console.log("🎉 IC Coder 插件已激活!"); + // 创建装饰类型(代码旁边的提示) + const decorationType = vscode.window.createTextEditorDecorationType({ + after: { + contentText: ' Ctrl+L 添加到 IC Coder 对话', + color: '#888', + fontStyle: 'italic', + margin: '0 0 0 1em' + } + }); + + // 更新装饰 + const updateDecorations = () => { + const editor = vscode.window.activeTextEditor; + if (!editor) return; + + if (!editor.selection.isEmpty) { + const range = new vscode.Range(editor.selection.end, editor.selection.end); + const decoration = { range }; + editor.setDecorations(decorationType, [decoration]); + } else { + editor.setDecorations(decorationType, []); + } + }; + + context.subscriptions.push( + vscode.window.onDidChangeTextEditorSelection(updateDecorations), + vscode.window.onDidChangeActiveTextEditor(updateDecorations) + ); + + updateDecorations(); + // 初始化通知服务 const notificationService = NotificationService.getInstance(context); console.log('[Extension] 通知服务已初始化'); @@ -250,6 +282,48 @@ export async function activate(context: vscode.ExtensionContext) { } ); + // 注册命令:将选中代码添加到对话 + const addCodeToChat = vscode.commands.registerCommand( + "ic-coder.addCodeToChat", + async () => { + const editor = vscode.window.activeTextEditor; + if (!editor) return; + + const selection = editor.selection; + const selectedText = editor.document.getText(selection); + + if (!selectedText) { + vscode.window.showWarningMessage("请先选择代码"); + return; + } + + const fileName = editor.document.fileName; + const startLine = selection.start.line + 1; + const endLine = selection.end.line + 1; + + // 检查是否已有打开的面板 + let panel = (global as any).currentICHelperPanel; + if (!panel || panel._isDisposed) { + await showICHelperPanel(context); + panel = (global as any).currentICHelperPanel; + } + + // 发送代码上下文 + setTimeout(() => { + if (panel?.webview) { + panel.webview.postMessage({ + command: 'addCodeContext', + fileName, + startLine, + endLine, + code: selectedText, + languageId: editor.document.languageId + }); + } + }, 300); + } + ); + // 注册命令:查看会话历史 // TODO: 这些命令需要根据新的任务架构重新实现 // 暂时注释掉,等待重新实现 @@ -312,6 +386,13 @@ export async function activate(context: vscode.ExtensionContext) { // 注册 VCD 自定义编辑器 const vcdEditorProvider = VCDViewerEditorProvider.register(context, vcdFileServer); + // 注册 Code Action Provider + const codeActionProvider = vscode.languages.registerCodeActionsProvider( + { scheme: 'file' }, + new ICCoderCodeActionProvider(), + { providedCodeActionKinds: [vscode.CodeActionKind.RefactorRewrite] } + ); + // 添加到订阅 context.subscriptions.push( openPanelCommand, @@ -322,6 +403,7 @@ export async function activate(context: vscode.ExtensionContext) { logoutCommand, changeInvitationCodeCommand, testNotificationCommand, + addCodeToChat, // testTrialUserCommand, // testExpiredUserCommand, // TODO: 等待重新实现这些命令 @@ -332,7 +414,8 @@ export async function activate(context: vscode.ExtensionContext) { // clearHistoryCommand, // searchSessionCommand, viewRegistration, - vcdEditorProvider + vcdEditorProvider, + codeActionProvider ); } diff --git a/src/panels/ICHelperPanel.ts b/src/panels/ICHelperPanel.ts index bd9e660..fade7a0 100644 --- a/src/panels/ICHelperPanel.ts +++ b/src/panels/ICHelperPanel.ts @@ -143,6 +143,9 @@ export async function showICHelperPanel( }, ); + // 保存 panel 引用到全局 + (global as any).currentICHelperPanel = panel; + // 为面板生成唯一ID const panelId = `panel_${Date.now()}_${Math.random() .toString(36) diff --git a/src/providers/codeActionProvider.ts b/src/providers/codeActionProvider.ts new file mode 100644 index 0000000..715e7ee --- /dev/null +++ b/src/providers/codeActionProvider.ts @@ -0,0 +1,26 @@ +/** + * Code Action Provider - 为选中代码提供快捷操作 + * 功能:在小灯泡菜单中显示"添加到 IC Coder 对话"选项 + */ +import * as vscode from 'vscode'; + +export class ICCoderCodeActionProvider implements vscode.CodeActionProvider { + provideCodeActions( + document: vscode.TextDocument, + range: vscode.Range + ): vscode.CodeAction[] { + const selectedText = document.getText(range); + if (!selectedText) return []; + + const action = new vscode.CodeAction( + '💬 添加到 IC Coder 对话', + vscode.CodeActionKind.RefactorRewrite + ); + action.command = { + command: 'ic-coder.addCodeToChat', + title: '添加到对话' + }; + + return [action]; + } +} diff --git a/src/views/contextDisplay.ts b/src/views/contextDisplay.ts index 6ff0355..98fd2b3 100644 --- a/src/views/contextDisplay.ts +++ b/src/views/contextDisplay.ts @@ -126,6 +126,11 @@ export function getContextDisplayScript(): string { return ''; } + // 获取代码图标 SVG + function getCodeIcon() { + return ''; + } + // 获取删除图标 SVG function getRemoveIcon() { return ''; @@ -172,10 +177,11 @@ export function getContextDisplayScript(): string { case 'folder': icon = getFolderIcon(); break; case 'image': icon = getImageIcon(); break; case 'document': icon = getDocumentIcon(); break; + case 'code': icon = getCodeIcon(); break; } return \` -
+
\${icon} \${item.displayPath || getFileName(item.path)} @@ -211,6 +217,18 @@ export function getContextDisplayScript(): string { message.documents.forEach(doc => addContextItem('document', doc)); } break; + case 'addCodeContext': + // 添加代码上下文 + const displayName = \`\${message.fileName.split(/[\\\\/]/).pop()}:\${message.startLine}-\${message.endLine}\`; + const codeData = { + fileName: message.fileName, + startLine: message.startLine, + endLine: message.endLine, + code: message.code, + languageId: message.languageId + }; + addContextItem('code', JSON.stringify(codeData), displayName); + break; } });