Squashed 'third_party/pi/' content from commit d981de122
git-subtree-dir: third_party/pi git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
174
packages/coding-agent/test/theme-detection.test.ts
Normal file
174
packages/coding-agent/test/theme-detection.test.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { type RgbColor, resetCapabilitiesCache, setCapabilities } from "@earendil-works/pi-tui";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
detectTerminalBackgroundFromEnv,
|
||||
detectTerminalBackgroundTheme,
|
||||
detectTerminalThemeForAuto,
|
||||
getThemeByName,
|
||||
getThemeForRgbColor,
|
||||
parseAutoThemeSetting,
|
||||
resolveThemeSetting,
|
||||
} from "../src/modes/interactive/theme/theme.ts";
|
||||
|
||||
afterEach(() => {
|
||||
resetCapabilitiesCache();
|
||||
});
|
||||
|
||||
describe("detectTerminalBackgroundFromEnv", () => {
|
||||
it("uses the COLORFGBG background color index", () => {
|
||||
expect(detectTerminalBackgroundFromEnv({ env: { COLORFGBG: "0;15" } })).toMatchObject({
|
||||
theme: "light",
|
||||
source: "COLORFGBG",
|
||||
confidence: "high",
|
||||
});
|
||||
expect(detectTerminalBackgroundFromEnv({ env: { COLORFGBG: "15;0" } })).toMatchObject({
|
||||
theme: "dark",
|
||||
source: "COLORFGBG",
|
||||
confidence: "high",
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the last COLORFGBG field as the background", () => {
|
||||
expect(detectTerminalBackgroundFromEnv({ env: { COLORFGBG: "0;7;15" } }).theme).toBe("light");
|
||||
});
|
||||
|
||||
it("defaults to dark without terminal background hints", () => {
|
||||
expect(detectTerminalBackgroundFromEnv({ env: {} })).toMatchObject({
|
||||
theme: "dark",
|
||||
source: "fallback",
|
||||
confidence: "low",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("detectTerminalBackgroundTheme", () => {
|
||||
it("uses the queried terminal background before environment hints", async () => {
|
||||
let queriedTimeoutMs: number | undefined;
|
||||
const detection = await detectTerminalBackgroundTheme({
|
||||
env: { COLORFGBG: "15;0" },
|
||||
timeoutMs: 250,
|
||||
ui: {
|
||||
async queryTerminalBackgroundColor({ timeoutMs }: { timeoutMs: number }): Promise<RgbColor | undefined> {
|
||||
queriedTimeoutMs = timeoutMs;
|
||||
return { r: 250, g: 250, b: 250 };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(queriedTimeoutMs).toBe(250);
|
||||
expect(detection).toMatchObject({
|
||||
theme: "light",
|
||||
source: "terminal background",
|
||||
confidence: "high",
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to environment hints when the terminal query returns no color", async () => {
|
||||
const detection = await detectTerminalBackgroundTheme({
|
||||
env: { COLORFGBG: "15;0" },
|
||||
timeoutMs: 250,
|
||||
ui: {
|
||||
async queryTerminalBackgroundColor(): Promise<RgbColor | undefined> {
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(detection).toMatchObject({
|
||||
theme: "dark",
|
||||
source: "COLORFGBG",
|
||||
confidence: "high",
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to environment hints when the terminal query fails", async () => {
|
||||
const detection = await detectTerminalBackgroundTheme({
|
||||
env: { COLORFGBG: "0;15" },
|
||||
timeoutMs: 250,
|
||||
ui: {
|
||||
async queryTerminalBackgroundColor(): Promise<RgbColor | undefined> {
|
||||
throw new Error("terminal write failed");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(detection).toMatchObject({
|
||||
theme: "light",
|
||||
source: "COLORFGBG",
|
||||
confidence: "high",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("detectTerminalThemeForAuto", () => {
|
||||
it("starts both queries and returns the preferred color-scheme result without waiting", async () => {
|
||||
let resolveColorScheme!: (theme: "dark" | "light" | undefined) => void;
|
||||
let backgroundQueryStarted = false;
|
||||
const detection = detectTerminalThemeForAuto({
|
||||
timeoutMs: 100,
|
||||
ui: {
|
||||
queryTerminalColorScheme: () =>
|
||||
new Promise((resolve) => {
|
||||
resolveColorScheme = resolve;
|
||||
}),
|
||||
queryTerminalBackgroundColor: () => {
|
||||
backgroundQueryStarted = true;
|
||||
return new Promise<RgbColor | undefined>(() => {});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(backgroundQueryStarted).toBe(true);
|
||||
resolveColorScheme("dark");
|
||||
await expect(detection).resolves.toBe("dark");
|
||||
});
|
||||
|
||||
it("uses the background result when the color-scheme query fails", async () => {
|
||||
await expect(
|
||||
detectTerminalThemeForAuto({
|
||||
timeoutMs: 100,
|
||||
ui: {
|
||||
async queryTerminalColorScheme(): Promise<undefined> {
|
||||
throw new Error("color-scheme query failed");
|
||||
},
|
||||
async queryTerminalBackgroundColor(): Promise<RgbColor> {
|
||||
return { r: 250, g: 250, b: 250 };
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toBe("light");
|
||||
});
|
||||
});
|
||||
|
||||
describe("theme color mode", () => {
|
||||
it("uses terminal capabilities", () => {
|
||||
setCapabilities({ images: null, trueColor: false, hyperlinks: false });
|
||||
const ansi256Theme = getThemeByName("dark");
|
||||
if (!ansi256Theme) throw new Error("dark theme not found");
|
||||
expect(ansi256Theme.getColorMode()).toBe("256color");
|
||||
expect(ansi256Theme.getFgAnsi("accent")).toMatch(/^\x1b\[38;5;\d+m$/);
|
||||
|
||||
setCapabilities({ images: null, trueColor: true, hyperlinks: false });
|
||||
const truecolorTheme = getThemeByName("dark");
|
||||
if (!truecolorTheme) throw new Error("dark theme not found");
|
||||
expect(truecolorTheme.getColorMode()).toBe("truecolor");
|
||||
expect(truecolorTheme.getFgAnsi("accent")).toMatch(/^\x1b\[38;2;\d+;\d+;\d+m$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("theme detection from RGB", () => {
|
||||
it("classifies RGB colors by luminance", () => {
|
||||
expect(getThemeForRgbColor({ r: 8, g: 8, b: 8 })).toBe("dark");
|
||||
expect(getThemeForRgbColor({ r: 250, g: 250, b: 250 })).toBe("light");
|
||||
});
|
||||
});
|
||||
|
||||
describe("theme setting helpers", () => {
|
||||
it("parses and resolves automatic theme settings", () => {
|
||||
expect(parseAutoThemeSetting("light/dark")).toEqual({ lightTheme: "light", darkTheme: "dark" });
|
||||
expect(resolveThemeSetting("dark", "light")).toBe("dark");
|
||||
expect(resolveThemeSetting("light/dark", "light")).toBe("light");
|
||||
expect(resolveThemeSetting("light/dark", "dark")).toBe("dark");
|
||||
expect(resolveThemeSetting("light/dark/extra", "dark")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user