@heyhuynhgiabuu/pi-diff 0.7.0 → 0.7.1
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/dist/core/hashline-edit.d.ts +17 -0
- package/dist/core/hashline-edit.d.ts.map +1 -0
- package/dist/core/hashline-edit.js +42 -0
- package/dist/core/hashline-edit.js.map +1 -0
- package/dist/core/hashline-execute.d.ts +24 -0
- package/dist/core/hashline-execute.d.ts.map +1 -0
- package/dist/core/hashline-execute.js +94 -0
- package/dist/core/hashline-execute.js.map +1 -0
- package/dist/core/text-encoding.d.ts +19 -0
- package/dist/core/text-encoding.d.ts.map +1 -0
- package/dist/core/text-encoding.js +30 -0
- package/dist/core/text-encoding.js.map +1 -0
- package/dist/hashline.d.ts +61 -0
- package/dist/hashline.d.ts.map +1 -0
- package/dist/hashline.js +259 -0
- package/dist/hashline.js.map +1 -0
- package/package.json +18 -2
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type HashlineApplyError, type HashlineApplyOk, type HashlineEdit } from "../hashline.js";
|
|
2
|
+
export type FileHashlineApplyResult = HashlineApplyOk | HashlineApplyError;
|
|
3
|
+
export type HashlineEditApplyOptions = {
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
/** If set, skip reading filePath (caller already read once). */
|
|
6
|
+
rawUtf8?: string;
|
|
7
|
+
};
|
|
8
|
+
export type FileHashlineApplyOk = HashlineApplyOk & {
|
|
9
|
+
newContent: string;
|
|
10
|
+
/** Full on-disk text after edit (BOM + EOL restored); same as written when not dryRun. */
|
|
11
|
+
finalRaw: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function applyHashlineEditsToFile(filePath: string, changes: HashlineEdit[], options?: HashlineEditApplyOptions): Promise<(FileHashlineApplyOk | HashlineApplyError) & {
|
|
14
|
+
newContent?: string;
|
|
15
|
+
finalRaw?: string;
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=hashline-edit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline-edit.d.ts","sourceRoot":"","sources":["../../src/core/hashline-edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKtH,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAE3E,MAAM,MAAM,wBAAwB,GAAG;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AASF,wBAAsB,wBAAwB,CAC7C,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,CAAC,EAAE,wBAAwB,GAChC,OAAO,CAAC,CAAC,mBAAmB,GAAG,kBAAkB,CAAC,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BlG"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { applyHashlineEdits } from "../hashline.js";
|
|
2
|
+
import { finalizeHashlineWriteContent, prepareTextForHashlineEdit } from "./text-encoding.js";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
async function atomicWriteFile(filePath, content) {
|
|
6
|
+
const dir = path.dirname(filePath);
|
|
7
|
+
const tmp = path.join(dir, `.${path.basename(filePath)}.pi-hashline.${process.pid}.tmp`);
|
|
8
|
+
await fs.promises.writeFile(tmp, content, "utf8");
|
|
9
|
+
await fs.promises.rename(tmp, filePath);
|
|
10
|
+
}
|
|
11
|
+
export async function applyHashlineEditsToFile(filePath, changes, options) {
|
|
12
|
+
const dryRun = options?.dryRun === true;
|
|
13
|
+
let raw;
|
|
14
|
+
if (options?.rawUtf8 !== undefined) {
|
|
15
|
+
raw = options.rawUtf8;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
try {
|
|
19
|
+
raw = await fs.promises.readFile(filePath, "utf8");
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
23
|
+
return { ok: false, error: `[E_READ_FAILED] cannot read ${filePath}: ${msg}`, code: "E_READ_FAILED" };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const { bom, ending, normalized } = prepareTextForHashlineEdit(raw);
|
|
27
|
+
const result = applyHashlineEdits(normalized, changes, filePath);
|
|
28
|
+
if (!result.ok)
|
|
29
|
+
return result;
|
|
30
|
+
const finalRaw = finalizeHashlineWriteContent(bom, ending, result.newContent);
|
|
31
|
+
if (!dryRun) {
|
|
32
|
+
try {
|
|
33
|
+
await atomicWriteFile(filePath, finalRaw);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
37
|
+
return { ok: false, error: `[E_WRITE_FAILED] cannot write ${filePath}: ${msg}`, code: "E_WRITE_FAILED" };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { ...result, newContent: result.newContent, finalRaw };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=hashline-edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline-edit.js","sourceRoot":"","sources":["../../src/core/hashline-edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAoE,MAAM,gBAAgB,CAAC;AACtH,OAAO,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAC9F,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAgBlC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAe;IAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IACzF,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC7C,QAAgB,EAChB,OAAuB,EACvB,OAAkC;IAElC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,IAAI,GAAW,CAAC;IAChB,IAAI,OAAO,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;QACpC,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IACvB,CAAC;SAAM,CAAC;QACP,IAAI,CAAC;YACJ,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,QAAQ,KAAK,GAAG,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;QACvG,CAAC;IACF,CAAC;IAED,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,0BAA0B,CAAC,GAAG,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IAE9B,MAAM,QAAQ,GAAG,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC9E,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,IAAI,CAAC;YACJ,MAAM,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iCAAiC,QAAQ,KAAK,GAAG,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;QAC1G,CAAC;IACF,CAAC;IAED,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ParsedDiff } from "./diff.js";
|
|
2
|
+
import type { HashlineEdit } from "../hashline.js";
|
|
3
|
+
export declare const HASHLINE_WORKFLOW = "Workflow: hashline_read(path) \u2192 copy anchors from output \u2192 hashline_edit(path, hashlineChanges). Do not use plain read for edits.";
|
|
4
|
+
export declare const HASHLINE_READ_DESC = "Workflow: hashline_read(path) \u2192 copy anchors from output \u2192 hashline_edit(path, hashlineChanges). Do not use plain read for edits. Returns lines as LINE\u2502HASH\u2502content (1-based line numbers). Use HASH anchors in hashline_edit only.";
|
|
5
|
+
export declare const HASHLINE_EDIT_DESC = "Workflow: hashline_read(path) \u2192 copy anchors from output \u2192 hashline_edit(path, hashlineChanges). Do not use plain read for edits. Strict atomic apply. Empty content_lines deletes the range. Set dryRun:true to validate and preview diff without writing.";
|
|
6
|
+
export type HashlineToolResult = {
|
|
7
|
+
content: Array<{
|
|
8
|
+
type: "text";
|
|
9
|
+
text: string;
|
|
10
|
+
}>;
|
|
11
|
+
isError?: boolean;
|
|
12
|
+
details: Record<string, unknown>;
|
|
13
|
+
};
|
|
14
|
+
export type HashlineExecuteOptions = {
|
|
15
|
+
resolvedPath: string;
|
|
16
|
+
changes: HashlineEdit[];
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
/** Pi tool call id — used to stash diff stats for renderCall */
|
|
19
|
+
toolCallId?: string;
|
|
20
|
+
onDiffStats?: (toolCallId: string, diff: ParsedDiff) => void;
|
|
21
|
+
};
|
|
22
|
+
export declare function runHashlineEdit(opts: HashlineExecuteOptions): Promise<HashlineToolResult>;
|
|
23
|
+
export declare function executeHashlineRead(fp: string, content: string, startLine: number, endLine: number): HashlineToolResult;
|
|
24
|
+
//# sourceMappingURL=hashline-execute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline-execute.d.ts","sourceRoot":"","sources":["../../src/core/hashline-execute.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAM7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,eAAO,MAAM,iBAAiB,gJACsG,CAAC;AAErI,eAAO,MAAM,kBAAkB,6PAC2F,CAAC;AAE3H,eAAO,MAAM,kBAAkB,0QACkH,CAAC;AAElJ,MAAM,MAAM,kBAAkB,GAAG;IAChC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CAC7D,CAAC;AAoCF,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkD/F;AAED,wBAAgB,mBAAmB,CAClC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACb,kBAAkB,CAYpB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as Diff from "diff";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import { parsePatchFiles } from "./diff.js";
|
|
4
|
+
import { applyHashlineEditsToFile, } from "./hashline-edit.js";
|
|
5
|
+
import { formatHashlineReadLines } from "../hashline.js";
|
|
6
|
+
export const HASHLINE_WORKFLOW = "Workflow: hashline_read(path) → copy anchors from output → hashline_edit(path, hashlineChanges). Do not use plain read for edits.";
|
|
7
|
+
export const HASHLINE_READ_DESC = `${HASHLINE_WORKFLOW} Returns lines as LINE│HASH│content (1-based line numbers). Use HASH anchors in hashline_edit only.`;
|
|
8
|
+
export const HASHLINE_EDIT_DESC = `${HASHLINE_WORKFLOW} Strict atomic apply. Empty content_lines deletes the range. Set dryRun:true to validate and preview diff without writing.`;
|
|
9
|
+
function buildDiff(before, after, fp) {
|
|
10
|
+
if (before === after)
|
|
11
|
+
return null;
|
|
12
|
+
const patch = Diff.createPatch(fp, before, after, "before", "after", { context: 3 });
|
|
13
|
+
const parsed = parsePatchFiles(patch);
|
|
14
|
+
return parsed[0] || null;
|
|
15
|
+
}
|
|
16
|
+
function formatOkText(fp, changedRange, dryRun, warnings) {
|
|
17
|
+
const start = changedRange[0] + 1;
|
|
18
|
+
const end = changedRange[1] + 1;
|
|
19
|
+
const prefix = dryRun ? "[DRY-RUN]" : "[OK]";
|
|
20
|
+
let text = `${prefix} ${fp} ${dryRun ? "would edit" : "edited"} (lines ${start}-${end})`;
|
|
21
|
+
if (warnings.length > 0) {
|
|
22
|
+
text += `\n[${warnings.length} boundary warning(s)]\n${warnings.join("\n")}`;
|
|
23
|
+
}
|
|
24
|
+
return text;
|
|
25
|
+
}
|
|
26
|
+
function rereadHintFromSuggestions(fp, suggestions) {
|
|
27
|
+
if (!suggestions?.length)
|
|
28
|
+
return undefined;
|
|
29
|
+
const lines = suggestions.map((s) => s.line + 1);
|
|
30
|
+
const startLine = Math.max(1, Math.min(...lines) - 2);
|
|
31
|
+
const endLine = Math.max(...lines) + 2;
|
|
32
|
+
return { path: fp, startLine, endLine };
|
|
33
|
+
}
|
|
34
|
+
export async function runHashlineEdit(opts) {
|
|
35
|
+
const { resolvedPath: fp, changes, dryRun = false, toolCallId, onDiffStats } = opts;
|
|
36
|
+
let beforeContent = "";
|
|
37
|
+
let rawUtf8;
|
|
38
|
+
try {
|
|
39
|
+
beforeContent = await fs.promises.readFile(fp, "utf8");
|
|
40
|
+
rawUtf8 = beforeContent;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// applyHashlineEditsToFile reads once when rawUtf8 is omitted
|
|
44
|
+
}
|
|
45
|
+
const applyOpts = { dryRun, rawUtf8 };
|
|
46
|
+
const result = await applyHashlineEditsToFile(fp, changes, applyOpts);
|
|
47
|
+
if (!result.ok) {
|
|
48
|
+
const reread = rereadHintFromSuggestions(fp, result.suggestions);
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text: result.error }],
|
|
51
|
+
isError: true,
|
|
52
|
+
details: {
|
|
53
|
+
_type: "hashlineEditError",
|
|
54
|
+
path: fp,
|
|
55
|
+
code: result.code,
|
|
56
|
+
ref: result.ref,
|
|
57
|
+
suggestions: result.suggestions,
|
|
58
|
+
hashlineRereadHint: reread,
|
|
59
|
+
nextStep: `hashline_read path=${JSON.stringify(fp)}${reread ? ` startLine=${reread.startLine} endLine=${reread.endLine}` : ""}`,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const afterContent = result.finalRaw ?? beforeContent;
|
|
64
|
+
const diff = buildDiff(beforeContent, afterContent, fp);
|
|
65
|
+
if (diff && toolCallId && onDiffStats) {
|
|
66
|
+
onDiffStats(toolCallId, diff);
|
|
67
|
+
}
|
|
68
|
+
const warnings = result.boundaryWarnings ?? [];
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: "text", text: formatOkText(fp, result.changedRange, dryRun, warnings) }],
|
|
71
|
+
details: {
|
|
72
|
+
_type: dryRun ? "hashlineEditDryRun" : "hashlineEditInfo",
|
|
73
|
+
path: fp,
|
|
74
|
+
diff,
|
|
75
|
+
dryRun,
|
|
76
|
+
result,
|
|
77
|
+
before: beforeContent,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function executeHashlineRead(fp, content, startLine, endLine) {
|
|
82
|
+
const { text, lineCount, startLine: from, endLine: to } = formatHashlineReadLines(content, startLine, endLine);
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text }],
|
|
85
|
+
details: {
|
|
86
|
+
_type: "hashlineReadInfo",
|
|
87
|
+
path: fp,
|
|
88
|
+
lineCount,
|
|
89
|
+
startLine: from,
|
|
90
|
+
endLine: to,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=hashline-execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline-execute.js","sourceRoot":"","sources":["../../src/core/hashline-execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM and line-ending preservation for hashline file I/O (aligned with pi-mono edit tool).
|
|
3
|
+
*/
|
|
4
|
+
export type LineEnding = "\r\n" | "\n";
|
|
5
|
+
export declare function stripBom(content: string): {
|
|
6
|
+
bom: string;
|
|
7
|
+
text: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function detectLineEnding(content: string): LineEnding;
|
|
10
|
+
export declare function normalizeToLF(text: string): string;
|
|
11
|
+
export declare function restoreLineEndings(text: string, ending: LineEnding): string;
|
|
12
|
+
/** Strip BOM and normalize newlines for hashline matching; keep metadata for write-back. */
|
|
13
|
+
export declare function prepareTextForHashlineEdit(rawUtf8: string): {
|
|
14
|
+
bom: string;
|
|
15
|
+
ending: LineEnding;
|
|
16
|
+
normalized: string;
|
|
17
|
+
};
|
|
18
|
+
export declare function finalizeHashlineWriteContent(bom: string, ending: LineEnding, lfContent: string): string;
|
|
19
|
+
//# sourceMappingURL=text-encoding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-encoding.d.ts","sourceRoot":"","sources":["../../src/core/text-encoding.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;AAEvC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAEvE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAK5D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAE3E;AAED,4FAA4F;AAC5F,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACnB,CAKA;AAED,wBAAgB,4BAA4B,CAC3C,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,GACf,MAAM,CAER"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM and line-ending preservation for hashline file I/O (aligned with pi-mono edit tool).
|
|
3
|
+
*/
|
|
4
|
+
export function stripBom(content) {
|
|
5
|
+
return content.startsWith("\uFEFF") ? { bom: "\uFEFF", text: content.slice(1) } : { bom: "", text: content };
|
|
6
|
+
}
|
|
7
|
+
export function detectLineEnding(content) {
|
|
8
|
+
const crlfIdx = content.indexOf("\r\n");
|
|
9
|
+
const lfIdx = content.indexOf("\n");
|
|
10
|
+
if (lfIdx === -1 || crlfIdx === -1)
|
|
11
|
+
return "\n";
|
|
12
|
+
return crlfIdx < lfIdx ? "\r\n" : "\n";
|
|
13
|
+
}
|
|
14
|
+
export function normalizeToLF(text) {
|
|
15
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
16
|
+
}
|
|
17
|
+
export function restoreLineEndings(text, ending) {
|
|
18
|
+
return ending === "\r\n" ? text.replace(/\n/g, "\r\n") : text;
|
|
19
|
+
}
|
|
20
|
+
/** Strip BOM and normalize newlines for hashline matching; keep metadata for write-back. */
|
|
21
|
+
export function prepareTextForHashlineEdit(rawUtf8) {
|
|
22
|
+
const { bom, text } = stripBom(rawUtf8);
|
|
23
|
+
const ending = detectLineEnding(text);
|
|
24
|
+
const normalized = normalizeToLF(text);
|
|
25
|
+
return { bom, ending, normalized };
|
|
26
|
+
}
|
|
27
|
+
export function finalizeHashlineWriteContent(bom, ending, lfContent) {
|
|
28
|
+
return bom + restoreLineEndings(lfContent, ending);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=text-encoding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-encoding.js","sourceRoot":"","sources":["../../src/core/text-encoding.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACvC,OAAO,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC9G,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,OAAO,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,MAAkB;IAClE,OAAO,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,0BAA0B,CAAC,OAAe;IAKzD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC3C,GAAW,EACX,MAAkB,EAClB,SAAiB;IAEjB,OAAO,GAAG,GAAG,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashline engine — content-anchored line IDs for robust edits.
|
|
3
|
+
*
|
|
4
|
+
* Hash format: 3-char URL-safe base64 from xxHash32, 18 bits entropy.
|
|
5
|
+
* Display: `HASH│content` (U+2502 box drawings light vertical).
|
|
6
|
+
* Collisions: resolved with `:R{n}` suffix (perfect hashing per file).
|
|
7
|
+
* Canonical: CR stripped, trailing whitespace stripped before hashing.
|
|
8
|
+
*
|
|
9
|
+
* Design: edit-pro style (strict, no fuzzy fallback). The 6-strategy
|
|
10
|
+
* oldString path in `core/replace.ts` remains as a fallback for models
|
|
11
|
+
* that don't use the hashline format.
|
|
12
|
+
*/
|
|
13
|
+
export declare function initHashline(): Promise<void>;
|
|
14
|
+
export declare function hashLines(content: string): string[];
|
|
15
|
+
export declare function parseAnchor(ref: string | undefined | null): string;
|
|
16
|
+
export interface AnchorResolveOk {
|
|
17
|
+
ok: true;
|
|
18
|
+
line: number;
|
|
19
|
+
ref: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AnchorResolveError {
|
|
22
|
+
ok: false;
|
|
23
|
+
error: "empty" | "not_found" | "ambiguous";
|
|
24
|
+
ref: string;
|
|
25
|
+
suggestions?: Array<{
|
|
26
|
+
line: number;
|
|
27
|
+
ref: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export declare function resolveAnchor(ref: string, fileHashes: string[]): AnchorResolveOk | AnchorResolveError;
|
|
31
|
+
export interface HashlineEdit {
|
|
32
|
+
hash_range_inclusive: [string, string];
|
|
33
|
+
content_lines: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface HashlineApplyOk {
|
|
36
|
+
ok: true;
|
|
37
|
+
newContent: string;
|
|
38
|
+
changedRange: [number, number];
|
|
39
|
+
boundaryWarnings: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface HashlineApplyError {
|
|
42
|
+
ok: false;
|
|
43
|
+
error: string;
|
|
44
|
+
code: "E_STALE_ANCHOR" | "E_BAD_RANGE" | "E_OVERLAP" | "E_EMPTY" | "E_NOT_INITIALIZED" | "E_READ_FAILED" | "E_WRITE_FAILED";
|
|
45
|
+
ref?: string;
|
|
46
|
+
suggestions?: Array<{
|
|
47
|
+
line: number;
|
|
48
|
+
ref: string;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
export declare function applyHashlineEdits(fileContent: string, changes: HashlineEdit[], filePathForErrors?: string): HashlineApplyOk | HashlineApplyError;
|
|
52
|
+
export declare function formatHashlineReadLines(fileContent: string, startLine?: number, endLine?: number): {
|
|
53
|
+
text: string;
|
|
54
|
+
lineCount: number;
|
|
55
|
+
startLine: number;
|
|
56
|
+
endLine: number;
|
|
57
|
+
};
|
|
58
|
+
/** @deprecated Use formatHashlineReadLines */
|
|
59
|
+
export declare function formatHashlineReadView(fileContent: string): string;
|
|
60
|
+
export declare function clearHashlineCache(): void;
|
|
61
|
+
//# sourceMappingURL=hashline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline.d.ts","sourceRoot":"","sources":["../src/hashline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH,wBAAgB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAO5C;AA2BD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BnD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAOlE;AAED,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACZ;AACD,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,WAAW,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AA+BD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,eAAe,GAAG,kBAAkB,CAmBrG;AAED,MAAM,WAAW,YAAY;IAC5B,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,aAAa,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,IAAI,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC3B;AACD,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,gBAAgB,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,mBAAmB,GAAG,eAAe,GAAG,gBAAgB,CAAC;IAC5H,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AASD,wBAAgB,kBAAkB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EAAE,EACvB,iBAAiB,SAAK,GACpB,eAAe,GAAG,kBAAkB,CAkGtC;AAUD,wBAAgB,uBAAuB,CACtC,WAAW,EAAE,MAAM,EACnB,SAAS,SAAI,EACb,OAAO,SAAW,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAUzE;AAED,8CAA8C;AAC9C,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
package/dist/hashline.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashline engine — content-anchored line IDs for robust edits.
|
|
3
|
+
*
|
|
4
|
+
* Hash format: 3-char URL-safe base64 from xxHash32, 18 bits entropy.
|
|
5
|
+
* Display: `HASH│content` (U+2502 box drawings light vertical).
|
|
6
|
+
* Collisions: resolved with `:R{n}` suffix (perfect hashing per file).
|
|
7
|
+
* Canonical: CR stripped, trailing whitespace stripped before hashing.
|
|
8
|
+
*
|
|
9
|
+
* Design: edit-pro style (strict, no fuzzy fallback). The 6-strategy
|
|
10
|
+
* oldString path in `core/replace.ts` remains as a fallback for models
|
|
11
|
+
* that don't use the hashline format.
|
|
12
|
+
*/
|
|
13
|
+
import xxhashWasm from "xxhash-wasm";
|
|
14
|
+
const DICT = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
15
|
+
const HASH_LEN = 3;
|
|
16
|
+
const HASH_MOD = 64 ** 3; // 262144
|
|
17
|
+
const SEP = "\u2502"; // │
|
|
18
|
+
let h32Fn = null;
|
|
19
|
+
let initPromise = null;
|
|
20
|
+
export function initHashline() {
|
|
21
|
+
if (!initPromise) {
|
|
22
|
+
initPromise = xxhashWasm().then((xxh) => {
|
|
23
|
+
h32Fn = xxh.h32;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return initPromise;
|
|
27
|
+
}
|
|
28
|
+
function ensureReady() {
|
|
29
|
+
if (!h32Fn)
|
|
30
|
+
throw new Error("[E_NOT_INITIALIZED] hashline: initHashline() not called before use");
|
|
31
|
+
return h32Fn;
|
|
32
|
+
}
|
|
33
|
+
function canonicalize(line) {
|
|
34
|
+
if (line.endsWith("\r"))
|
|
35
|
+
line = line.slice(0, -1);
|
|
36
|
+
return line.replace(/[ \t]+$/, "");
|
|
37
|
+
}
|
|
38
|
+
function toDict(n) {
|
|
39
|
+
let s = "";
|
|
40
|
+
for (let i = 0; i < HASH_LEN; i++) {
|
|
41
|
+
s = DICT[n & 63] + s;
|
|
42
|
+
n >>>= 6;
|
|
43
|
+
}
|
|
44
|
+
return s;
|
|
45
|
+
}
|
|
46
|
+
function rawHash(canonical, seed = 0) {
|
|
47
|
+
return ensureReady()(canonical, seed) >>> 0;
|
|
48
|
+
}
|
|
49
|
+
const hashCache = new Map();
|
|
50
|
+
export function hashLines(content) {
|
|
51
|
+
const cached = hashCache.get(content);
|
|
52
|
+
if (cached)
|
|
53
|
+
return cached;
|
|
54
|
+
content = content.replace(/\r\n/g, "\n");
|
|
55
|
+
const lines = content.split("\n");
|
|
56
|
+
const hashes = [];
|
|
57
|
+
const seen = new Map();
|
|
58
|
+
for (const line of lines) {
|
|
59
|
+
const canon = canonicalize(line);
|
|
60
|
+
let hash = toDict(rawHash(canon) % HASH_MOD);
|
|
61
|
+
let count = seen.get(hash) ?? 0;
|
|
62
|
+
if (count > 0) {
|
|
63
|
+
let resolved = null;
|
|
64
|
+
for (let retry = 1; retry < 1000; retry++) {
|
|
65
|
+
const candidate = `${toDict(rawHash(canon, retry) % HASH_MOD)}:R${retry}`;
|
|
66
|
+
if (!seen.has(candidate)) {
|
|
67
|
+
resolved = candidate;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (resolved)
|
|
72
|
+
hash = resolved;
|
|
73
|
+
else
|
|
74
|
+
throw new Error(`[E_HASH_COLLISION] cannot resolve collision for line: ${canon.slice(0, 80)}`);
|
|
75
|
+
}
|
|
76
|
+
seen.set(hash, 1);
|
|
77
|
+
hashes.push(hash);
|
|
78
|
+
}
|
|
79
|
+
hashCache.set(content, hashes);
|
|
80
|
+
return hashes;
|
|
81
|
+
}
|
|
82
|
+
export function parseAnchor(ref) {
|
|
83
|
+
if (typeof ref !== "string")
|
|
84
|
+
return "";
|
|
85
|
+
// Strip the "│content" or " content" suffix. Anchor format is
|
|
86
|
+
// either 3-char base64 or 3-char base64 with :R{n} collision suffix.
|
|
87
|
+
const idx = ref.indexOf(SEP);
|
|
88
|
+
if (idx >= 0)
|
|
89
|
+
ref = ref.slice(0, idx);
|
|
90
|
+
return ref.trim();
|
|
91
|
+
}
|
|
92
|
+
function formatAnchorFailureMessage(role, refRaw, fail, filePath) {
|
|
93
|
+
const reason = fail.error === "ambiguous"
|
|
94
|
+
? "ambiguous (multiple lines share this anchor)"
|
|
95
|
+
: fail.error === "empty"
|
|
96
|
+
? "empty anchor"
|
|
97
|
+
: "not found (file changed since hashline_read)";
|
|
98
|
+
let msg = `[E_STALE_ANCHOR] ${role} anchor ${JSON.stringify(refRaw)} — ${reason}.`;
|
|
99
|
+
if (fail.suggestions?.length) {
|
|
100
|
+
const hints = fail.suggestions
|
|
101
|
+
.map((s) => `line ${s.line + 1} ref ${s.ref}`)
|
|
102
|
+
.join("; ");
|
|
103
|
+
msg += ` Nearby: ${hints}.`;
|
|
104
|
+
}
|
|
105
|
+
const rereadStart = fail.suggestions?.length
|
|
106
|
+
? Math.max(1, Math.min(...fail.suggestions.map((s) => s.line + 1)) - 2)
|
|
107
|
+
: 1;
|
|
108
|
+
const rereadEnd = fail.suggestions?.length
|
|
109
|
+
? Math.max(...fail.suggestions.map((s) => s.line + 1)) + 2
|
|
110
|
+
: "";
|
|
111
|
+
msg += ` Next: hashline_read path=${JSON.stringify(filePath)} startLine=${rereadStart}${rereadEnd ? ` endLine=${rereadEnd}` : ""}.`;
|
|
112
|
+
return msg;
|
|
113
|
+
}
|
|
114
|
+
export function resolveAnchor(ref, fileHashes) {
|
|
115
|
+
if (ref === "")
|
|
116
|
+
return { ok: false, error: "empty", ref };
|
|
117
|
+
const matches = [];
|
|
118
|
+
for (let i = 0; i < fileHashes.length; i++) {
|
|
119
|
+
if (fileHashes[i] === ref)
|
|
120
|
+
matches.push(i);
|
|
121
|
+
}
|
|
122
|
+
if (matches.length === 1)
|
|
123
|
+
return { ok: true, line: matches[0], ref };
|
|
124
|
+
if (matches.length === 0) {
|
|
125
|
+
const suggestions = [];
|
|
126
|
+
for (let i = 0; i < fileHashes.length; i++) {
|
|
127
|
+
if (suggestions.length >= 5)
|
|
128
|
+
break;
|
|
129
|
+
const h = fileHashes[i];
|
|
130
|
+
if (h.length >= 3 && (h.startsWith(ref) || ref.startsWith(h.slice(0, 3)))) {
|
|
131
|
+
suggestions.push({ line: i, ref: h });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { ok: false, error: "not_found", ref, suggestions };
|
|
135
|
+
}
|
|
136
|
+
return { ok: false, error: "ambiguous", ref };
|
|
137
|
+
}
|
|
138
|
+
function emptyToBoundary(content, idx, side) {
|
|
139
|
+
const lines = content.split("\n");
|
|
140
|
+
if (side === "prev" && idx > 0)
|
|
141
|
+
return lines[idx - 1];
|
|
142
|
+
if (side === "next" && idx < lines.length - 1)
|
|
143
|
+
return lines[idx + 1];
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
export function applyHashlineEdits(fileContent, changes, filePathForErrors = "") {
|
|
147
|
+
if (changes.length === 0) {
|
|
148
|
+
return { ok: true, newContent: fileContent, changedRange: [0, -1], boundaryWarnings: [] };
|
|
149
|
+
}
|
|
150
|
+
let hashes;
|
|
151
|
+
try {
|
|
152
|
+
hashes = hashLines(fileContent);
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
156
|
+
if (msg.startsWith("[E_NOT_INITIALIZED]")) {
|
|
157
|
+
return { ok: false, error: msg, code: "E_NOT_INITIALIZED" };
|
|
158
|
+
}
|
|
159
|
+
throw e;
|
|
160
|
+
}
|
|
161
|
+
const resolved = [];
|
|
162
|
+
for (const change of changes) {
|
|
163
|
+
const [startRefRaw, endRefRaw] = change.hash_range_inclusive;
|
|
164
|
+
const startRef = parseAnchor(startRefRaw);
|
|
165
|
+
const endRef = parseAnchor(endRefRaw);
|
|
166
|
+
const s = resolveAnchor(startRef, hashes);
|
|
167
|
+
if (!s.ok) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
error: formatAnchorFailureMessage("start", startRefRaw, s, filePathForErrors),
|
|
171
|
+
code: "E_STALE_ANCHOR",
|
|
172
|
+
ref: startRefRaw,
|
|
173
|
+
suggestions: s.suggestions,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const e = resolveAnchor(endRef, hashes);
|
|
177
|
+
if (!e.ok) {
|
|
178
|
+
return {
|
|
179
|
+
ok: false,
|
|
180
|
+
error: formatAnchorFailureMessage("end", endRefRaw, e, filePathForErrors),
|
|
181
|
+
code: "E_STALE_ANCHOR",
|
|
182
|
+
ref: endRefRaw,
|
|
183
|
+
suggestions: e.suggestions,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (e.line < s.line) {
|
|
187
|
+
return {
|
|
188
|
+
ok: false,
|
|
189
|
+
error: `[E_BAD_RANGE] end anchor "${endRefRaw}" (line ${e.line + 1}) is before start anchor "${startRefRaw}" (line ${s.line + 1}).`,
|
|
190
|
+
code: "E_BAD_RANGE",
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
resolved.push({ startLine: s.line, endLine: e.line, change });
|
|
194
|
+
}
|
|
195
|
+
resolved.sort((a, b) => b.startLine - a.startLine);
|
|
196
|
+
for (let i = 1; i < resolved.length; i++) {
|
|
197
|
+
const prev = resolved[i - 1];
|
|
198
|
+
const curr = resolved[i];
|
|
199
|
+
if (curr.endLine >= prev.startLine) {
|
|
200
|
+
return {
|
|
201
|
+
ok: false,
|
|
202
|
+
error: `[E_OVERLAP] edit ranges overlap. After sorting, range ${i} (lines ${curr.startLine + 1}-${curr.endLine + 1}) overlaps range ${i - 1} (lines ${prev.startLine + 1}-${prev.endLine + 1}). Each 'changes' entry must affect a disjoint line range.`,
|
|
203
|
+
code: "E_OVERLAP",
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const workingLines = fileContent.split("\n");
|
|
208
|
+
const boundaryWarnings = [];
|
|
209
|
+
let minChangedLine = workingLines.length;
|
|
210
|
+
let maxChangedLine = -1;
|
|
211
|
+
for (const r of resolved) {
|
|
212
|
+
const { startLine, endLine, change } = r;
|
|
213
|
+
const newLines = change.content_lines;
|
|
214
|
+
if (newLines.length > 0) {
|
|
215
|
+
const prev = emptyToBoundary(workingLines.join("\n"), startLine, "prev");
|
|
216
|
+
if (prev !== null && prev === newLines[0]) {
|
|
217
|
+
boundaryWarnings.push(`[W_BOUNDARY_DUP] first replacement line duplicates the line just before the range (line ${startLine}). Consider removing the duplicate.`);
|
|
218
|
+
}
|
|
219
|
+
const next = emptyToBoundary(workingLines.join("\n"), endLine, "next");
|
|
220
|
+
if (next !== null && next === newLines[newLines.length - 1]) {
|
|
221
|
+
boundaryWarnings.push(`[W_BOUNDARY_DUP] last replacement line duplicates the line just after the range (line ${endLine + 2}). Consider removing the duplicate.`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
workingLines.splice(startLine, endLine - startLine + 1, ...newLines);
|
|
225
|
+
minChangedLine = Math.min(minChangedLine, startLine);
|
|
226
|
+
maxChangedLine = Math.max(maxChangedLine, startLine + newLines.length - 1);
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
ok: true,
|
|
230
|
+
newContent: workingLines.join("\n"),
|
|
231
|
+
changedRange: [minChangedLine, maxChangedLine],
|
|
232
|
+
boundaryWarnings,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const READ_LINE_PAD = 6;
|
|
236
|
+
function formatReadLine(lineNo1, hash, line) {
|
|
237
|
+
const n = String(lineNo1);
|
|
238
|
+
const pad = n.length >= READ_LINE_PAD ? "" : " ".repeat(READ_LINE_PAD - n.length);
|
|
239
|
+
return `${pad}${n}${SEP}${hash}${SEP}${line}`;
|
|
240
|
+
}
|
|
241
|
+
export function formatHashlineReadLines(fileContent, startLine = 1, endLine = Infinity) {
|
|
242
|
+
const lines = fileContent.split("\n");
|
|
243
|
+
const hashes = hashLines(fileContent);
|
|
244
|
+
const startIdx = Math.max(0, startLine - 1);
|
|
245
|
+
const endIdx = Math.min(lines.length, Number.isFinite(endLine) ? endLine : lines.length);
|
|
246
|
+
const out = [];
|
|
247
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
248
|
+
out.push(formatReadLine(i + 1, hashes[i], lines[i]));
|
|
249
|
+
}
|
|
250
|
+
return { text: out.join("\n"), lineCount: out.length, startLine, endLine: endIdx };
|
|
251
|
+
}
|
|
252
|
+
/** @deprecated Use formatHashlineReadLines */
|
|
253
|
+
export function formatHashlineReadView(fileContent) {
|
|
254
|
+
return formatHashlineReadLines(fileContent).text;
|
|
255
|
+
}
|
|
256
|
+
export function clearHashlineCache() {
|
|
257
|
+
hashCache.clear();
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=hashline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline.js","sourceRoot":"","sources":["../src/hashline.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyhuynhgiabuu/pi-diff",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "Shiki-powered terminal diff renderer for pi
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "Shiki-powered terminal diff renderer for pi — syntax-highlighted, word-level diffs in split and unified views.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"diff",
|
|
7
7
|
"pi",
|
|
@@ -54,6 +54,22 @@
|
|
|
54
54
|
"dist/core/resolve-lines.d.ts.map",
|
|
55
55
|
"dist/core/resolve-lines.js",
|
|
56
56
|
"dist/core/resolve-lines.js.map",
|
|
57
|
+
"dist/hashline.d.ts",
|
|
58
|
+
"dist/hashline.d.ts.map",
|
|
59
|
+
"dist/hashline.js",
|
|
60
|
+
"dist/hashline.js.map",
|
|
61
|
+
"dist/core/hashline-edit.d.ts",
|
|
62
|
+
"dist/core/hashline-edit.d.ts.map",
|
|
63
|
+
"dist/core/hashline-edit.js",
|
|
64
|
+
"dist/core/hashline-edit.js.map",
|
|
65
|
+
"dist/core/hashline-execute.d.ts",
|
|
66
|
+
"dist/core/hashline-execute.d.ts.map",
|
|
67
|
+
"dist/core/hashline-execute.js",
|
|
68
|
+
"dist/core/hashline-execute.js.map",
|
|
69
|
+
"dist/core/text-encoding.d.ts",
|
|
70
|
+
"dist/core/text-encoding.d.ts.map",
|
|
71
|
+
"dist/core/text-encoding.js",
|
|
72
|
+
"dist/core/text-encoding.js.map",
|
|
57
73
|
"dist/review/git.d.ts",
|
|
58
74
|
"dist/review/git.d.ts.map",
|
|
59
75
|
"dist/review/git.js",
|