@heyhuynhgiabuu/pi-diff 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +55 -27
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyhuynhgiabuu/pi-diff",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Shiki-powered terminal diff renderer for pi — syntax-highlighted, word-level diffs in split and unified views.",
5
5
  "author": "huynhgiabuu",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -169,6 +169,16 @@ function deriveBgFromFg(fgAnsi: string, intensity: number): string {
169
169
  return `\x1b[48;2;${r};${g};${b}m`;
170
170
  }
171
171
 
172
+ /** Mix an accent color into a base color at the given intensity (0.0–1.0).
173
+ * Returns an ANSI 24-bit background escape. Used to derive diff backgrounds
174
+ * that blend with the tool box background (toolSuccessBg). */
175
+ function mixBg(base: { r: number; g: number; b: number }, accent: { r: number; g: number; b: number }, intensity: number): string {
176
+ const r = Math.round(base.r + (accent.r - base.r) * intensity);
177
+ const g = Math.round(base.g + (accent.g - base.g) * intensity);
178
+ const b = Math.round(base.b + (accent.b - base.b) * intensity);
179
+ return `\x1b[48;2;${r};${g};${b}m`;
180
+ }
181
+
172
182
  /** Whether auto-derive from theme is still pending (runs lazily on first render). */
173
183
  let _autoDerivePending = true;
174
184
 
@@ -176,37 +186,44 @@ let _autoDerivePending = true;
176
186
  let _hasExplicitBgConfig = false;
177
187
 
