@heyhuynhgiabuu/pi-diff 0.2.2 → 0.4.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/README.md +117 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +55 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/diff.d.ts +14 -0
- package/dist/core/diff.d.ts.map +1 -0
- package/dist/core/diff.js +72 -0
- package/dist/core/diff.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1738 -0
- package/dist/index.js.map +1 -0
- package/dist/review/command.d.ts +2 -0
- package/dist/review/command.d.ts.map +1 -0
- package/dist/review/command.js +365 -0
- package/dist/review/command.js.map +1 -0
- package/dist/review/export.d.ts +7 -0
- package/dist/review/export.d.ts.map +1 -0
- package/dist/review/export.js +77 -0
- package/dist/review/export.js.map +1 -0
- package/dist/review/file-preview.d.ts +9 -0
- package/dist/review/file-preview.d.ts.map +1 -0
- package/dist/review/file-preview.js +228 -0
- package/dist/review/file-preview.js.map +1 -0
- package/dist/review/git.d.ts +49 -0
- package/dist/review/git.d.ts.map +1 -0
- package/dist/review/git.js +200 -0
- package/dist/review/git.js.map +1 -0
- package/dist/review/hunk-preview.d.ts +25 -0
- package/dist/review/hunk-preview.d.ts.map +1 -0
- package/dist/review/hunk-preview.js +973 -0
- package/dist/review/hunk-preview.js.map +1 -0
- package/dist/review/interactive.d.ts +27 -0
- package/dist/review/interactive.d.ts.map +1 -0
- package/dist/review/interactive.js +146 -0
- package/dist/review/interactive.js.map +1 -0
- package/dist/review/model.d.ts +33 -0
- package/dist/review/model.d.ts.map +1 -0
- package/dist/review/model.js +208 -0
- package/dist/review/model.js.map +1 -0
- package/dist/review/prompt.d.ts +4 -0
- package/dist/review/prompt.d.ts.map +1 -0
- package/dist/review/prompt.js +43 -0
- package/dist/review/prompt.js.map +1 -0
- package/dist/review/session.d.ts +69 -0
- package/dist/review/session.d.ts.map +1 -0
- package/dist/review/session.js +190 -0
- package/dist/review/session.js.map +1 -0
- package/dist/review/tui.d.ts +57 -0
- package/dist/review/tui.d.ts.map +1 -0
- package/dist/review/tui.js +486 -0
- package/dist/review/tui.js.map +1 -0
- package/media/review-diff.png +0 -0
- package/package.json +73 -5
- package/prompts/review-diff-agent.md +19 -0
- package/biome.json +0 -29
- package/src/index.ts +0 -1635
- package/tsconfig.json +0 -19
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ A [pi](https://pi.dev) extension that replaces the default `write` and `edit` to
|
|
|
25
25
|
- **Adaptive layout** — auto-detects terminal width; wraps intelligently on wide terminals, truncates on narrow ones
|
|
26
26
|
- **LRU cache** — singleton Shiki highlighter with 192-entry cache for fast re-renders
|
|
27
27
|
- **Large diff fallback** — gracefully degrades (skips highlighting, still shows diff structure) for files > 80k chars
|
|
28
|
+
- **Review context export** — `pi-diff-review` exports Git changes as agent-ready markdown for Warp-style local code review
|
|
28
29
|
- **Fully customizable** — every color and threshold is overridable via environment variables
|
|
29
30
|
|
|
30
31
|
## Install
|
|
@@ -41,6 +42,122 @@ Or load directly for development:
|
|
|
41
42
|
pi -e ./src/index.ts
|
|
42
43
|
```
|
|
43
44
|
|
|
45
|
+
## Git Review in Pi TUI
|
|
46
|
+
|
|
47
|
+
pi-diff now has two review paths:
|
|
48
|
+
|
|
49
|
+
1. **`/review-diff`** — the primary interactive local-review command
|
|
50
|
+
2. **`review_git_diff`** — the read-only markdown/tooling path for agent context and scripted review
|
|
51
|
+
|
|
52
|
+
### `/review-diff` — interactive local review
|
|
53
|
+
|
|
54
|
+
Use `/review-diff` inside Pi TUI to open a full-width centered review overlay for your local Git diff.
|
|
55
|
+
|
|
56
|
+
<img width="900" alt="pi-diff review-diff interactive Git review overlay" src="media/review-diff.png" />
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
/review-diff
|
|
60
|
+
/review-diff --base main
|
|
61
|
+
/review-diff working-tree
|
|
62
|
+
/review-diff feature/base-branch
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
What the overlay supports now:
|
|
66
|
+
- keyboard-driven file navigation
|
|
67
|
+
- hunk navigation for the selected file
|
|
68
|
+
- a fixed-height focused **hunk diff viewport** instead of a panel that grows/shrinks with diff size
|
|
69
|
+
- hunk-level preview scrolling inside the selected hunk, with scroll status and a visible `▶` selection marker
|
|
70
|
+
- load the selected file/line into Pi's main editor as review context
|
|
71
|
+
- copy the selected file/line/hunk reference to the clipboard
|
|
72
|
+
- line-anchored draft/edit/delete review comments
|
|
73
|
+
- approve/dismiss comments before submission
|
|
74
|
+
- batch-submit approved comments back into Pi as a follow-up prompt
|
|
75
|
+
- live auto-refresh while the overlay is open when the local git diff changes
|
|
76
|
+
- manual refresh of the current diff without leaving the review flow
|
|
77
|
+
- session persistence via Pi custom entries so reopening `/review-diff` restores the latest review state for the current session
|
|
78
|
+
|
|
79
|
+
Key bindings in the overlay:
|
|
80
|
+
- `Tab` cycles focus between files, hunks, preview, and comments
|
|
81
|
+
- `↑↓` / `Ctrl+j` / `Ctrl+k` navigate the focused region; in Preview focus this scrolls the selected hunk while keeping rendered content visible
|
|
82
|
+
- `PageUp` / `PageDown` move by a full visible page in the focused region; in Preview focus this scrolls the selected hunk viewport
|
|
83
|
+
- `Home` / `End` jump to the start/end of the focused region; in Preview focus this jumps within the selected hunk viewport
|
|
84
|
+
- mouse wheel scrolls the selected hunk viewport vertically when Pi forwards terminal wheel events to the overlay
|
|
85
|
+
- `[` / `]` jump between files
|
|
86
|
+
- `o` loads the selected file/line into Pi's main editor as review context
|
|
87
|
+
- `y` copies the selected file/line/hunk reference to the clipboard; if clipboard access fails, it loads the reference into Pi's main editor
|
|
88
|
+
- `c` drafts a comment on the current hunk / anchored preview line
|
|
89
|
+
- `e` edits the selected comment; if none exists yet, the overlay warns instead of silently doing nothing
|
|
90
|
+
- `x` deletes the selected comment
|
|
91
|
+
- `a` approves the selected comment
|
|
92
|
+
- `d` dismisses the selected comment
|
|
93
|
+
- `A` approves all comments
|
|
94
|
+
- `r` manually refreshes the diff immediately (the overlay also auto-refreshes while open)
|
|
95
|
+
- `s` submits approved comments back to Pi
|
|
96
|
+
- `Esc` / `q` closes the overlay
|
|
97
|
+
|
|
98
|
+
**Important:** `/review-diff` is a command, not a prompt template. Pi resolves extension commands before prompt templates, so a prompt template with the same name would be shadowed and never run.
|
|
99
|
+
|
|
100
|
+
### `/review-diff-agent` — prompt template companion
|
|
101
|
+
|
|
102
|
+
If you want a blunt text review from the agent instead of the interactive overlay, use the bundled prompt template:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
/review-diff-agent
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This prompt asks the agent to use `review_git_diff` as needed and produce a brutal review of the current local diff.
|
|
109
|
+
|
|
110
|
+
### `review_git_diff` — read-only markdown review tool
|
|
111
|
+
|
|
112
|
+
`review_git_diff` remains available for agent/tool use and for non-destructive markdown exports.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
// Open the read-only review markdown for working-tree changes, including untracked files
|
|
116
|
+
review_git_diff({})
|
|
117
|
+
|
|
118
|
+
// Review branch changes as main...HEAD
|
|
119
|
+
review_git_diff({ base: "main" })
|
|
120
|
+
|
|
121
|
+
// Focus a file from the changed-file list
|
|
122
|
+
review_git_diff({ file: "src/index.ts" })
|
|
123
|
+
|
|
124
|
+
// Focus a hunk ID shown by the panel
|
|
125
|
+
review_git_diff({ file: "src/index.ts", hunkId: "src/index.ts:10:12" })
|
|
126
|
+
|
|
127
|
+
// Draft inline comments through the tool API
|
|
128
|
+
review_git_comment({ file: "src/index.ts", line: 42, body: "This needs a regression test." })
|
|
129
|
+
|
|
130
|
+
// List or clear drafted comments
|
|
131
|
+
review_git_comments({})
|
|
132
|
+
review_git_comments({ clear: true })
|
|
133
|
+
|
|
134
|
+
// Return the older full markdown export with raw unified diff included
|
|
135
|
+
review_git_diff({ base: "main", includeRawDiff: true })
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- No `base` means working-tree review, including untracked files.
|
|
139
|
+
- `base: "main"` means `main...HEAD` branch review.
|
|
140
|
+
- `includeRawDiff` returns the older full review export with raw unified diff.
|
|
141
|
+
- `maxLinesPerHunk`, `maxFiles`, and `maxHunks` cap large markdown reviews.
|
|
142
|
+
- The tool path is intentionally non-destructive: it never reverts, stages, commits, discards, or edits files.
|
|
143
|
+
|
|
144
|
+
## Review Export CLI
|
|
145
|
+
|
|
146
|
+
`pi-diff-review` exports the same Git review context as markdown for use outside Pi TUI.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Review uncommitted working-tree changes
|
|
150
|
+
pi-diff-review
|
|
151
|
+
|
|
152
|
+
# Review branch changes like a pull request
|
|
153
|
+
pi-diff-review --base main
|
|
154
|
+
|
|
155
|
+
# Include the raw git diff after the structured summary
|
|
156
|
+
pi-diff-review --raw
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The export includes changed files, hunk headers, changed-line numbers, and review instructions focused on correctness, regressions, security, tests, and maintainability.
|
|
160
|
+
|
|
44
161
|
## How It Works
|
|
45
162
|
|
|
46
163
|
pi-diff wraps the built-in `write` and `edit` tools from the pi SDK, including single-edit and multi-edit `edit` calls. When the agent writes or edits a file:
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const export_js_1 = require("./review/export.js");
|
|
5
|
+
const git_js_1 = require("./review/git.js");
|
|
6
|
+
function main(argv) {
|
|
7
|
+
const options = parseArgs(argv);
|
|
8
|
+
const diff = (0, git_js_1.readGitDiff)(process.cwd(), options.mode);
|
|
9
|
+
process.stdout.write((0, export_js_1.formatReviewMarkdown)(diff, {
|
|
10
|
+
includeRawDiff: options.includeRawDiff,
|
|
11
|
+
maxLinesPerHunk: options.maxLinesPerHunk,
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
function parseArgs(argv) {
|
|
15
|
+
const options = { mode: { type: "working-tree" }, includeRawDiff: false };
|
|
16
|
+
for (let index = 0; index < argv.length; index++) {
|
|
17
|
+
const arg = argv[index];
|
|
18
|
+
if (arg === "--help" || arg === "-h") {
|
|
19
|
+
printHelp();
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
if (arg === "--base") {
|
|
23
|
+
const base = argv[++index];
|
|
24
|
+
if (!base)
|
|
25
|
+
throw new Error("--base requires a branch name");
|
|
26
|
+
options.mode = { type: "branch", base };
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (arg === "--raw") {
|
|
30
|
+
options.includeRawDiff = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (arg === "--max-lines-per-hunk") {
|
|
34
|
+
const value = Number(argv[++index]);
|
|
35
|
+
if (!Number.isInteger(value) || value <= 0)
|
|
36
|
+
throw new Error("--max-lines-per-hunk requires a positive integer");
|
|
37
|
+
options.maxLinesPerHunk = value;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
41
|
+
}
|
|
42
|
+
return options;
|
|
43
|
+
}
|
|
44
|
+
function printHelp() {
|
|
45
|
+
process.stdout.write(`pi-diff-review\n\nExport current Git changes as agent-ready code review context.\n\nUsage:\n pi-diff-review [--base <branch>] [--raw] [--max-lines-per-hunk <n>]\n\nOptions:\n --base <branch> Compare <branch>...HEAD instead of working tree changes.\n --raw Include the raw git diff at the end.\n --max-lines-per-hunk <n> Limit emitted lines per hunk (default: 80).\n`);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
main(process.argv.slice(2));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
process.stderr.write(`pi-diff-review: ${message}\n`);
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAEA,kDAA0D;AAC1D,4CAAmE;AAQnE,SAAS,IAAI,CAAC,IAAc;IAC3B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,IAAA,oBAAW,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CACnB,IAAA,gCAAoB,EAAC,IAAI,EAAE;QAC1B,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,eAAe,EAAE,OAAO,CAAC,eAAe;KACxC,CAAC,CACF,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAChC,MAAM,OAAO,GAAe,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IACtF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACtC,SAAS,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAC5D,OAAO,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACxC,SAAS;QACV,CAAC;QACD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;YAC9B,SAAS;QACV,CAAC;QACD,IAAI,GAAG,KAAK,sBAAsB,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;YAChH,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC;YAChC,SAAS;QACV,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,SAAS,SAAS;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CACnB,+YAA+Y,CAC/Y,CAAC;AACH,CAAC;AAED,IAAI,CAAC;IACJ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,OAAO,IAAI,CAAC,CAAC;IACrD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface DiffLine {
|
|
2
|
+
type: "add" | "del" | "ctx" | "sep";
|
|
3
|
+
oldNum: number | null;
|
|
4
|
+
newNum: number | null;
|
|
5
|
+
content: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ParsedDiff {
|
|
8
|
+
lines: DiffLine[];
|
|
9
|
+
added: number;
|
|
10
|
+
removed: number;
|
|
11
|
+
chars: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function parseDiff(oldContent: string, newContent: string, ctx?: number): ParsedDiff;
|
|
14
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/core/diff.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IACpC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,SAAI,GAAG,UAAU,CA+BrF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseDiff = parseDiff;
|
|
37
|
+
const Diff = __importStar(require("diff"));
|
|
38
|
+
function parseDiff(oldContent, newContent, ctx = 3) {
|
|
39
|
+
const patch = Diff.structuredPatch("", "", oldContent, newContent, "", "", { context: ctx });
|
|
40
|
+
const lines = [];
|
|
41
|
+
let added = 0;
|
|
42
|
+
let removed = 0;
|
|
43
|
+
for (let hi = 0; hi < patch.hunks.length; hi++) {
|
|
44
|
+
if (hi > 0) {
|
|
45
|
+
const prev = patch.hunks[hi - 1];
|
|
46
|
+
const gap = patch.hunks[hi].oldStart - (prev.oldStart + prev.oldLines);
|
|
47
|
+
lines.push({ type: "sep", oldNum: null, newNum: gap > 0 ? gap : null, content: "" });
|
|
48
|
+
}
|
|
49
|
+
const h = patch.hunks[hi];
|
|
50
|
+
let oL = h.oldStart;
|
|
51
|
+
let nL = h.newStart;
|
|
52
|
+
for (const raw of h.lines) {
|
|
53
|
+
if (raw === "\")
|
|
54
|
+
continue;
|
|
55
|
+
const ch = raw[0];
|
|
56
|
+
const text = raw.slice(1);
|
|
57
|
+
if (ch === "+") {
|
|
58
|
+
lines.push({ type: "add", oldNum: null, newNum: nL++, content: text });
|
|
59
|
+
added++;
|
|
60
|
+
}
|
|
61
|
+
else if (ch === "-") {
|
|
62
|
+
lines.push({ type: "del", oldNum: oL++, newNum: null, content: text });
|
|
63
|
+
removed++;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
lines.push({ type: "ctx", oldNum: oL++, newNum: nL++, content: text });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { lines, added, removed, chars: oldContent.length + newContent.length };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/core/diff.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,8BA+BC;AA/CD,2CAA6B;AAgB7B,SAAgB,SAAS,CAAC,UAAkB,EAAE,UAAkB,EAAE,GAAG,GAAG,CAAC;IACxE,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7F,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;QAChD,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACjC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC1B,IAAI,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC;QACpB,IAAI,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC;QACpB,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,GAAG,KAAK,8BAA8B;gBAAE,SAAS;YACrD,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAClB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gBAChB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvE,KAAK,EAAE,CAAC;YACT,CAAC;iBAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvE,OAAO,EAAE,CAAC;YACX,CAAC;iBAAM,CAAC;gBACP,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;AAChF,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-diff — Shiki-powered terminal diff renderer for pi.
|
|
3
|
+
*
|
|
4
|
+
* @module pi-diff
|
|
5
|
+
* @see https://github.com/buddingnewinsights/pi-diff
|
|
6
|
+
*
|
|
7
|
+
* Architecture (like OpenTUI / delta):
|
|
8
|
+
* 1. Syntax-highlight full code blocks via Shiki → ANSI (fg-only codes)
|
|
9
|
+
* 2. Layer diff background colors underneath (composites at cell level)
|
|
10
|
+
* 3. For word-level changes, inject brighter bg at changed char positions
|
|
11
|
+
* 4. Result: syntax fg + diff bg + word emphasis — all three visible together
|
|
12
|
+
*
|
|
13
|
+
* Views:
|
|
14
|
+
* • Split (side-by-side) — edit tool, auto-falls back to unified on narrow terminals
|
|
15
|
+
* • Unified (stacked) — write tool overwrites
|
|
16
|
+
*
|
|
17
|
+
* Performance:
|
|
18
|
+
* • Singleton Shiki highlighter (managed by @shikijs/cli)
|
|
19
|
+
* • LRU memo cache per highlighted block
|
|
20
|
+
* • Large-diff fallback (skip highlighting, still show diff)
|
|
21
|
+
* • Async rendering with invalidate() for non-blocking preview
|
|
22
|
+
*/
|
|
23
|
+
import type { BundledLanguage } from "shiki";
|
|
24
|
+
import { type ParsedDiff, parseDiff } from "./core/diff.js";
|
|
25
|
+
/** Resolved ANSI colors for diff rendering — theme overrides hardcoded defaults. */
|
|
26
|
+
interface DiffColors {
|
|
27
|
+
fgAdd: string;
|
|
28
|
+
fgDel: string;
|
|
29
|
+
fgCtx: string;
|
|
30
|
+
}
|
|
31
|
+
declare function normalizeShikiContrast(ansi: string): string;
|
|
32
|
+
declare function renderUnified(diff: ParsedDiff, language: BundledLanguage | undefined, max?: number, dc?: DiffColors): Promise<string>;
|
|
33
|
+
declare function renderSplit(diff: ParsedDiff, language: BundledLanguage | undefined, max?: number, dc?: DiffColors): Promise<string>;
|
|
34
|
+
export declare const __testing: {
|
|
35
|
+
normalizeShikiContrast: typeof normalizeShikiContrast;
|
|
36
|
+
parseDiff: typeof parseDiff;
|
|
37
|
+
renderSplit: typeof renderSplit;
|
|
38
|
+
renderUnified: typeof renderUnified;
|
|
39
|
+
};
|
|
40
|
+
export default function diffRendererExtension(pi: any): Promise<void>;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,OAAO,CAAC;AAE3D,OAAO,EAAiB,KAAK,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAuc3E,oFAAoF;AACpF,UAAU,UAAU;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AAuKD,iBAAS,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpD;AAkVD,iBAAe,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,GAAG,SAAmB,EACtB,EAAE,GAAE,UAAgC,GAClC,OAAO,CAAC,MAAM,CAAC,CAwHjB;AAMD,iBAAe,WAAW,CACzB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,GAAG,SAAoB,EACvB,EAAE,GAAE,UAAgC,GAClC,OAAO,CAAC,MAAM,CAAC,CA6JjB;AAMD,eAAO,MAAM,SAAS;;;;;CAKrB,CAAC;AA8CF,wBAA8B,qBAAqB,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAykB1E"}
|