Skip to content

Commit e826a65

Browse files
benvinegarmvanhorn
andauthored
feat: allow transparent background via config or flag (#392)
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
1 parent 7f4abac commit e826a65

3 files changed

Lines changed: 58 additions & 11 deletions

File tree

src/ui/App.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ export function App({
138138
() => availableThemes(bootstrap.customTheme),
139139
[bootstrap.customTheme],
140140
);
141-
const baseTheme = resolveTheme(themeId, detectedThemeMode ?? null, bootstrap.customTheme);
141+
const baseTheme = useMemo(
142+
() => resolveTheme(themeId, detectedThemeMode ?? null, bootstrap.customTheme),
143+
[themeId, detectedThemeMode, bootstrap.customTheme],
144+
);
142145
const activeTheme = useMemo(
143146
() =>
144147
bootstrap.input.options.transparentBackground

src/ui/diff/pierre.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { resolveSplitPaneWidths } from "./codeColumns";
1313
import { renderCodeOnlyPlannedRowText, renderDecoratedPlannedRowText } from "./renderRows";
1414
import { buildReviewRenderPlan } from "./reviewRenderPlan";
1515
import { measureTextWidth } from "../lib/text";
16-
import { resolveTheme } from "../themes";
16+
import { TRANSPARENT_BACKGROUND, resolveTheme, withTransparentBackground } from "../themes";
1717

1818
function createDiffFile(): DiffFile {
1919
const metadata = parseDiffFromFile(
@@ -146,6 +146,28 @@ describe("Pierre diff rows", () => {
146146
).toBe(true);
147147
});
148148

149+
test("keeps word-diff highlight backgrounds transparent in transparent mode", async () => {
150+
const file = createDiffFile();
151+
const theme = withTransparentBackground(resolveTheme("midnight", null));
152+
const highlighted = await loadHighlightedDiff(file);
153+
const rows = buildSplitRows(file, highlighted, theme);
154+
const changedRow = rows.find(
155+
(row) =>
156+
row.type === "split-line" && row.left.kind === "deletion" && row.right.kind === "addition",
157+
);
158+
159+
expect(changedRow).toBeDefined();
160+
if (!changedRow || changedRow.type !== "split-line") {
161+
throw new Error("Expected a split-line change row");
162+
}
163+
164+
const removedWordSpan = changedRow.left.spans.find((span) => span.text.includes("41"));
165+
const addedWordSpan = changedRow.right.spans.find((span) => span.text.includes("42"));
166+
167+
expect(removedWordSpan?.bg).toBe(TRANSPARENT_BACKGROUND);
168+
expect(addedWordSpan?.bg).toBe(TRANSPARENT_BACKGROUND);
169+
});
170+
149171
test("builds stacked rows with separate deletion and addition lines", () => {
150172
const file = createDiffFile();
151173
const theme = resolveTheme("paper", null);

src/ui/diff/pierre.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { formatHunkHeader } from "../../core/hunkHeader";
1111
import type { DiffFile } from "../../core/types";
1212
import { blendHex, hexColorDistance } from "../lib/color";
1313
import { sanitizeTerminalLine } from "../../lib/terminalText";
14-
import type { AppTheme } from "../themes";
14+
import { TRANSPARENT_BACKGROUND, type AppTheme } from "../themes";
1515
import { expandDiffTabs } from "./codeColumns";
1616

1717
const PIERRE_THEME = {
@@ -238,6 +238,26 @@ function strengthenWordDiffBg(lineBg: string, signColor: string) {
238238
return strongestCandidate;
239239
}
240240

241+
/** Return whether a theme color can safely participate in RGB distance and blend math. */
242+
function isHexThemeColor(color: string) {
243+
return /^#[0-9a-f]{6}$/i.test(color);
244+
}
245+
246+
/** Resolve one word-diff background without turning transparent surfaces into black blends. */
247+
function resolveWordDiffHighlightBg(contentBg: string, lineBg: string, signColor: string) {
248+
if (contentBg === TRANSPARENT_BACKGROUND || lineBg === TRANSPARENT_BACKGROUND) {
249+
return contentBg;
250+
}
251+
252+
if (!isHexThemeColor(contentBg) || !isHexThemeColor(lineBg)) {
253+
return contentBg;
254+
}
255+
256+
return hexColorDistance(contentBg, lineBg) >= MIN_WORD_DIFF_BG_DISTANCE
257+
? contentBg
258+
: strengthenWordDiffBg(lineBg, signColor);
259+
}
260+
241261
/** Resolve the inline word-diff background, strengthening theme colors that are too subtle to see. */
242262
function wordDiffHighlightBg(kind: SplitLineCell["kind"], theme: AppTheme) {
243263
const cacheKey = [
@@ -251,14 +271,16 @@ function wordDiffHighlightBg(kind: SplitLineCell["kind"], theme: AppTheme) {
251271
].join(":");
252272
let cached = wordDiffBackgroundCache.get(cacheKey);
253273
if (!cached) {
254-
const addition =
255-
hexColorDistance(theme.addedContentBg, theme.addedBg) >= MIN_WORD_DIFF_BG_DISTANCE
256-
? theme.addedContentBg
257-
: strengthenWordDiffBg(theme.addedBg, theme.addedSignColor);
258-
const deletion =
259-
hexColorDistance(theme.removedContentBg, theme.removedBg) >= MIN_WORD_DIFF_BG_DISTANCE
260-
? theme.removedContentBg
261-
: strengthenWordDiffBg(theme.removedBg, theme.removedSignColor);
274+
const addition = resolveWordDiffHighlightBg(
275+
theme.addedContentBg,
276+
theme.addedBg,
277+
theme.addedSignColor,
278+
);
279+
const deletion = resolveWordDiffHighlightBg(
280+
theme.removedContentBg,
281+
theme.removedBg,
282+
theme.removedSignColor,
283+
);
262284

263285
cached = {
264286
addition,

0 commit comments

Comments
 (0)