difit 4.0.7 → 5.0.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.ja.md +1 -2
- package/README.ko.md +1 -2
- package/README.md +6 -2
- package/README.zh.md +1 -2
- package/dist/cli/index.js +0 -35
- package/dist/cli/index.test.js +0 -264
- package/dist/cli/utils.d.ts +0 -2
- package/dist/cli/utils.js +1 -18
- package/dist/cli/utils.test.js +0 -16
- package/dist/client/assets/{arc-DX2p9X2Y.js → arc-DbOd2jxV.js} +1 -1
- package/dist/client/assets/architecture-YZFGNWBL-0n2ZLuLj.js +1 -0
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-FixTWViB.js → architectureDiagram-Q4EWVU46-BFXI_tUS.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-CUAMgGr9.js → blockDiagram-DXYQGD6D-BOEZDsFe.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-BM_HNNZe.js → c4Diagram-AHTNJAMY-BdIoPSTS.js} +1 -1
- package/dist/client/assets/channel-DPag0OPA.js +1 -0
- package/dist/client/assets/{chunk-2KRD3SAO-DeT59g2K.js → chunk-2KRD3SAO-BaHSMZbk.js} +1 -1
- package/dist/client/assets/{chunk-336JU56O-CaGvJA86.js → chunk-336JU56O-BGfMTguc.js} +2 -2
- package/dist/client/assets/chunk-426QAEUC-Ct2OJ1s3.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-D9mNDl5f.js → chunk-4BX2VUAB-CNkIhTNe.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-Df3b4HEG.js → chunk-4TB4RGXK-wFMAN-Ug.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-dCWLe_n4.js → chunk-55IACEB6-J_10GkPG.js} +1 -1
- package/dist/client/assets/{chunk-5FUZZQ4R-EScvXcSN.js → chunk-5FUZZQ4R-0NY9W0kL.js} +1 -1
- package/dist/client/assets/{chunk-5PVQY5BW-ail-oj89.js → chunk-5PVQY5BW-nUEO-vub.js} +1 -1
- package/dist/client/assets/{chunk-67CJDMHE-CHeCIL1u.js → chunk-67CJDMHE-CpK_DCjw.js} +1 -1
- package/dist/client/assets/{chunk-7N4EOEYR-P0tNRVMZ.js → chunk-7N4EOEYR-CJfX2SRB.js} +1 -1
- package/dist/client/assets/{chunk-AA7GKIK3-DloBHWSo.js → chunk-AA7GKIK3-DGHjDQX4.js} +1 -1
- package/dist/client/assets/{chunk-BSJP7CBP-CGLThsR8.js → chunk-BSJP7CBP-DiXS795w.js} +1 -1
- package/dist/client/assets/{chunk-CIAEETIT-rCt2IEMp.js → chunk-CIAEETIT-DaOGL_z8.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-DIJEIKIq.js → chunk-EDXVE4YY-EPdmphYw.js} +1 -1
- package/dist/client/assets/{chunk-ENJZ2VHE-CdrdxFfV.js → chunk-ENJZ2VHE-9x7-Qpzy.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-BH_GgR9u.js → chunk-FMBD7UC4-Dgx4um1Q.js} +1 -1
- package/dist/client/assets/{chunk-FOC6F5B3-D71VljSN.js → chunk-FOC6F5B3-BaVe0aqm.js} +1 -1
- package/dist/client/assets/{chunk-ICPOFSXX-2vcQKuhB.js → chunk-ICPOFSXX-C9l3r2YR.js} +1 -1
- package/dist/client/assets/{chunk-K5T4RW27-BWIFd7pZ.js → chunk-K5T4RW27-Bv0dnd8C.js} +1 -1
- package/dist/client/assets/{chunk-KGLVRYIC-Ck8I8tdt.js → chunk-KGLVRYIC-BdTDi9hU.js} +1 -1
- package/dist/client/assets/{chunk-LIHQZDEY-Cc7TtI-w.js → chunk-LIHQZDEY-BEYvjNoB.js} +1 -1
- package/dist/client/assets/{chunk-ORNJ4GCN-BMSqiphc.js → chunk-ORNJ4GCN-CHeeoEx_.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-B5faFb53.js → chunk-OYMX7WX6-Bapbqtyc.js} +1 -1
- package/dist/client/assets/chunk-QZHKN3VN-CNqVW4m2.js +1 -0
- package/dist/client/assets/{chunk-U2HBQHQK-BILTfRyq.js → chunk-U2HBQHQK-CpVfEbNc.js} +1 -1
- package/dist/client/assets/{chunk-X2U36JSP-D4-56gWx.js → chunk-X2U36JSP-BAcfna0L.js} +1 -1
- package/dist/client/assets/{chunk-XPW4576I-SxB401Zg.js → chunk-XPW4576I-D0wrDPCQ.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-CWXUVxFj.js → chunk-YZCP3GAM-D_AeoI3D.js} +1 -1
- package/dist/client/assets/{chunk-ZZ45TVLE-CXjZua4f.js → chunk-ZZ45TVLE-CwpZ5yb7.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-aX3PLX0y.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-CshAcrwe.js +1 -0
- package/dist/client/assets/clone-J5cJUwR3.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-YToNpueF.js → cose-bilkent-S5V4N54A-DJvkrscF.js} +1 -1
- package/dist/client/assets/{dagre-tvaMpP4D.js → dagre-BADyoi72.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-QFYoTa0z.js → dagre-KV5264BT-BDTirpEd.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-DM0NNmEN.js → diagram-5BDNPKRD-CJSn8eie.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-TiLkMmwt.js → diagram-G4DWMVQ6-COzN0wAe.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-DM1ykqrB.js → diagram-MMDJMWI5-Bau__Yfk.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-BEOLX1wr.js → diagram-TYMM5635-DKIgp_-m.js} +1 -1
- package/dist/client/assets/{dist-CCBhd9az.js → dist-CL_sSZWx.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-DZcjZq6z.js → erDiagram-SMLLAGMA-Iw0m0edr.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-B1AVT9es.js → flowDiagram-DWJPFMVM-CtXQs1rX.js} +1 -1
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-BCEXws9V.js → ganttDiagram-T4ZO3ILL-B0341I_2.js} +1 -1
- package/dist/client/assets/gitGraph-7Q5UKJZL-NWgYXB7y.js +1 -0
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-CVznBDOl.js → gitGraphDiagram-UUTBAWPF-Yv3oicIa.js} +1 -1
- package/dist/client/assets/{graphlib-C4fWcyt1.js → graphlib-BLiSTux3.js} +1 -1
- package/dist/client/assets/{index-6LShOAAb.js → index-C2jd9xpN.js} +6 -6
- package/dist/client/assets/{index-C16wNcPQ.css → index-v-PY_jQI.css} +1 -1
- package/dist/client/assets/info-OMHHGYJF-Bvc7BWzq.js +1 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-D8Oxr-KJ.js → infoDiagram-42DDH7IO-Cfjrwz2v.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-BE9KniVE.js → ishikawaDiagram-UXIWVN3A-Cc-jozqB.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-B3lGcz06.js → journeyDiagram-VCZTEJTY-Bjx1sC-s.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-Bs1QdB0j.js → kanban-definition-6JOO6SKY-CIkJYslO.js} +1 -1
- package/dist/client/assets/{line-CO4-KhEq.js → line-yxqmb99x.js} +1 -1
- package/dist/client/assets/{linear-CnaJKs0I.js → linear-DCAQGlgU.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-CravK6bS.js → mermaid-parser.core-B5ufZrv2.js} +2 -2
- package/dist/client/assets/{mermaid.core-DTh9KJvF.js → mermaid.core-BFOnV1aK.js} +3 -3
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-D2xU2hfX.js → mindmap-definition-QFDTVHPH-CPflWkUN.js} +1 -1
- package/dist/client/assets/packet-4T2RLAQJ-DNpLsp8v.js +1 -0
- package/dist/client/assets/pie-ZZUOXDRM-D8uToFEL.js +1 -0
- package/dist/client/assets/{pieDiagram-DEJITSTG-CRX6y4IQ.js → pieDiagram-DEJITSTG-Dl3gScVb.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-K2HFp8O8.js → quadrantDiagram-34T5L4WZ-38YyGeXU.js} +1 -1
- package/dist/client/assets/radar-PYXPWWZC-VrpLp1jL.js +1 -0
- package/dist/client/assets/{requirementDiagram-MS252O5E-C-8AW0uI.js → requirementDiagram-MS252O5E-CZW6zJs_.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-Bv-_ZFS5.js → sankeyDiagram-XADWPNL6-D4r0GNlW.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-Bk4QYIPk.js → sequenceDiagram-FGHM5R23-2xItvAxs.js} +1 -1
- package/dist/client/assets/{src-XMuEuFcU.js → src-YK4ClFOB.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-CI1G7zGC.js → stateDiagram-FHFEXIEX-lBViG7kM.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BcU-AM4S.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-CnXv8xHg.js → timeline-definition-GMOUNBTQ-DmlaOXs4.js} +1 -1
- package/dist/client/assets/treeView-SZITEDCU-B1qc9ijP.js +1 -0
- package/dist/client/assets/treemap-W4RFUUIX-Dl7yWWae.js +1 -0
- package/dist/client/assets/{vennDiagram-DHZGUBPP-M5x471Ar.js → vennDiagram-DHZGUBPP-BOLv0A8q.js} +1 -1
- package/dist/client/assets/wardley-RL74JXVD-CEXd-1Ht.js +1 -0
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-BG99uPNN.js → wardleyDiagram-NUSXRM2D-B5lHUuTU.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-DO7Upr9G.js → xychartDiagram-5P7HB3ND-D8nLdJo8.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/types/diff.d.ts +0 -10
- package/dist/utils/commentFormatting.test.js +0 -52
- package/package.json +4 -5
- package/dist/cli/tuiDeprecation.d.ts +0 -3
- package/dist/cli/tuiDeprecation.js +0 -16
- package/dist/cli/tuiDeprecation.test.d.ts +0 -1
- package/dist/cli/tuiDeprecation.test.js +0 -16
- package/dist/client/assets/architecture-YZFGNWBL-2zVtKbnG.js +0 -1
- package/dist/client/assets/channel-B_ddQhpW.js +0 -1
- package/dist/client/assets/chunk-426QAEUC-CMTCMPn4.js +0 -1
- package/dist/client/assets/chunk-QZHKN3VN-B-G9G-FB.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-DnUQ2iGN.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-Dwp5vuOB.js +0 -1
- package/dist/client/assets/clone-aWrl-obY.js +0 -1
- package/dist/client/assets/gitGraph-7Q5UKJZL-BE3Mcr-v.js +0 -1
- package/dist/client/assets/info-OMHHGYJF-CBpXVhw-.js +0 -1
- package/dist/client/assets/packet-4T2RLAQJ-abaJ3V5T.js +0 -1
- package/dist/client/assets/pie-ZZUOXDRM-B12dpA7V.js +0 -1
- package/dist/client/assets/radar-PYXPWWZC-BbBaJJN8.js +0 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DQ0U-oto.js +0 -1
- package/dist/client/assets/treeView-SZITEDCU-CM0rCBUc.js +0 -1
- package/dist/client/assets/treemap-W4RFUUIX-CXoNE_rL.js +0 -1
- package/dist/client/assets/wardley-RL74JXVD-B_EtnvOk.js +0 -1
- package/dist/server/git-diff-tui.d.ts +0 -2
- package/dist/server/git-diff-tui.js +0 -100
- package/dist/server/git-diff-tui.test.d.ts +0 -1
- package/dist/server/git-diff-tui.test.js +0 -76
- package/dist/tui/App.d.ts +0 -10
- package/dist/tui/App.js +0 -92
- package/dist/tui/components/DiffViewer.d.ts +0 -8
- package/dist/tui/components/DiffViewer.js +0 -88
- package/dist/tui/components/FileList.d.ts +0 -8
- package/dist/tui/components/FileList.js +0 -48
- package/dist/tui/components/SideBySideDiffViewer.d.ts +0 -9
- package/dist/tui/components/SideBySideDiffViewer.js +0 -240
- package/dist/tui/components/StatusBar.d.ts +0 -8
- package/dist/tui/components/StatusBar.js +0 -19
- package/dist/tui/utils/parseDiff.d.ts +0 -2
- package/dist/tui/utils/parseDiff.js +0 -67
- package/dist/utils/createId.test.d.ts +0 -1
- package/dist/utils/createId.test.js +0 -48
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Box, Text } from 'ink';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
const FileList = ({ files, selectedIndex }) => {
|
|
4
|
-
const getStatusColor = (status) => {
|
|
5
|
-
switch (status) {
|
|
6
|
-
case 'A':
|
|
7
|
-
return 'green';
|
|
8
|
-
case 'M':
|
|
9
|
-
return 'yellow';
|
|
10
|
-
case 'D':
|
|
11
|
-
return 'red';
|
|
12
|
-
default:
|
|
13
|
-
return 'white';
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
const getStatusLabel = (status) => {
|
|
17
|
-
switch (status) {
|
|
18
|
-
case 'A':
|
|
19
|
-
return '[+]';
|
|
20
|
-
case 'M':
|
|
21
|
-
return '[M]';
|
|
22
|
-
case 'D':
|
|
23
|
-
return '[-]';
|
|
24
|
-
default:
|
|
25
|
-
return '[?]';
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
29
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
30
|
-
React.createElement(Text, { bold: true },
|
|
31
|
-
"Changed Files (",
|
|
32
|
-
files.length,
|
|
33
|
-
")")),
|
|
34
|
-
files.map((file, index) => (React.createElement(Box, { key: `${file.path}-${index}` },
|
|
35
|
-
React.createElement(Text, { color: index === selectedIndex ? 'cyan' : undefined, backgroundColor: index === selectedIndex ? 'gray' : undefined },
|
|
36
|
-
index === selectedIndex ? '▶ ' : ' ',
|
|
37
|
-
React.createElement(Text, { color: getStatusColor(file.status) }, getStatusLabel(file.status)),
|
|
38
|
-
' ',
|
|
39
|
-
file.path,
|
|
40
|
-
' ',
|
|
41
|
-
React.createElement(Text, { dimColor: true },
|
|
42
|
-
"(+",
|
|
43
|
-
file.additions,
|
|
44
|
-
" -",
|
|
45
|
-
file.deletions,
|
|
46
|
-
")")))))));
|
|
47
|
-
};
|
|
48
|
-
export default FileList;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { type FileDiff } from '../../types/diff.js';
|
|
3
|
-
interface SideBySideDiffViewerProps {
|
|
4
|
-
files: FileDiff[];
|
|
5
|
-
initialFileIndex: number;
|
|
6
|
-
onBack: () => void;
|
|
7
|
-
}
|
|
8
|
-
declare const SideBySideDiffViewer: React.FC<SideBySideDiffViewerProps>;
|
|
9
|
-
export default SideBySideDiffViewer;
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { Box, Text, useInput, useApp } from 'ink';
|
|
2
|
-
import React, { useState } from 'react';
|
|
3
|
-
import { parseDiff } from '../utils/parseDiff.js';
|
|
4
|
-
const SideBySideDiffViewer = ({ files, initialFileIndex, onBack, }) => {
|
|
5
|
-
const [currentFileIndex, setCurrentFileIndex] = useState(initialFileIndex);
|
|
6
|
-
const [scrollOffset, setScrollOffset] = useState(0);
|
|
7
|
-
const { exit } = useApp();
|
|
8
|
-
const viewportHeight = Math.max(10, (process.stdout.rows || 24) - 10);
|
|
9
|
-
const currentFile = files[currentFileIndex];
|
|
10
|
-
useInput((input, key) => {
|
|
11
|
-
if (input === 'q' || (key.ctrl && input === 'c')) {
|
|
12
|
-
exit();
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
if (key.escape || input === 'b') {
|
|
16
|
-
onBack();
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
if (!currentFile)
|
|
20
|
-
return;
|
|
21
|
-
// Scroll within file
|
|
22
|
-
if (key.upArrow || input === 'k') {
|
|
23
|
-
setScrollOffset((prev) => Math.max(0, prev - 1));
|
|
24
|
-
}
|
|
25
|
-
if (key.downArrow || input === 'j') {
|
|
26
|
-
setScrollOffset((prev) => prev + 1);
|
|
27
|
-
}
|
|
28
|
-
if (key.pageUp) {
|
|
29
|
-
setScrollOffset((prev) => Math.max(0, prev - viewportHeight));
|
|
30
|
-
}
|
|
31
|
-
if (key.pageDown) {
|
|
32
|
-
setScrollOffset((prev) => prev + viewportHeight);
|
|
33
|
-
}
|
|
34
|
-
// Navigate between files
|
|
35
|
-
if (key.tab && !key.shift) {
|
|
36
|
-
// Next file (loop to first when at end)
|
|
37
|
-
setCurrentFileIndex((currentFileIndex + 1) % files.length);
|
|
38
|
-
setScrollOffset(0);
|
|
39
|
-
}
|
|
40
|
-
if (key.tab && key.shift) {
|
|
41
|
-
// Previous file (loop to last when at start)
|
|
42
|
-
setCurrentFileIndex((currentFileIndex - 1 + files.length) % files.length);
|
|
43
|
-
setScrollOffset(0);
|
|
44
|
-
}
|
|
45
|
-
}, { isActive: true });
|
|
46
|
-
if (!currentFile || files.length === 0) {
|
|
47
|
-
return (React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
48
|
-
React.createElement(Text, { color: "yellow" }, "No files to display"),
|
|
49
|
-
React.createElement(Box, { marginTop: 1 },
|
|
50
|
-
React.createElement(Text, { dimColor: true }, "Press ESC or 'b' to go back"))));
|
|
51
|
-
}
|
|
52
|
-
const parsedDiff = parseDiff(currentFile.diff);
|
|
53
|
-
// Calculate total lines for current file
|
|
54
|
-
const allLines = [];
|
|
55
|
-
parsedDiff.chunks.forEach((chunk) => {
|
|
56
|
-
// Add chunk header
|
|
57
|
-
allLines.push({
|
|
58
|
-
old: chunk.header,
|
|
59
|
-
new: chunk.header,
|
|
60
|
-
type: 'header',
|
|
61
|
-
});
|
|
62
|
-
let oldIdx = 0;
|
|
63
|
-
let newIdx = 0;
|
|
64
|
-
while (oldIdx < chunk.lines.length || newIdx < chunk.lines.length) {
|
|
65
|
-
const oldLine = chunk.lines[oldIdx];
|
|
66
|
-
const newLine = chunk.lines[newIdx];
|
|
67
|
-
if (oldLine?.type === 'remove' && newLine?.type === 'add') {
|
|
68
|
-
// Same line modified - show side by side
|
|
69
|
-
allLines.push({
|
|
70
|
-
old: oldLine.content,
|
|
71
|
-
new: newLine.content,
|
|
72
|
-
oldNum: oldLine.oldLineNumber,
|
|
73
|
-
newNum: newLine.newLineNumber,
|
|
74
|
-
type: 'modified',
|
|
75
|
-
});
|
|
76
|
-
oldIdx++;
|
|
77
|
-
newIdx++;
|
|
78
|
-
}
|
|
79
|
-
else if (oldLine?.type === 'remove') {
|
|
80
|
-
// Line removed
|
|
81
|
-
allLines.push({
|
|
82
|
-
old: oldLine.content,
|
|
83
|
-
oldNum: oldLine.oldLineNumber,
|
|
84
|
-
type: 'remove',
|
|
85
|
-
});
|
|
86
|
-
oldIdx++;
|
|
87
|
-
}
|
|
88
|
-
else if (newLine?.type === 'add') {
|
|
89
|
-
// Line added
|
|
90
|
-
allLines.push({
|
|
91
|
-
new: newLine.content,
|
|
92
|
-
newNum: newLine.newLineNumber,
|
|
93
|
-
type: 'add',
|
|
94
|
-
});
|
|
95
|
-
newIdx++;
|
|
96
|
-
}
|
|
97
|
-
else if (oldLine?.type === 'context') {
|
|
98
|
-
// Unchanged line
|
|
99
|
-
allLines.push({
|
|
100
|
-
old: oldLine.content,
|
|
101
|
-
new: oldLine.content,
|
|
102
|
-
oldNum: oldLine.oldLineNumber,
|
|
103
|
-
newNum: oldLine.newLineNumber,
|
|
104
|
-
type: 'context',
|
|
105
|
-
});
|
|
106
|
-
oldIdx++;
|
|
107
|
-
newIdx++;
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
oldIdx++;
|
|
111
|
-
newIdx++;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
const actualMaxScroll = Math.max(0, allLines.length - viewportHeight);
|
|
116
|
-
const clampedScrollOffset = Math.max(0, Math.min(actualMaxScroll, scrollOffset));
|
|
117
|
-
const visibleLines = allLines.slice(clampedScrollOffset, clampedScrollOffset + viewportHeight);
|
|
118
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
119
|
-
const columnWidth = Math.floor((terminalWidth - 6) / 2); // 6 for borders and separators
|
|
120
|
-
const getLineColor = (type) => {
|
|
121
|
-
switch (type) {
|
|
122
|
-
case 'add':
|
|
123
|
-
return 'green';
|
|
124
|
-
case 'remove':
|
|
125
|
-
return 'red';
|
|
126
|
-
case 'modified':
|
|
127
|
-
return undefined; // Will be handled separately for each side
|
|
128
|
-
case 'header':
|
|
129
|
-
return 'cyan';
|
|
130
|
-
default:
|
|
131
|
-
return undefined;
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
const truncateLine = (line, width) => {
|
|
135
|
-
if (line.length <= width)
|
|
136
|
-
return line.padEnd(width);
|
|
137
|
-
return line.substring(0, width - 1) + '…';
|
|
138
|
-
};
|
|
139
|
-
return (React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
140
|
-
React.createElement(Box, { marginBottom: 1, flexDirection: "column" },
|
|
141
|
-
React.createElement(Box, null,
|
|
142
|
-
React.createElement(Text, { bold: true },
|
|
143
|
-
currentFile.path,
|
|
144
|
-
" (",
|
|
145
|
-
currentFileIndex + 1,
|
|
146
|
-
"/",
|
|
147
|
-
files.length,
|
|
148
|
-
")"),
|
|
149
|
-
React.createElement(Text, { dimColor: true },
|
|
150
|
-
' ',
|
|
151
|
-
"- ",
|
|
152
|
-
currentFile.additions,
|
|
153
|
-
" additions, ",
|
|
154
|
-
currentFile.deletions,
|
|
155
|
-
" deletions")),
|
|
156
|
-
React.createElement(Box, { height: 2, overflow: "hidden", flexDirection: "column" }, (() => {
|
|
157
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
158
|
-
const maxWidth = terminalWidth - 4; // Leave some margin
|
|
159
|
-
// Generate file list with current file highlighted
|
|
160
|
-
const fileItems = [];
|
|
161
|
-
// Add files before current
|
|
162
|
-
for (let i = Math.max(0, currentFileIndex - 2); i < currentFileIndex; i++) {
|
|
163
|
-
fileItems.push({
|
|
164
|
-
text: files[i].path,
|
|
165
|
-
isActive: false,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
// Add current file
|
|
169
|
-
fileItems.push({
|
|
170
|
-
text: `[${files[currentFileIndex].path}]`,
|
|
171
|
-
isActive: true,
|
|
172
|
-
});
|
|
173
|
-
// Add files after current
|
|
174
|
-
for (let i = currentFileIndex + 1; i < Math.min(files.length, currentFileIndex + 3); i++) {
|
|
175
|
-
fileItems.push({
|
|
176
|
-
text: files[i].path,
|
|
177
|
-
isActive: false,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
// Build lines (max 2 lines)
|
|
181
|
-
const lines = [[]];
|
|
182
|
-
let currentLineWidth = 0;
|
|
183
|
-
for (const item of fileItems) {
|
|
184
|
-
const itemWidth = item.text.length + 3; // Include separator
|
|
185
|
-
if (currentLineWidth + itemWidth > maxWidth && lines.length < 2) {
|
|
186
|
-
lines.push([]);
|
|
187
|
-
currentLineWidth = 0;
|
|
188
|
-
}
|
|
189
|
-
if (lines.length <= 2) {
|
|
190
|
-
lines[lines.length - 1].push(item);
|
|
191
|
-
currentLineWidth += itemWidth;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return lines.map((line, lineIndex) => (React.createElement(Box, { key: lineIndex }, line.map((item, itemIndex) => (React.createElement(React.Fragment, { key: itemIndex },
|
|
195
|
-
itemIndex > 0 && React.createElement(Text, { dimColor: true }, " | "),
|
|
196
|
-
React.createElement(Text, { color: item.isActive ? 'cyan' : undefined, dimColor: !item.isActive }, item.text)))))));
|
|
197
|
-
})())),
|
|
198
|
-
React.createElement(Box, { borderStyle: "single", flexDirection: "column", flexGrow: 1 },
|
|
199
|
-
React.createElement(Box, { borderStyle: "single", borderTop: false, borderLeft: false, borderRight: false },
|
|
200
|
-
React.createElement(Box, { width: columnWidth },
|
|
201
|
-
React.createElement(Text, { dimColor: true }, " \u2502 "),
|
|
202
|
-
React.createElement(Text, { bold: true }, "Old")),
|
|
203
|
-
React.createElement(Text, { dimColor: true }, " \u2503 "),
|
|
204
|
-
React.createElement(Box, { width: columnWidth },
|
|
205
|
-
React.createElement(Text, { dimColor: true }, " \u2502 "),
|
|
206
|
-
React.createElement(Text, { bold: true }, "New"))),
|
|
207
|
-
React.createElement(Box, { flexDirection: "column", flexGrow: 1 }, visibleLines.map((line, index) => (React.createElement(Box, { key: `line-${scrollOffset + index}` },
|
|
208
|
-
React.createElement(Box, { width: columnWidth },
|
|
209
|
-
React.createElement(Text, { dimColor: true }, line.oldNum ? String(line.oldNum).padStart(4) : ' '),
|
|
210
|
-
React.createElement(Text, { dimColor: true }, " \u2502 "),
|
|
211
|
-
React.createElement(Text, { color: line.type === 'remove' || line.type === 'modified' ? 'red' : undefined, dimColor: line.type === 'header' }, line.type === 'remove' || line.type === 'modified' ? '- ' : ' '),
|
|
212
|
-
React.createElement(Text, { color: line.type === 'remove' || line.type === 'modified'
|
|
213
|
-
? 'red'
|
|
214
|
-
: getLineColor(line.type) }, line.old
|
|
215
|
-
? truncateLine(line.old, columnWidth - 10)
|
|
216
|
-
: ' '.repeat(columnWidth - 10))),
|
|
217
|
-
React.createElement(Text, { dimColor: true }, " \u2503 "),
|
|
218
|
-
React.createElement(Box, { width: columnWidth },
|
|
219
|
-
React.createElement(Text, { dimColor: true }, line.newNum ? String(line.newNum).padStart(4) : ' '),
|
|
220
|
-
React.createElement(Text, { dimColor: true }, " \u2502 "),
|
|
221
|
-
React.createElement(Text, { color: line.type === 'add' || line.type === 'modified' ? 'green' : undefined, dimColor: line.type === 'header' }, line.type === 'add' || line.type === 'modified' ? '+ ' : ' '),
|
|
222
|
-
React.createElement(Text, { color: line.type === 'add' || line.type === 'modified'
|
|
223
|
-
? 'green'
|
|
224
|
-
: getLineColor(line.type) }, line.new
|
|
225
|
-
? truncateLine(line.new, columnWidth - 10)
|
|
226
|
-
: ' '.repeat(columnWidth - 10)))))))),
|
|
227
|
-
React.createElement(Box, { marginTop: 1, justifyContent: "space-between" },
|
|
228
|
-
React.createElement(Text, { dimColor: true },
|
|
229
|
-
"Lines ",
|
|
230
|
-
scrollOffset + 1,
|
|
231
|
-
"-",
|
|
232
|
-
Math.min(scrollOffset + viewportHeight, allLines.length),
|
|
233
|
-
" of",
|
|
234
|
-
' ',
|
|
235
|
-
allLines.length,
|
|
236
|
-
scrollOffset + viewportHeight < allLines.length &&
|
|
237
|
-
` (${allLines.length - scrollOffset - viewportHeight} more)`),
|
|
238
|
-
React.createElement(Text, { dimColor: true }, "Tab: next file | Shift+Tab: prev file | \u2191\u2193/jk: scroll | ESC/b: back"))));
|
|
239
|
-
};
|
|
240
|
-
export default SideBySideDiffViewer;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Box, Text } from 'ink';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
const StatusBar = ({ commitish, totalFiles, currentMode }) => {
|
|
4
|
-
return (React.createElement(Box, { borderStyle: "round", paddingX: 1, marginBottom: 1 },
|
|
5
|
-
React.createElement(Box, { flexGrow: 1 },
|
|
6
|
-
React.createElement(Text, { bold: true, color: "cyan" }, "\uD83D\uDCCB difit TUI"),
|
|
7
|
-
React.createElement(Text, null, " | "),
|
|
8
|
-
React.createElement(Text, { color: "yellow" }, commitish),
|
|
9
|
-
React.createElement(Text, null, " | "),
|
|
10
|
-
React.createElement(Text, null,
|
|
11
|
-
totalFiles,
|
|
12
|
-
" files changed")),
|
|
13
|
-
React.createElement(Box, null,
|
|
14
|
-
React.createElement(Text, { dimColor: true },
|
|
15
|
-
"[",
|
|
16
|
-
currentMode === 'list' ? 'File List' : currentMode === 'split' ? 'Split' : 'Unified',
|
|
17
|
-
"]"))));
|
|
18
|
-
};
|
|
19
|
-
export default StatusBar;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
export function parseDiff(diffText) {
|
|
2
|
-
const lines = diffText.split('\n');
|
|
3
|
-
const chunks = [];
|
|
4
|
-
let currentChunk = null;
|
|
5
|
-
let oldLineNumber = 0;
|
|
6
|
-
let newLineNumber = 0;
|
|
7
|
-
for (const line of lines) {
|
|
8
|
-
// Skip file headers
|
|
9
|
-
if (line.startsWith('diff --git') ||
|
|
10
|
-
line.startsWith('index ') ||
|
|
11
|
-
line.startsWith('---') ||
|
|
12
|
-
line.startsWith('+++')) {
|
|
13
|
-
continue;
|
|
14
|
-
}
|
|
15
|
-
// Chunk header
|
|
16
|
-
if (line.startsWith('@@')) {
|
|
17
|
-
const match = line.match(/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);
|
|
18
|
-
if (match) {
|
|
19
|
-
const [, oldStart, oldLinesStr, newStart, newLinesStr] = match;
|
|
20
|
-
currentChunk = {
|
|
21
|
-
header: line,
|
|
22
|
-
oldStart: parseInt(oldStart),
|
|
23
|
-
oldLines: parseInt(oldLinesStr || '1'),
|
|
24
|
-
newStart: parseInt(newStart),
|
|
25
|
-
newLines: parseInt(newLinesStr || '1'),
|
|
26
|
-
lines: [],
|
|
27
|
-
};
|
|
28
|
-
chunks.push(currentChunk);
|
|
29
|
-
oldLineNumber = currentChunk.oldStart - 1;
|
|
30
|
-
newLineNumber = currentChunk.newStart - 1;
|
|
31
|
-
}
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
// Skip if no current chunk
|
|
35
|
-
if (!currentChunk)
|
|
36
|
-
continue;
|
|
37
|
-
// Parse diff lines
|
|
38
|
-
if (line.startsWith('+')) {
|
|
39
|
-
newLineNumber++;
|
|
40
|
-
currentChunk.lines.push({
|
|
41
|
-
type: 'add',
|
|
42
|
-
content: line.substring(1),
|
|
43
|
-
newLineNumber: newLineNumber,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
else if (line.startsWith('-')) {
|
|
47
|
-
oldLineNumber++;
|
|
48
|
-
currentChunk.lines.push({
|
|
49
|
-
type: 'remove',
|
|
50
|
-
content: line.substring(1),
|
|
51
|
-
oldLineNumber: oldLineNumber,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
// Context line
|
|
56
|
-
oldLineNumber++;
|
|
57
|
-
newLineNumber++;
|
|
58
|
-
currentChunk.lines.push({
|
|
59
|
-
type: 'context',
|
|
60
|
-
content: line.substring(1),
|
|
61
|
-
oldLineNumber: oldLineNumber,
|
|
62
|
-
newLineNumber: newLineNumber,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return { chunks };
|
|
67
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { createId } from './createId';
|
|
3
|
-
describe('createId', () => {
|
|
4
|
-
it('creates a 16-character lowercase alphanumeric id', () => {
|
|
5
|
-
const randomSpy = vi.spyOn(Math, 'random').mockReturnValue(0);
|
|
6
|
-
expect(createId()).toBe('aaaaaaaaaaaaaaaa');
|
|
7
|
-
randomSpy.mockRestore();
|
|
8
|
-
});
|
|
9
|
-
it('creates different ids across successive calls', () => {
|
|
10
|
-
const randomSpy = vi
|
|
11
|
-
.spyOn(Math, 'random')
|
|
12
|
-
.mockReturnValueOnce(0)
|
|
13
|
-
.mockReturnValueOnce(1 / 36)
|
|
14
|
-
.mockReturnValueOnce(2 / 36)
|
|
15
|
-
.mockReturnValueOnce(3 / 36)
|
|
16
|
-
.mockReturnValueOnce(4 / 36)
|
|
17
|
-
.mockReturnValueOnce(5 / 36)
|
|
18
|
-
.mockReturnValueOnce(6 / 36)
|
|
19
|
-
.mockReturnValueOnce(7 / 36)
|
|
20
|
-
.mockReturnValueOnce(8 / 36)
|
|
21
|
-
.mockReturnValueOnce(9 / 36)
|
|
22
|
-
.mockReturnValueOnce(10 / 36)
|
|
23
|
-
.mockReturnValueOnce(11 / 36)
|
|
24
|
-
.mockReturnValueOnce(12 / 36)
|
|
25
|
-
.mockReturnValueOnce(13 / 36)
|
|
26
|
-
.mockReturnValueOnce(14 / 36)
|
|
27
|
-
.mockReturnValueOnce(15 / 36)
|
|
28
|
-
.mockReturnValueOnce(16 / 36)
|
|
29
|
-
.mockReturnValueOnce(17 / 36)
|
|
30
|
-
.mockReturnValueOnce(18 / 36)
|
|
31
|
-
.mockReturnValueOnce(19 / 36)
|
|
32
|
-
.mockReturnValueOnce(20 / 36)
|
|
33
|
-
.mockReturnValueOnce(21 / 36)
|
|
34
|
-
.mockReturnValueOnce(22 / 36)
|
|
35
|
-
.mockReturnValueOnce(23 / 36)
|
|
36
|
-
.mockReturnValueOnce(24 / 36)
|
|
37
|
-
.mockReturnValueOnce(25 / 36)
|
|
38
|
-
.mockReturnValueOnce(26 / 36)
|
|
39
|
-
.mockReturnValueOnce(27 / 36)
|
|
40
|
-
.mockReturnValueOnce(28 / 36)
|
|
41
|
-
.mockReturnValueOnce(29 / 36)
|
|
42
|
-
.mockReturnValueOnce(30 / 36)
|
|
43
|
-
.mockReturnValueOnce(31 / 36);
|
|
44
|
-
expect(createId()).toBe('abcdefghijklmnop');
|
|
45
|
-
expect(createId()).toBe('qrstuvwxyz012345');
|
|
46
|
-
randomSpy.mockRestore();
|
|
47
|
-
});
|
|
48
|
-
});
|