@pi-archimedes/diff 2.2.0 → 2.3.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-archimedes/diff",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -24,6 +24,8 @@
24
24
  "@earendil-works/pi-tui": ">=0.1.0"
25
25
  },
26
26
  "devDependencies": {
27
+ "@earendil-works/pi-coding-agent": "^0.84.2",
28
+ "@earendil-works/pi-tui": "^0.84.2",
27
29
  "@types/diff": "^7.0.2",
28
30
  "typescript": "^6.0.0"
29
31
  },
package/src/ansi/codes.ts CHANGED
@@ -7,6 +7,7 @@ import { deriveBgFromTheme } from "./colors.js";
7
7
  // ---------------------------------------------------------------------------
8
8
 
9
9
  export const RST = "\x1b[0m";
10
+ export const FG_RST = "\x1b[39m"; // reset foreground only — safe inside background-painted lines
10
11
  export const BOLD = "\x1b[1m";
11
12
  export const DIM = "\x1b[2m";
12
13
 
package/src/ansi/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /** ANSI utilities — barrel re-export. */
2
2
 
3
3
  export {
4
- RST, BOLD, DIM,
4
+ RST, FG_RST, BOLD, DIM,
5
5
  FG_ADD, FG_DEL, FG_DIM, FG_LNUM, FG_RULE, FG_SAFE_MUTED, FG_STRIPE,
6
6
  BORDER_BAR,
7
7
  DEFAULT_DIFF_BG,
package/src/ansi/manip.ts CHANGED
@@ -109,7 +109,7 @@ export function shortPath(cwd: string, home: string, p: string): string {
109
109
  /** Summarize added/removed counts as colored `+N -M` string. */
110
110
  export function summarize(a: number, d: number): string {
111
111
  const p: string[] = [];
112
- if (a > 0) p.push(`${C.FG_ADD}+${a}${C.RST}`);
113
- if (d > 0) p.push(`${C.FG_DEL}-${d}${C.RST}`);
114
- return p.length ? p.join(" ") : `${C.FG_DIM}no changes${C.RST}`;
112
+ if (a > 0) p.push(`${C.FG_ADD}+${a}${C.FG_RST}`);
113
+ if (d > 0) p.push(`${C.FG_DEL}-${d}${C.FG_RST}`);
114
+ return p.length ? p.join(" ") : `${C.FG_DIM}no changes${C.FG_RST}`;
115
115
  }
package/src/tools/edit.ts CHANGED
@@ -143,28 +143,48 @@ export function registerEditTool(
143
143
  renderResult(result: any, _opt: any, theme: any, ctx: any) {
144
144
  // Update the call Box background to reflect final state.
145
145
  const box = ctx.state.callBox as Box | undefined;
146
- if (box) {
147
- const bgKey = ctx.isError ? "toolErrorBg" : "toolSuccessBg";
148
- box.setBgFn((s: string) => theme.bg(bgKey, s));
149
- }
150
- // Show summary below the diff
146
+ const bgKey = ctx.isError ? "toolErrorBg" : "toolSuccessBg";
147
+ if (box) box.setBgFn((s: string) => theme.bg(bgKey, s));
148
+
149
+ // Build the line to show below the diff.
150
+ let line: string;
151
151
  if (ctx.isError) {
152
152
  const e = result.content
153
153
  ?.filter((c: any) => c.type === "text")
154
154
  .map((c: any) => c.text || "")
155
155
  .join("\n") ?? "Error";
156
- return new Text(`\n${theme.fg("error", e)}`, 1, 0);
157
- }
158
- if (result.details?._type === "editInfo") {
156
+ line = theme.fg("error", e);
157
+ } else if (result.details?._type === "editInfo") {
159
158
  const { summary: s, editLine } = result.details;
160
159
  const loc = editLine > 0 ? ` ${theme.fg("muted", `at line ${editLine}`)}` : "";
161
- return new Text(` ${s}${loc}`, 1, 0);
162
- }
163
- if (result.details?._type === "multiEditInfo") {
160
+ line = `${s}${loc}`;
161
+ } else if (result.details?._type === "multiEditInfo") {
164
162
  const { summary: s, editCount, diffLineCount } = result.details;
165
- return new Text(` ${editCount} edits ${s}${typeof diffLineCount === "number" ? ` ${theme.fg("muted", `(${diffLineCount} diff lines)`)}` : ""}`, 1, 0);
163
+ line = `${editCount} edits ${s}${typeof diffLineCount === "number" ? ` ${theme.fg("muted", `(${diffLineCount} diff lines)`)}` : ""}`;
164
+ } else {
165
+ return new Text("", 0, 0);
166
+ }
167
+
168
+ // Render inside the call Box so the line sits on the tool background —
169
+ // a sibling Text would fall through to the raw terminal background.
170
+ // Escape sequences terminating with a full \x1b[0m reset would kill the
171
+ // Box-painted background mid-line, so downgrade them to fg-only resets.
172
+ // Guard against re-adding on every updateDisplay() pass. Must return
173
+ // an EMPTY Text (pi re-adds the returned component as a sibling —
174
+ // returning the attached Text would render the line twice).
175
+ const safeLine = line.replace(/\x1b\[0m/g, Ansi.FG_RST);
176
+ const key = `${bgKey}|${safeLine}`;
177
+ const prev = ctx.state._resText as Text | undefined;
178
+ const empty = new Text("", 0, 0);
179
+ if (prev && ctx.state._resKey === key && box && box.children.includes(prev)) return empty;
180
+ const t = new Text(safeLine, 0, 0);
181
+ if (box) {
182
+ if (prev) box.removeChild(prev);
183
+ box.addChild(t);
166
184
  }
167
- return new Text("", 0, 0);
185
+ ctx.state._resText = t;
186
+ ctx.state._resKey = key;
187
+ return box ? empty : t;
168
188
  },
169
189
  });
170
190
  }