178
188
  /** Auto-derive all diff background colors from the pi theme's fg diff colors.
179
- * Uses different intensity levels for line bg, word highlights, and gutters. */
189
+ * Reads toolSuccessBg as the base and mixes accent colors into it.
190
+ * Falls back to black (0,0,0) as base if toolSuccessBg is unavailable. */
180
191
  function autoDeriveBgFromTheme(theme: any): void {
181
192
  if (!theme?.getFgAnsi) return;
182
193
  try {
183
194
  const fgAdd = theme.getFgAnsi("toolDiffAdded");
184
195
  const fgDel = theme.getFgAnsi("toolDiffRemoved");
196
+ const addRgb = parseAnsiRgb(fgAdd);
197
+ const delRgb = parseAnsiRgb(fgDel);
198
+ if (!addRgb || !delRgb) return;
185
199
 
186
- // Line backgrounds subtle tint (8–10% of fg color)
187
- const bgAdd = deriveBgFromFg(fgAdd, 0.08);
188
- if (bgAdd) BG_ADD = bgAdd;
189
- const bgDel = deriveBgFromFg(fgDel, 0.10);
190
- if (bgDel) BG_DEL = bgDel;
200
+ // Read toolSuccessBg as the base background color
201
+ let base = { r: 0, g: 0, b: 0 };
202
+ if (theme.getBgAnsi) {
203
+ try {
204
+ const bgAnsi = theme.getBgAnsi("toolSuccessBg");
205
+ const parsed = parseAnsiRgb(bgAnsi);
206
+ if (parsed) {
207
+ base = parsed;
208
+ BG_BASE = bgAnsi;
209
+ }
210
+ } catch { /* no toolSuccessBg — use black */ }
211
+ }
212
+
213
+ // Line backgrounds — subtle accent mixed into base (8–10%)
214
+ BG_ADD = mixBg(base, addRgb, 0.08);
215
+ BG_DEL = mixBg(base, delRgb, 0.10);
191
216
 
192
217
  // Word-level highlights — more visible (20–22%)
193
- const bgAddW = deriveBgFromFg(fgAdd, 0.20);
194
- if (bgAddW) BG_ADD_W = bgAddW;
195
- const bgDelW = deriveBgFromFg(fgDel, 0.22);
196
- if (bgDelW) BG_DEL_W = bgDelW;
218
+ BG_ADD_W = mixBg(base, addRgb, 0.20);
219
+ BG_DEL_W = mixBg(base, delRgb, 0.22);
197
220
 
198
221
  // Gutters — subtler than lines (5–6%)
199
- const bgGA = deriveBgFromFg(fgAdd, 0.05);
200
- if (bgGA) BG_GUTTER_ADD = bgGA;
201
- const bgGD = deriveBgFromFg(fgDel, 0.06);
202
- if (bgGD) BG_GUTTER_DEL = bgGD;
222
+ BG_GUTTER_ADD = mixBg(base, addRgb, 0.05);
223
+ BG_GUTTER_DEL = mixBg(base, delRgb, 0.06);
203
224
 
204
- // Empty filler neutral dark from add color luminance
205
- const addRgb = parseAnsiRgb(fgAdd);
206
- if (addRgb) {
207
- const lum = Math.round((addRgb.r * 0.3 + addRgb.g * 0.6 + addRgb.b * 0.1) * 0.04);
208
- BG_EMPTY = `\x1b[48;2;${lum};${lum};${lum}m`;
209
- }
225
+ // Empty filler and context match the base
226
+ BG_EMPTY = BG_BASE;
210
227
 
211
228
  // Rebuild derived constants
212
229
  DIVIDER = `${FG_RULE}│${RST}`;
@@ -392,6 +409,7 @@ const ANSI_RE = new RegExp(`${ESC_RE}\\[[0-9;]*m`, "g");
392
409
  const ANSI_CAPTURE_RE = new RegExp(`${ESC_RE}\\[([^m]*)m`, "g");
393
410
  const ANSI_PARAM_CAPTURE_RE = new RegExp(`${ESC_RE}\\[([0-9;]*)m`, "g");
394
411
  const BG_DEFAULT = "\x1b[49m"; // reset to terminal default background
412
+ let BG_BASE = BG_DEFAULT; // tool box base bg — updated from theme's toolSuccessBg
395
413
 
396
414
  // ---------------------------------------------------------------------------
397
415
  // Theme-aware diff colors
@@ -407,8 +425,18 @@ interface DiffColors {
407
425
  let DEFAULT_DIFF_COLORS: DiffColors = { fgAdd: FG_ADD, fgDel: FG_DEL, fgCtx: FG_DIM };
408
426
 
409
427
  /** Resolve diff fg colors from theme (if available), falling back to hardcoded ANSI.
410
- * On first call with a valid theme, auto-derives bg colors if no explicit config was set. */
428
+ * On first call with a valid theme, auto-derives bg colors if no explicit config was set.
429
+ * Always reads toolSuccessBg for BG_BASE (used for context line backgrounds). */
411
430
  function resolveDiffColors(theme?: any): DiffColors {
431
+ // Always read toolSuccessBg for BG_BASE (even with explicit config)
432
+ if (theme?.getBgAnsi && BG_BASE === BG_DEFAULT) {
433
+ try {
434
+ const bgAnsi = theme.getBgAnsi("toolSuccessBg");
435
+ const parsed = parseAnsiRgb(bgAnsi);
436
+ if (parsed) BG_BASE = bgAnsi;
437
+ } catch { /* ignore */ }
438
+ }
439
+
412
440
  // Auto-derive bg colors from theme on first render (if no explicit preset/overrides)
413
441
  if (_autoDerivePending && theme?.getFgAnsi) {
414
442
  autoDeriveBgFromTheme(theme);
@@ -954,7 +982,7 @@ async function renderUnified(
954
982
  bodyBg = "",
955
983
  ): void {
956
984
  const borderFg = sign === "-" ? dc.fgDel : sign === "+" ? dc.fgAdd : "";
957
- const border = borderFg ? `${borderFg}${BORDER_BAR}${RST}` : `${BG_DEFAULT} `;
985
+ const border = borderFg ? `${borderFg}${BORDER_BAR}${RST}` : `${BG_BASE} `;
958
986
  const numFg = borderFg || FG_LNUM;
959
987
  const gutter = `${border}${gutterBg}${lnum(num, nw, numFg)}${signFg}${sign}${RST} ${DIVIDER} `;
960
988
  const contGutter = `${border}${gutterBg}${" ".repeat(nw + 1)}${RST} ${DIVIDER} `;
@@ -982,7 +1010,7 @@ async function renderUnified(
982
1010
  // Context line — dimmed, single line number
983
1011
  if (l.type === "ctx") {
984
1012
  const hl = oldHL[oI] ?? l.content;
985
- emitRow(l.newNum, " ", BG_DEFAULT, dc.fgCtx, `${BG_DEFAULT}${DIM}${hl}`, BG_DEFAULT);
1013
+ emitRow(l.newNum, " ", BG_BASE, dc.fgCtx, `${BG_BASE}${DIM}${hl}`, BG_BASE);
986
1014
  oI++;
987
1015
  nI++;
988
1016
  idx++;
@@ -1126,15 +1154,15 @@ async function renderSplit(
1126
1154
 
1127
1155
  const isDel = line.type === "del",
1128
1156
  isAdd = line.type === "add";
1129
- const gBg = isDel ? BG_GUTTER_DEL : isAdd ? BG_GUTTER_ADD : BG_DEFAULT;
1130
- const cBg = isDel ? BG_DEL : isAdd ? BG_ADD : BG_DEFAULT;
1157
+ const gBg = isDel ? BG_GUTTER_DEL : isAdd ? BG_GUTTER_ADD : BG_BASE;
1158
+ const cBg = isDel ? BG_DEL : isAdd ? BG_ADD : BG_BASE;
1131
1159
  const sFg = isDel ? dc.fgDel : isAdd ? dc.fgAdd : dc.fgCtx;
1132
1160
  const sign = isDel ? "-" : isAdd ? "+" : " ";
1133
1161
  const num = isDel ? line.oldNum : isAdd ? line.newNum : side === "left" ? line.oldNum : line.newNum;
1134
1162
 
1135
1163
  // Border bar + colored line numbers for changed lines
1136
1164
  const borderFg = isDel ? dc.fgDel : isAdd ? dc.fgAdd : "";
1137
- const border = borderFg ? `${borderFg}${BORDER_BAR}${RST}` : ` ${BG_DEFAULT}`;
1165
+ const border = borderFg ? `${borderFg}${BORDER_BAR}${RST}` : ` ${BG_BASE}`;
1138
1166
  const numFg = borderFg || FG_LNUM;
1139
1167
 
1140
1168
  let body: string;
@@ -1143,7 +1171,7 @@ async function renderSplit(
1143
1171
  } else if (isDel || isAdd) {
1144
1172
  body = `${cBg}${hl}`;
1145
1173
  } else {
1146
- body = `${BG_DEFAULT}${DIM}${hl}`;
1174
+ body = `${BG_BASE}${DIM}${hl}`;
1147
1175
  }
1148
1176
 
1149
1177
  const gutter = `${border}${gBg}${lnum(num, nw, numFg)}${sFg}${BOLD}${sign}${RST} ${FG_RULE}│${RST} `;