From 407f3418296862433cacbe163b0d9b423a901713 Mon Sep 17 00:00:00 2001 From: OpenClaw Copilot Date: Sat, 7 Mar 2026 00:48:55 -0500 Subject: [PATCH 1/2] fix: implement analysis error investigation fixes --- src/codeLensProvider.ts | 6 ++++-- src/explanationProvider.ts | 16 +++++++++++++++- src/extension.ts | 6 ++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/codeLensProvider.ts b/src/codeLensProvider.ts index 9a64e84..54c59f1 100644 --- a/src/codeLensProvider.ts +++ b/src/codeLensProvider.ts @@ -91,7 +91,9 @@ export class SourceDocCodeLensProvider implements vscode.CodeLensProvider { } const lenses: vscode.CodeLens[] = []; - const firstRange = new vscode.Range(0, 0, 0, document.lineAt(0).text.length); + const firstRange = document.lineCount > 0 + ? new vscode.Range(0, 0, 0, document.lineAt(0).text.length) + : new vscode.Range(0, 0, 0, 0); // File-level lens at line 0 — always shown (except 'none') lenses.push( @@ -187,7 +189,7 @@ export class SourceDocCodeLensProvider implements vscode.CodeLensProvider { // For code languages: match function/class/method/def/fn declarations. const CODE_RE = /^[ \t]*((?:export\s+)?(?:default\s+)?(?:async\s+)?function[\s*]+\w+|(?:export\s+)?(?:abstract\s+|sealed\s+)?class\s+\w+|(?:export\s+)?(?:abstract\s+)?interface\s+\w+|(?:export\s+)?(?:const|let|var)\s+\w+\s*=\s*(?:async\s*)?(?:\([^)]*\)|\w+)\s*=>|(?:public|private|protected|internal)(?:\s+(?:static|override|virtual|abstract|async|readonly))*\s+\S+\s+\w+\s*[({]|def\s+\w+\s*\(|fn\s+\w+\s*[(<]|func\s+\w+\s*[(<])/; - const RE = isXml ? XAML_RE : CODE_RE;; + const RE = isXml ? XAML_RE : CODE_RE; // In block mode, pass the full element/function text as context. // For XAML, capture from the opening tag to the matching close or end-of-line. diff --git a/src/explanationProvider.ts b/src/explanationProvider.ts index c35bf85..f089275 100644 --- a/src/explanationProvider.ts +++ b/src/explanationProvider.ts @@ -76,12 +76,26 @@ export class ExplanationProvider implements vscode.Disposable { } } catch (err) { if (err instanceof vscode.LanguageModelError) { - throw new Error(`Copilot error (${err.code}): ${err.message}`); + switch (err.code) { + case 'NoPermissions': + throw new Error('Copilot access denied. Please check your GitHub Copilot subscription.'); + case 'Blocked': + throw new Error('Copilot request was blocked. Please check your GitHub Copilot settings.'); + case 'NotFound': + throw new Error('Copilot model not found. Please check your GitHub Copilot extension.'); + case 'RequestFailed': + throw new Error('Copilot request failed. Please try again.'); + default: + throw new Error(`Copilot error (${err.code}): ${err.message}. Please check your GitHub Copilot extension.`); + } } throw err; } result = result.trim(); + if (!result) { + throw new Error('Copilot returned an empty explanation. Please try again.'); + } this.addToCache(key, result); return result; } diff --git a/src/extension.ts b/src/extension.ts index 4a69fbd..ae5141d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -50,6 +50,7 @@ export function activate(context: vscode.ExtensionContext): void { languageRegistrations.forEach(d => d.dispose()); languageRegistrations = []; registerCodeLensProviders(context, codeLensProvider, languageRegistrations); + languageRegistrations.forEach(d => context.subscriptions.push(d)); } }), ); @@ -153,6 +154,11 @@ export function activate(context: vscode.ExtensionContext): void { } } + if (lines.length === 0) { + vscode.window.showInformationMessage('Source Doc: nothing to explain in this file.'); + return; + } + await vscode.window.withProgress( { location: vscode.ProgressLocation.Window, From 8577a8a9f17bf3356ae09ca2ddce69bb62a9b5e3 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 00:57:51 -0500 Subject: [PATCH 2/2] fix: CodeLens registration leak, cancellation surfaced as error, LanguageModelError codes missing from messages (#3) * Initial plan * fix: address review comments - registration leak, cancellation, and error codes Co-authored-by: moonolgerd <3743184+moonolgerd@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: moonolgerd <3743184+moonolgerd@users.noreply.github.com> --- package-lock.json | 4 ++-- src/explanationProvider.ts | 11 +++++++---- src/extension.ts | 15 +++++++++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08ce22f..694d8ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "source-doc", - "version": "0.2.1", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "source-doc", - "version": "0.2.1", + "version": "0.3.0", "license": "MIT", "devDependencies": { "@types/glob": "^8.1.0", diff --git a/src/explanationProvider.ts b/src/explanationProvider.ts index f089275..8b8e142 100644 --- a/src/explanationProvider.ts +++ b/src/explanationProvider.ts @@ -78,13 +78,13 @@ export class ExplanationProvider implements vscode.Disposable { if (err instanceof vscode.LanguageModelError) { switch (err.code) { case 'NoPermissions': - throw new Error('Copilot access denied. Please check your GitHub Copilot subscription.'); + throw new Error(`Copilot error (${err.code}): access denied. Please check your GitHub Copilot subscription.`); case 'Blocked': - throw new Error('Copilot request was blocked. Please check your GitHub Copilot settings.'); + throw new Error(`Copilot error (${err.code}): request was blocked. Please check your GitHub Copilot settings.`); case 'NotFound': - throw new Error('Copilot model not found. Please check your GitHub Copilot extension.'); + throw new Error(`Copilot error (${err.code}): model not found. Please check your GitHub Copilot extension.`); case 'RequestFailed': - throw new Error('Copilot request failed. Please try again.'); + throw new Error(`Copilot error (${err.code}): request failed. Please try again.`); default: throw new Error(`Copilot error (${err.code}): ${err.message}. Please check your GitHub Copilot extension.`); } @@ -93,6 +93,9 @@ export class ExplanationProvider implements vscode.Disposable { } result = result.trim(); + if (token.isCancellationRequested) { + throw new vscode.CancellationError(); + } if (!result) { throw new Error('Copilot returned an empty explanation. Please try again.'); } diff --git a/src/extension.ts b/src/extension.ts index ae5141d..0b42d67 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -30,7 +30,13 @@ export function activate(context: vscode.ExtensionContext): void { ); // ── Register CodeLens provider for each configured language ────────────── - registerCodeLensProviders(context, codeLensProvider); + // Track ALL registrations in languageRegistrations (not context.subscriptions) + // so the full set can be disposed when sourceDoc.languages changes. + let languageRegistrations: vscode.Disposable[] = []; + registerCodeLensProviders(codeLensProvider, languageRegistrations); + + // Dispose the language registrations when the extension is deactivated. + context.subscriptions.push({ dispose: () => languageRegistrations.forEach(d => d.dispose()) }); // Refresh lenses when the user switches to a different editor tab context.subscriptions.push( @@ -43,14 +49,12 @@ export function activate(context: vscode.ExtensionContext): void { ); // Re-register providers when sourceDoc.languages changes - let languageRegistrations: vscode.Disposable[] = []; context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(e => { if (e.affectsConfiguration('sourceDoc.languages')) { languageRegistrations.forEach(d => d.dispose()); languageRegistrations = []; - registerCodeLensProviders(context, codeLensProvider, languageRegistrations); - languageRegistrations.forEach(d => context.subscriptions.push(d)); + registerCodeLensProviders(codeLensProvider, languageRegistrations); } }), ); @@ -206,9 +210,8 @@ export function deactivate(): void { // ── Helpers ─────────────────────────────────────────────────────────────────── function registerCodeLensProviders( - context: vscode.ExtensionContext, provider: SourceDocCodeLensProvider, - into: vscode.Disposable[] = context.subscriptions as unknown as vscode.Disposable[], + into: vscode.Disposable[], ): void { const config = vscode.workspace.getConfiguration('sourceDoc'); const languages = config.get('languages') ?? [