@oh-my-pi/hashline 15.10.4 → 15.10.6

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.
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * Re-number a unified diff that uses the `+<lineNum>|content` /
3
3
  * `-<lineNum>|content` / ` <lineNum>|content` line format into a compact
4
- * preview that anchors every line to its post-edit position. Added lines,
5
- * removed lines, and context lines all end up with a hashline-style anchor
6
- * so a follow-up edit can reuse them directly.
4
+ * current-file preview. Removed lines are counted for stats and post-edit
5
+ * offset tracking, but omitted from the preview. Added and context lines are
6
+ * anchored to their post-edit positions so a follow-up edit can reuse visible
7
+ * concrete lines directly. Long contiguous added runs are summarized with a
8
+ * `…` marker instead of echoing every inserted line.
7
9
  *
8
10
  * This is intentionally decoupled from the diff producer: anything that
9
11
  * emits the `<sign><lineNum>|<content>` shape works.
10
12
  */
11
13
  import type { CompactDiffOptions, CompactDiffPreview } from "./types";
12
- export declare function buildCompactDiffPreview(diff: string, _options?: CompactDiffOptions): CompactDiffPreview;
14
+ export declare function buildCompactDiffPreview(diff: string, options?: CompactDiffOptions): CompactDiffPreview;
@@ -103,9 +103,11 @@ export interface CompactDiffPreview {
103
103
  addedLines: number;
104
104
  removedLines: number;
105
105
  }
106
- /** Optional knobs for {@link buildCompactDiffPreview}. Reserved for future use. */
106
+ /** Optional knobs for {@link buildCompactDiffPreview}. */
107
107
  export interface CompactDiffOptions {
108
- /** Maximum entries kept on each side of an unchanged-context truncation (default 2). */
108
+ /** Added lines kept on each side of a long added-run elision (default 2). */
109
+ maxAddedRunContext?: number;
110
+ /** Back-compat alias for {@link maxAddedRunContext}. */
109
111
  maxUnchangedRun?: number;
110
112
  }
111
113
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/hashline",
4
- "version": "15.10.4",
4
+ "version": "15.10.6",
5
5
  "description": "Hashline: a compact, line-anchored patch language and applier. Pluggable FS/IO so it works over disk, in-memory, or any custom backend.",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -1,49 +1,112 @@
1
1
  /**
2
2
  * Re-number a unified diff that uses the `+<lineNum>|content` /
3
3
  * `-<lineNum>|content` / ` <lineNum>|content` line format into a compact
4
- * preview that anchors every line to its post-edit position. Added lines,
5
- * removed lines, and context lines all end up with a hashline-style anchor
6
- * so a follow-up edit can reuse them directly.
4
+ * current-file preview. Removed lines are counted for stats and post-edit
5
+ * offset tracking, but omitted from the preview. Added and context lines are
6
+ * anchored to their post-edit positions so a follow-up edit can reuse visible
7
+ * concrete lines directly. Long contiguous added runs are summarized with a
8
+ * `…` marker instead of echoing every inserted line.
7
9
  *
8
10
  * This is intentionally decoupled from the diff producer: anything that
9
11
  * emits the `<sign><lineNum>|<content>` shape works.
10
12
  */
11
13
  import type { CompactDiffOptions, CompactDiffPreview } from "./types";
12
14
 
