feat: 更新Webview视图提供者,优化HTML内容生成和通知服务逻辑

This commit is contained in:
Roe-xin
2026-01-28 21:38:49 +08:00
parent 7c4ecb013e
commit 4f1d7f495a
4 changed files with 130 additions and 200 deletions

View File

@ -27,7 +27,7 @@
}, },
"activationEvents": [ "activationEvents": [
"onCommand:ic-coder.openPanel", "onCommand:ic-coder.openPanel",
"onView:ic-coder-sidebar", "onView:ic-coder.mainView",
"onLanguage:verilog", "onLanguage:verilog",
"onLanguage:vhdl", "onLanguage:vhdl",
"onStartupFinished" "onStartupFinished"

View File

@ -289,7 +289,12 @@ export async function activate(context: vscode.ExtensionContext) {
const viewProvider = new ICViewProvider(context.extensionUri, context); const viewProvider = new ICViewProvider(context.extensionUri, context);
const viewRegistration = vscode.window.registerWebviewViewProvider( const viewRegistration = vscode.window.registerWebviewViewProvider(
"ic-coder.mainView", "ic-coder.mainView",
viewProvider viewProvider,
{
webviewOptions: {
retainContextWhenHidden: true
}
}
); );
// 注册 VCD 自定义编辑器 // 注册 VCD 自定义编辑器

View File

@ -1,8 +1,14 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as path from 'path'; import * as path from 'path';
// 使用 require 导入 node-notifier // 尝试加载 node-notifier,如果失败则使用 null
const notifier = require('node-notifier'); let notifier: any = null;
try {
notifier = require('node-notifier');
console.log('[NotificationService] node-notifier 加载成功');
} catch (error) {
console.log('[NotificationService] node-notifier 加载失败,将只使用 VS Code 内置通知');
}
/** /**
* 通知类型枚举 * 通知类型枚举
@ -114,6 +120,13 @@ export class NotificationService {
} }
console.log('[NotificationService] 通过防抖检查'); console.log('[NotificationService] 通过防抖检查');
// 如果 node-notifier 不可用,直接使用 VS Code 内置通知
if (!notifier) {
console.log('[NotificationService] node-notifier 不可用,使用 VS Code 内置通知');
this.showVSCodeNotification(title, message, type, onClick);
return;
}
// 使用 node-notifier 发送系统通知 // 使用 node-notifier 发送系统通知
console.log('[NotificationService] 使用 node-notifier 发送系统通知'); console.log('[NotificationService] 使用 node-notifier 发送系统通知');

View File

@ -206,34 +206,45 @@ export class ICViewProvider implements vscode.WebviewViewProvider {
} }
resolveWebviewView(webviewView: vscode.WebviewView) { resolveWebviewView(webviewView: vscode.WebviewView) {
console.log('[ICViewProvider] ========== resolveWebviewView 被调用 ==========');
// 保存引用以便后续刷新 // 保存引用以便后续刷新
this._view = webviewView; this._view = webviewView;
webviewView.webview.options = { webviewView.webview.options = {
enableScripts: true, enableScripts: true,
localResourceRoots: [vscode.Uri.joinPath(this.extensionUri, "media")], localResourceRoots: [
vscode.Uri.joinPath(this.extensionUri, "media"),
vscode.Uri.joinPath(this.extensionUri, "src", "assets")
],
}; };
// 异步检查 token 是否过期并清除 console.log('[ICViewProvider] Webview options 已设置');
vscode.authentication.getSession("iccoder", [], { createIfNone: false }) console.log('[ICViewProvider] extensionUri:', this.extensionUri.toString());
.then((session) => {
const token = session?.accessToken;
if (token && isTokenExpired(token)) {
// 静默清除过期的 session
this.context.globalState.update('icCoderSessions', []);
this.context.globalState.update('icCoderUserInfo', undefined);
console.log('[ICViewProvider] Token 已过期,已清除所有登录状态');
}
}, () => {
// 忽略错误
});
// 检查是否已登录(使用 Authentication API // 【关键修复】先设置默认 HTML避免一直加载
this.checkLoginStatus().then((isLoggedIn) => { try {
const html = this.getWebviewContent(webviewView.webview, false);
console.log('[ICViewProvider] HTML 内容已生成,长度:', html.length);
webviewView.webview.html = html;
console.log('[ICViewProvider] HTML 已设置到 webview');
} catch (error) {
console.error('[ICViewProvider] 设置 HTML 失败:', error);
}
// 异步检查登录状态并更新 UI
this.checkLoginStatus()
.then((isLoggedIn) => {
console.log('[ICViewProvider] 登录状态检查完成:', isLoggedIn);
webviewView.webview.html = this.getWebviewContent( webviewView.webview.html = this.getWebviewContent(
webviewView.webview, webviewView.webview,
isLoggedIn isLoggedIn
); );
})
.catch((error) => {
console.error('[ICViewProvider] 检查登录状态失败:', error);
// 即使失败也显示未登录状态
webviewView.webview.html = this.getWebviewContent(webviewView.webview, false);
}); });
// 处理侧边栏的消息 // 处理侧边栏的消息
@ -265,14 +276,17 @@ export class ICViewProvider implements vscode.WebviewViewProvider {
webview: vscode.Webview, webview: vscode.Webview,
isLoggedIn: boolean isLoggedIn: boolean
): string { ): string {
console.log('[ICViewProvider] 开始生成 HTML 内容, isLoggedIn:', isLoggedIn);
const logoUri = webview.asWebviewUri( const logoUri = webview.asWebviewUri(
vscode.Uri.joinPath(this.extensionUri, "media", "icon.png") vscode.Uri.joinPath(this.extensionUri, "media", "icon.png")
); );
return ` return `<!DOCTYPE html>
<!DOCTYPE html> <html>
<html> <head>
<head> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style> <style>
body { body {
margin: 0; margin: 0;
@ -316,136 +330,34 @@ export class ICViewProvider implements vscode.WebviewViewProvider {
.btn:hover { .btn:hover {
background: var(--vscode-button-hoverBackground); background: var(--vscode-button-hoverBackground);
} }
h3 {
margin: 0 0 8px 0;
font-size: 12px;
color: var(--vscode-descriptionForeground);
}
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<img src="${logoUri}" alt="IC Coder" width="120" /> <img src="${logoUri}" alt="IC Coder" width="120" />
<h2>欢迎使用 IC Coder</h2> <h2>欢迎使用 IC Coder</h2>
${ ${isLoggedIn
isLoggedIn
? '<button class="btn" onclick="openChat()">开始创作</button>' ? '<button class="btn" onclick="openChat()">开始创作</button>'
: '<button class="btn" onclick="login()">登录账户</button>' : '<button class="btn" onclick="login()">登录账户</button>'
} }
</div> </div>
<script> <script>
console.log('[Webview] 脚本已加载');
const vscode = acquireVsCodeApi(); const vscode = acquireVsCodeApi();
function openChat() { function openChat() {
console.log('[Webview] 点击开始创作');
vscode.postMessage({ command: 'openChat' }); vscode.postMessage({ command: 'openChat' });
} }
// 登录功能
function login() { function login() {
console.log('[Webview] 点击登录');
vscode.postMessage({ command: 'login' }); vscode.postMessage({ command: 'login' });
} }
function generateCode(type) { console.log('[Webview] 初始化完成');
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> </script>
</body> </body>
</html> </html>`;
`;
} }
} }