- 在 ICHelperPanel.ts 添加 optimizePrompt 消息处理分支 - 新增 promptOptimizeService.ts 调用后端优化 API - 完善 WebView 端优化按钮交互逻辑
412 lines
11 KiB
TypeScript
412 lines
11 KiB
TypeScript
import * as vscode from "vscode";
|
||
import { getWebviewContent } from "./webviewContent";
|
||
import { isTokenExpired } from "../utils/jwtUtils";
|
||
import {
|
||
handleUserMessage,
|
||
insertCodeToEditor,
|
||
handleReadFile,
|
||
handleCreateFile,
|
||
handleUpdateFile,
|
||
handleRenameFile,
|
||
handleReplaceInFile,
|
||
handleUserAnswer,
|
||
abortCurrentDialog,
|
||
handleOptimizePrompt,
|
||
} from "../utils/messageHandler";
|
||
|
||
/**
|
||
* 创建并显示IC 侧边栏视图
|
||
*/
|
||
export function showICHelperPanel(context: vscode.ExtensionContext) {
|
||
// 创建WebView面板
|
||
const panel = vscode.window.createWebviewPanel(
|
||
"icCoder", // 面板ID
|
||
"IC Coder", // 面板标题
|
||
vscode.ViewColumn.Beside, // 显示在旁边
|
||
{
|
||
enableScripts: true,
|
||
retainContextWhenHidden: true,
|
||
localResourceRoots: [
|
||
vscode.Uri.joinPath(context.extensionUri, "media"),
|
||
vscode.Uri.joinPath(context.extensionUri, "src", "assets")
|
||
],
|
||
}
|
||
);
|
||
|
||
// 设置标签页图标
|
||
panel.iconPath = vscode.Uri.joinPath(
|
||
context.extensionUri,
|
||
"media",
|
||
"icon.png"
|
||
);
|
||
|
||
// 获取页面内图标URI
|
||
const iconUri = panel.webview.asWebviewUri(
|
||
vscode.Uri.joinPath(context.extensionUri, "media", "icon.png")
|
||
);
|
||
|
||
// 获取模型图标URI
|
||
const autoIconUri = panel.webview.asWebviewUri(
|
||
vscode.Uri.joinPath(context.extensionUri, "src", "assets", "model", "Auto.png")
|
||
);
|
||
const liteIconUri = panel.webview.asWebviewUri(
|
||
vscode.Uri.joinPath(context.extensionUri, "src", "assets", "model", "lite.png")
|
||
);
|
||
const syIconUri = panel.webview.asWebviewUri(
|
||
vscode.Uri.joinPath(context.extensionUri, "src", "assets", "model", "Sy.png")
|
||
);
|
||
const maxIconUri = panel.webview.asWebviewUri(
|
||
vscode.Uri.joinPath(context.extensionUri, "src", "assets", "model", "Max.png")
|
||
);
|
||
|
||
// 设置HTML内容
|
||
panel.webview.html = getWebviewContent(
|
||
iconUri.toString(),
|
||
autoIconUri.toString(),
|
||
liteIconUri.toString(),
|
||
syIconUri.toString(),
|
||
maxIconUri.toString()
|
||
);
|
||
|
||
// 处理消息
|
||
panel.webview.onDidReceiveMessage(
|
||
(message) => {
|
||
console.log("[ICViewProvider] ====== 收到 WebView 消息 ======");
|
||
console.log("[ICViewProvider] command:", message.command);
|
||
console.log("[ICViewProvider] 完整消息:", JSON.stringify(message));
|
||
switch (message.command) {
|
||
case "sendMessage":
|
||
handleUserMessage(panel, message.text, context.extensionPath, message.mode);
|
||
break;
|
||
case "readFile":
|
||
handleReadFile(panel, message.filePath);
|
||
break;
|
||
case "updateFile":
|
||
handleUpdateFile(panel, message.filePath, message.content);
|
||
break;
|
||
case "renameFile":
|
||
handleRenameFile(panel, message.oldPath, message.newPath);
|
||
break;
|
||
case "replaceInFile":
|
||
handleReplaceInFile(
|
||
panel,
|
||
message.filePath,
|
||
message.searchText,
|
||
message.replaceText
|
||
);
|
||
break;
|
||
case "insertCode":
|
||
insertCodeToEditor(message.code);
|
||
break;
|
||
case "createFile":
|
||
handleCreateFile(
|
||
panel,
|
||
message.filePath,
|
||
message.content,
|
||
message.overwrite
|
||
);
|
||
break;
|
||
case "showInfo":
|
||
vscode.window.showInformationMessage(message.text);
|
||
break;
|
||
// 新增:处理用户回答
|
||
case "submitAnswer":
|
||
handleUserAnswer(
|
||
message.askId,
|
||
message.selected,
|
||
message.customInput
|
||
);
|
||
break;
|
||
// 新增:中止对话
|
||
case "abortDialog":
|
||
void abortCurrentDialog();
|
||
break;
|
||
// 新增:优化提示词
|
||
case "optimizePrompt":
|
||
handleOptimizePrompt(panel, message.prompt);
|
||
break;
|
||
}
|
||
},
|
||
undefined,
|
||
context.subscriptions
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 侧边栏视图提供者
|
||
*/
|
||
export class ICViewProvider implements vscode.WebviewViewProvider {
|
||
private _view?: vscode.WebviewView;
|
||
|
||
constructor(
|
||
private readonly extensionUri: vscode.Uri,
|
||
private readonly context: vscode.ExtensionContext
|
||
) {
|
||
// 监听认证状态变化
|
||
this.context.subscriptions.push(
|
||
vscode.authentication.onDidChangeSessions((e) => {
|
||
if (e.provider.id === "iccoder") {
|
||
this.refreshLoginStatus();
|
||
}
|
||
})
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 刷新登录状态并更新视图
|
||
*/
|
||
private async refreshLoginStatus(): Promise<void> {
|
||
if (this._view) {
|
||
const isLoggedIn = await this.checkLoginStatus();
|
||
this._view.webview.html = this.getWebviewContent(
|
||
this._view.webview,
|
||
isLoggedIn
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查登录状态(使用 Authentication API)
|
||
*/
|
||
private async checkLoginStatus(): Promise<boolean> {
|
||
try {
|
||
const session = await vscode.authentication.getSession("iccoder", [], { createIfNone: false });
|
||
console.log("[ICViewProvider] 检查登录状态, session:", session ? "存在" : "不存在");
|
||
if (!session) {
|
||
return false;
|
||
}
|
||
// 检查 token 是否过期
|
||
const expired = isTokenExpired(session.accessToken);
|
||
console.log("[ICViewProvider] token 过期检查结果:", expired);
|
||
// 只有明确过期才认为未登录,无法判断时认为已登录
|
||
if (expired === true) {
|
||
console.log("[ICViewProvider] Token 已过期");
|
||
return false;
|
||
}
|
||
return true;
|
||
} catch (error) {
|
||
console.log("[ICViewProvider] 检查登录状态失败:", error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
resolveWebviewView(webviewView: vscode.WebviewView) {
|
||
// 保存引用以便后续刷新
|
||
this._view = webviewView;
|
||
|
||
webviewView.webview.options = {
|
||
enableScripts: true,
|
||
localResourceRoots: [vscode.Uri.joinPath(this.extensionUri, "media")],
|
||
};
|
||
|
||
// 检查是否已登录(使用 Authentication API)
|
||
this.checkLoginStatus().then((isLoggedIn) => {
|
||
webviewView.webview.html = this.getWebviewContent(
|
||
webviewView.webview,
|
||
isLoggedIn
|
||
);
|
||
});
|
||
|
||
// 处理侧边栏的消息
|
||
webviewView.webview.onDidReceiveMessage(
|
||
(message) => {
|
||
if (message.command === "openChat") {
|
||
vscode.commands.executeCommand("ic-coder.openChat");
|
||
} else if (message.command === "login") {
|
||
vscode.commands.executeCommand("ic-coder.login");
|
||
}
|
||
},
|
||
undefined,
|
||
this.context.subscriptions
|
||
);
|
||
}
|
||
|
||
private getWebviewContent(
|
||
webview: vscode.Webview,
|
||
isLoggedIn: boolean
|
||
): string {
|
||
const logoUri = webview.asWebviewUri(
|
||
vscode.Uri.joinPath(this.extensionUri, "media", "icon.png")
|
||
);
|
||
|
||
return `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<style>
|
||
body {
|
||
margin: 0;
|
||
padding: 0;
|
||
font-family: var(--vscode-font-family);
|
||
color: var(--vscode-foreground);
|
||
height: 100vh;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background: linear-gradient(135deg,
|
||
var(--vscode-editor-background) 0%,
|
||
color-mix(in srgb, var(--vscode-editor-background) 85%, var(--vscode-button-background) 15%) 50%,
|
||
color-mix(in srgb, var(--vscode-editor-background) 90%, var(--vscode-button-background) 10%) 100%);
|
||
}
|
||
.container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
text-align: center;
|
||
padding: 20px;
|
||
}
|
||
.container img {
|
||
margin-bottom: 16px;
|
||
}
|
||
.container h2 {
|
||
margin: 0 0 16px 0;
|
||
}
|
||
.btn {
|
||
width: 200px;
|
||
padding: 8px 12px;
|
||
margin: 4px 0;
|
||
background: var(--vscode-button-background);
|
||
color: var(--vscode-button-foreground);
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
text-align: center;
|
||
}
|
||
.btn:hover {
|
||
background: var(--vscode-button-hoverBackground);
|
||
}
|
||
h3 {
|
||
margin: 0 0 8px 0;
|
||
font-size: 12px;
|
||
color: var(--vscode-descriptionForeground);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<img src="${logoUri}" alt="IC Coder" width="120" />
|
||
<h2>欢迎使用 IC Coder</h2>
|
||
${
|
||
isLoggedIn
|
||
? '<button class="btn" onclick="openChat()">开始创作</button>'
|
||
: '<button class="btn" onclick="login()">登录账户</button>'
|
||
}
|
||
</div>
|
||
|
||
<script>
|
||
const vscode = acquireVsCodeApi();
|
||
|
||
function openChat() {
|
||
vscode.postMessage({ command: 'openChat' });
|
||
}
|
||
|
||
// 登录功能
|
||
function login() {
|
||
vscode.postMessage({ command: 'login' });
|
||
}
|
||
|
||
function generateCode(type) {
|
||
const code = getCodeTemplate(type);
|
||
vscode.postMessage({
|
||
command: 'insertCode',
|
||
code: code
|
||
});
|
||
}
|
||
|
||
function getCodeTemplate(type) {
|
||
const templates = {
|
||
counter: \`module counter #(
|
||
parameter WIDTH = 4
|
||
)(
|
||
input wire clk,
|
||
input wire rst_n,
|
||
input wire enable,
|
||
output reg [WIDTH-1:0] count
|
||
);
|
||
always @(posedge clk or negedge rst_n) begin
|
||
if (!rst_n) begin
|
||
count <= 0;
|
||
end else if (enable) begin
|
||
count <= count + 1;
|
||
end
|
||
end
|
||
endmodule\`,
|
||
fsm: \`module fsm (
|
||
input wire clk,
|
||
input wire rst_n,
|
||
input wire start,
|
||
output reg done
|
||
);
|
||
parameter IDLE = 2'b00;
|
||
parameter STATE1 = 2'b01;
|
||
parameter STATE2 = 2'b10;
|
||
|
||
reg [1:0] state, next_state;
|
||
|
||
always @(posedge clk or negedge rst_n) begin
|
||
if (!rst_n) begin
|
||
state <= IDLE;
|
||
end else begin
|
||
state <= next_state;
|
||
end
|
||
end
|
||
|
||
always @(*) begin
|
||
case (state)
|
||
IDLE: next_state = start ? STATE1 : IDLE;
|
||
STATE1: next_state = STATE2;
|
||
STATE2: next_state = IDLE;
|
||
default: next_state = IDLE;
|
||
endcase
|
||
end
|
||
|
||
assign done = (state == STATE2);
|
||
endmodule\`,
|
||
fifo: \`module sync_fifo #(
|
||
parameter DATA_WIDTH = 8,
|
||
parameter DEPTH = 16
|
||
)(
|
||
input wire clk,
|
||
input wire rst_n,
|
||
input wire wr_en,
|
||
input wire [DATA_WIDTH-1:0] din,
|
||
input wire rd_en,
|
||
output reg [DATA_WIDTH-1:0] dout,
|
||
output wire full,
|
||
output wire empty
|
||
);
|
||
reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
|
||
reg [$clog2(DEPTH):0] wr_ptr, rd_ptr;
|
||
|
||
assign full = (wr_ptr == rd_ptr + DEPTH);
|
||
assign empty = (wr_ptr == rd_ptr);
|
||
|
||
always @(posedge clk) begin
|
||
if (!rst_n) wr_ptr <= 0;
|
||
else if (wr_en && !full) begin
|
||
mem[wr_ptr] <= din;
|
||
wr_ptr <= wr_ptr + 1;
|
||
end
|
||
end
|
||
|
||
always @(posedge clk) begin
|
||
if (!rst_n) begin
|
||
rd_ptr <= 0;
|
||
dout <= 0;
|
||
end else if (rd_en && !empty) begin
|
||
dout <= mem[rd_ptr];
|
||
rd_ptr <= rd_ptr + 1;
|
||
end
|
||
end
|
||
endmodule\`
|
||
};
|
||
return templates[type] || '// 代码模板';
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|
||
`;
|
||
}
|
||
}
|