13
- export function buildCompactDiffPreview(diff: string, _options: CompactDiffOptions = {}): CompactDiffPreview {
15
+ const DEFAULT_ADDED_RUN_CONTEXT_LINES = 2;
16
+
17
+ const PREVIEW_ELISION_MARKER = "…";
18
+ const RAW_ELISION_MARKERS = new Set(["...", PREVIEW_ELISION_MARKER, `+${PREVIEW_ELISION_MARKER}`]);
19
+
20
+ function appendPreviewLine(output: string[], line: string): void {
21
+ const normalized = RAW_ELISION_MARKERS.has(line) ? PREVIEW_ELISION_MARKER : line;
22
+ if (normalized === PREVIEW_ELISION_MARKER && output[output.length - 1] === PREVIEW_ELISION_MARKER) return;
23
+ output.push(normalized);
24
+ }
25
+
26
+ interface ParsedDiffLine {
27
+ kind: "+" | "-" | " ";
28
+ lineNumber: number;
29
+ content: string;
30
+ }
31
+
32
+ function normalizeAddedRunContext(value: number | undefined): number {
33
+ if (value === undefined || !Number.isFinite(value)) return DEFAULT_ADDED_RUN_CONTEXT_LINES;
34
+ return Math.max(1, Math.trunc(value));
35
+ }
36
+
37
+ function parseNumberedDiffLine(line: string): ParsedDiffLine | undefined {
38
+ const kind = line[0];
39
+ if (kind !== "+" && kind !== "-" && kind !== " ") return undefined;
40
+
41
+ const body = line.slice(1);
42
+ const sep = body.indexOf("|");
43
+ if (sep === -1) return undefined;
44
+
45
+ const lineNumber = Number.parseInt(body.slice(0, sep), 10);
46
+ if (!Number.isFinite(lineNumber)) return undefined;
47
+
48
+ return { kind, lineNumber, content: body.slice(sep + 1) };
49
+ }
50
+
51
+ function appendAddedRun(output: string[], run: string[], edgeLines: number): void {
52
+ if (run.length === 0) return;
53
+
54
+ const collapseThreshold = edgeLines * 2 + 1;
55
+ if (run.length <= collapseThreshold) {
56
+ for (const text of run) appendPreviewLine(output, text);
57
+ return;
58
+ }
59
+
60
+ for (let i = 0; i < edgeLines; i++) appendPreviewLine(output, run[i]);
61
+ appendPreviewLine(output, PREVIEW_ELISION_MARKER);
62
+ for (let i = run.length - edgeLines; i < run.length; i++) appendPreviewLine(output, run[i]);
63
+ }
64
+
65
+ export function buildCompactDiffPreview(diff: string, options: CompactDiffOptions = {}): CompactDiffPreview {
14
66
  const lines = diff.length === 0 ? [] : diff.split("\n");
67
+ const addedRunContext = normalizeAddedRunContext(options.maxAddedRunContext ?? options.maxUnchangedRun);
15
68
  let addedLines = 0;
16
69
  let removedLines = 0;
70
+ const formatted: string[] = [];
71
+ const addedRun: string[] = [];
72
+
73
+ const flushAddedRun = (): void => {
74
+ appendAddedRun(formatted, addedRun, addedRunContext);
75
+ addedRun.length = 0;
76
+ };
17
77
 
18
78
  // External diff producers number `+` lines with the post-edit line number,
19
79
  // `-` lines with the pre-edit line number, and context lines with the
20
80
  // pre-edit line number. To emit fresh line numbers usable for follow-up
21
81
  // edits, convert context-line numbers to post-edit positions by tracking
22
82
  // the running offset (added so far - removed so far) as we walk the diff.
23
- const formatted = lines.map(line => {
24
- const kind = line[0];
25
- if (kind !== "+" && kind !== "-" && kind !== " ") return line;
26
-
27
- const body = line.slice(1);
28
- const sep = body.indexOf("|");
29
- if (sep === -1) return line;
30
-
31
- const lineNumber = Number.parseInt(body.slice(0, sep), 10);
32
- const content = body.slice(sep + 1);
83
+ for (const line of lines) {
84
+ const parsed = parseNumberedDiffLine(line);
85
+ if (!parsed) {
86
+ flushAddedRun();
87
+ appendPreviewLine(formatted, line);
88
+ continue;
89
+ }
33
90
 
34
- switch (kind) {
35
- case "+":
91
+ switch (parsed.kind) {
92
+ case "+": {
36
93
  addedLines++;
37
- return `+${lineNumber}:${content}`;
94
+ addedRun.push(`${parsed.lineNumber}:${parsed.content}`);
95
+ break;
96
+ }
38
97
  case "-":
98
+ flushAddedRun();
39
99
  removedLines++;
40
- return `-${lineNumber}:${content}`;
100
+ break;
41
101
  default: {
42
- const newLineNumber = lineNumber + addedLines - removedLines;
43
- return ` ${newLineNumber}:${content}`;
102
+ flushAddedRun();
103
+ const newLineNumber = parsed.lineNumber + addedLines - removedLines;
104
+ appendPreviewLine(formatted, `${newLineNumber}:${parsed.content}`);
105
+ break;
44
106
  }
45
107
  }
46
- });
108
+ }
109
+ flushAddedRun();
47
110
 
48
111
  return { preview: formatted.join("\n"), addedLines, removedLines };
49
112
  }
package/src/types.ts CHANGED
@@ -103,9 +103,11 @@ export interface CompactDiffPreview {
103
103
  removedLines: number;
104
104
  }
105
105
 
106
- /** Optional knobs for {@link buildCompactDiffPreview}. Reserved for future use. */
106
+ /** Optional knobs for {@link buildCompactDiffPreview}. */
107
107
  export interface CompactDiffOptions {
108
- /** Maximum entries kept on each side of an unchanged-context truncation (default 2). */
108
+ /** Added lines kept on each side of a long added-run elision (default 2). */
109
+ maxAddedRunContext?: number;
110
+ /** Back-compat alias for {@link maxAddedRunContext}. */
109
111
  maxUnchangedRun?: number;
110
112
  }
111
113