From 596e7a771d4db4a423433fb1c300380d2102fa20 Mon Sep 17 00:00:00 2001 From: Yusuf Efe <120668197+yuefdev@users.noreply.github.com> Date: Sun, 18 Oct 2026 02:03:42 +0300 Subject: [PATCH] fix: query diagnostics only for visible documents --- CHANGELOG.md | 6 +++ extension.js | 20 ++++++---- tests/diagnostics.test.js | 82 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 tests/diagnostics.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index d1d149d..37e3f74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). --- +## [Unreleased] + +### Fixed + +- Query diagnostics only for visible documents and count split editors once per document, avoiding a workspace-wide scan on every diagnostics event. + ## [2.0.0] - 2026-09-25 *The massive Companion Update! Bringing new pet species, a persistent sidebar view, wearables, and interactivity to CodeCritter.* diff --git a/extension.js b/extension.js index e270404..02cecaf 100644 --- a/extension.js +++ b/extension.js @@ -323,14 +323,18 @@ function activate(context) { // ── Event: Diagnostics (errors/warnings) ── const onDiagnostics = vscode.languages.onDidChangeDiagnostics(() => { - // Only scan diagnostics from open editors to avoid noisy workspace-wide counts - const openUris = vscode.window.visibleTextEditors.map(e => e.document.uri.toString()); - const allDiags = vscode.languages.getDiagnostics(); - const errorCount = allDiags - .filter(([uri]) => openUris.includes(uri.toString())) - .flatMap(([, diags]) => diags) - .filter(d => d.severity === vscode.DiagnosticSeverity.Error) - .length; + // Query each visible document once, even when it is open in split editors. + const seen = new Set(); + let errorCount = 0; + for (const editor of vscode.window.visibleTextEditors) { + const uri = editor.document.uri; + const key = uri.toString(); + if (seen.has(key)) continue; + seen.add(key); + for (const diagnostic of vscode.languages.getDiagnostics(uri)) { + if (diagnostic.severity === vscode.DiagnosticSeverity.Error) errorCount++; + } + } // Award credit for errors fixed if (errorCount < prevErrorCount) { diff --git a/tests/diagnostics.test.js b/tests/diagnostics.test.js new file mode 100644 index 0000000..e68b56c --- /dev/null +++ b/tests/diagnostics.test.js @@ -0,0 +1,82 @@ +'use strict'; + +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const test = require('node:test'); +const vm = require('node:vm'); + +test('diagnostics queries only distinct visible documents and credits fixed errors', () => { + const disposable = { dispose() {} }; + const calls = []; + let onDiagnostics; + let fixed = 0; + const uri = { toString: () => 'file:///visible.js' }; + let diagnostics = [{ severity: 0 }, { severity: 1 }]; + const statusBar = { show() {}, hide() {} }; + const vscode = { + DiagnosticSeverity: { Error: 0 }, + StatusBarAlignment: { Right: 1 }, + MarkdownString: class { constructor(value) { this.value = value; } }, + commands: { registerCommand: () => disposable }, + workspace: { + getConfiguration: () => ({ get: (key, fallback) => key === 'weeklyReview' ? false : fallback }), + onDidSaveTextDocument: () => disposable, + onDidChangeTextDocument: () => disposable, + onDidChangeConfiguration: () => disposable + }, + window: { + createStatusBarItem: () => statusBar, + registerWebviewViewProvider: () => disposable, + visibleTextEditors: [{ document: { uri } }, { document: { uri } }] + }, + languages: { + onDidChangeDiagnostics: callback => { onDiagnostics = callback; return disposable; }, + getDiagnostics: requested => { + assert.equal(requested, uri, 'must never scan the workspace'); + calls.push(requested); + return diagnostics; + } + } + }; + const dependencies = { + vscode, + './src/stats': { StatsEngine: class { + getLevel() { return 1; } + getSnapshot() { return { level: 1, saveCount: 0, linesTyped: 0, currentStreak: 0, errorsFixed: fixed }; } + recordErrorFixed() { fixed++; } + } }, + './src/moods': { + getMoodDisplay: mood => ({ statusText: mood, label: mood, tip: '' }), + checkMilestones: () => [], + PET_THEMES: { default: { label: 'Default' } } + }, + './src/dashboard': { updateDashboardIfOpen() {} }, + './src/sidebar': { SidebarProvider: class { update() {} } } + }; + const sandbox = { + module: { exports: {} }, + require: name => { assert.ok(name in dependencies); return dependencies[name]; }, + setInterval: () => 0, + setTimeout: () => 0, + clearInterval() {}, + clearTimeout() {} + }; + vm.runInNewContext(fs.readFileSync(path.join(__dirname, '..', 'extension.js'), 'utf8'), sandbox); + sandbox.module.exports.activate({ subscriptions: [] }); + + onDiagnostics(); + assert.equal(calls.length, 1, 'split editors must not double-count one document'); + assert.match(statusBar.text, /struggling/); + + diagnostics = []; + onDiagnostics(); + assert.equal(fixed, 1, 'warnings must not count as fixed errors'); + assert.match(statusBar.text, /focused/); + + calls.length = 0; + vscode.window.visibleTextEditors = []; + onDiagnostics(); + assert.equal(calls.length, 0, 'no editor means no diagnostic query'); + assert.equal(fixed, 1); +});