feat: 更新Webview视图提供者,优化HTML内容生成和通知服务逻辑
This commit is contained in:
@ -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"
|
||||||
|
|||||||
@ -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 自定义编辑器
|
||||||
|
|||||||
@ -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 发送系统通知');
|
||||||
|
|
||||||
|
|||||||
@ -206,35 +206,46 @@ 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 {
|
||||||
webviewView.webview.html = this.getWebviewContent(
|
const html = this.getWebviewContent(webviewView.webview, false);
|
||||||
webviewView.webview,
|
console.log('[ICViewProvider] HTML 内容已生成,长度:', html.length);
|
||||||
isLoggedIn
|
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,
|
||||||
|
isLoggedIn
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('[ICViewProvider] 检查登录状态失败:', error);
|
||||||
|
// 即使失败也显示未登录状态
|
||||||
|
webviewView.webview.html = this.getWebviewContent(webviewView.webview, false);
|
||||||
|
});
|
||||||
|
|
||||||
// 处理侧边栏的消息
|
// 处理侧边栏的消息
|
||||||
webviewView.webview.onDidReceiveMessage(
|
webviewView.webview.onDidReceiveMessage(
|
||||||
@ -265,187 +276,88 @@ 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">
|
||||||
<style>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
body {
|
<style>
|
||||||
margin: 0;
|
body {
|
||||||
padding: 0;
|
margin: 0;
|
||||||
font-family: var(--vscode-font-family);
|
padding: 0;
|
||||||
color: var(--vscode-foreground);
|
font-family: var(--vscode-font-family);
|
||||||
height: 100vh;
|
color: var(--vscode-foreground);
|
||||||
display: flex;
|
height: 100vh;
|
||||||
justify-content: center;
|
display: flex;
|
||||||
align-items: center;
|
justify-content: center;
|
||||||
background: linear-gradient(135deg,
|
align-items: center;
|
||||||
var(--vscode-editor-background) 0%,
|
background: linear-gradient(135deg,
|
||||||
color-mix(in srgb, var(--vscode-editor-background) 85%, var(--vscode-button-background) 15%) 50%,
|
var(--vscode-editor-background) 0%,
|
||||||
color-mix(in srgb, var(--vscode-editor-background) 90%, var(--vscode-button-background) 10%) 100%);
|
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;
|
.container {
|
||||||
flex-direction: column;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: column;
|
||||||
align-items: center;
|
justify-content: center;
|
||||||
text-align: center;
|
align-items: center;
|
||||||
padding: 20px;
|
text-align: center;
|
||||||
}
|
padding: 20px;
|
||||||
.container img {
|
}
|
||||||
margin-bottom: 16px;
|
.container img {
|
||||||
}
|
margin-bottom: 16px;
|
||||||
.container h2 {
|
}
|
||||||
margin: 0 0 16px 0;
|
.container h2 {
|
||||||
}
|
margin: 0 0 16px 0;
|
||||||
.btn {
|
}
|
||||||
width: 200px;
|
.btn {
|
||||||
padding: 8px 12px;
|
width: 200px;
|
||||||
margin: 4px 0;
|
padding: 8px 12px;
|
||||||
background: var(--vscode-button-background);
|
margin: 4px 0;
|
||||||
color: var(--vscode-button-foreground);
|
background: var(--vscode-button-background);
|
||||||
border: none;
|
color: var(--vscode-button-foreground);
|
||||||
border-radius: 4px;
|
border: none;
|
||||||
cursor: pointer;
|
border-radius: 4px;
|
||||||
text-align: center;
|
cursor: pointer;
|
||||||
}
|
text-align: center;
|
||||||
.btn:hover {
|
}
|
||||||
background: var(--vscode-button-hoverBackground);
|
.btn:hover {
|
||||||
}
|
background: var(--vscode-button-hoverBackground);
|
||||||
h3 {
|
}
|
||||||
margin: 0 0 8px 0;
|
</style>
|
||||||
font-size: 12px;
|
</head>
|
||||||
color: var(--vscode-descriptionForeground);
|
<body>
|
||||||
}
|
<div class="container">
|
||||||
</style>
|
<img src="${logoUri}" alt="IC Coder" width="120" />
|
||||||
</head>
|
<h2>欢迎使用 IC Coder</h2>
|
||||||
<body>
|
${isLoggedIn
|
||||||
<div class="container">
|
? '<button class="btn" onclick="openChat()">开始创作</button>'
|
||||||
<img src="${logoUri}" alt="IC Coder" width="120" />
|
: '<button class="btn" onclick="login()">登录账户</button>'
|
||||||
<h2>欢迎使用 IC Coder</h2>
|
}
|
||||||
${
|
</div>
|
||||||
isLoggedIn
|
<script>
|
||||||
? '<button class="btn" onclick="openChat()">开始创作</button>'
|
console.log('[Webview] 脚本已加载');
|
||||||
: '<button class="btn" onclick="login()">登录账户</button>'
|
const vscode = acquireVsCodeApi();
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
function openChat() {
|
||||||
const vscode = acquireVsCodeApi();
|
console.log('[Webview] 点击开始创作');
|
||||||
|
vscode.postMessage({ command: 'openChat' });
|
||||||
|
}
|
||||||
|
|
||||||
function openChat() {
|
function login() {
|
||||||
vscode.postMessage({ command: 'openChat' });
|
console.log('[Webview] 点击登录');
|
||||||
}
|
vscode.postMessage({ command: 'login' });
|
||||||
|
}
|
||||||
|
|
||||||
// 登录功能
|
console.log('[Webview] 初始化完成');
|
||||||
function login() {
|
</script>
|
||||||
vscode.postMessage({ command: 'login' });
|
</body>
|
||||||
}
|
</html>`;
|
||||||
|
|
||||||
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>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user