import * as vscode from 'vscode'; import { Orchestrator } from './orchestrator/orchestrator'; import { registerCommands } from './activation/commands'; import { SetupViewProvider } from './views/setupView'; import { setLanguage, t, type Language } from './i18n/messages'; import { getAIOutputLanguage } from './config'; import { ReviewStatusCache } from './scope/status-cache'; import { MethodCodeLensProvider } from './views/codeLensProvider'; import { DiagnosticMarkers, isMarkersEnabled } from './diagnostics/diagnosticMarkers'; import { FixCodeActionProvider } from './fix/codeActionProvider'; import { FixSessionManager } from './fix/fixSession'; import { FixPendingStore } from './fix/fixPending'; import { registerFixPreviewProvider } from './fix/fixPreview'; let orchestrator: Orchestrator; let markers: DiagnosticMarkers; async function runStaticAndApply(document: vscode.TextDocument): Promise { try { const version = document.version; const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; const workingDir = workspaceRoot || vscode.Uri.joinPath(document.uri, '..').fsPath; const result = await orchestrator.runStaticAnalysis(document, workingDir); const current = vscode.workspace.textDocuments.find(d => d.uri.toString() === document.uri.toString()); if (!current || current.version !== version) { return; } markers.apply(document.uri, result.diagnostics); } catch (err) { console.error('[code-reviewer] static analysis failed:', err); } } const analysisTimers = new Map(); function scheduleAnalysis(document: vscode.TextDocument, delay: number): void { if (document.uri.scheme !== 'file' || !isMarkersEnabled()) { return; } const key = document.uri.toString(); const existing = analysisTimers.get(key); if (existing) { clearTimeout(existing); } const timer = setTimeout(async () => { analysisTimers.delete(key); await runStaticAndApply(document); }, delay); analysisTimers.set(key, timer); } async function analyzeOpenDocuments(): Promise { const docs = vscode.workspace.textDocuments; const active = vscode.window.activeTextEditor?.document; const ordered = [...docs].sort((a, b) => a === active ? -1 : b === active ? 1 : 0); for (const doc of ordered) { if (doc.uri.scheme !== 'file' || !isMarkersEnabled()) { continue; } await runStaticAndApply(doc); } } export function activate(context: vscode.ExtensionContext) { const lang = getAIOutputLanguage() as Language; setLanguage(lang); console.log(t('extension.activated')); orchestrator = new Orchestrator(); markers = new DiagnosticMarkers(); context.subscriptions.push(markers); const setupProvider = new SetupViewProvider(context); context.subscriptions.push( vscode.window.registerWebviewViewProvider('codeReviewer.setupView', setupProvider) ); const statusCache = new ReviewStatusCache(); const codeLensProvider = new MethodCodeLensProvider(statusCache); const fixSession = new FixSessionManager(); const pendingStore = new FixPendingStore(); registerFixPreviewProvider(context); context.subscriptions.push( vscode.languages.registerCodeActionsProvider( { scheme: 'file' }, new FixCodeActionProvider(orchestrator), { providedCodeActionKinds: [vscode.CodeActionKind.QuickFix] } ) ); void analyzeOpenDocuments(); context.subscriptions.push( vscode.languages.registerCodeLensProvider( { scheme: 'file' }, codeLensProvider ) ); context.subscriptions.push( vscode.workspace.onDidCloseTextDocument((document) => { statusCache.clearDocument(document.uri); markers.clear(document.uri); fixSession.clear(document.uri); pendingStore.clear(document.fileName); }) ); context.subscriptions.push( vscode.workspace.onDidOpenTextDocument((document) => { if (document.uri.scheme !== 'file' || !isMarkersEnabled()) { return; } void runStaticAndApply(document); }) ); context.subscriptions.push( vscode.workspace.onDidChangeTextDocument((event) => { markers.clear(event.document.uri); scheduleAnalysis(event.document, 1000); }) ); registerCommands(context, orchestrator, codeLensProvider, statusCache, markers, fixSession, pendingStore); context.subscriptions.push( vscode.workspace.onDidSaveTextDocument((document) => { scheduleAnalysis(document, 500); }) ); context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(e => { if (e.affectsConfiguration('vscode-code-reviewer.ai.outputLanguage')) { const newLang = getAIOutputLanguage() as Language; setLanguage(newLang); } }) ); } export function deactivate() { for (const timer of analysisTimers.values()) { clearTimeout(timer); } analysisTimers.clear(); markers?.dispose(); orchestrator = undefined!; }