From d415d8ee4e5e785cd7691002ef6d85382d87e048 Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Tue, 30 Dec 2025 15:02:28 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E6=9C=8D=E5=8A=A1=E5=9C=B0=E5=9D=80=E4=B8=BA192.168.1?= =?UTF-8?q?.108?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 003c9cf..6587717 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "properties": { "icCoder.backendUrl": { "type": "string", - "default": "http://localhost:2233", + "default": "http://192.168.1.108:2233", "description": "后端服务地址" }, "icCoder.timeout": { From 0f458f629916bac98dcb8fbece61755db3e5d7ba Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Tue, 30 Dec 2025 15:35:35 +0800 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E6=B3=A2?= =?UTF-8?q?=E5=BD=A2=E9=A2=84=E8=A7=88=E8=84=9A=E6=9C=AC=E7=BB=98=E5=88=B6?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E6=94=AF=E6=8C=81=E5=8D=95=E6=AF=94?= =?UTF-8?q?=E7=89=B9=E5=92=8C=E5=A4=9A=E6=AF=94=E7=89=B9=E4=BF=A1=E5=8F=B7?= =?UTF-8?q?=E7=9A=84=E4=B8=8D=E5=90=8C=E7=BB=98=E5=88=B6=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/waveformPreviewContent.ts | 84 +++++++++++++++-------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/src/views/waveformPreviewContent.ts b/src/views/waveformPreviewContent.ts index 6c98a77..9e20df4 100644 --- a/src/views/waveformPreviewContent.ts +++ b/src/views/waveformPreviewContent.ts @@ -263,61 +263,63 @@ export function getWaveformPreviewScript(): string { const timeRange = maxTime - minTime || 1; // 绘制波形 - let pathData = ''; - let lastX = leftMargin; - let lastValue = signal.values[0].value; + if (signal.width === 1) { + // 单比特信号 - 绘制数字波形 + let pathData = ''; + const yHigh = y; + const yLow = y + signalHeight; - signal.values.forEach((point, i) => { - const x = leftMargin + ((point.time - minTime) / timeRange) * waveformWidth; - const value = point.value; - - if (signal.width === 1) { - // 单比特信号 - 绘制数字波形 - const yHigh = y; - const yLow = y + signalHeight; - const currentY = (value === '1') ? yHigh : yLow; + signal.values.forEach((point, i) => { + const x = leftMargin + ((point.time - minTime) / timeRange) * waveformWidth; + const currentY = (point.value === '1') ? yHigh : yLow; if (i === 0) { pathData = \`M \${x} \${currentY}\`; } else { - // 绘制垂直跳变 - const prevY = (lastValue === '1') ? yHigh : yLow; + const prevValue = signal.values[i - 1].value; + const prevY = (prevValue === '1') ? yHigh : yLow; if (prevY !== currentY) { pathData += \` L \${x} \${prevY} L \${x} \${currentY}\`; } else { pathData += \` L \${x} \${currentY}\`; } } + }); - lastValue = value; - lastX = x; - } else { - // 多比特信号 - 绘制总线波形(梯形) - const yTop = y + 5; - const yBottom = y + signalHeight - 5; - const transitionWidth = 5; - - if (i === 0) { - pathData = \`M \${x} \${yTop + (yBottom - yTop) / 2}\`; - } else { - // 绘制梯形过渡 - pathData += \` L \${x - transitionWidth} \${yTop} L \${x} \${yTop + (yBottom - yTop) / 2}\`; - } - - lastX = x; - } - }); - - // 延伸到右边界 - if (signal.width === 1) { - const lastY = (lastValue === '1') ? y : (y + signalHeight); + // 延伸到右边界 + const lastValue = signal.values[signal.values.length - 1].value; + const lastY = (lastValue === '1') ? yHigh : yLow; pathData += \` L \${leftMargin + waveformWidth} \${lastY}\`; - } else { - const yMid = y + signalHeight / 2; - pathData += \` L \${leftMargin + waveformWidth} \${yMid}\`; - } - svgContent += \`\`; + svgContent += \`\`; + } else { + // 多比特信号 - 绘制总线波形(上下双线) + const yTop = y + 5; + const yBottom = y + signalHeight - 5; + const transitionWidth = 4; + + let topPath = \`M \${leftMargin} \${yTop}\`; + let bottomPath = \`M \${leftMargin} \${yBottom}\`; + + signal.values.forEach((point, i) => { + const x = leftMargin + ((point.time - minTime) / timeRange) * waveformWidth; + + // 上线和下线都延伸到变化点 + topPath += \` L \${x} \${yTop}\`; + bottomPath += \` L \${x} \${yBottom}\`; + + // 绘制梯形过渡 + topPath += \` L \${x + transitionWidth} \${yBottom} L \${x + transitionWidth} \${yTop}\`; + bottomPath += \` L \${x + transitionWidth} \${yTop} L \${x + transitionWidth} \${yBottom}\`; + }); + + // 延伸到右边界 + topPath += \` L \${leftMargin + waveformWidth} \${yTop}\`; + bottomPath += \` L \${leftMargin + waveformWidth} \${yBottom}\`; + + svgContent += \`\`; + svgContent += \`\`; + } }); // 绘制时间轴 From 3f0cc8ae29f5e4d6c6c6bc8d893647a0eba0f314 Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Tue, 30 Dec 2025 16:02:36 +0800 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E5=8C=BA=E7=8A=B6=E6=80=81=E6=A3=80=E6=9F=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=20-=20=E7=94=A8=E6=88=B7=E9=BC=A0=E6=A0=87=E8=81=9A?= =?UTF-8?q?=E7=84=A6=E5=88=B0=E8=BE=93=E5=85=A5=E6=A1=86=E4=B8=AD=E5=B0=B1?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E6=8F=90=E7=A4=BA=E7=94=A8=E6=88=B7=E6=89=93?= =?UTF-8?q?=E5=BC=80=20=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7=E4=BD=93?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/panels/ICHelperPanel.ts | 20 +++++++++++++ src/utils/createFiles.ts | 56 ++++++++++++++++++++++++++----------- src/views/inputArea.ts | 23 +++++++++++++-- src/views/webviewContent.ts | 10 +++++-- 4 files changed, 88 insertions(+), 21 deletions(-) diff --git a/src/panels/ICHelperPanel.ts b/src/panels/ICHelperPanel.ts index f9d227e..4aecdca 100644 --- a/src/panels/ICHelperPanel.ts +++ b/src/panels/ICHelperPanel.ts @@ -181,6 +181,26 @@ export async function showICHelperPanel( case "abortDialog": abortCurrentDialog(); break; + // 新增:检查工作区状态 + case "checkWorkspace": + const hasWorkspace = !!(vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0); + if (!hasWorkspace) { + // 弹窗提示用户需要打开工作区 + vscode.window.showWarningMessage( + "请先打开一个文件夹作为工作区,这样我就能更好地为您服务了 😊", + "打开文件夹" + ).then((selection) => { + if (selection === "打开文件夹") { + vscode.commands.executeCommand("vscode.openFolder"); + } + }); + } + // 返回工作区状态给前端 + panel.webview.postMessage({ + command: "workspaceStatus", + hasWorkspace: hasWorkspace + }); + break; } }, undefined, diff --git a/src/utils/createFiles.ts b/src/utils/createFiles.ts index cf1d8a5..c8a089c 100644 --- a/src/utils/createFiles.ts +++ b/src/utils/createFiles.ts @@ -16,7 +16,9 @@ export async function createFile( if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); } else { - throw new Error("没有打开的工作区,无法创建相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您创建文件了" + ); } } @@ -28,7 +30,7 @@ export async function createFile( throw new Error(`文件已存在: ${absolutePath}`); } catch (error: any) { // 如果文件不存在,继续创建 - if (error.code !== 'FileNotFound') { + if (error.code !== "FileNotFound") { throw error; } } @@ -65,7 +67,9 @@ export async function createOrOverwriteFile( if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); } else { - throw new Error("没有打开的工作区,无法创建相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您创建文件了" + ); } } @@ -99,7 +103,9 @@ export async function createDirectory(dirPath: string): Promise { if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, dirPath); } else { - throw new Error("没有打开的工作区,无法创建相对路径的目录"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您创建目录了" + ); } } @@ -115,7 +121,7 @@ export async function createDirectory(dirPath: string): Promise { } } catch (error: any) { // 如果目录不存在,继续创建 - if (error.code !== 'FileNotFound') { + if (error.code !== "FileNotFound") { throw error; } } @@ -161,7 +167,9 @@ export async function deleteFile(filePath: string): Promise { if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); } else { - throw new Error("没有打开的工作区,无法删除相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您删除文件了" + ); } } @@ -197,7 +205,9 @@ export async function updateFile( if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); } else { - throw new Error("没有打开的工作区,无法修改相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您修改文件了" + ); } } @@ -236,7 +246,9 @@ export async function appendToFile( if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); } else { - throw new Error("没有打开的工作区,无法追加相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您追加文件内容了" + ); } } @@ -274,7 +286,9 @@ export async function replaceFile( if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); } else { - throw new Error("没有打开的工作区,无法修改相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您修改文件了" + ); } } @@ -291,14 +305,17 @@ export async function replaceFile( // 转义特殊字符,将字符串作为字面量处理 const escapeRegExp = (str: string) => { - return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }; // 替换内容 - 如果是字符串,先转义特殊字符 let newContent: string; - if (typeof searchValue === 'string') { + if (typeof searchValue === "string") { const escapedSearch = escapeRegExp(searchValue); - newContent = fileContent.replace(new RegExp(escapedSearch, "g"), replaceValue); + newContent = fileContent.replace( + new RegExp(escapedSearch, "g"), + replaceValue + ); } else { newContent = fileContent.replace(searchValue, replaceValue); } @@ -330,7 +347,9 @@ export async function insertAtLine( if (workspaceFolders && workspaceFolders.length > 0) { absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); } else { - throw new Error("没有打开的工作区,无法修改相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您修改文件了" + ); } } @@ -382,7 +401,9 @@ export async function renameFile( absoluteNewPath = path.join(workspaceRoot, newPath); } } else { - throw new Error("没有打开的工作区,无法重命名相对路径的文件"); + throw new Error( + "请先打开一个文件夹作为工作区,这样我就能为您重命名文件了" + ); } const oldUri = vscode.Uri.file(absoluteOldPath); @@ -401,10 +422,13 @@ export async function renameFile( throw new Error(`目标文件已存在: ${absoluteNewPath}`); } catch (error: any) { // 如果文件不存在,继续重命名 - if (error.code !== 'FileNotFound' && !error.message.includes('目标文件已存在')) { + if ( + error.code !== "FileNotFound" && + !error.message.includes("目标文件已存在") + ) { throw error; } - if (error.message.includes('目标文件已存在')) { + if (error.message.includes("目标文件已存在")) { throw error; } } diff --git a/src/views/inputArea.ts b/src/views/inputArea.ts index a0ec703..fcef3bf 100644 --- a/src/views/inputArea.ts +++ b/src/views/inputArea.ts @@ -271,6 +271,10 @@ export function getInputAreaScript(): string { // 对话状态管理 let isConversationActive = false; + // 工作区检测状态 + let hasCheckedWorkspace = false; // 是否已经检测过工作区 + let hasWorkspace = true; // 工作区状态 + // 自动调整 textarea 高度 function autoResizeTextarea() { if (messageInput) { @@ -283,11 +287,16 @@ export function getInputAreaScript(): string { if (messageInput) { messageInput.addEventListener('input', autoResizeTextarea); + // 监听点击事件,检测工作区状态 + messageInput.addEventListener('focus', () => { + if (!hasCheckedWorkspace) { + hasCheckedWorkspace = true; + vscode.postMessage({ command: 'checkWorkspace' }); + } + }); + // 初始化时调整一次高度 autoResizeTextarea(); - - // 聚焦到输入框 - messageInput.focus(); } // 切换发送按钮状态 @@ -326,6 +335,14 @@ export function getInputAreaScript(): string { const text = messageInput.value.trim(); if (!text) return; + // 检查工作区状态 + if (!hasWorkspace) { + // 如果没有工作区,阻止发送并清空输入框 + messageInput.value = ''; + autoResizeTextarea(); + return; + } + const mode = getCurrentMode(); // 从模式选择器组件获取当前模式 const model = getCurrentModel(); // 从模型选择器组件获取当前模型 diff --git a/src/views/webviewContent.ts b/src/views/webviewContent.ts index c586f31..db19a9b 100644 --- a/src/views/webviewContent.ts +++ b/src/views/webviewContent.ts @@ -443,8 +443,6 @@ export function getWebviewContent(iconUri?: string): string { } } - messageInput.focus(); - // 监听来自插件的消息 window.addEventListener('message', event => { const message = event.data; @@ -516,6 +514,14 @@ export function getWebviewContent(iconUri?: string): string { hideLoadingIndicator(); break; + case 'workspaceStatus': + // 更新工作区状态 + if (typeof hasWorkspace !== 'undefined') { + hasWorkspace = message.hasWorkspace; + console.log('[WebView] 工作区状态:', hasWorkspace); + } + break; + case 'vcdInfo': // 渲染迷你波形预览信息 try { From c42ebdfe597bc425e1b9fc87511d0c70b39ef8a9 Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Tue, 30 Dec 2025 16:10:49 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=90=8E=E7=AB=AF=E6=9C=8D=E5=8A=A1=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E4=B8=BA192.168.1.108?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/settings.ts b/src/config/settings.ts index e6c041f..8b6e490 100644 --- a/src/config/settings.ts +++ b/src/config/settings.ts @@ -16,7 +16,7 @@ export interface IccoderConfig { /** 默认配置 */ const DEFAULT_CONFIG: IccoderConfig = { - backendUrl: "http://localhost:8080", + backendUrl: "http://192.168.1.108:2233", timeout: 60000, userId: "default-user", }; From 02b56a7031b7b3b8fbc47fd2acb82ce6870a15f4 Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Tue, 30 Dec 2025 16:49:49 +0800 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E5=88=86=E7=B1=BB=E4=B8=BA=E8=81=8A=E5=A4=A9=E5=92=8C?= =?UTF-8?q?=E7=BC=96=E7=A8=8B=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6587717..c6a416a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ }, "icon": "media/icon.png", "categories": [ - "Other" + "Chat", + "Programming Languages" ], "keywords": [ "IC", From 842e5fb49bc5e079d1fc19132492a2a30d4e0e7a Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Tue, 30 Dec 2025 20:48:32 +0800 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20=E7=A7=BB=E9=99=A4=E8=AE=A1?= =?UTF-8?q?=E5=88=92=E5=88=87=E6=8D=A2=E7=9B=B8=E5=85=B3=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E5=92=8C=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/inputArea.ts | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/views/inputArea.ts b/src/views/inputArea.ts index 8564c81..dc3d0f8 100644 --- a/src/views/inputArea.ts +++ b/src/views/inputArea.ts @@ -2,37 +2,29 @@ import { getWaveformPreviewContent } from "./waveformPreviewContent"; import { getModelSelectorContent, getModelSelectorStyles, - getModelSelectorScript + getModelSelectorScript, } from "./modelSelector"; import { getModeSelectorContent, getModeSelectorStyles, - getModeSelectorScript + getModeSelectorScript, } from "./agentModeSelector"; import { getContextButtonContent, getContextButtonStyles, - getContextButtonScript + getContextButtonScript, } from "./contextButton"; import { getContextCompressContent, getContextCompressStyles, - getContextCompressScript + getContextCompressScript, } from "./contextCompress"; -import { - getPlanToggleContent, - getPlanToggleStyles, - getPlanToggleScript -} from "./planToggle"; import { getOptimizeButtonContent, getOptimizeButtonStyles, - getOptimizeButtonScript + getOptimizeButtonScript, } from "./optimizeButton"; -import { - sendIconSvg, - stopIconSvg -} from "../constants/toolIcons"; +import { sendIconSvg, stopIconSvg } from "../constants/toolIcons"; /** * 获取输入区域的 HTML 内容 @@ -45,7 +37,6 @@ export function getInputAreaContent(): string {
${getContextButtonContent()} - ${getPlanToggleContent()}