diffstalker 0.2.2 → 0.2.4
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/.dependency-cruiser.cjs +2 -2
- package/dist/App.js +299 -664
- package/dist/KeyBindings.js +125 -39
- package/dist/ModalController.js +166 -0
- package/dist/MouseHandlers.js +43 -25
- package/dist/NavigationController.js +290 -0
- package/dist/StagingOperations.js +199 -0
- package/dist/config.js +39 -0
- package/dist/core/CompareManager.js +134 -0
- package/dist/core/ExplorerStateManager.js +27 -40
- package/dist/core/GitStateManager.js +28 -630
- package/dist/core/HistoryManager.js +72 -0
- package/dist/core/RemoteOperationManager.js +109 -0
- package/dist/core/WorkingTreeManager.js +412 -0
- package/dist/git/status.js +95 -0
- package/dist/index.js +59 -54
- package/dist/state/FocusRing.js +40 -0
- package/dist/state/UIState.js +82 -48
- package/dist/types/remote.js +5 -0
- package/dist/ui/PaneRenderers.js +11 -4
- package/dist/ui/modals/BaseBranchPicker.js +4 -7
- package/dist/ui/modals/CommitActionConfirm.js +66 -0
- package/dist/ui/modals/DiscardConfirm.js +4 -7
- package/dist/ui/modals/FileFinder.js +33 -27
- package/dist/ui/modals/HotkeysModal.js +32 -13
- package/dist/ui/modals/Modal.js +1 -0
- package/dist/ui/modals/RepoPicker.js +109 -0
- package/dist/ui/modals/ThemePicker.js +4 -7
- package/dist/ui/widgets/CommitPanel.js +52 -14
- package/dist/ui/widgets/CompareListView.js +1 -11
- package/dist/ui/widgets/DiffView.js +2 -27
- package/dist/ui/widgets/ExplorerContent.js +1 -4
- package/dist/ui/widgets/ExplorerView.js +1 -11
- package/dist/ui/widgets/FileList.js +2 -8
- package/dist/ui/widgets/Footer.js +1 -0
- package/dist/ui/widgets/Header.js +37 -3
- package/dist/utils/ansi.js +38 -0
- package/dist/utils/ansiTruncate.js +1 -5
- package/dist/utils/displayRows.js +72 -59
- package/dist/utils/fileCategories.js +7 -0
- package/dist/utils/fileResolution.js +23 -0
- package/dist/utils/languageDetection.js +3 -2
- package/dist/utils/logger.js +32 -0
- package/metrics/v0.2.3.json +243 -0
- package/metrics/v0.2.4.json +236 -0
- package/package.json +5 -2
- package/dist/utils/layoutCalculations.js +0 -100
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getFileAtIndex } from './fileCategories.js';
|
|
2
|
+
import { getFlatFileAtIndex } from './flatFileList.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a FileEntry from an index, abstracting over flat vs categorized mode.
|
|
5
|
+
* In flat mode, returns the unstaged entry (preferred) or staged entry.
|
|
6
|
+
* In categorized mode, returns the file at the categorized index.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveFileAtIndex(index, flatViewMode, flatFiles, files) {
|
|
9
|
+
if (flatViewMode) {
|
|
10
|
+
const flatEntry = getFlatFileAtIndex(flatFiles, index);
|
|
11
|
+
return flatEntry?.unstagedEntry ?? flatEntry?.stagedEntry ?? null;
|
|
12
|
+
}
|
|
13
|
+
return getFileAtIndex(files, index);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the maximum valid file index for the current view mode.
|
|
17
|
+
*/
|
|
18
|
+
export function getFileListMaxIndex(flatViewMode, flatFiles, files) {
|
|
19
|
+
if (flatViewMode) {
|
|
20
|
+
return flatFiles.length - 1;
|
|
21
|
+
}
|
|
22
|
+
return files.length - 1;
|
|
23
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createEmphasize } from 'emphasize';
|
|
6
6
|
import { common } from 'lowlight';
|
|
7
|
+
import { ANSI_FG_RESET } from './ansi.js';
|
|
7
8
|
// Create emphasize instance with common languages
|
|
8
9
|
const emphasize = createEmphasize(common);
|
|
9
10
|
// Map file extensions to highlight.js language names
|
|
@@ -182,7 +183,7 @@ export function highlightLinePreserveBg(content, language) {
|
|
|
182
183
|
const result = emphasize.highlight(language, content);
|
|
183
184
|
// Replace full reset (\x1b[0m) with foreground-only reset (\x1b[39m)
|
|
184
185
|
// This preserves any background color set by the caller
|
|
185
|
-
return result.value.replace(/\x1b\[0m/g,
|
|
186
|
+
return result.value.replace(/\x1b\[0m/g, ANSI_FG_RESET);
|
|
186
187
|
}
|
|
187
188
|
catch {
|
|
188
189
|
return content;
|
|
@@ -217,7 +218,7 @@ export function highlightBlockPreserveBg(lines, language) {
|
|
|
217
218
|
const block = lines.join('\n');
|
|
218
219
|
const result = emphasize.highlight(language, block);
|
|
219
220
|
// Replace full resets with foreground-only resets
|
|
220
|
-
const highlighted = result.value.replace(/\x1b\[0m/g,
|
|
221
|
+
const highlighted = result.value.replace(/\x1b\[0m/g, ANSI_FG_RESET);
|
|
221
222
|
return highlighted.split('\n');
|
|
222
223
|
}
|
|
223
224
|
catch {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight structured logger writing to stderr.
|
|
3
|
+
*
|
|
4
|
+
* - `debug()` is gated by `setDebug(true)` (set from the --debug flag)
|
|
5
|
+
* - `warn()` and `error()` always write to stderr
|
|
6
|
+
*/
|
|
7
|
+
let debugEnabled = false;
|
|
8
|
+
export function setDebug(enabled) {
|
|
9
|
+
debugEnabled = enabled;
|
|
10
|
+
}
|
|
11
|
+
function timestamp() {
|
|
12
|
+
return new Date().toISOString();
|
|
13
|
+
}
|
|
14
|
+
export function debug(message) {
|
|
15
|
+
if (debugEnabled) {
|
|
16
|
+
process.stderr.write(`[diffstalker ${timestamp()}] ${message}\n`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function warn(message) {
|
|
20
|
+
process.stderr.write(`[diffstalker warn] ${message}\n`);
|
|
21
|
+
}
|
|
22
|
+
function formatError(err) {
|
|
23
|
+
if (err instanceof Error)
|
|
24
|
+
return err.message;
|
|
25
|
+
if (err)
|
|
26
|
+
return String(err);
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
export function error(message, err) {
|
|
30
|
+
const detail = err ? `: ${formatError(err)}` : '';
|
|
31
|
+
process.stderr.write(`[diffstalker error] ${message}${detail}\n`);
|
|
32
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2026-02-06T18:38:55.083Z",
|
|
3
|
+
"gitRef": "v0.2.3",
|
|
4
|
+
"gitSha": "11ba9fc",
|
|
5
|
+
"summary": {
|
|
6
|
+
"files": 82,
|
|
7
|
+
"lines": 16165,
|
|
8
|
+
"functions": 1146,
|
|
9
|
+
"avgCyclomaticComplexity": 5.1,
|
|
10
|
+
"maxCyclomaticComplexity": {
|
|
11
|
+
"value": 42,
|
|
12
|
+
"function": "buildDiffDisplayRows",
|
|
13
|
+
"file": "src/utils/displayRows.ts:112"
|
|
14
|
+
},
|
|
15
|
+
"avgCognitiveComplexity": 6.5,
|
|
16
|
+
"maxCognitiveComplexity": {
|
|
17
|
+
"value": 68,
|
|
18
|
+
"function": "buildDiffDisplayRows",
|
|
19
|
+
"file": "src/utils/displayRows.ts:112"
|
|
20
|
+
},
|
|
21
|
+
"smells": 0
|
|
22
|
+
},
|
|
23
|
+
"hotspots": [
|
|
24
|
+
{
|
|
25
|
+
"file": "src/utils/displayRows.ts",
|
|
26
|
+
"lines": 567,
|
|
27
|
+
"cyclomaticMax": 42,
|
|
28
|
+
"cognitiveMax": 68,
|
|
29
|
+
"smells": 0
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"file": "src/ui/widgets/CommitPanel.ts",
|
|
33
|
+
"lines": 217,
|
|
34
|
+
"cyclomaticMax": 34,
|
|
35
|
+
"cognitiveMax": 42,
|
|
36
|
+
"smells": 0
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"file": "src/App.ts",
|
|
40
|
+
"lines": 1548,
|
|
41
|
+
"cyclomaticMax": 31,
|
|
42
|
+
"cognitiveMax": 13,
|
|
43
|
+
"smells": 0
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"file": "src/utils/flatFileList.ts",
|
|
47
|
+
"lines": 100,
|
|
48
|
+
"cyclomaticMax": 29,
|
|
49
|
+
"cognitiveMax": 14,
|
|
50
|
+
"smells": 0
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"file": "src/git/diff.ts",
|
|
54
|
+
"lines": 656,
|
|
55
|
+
"cyclomaticMax": 26,
|
|
56
|
+
"cognitiveMax": 41,
|
|
57
|
+
"smells": 0
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"file": "src/git/status.ts",
|
|
61
|
+
"lines": 392,
|
|
62
|
+
"cyclomaticMax": 22,
|
|
63
|
+
"cognitiveMax": 25,
|
|
64
|
+
"smells": 0
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"file": "src/ui/PaneRenderers.ts",
|
|
68
|
+
"lines": 249,
|
|
69
|
+
"cyclomaticMax": 20,
|
|
70
|
+
"cognitiveMax": 8,
|
|
71
|
+
"smells": 0
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"file": "src/ui/widgets/ExplorerContent.ts",
|
|
75
|
+
"lines": 130,
|
|
76
|
+
"cyclomaticMax": 20,
|
|
77
|
+
"cognitiveMax": 24,
|
|
78
|
+
"smells": 0
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"file": "src/ui/widgets/Header.ts",
|
|
82
|
+
"lines": 134,
|
|
83
|
+
"cyclomaticMax": 18,
|
|
84
|
+
"cognitiveMax": 22,
|
|
85
|
+
"smells": 0
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"file": "src/MouseHandlers.ts",
|
|
89
|
+
"lines": 268,
|
|
90
|
+
"cyclomaticMax": 17,
|
|
91
|
+
"cognitiveMax": 15,
|
|
92
|
+
"smells": 0
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"file": "src/ipc/CommandServer.ts",
|
|
96
|
+
"lines": 266,
|
|
97
|
+
"cyclomaticMax": 17,
|
|
98
|
+
"cognitiveMax": 6,
|
|
99
|
+
"smells": 0
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"file": "src/index.ts",
|
|
103
|
+
"lines": 178,
|
|
104
|
+
"cyclomaticMax": 16,
|
|
105
|
+
"cognitiveMax": 17,
|
|
106
|
+
"smells": 0
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"file": "src/ui/widgets/ExplorerView.ts",
|
|
110
|
+
"lines": 245,
|
|
111
|
+
"cyclomaticMax": 16,
|
|
112
|
+
"cognitiveMax": 21,
|
|
113
|
+
"smells": 0
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"file": "src/utils/ansiTruncate.ts",
|
|
117
|
+
"lines": 123,
|
|
118
|
+
"cyclomaticMax": 16,
|
|
119
|
+
"cognitiveMax": 24,
|
|
120
|
+
"smells": 0
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"file": "src/ui/widgets/DiffView.ts",
|
|
124
|
+
"lines": 511,
|
|
125
|
+
"cyclomaticMax": 15,
|
|
126
|
+
"cognitiveMax": 12,
|
|
127
|
+
"smells": 0
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"file": "src/ui/widgets/CompareListView.ts",
|
|
131
|
+
"lines": 383,
|
|
132
|
+
"cyclomaticMax": 14,
|
|
133
|
+
"cognitiveMax": 16,
|
|
134
|
+
"smells": 0
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"file": "src/utils/diffRowCalculations.ts",
|
|
138
|
+
"lines": 136,
|
|
139
|
+
"cyclomaticMax": 13,
|
|
140
|
+
"cognitiveMax": 24,
|
|
141
|
+
"smells": 0
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"file": "src/core/ExplorerStateManager.ts",
|
|
145
|
+
"lines": 727,
|
|
146
|
+
"cyclomaticMax": 12,
|
|
147
|
+
"cognitiveMax": 15,
|
|
148
|
+
"smells": 0
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"file": "src/ui/widgets/FileList.ts",
|
|
152
|
+
"lines": 215,
|
|
153
|
+
"cyclomaticMax": 12,
|
|
154
|
+
"cognitiveMax": 12,
|
|
155
|
+
"smells": 0
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"file": "src/utils/lineBreaking.ts",
|
|
159
|
+
"lines": 114,
|
|
160
|
+
"cyclomaticMax": 12,
|
|
161
|
+
"cognitiveMax": 17,
|
|
162
|
+
"smells": 0
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"file": "src/ui/modals/BranchPicker.ts",
|
|
166
|
+
"lines": 185,
|
|
167
|
+
"cyclomaticMax": 11,
|
|
168
|
+
"cognitiveMax": 17,
|
|
169
|
+
"smells": 0
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"file": "src/config.ts",
|
|
173
|
+
"lines": 107,
|
|
174
|
+
"cyclomaticMax": 10,
|
|
175
|
+
"cognitiveMax": 13,
|
|
176
|
+
"smells": 0
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"file": "src/state/UIState.ts",
|
|
180
|
+
"lines": 307,
|
|
181
|
+
"cyclomaticMax": 10,
|
|
182
|
+
"cognitiveMax": 12,
|
|
183
|
+
"smells": 0
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"file": "src/KeyBindings.ts",
|
|
187
|
+
"lines": 373,
|
|
188
|
+
"cyclomaticMax": 9,
|
|
189
|
+
"cognitiveMax": 15,
|
|
190
|
+
"smells": 0
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"file": "src/core/GitStateManager.ts",
|
|
194
|
+
"lines": 989,
|
|
195
|
+
"cyclomaticMax": 9,
|
|
196
|
+
"cognitiveMax": 12,
|
|
197
|
+
"smells": 0
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"file": "src/ui/widgets/HistoryView.ts",
|
|
201
|
+
"lines": 97,
|
|
202
|
+
"cyclomaticMax": 9,
|
|
203
|
+
"cognitiveMax": 12,
|
|
204
|
+
"smells": 0
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"file": "src/utils/formatPath.ts",
|
|
208
|
+
"lines": 72,
|
|
209
|
+
"cyclomaticMax": 9,
|
|
210
|
+
"cognitiveMax": 11,
|
|
211
|
+
"smells": 0
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"file": "src/utils/explorerDisplayRows.ts",
|
|
215
|
+
"lines": 206,
|
|
216
|
+
"cyclomaticMax": 8,
|
|
217
|
+
"cognitiveMax": 15,
|
|
218
|
+
"smells": 0
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"file": "src/ui/modals/FileFinder.ts",
|
|
222
|
+
"lines": 238,
|
|
223
|
+
"cyclomaticMax": 7,
|
|
224
|
+
"cognitiveMax": 13,
|
|
225
|
+
"smells": 0
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"file": "src/ui/modals/BaseBranchPicker.ts",
|
|
229
|
+
"lines": 134,
|
|
230
|
+
"cyclomaticMax": 6,
|
|
231
|
+
"cognitiveMax": 13,
|
|
232
|
+
"smells": 0
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"file": "src/ui/modals/StashListModal.ts",
|
|
236
|
+
"lines": 122,
|
|
237
|
+
"cyclomaticMax": 5,
|
|
238
|
+
"cognitiveMax": 11,
|
|
239
|
+
"smells": 0
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
"smellsByRule": {}
|
|
243
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2026-03-06T05:12:44.045Z",
|
|
3
|
+
"gitRef": "v0.2.4",
|
|
4
|
+
"gitSha": "0677167",
|
|
5
|
+
"summary": {
|
|
6
|
+
"files": 91,
|
|
7
|
+
"lines": 16342,
|
|
8
|
+
"functions": 1163,
|
|
9
|
+
"avgCyclomaticComplexity": 4.9,
|
|
10
|
+
"maxCyclomaticComplexity": {
|
|
11
|
+
"value": 34,
|
|
12
|
+
"function": "reconcileSelectionAfterStateChange",
|
|
13
|
+
"file": "src/App.ts:538"
|
|
14
|
+
},
|
|
15
|
+
"avgCognitiveComplexity": 6.1,
|
|
16
|
+
"maxCognitiveComplexity": {
|
|
17
|
+
"value": 41,
|
|
18
|
+
"function": "(anonymous)",
|
|
19
|
+
"file": "src/git/diff.ts:517"
|
|
20
|
+
},
|
|
21
|
+
"smells": 0
|
|
22
|
+
},
|
|
23
|
+
"hotspots": [
|
|
24
|
+
{
|
|
25
|
+
"file": "src/App.ts",
|
|
26
|
+
"lines": 1004,
|
|
27
|
+
"cyclomaticMax": 34,
|
|
28
|
+
"cognitiveMax": 19,
|
|
29
|
+
"smells": 0
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"file": "src/utils/flatFileList.ts",
|
|
33
|
+
"lines": 100,
|
|
34
|
+
"cyclomaticMax": 29,
|
|
35
|
+
"cognitiveMax": 14,
|
|
36
|
+
"smells": 0
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"file": "src/git/diff.ts",
|
|
40
|
+
"lines": 656,
|
|
41
|
+
"cyclomaticMax": 26,
|
|
42
|
+
"cognitiveMax": 41,
|
|
43
|
+
"smells": 0
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"file": "src/utils/displayRows.ts",
|
|
47
|
+
"lines": 614,
|
|
48
|
+
"cyclomaticMax": 25,
|
|
49
|
+
"cognitiveMax": 39,
|
|
50
|
+
"smells": 0
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"file": "src/git/status.ts",
|
|
54
|
+
"lines": 392,
|
|
55
|
+
"cyclomaticMax": 22,
|
|
56
|
+
"cognitiveMax": 25,
|
|
57
|
+
"smells": 0
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"file": "src/ui/PaneRenderers.ts",
|
|
61
|
+
"lines": 240,
|
|
62
|
+
"cyclomaticMax": 20,
|
|
63
|
+
"cognitiveMax": 8,
|
|
64
|
+
"smells": 0
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"file": "src/ui/widgets/ExplorerContent.ts",
|
|
68
|
+
"lines": 126,
|
|
69
|
+
"cyclomaticMax": 20,
|
|
70
|
+
"cognitiveMax": 24,
|
|
71
|
+
"smells": 0
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"file": "src/NavigationController.ts",
|
|
75
|
+
"lines": 352,
|
|
76
|
+
"cyclomaticMax": 19,
|
|
77
|
+
"cognitiveMax": 13,
|
|
78
|
+
"smells": 0
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"file": "src/config.ts",
|
|
82
|
+
"lines": 168,
|
|
83
|
+
"cyclomaticMax": 18,
|
|
84
|
+
"cognitiveMax": 25,
|
|
85
|
+
"smells": 0
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"file": "src/ui/widgets/CommitPanel.ts",
|
|
89
|
+
"lines": 133,
|
|
90
|
+
"cyclomaticMax": 18,
|
|
91
|
+
"cognitiveMax": 16,
|
|
92
|
+
"smells": 0
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"file": "src/ui/widgets/Header.ts",
|
|
96
|
+
"lines": 134,
|
|
97
|
+
"cyclomaticMax": 18,
|
|
98
|
+
"cognitiveMax": 22,
|
|
99
|
+
"smells": 0
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"file": "src/MouseHandlers.ts",
|
|
103
|
+
"lines": 276,
|
|
104
|
+
"cyclomaticMax": 17,
|
|
105
|
+
"cognitiveMax": 15,
|
|
106
|
+
"smells": 0
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"file": "src/ipc/CommandServer.ts",
|
|
110
|
+
"lines": 266,
|
|
111
|
+
"cyclomaticMax": 17,
|
|
112
|
+
"cognitiveMax": 6,
|
|
113
|
+
"smells": 0
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"file": "src/index.ts",
|
|
117
|
+
"lines": 180,
|
|
118
|
+
"cyclomaticMax": 16,
|
|
119
|
+
"cognitiveMax": 17,
|
|
120
|
+
"smells": 0
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"file": "src/ui/widgets/ExplorerView.ts",
|
|
124
|
+
"lines": 245,
|
|
125
|
+
"cyclomaticMax": 16,
|
|
126
|
+
"cognitiveMax": 21,
|
|
127
|
+
"smells": 0
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"file": "src/utils/ansiTruncate.ts",
|
|
131
|
+
"lines": 118,
|
|
132
|
+
"cyclomaticMax": 16,
|
|
133
|
+
"cognitiveMax": 24,
|
|
134
|
+
"smells": 0
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"file": "src/ui/widgets/DiffView.ts",
|
|
138
|
+
"lines": 493,
|
|
139
|
+
"cyclomaticMax": 15,
|
|
140
|
+
"cognitiveMax": 12,
|
|
141
|
+
"smells": 0
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"file": "src/ui/widgets/CompareListView.ts",
|
|
145
|
+
"lines": 383,
|
|
146
|
+
"cyclomaticMax": 14,
|
|
147
|
+
"cognitiveMax": 16,
|
|
148
|
+
"smells": 0
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"file": "src/core/ExplorerStateManager.ts",
|
|
152
|
+
"lines": 735,
|
|
153
|
+
"cyclomaticMax": 13,
|
|
154
|
+
"cognitiveMax": 17,
|
|
155
|
+
"smells": 0
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"file": "src/utils/diffRowCalculations.ts",
|
|
159
|
+
"lines": 136,
|
|
160
|
+
"cyclomaticMax": 13,
|
|
161
|
+
"cognitiveMax": 24,
|
|
162
|
+
"smells": 0
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"file": "src/StagingOperations.ts",
|
|
166
|
+
"lines": 224,
|
|
167
|
+
"cyclomaticMax": 12,
|
|
168
|
+
"cognitiveMax": 10,
|
|
169
|
+
"smells": 0
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"file": "src/ui/widgets/FileList.ts",
|
|
173
|
+
"lines": 209,
|
|
174
|
+
"cyclomaticMax": 12,
|
|
175
|
+
"cognitiveMax": 12,
|
|
176
|
+
"smells": 0
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"file": "src/utils/lineBreaking.ts",
|
|
180
|
+
"lines": 114,
|
|
181
|
+
"cyclomaticMax": 12,
|
|
182
|
+
"cognitiveMax": 17,
|
|
183
|
+
"smells": 0
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"file": "src/core/WorkingTreeManager.ts",
|
|
187
|
+
"lines": 515,
|
|
188
|
+
"cyclomaticMax": 10,
|
|
189
|
+
"cognitiveMax": 13,
|
|
190
|
+
"smells": 0
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"file": "src/ui/widgets/HistoryView.ts",
|
|
194
|
+
"lines": 97,
|
|
195
|
+
"cyclomaticMax": 9,
|
|
196
|
+
"cognitiveMax": 12,
|
|
197
|
+
"smells": 0
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"file": "src/utils/formatPath.ts",
|
|
201
|
+
"lines": 72,
|
|
202
|
+
"cyclomaticMax": 9,
|
|
203
|
+
"cognitiveMax": 11,
|
|
204
|
+
"smells": 0
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"file": "src/utils/explorerDisplayRows.ts",
|
|
208
|
+
"lines": 206,
|
|
209
|
+
"cyclomaticMax": 8,
|
|
210
|
+
"cognitiveMax": 15,
|
|
211
|
+
"smells": 0
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"file": "src/ui/modals/FileFinder.ts",
|
|
215
|
+
"lines": 236,
|
|
216
|
+
"cyclomaticMax": 7,
|
|
217
|
+
"cognitiveMax": 13,
|
|
218
|
+
"smells": 0
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"file": "src/ui/modals/BaseBranchPicker.ts",
|
|
222
|
+
"lines": 132,
|
|
223
|
+
"cyclomaticMax": 6,
|
|
224
|
+
"cognitiveMax": 13,
|
|
225
|
+
"smells": 0
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"file": "src/ui/modals/RepoPicker.ts",
|
|
229
|
+
"lines": 134,
|
|
230
|
+
"cyclomaticMax": 6,
|
|
231
|
+
"cognitiveMax": 13,
|
|
232
|
+
"smells": 0
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
"smellsByRule": {}
|
|
236
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "diffstalker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Terminal application that displays git diff/status for directories",
|
|
5
5
|
"author": "yogh-io",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,10 @@
|
|
|
35
35
|
"deps": "depcruise src/ --config .dependency-cruiser.cjs",
|
|
36
36
|
"metrics": "bun scripts/collect-metrics.ts",
|
|
37
37
|
"metrics:snapshot": "bun scripts/collect-metrics.ts --save",
|
|
38
|
-
"prepublishOnly": "bun run build:prod"
|
|
38
|
+
"prepublishOnly": "bun run build:prod",
|
|
39
|
+
"release": "scripts/release.sh",
|
|
40
|
+
"release:minor": "scripts/release.sh minor",
|
|
41
|
+
"release:major": "scripts/release.sh major"
|
|
39
42
|
},
|
|
40
43
|
"keywords": [
|
|
41
44
|
"git",
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { getFileListSectionCounts } from './fileCategories.js';
|
|
2
|
-
// Re-export for backwards compatibility
|
|
3
|
-
export { getFileListSectionCounts } from './fileCategories.js';
|
|
4
|
-
/**
|
|
5
|
-
* Calculate total rows for the FileList component.
|
|
6
|
-
* Accounts for headers and spacers between sections.
|
|
7
|
-
*/
|
|
8
|
-
export function getFileListTotalRows(files) {
|
|
9
|
-
const { modifiedCount, untrackedCount, stagedCount } = getFileListSectionCounts(files);
|
|
10
|
-
let rows = 0;
|
|
11
|
-
// Modified section
|
|
12
|
-
if (modifiedCount > 0) {
|
|
13
|
-
rows += 1 + modifiedCount; // header + files
|
|
14
|
-
}
|
|
15
|
-
// Untracked section
|
|
16
|
-
if (untrackedCount > 0) {
|
|
17
|
-
if (modifiedCount > 0)
|
|
18
|
-
rows += 1; // spacer
|
|
19
|
-
rows += 1 + untrackedCount; // header + files
|
|
20
|
-
}
|
|
21
|
-
// Staged section
|
|
22
|
-
if (stagedCount > 0) {
|
|
23
|
-
if (modifiedCount > 0 || untrackedCount > 0)
|
|
24
|
-
rows += 1; // spacer
|
|
25
|
-
rows += 1 + stagedCount; // header + files
|
|
26
|
-
}
|
|
27
|
-
return rows;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Calculate the heights of the top (file list) and bottom (diff/commit/etc) panes
|
|
31
|
-
* based on the number of files and available content area.
|
|
32
|
-
*
|
|
33
|
-
* The top pane grows to fit files up to 40% of content height.
|
|
34
|
-
* The bottom pane gets the remaining space.
|
|
35
|
-
*
|
|
36
|
-
* When flatRowCount is provided (flat view mode), uses that directly instead
|
|
37
|
-
* of computing row count from categorized file list.
|
|
38
|
-
*/
|
|
39
|
-
export function calculatePaneHeights(files, contentHeight, maxTopRatio = 0.4, flatRowCount) {
|
|
40
|
-
// Calculate content rows needed for staging area
|
|
41
|
-
const neededRows = flatRowCount !== undefined ? flatRowCount : getFileListTotalRows(files);
|
|
42
|
-
// Minimum height of 3 (header + 2 lines for empty state)
|
|
43
|
-
const minHeight = 3;
|
|
44
|
-
// Maximum is maxTopRatio of content area
|
|
45
|
-
const maxHeight = Math.floor(contentHeight * maxTopRatio);
|
|
46
|
-
// Use the smaller of needed or max, but at least min
|
|
47
|
-
const topHeight = Math.max(minHeight, Math.min(neededRows, maxHeight));
|
|
48
|
-
const bottomHeight = contentHeight - topHeight;
|
|
49
|
-
return { topPaneHeight: topHeight, bottomPaneHeight: bottomHeight };
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Calculate which row in the file list a file at a given index occupies.
|
|
53
|
-
* This accounts for headers and spacers in the list.
|
|
54
|
-
* File order: Modified → Untracked → Staged (matches FileList.tsx)
|
|
55
|
-
*/
|
|
56
|
-
export function getRowForFileIndex(selectedIndex, modifiedCount, untrackedCount, _stagedCount) {
|
|
57
|
-
let row = 0;
|
|
58
|
-
// Modified section
|
|
59
|
-
if (selectedIndex < modifiedCount) {
|
|
60
|
-
// In modified section: header + file rows
|
|
61
|
-
return 1 + selectedIndex;
|
|
62
|
-
}
|
|
63
|
-
if (modifiedCount > 0) {
|
|
64
|
-
row += 1 + modifiedCount; // header + files
|
|
65
|
-
}
|
|
66
|
-
// Untracked section
|
|
67
|
-
const untrackedStart = modifiedCount;
|
|
68
|
-
if (selectedIndex < untrackedStart + untrackedCount) {
|
|
69
|
-
// In untracked section
|
|
70
|
-
const untrackedIdx = selectedIndex - untrackedStart;
|
|
71
|
-
if (modifiedCount > 0)
|
|
72
|
-
row += 1; // spacer
|
|
73
|
-
return row + 1 + untrackedIdx; // header + file position
|
|
74
|
-
}
|
|
75
|
-
if (untrackedCount > 0) {
|
|
76
|
-
if (modifiedCount > 0)
|
|
77
|
-
row += 1; // spacer
|
|
78
|
-
row += 1 + untrackedCount; // header + files
|
|
79
|
-
}
|
|
80
|
-
// Staged section
|
|
81
|
-
const stagedStart = modifiedCount + untrackedCount;
|
|
82
|
-
const stagedIdx = selectedIndex - stagedStart;
|
|
83
|
-
if (modifiedCount > 0 || untrackedCount > 0)
|
|
84
|
-
row += 1; // spacer
|
|
85
|
-
return row + 1 + stagedIdx; // header + file position
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Calculate the scroll offset needed to keep a selected row visible.
|
|
89
|
-
*/
|
|
90
|
-
export function calculateScrollOffset(selectedRow, currentScrollOffset, visibleHeight) {
|
|
91
|
-
// Scroll up if selected is above visible area
|
|
92
|
-
if (selectedRow < currentScrollOffset) {
|
|
93
|
-
return Math.max(0, selectedRow - 1);
|
|
94
|
-
}
|
|
95
|
-
// Scroll down if selected is below visible area
|
|
96
|
-
else if (selectedRow >= currentScrollOffset + visibleHeight) {
|
|
97
|
-
return selectedRow - visibleHeight + 1;
|
|
98
|
-
}
|
|
99
|
-
return currentScrollOffset;
|
|
100
|
-
}
|