reslop 0.2.4 → 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 +25 -1
- package/LICENSE +1 -1
- package/README.md +12 -13
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -12
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +48 -18
- 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 +196 -404
- package/lib/deps.js +240 -399
- 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 +138 -141
- 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 +90 -206
- package/lib/editor.js +98 -55
- package/lib/files.js +86 -103
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +182 -344
- 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 +157 -132
- 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 +16 -26
- 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 +22 -35
- package/lib/highlight/txt.js +9 -22
- package/lib/highlight.js +17 -46
- package/lib/keys.js +62 -85
- package/lib/manifest.js +67 -130
- package/lib/npm-commands.js +119 -189
- package/lib/remote.js +141 -197
- package/lib/render/branches.js +66 -73
- package/lib/render/chrome.js +264 -323
- package/lib/render/commits.js +187 -500
- 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 -228
- package/lib/render/files.js +45 -99
- package/lib/render/frame.js +129 -183
- package/lib/render/notes.js +144 -160
- package/lib/render/npm.js +234 -112
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +131 -170
- 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 -28
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -38
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -78
- package/lib/report-test.js +256 -141
- package/lib/report-tools.js +96 -161
- package/lib/review-merge.js +114 -152
- package/lib/review.js +115 -189
- package/lib/runs.js +225 -0
- package/lib/select.js +89 -75
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +82 -63
- package/lib/session/branches.js +193 -247
- package/lib/session/change-actions.js +171 -214
- package/lib/session/commit.js +280 -342
- package/lib/session/compose.js +559 -674
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +164 -157
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +85 -53
- package/lib/session/items.js +73 -104
- package/lib/session/lifecycle.js +403 -541
- package/lib/session/load.js +48 -68
- package/lib/session/navigation.js +96 -87
- package/lib/session/npm.js +409 -345
- package/lib/session/ops.js +196 -63
- package/lib/session/pointer.js +23 -15
- package/lib/session/progress.js +33 -21
- package/lib/session/review.js +33 -54
- package/lib/session/tasks.js +333 -0
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -136
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +52 -83
- package/lib/session/watch.js +208 -204
- package/lib/session.js +112 -237
- package/lib/update.js +45 -116
- package/lib/utilities.js +67 -89
- package/lib/wrap.js +33 -44
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
package/lib/session/dispatch.js
CHANGED
|
@@ -1,185 +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
|
-
next: ui.filesPane.onNext,
|
|
36
|
-
prev: ui.filesPane.onPrev,
|
|
37
|
-
layout: ui.filesPane.onLayout,
|
|
38
|
-
theme: ui.filesPane.onTheme,
|
|
39
|
-
files: ui.filesPane.onFiles,
|
|
40
|
-
feedback: ui.composer.onFeedback,
|
|
41
|
-
todo: ui.composer.onTodo,
|
|
42
|
-
code: ui.composer.onCode,
|
|
43
|
-
reload: ui.lifecycle.onReload,
|
|
44
|
-
commit: ui.commits.onCommit,
|
|
45
|
-
amend: ui.commits.onAmend,
|
|
46
|
-
reword: ui.commits.onReword,
|
|
47
|
-
apply: ui.commits.onApply,
|
|
48
|
-
fixup: ui.commits.onFixup,
|
|
49
|
-
view: () => ui.commits.onView(),
|
|
50
|
-
branch: ui.gitBranches.onBranch,
|
|
51
|
-
pull: ui.gitBranches.onPull,
|
|
52
|
-
push: ui.gitBranches.onPush,
|
|
53
|
-
newBranch: ui.gitBranches.onNewBranch,
|
|
54
|
-
rebase: ui.gitBranches.onRebaseBranch,
|
|
55
|
-
drop: () => {
|
|
56
|
-
if (ui.pane === 'commits') {
|
|
57
|
-
return void ui.commits.onDropCommit();
|
|
58
|
-
}
|
|
59
|
-
ui.gitBranches.onDropBranch();
|
|
60
|
-
},
|
|
61
|
-
open: ui.filesPane.onOpenFile,
|
|
62
|
-
file: ui.filesPane.onFileScope,
|
|
63
|
-
diff: ui.filesPane.onDiffScope,
|
|
64
|
-
npm: ui.npm.open,
|
|
65
|
-
npmEdit: ui.npm.edit,
|
|
66
|
-
npmNew: ui.npm.create,
|
|
67
|
-
npmDrop: () => ui.npm.askDrop(),
|
|
68
|
-
npmLogs: () => ui.npm.askLogs(),
|
|
69
|
-
npmStop: () => ui.npm.closeView(),
|
|
70
|
-
npmRerun: () => ui.npm.rerun(),
|
|
71
|
-
check: () => ui.composer.toggleFocusedTodo(),
|
|
72
|
-
removeTodo: () => {
|
|
73
|
-
if (ui.pane === 'npm') return void ui.npm.askDrop();
|
|
74
|
-
ui.composer.removeFocusedTodo();
|
|
75
|
-
},
|
|
76
|
-
quit: () => ui.onQuit(),
|
|
77
|
-
scrollUp: () => ui.filesPane.onScroll(-1),
|
|
78
|
-
scrollDown: () => ui.filesPane.onScroll(1),
|
|
79
|
-
pageUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-1)),
|
|
80
|
-
pageDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(1)),
|
|
81
|
-
halfUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-0.5)),
|
|
82
|
-
halfDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(0.5)),
|
|
83
|
-
home: ui.filesPane.onHome,
|
|
84
|
-
end: ui.filesPane.onEnd,
|
|
85
|
-
};
|
|
28
|
+
const scrollBy = (fraction) => (ui) =>
|
|
29
|
+
filesPane.onScroll(ui, filesPane.scrollStep(ui, fraction));
|
|
86
30
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
const pane = ui.pane;
|
|
95
|
-
if (LIST_PANES.includes(pane) && (action === 'next' || action === 'prev')) {
|
|
96
|
-
ui.filesPane.onScroll(action === 'next' ? 1 : -1);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const hidden = disabledActions(pane, currentTarget(ui));
|
|
100
|
-
if (hidden.includes(action)) return;
|
|
101
|
-
const handler = handlers[action];
|
|
102
|
-
if (!handler) return;
|
|
103
|
-
handler();
|
|
104
|
-
};
|
|
31
|
+
const DASH_HANDLERS = Object.fromEntries(
|
|
32
|
+
Object.entries(DASH_BLOCKS).map(([id, block]) => [
|
|
33
|
+
id,
|
|
34
|
+
(ui) => ui.dashboard.open(block),
|
|
35
|
+
]),
|
|
36
|
+
);
|
|
105
37
|
|
|
106
|
-
|
|
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,
|
|
107
95
|
};
|
|
108
96
|
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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();
|
|
135
129
|
},
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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();
|
|
139
134
|
},
|
|
140
|
-
}
|
|
135
|
+
},
|
|
136
|
+
confirmPush: {
|
|
137
|
+
force: (ui) => ui.gitBranches.onForcePush(),
|
|
138
|
+
cancel: (ui) => ui.gitBranches.cancelPush(),
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
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
|
+
};
|
|
147
|
+
|
|
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
|
+
};
|
|
141
155
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
+
};
|
|
147
162
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
if (ui.pane === 'npm' && ui.npm.viewing) {
|
|
157
|
-
if (key === 'escape') return void ui.npm.closeView();
|
|
158
|
-
if (key === 'r') return void ui.npm.rerun();
|
|
159
|
-
if (key === 'e' || key === 'n') return;
|
|
160
|
-
}
|
|
161
|
-
if (ui.pane === 'npm' && key === 'ctrl-up') return void ui.npm.reorder(-1);
|
|
162
|
-
if (ui.pane === 'npm' && key === 'ctrl-down') {
|
|
163
|
-
return void ui.npm.reorder(1);
|
|
164
|
-
}
|
|
165
|
-
if (ui.pane === 'npm' && (key === 'up' || key === 'down')) {
|
|
166
|
-
return void ui.npm.move(key === 'up' ? -1 : 1);
|
|
167
|
-
}
|
|
168
|
-
if (key === 'escape') return void ui.filesPane.onEscape();
|
|
169
|
-
const toggle = key === 'x' || key === ' ';
|
|
170
|
-
if (toggle && ui.composer.toggleFocusedTodo()) return;
|
|
171
|
-
if (ui.composer.typeIntoTodo(key)) return;
|
|
172
|
-
const action = actionFromKey(key, ui.pane, ui.fileScope);
|
|
173
|
-
if (action) ui.dispatch(action);
|
|
174
|
-
};
|
|
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
|
+
};
|
|
175
170
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
ui.
|
|
180
|
-
}
|
|
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
|
+
};
|
|
181
186
|
|
|
182
|
-
|
|
187
|
+
const handleEvent = (ui, event) => {
|
|
188
|
+
if (event.type === 'key') return void handleKey(ui, event.key);
|
|
189
|
+
if (event.type === 'mouse') handlePointer(ui, event);
|
|
183
190
|
};
|
|
184
191
|
|
|
185
|
-
module.exports = {
|
|
192
|
+
module.exports = { dispatchAction, confirmChoice, handleEvent };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const wrap = require('../wrap.js');
|
|
4
|
+
const diff = require('../render/diff.js');
|
|
5
|
+
|
|
6
|
+
const { indexAtRow } = wrap;
|
|
7
|
+
const { codeInnerWidth } = diff;
|
|
8
|
+
|
|
9
|
+
const hitAt = (hits, cell) => {
|
|
10
|
+
for (const hit of hits) {
|
|
11
|
+
if (hit.y !== cell.y) continue;
|
|
12
|
+
const x0 = hit.x0 ?? hit.textX;
|
|
13
|
+
if (cell.x < x0) continue;
|
|
14
|
+
if (hit.x1 !== undefined && cell.x >= hit.x1) continue;
|
|
15
|
+
return hit;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const offsetOf = (hit, cellX) => {
|
|
21
|
+
const shown = cellX - hit.textX;
|
|
22
|
+
const col = Math.max(0, shown) + (hit.scroll || 0);
|
|
23
|
+
const at = indexAtRow(hit.start || 0, hit.text, col);
|
|
24
|
+
if (hit.limit !== undefined && at > hit.limit) return hit.limit;
|
|
25
|
+
return at;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const revealCode = (ui) => {
|
|
29
|
+
const kind = ui.composeKind;
|
|
30
|
+
if (kind !== 'code' && kind !== 'file') return;
|
|
31
|
+
const size = ui.lastSize ?? ui.getSize();
|
|
32
|
+
ui.editor.reveal(codeInnerWidth(size.width, ui.layout));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const focusField = (ui, hit) => {
|
|
36
|
+
if (!hit.field || !ui.npm) return true;
|
|
37
|
+
if (hit.field === ui.npm.editField) return true;
|
|
38
|
+
return ui.npm.focusField(hit.field);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const placeClick = (ui, cell) => {
|
|
42
|
+
if (ui.mode !== 'compose' || !ui.editor) return false;
|
|
43
|
+
const hits = ui.lastFrame && ui.lastFrame.editHits;
|
|
44
|
+
if (!hits || !hits.length) return false;
|
|
45
|
+
const hit = hitAt(hits, cell);
|
|
46
|
+
if (!hit) return false;
|
|
47
|
+
if (!focusField(ui, hit)) {
|
|
48
|
+
ui.paint();
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
ui.editor.place(offsetOf(hit, cell.x));
|
|
52
|
+
revealCode(ui);
|
|
53
|
+
ui.paint();
|
|
54
|
+
return true;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
module.exports = { placeClick };
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const ansi = require('../ansi.js');
|
|
4
4
|
const files = require('../files.js');
|
|
5
5
|
const { THEME_NAMES, setTheme, themeName } = ansi;
|
|
6
|
-
const {
|
|
6
|
+
const { isTasksEntry, TASKS_FILE } = files;
|
|
7
7
|
const npm = require('../render/npm.js');
|
|
8
8
|
const { logViewRows } = npm;
|
|
9
9
|
const unit = require('./unit.js');
|
|
@@ -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);
|
|
@@ -32,18 +32,54 @@ const syncFileCursor = (ui) => {
|
|
|
32
32
|
const showFiles = (ui) => {
|
|
33
33
|
const nav = ui.nav;
|
|
34
34
|
const held =
|
|
35
|
-
nav.
|
|
35
|
+
nav.tasksOpen === true ||
|
|
36
36
|
nav.pane === 'branches' ||
|
|
37
37
|
nav.pane === 'commits' ||
|
|
38
38
|
nav.pane === 'npm';
|
|
39
39
|
nav.pane = 'files';
|
|
40
|
+
nav.resetListScroll('files');
|
|
40
41
|
nav.clearSelection();
|
|
41
42
|
followReviewPath(ui);
|
|
42
|
-
nav.
|
|
43
|
+
nav.tasksOpen = false;
|
|
43
44
|
if (held) ui.lifecycle.catchUpWatch();
|
|
44
45
|
};
|
|
45
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
|
+
|
|
46
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
|
+
}
|
|
47
83
|
if (ui.nav.pane === 'files') return void ui.onQuit();
|
|
48
84
|
showFiles(ui);
|
|
49
85
|
};
|
|
@@ -54,12 +90,11 @@ const onFiles = (ui) => {
|
|
|
54
90
|
if (ui.nav.fileScope === 'file') {
|
|
55
91
|
const list = ui.fileList();
|
|
56
92
|
const entry = list[ui.nav.fileCursor];
|
|
57
|
-
if (entry && !
|
|
93
|
+
if (entry && !isTasksEntry(entry)) openUnitFile(ui, entry);
|
|
58
94
|
return;
|
|
59
95
|
}
|
|
60
96
|
ui.nav.pane = 'diff';
|
|
61
97
|
ui.nav.clearSelection();
|
|
62
|
-
if (ui.nav.reviewPath === TODO_FILE) ui.composer.openTodoPage();
|
|
63
98
|
return;
|
|
64
99
|
}
|
|
65
100
|
showFiles(ui);
|
|
@@ -72,18 +107,18 @@ const onOpenFile = (ui) => {
|
|
|
72
107
|
if (ui.nav.pane === 'commits') return void ui.commits.onShowDiff();
|
|
73
108
|
if (ui.nav.pane === 'npm') return void ui.npm.run();
|
|
74
109
|
if (ui.nav.pane !== 'files') {
|
|
75
|
-
if (ui.nav.
|
|
110
|
+
if (ui.nav.tasksOpen) ui.composer.tasks.editFocusedTask();
|
|
76
111
|
return;
|
|
77
112
|
}
|
|
78
113
|
const list = ui.fileList();
|
|
79
114
|
const entry = list[ui.nav.fileCursor];
|
|
80
115
|
if (!entry) return;
|
|
81
|
-
if (
|
|
82
|
-
ui.composer.
|
|
116
|
+
if (isTasksEntry(entry)) {
|
|
117
|
+
ui.composer.tasks.openTasksPage();
|
|
83
118
|
ui.status = '';
|
|
84
119
|
return;
|
|
85
120
|
}
|
|
86
|
-
ui.nav.
|
|
121
|
+
ui.nav.tasksOpen = false;
|
|
87
122
|
ui.nav.index = entry.openIndex ?? entry.firstIndex;
|
|
88
123
|
if (ui.nav.fileScope === 'file') {
|
|
89
124
|
return void openUnitFile(ui, entry);
|
|
@@ -107,8 +142,8 @@ const onFileMove = (ui, delta) => {
|
|
|
107
142
|
if (next === ui.nav.fileCursor) return;
|
|
108
143
|
ui.nav.fileCursor = next;
|
|
109
144
|
const entry = list[next];
|
|
110
|
-
if (
|
|
111
|
-
ui.nav.reviewPath =
|
|
145
|
+
if (isTasksEntry(entry)) {
|
|
146
|
+
ui.nav.reviewPath = TASKS_FILE;
|
|
112
147
|
} else {
|
|
113
148
|
ui.nav.reviewPath = entry.path;
|
|
114
149
|
ui.nav.index = entry.firstIndex;
|
|
@@ -133,21 +168,13 @@ const moveRemaining = (ui, step) => {
|
|
|
133
168
|
|
|
134
169
|
const onNext = (ui) => {
|
|
135
170
|
if (ui.nav.pane === 'unit') return void moveUnitBlock(ui, 1);
|
|
136
|
-
if (ui.nav.
|
|
137
|
-
ui.composer.closeTodoPage();
|
|
138
|
-
if (ui.items.length) ui.nav.index = 0;
|
|
139
|
-
ui.nav.scroll = 0;
|
|
140
|
-
syncReviewPath(ui);
|
|
141
|
-
syncFileCursor(ui);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
171
|
+
if (ui.nav.pane === 'tasks') return void ui.composer.tasks.moveTaskFocus(1);
|
|
144
172
|
moveRemaining(ui, 1);
|
|
145
173
|
};
|
|
146
174
|
|
|
147
175
|
const onPrev = (ui) => {
|
|
148
176
|
if (ui.nav.pane === 'unit') return void moveUnitBlock(ui, -1);
|
|
149
|
-
if (ui.nav.
|
|
150
|
-
if (ui.nav.index <= 0) return void ui.composer.openTodoPage();
|
|
177
|
+
if (ui.nav.pane === 'tasks') return void ui.composer.tasks.moveTaskFocus(-1);
|
|
151
178
|
moveRemaining(ui, -1);
|
|
152
179
|
};
|
|
153
180
|
|
|
@@ -157,7 +184,7 @@ const scrollStep = (ui, fraction) => {
|
|
|
157
184
|
const rows = size.height ?? 24;
|
|
158
185
|
const fallback = Math.max(1, rows - 4);
|
|
159
186
|
const bodyH = frame?.bodyH ?? fallback;
|
|
160
|
-
const viewing = ui.nav.pane === 'npm' && ui.npm
|
|
187
|
+
const viewing = ui.nav.pane === 'npm' && ui.npm.viewing;
|
|
161
188
|
const viewRows = viewing ? logViewRows(bodyH) : bodyH;
|
|
162
189
|
const height = Math.max(1, viewRows);
|
|
163
190
|
const span = Math.floor(height * Math.abs(fraction));
|
|
@@ -167,6 +194,7 @@ const scrollStep = (ui, fraction) => {
|
|
|
167
194
|
};
|
|
168
195
|
|
|
169
196
|
const onScroll = (ui, delta) => {
|
|
197
|
+
if (ui.nav.pane === 'dashboard') return;
|
|
170
198
|
if (ui.nav.pane === 'files') return void onFileMove(ui, delta);
|
|
171
199
|
if (ui.nav.pane === 'branches') {
|
|
172
200
|
return void ui.gitBranches.onBranchMove(delta);
|
|
@@ -175,8 +203,8 @@ const onScroll = (ui, delta) => {
|
|
|
175
203
|
return void ui.commits.onCommitMove(delta);
|
|
176
204
|
}
|
|
177
205
|
if (ui.nav.pane === 'npm') return void ui.npm.move(delta);
|
|
178
|
-
if (ui.nav.
|
|
179
|
-
return void ui.composer.
|
|
206
|
+
if (ui.nav.tasksOpen && ui.composer.tasks.taskRowCount() > 1) {
|
|
207
|
+
return void ui.composer.tasks.moveTaskFocus(delta);
|
|
180
208
|
}
|
|
181
209
|
const frame = ui.lastFrame;
|
|
182
210
|
const max = frame ? frame.scrollMax : null;
|
|
@@ -189,15 +217,16 @@ const onScroll = (ui, delta) => {
|
|
|
189
217
|
};
|
|
190
218
|
|
|
191
219
|
const onJump = (ui, toEnd) => {
|
|
220
|
+
if (ui.nav.pane === 'dashboard') return;
|
|
192
221
|
if (LIST_PANES.includes(ui.nav.pane)) {
|
|
193
222
|
const delta = toEnd ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER;
|
|
194
223
|
return void onScroll(ui, delta);
|
|
195
224
|
}
|
|
196
|
-
if (ui.nav.
|
|
197
|
-
const last = ui.composer.
|
|
225
|
+
if (ui.nav.tasksOpen && ui.composer.tasks.taskRowCount() > 0) {
|
|
226
|
+
const last = ui.composer.tasks.taskRowCount() - 1;
|
|
198
227
|
const target = toEnd ? last : 0;
|
|
199
|
-
const at = ui.composer.
|
|
200
|
-
return void ui.composer.
|
|
228
|
+
const at = ui.composer.tasks.clampedTaskFocus();
|
|
229
|
+
return void ui.composer.tasks.moveTaskFocus(target - at);
|
|
201
230
|
}
|
|
202
231
|
const frame = ui.lastFrame;
|
|
203
232
|
const max = frame ? frame.scrollMax : 0;
|
|
@@ -222,25 +251,28 @@ const onTheme = (ui) => {
|
|
|
222
251
|
ui.status = next;
|
|
223
252
|
};
|
|
224
253
|
|
|
225
|
-
const
|
|
226
|
-
|
|
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
|
+
};
|