pi-diff-review 0.1.12 → 0.1.14
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 +36 -4
- package/package.json +1 -1
- package/src/comment-manager.ts +73 -0
- package/src/diff-source.ts +36 -10
- package/src/explanation-controller.ts +167 -0
- package/src/index.ts +70 -0
- package/src/prompt.ts +1 -1
- package/src/render-utils.ts +11 -0
- package/src/review-component.ts +539 -708
- package/src/review-navigation.ts +94 -0
- package/src/split-diff.ts +61 -0
- package/src/types.ts +0 -3
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { DiffRenderMode, SelectionBounds } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
export type JumpBoundaryResult = {
|
|
4
|
+
changed: boolean;
|
|
5
|
+
clearedSelection: boolean;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export class ReviewNavigationState {
|
|
9
|
+
selected: number;
|
|
10
|
+
scrollTop = 0;
|
|
11
|
+
selectionAnchor?: number;
|
|
12
|
+
diffRenderMode: DiffRenderMode = "unified";
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly lineCount: number,
|
|
16
|
+
initialSelected = 0,
|
|
17
|
+
) {
|
|
18
|
+
this.selected = this.clampLineIndex(initialSelected);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
move(delta: number): boolean {
|
|
22
|
+
const next = this.clampLineIndex(this.selected + delta);
|
|
23
|
+
if (next === this.selected) return false;
|
|
24
|
+
this.selected = next;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
jumpToBoundary(boundary: "start" | "end"): JumpBoundaryResult {
|
|
29
|
+
const next = boundary === "start" ? 0 : Math.max(0, this.lineCount - 1);
|
|
30
|
+
const hadSelection = this.selectionAnchor != null;
|
|
31
|
+
const changed = next !== this.selected || hadSelection;
|
|
32
|
+
this.selected = next;
|
|
33
|
+
if (hadSelection) this.selectionAnchor = undefined;
|
|
34
|
+
return { changed, clearedSelection: hadSelection };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
extendSelection(delta: number): boolean {
|
|
38
|
+
if (this.selectionAnchor == null) {
|
|
39
|
+
this.selectionAnchor = this.selected;
|
|
40
|
+
}
|
|
41
|
+
const next = this.clampLineIndex(this.selected + delta);
|
|
42
|
+
if (next === this.selected) return false;
|
|
43
|
+
this.selected = next;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
clearSelection(): boolean {
|
|
48
|
+
if (this.selectionAnchor == null) return false;
|
|
49
|
+
this.selectionAnchor = undefined;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
hasSelection(): boolean {
|
|
54
|
+
return (
|
|
55
|
+
this.selectionAnchor != null && this.selectionAnchor !== this.selected
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getSelectionBounds(): SelectionBounds | undefined {
|
|
60
|
+
if (this.selectionAnchor == null) return undefined;
|
|
61
|
+
return {
|
|
62
|
+
start: Math.min(this.selectionAnchor, this.selected),
|
|
63
|
+
end: Math.max(this.selectionAnchor, this.selected),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
toggleDiffRenderMode(): DiffRenderMode {
|
|
68
|
+
this.diffRenderMode =
|
|
69
|
+
this.diffRenderMode === "unified" ? "split" : "unified";
|
|
70
|
+
this.scrollTop = 0;
|
|
71
|
+
return this.diffRenderMode;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
ensureScroll(
|
|
75
|
+
viewportHeight: number,
|
|
76
|
+
selectedDisplayRow: number,
|
|
77
|
+
displayRowCount: number,
|
|
78
|
+
): void {
|
|
79
|
+
if (selectedDisplayRow < this.scrollTop) {
|
|
80
|
+
this.scrollTop = selectedDisplayRow;
|
|
81
|
+
}
|
|
82
|
+
if (selectedDisplayRow >= this.scrollTop + viewportHeight) {
|
|
83
|
+
this.scrollTop = selectedDisplayRow - viewportHeight + 1;
|
|
84
|
+
}
|
|
85
|
+
this.scrollTop = Math.max(
|
|
86
|
+
0,
|
|
87
|
+
Math.min(this.scrollTop, Math.max(0, displayRowCount - viewportHeight)),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private clampLineIndex(index: number): number {
|
|
92
|
+
return Math.max(0, Math.min(Math.max(0, this.lineCount - 1), index));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ReviewLine, SplitDiffCell, SplitDiffRow } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
export type SplitDiffRowsResult = {
|
|
4
|
+
rows: SplitDiffRow[];
|
|
5
|
+
rowByLineIndex: number[];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function buildSplitDiffRows(lines: ReviewLine[]): SplitDiffRowsResult {
|
|
9
|
+
const rows: SplitDiffRow[] = [];
|
|
10
|
+
const rowByLineIndex: number[] = [];
|
|
11
|
+
let index = 0;
|
|
12
|
+
|
|
13
|
+
const pushRow = (row: SplitDiffRow) => {
|
|
14
|
+
const displayRow = rows.length;
|
|
15
|
+
rows.push(row);
|
|
16
|
+
if (row.kind === "full") {
|
|
17
|
+
rowByLineIndex[row.cell.index] = displayRow;
|
|
18
|
+
} else {
|
|
19
|
+
if (row.left) rowByLineIndex[row.left.index] = displayRow;
|
|
20
|
+
if (row.right) rowByLineIndex[row.right.index] = displayRow;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
while (index < lines.length) {
|
|
25
|
+
const line = lines[index]!;
|
|
26
|
+
|
|
27
|
+
if (line.kind === "remove" || line.kind === "add") {
|
|
28
|
+
const removals: SplitDiffCell[] = [];
|
|
29
|
+
const additions: SplitDiffCell[] = [];
|
|
30
|
+
|
|
31
|
+
while (lines[index]?.kind === "remove") {
|
|
32
|
+
removals.push({ line: lines[index]!, index });
|
|
33
|
+
index++;
|
|
34
|
+
}
|
|
35
|
+
while (lines[index]?.kind === "add") {
|
|
36
|
+
additions.push({ line: lines[index]!, index });
|
|
37
|
+
index++;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const count = Math.max(removals.length, additions.length);
|
|
41
|
+
for (let offset = 0; offset < count; offset++) {
|
|
42
|
+
pushRow({
|
|
43
|
+
kind: "split",
|
|
44
|
+
left: removals[offset],
|
|
45
|
+
right: additions[offset],
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (line.kind === "context") {
|
|
52
|
+
const cell = { line, index };
|
|
53
|
+
pushRow({ kind: "split", left: cell, right: cell });
|
|
54
|
+
} else {
|
|
55
|
+
pushRow({ kind: "full", cell: { line, index } });
|
|
56
|
+
}
|
|
57
|
+
index++;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { rows, rowByLineIndex };
|
|
61
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -42,7 +42,6 @@ export type DiffSource = {
|
|
|
42
42
|
args: string[];
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
export type ReviewLayout = "side-by-side" | "stacked";
|
|
46
45
|
export type DiffRenderMode = "unified" | "split";
|
|
47
46
|
|
|
48
47
|
export type SplitDiffCell = {
|
|
@@ -60,5 +59,3 @@ export type ReviewTui = {
|
|
|
60
59
|
};
|
|
61
60
|
|
|
62
61
|
export type ReviewTheme = Theme;
|
|
63
|
-
|
|
64
|
-
export type RightPaneMode = "comments" | "explanation";
|