Files
IC-Coder-Plugin/src/extension.ts

460 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as vscode from "vscode";
import { ICViewProvider } from "./views/ICViewProvider";
import { showICHelperPanel } from "./panels/ICHelperPanel";
import { VCDViewerPanel, VCDViewerEditorProvider } from "./panels/VCDViewerPanel";
import { ChatHistoryManager } from "./utils/chatHistoryManager";
import { ICCoderAuthenticationProvider } from "./services/icCoderAuthProvider";
import { VCDFileServer } from "./services/vcdFileServer";
import { initUserService } from "./services/userService";
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 { anchor, active } = editor.selection;
const endPos = anchor.isAfter(active) ? anchor : active;
const lineEndPos = editor.document.lineAt(endPos.line).range.end;
const range = new vscode.Range(lineEndPos, lineEndPos);
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] 通知服务已初始化');
// 【关键】在创建 AuthProvider 之前,先检查并清除过期的 session
const storedSessions = context.globalState.get<any[]>('icCoderSessions', []);
console.log('[Extension] 检查 sessions 数量:', storedSessions.length);
if (storedSessions.length > 0) {
const session = storedSessions[0];
const token = session.accessToken;
console.log('[Extension] 检查 token 是否过期...');
if (token) {
const expired = isTokenExpired(token);
console.log('[Extension] token 过期检查结果:', expired);
if (expired) {
// 必须等待清除完成后再创建 AuthProvider
await context.globalState.update('icCoderSessions', []);
await context.globalState.update('icCoderUserInfo', undefined);
console.log('[Extension] Token 已过期,已清除所有登录状态');
}
}
}
// 初始化用户服务
initUserService(context);
// 初始化 Credits 服务
initCreditsService(context);
// 初始化 VCD 文件服务器
const vcdFileServer = new VCDFileServer(context.extensionUri);
vcdFileServer.start().then((port) => {
console.log(`VCD 文件服务器已启动,端口: ${port}`);
}).catch((error) => {
console.error("启动 VCD 文件服务器失败:", error);
});
// 在插件停用时关闭服务器
context.subscriptions.push({
dispose: () => vcdFileServer.stop()
});
// 注册 Authentication Provider此时 icCoderSessions 已经被清除)
const authProvider = new ICCoderAuthenticationProvider(context);
context.subscriptions.push(
vscode.authentication.registerAuthenticationProvider(
"iccoder",
"IC Coder",
authProvider
)
);
// 检查登录状态,如果已登录则自动打开聊天面板
vscode.authentication.getSession("iccoder", [], { createIfNone: false })
.then((session) => {
if (session) {
vscode.commands.executeCommand("ic-coder.openChat");
}
}, () => {
// 未登录,不做任何操作
});
// 注册命令:打开助手面板
const openPanelCommand = vscode.commands.registerCommand(
"ic-coder.openPanel",
async () => {
await showICHelperPanel(context);
}
);
// 注册命令:打开聊天(用于侧边栏)
const openChatCommand = vscode.commands.registerCommand(
"ic-coder.openChat",
async () => {
await showICHelperPanel(context);
}
);
// 注册命令:打开 VCD 波形查看器
const openVCDViewerCommand = vscode.commands.registerCommand(
"ic-coder.openVCDViewer",
async (vcdFilePath?: string) => {
if (!vcdFilePath) {
// 如果没有提供文件路径,让用户选择 VCD 文件
const fileUri = await vscode.window.showOpenDialog({
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
filters: {
"VCD 文件": ["vcd"],
"所有文件": ["*"],
},
title: "选择 VCD 文件",
});
if (fileUri && fileUri[0]) {
vcdFilePath = fileUri[0].fsPath;
} else {
return;
}
}
VCDViewerPanel.createOrShow(context.extensionUri, vcdFilePath, vcdFileServer);
}
);
// 注册命令:在浏览器中打开 VCD 波形查看器
const openVCDViewerInBrowserCommand = vscode.commands.registerCommand(
"ic-coder.openVCDViewerInBrowser",
async (vcdFilePath?: string) => {
if (!vcdFilePath) {
const fileUri = await vscode.window.showOpenDialog({
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
filters: {
"VCD 文件": ["vcd"],
"所有文件": ["*"],
},
title: "选择 VCD 文件",
});
if (fileUri && fileUri[0]) {
vcdFilePath = fileUri[0].fsPath;
} else {
return;
}
}
// 注册文件到服务器
const fileId = vcdFileServer.registerFile(vcdFilePath);
const viewerUrl = vcdFileServer.getViewerUrl(fileId);
// 在默认浏览器中打开
vscode.env.openExternal(vscode.Uri.parse(viewerUrl));
vscode.window.showInformationMessage(`波形查看器已在浏览器中打开`);
}
);
// 注册命令:用户登录
const loginCommand = vscode.commands.registerCommand(
"ic-coder.login",
async (options?: { forceReauth?: boolean }) => {
try {
const forceReauth = options?.forceReauth === true;
const session = await vscode.authentication.getSession("iccoder", [], {
createIfNone: false,
});
const expired = session?.accessToken
? isTokenExpired(session.accessToken)
: null;
// 会话仍有效时,直接打开聊天面板
if (session && expired === false && !forceReauth) {
vscode.commands.executeCommand("ic-coder.openChat");
return;
}
// 1) 清空当前登录状态信息
await authProvider.clearSessionsForRelogin();
await context.globalState.update("icCoderSessions", []);
await context.globalState.update("icCoderUserInfo", undefined);
// 2) 重新登录(强制新会话)
await vscode.authentication.getSession("iccoder", [], {
clearSessionPreference: true,
forceNewSession: true,
});
} catch (error) {
vscode.window.showErrorMessage(`登录失败: ${error}`);
}
}
);
// 注册命令:用户登出
const logoutCommand = vscode.commands.registerCommand(
"ic-coder.logout",
async () => {
try {
const session = await vscode.authentication.getSession("iccoder", [], { createIfNone: false });
if (session) {
// 调用 authProvider 的 removeSession 方法
await authProvider.removeSession(session.id);
// 清除邀请码验证状态
await InvitationService.clearVerificationStatus(context);
} else {
vscode.window.showInformationMessage("当前未登录");
}
} catch (error) {
vscode.window.showInformationMessage("当前未登录");
}
}
);
// 注册命令:更换邀请码
const changeInvitationCodeCommand = vscode.commands.registerCommand(
"ic-coder.changeInvitationCode",
async () => {
const confirm = await vscode.window.showWarningMessage(
'确定要更换邀请码吗?',
'确定',
'取消'
);
if (confirm === '确定') {
await InvitationService.clearVerificationStatus(context);
vscode.window.showInformationMessage('已清除邀请码,请重新验证');
}
}
);
// 注册命令:测试系统通知
const testNotificationCommand = vscode.commands.registerCommand(
"ic-coder.testNotification",
() => {
console.log('[Extension] ========== 测试通知命令被调用 ==========');
// 先显示 VS Code 通知确认命令执行
vscode.window.showInformationMessage('正在测试系统通知...');
// 发送系统通知
notificationService.success(
'IC Coder - 测试通知',
'系统通知功能正常工作!',
() => {
vscode.window.showInformationMessage('您点击了系统通知!');
}
);
console.log('[Extension] 测试通知命令执行完成');
}
);
// 注册命令:将选中代码添加到对话
const addCodeToChat = vscode.commands.registerCommand(
"ic-coder.addCodeToChat",
async () => {
console.log('[addCodeToChat] 命令触发');
const editor = vscode.window.activeTextEditor;
if (!editor) {
console.log('[addCodeToChat] 没有活动编辑器');
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;
let needCreatePanel = false;
if (!panel) {
needCreatePanel = true;
} else {
// 尝试访问 webview如果抛出异常说明已销毁
try {
const _ = panel.webview;
} catch (e) {
needCreatePanel = true;
}
}
console.log('[addCodeToChat] 需要创建面板:', needCreatePanel);
if (needCreatePanel) {
console.log('[addCodeToChat] 正在打开面板...');
await showICHelperPanel(context);
panel = (global as any).currentICHelperPanel;
console.log('[addCodeToChat] 面板打开后状态:', panel ? '成功' : '失败');
// 如果面板仍未创建(如未登录),直接返回
if (!panel) {
console.log('[addCodeToChat] 面板创建失败,退出');
return;
}
}
// 发送代码上下文
console.log('[addCodeToChat] 准备发送代码到面板');
setTimeout(() => {
try {
if (panel?.webview) {
console.log('[addCodeToChat] 发送 addCodeContext 消息');
panel.webview.postMessage({
command: 'addCodeContext',
fileName,
startLine,
endLine,
code: selectedText,
languageId: editor.document.languageId
});
}
} catch (e) {
console.log('[addCodeToChat] 发送消息失败:', e);
}
}, 500);
}
);
// 注册命令:查看会话历史
// TODO: 这些命令需要根据新的任务架构重新实现
// 暂时注释掉,等待重新实现
/*
const viewHistoryCommand = vscode.commands.registerCommand(
"ic-coder.viewHistory",
() => {
vscode.window.showInformationMessage("此功能正在重构中,敬请期待");
}
);
const newSessionCommand = vscode.commands.registerCommand(
"ic-coder.newSession",
() => {
vscode.window.showInformationMessage("此功能正在重构中,敬请期待");
}
);
const exportSessionCommand = vscode.commands.registerCommand(
"ic-coder.exportSession",
() => {
vscode.window.showInformationMessage("此功能正在重构中,敬请期待");
}
);
const deleteSessionCommand = vscode.commands.registerCommand(
"ic-coder.deleteSession",
() => {
vscode.window.showInformationMessage("此功能正在重构中,敬请期待");
}
);
const clearHistoryCommand = vscode.commands.registerCommand(
"ic-coder.clearHistory",
() => {
vscode.window.showInformationMessage("此功能正在重构中,敬请期待");
}
);
const searchSessionCommand = vscode.commands.registerCommand(
"ic-coder.searchSession",
() => {
vscode.window.showInformationMessage("此功能正在重构中,敬请期待");
}
);
*/
// 注册侧边栏视图
const viewProvider = new ICViewProvider(context.extensionUri, context);
const viewRegistration = vscode.window.registerWebviewViewProvider(
"ic-coder.mainView",
viewProvider,
{
webviewOptions: {
retainContextWhenHidden: true
}
}
);
// 注册 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,
openChatCommand,
openVCDViewerCommand,
openVCDViewerInBrowserCommand,
loginCommand,
logoutCommand,
changeInvitationCodeCommand,
testNotificationCommand,
addCodeToChat,
// testTrialUserCommand,
// testExpiredUserCommand,
// TODO: 等待重新实现这些命令
// viewHistoryCommand,
// newSessionCommand,
// exportSessionCommand,
// deleteSessionCommand,
// clearHistoryCommand,
// searchSessionCommand,
viewRegistration,
vcdEditorProvider,
codeActionProvider
);
}
export function deactivate() {}