reslop 0.2.5 → 0.2.6
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/CHANGELOG.md +12 -1
- package/LICENSE +1 -1
- package/README.md +11 -11
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -8
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +39 -47
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +332 -0
- package/lib/dashboard/npm.js +193 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +197 -402
- package/lib/deps.js +113 -240
- package/lib/detect.js +8 -18
- package/lib/diff/align.js +41 -113
- package/lib/diff/diff.js +12 -43
- package/lib/diff/display.js +25 -36
- package/lib/diff/edit.js +6 -20
- package/lib/diff/inline.js +76 -144
- package/lib/diff/items.js +33 -47
- package/lib/diff/parse.js +28 -56
- package/lib/diff/patch.js +12 -33
- package/lib/diff/unit.js +79 -178
- package/lib/editor.js +52 -69
- package/lib/files.js +71 -89
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +147 -272
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +141 -212
- package/lib/git.js +21 -49
- package/lib/github.js +67 -181
- package/lib/gitlab.js +40 -90
- package/lib/highlight/bash.js +55 -177
- package/lib/highlight/core.js +155 -141
- package/lib/highlight/css.js +25 -58
- package/lib/highlight/csv.js +19 -37
- package/lib/highlight/dart.js +72 -213
- package/lib/highlight/dot.js +14 -14
- package/lib/highlight/html.js +42 -63
- package/lib/highlight/js.js +177 -506
- package/lib/highlight/json.js +17 -37
- package/lib/highlight/log.js +19 -25
- package/lib/highlight/txt.js +7 -10
- package/lib/highlight.js +17 -46
- package/lib/keys.js +49 -82
- package/lib/manifest.js +67 -126
- package/lib/npm-commands.js +120 -169
- package/lib/remote.js +140 -190
- package/lib/render/branches.js +63 -61
- package/lib/render/chrome.js +220 -333
- package/lib/render/commits.js +160 -361
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +245 -0
- package/lib/render/dash-table.js +290 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -258
- package/lib/render/files.js +40 -85
- package/lib/render/frame.js +78 -117
- package/lib/render/notes.js +139 -210
- package/lib/render/npm.js +213 -177
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +72 -174
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/tiles.js +260 -0
- package/lib/render/unit.js +15 -31
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -37
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -77
- package/lib/report-test.js +221 -99
- package/lib/report-tools.js +96 -154
- package/lib/review-merge.js +33 -41
- package/lib/review.js +68 -129
- package/lib/runs.js +225 -0
- package/lib/select.js +53 -91
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +61 -43
- package/lib/session/branches.js +166 -222
- package/lib/session/change-actions.js +49 -119
- package/lib/session/commit.js +274 -355
- package/lib/session/compose.js +556 -714
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +162 -170
- package/lib/session/files-pane.js +76 -44
- package/lib/session/items.js +6 -17
- package/lib/session/lifecycle.js +393 -466
- package/lib/session/load.js +1 -14
- package/lib/session/navigation.js +2 -2
- package/lib/session/npm.js +403 -420
- package/lib/session/ops.js +5 -13
- package/lib/session/pointer.js +16 -14
- package/lib/session/progress.js +39 -30
- package/lib/session/review.js +1 -3
- package/lib/session/tasks.js +276 -235
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -132
- package/lib/session/view.js +47 -81
- package/lib/session/watch.js +196 -212
- package/lib/session.js +81 -161
- package/lib/update.js +44 -111
- package/lib/utilities.js +46 -88
- package/lib/wrap.js +29 -55
- package/package.json +1 -1
package/lib/session/dispatch.js
CHANGED
|
@@ -1,200 +1,192 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const compose = require('./compose.js');
|
|
4
|
+
const { COMPOSE_LEAVE } = compose;
|
|
4
5
|
const commit = require('./commit.js');
|
|
5
6
|
const { hasStagedChanges, listedCommits } = commit;
|
|
6
|
-
const { COMPOSE_LEAVE } = compose;
|
|
7
7
|
const actions = require('./actions.js');
|
|
8
|
-
const {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} =
|
|
8
|
+
const { LIST_PANES, DASH_BLOCKS, DASH_ALLOWED, CONFIRM_MODE } = actions;
|
|
9
|
+
const { disabledActions, actionFromKey, confirmKey } = actions;
|
|
10
|
+
const changeActions = require('./change-actions.js');
|
|
11
|
+
const { onCommand } = changeActions;
|
|
12
|
+
const filesPane = require('./files-pane.js');
|
|
13
|
+
const pointer = require('./pointer.js');
|
|
14
|
+
const { handlePointer } = pointer;
|
|
15
15
|
|
|
16
16
|
const currentTarget = (ui) => {
|
|
17
17
|
if (ui.pane === 'files') return ui.fileCursorEntry();
|
|
18
|
-
if (ui.pane === 'branches')
|
|
19
|
-
return ui.branches[ui.branchCursor];
|
|
20
|
-
}
|
|
18
|
+
if (ui.pane === 'branches') return ui.branches[ui.branchCursor];
|
|
21
19
|
if (ui.pane === 'commits') {
|
|
22
20
|
const entry = listedCommits(ui.commits.commits)[ui.commitCursor];
|
|
23
|
-
const
|
|
21
|
+
const canCommit = hasStagedChanges(ui);
|
|
24
22
|
const unstagedCurrent = !ui.rev && !ui.revShort;
|
|
25
|
-
return { ...entry, canCommit
|
|
23
|
+
return { ...entry, canCommit, unstagedCurrent };
|
|
26
24
|
}
|
|
27
25
|
return ui.current();
|
|
28
26
|
};
|
|
29
27
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
add: ui.changeActions.onAdd,
|
|
33
|
-
unstage: ui.changeActions.onUnstage,
|
|
34
|
-
revert: ui.changeActions.onRevert,
|
|
35
|
-
ignore: ui.changeActions.onIgnore,
|
|
36
|
-
next: ui.filesPane.onNext,
|
|
37
|
-
prev: ui.filesPane.onPrev,
|
|
38
|
-
layout: ui.filesPane.onLayout,
|
|
39
|
-
theme: ui.filesPane.onTheme,
|
|
40
|
-
files: ui.filesPane.onFiles,
|
|
41
|
-
feedback: ui.composer.onFeedback,
|
|
42
|
-
tasks: ui.composer.onTasks,
|
|
43
|
-
code: ui.composer.onCode,
|
|
44
|
-
reload: ui.lifecycle.onReload,
|
|
45
|
-
commit: ui.commits.onCommit,
|
|
46
|
-
amend: ui.commits.onAmend,
|
|
47
|
-
reword: ui.commits.onReword,
|
|
48
|
-
apply: ui.commits.onApply,
|
|
49
|
-
fixup: ui.commits.onFixup,
|
|
50
|
-
view: () => ui.commits.onView(),
|
|
51
|
-
branch: ui.gitBranches.onBranch,
|
|
52
|
-
pull: ui.gitBranches.onPull,
|
|
53
|
-
push: ui.gitBranches.onPush,
|
|
54
|
-
newBranch: ui.gitBranches.onNewBranch,
|
|
55
|
-
rebase: ui.gitBranches.onRebaseBranch,
|
|
56
|
-
drop: () => {
|
|
57
|
-
if (ui.pane === 'commits') {
|
|
58
|
-
return void ui.commits.onDropCommit();
|
|
59
|
-
}
|
|
60
|
-
ui.gitBranches.onDropBranch();
|
|
61
|
-
},
|
|
62
|
-
open: ui.filesPane.onOpenFile,
|
|
63
|
-
file: ui.filesPane.onFileScope,
|
|
64
|
-
diff: ui.filesPane.onDiffScope,
|
|
65
|
-
npm: ui.npm.open,
|
|
66
|
-
npmEdit: ui.npm.edit,
|
|
67
|
-
npmNew: ui.npm.create,
|
|
68
|
-
npmDrop: () => ui.npm.askDrop(),
|
|
69
|
-
npmLogs: () => ui.npm.askLogs(),
|
|
70
|
-
npmStop: () => ui.npm.closeView(),
|
|
71
|
-
back: () => ui.filesPane.onEscape(),
|
|
72
|
-
npmVerbose: () => ui.npm.toggleVerbose(),
|
|
73
|
-
npmRerun: () => ui.npm.rerun(),
|
|
74
|
-
check: () => ui.composer.toggleFocusedTask(),
|
|
75
|
-
removeTask: () => {
|
|
76
|
-
if (ui.pane === 'npm') return void ui.npm.askDrop();
|
|
77
|
-
ui.composer.removeFocusedTask();
|
|
78
|
-
},
|
|
79
|
-
quit: () => ui.onQuit(),
|
|
80
|
-
scrollUp: () => ui.filesPane.onScroll(-1),
|
|
81
|
-
scrollDown: () => ui.filesPane.onScroll(1),
|
|
82
|
-
pageUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-1)),
|
|
83
|
-
pageDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(1)),
|
|
84
|
-
halfUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-0.5)),
|
|
85
|
-
halfDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(0.5)),
|
|
86
|
-
home: ui.filesPane.onHome,
|
|
87
|
-
end: ui.filesPane.onEnd,
|
|
88
|
-
};
|
|
28
|
+
const scrollBy = (fraction) => (ui) =>
|
|
29
|
+
filesPane.onScroll(ui, filesPane.scrollStep(ui, fraction));
|
|
89
30
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
const pane = ui.pane;
|
|
98
|
-
if (LIST_PANES.includes(pane) && (action === 'next' || action === 'prev')) {
|
|
99
|
-
ui.filesPane.onScroll(action === 'next' ? 1 : -1);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const hidden = disabledActions(pane, currentTarget(ui));
|
|
103
|
-
if (hidden.includes(action)) return;
|
|
104
|
-
const handler = handlers[action];
|
|
105
|
-
if (!handler) return;
|
|
106
|
-
handler();
|
|
107
|
-
};
|
|
31
|
+
const DASH_HANDLERS = Object.fromEntries(
|
|
32
|
+
Object.entries(DASH_BLOCKS).map(([id, block]) => [
|
|
33
|
+
id,
|
|
34
|
+
(ui) => ui.dashboard.open(block),
|
|
35
|
+
]),
|
|
36
|
+
);
|
|
108
37
|
|
|
109
|
-
|
|
38
|
+
const HANDLERS = {
|
|
39
|
+
add: (ui) => onCommand(ui, 'add'),
|
|
40
|
+
unstage: (ui) => onCommand(ui, 'unstage'),
|
|
41
|
+
revert: (ui) => onCommand(ui, 'revert'),
|
|
42
|
+
ignore: (ui) => onCommand(ui, 'ignore'),
|
|
43
|
+
next: filesPane.onNext,
|
|
44
|
+
prev: filesPane.onPrev,
|
|
45
|
+
layout: filesPane.onLayout,
|
|
46
|
+
theme: filesPane.onTheme,
|
|
47
|
+
files: filesPane.onFiles,
|
|
48
|
+
open: filesPane.onOpenFile,
|
|
49
|
+
file: filesPane.onFileScope,
|
|
50
|
+
diff: filesPane.onDiffScope,
|
|
51
|
+
back: filesPane.onEscape,
|
|
52
|
+
home: filesPane.onHome,
|
|
53
|
+
end: filesPane.onEnd,
|
|
54
|
+
scrollUp: (ui) => filesPane.onScroll(ui, -1),
|
|
55
|
+
scrollDown: (ui) => filesPane.onScroll(ui, 1),
|
|
56
|
+
pageUp: scrollBy(-1),
|
|
57
|
+
pageDown: scrollBy(1),
|
|
58
|
+
halfUp: scrollBy(-0.5),
|
|
59
|
+
halfDown: scrollBy(0.5),
|
|
60
|
+
feedback: (ui) => ui.composer.onFeedback(),
|
|
61
|
+
code: (ui) => ui.composer.onCode(),
|
|
62
|
+
tasks: (ui) => ui.composer.tasks.onTasks(),
|
|
63
|
+
check: (ui) => ui.composer.tasks.toggleFocusedTask(),
|
|
64
|
+
removeTask: (ui) => {
|
|
65
|
+
if (ui.pane === 'npm') return void ui.npm.askDrop();
|
|
66
|
+
ui.composer.tasks.removeFocusedTask();
|
|
67
|
+
},
|
|
68
|
+
reload: (ui) => ui.lifecycle.onReload(),
|
|
69
|
+
commit: (ui) => ui.commits.onCommit(),
|
|
70
|
+
amend: (ui) => ui.commits.onAmend(),
|
|
71
|
+
reword: (ui) => ui.commits.onReword(),
|
|
72
|
+
apply: (ui) => ui.commits.onApply(),
|
|
73
|
+
fixup: (ui) => ui.commits.onFixup(),
|
|
74
|
+
view: (ui) => ui.commits.onView(),
|
|
75
|
+
branch: (ui) => ui.gitBranches.onBranch(),
|
|
76
|
+
pull: (ui) => ui.gitBranches.onPull(),
|
|
77
|
+
push: (ui) => ui.gitBranches.onPush(),
|
|
78
|
+
newBranch: (ui) => ui.gitBranches.onNewBranch(),
|
|
79
|
+
rebase: (ui) => ui.gitBranches.onRebaseBranch(),
|
|
80
|
+
drop: (ui) => {
|
|
81
|
+
if (ui.pane === 'commits') return void ui.commits.onDropCommit();
|
|
82
|
+
if (ui.pane === 'tasks') return void ui.composer.tasks.removeFocusedTask();
|
|
83
|
+
ui.gitBranches.onDropBranch();
|
|
84
|
+
},
|
|
85
|
+
npm: (ui) => ui.npm.open(),
|
|
86
|
+
npmEdit: (ui) => ui.npm.edit(),
|
|
87
|
+
npmNew: (ui) => ui.npm.create(),
|
|
88
|
+
npmDrop: (ui) => ui.npm.askDrop(),
|
|
89
|
+
npmLogs: (ui) => ui.npm.askLogs(),
|
|
90
|
+
npmStop: (ui) => ui.npm.closeView(),
|
|
91
|
+
npmVerbose: (ui) => ui.npm.toggleVerbose(),
|
|
92
|
+
npmRerun: (ui) => ui.npm.rerun(),
|
|
93
|
+
quit: (ui) => ui.onQuit(),
|
|
94
|
+
...DASH_HANDLERS,
|
|
110
95
|
};
|
|
111
96
|
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
97
|
+
const dispatchAction = (ui, action) => {
|
|
98
|
+
if (CONFIRM_MODE.includes(ui.mode)) return;
|
|
99
|
+
if (ui.mode === 'compose') {
|
|
100
|
+
if (!COMPOSE_LEAVE.includes(action)) return;
|
|
101
|
+
const result = ui.composer.saveCompose();
|
|
102
|
+
if (result && result.kind === 'error') return;
|
|
103
|
+
}
|
|
104
|
+
const pane = ui.pane;
|
|
105
|
+
if (pane === 'dashboard' && !DASH_ALLOWED.includes(action)) return;
|
|
106
|
+
if (LIST_PANES.includes(pane) && (action === 'next' || action === 'prev')) {
|
|
107
|
+
return void filesPane.onScroll(ui, action === 'next' ? 1 : -1);
|
|
108
|
+
}
|
|
109
|
+
if (disabledActions(pane, currentTarget(ui)).includes(action)) return;
|
|
110
|
+
const handler = HANDLERS[action];
|
|
111
|
+
if (handler) handler(ui);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const CONFIRMATIONS = {
|
|
115
|
+
confirmQuit: {
|
|
116
|
+
ready: (ui) => ui.finishQuit('ready'),
|
|
117
|
+
editing: (ui) => ui.finishQuit('editing'),
|
|
118
|
+
cancel: (ui) => ui.cancelQuit(),
|
|
119
|
+
},
|
|
120
|
+
confirmUpdate: {
|
|
121
|
+
accept: (ui) => ui.updater.accept(),
|
|
122
|
+
decline: (ui) => ui.updater.decline(),
|
|
123
|
+
},
|
|
124
|
+
confirmDrop: {
|
|
125
|
+
confirm: (ui) => {
|
|
126
|
+
if (ui.npm.dropName) return void ui.npm.confirmDrop();
|
|
127
|
+
if (ui.commits.dropName) return void ui.commits.confirmDropCommit();
|
|
128
|
+
ui.gitBranches.confirmDropBranch();
|
|
138
129
|
},
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
130
|
+
cancel: (ui) => {
|
|
131
|
+
if (ui.npm.dropName) return void ui.npm.cancelDrop();
|
|
132
|
+
if (ui.commits.dropName) return void ui.commits.cancelDropCommit();
|
|
133
|
+
ui.gitBranches.cancelDropBranch();
|
|
142
134
|
},
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
};
|
|
135
|
+
},
|
|
136
|
+
confirmPush: {
|
|
137
|
+
force: (ui) => ui.gitBranches.onForcePush(),
|
|
138
|
+
cancel: (ui) => ui.gitBranches.cancelPush(),
|
|
139
|
+
},
|
|
140
|
+
};
|
|
150
141
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
n: () => {},
|
|
157
|
-
};
|
|
142
|
+
const confirmChoice = (ui, key) => {
|
|
143
|
+
const handlers = CONFIRMATIONS[ui.mode];
|
|
144
|
+
const action = handlers ? confirmKey(ui.mode, key) : null;
|
|
145
|
+
if (action && handlers[action]) handlers[action](ui);
|
|
146
|
+
};
|
|
158
147
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
148
|
+
const NPM_VIEW_KEYS = {
|
|
149
|
+
escape: (ui) => ui.npm.closeView(),
|
|
150
|
+
r: (ui) => ui.npm.rerun(),
|
|
151
|
+
v: (ui) => ui.npm.toggleVerbose(),
|
|
152
|
+
e: () => {},
|
|
153
|
+
i: () => {},
|
|
154
|
+
};
|
|
165
155
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
};
|
|
156
|
+
const NPM_LIST_KEYS = {
|
|
157
|
+
'ctrl-up': (ui) => ui.npm.reorder(-1),
|
|
158
|
+
'ctrl-down': (ui) => ui.npm.reorder(1),
|
|
159
|
+
up: (ui) => ui.npm.move(-1),
|
|
160
|
+
down: (ui) => ui.npm.move(1),
|
|
161
|
+
};
|
|
173
162
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const onNpmKey = npmKey(key);
|
|
182
|
-
if (onNpmKey) return void onNpmKey();
|
|
183
|
-
if (key === 'escape') return void ui.filesPane.onEscape();
|
|
184
|
-
const toggle = key === 'x' || key === ' ';
|
|
185
|
-
if (toggle && ui.composer.toggleFocusedTask()) return;
|
|
186
|
-
if (ui.composer.typeIntoTask(key)) return;
|
|
187
|
-
const action = actionFromKey(key, ui.pane, ui.fileScope);
|
|
188
|
-
if (action) ui.dispatch(action);
|
|
189
|
-
};
|
|
163
|
+
const npmKey = (ui, key) => {
|
|
164
|
+
if (ui.pane !== 'npm') return null;
|
|
165
|
+
if (ui.npm.viewing && Object.hasOwn(NPM_VIEW_KEYS, key)) {
|
|
166
|
+
return NPM_VIEW_KEYS[key];
|
|
167
|
+
}
|
|
168
|
+
return Object.hasOwn(NPM_LIST_KEYS, key) ? NPM_LIST_KEYS[key] : null;
|
|
169
|
+
};
|
|
190
170
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
ui.
|
|
195
|
-
}
|
|
171
|
+
const handleKey = (ui, key) => {
|
|
172
|
+
if (CONFIRM_MODE.includes(ui.mode)) return void confirmChoice(ui, key);
|
|
173
|
+
if (ui.mode === 'compose') {
|
|
174
|
+
return void ui.runComposeCommand(ui.composer.handleKey(key));
|
|
175
|
+
}
|
|
176
|
+
const onNpmKey = npmKey(ui, key);
|
|
177
|
+
if (onNpmKey) return void onNpmKey(ui);
|
|
178
|
+
if (key === 'escape') return void filesPane.onEscape(ui);
|
|
179
|
+
const tasks = ui.composer.tasks;
|
|
180
|
+
const toggle = key === 'x' || key === ' ';
|
|
181
|
+
if (toggle && tasks.toggleFocusedTask()) return;
|
|
182
|
+
if (tasks.typeIntoTask(key)) return;
|
|
183
|
+
const action = actionFromKey(key, ui.pane, ui.fileScope);
|
|
184
|
+
if (action) ui.dispatch(action);
|
|
185
|
+
};
|
|
196
186
|
|
|
197
|
-
|
|
187
|
+
const handleEvent = (ui, event) => {
|
|
188
|
+
if (event.type === 'key') return void handleKey(ui, event.key);
|
|
189
|
+
if (event.type === 'mouse') handlePointer(ui, event);
|
|
198
190
|
};
|
|
199
191
|
|
|
200
|
-
module.exports = {
|
|
192
|
+
module.exports = { dispatchAction, confirmChoice, handleEvent };
|
|
@@ -13,16 +13,16 @@ const { setFileScope, openUnitFile, moveUnitBlock } = unit;
|
|
|
13
13
|
|
|
14
14
|
const LAYOUTS = ['unified', 'mixed', 'side'];
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const fileCursorEntry = (ui) => ui.fileList()[ui.nav.fileCursor] ?? null;
|
|
17
17
|
|
|
18
18
|
const clampIndex = (ui) => ui.nav.clampIndex(ui.items.length);
|
|
19
19
|
|
|
20
|
-
const syncReviewPath = (ui) => ui.nav.syncReviewPath(current(
|
|
20
|
+
const syncReviewPath = (ui) => ui.nav.syncReviewPath(ui.current());
|
|
21
21
|
|
|
22
22
|
const clampFileCursor = (ui) => ui.nav.clampFileCursor(ui.fileList().length);
|
|
23
23
|
|
|
24
24
|
const followReviewPath = (ui) =>
|
|
25
|
-
ui.nav.followReviewPath(ui.fileList(), current(
|
|
25
|
+
ui.nav.followReviewPath(ui.fileList(), ui.current());
|
|
26
26
|
|
|
27
27
|
const syncFileCursor = (ui) => {
|
|
28
28
|
if (ui.nav.pane === 'files') return void clampFileCursor(ui);
|
|
@@ -44,7 +44,42 @@ const showFiles = (ui) => {
|
|
|
44
44
|
if (held) ui.lifecycle.catchUpWatch();
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
+
const viewingCommit = (ui) => !ui.change && Boolean(ui.rev || ui.revShort);
|
|
48
|
+
|
|
49
|
+
const releaseCommit = (ui) => {
|
|
50
|
+
if (!viewingCommit(ui)) return;
|
|
51
|
+
ui.rev = '';
|
|
52
|
+
ui.revShort = '';
|
|
53
|
+
ui.refreshFromRepo({ keepEmpty: true });
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const showDashboard = (ui) => {
|
|
57
|
+
const nav = ui.nav;
|
|
58
|
+
const held = nav.pane !== 'dashboard';
|
|
59
|
+
nav.pane = 'dashboard';
|
|
60
|
+
nav.tasksOpen = false;
|
|
61
|
+
nav.scroll = 0;
|
|
62
|
+
nav.clearSelection();
|
|
63
|
+
ui.status = '';
|
|
64
|
+
releaseCommit(ui);
|
|
65
|
+
if (held) ui.lifecycle.catchUpWatch();
|
|
66
|
+
ui.dashboard.enter();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const HOME_CHILDREN = ['files', 'branches', 'commits', 'npm'];
|
|
70
|
+
|
|
71
|
+
const returnsHome = (ui) => {
|
|
72
|
+
if (!ui.dashboardHome) return false;
|
|
73
|
+
const { pane, tasksOpen } = ui.nav;
|
|
74
|
+
return HOME_CHILDREN.includes(pane) || tasksOpen === true;
|
|
75
|
+
};
|
|
76
|
+
|
|
47
77
|
const onEscape = (ui) => {
|
|
78
|
+
if (ui.nav.pane === 'dashboard') return void ui.onQuit();
|
|
79
|
+
const commitDiff = ui.nav.pane === 'diff' && viewingCommit(ui);
|
|
80
|
+
if (returnsHome(ui) || (ui.dashboardHome && commitDiff)) {
|
|
81
|
+
return void showDashboard(ui);
|
|
82
|
+
}
|
|
48
83
|
if (ui.nav.pane === 'files') return void ui.onQuit();
|
|
49
84
|
showFiles(ui);
|
|
50
85
|
};
|
|
@@ -60,7 +95,6 @@ const onFiles = (ui) => {
|
|
|
60
95
|
}
|
|
61
96
|
ui.nav.pane = 'diff';
|
|
62
97
|
ui.nav.clearSelection();
|
|
63
|
-
if (ui.nav.reviewPath === TASKS_FILE) ui.composer.openTasksPage();
|
|
64
98
|
return;
|
|
65
99
|
}
|
|
66
100
|
showFiles(ui);
|
|
@@ -73,14 +107,14 @@ const onOpenFile = (ui) => {
|
|
|
73
107
|
if (ui.nav.pane === 'commits') return void ui.commits.onShowDiff();
|
|
74
108
|
if (ui.nav.pane === 'npm') return void ui.npm.run();
|
|
75
109
|
if (ui.nav.pane !== 'files') {
|
|
76
|
-
if (ui.nav.tasksOpen) ui.composer.editFocusedTask();
|
|
110
|
+
if (ui.nav.tasksOpen) ui.composer.tasks.editFocusedTask();
|
|
77
111
|
return;
|
|
78
112
|
}
|
|
79
113
|
const list = ui.fileList();
|
|
80
114
|
const entry = list[ui.nav.fileCursor];
|
|
81
115
|
if (!entry) return;
|
|
82
116
|
if (isTasksEntry(entry)) {
|
|
83
|
-
ui.composer.openTasksPage();
|
|
117
|
+
ui.composer.tasks.openTasksPage();
|
|
84
118
|
ui.status = '';
|
|
85
119
|
return;
|
|
86
120
|
}
|
|
@@ -134,21 +168,13 @@ const moveRemaining = (ui, step) => {
|
|
|
134
168
|
|
|
135
169
|
const onNext = (ui) => {
|
|
136
170
|
if (ui.nav.pane === 'unit') return void moveUnitBlock(ui, 1);
|
|
137
|
-
if (ui.nav.
|
|
138
|
-
ui.composer.closeTasksPage();
|
|
139
|
-
if (ui.items.length) ui.nav.index = 0;
|
|
140
|
-
ui.nav.scroll = 0;
|
|
141
|
-
syncReviewPath(ui);
|
|
142
|
-
syncFileCursor(ui);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
171
|
+
if (ui.nav.pane === 'tasks') return void ui.composer.tasks.moveTaskFocus(1);
|
|
145
172
|
moveRemaining(ui, 1);
|
|
146
173
|
};
|
|
147
174
|
|
|
148
175
|
const onPrev = (ui) => {
|
|
149
176
|
if (ui.nav.pane === 'unit') return void moveUnitBlock(ui, -1);
|
|
150
|
-
if (ui.nav.
|
|
151
|
-
if (ui.nav.index <= 0) return void ui.composer.openTasksPage();
|
|
177
|
+
if (ui.nav.pane === 'tasks') return void ui.composer.tasks.moveTaskFocus(-1);
|
|
152
178
|
moveRemaining(ui, -1);
|
|
153
179
|
};
|
|
154
180
|
|
|
@@ -158,7 +184,7 @@ const scrollStep = (ui, fraction) => {
|
|
|
158
184
|
const rows = size.height ?? 24;
|
|
159
185
|
const fallback = Math.max(1, rows - 4);
|
|
160
186
|
const bodyH = frame?.bodyH ?? fallback;
|
|
161
|
-
const viewing = ui.nav.pane === 'npm' && ui.npm
|
|
187
|
+
const viewing = ui.nav.pane === 'npm' && ui.npm.viewing;
|
|
162
188
|
const viewRows = viewing ? logViewRows(bodyH) : bodyH;
|
|
163
189
|
const height = Math.max(1, viewRows);
|
|
164
190
|
const span = Math.floor(height * Math.abs(fraction));
|
|
@@ -168,6 +194,7 @@ const scrollStep = (ui, fraction) => {
|
|
|
168
194
|
};
|
|
169
195
|
|
|
170
196
|
const onScroll = (ui, delta) => {
|
|
197
|
+
if (ui.nav.pane === 'dashboard') return;
|
|
171
198
|
if (ui.nav.pane === 'files') return void onFileMove(ui, delta);
|
|
172
199
|
if (ui.nav.pane === 'branches') {
|
|
173
200
|
return void ui.gitBranches.onBranchMove(delta);
|
|
@@ -176,8 +203,8 @@ const onScroll = (ui, delta) => {
|
|
|
176
203
|
return void ui.commits.onCommitMove(delta);
|
|
177
204
|
}
|
|
178
205
|
if (ui.nav.pane === 'npm') return void ui.npm.move(delta);
|
|
179
|
-
if (ui.nav.tasksOpen && ui.composer.taskRowCount() > 1) {
|
|
180
|
-
return void ui.composer.moveTaskFocus(delta);
|
|
206
|
+
if (ui.nav.tasksOpen && ui.composer.tasks.taskRowCount() > 1) {
|
|
207
|
+
return void ui.composer.tasks.moveTaskFocus(delta);
|
|
181
208
|
}
|
|
182
209
|
const frame = ui.lastFrame;
|
|
183
210
|
const max = frame ? frame.scrollMax : null;
|
|
@@ -190,15 +217,16 @@ const onScroll = (ui, delta) => {
|
|
|
190
217
|
};
|
|
191
218
|
|
|
192
219
|
const onJump = (ui, toEnd) => {
|
|
220
|
+
if (ui.nav.pane === 'dashboard') return;
|
|
193
221
|
if (LIST_PANES.includes(ui.nav.pane)) {
|
|
194
222
|
const delta = toEnd ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER;
|
|
195
223
|
return void onScroll(ui, delta);
|
|
196
224
|
}
|
|
197
|
-
if (ui.nav.tasksOpen && ui.composer.taskRowCount() > 0) {
|
|
198
|
-
const last = ui.composer.taskRowCount() - 1;
|
|
225
|
+
if (ui.nav.tasksOpen && ui.composer.tasks.taskRowCount() > 0) {
|
|
226
|
+
const last = ui.composer.tasks.taskRowCount() - 1;
|
|
199
227
|
const target = toEnd ? last : 0;
|
|
200
|
-
const at = ui.composer.clampedTaskFocus();
|
|
201
|
-
return void ui.composer.moveTaskFocus(target - at);
|
|
228
|
+
const at = ui.composer.tasks.clampedTaskFocus();
|
|
229
|
+
return void ui.composer.tasks.moveTaskFocus(target - at);
|
|
202
230
|
}
|
|
203
231
|
const frame = ui.lastFrame;
|
|
204
232
|
const max = frame ? frame.scrollMax : 0;
|
|
@@ -223,24 +251,28 @@ const onTheme = (ui) => {
|
|
|
223
251
|
ui.status = next;
|
|
224
252
|
};
|
|
225
253
|
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
254
|
+
const onHome = (ui) => onJump(ui, false);
|
|
255
|
+
const onEnd = (ui) => onJump(ui, true);
|
|
256
|
+
const onFileScope = (ui) => setFileScope(ui, 'file');
|
|
257
|
+
const onDiffScope = (ui) => setFileScope(ui, 'diff');
|
|
258
|
+
|
|
259
|
+
module.exports = {
|
|
260
|
+
fileCursorEntry,
|
|
261
|
+
clampIndex,
|
|
262
|
+
syncReviewPath,
|
|
263
|
+
syncFileCursor,
|
|
264
|
+
showFiles,
|
|
265
|
+
onEscape,
|
|
266
|
+
onFiles,
|
|
267
|
+
onOpenFile,
|
|
268
|
+
onNext,
|
|
269
|
+
onPrev,
|
|
270
|
+
scrollStep,
|
|
271
|
+
onScroll,
|
|
272
|
+
onHome,
|
|
273
|
+
onEnd,
|
|
274
|
+
onLayout,
|
|
275
|
+
onTheme,
|
|
276
|
+
onFileScope,
|
|
277
|
+
onDiffScope,
|
|
278
|
+
};
|
package/lib/session/items.js
CHANGED
|
@@ -29,13 +29,9 @@ const blockKey = (item) => {
|
|
|
29
29
|
if (isTaskItem(item)) return `todo:${TASKS_FILE}`;
|
|
30
30
|
const depId = depChangeKey(item);
|
|
31
31
|
if (depId) return `${rel}:dep:${depId}`;
|
|
32
|
-
if (!item.hunk) {
|
|
33
|
-
const block = item.blockId ?? '-';
|
|
34
|
-
return `${rel}:file:${block}`;
|
|
35
|
-
}
|
|
36
|
-
const oldStart = item.hunk.oldStart;
|
|
37
|
-
const newStart = item.hunk.newStart;
|
|
38
32
|
const block = item.blockId ?? '-';
|
|
33
|
+
if (!item.hunk) return `${rel}:file:${block}`;
|
|
34
|
+
const { oldStart, newStart } = item.hunk;
|
|
39
35
|
return `${rel}:${oldStart}:${newStart}:${block}`;
|
|
40
36
|
};
|
|
41
37
|
|
|
@@ -119,12 +115,10 @@ const alignLoadedItems = (prev, next) => {
|
|
|
119
115
|
const ordered = [];
|
|
120
116
|
for (const [rel, list] of groupByPath(prev)) {
|
|
121
117
|
seen.add(rel);
|
|
122
|
-
|
|
123
|
-
for (const item of aligned) ordered.push(item);
|
|
118
|
+
ordered.push(...alignGroup(list, nextGroups.get(rel) ?? []));
|
|
124
119
|
}
|
|
125
120
|
for (const [rel, list] of nextGroups) {
|
|
126
|
-
if (seen.has(rel))
|
|
127
|
-
for (const item of list) ordered.push(item);
|
|
121
|
+
if (!seen.has(rel)) ordered.push(...list);
|
|
128
122
|
}
|
|
129
123
|
return ordered;
|
|
130
124
|
};
|
|
@@ -195,8 +189,7 @@ const sameBlock = (left, right) => {
|
|
|
195
189
|
const canEditCode = (item) => {
|
|
196
190
|
if (!item || isTaskItem(item)) return false;
|
|
197
191
|
if (!item.hunk || !item.file) return false;
|
|
198
|
-
|
|
199
|
-
return true;
|
|
192
|
+
return !item.file.isBinary;
|
|
200
193
|
};
|
|
201
194
|
|
|
202
195
|
class ItemCollection {
|
|
@@ -237,11 +230,7 @@ class ItemCollection {
|
|
|
237
230
|
const replaced = this.items.map((entry) =>
|
|
238
231
|
sameBlock(entry, item) ? next : entry,
|
|
239
232
|
);
|
|
240
|
-
|
|
241
|
-
this.items = replaced;
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
this.items = refreshIndexPatches(replaced, next);
|
|
233
|
+
this.items = next.dep ? replaced : refreshIndexPatches(replaced, next);
|
|
245
234
|
}
|
|
246
235
|
}
|
|
247
236
|
|