diffstalker 0.1.5 → 0.1.7
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/.github/workflows/release.yml +5 -3
- package/bun.lock +618 -0
- package/dist/App.js +541 -1
- package/dist/components/BaseBranchPicker.js +60 -1
- package/dist/components/BottomPane.js +101 -1
- package/dist/components/CommitPanel.js +58 -1
- package/dist/components/CompareListView.js +110 -1
- package/dist/components/ExplorerContentView.js +80 -0
- package/dist/components/ExplorerView.js +37 -0
- package/dist/components/FileList.js +131 -1
- package/dist/components/Footer.js +6 -1
- package/dist/components/Header.js +107 -1
- package/dist/components/HistoryView.js +21 -1
- package/dist/components/HotkeysModal.js +108 -1
- package/dist/components/Modal.js +19 -1
- package/dist/components/ScrollableList.js +125 -1
- package/dist/components/ThemePicker.js +42 -1
- package/dist/components/TopPane.js +14 -1
- package/dist/components/UnifiedDiffView.js +115 -0
- package/dist/config.js +83 -2
- package/dist/core/GitOperationQueue.js +109 -1
- package/dist/core/GitStateManager.js +466 -1
- package/dist/git/diff.js +471 -10
- package/dist/git/status.js +269 -5
- package/dist/hooks/useCommitFlow.js +66 -1
- package/dist/hooks/useCompareState.js +123 -1
- package/dist/hooks/useExplorerState.js +248 -0
- package/dist/hooks/useGit.js +156 -1
- package/dist/hooks/useHistoryState.js +62 -1
- package/dist/hooks/useKeymap.js +167 -1
- package/dist/hooks/useLayout.js +154 -1
- package/dist/hooks/useMouse.js +87 -1
- package/dist/hooks/useTerminalSize.js +20 -1
- package/dist/hooks/useWatcher.js +137 -11
- package/dist/index.js +43 -3
- package/dist/services/commitService.js +22 -1
- package/dist/themes.js +127 -1
- package/dist/utils/ansiTruncate.js +108 -0
- package/dist/utils/baseBranchCache.js +44 -2
- package/dist/utils/commitFormat.js +38 -1
- package/dist/utils/diffFilters.js +21 -1
- package/dist/utils/diffRowCalculations.js +113 -0
- package/dist/utils/displayRows.js +172 -0
- package/dist/utils/explorerDisplayRows.js +169 -0
- package/dist/utils/fileCategories.js +26 -1
- package/dist/utils/formatDate.js +39 -1
- package/dist/utils/formatPath.js +58 -1
- package/dist/utils/languageDetection.js +180 -0
- package/dist/utils/layoutCalculations.js +98 -1
- package/dist/utils/lineBreaking.js +88 -0
- package/dist/utils/mouseCoordinates.js +165 -1
- package/dist/utils/rowCalculations.js +209 -3
- package/package.json +7 -10
- package/dist/components/CompareView.js +0 -1
- package/dist/components/DiffView.js +0 -1
- package/dist/components/HistoryDiffView.js +0 -1
|
@@ -1,3 +1,209 @@
|
|
|
1
|
-
import{isDisplayableDiffLine
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { isDisplayableDiffLine } from './diffFilters.js';
|
|
2
|
+
import { formatDateAbsolute } from './formatDate.js';
|
|
3
|
+
import { getDiffTotalRows, getDiffLineRowCount } from './diffRowCalculations.js';
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// History View Row Calculations
|
|
6
|
+
// ============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Map a visual row index to the commit index in HistoryView.
|
|
9
|
+
* Since each commit takes 1 row, this is simply visualRow + scrollOffset.
|
|
10
|
+
*/
|
|
11
|
+
export function getCommitIndexFromRow(visualRow, commits, _terminalWidth, scrollOffset = 0) {
|
|
12
|
+
const index = visualRow + scrollOffset;
|
|
13
|
+
if (index < 0 || index >= commits.length) {
|
|
14
|
+
return -1;
|
|
15
|
+
}
|
|
16
|
+
return index;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the total number of visual rows for all commits in HistoryView.
|
|
20
|
+
* Since each commit takes 1 row, this equals commits.length.
|
|
21
|
+
*/
|
|
22
|
+
export function getHistoryTotalRows(commits, _terminalWidth) {
|
|
23
|
+
return commits.length;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get the visual row offset for a given commit index in HistoryView.
|
|
27
|
+
* Since each commit takes 1 row, this equals commitIndex.
|
|
28
|
+
*/
|
|
29
|
+
export function getHistoryRowOffset(_commits, commitIndex, _terminalWidth) {
|
|
30
|
+
return commitIndex;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build all displayable rows for the history diff view.
|
|
34
|
+
* This includes commit metadata, message, and diff lines.
|
|
35
|
+
* Single source of truth for both rendering and row counting.
|
|
36
|
+
*/
|
|
37
|
+
export function buildHistoryDiffRows(commit, diff) {
|
|
38
|
+
const rows = [];
|
|
39
|
+
if (commit) {
|
|
40
|
+
// Commit header: hash, author, date
|
|
41
|
+
rows.push({
|
|
42
|
+
type: 'commit-header',
|
|
43
|
+
content: `commit ${commit.hash}`,
|
|
44
|
+
});
|
|
45
|
+
rows.push({
|
|
46
|
+
type: 'commit-header',
|
|
47
|
+
content: `Author: ${commit.author}`,
|
|
48
|
+
});
|
|
49
|
+
rows.push({
|
|
50
|
+
type: 'commit-header',
|
|
51
|
+
content: `Date: ${formatDateAbsolute(commit.date)}`,
|
|
52
|
+
});
|
|
53
|
+
// Blank line before message
|
|
54
|
+
rows.push({ type: 'spacer' });
|
|
55
|
+
// Commit message (can be multi-line)
|
|
56
|
+
const messageLines = commit.message.split('\n');
|
|
57
|
+
for (const line of messageLines) {
|
|
58
|
+
rows.push({
|
|
59
|
+
type: 'commit-message',
|
|
60
|
+
content: ` ${line}`,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// Blank line after message, before diff
|
|
64
|
+
rows.push({ type: 'spacer' });
|
|
65
|
+
}
|
|
66
|
+
// Diff lines (filter same as DiffView)
|
|
67
|
+
if (diff) {
|
|
68
|
+
for (const line of diff.lines) {
|
|
69
|
+
if (isDisplayableDiffLine(line)) {
|
|
70
|
+
rows.push({ type: 'diff-line', diffLine: line });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return rows;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the visual row count for a single HistoryDiffRow.
|
|
78
|
+
* Headers, spacers, and commit messages are always 1 row.
|
|
79
|
+
* Diff lines may wrap based on terminal width.
|
|
80
|
+
*/
|
|
81
|
+
export function getHistoryDiffRowHeight(row, lineNumWidth, terminalWidth) {
|
|
82
|
+
if (row.type !== 'diff-line' || !row.diffLine) {
|
|
83
|
+
return 1; // Headers, spacers, commit messages don't wrap
|
|
84
|
+
}
|
|
85
|
+
return getDiffLineRowCount(row.diffLine, lineNumWidth, terminalWidth);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get total displayable rows for history diff scroll calculation.
|
|
89
|
+
* Uses getDiffTotalRows for the diff portion to account for line wrapping.
|
|
90
|
+
*/
|
|
91
|
+
export function getHistoryDiffTotalRows(commit, diff, terminalWidth) {
|
|
92
|
+
// Count header rows (these don't wrap - they're short metadata)
|
|
93
|
+
let headerRows = 0;
|
|
94
|
+
if (commit) {
|
|
95
|
+
headerRows += 3; // hash, author, date
|
|
96
|
+
headerRows += 1; // spacer before message
|
|
97
|
+
headerRows += commit.message.split('\n').length; // message lines
|
|
98
|
+
headerRows += 1; // spacer after message
|
|
99
|
+
}
|
|
100
|
+
// Use getDiffTotalRows for diff portion (handles line wrapping)
|
|
101
|
+
const diffRows = getDiffTotalRows(diff, terminalWidth);
|
|
102
|
+
return headerRows + diffRows;
|
|
103
|
+
}
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// Compare View Row Calculations
|
|
106
|
+
// ============================================================================
|
|
107
|
+
/**
|
|
108
|
+
* Build a combined DiffResult from all compare files.
|
|
109
|
+
* This is the single source of truth for compare diff content.
|
|
110
|
+
*/
|
|
111
|
+
export function buildCombinedCompareDiff(compareDiff) {
|
|
112
|
+
if (!compareDiff || compareDiff.files.length === 0) {
|
|
113
|
+
return { raw: '', lines: [] };
|
|
114
|
+
}
|
|
115
|
+
const allLines = [];
|
|
116
|
+
const rawParts = [];
|
|
117
|
+
for (const file of compareDiff.files) {
|
|
118
|
+
// Include all lines from each file's diff (including headers)
|
|
119
|
+
for (const line of file.diff.lines) {
|
|
120
|
+
allLines.push(line);
|
|
121
|
+
}
|
|
122
|
+
rawParts.push(file.diff.raw);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
raw: rawParts.join('\n'),
|
|
126
|
+
lines: allLines,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Calculate the total number of displayable lines in the compare diff.
|
|
131
|
+
* This accounts for header filtering done by DiffView.
|
|
132
|
+
*/
|
|
133
|
+
export function getCompareDiffTotalRows(compareDiff) {
|
|
134
|
+
const combined = buildCombinedCompareDiff(compareDiff);
|
|
135
|
+
return combined.lines.filter(isDisplayableDiffLine).length;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Calculate the row offset to scroll to a specific file in the compare diff.
|
|
139
|
+
* Returns the row index where the file's diff --git header starts.
|
|
140
|
+
*/
|
|
141
|
+
export function getFileScrollOffset(compareDiff, fileIndex) {
|
|
142
|
+
if (!compareDiff || fileIndex < 0 || fileIndex >= compareDiff.files.length)
|
|
143
|
+
return 0;
|
|
144
|
+
const combined = buildCombinedCompareDiff(compareDiff);
|
|
145
|
+
let displayableRow = 0;
|
|
146
|
+
let currentFileIndex = 0;
|
|
147
|
+
for (const line of combined.lines) {
|
|
148
|
+
// Check if this is a file boundary
|
|
149
|
+
if (line.type === 'header' && line.content.startsWith('diff --git')) {
|
|
150
|
+
if (currentFileIndex === fileIndex) {
|
|
151
|
+
return displayableRow;
|
|
152
|
+
}
|
|
153
|
+
currentFileIndex++;
|
|
154
|
+
}
|
|
155
|
+
// Skip lines that DiffView filters out
|
|
156
|
+
if (!isDisplayableDiffLine(line)) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
displayableRow++;
|
|
160
|
+
}
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
// ============================================================================
|
|
164
|
+
// Compare List View Row Calculations
|
|
165
|
+
// ============================================================================
|
|
166
|
+
/**
|
|
167
|
+
* Map a visual row index to the item index in CompareListView.
|
|
168
|
+
* Returns the commit index for commits, or commitCount + fileIndex for files.
|
|
169
|
+
* Returns -1 if the row is a header, spacer, or out of bounds.
|
|
170
|
+
*
|
|
171
|
+
* Row structure (when both commits and files exist, both expanded):
|
|
172
|
+
* Row 0: "▼ Commits" header
|
|
173
|
+
* Row 1..N: commits
|
|
174
|
+
* Row N+1: spacer
|
|
175
|
+
* Row N+2: "▼ Files" header
|
|
176
|
+
* Rows N+3..: files
|
|
177
|
+
*/
|
|
178
|
+
export function getCompareItemIndexFromRow(row, commitCount, fileCount, commitsExpanded = true, filesExpanded = true) {
|
|
179
|
+
let currentRow = 0;
|
|
180
|
+
// Commits section
|
|
181
|
+
if (commitCount > 0) {
|
|
182
|
+
if (row === currentRow)
|
|
183
|
+
return -1; // "▼ Commits" header
|
|
184
|
+
currentRow++;
|
|
185
|
+
if (commitsExpanded) {
|
|
186
|
+
if (row < currentRow + commitCount) {
|
|
187
|
+
return row - currentRow; // Commit index
|
|
188
|
+
}
|
|
189
|
+
currentRow += commitCount;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Files section
|
|
193
|
+
if (fileCount > 0) {
|
|
194
|
+
if (commitCount > 0) {
|
|
195
|
+
if (row === currentRow)
|
|
196
|
+
return -1; // Spacer
|
|
197
|
+
currentRow++;
|
|
198
|
+
}
|
|
199
|
+
if (row === currentRow)
|
|
200
|
+
return -1; // "▼ Files" header
|
|
201
|
+
currentRow++;
|
|
202
|
+
if (filesExpanded) {
|
|
203
|
+
if (row < currentRow + fileCount) {
|
|
204
|
+
return commitCount + (row - currentRow); // File index (offset by commit count)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return -1; // Out of bounds
|
|
209
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "diffstalker",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Terminal application that displays git diff/status for directories",
|
|
5
5
|
"author": "yogh-io",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
"diffstalker": "bin/diffstalker"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"dev": "
|
|
21
|
+
"dev": "bun --watch src/index.tsx",
|
|
22
22
|
"build": "tsc",
|
|
23
|
-
"build:prod": "tsc &&
|
|
24
|
-
"bundle": "
|
|
25
|
-
"start": "
|
|
26
|
-
"start:bundle": "
|
|
23
|
+
"build:prod": "tsc && bun build dist/index.js --outfile dist/index.js --minify --target node --packages external",
|
|
24
|
+
"bundle": "bun run build:prod && bun build dist/index.js --outdir dist/bundle --minify --target node --external react-devtools-core",
|
|
25
|
+
"start": "bun dist/index.js",
|
|
26
|
+
"start:bundle": "bun dist/bundle/index.js",
|
|
27
27
|
"test": "vitest run",
|
|
28
28
|
"test:watch": "vitest",
|
|
29
29
|
"lint": "eslint src/",
|
|
30
30
|
"lint:fix": "eslint src/ --fix",
|
|
31
31
|
"format": "prettier --write src/",
|
|
32
32
|
"format:check": "prettier --check src/",
|
|
33
|
-
"prepublishOnly": "
|
|
33
|
+
"prepublishOnly": "bun run build:prod"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"git",
|
|
@@ -56,13 +56,10 @@
|
|
|
56
56
|
"@eslint/js": "^9.39.2",
|
|
57
57
|
"@types/node": "^22.10.7",
|
|
58
58
|
"@types/react": "^19.2.0",
|
|
59
|
-
"@vercel/ncc": "^0.38.4",
|
|
60
|
-
"esbuild": "^0.27.2",
|
|
61
59
|
"eslint": "^9.39.2",
|
|
62
60
|
"eslint-config-prettier": "^10.1.8",
|
|
63
61
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
64
62
|
"prettier": "^3.8.0",
|
|
65
|
-
"tsx": "^4.19.2",
|
|
66
63
|
"typescript": "^5.7.3",
|
|
67
64
|
"typescript-eslint": "^8.53.1",
|
|
68
65
|
"vitest": "^2.1.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as r,jsxs as a}from"react/jsx-runtime";import{useMemo as h}from"react";import{Box as e,Text as o}from"ink";import{DiffView as c}from"./DiffView.js";import{buildCombinedCompareDiff as u}from"../utils/rowCalculations.js";export{buildCombinedCompareDiff,getCompareDiffTotalRows,getFileScrollOffset}from"../utils/rowCalculations.js";export function CompareView({compareDiff:i,isLoading:d,error:n,scrollOffset:t,maxHeight:f,theme:m="dark",width:l}){const s=h(()=>u(i),[i]);return d?r(e,{paddingX:1,children:r(o,{dimColor:!0,children:"Loading diff..."})}):n?r(e,{paddingX:1,children:r(o,{color:"red",children:n})}):i?i.files.length===0?r(e,{paddingX:1,children:a(o,{dimColor:!0,children:["No changes compared to ",i.baseBranch]})}):r(c,{diff:s,maxHeight:f,scrollOffset:t,theme:m,width:l}):r(e,{paddingX:1,children:r(o,{dimColor:!0,children:"No base branch found (no origin/main or origin/master)"})})}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as a,jsxs as f}from"react/jsx-runtime";import{useMemo as I}from"react";import{Box as p,Text as u}from"ink";import{createEmphasize as R,common as z}from"emphasize";import L from"fast-diff";import{getTheme as G}from"../themes.js";import{ScrollableList as U}from"./ScrollableList.js";import{isDisplayableDiffLine as W}from"../utils/diffFilters.js";const X=R(z);function b(t,e){return e<=0||t.length<=e?t:e<=1?"\u2026":t.slice(0,e-1)+"\u2026"}const q={ts:"typescript",tsx:"typescript",js:"javascript",jsx:"javascript",mjs:"javascript",cjs:"javascript",py:"python",rb:"ruby",rs:"rust",go:"go",java:"java",c:"c",cpp:"cpp",h:"c",hpp:"cpp",cs:"csharp",php:"php",sh:"bash",bash:"bash",zsh:"bash",json:"json",yaml:"yaml",yml:"yaml",md:"markdown",html:"html",htm:"html",css:"css",scss:"scss",sass:"scss",less:"less",sql:"sql",xml:"xml",toml:"ini",ini:"ini",dockerfile:"dockerfile",makefile:"makefile",lua:"lua",vim:"vim",swift:"swift",kt:"kotlin",kts:"kotlin",scala:"scala",r:"r",pl:"perl",ex:"elixir",exs:"elixir",erl:"erlang",hs:"haskell",clj:"clojure",ml:"ocaml",fs:"fsharp",vue:"xml",svelte:"xml"};function O(t){if(!t)return;const e=t.split("/").pop()?.toLowerCase()??"";if(e==="dockerfile")return"dockerfile";if(e==="makefile"||e==="gnumakefile")return"makefile";const n=e.split(".").pop()?.toLowerCase();return n?q[n]||n:void 0}function P(t,e){if(!e||!t.trim())return t;try{return X.highlight(e,t).value}catch{return t}}function Q(t){let e=0;for(const n of t)n.oldLineNum&&n.oldLineNum>e&&(e=n.oldLineNum),n.newLineNum&&n.newLineNum>e&&(e=n.newLineNum);return Math.max(3,String(e).length)}function N(t){return t.type==="addition"||t.type==="deletion"||t.type==="context"&&t.content.startsWith(" ")?t.content.slice(1):t.content}const F=3;function $(t){if(t.length===0)return t;const e=[];for(let n=0;n<t.length;n++){const r=t[n];if(!r.isChange&&r.text.length<F){const o=n>0&&e[e.length-1]?.isChange,s=n<t.length-1&&t[n+1]?.isChange;if(o||s){o&&e.length>0?e[e.length-1].text+=r.text:e.push({text:r.text,isChange:!0});continue}}e.length>0&&e[e.length-1].isChange===r.isChange?e[e.length-1].text+=r.text:e.push({...r})}return e}function K(t,e){const n=L(t,e);let r=[],o=[];for(const[s,i]of n)s===L.EQUAL?(r.push({text:i,isChange:!1}),o.push({text:i,isChange:!1})):s===L.DELETE?r.push({text:i,isChange:!0}):s===L.INSERT&&o.push({text:i,isChange:!0});return r=$(r),o=$(o),{oldSegments:r,newSegments:o}}function V(t,e){if(t.length===0&&e.length===0)return 1;if(t.length===0||e.length===0)return 0;const n=L(t,e);let r=0,o=0;for(const[s,i]of n)s===L.EQUAL&&(r+=i.length),o+=i.length;return o>0?r/o:0}const Y=.35;function J(t){const e=new Map;for(let n=0;n<t.length-1;n++){const r=t[n],o=t[n+1];if(r.type==="deletion"&&o.type==="addition"){const s=N(r),i=N(o);if(V(s,i)>=Y){const d={deletion:r,addition:o,deletionIndex:n,additionIndex:n+1};e.set(n,d),e.set(n+1,d)}}}return e}function Z(t,e){const n=[];let r=e;for(const o of t){if(r<=0)break;if(o.text.length<=r)n.push(o),r-=o.text.length;else{const s=o.text.slice(0,r-1)+"\u2026";n.push({...o,text:s});break}}return n}function M({segments:t,isAddition:e,theme:n,maxWidth:r}){const{colors:o}=n,s=e?o.addBg:o.delBg,i=e?o.addHighlight:o.delHighlight,d=r?Z(t,r):t;return a(u,{backgroundColor:s,children:d.map((x,g)=>a(u,{color:o.text,backgroundColor:x.isChange?i:s,children:x.text||(g===d.length-1?" ":"")},g))})}function tt({line:t,lineNumWidth:e,language:n,wordDiffSegments:r,theme:o,maxWidth:s}){const{colors:i}=o,d=s?s-2:void 0;if(t.type==="header"){const c=t.content;if(c.startsWith("diff --git")){const m=c.match(/diff --git a\/.+ b\/(.+)$/);if(m){const C=d?d-6:void 0,y=C?b(m[1],C):m[1];return a(p,{children:f(u,{color:"cyan",bold:!0,children:["\u2500\u2500 ",y," \u2500\u2500"]})})}}const k=d?b(c,d):c;return a(p,{children:a(u,{dimColor:!0,children:k})})}if(t.type==="hunk"){const c=t.content.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);if(c){const m=parseInt(c[1],10),C=c[2]?parseInt(c[2],10):1,y=parseInt(c[3],10),v=c[4]?parseInt(c[4],10):1,E=c[5].trim(),T=m+C-1,H=y+v-1,A=C===1?`${m}`:`${m}-${T}`,_=v===1?`${y}`:`${y}-${H}`,B=`Lines ${A} \u2192 ${_}`,S=d?d-B.length-1:void 0,D=E&&S&&S>3?b(E,S):"";return f(p,{children:[a(u,{color:"cyan",dimColor:!0,children:B}),D&&f(u,{color:"gray",children:[" ",D]})]})}const k=d?b(t.content,d):t.content;return a(u,{color:"cyan",dimColor:!0,children:k})}const x=t.type==="addition"?t.newLineNum:t.type==="deletion"?t.oldLineNum:t.oldLineNum??t.newLineNum,g=x!==void 0?String(x).padStart(e," "):" ".repeat(e),w=N(t),l=s?s-e-5:void 0,h=l?b(w,l):w;if(t.type==="addition")return f(p,{children:[f(u,{backgroundColor:i.addBg,color:i.addLineNum,children:[g," "]}),f(u,{backgroundColor:i.addBg,color:i.addSymbol,bold:!0,children:["+"," "]}),r?a(M,{segments:r,isAddition:!0,theme:o,maxWidth:l}):a(u,{backgroundColor:i.addBg,color:i.text,children:h||" "})]});if(t.type==="deletion")return f(p,{children:[f(u,{backgroundColor:i.delBg,color:i.delLineNum,children:[g," "]}),f(u,{backgroundColor:i.delBg,color:i.delSymbol,bold:!0,children:["-"," "]}),r?a(M,{segments:r,isAddition:!1,theme:o,maxWidth:l}):a(u,{backgroundColor:i.delBg,color:i.text,children:h||" "})]});const j=P(h,n);return f(p,{children:[f(u,{color:i.contextLineNum,children:[g," "]}),a(u,{children:j})]})}export function DiffView({diff:t,filePath:e,maxHeight:n=20,scrollOffset:r=0,theme:o="dark",width:s}){const i=I(()=>G(o),[o]),d=I(()=>O(e),[e]),x=I(()=>{if(!t)return new Map;const l=J(t.lines),h=new Map;for(const[j,c]of l)if(j===c.deletionIndex){const k=N(c.deletion),m=N(c.addition),{oldSegments:C,newSegments:y}=K(k,m);h.set(c.deletionIndex,C),h.set(c.additionIndex,y)}return h},[t]),g=I(()=>t?.lines.map((l,h)=>({line:l,originalIndex:h})).filter(({line:l})=>W(l))??[],[t]);if(!t||g.length===0)return a(p,{paddingX:1,children:a(u,{dimColor:!0,children:"No diff to display"})});const w=Q(g.map(l=>l.line));return a(p,{flexDirection:"column",paddingX:1,overflowX:"hidden",children:a(U,{items:g,maxHeight:n,scrollOffset:r,getKey:l=>`${l.originalIndex}`,renderItem:l=>{const h=x.get(l.originalIndex);return a(tt,{line:l.line,lineNumWidth:w,language:d,wordDiffSegments:h,theme:i,maxWidth:s})}})})}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as i,jsxs as w}from"react/jsx-runtime";import{useMemo as x}from"react";import{Box as r,Text as n}from"ink";import{DiffView as g}from"./DiffView.js";import{buildHistoryDiffRows as R}from"../utils/rowCalculations.js";import{isDisplayableDiffLine as b}from"../utils/diffFilters.js";export{buildHistoryDiffRows,getHistoryDiffTotalRows}from"../utils/rowCalculations.js";export function HistoryDiffView({commit:s,diff:t,scrollOffset:l,maxHeight:d,theme:m="dark",width:a}){const c=x(()=>R(s,t),[s,t]),u=x(()=>{for(let e=0;e<c.length;e++)if(c[e].type==="diff-line")return e;return c.length},[c]),f=c.slice(l,l+d);if(!s)return i(r,{paddingX:1,children:i(n,{dimColor:!0,children:"Select a commit to view its diff"})});if(!t||t.lines.length===0)return w(r,{flexDirection:"column",children:[f.map((e,h)=>{const o=`row-${l+h}`;return e.type==="commit-header"?i(r,{children:i(n,{color:"yellow",children:e.content})},o):e.type==="commit-message"?i(r,{children:i(n,{children:e.content})},o):e.type==="spacer"?i(r,{children:i(n,{children:" "})},o):null}),i(r,{children:i(n,{dimColor:!0,children:"No changes in this commit"})})]});const p=t.lines.filter(b);if(l>=u)return i(g,{diff:{raw:t.raw,lines:p},maxHeight:d,scrollOffset:l-u,theme:m,width:a});const D=f.filter(e=>e.type!=="diff-line"),y=d-D.length;return w(r,{flexDirection:"column",overflowX:"hidden",children:[f.map((e,h)=>{const o=`row-${l+h}`;return e.type==="commit-header"?i(r,{children:i(n,{color:"yellow",children:e.content})},o):e.type==="commit-message"?i(r,{children:i(n,{children:e.content})},o):e.type==="spacer"?i(r,{children:i(n,{children:" "})},o):null}),y>0&&i(g,{diff:{raw:t.raw,lines:p},maxHeight:y,scrollOffset:0,theme:m,width:a})]})}
|