From c4e2d88a1a4549f7eba37286455a40bd445568e9 Mon Sep 17 00:00:00 2001 From: Bisma Nawaz Date: Fri, 21 Aug 2026 04:17:10 +0500 Subject: [PATCH 1/2] fix(vscode): guard theme colors lookup so a non-standard palette can't crash activation --- .../vscode/src/activation/InlineTipManager.ts | 6 +- .../src/activation/InlineTipManager.vitest.ts | 57 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 extensions/vscode/src/activation/InlineTipManager.vitest.ts diff --git a/extensions/vscode/src/activation/InlineTipManager.ts b/extensions/vscode/src/activation/InlineTipManager.ts index 4a544147cc3..c6675fa1c83 100644 --- a/extensions/vscode/src/activation/InlineTipManager.ts +++ b/extensions/vscode/src/activation/InlineTipManager.ts @@ -236,7 +236,7 @@ export class InlineTipManager { private createSvgTooltipDecoration() { var backgroundColour = "#333333"; - if (this.theme) { + if (this.theme?.colors?.["editor.background"]) { backgroundColour = this.theme.colors["editor.background"]; } return vscode.window.createTextEditorDecorationType({ @@ -274,7 +274,7 @@ export class InlineTipManager { { ...baseTextConfig, x: SVG_CONFIG.chatLabelX, - fill: this.theme?.colors["editor.foreground"] ?? SVG_CONFIG.stroke, + fill: this.theme?.colors?.["editor.foreground"] ?? SVG_CONFIG.stroke, }, SVG_CONFIG.chatLabel, ) @@ -291,7 +291,7 @@ export class InlineTipManager { { ...baseTextConfig, x: SVG_CONFIG.editLabelX, - fill: this.theme?.colors["editor.foreground"] ?? SVG_CONFIG.stroke, + fill: this.theme?.colors?.["editor.foreground"] ?? SVG_CONFIG.stroke, }, SVG_CONFIG.editLabel, ) diff --git a/extensions/vscode/src/activation/InlineTipManager.vitest.ts b/extensions/vscode/src/activation/InlineTipManager.vitest.ts new file mode 100644 index 00000000000..15946a515d2 --- /dev/null +++ b/extensions/vscode/src/activation/InlineTipManager.vitest.ts @@ -0,0 +1,57 @@ +import { describe, expect, it, vi } from "vitest"; + +// createSvgTooltipDecoration only calls window.createTextEditorDecorationType, +// but importing the module pulls in helpers that read the workspace config, so +// the mock covers that surface too. +vi.mock("vscode", () => ({ + window: { + createTextEditorDecorationType: vi + .fn() + .mockReturnValue({ dispose: vi.fn() }), + }, + workspace: { + getConfiguration: vi.fn().mockReturnValue({ get: vi.fn() }), + onDidChangeConfiguration: vi.fn().mockReturnValue({ dispose: vi.fn() }), + }, + ThemeColor: class { + constructor(public id: string) {} + }, + Uri: { file: vi.fn(), parse: vi.fn() }, +})); +vi.mock("core/control-plane/env", () => ({ EXTENSION_NAME: "continue" })); +vi.mock("../util/util", () => ({ + getMetaKeyLabel: () => "Cmd", + getMetaKeyName: () => "metaKey", +})); +vi.mock("../util/getTheme", () => ({ + getTheme: vi.fn().mockReturnValue({ colors: {} }), +})); +vi.mock("svg-builder", () => ({ + default: { newInstance: () => ({ width: () => ({ height: () => ({}) }) }) }, +})); + +import { InlineTipManager } from "./InlineTipManager"; + +describe("InlineTipManager.createSvgTooltipDecoration", () => { + it("does not throw when the active theme exposes no colors map", () => { + // A non-standard color theme can produce a Monaco theme whose `colors` is + // undefined. Previously the guard only checked `this.theme` was truthy and + // then read `this.theme.colors["editor.background"]`, throwing a TypeError + // that killed extension activation (issue #12947). + const instance = Object.create( + InlineTipManager.prototype, + ) as { createSvgTooltipDecoration: () => unknown; theme: unknown }; + instance.theme = { colors: undefined }; + + expect(() => instance.createSvgTooltipDecoration()).not.toThrow(); + }); + + it("uses the theme background when the colors map is present", () => { + const instance = Object.create( + InlineTipManager.prototype, + ) as { createSvgTooltipDecoration: () => unknown; theme: unknown }; + instance.theme = { colors: { "editor.background": "#101010" } }; + + expect(() => instance.createSvgTooltipDecoration()).not.toThrow(); + }); +}); From 6c02c54545b093c766b20630a4898436ae1634aa Mon Sep 17 00:00:00 2001 From: Bisma Nawaz Date: Fri, 21 Aug 2026 23:20:43 +0500 Subject: [PATCH 2/2] style: apply prettier formatting --- .../vscode/src/activation/InlineTipManager.ts | 6 ++++-- .../src/activation/InlineTipManager.vitest.ts | 14 ++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/extensions/vscode/src/activation/InlineTipManager.ts b/extensions/vscode/src/activation/InlineTipManager.ts index c6675fa1c83..0921732c99b 100644 --- a/extensions/vscode/src/activation/InlineTipManager.ts +++ b/extensions/vscode/src/activation/InlineTipManager.ts @@ -274,7 +274,8 @@ export class InlineTipManager { { ...baseTextConfig, x: SVG_CONFIG.chatLabelX, - fill: this.theme?.colors?.["editor.foreground"] ?? SVG_CONFIG.stroke, + fill: + this.theme?.colors?.["editor.foreground"] ?? SVG_CONFIG.stroke, }, SVG_CONFIG.chatLabel, ) @@ -291,7 +292,8 @@ export class InlineTipManager { { ...baseTextConfig, x: SVG_CONFIG.editLabelX, - fill: this.theme?.colors?.["editor.foreground"] ?? SVG_CONFIG.stroke, + fill: + this.theme?.colors?.["editor.foreground"] ?? SVG_CONFIG.stroke, }, SVG_CONFIG.editLabel, ) diff --git a/extensions/vscode/src/activation/InlineTipManager.vitest.ts b/extensions/vscode/src/activation/InlineTipManager.vitest.ts index 15946a515d2..65ee72ba204 100644 --- a/extensions/vscode/src/activation/InlineTipManager.vitest.ts +++ b/extensions/vscode/src/activation/InlineTipManager.vitest.ts @@ -38,18 +38,20 @@ describe("InlineTipManager.createSvgTooltipDecoration", () => { // undefined. Previously the guard only checked `this.theme` was truthy and // then read `this.theme.colors["editor.background"]`, throwing a TypeError // that killed extension activation (issue #12947). - const instance = Object.create( - InlineTipManager.prototype, - ) as { createSvgTooltipDecoration: () => unknown; theme: unknown }; + const instance = Object.create(InlineTipManager.prototype) as { + createSvgTooltipDecoration: () => unknown; + theme: unknown; + }; instance.theme = { colors: undefined }; expect(() => instance.createSvgTooltipDecoration()).not.toThrow(); }); it("uses the theme background when the colors map is present", () => { - const instance = Object.create( - InlineTipManager.prototype, - ) as { createSvgTooltipDecoration: () => unknown; theme: unknown }; + const instance = Object.create(InlineTipManager.prototype) as { + createSvgTooltipDecoration: () => unknown; + theme: unknown; + }; instance.theme = { colors: { "editor.background": "#101010" } }; expect(() => instance.createSvgTooltipDecoration()).not.toThrow();