reslop 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -1
- package/README.md +27 -38
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +6 -2
- package/lib/api.js +2 -2
- package/lib/capabilities.js +10 -14
- package/lib/cli.js +28 -47
- package/lib/clipboard.js +1 -1
- package/lib/deps-diff.js +712 -0
- package/lib/deps.js +556 -32
- package/lib/detect.js +1 -7
- package/lib/diff/align.js +7 -10
- package/lib/diff/diff.js +53 -0
- package/lib/diff/display.js +5 -4
- package/lib/diff/inline.js +26 -21
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +1 -3
- package/lib/diff/unit.js +392 -0
- package/lib/files.js +34 -8
- package/lib/{git/branches.js → git-branches.js} +103 -10
- package/lib/{git/dependencies.js → git-deps.js} +111 -38
- package/lib/git.js +592 -65
- package/lib/github.js +28 -197
- package/lib/gitlab.js +24 -195
- package/lib/highlight/bash.js +1 -3
- package/lib/highlight/css.js +1 -3
- package/lib/highlight/js.js +11 -14
- package/lib/highlight.js +6 -9
- package/lib/keys.js +22 -9
- package/lib/manifest.js +330 -0
- package/lib/remote.js +374 -0
- package/lib/render/branches.js +34 -66
- package/lib/render/chrome.js +57 -22
- package/lib/render/commits.js +85 -0
- package/lib/render/diff.js +16 -16
- package/lib/render/files.js +29 -37
- package/lib/render/frame.js +29 -13
- package/lib/render/notes.js +4 -3
- package/lib/render/primitives.js +46 -1
- package/lib/{render.js → render/render.js} +6 -7
- package/lib/render/unit.js +41 -0
- package/lib/review.js +750 -14
- package/lib/select.js +5 -10
- package/lib/session/accessors.js +9 -1
- package/lib/session/actions.js +93 -36
- package/lib/session/branches.js +130 -144
- package/lib/session/change-actions.js +206 -124
- package/lib/session/commit.js +217 -62
- package/lib/session/compose.js +158 -13
- package/lib/session/dispatch.js +109 -55
- package/lib/session/files-pane.js +145 -142
- package/lib/session/items.js +131 -34
- package/lib/session/lifecycle.js +82 -42
- package/lib/session/load.js +19 -33
- package/lib/session/navigation.js +15 -3
- package/lib/session/ops.js +28 -41
- package/lib/session/pointer.js +58 -54
- package/lib/session/review.js +23 -37
- package/lib/session/terminal.js +6 -12
- package/lib/session/todos.js +8 -12
- package/lib/session/unit.js +208 -0
- package/lib/session/update.js +33 -46
- package/lib/session/view.js +82 -11
- package/lib/session/watch.js +11 -19
- package/lib/session.js +29 -226
- package/lib/source.js +3 -3
- package/lib/update.js +40 -75
- package/lib/{git/proc.js → utilities.js} +75 -11
- package/lib/wrap.js +1 -3
- package/package.json +2 -2
- package/lib/deps/changes.js +0 -331
- package/lib/deps/items.js +0 -131
- package/lib/deps/manifest.js +0 -145
- package/lib/deps/merge.js +0 -120
- package/lib/deps/proposals.js +0 -164
- package/lib/deps/reports.js +0 -180
- package/lib/deps/rows.js +0 -177
- package/lib/deps/scan.js +0 -138
- package/lib/deps/usage.js +0 -68
- package/lib/deps/versions.js +0 -119
- package/lib/diff.js +0 -33
- package/lib/git/changes.js +0 -164
- package/lib/git/read.js +0 -253
- package/lib/git/run.js +0 -100
- package/lib/npm/commands.js +0 -100
- package/lib/remote/changes.js +0 -37
- package/lib/remote/headers.js +0 -36
- package/lib/remote/http.js +0 -122
- package/lib/remote/notes.js +0 -94
- package/lib/review/format.js +0 -434
- package/lib/review/storage.js +0 -150
- package/lib/review/store.js +0 -178
- package/lib/review/templates.js +0 -49
- package/lib/session/origins.js +0 -7
- package/lib/sys.js +0 -84
package/lib/session/dispatch.js
CHANGED
|
@@ -5,56 +5,88 @@ const { COMPOSE_LEAVE } = compose;
|
|
|
5
5
|
const actions = require('./actions.js');
|
|
6
6
|
const { CONFIRM_MODE, disabledActions, actionFromKey, applyConfirm } = actions;
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const targetHasStaged = (session) => {
|
|
9
|
+
if (session.repo.hasStaged) return session.repo.hasStaged(session.top);
|
|
10
|
+
return session.items.some((item) => item.origin === 'staged');
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const currentTarget = (ui) => {
|
|
14
|
+
if (ui.pane === 'files') return ui.fileCursorEntry();
|
|
15
|
+
if (ui.pane === 'branches') {
|
|
16
|
+
return ui.branches[ui.branchCursor];
|
|
17
|
+
}
|
|
18
|
+
if (ui.pane === 'commits') {
|
|
19
|
+
const entry = ui.commits.commits[ui.commitCursor];
|
|
20
|
+
const staged = targetHasStaged(ui);
|
|
21
|
+
if (!entry) return { canCommit: staged };
|
|
22
|
+
return { ...entry, canCommit: staged };
|
|
23
|
+
}
|
|
24
|
+
return ui.current();
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const createDispatcher = (ui) => {
|
|
9
28
|
const handlers = {
|
|
10
|
-
add:
|
|
11
|
-
unstage:
|
|
12
|
-
revert:
|
|
13
|
-
next:
|
|
14
|
-
prev:
|
|
15
|
-
layout:
|
|
16
|
-
files:
|
|
17
|
-
feedback:
|
|
18
|
-
todo:
|
|
19
|
-
code:
|
|
20
|
-
reload:
|
|
21
|
-
commit:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
add: ui.changeActions.onAdd,
|
|
30
|
+
unstage: ui.changeActions.onUnstage,
|
|
31
|
+
revert: ui.changeActions.onRevert,
|
|
32
|
+
next: ui.filesPane.onNext,
|
|
33
|
+
prev: ui.filesPane.onPrev,
|
|
34
|
+
layout: ui.filesPane.onLayout,
|
|
35
|
+
files: ui.filesPane.onFiles,
|
|
36
|
+
feedback: ui.composer.onFeedback,
|
|
37
|
+
todo: ui.composer.onTodo,
|
|
38
|
+
code: ui.composer.onCode,
|
|
39
|
+
reload: ui.lifecycle.onReload,
|
|
40
|
+
commit: ui.commits.onCommit,
|
|
41
|
+
amend: ui.commits.onAmend,
|
|
42
|
+
fixup: ui.commits.onFixup,
|
|
43
|
+
branch: ui.gitBranches.onBranch,
|
|
44
|
+
pull: ui.gitBranches.onPull,
|
|
45
|
+
push: ui.gitBranches.onPush,
|
|
46
|
+
newBranch: ui.gitBranches.onNewBranch,
|
|
47
|
+
rebase: ui.gitBranches.onRebaseBranch,
|
|
48
|
+
drop: () => {
|
|
49
|
+
if (ui.pane === 'commits') {
|
|
50
|
+
return void ui.commits.onDropCommit();
|
|
51
|
+
}
|
|
52
|
+
ui.gitBranches.onDropBranch();
|
|
53
|
+
},
|
|
54
|
+
open: ui.filesPane.onOpenFile,
|
|
55
|
+
file: ui.filesPane.onFileScope,
|
|
56
|
+
diff: ui.filesPane.onDiffScope,
|
|
57
|
+
removeTodo: ui.composer.removeFocusedTodo,
|
|
58
|
+
quit: () => ui.onQuit(),
|
|
59
|
+
scrollUp: () => ui.filesPane.onScroll(-1),
|
|
60
|
+
scrollDown: () => ui.filesPane.onScroll(1),
|
|
61
|
+
pageUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-1)),
|
|
62
|
+
pageDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(1)),
|
|
63
|
+
halfUp: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(-0.5)),
|
|
64
|
+
halfDown: () => ui.filesPane.onScroll(ui.filesPane.scrollStep(0.5)),
|
|
65
|
+
home: ui.filesPane.onHome,
|
|
66
|
+
end: ui.filesPane.onEnd,
|
|
39
67
|
};
|
|
40
68
|
|
|
41
69
|
const dispatch = (action) => {
|
|
42
|
-
if (CONFIRM_MODE.includes(
|
|
43
|
-
if (
|
|
70
|
+
if (CONFIRM_MODE.includes(ui.mode)) return;
|
|
71
|
+
if (ui.mode === 'compose') {
|
|
44
72
|
if (!COMPOSE_LEAVE.includes(action)) return;
|
|
45
|
-
const result =
|
|
73
|
+
const result = ui.composer.saveCompose();
|
|
46
74
|
if (result && result.kind === 'error') return;
|
|
47
75
|
}
|
|
48
|
-
const pane =
|
|
76
|
+
const pane = ui.pane;
|
|
49
77
|
if (pane === 'files') {
|
|
50
|
-
if (action === 'next') return void
|
|
51
|
-
if (action === 'prev') return void
|
|
78
|
+
if (action === 'next') return void ui.filesPane.onFileMove(1);
|
|
79
|
+
if (action === 'prev') return void ui.filesPane.onFileMove(-1);
|
|
52
80
|
}
|
|
53
81
|
if (pane === 'branches') {
|
|
54
|
-
if (action === 'next') return void
|
|
55
|
-
if (action === 'prev') return void
|
|
82
|
+
if (action === 'next') return void ui.gitBranches.onBranchMove(1);
|
|
83
|
+
if (action === 'prev') return void ui.gitBranches.onBranchMove(-1);
|
|
84
|
+
}
|
|
85
|
+
if (pane === 'commits') {
|
|
86
|
+
if (action === 'next') return void ui.commits.onCommitMove(1);
|
|
87
|
+
if (action === 'prev') return void ui.commits.onCommitMove(-1);
|
|
56
88
|
}
|
|
57
|
-
const hidden = disabledActions(pane,
|
|
89
|
+
const hidden = disabledActions(pane, currentTarget(ui));
|
|
58
90
|
if (hidden.includes(action)) return;
|
|
59
91
|
const handler = handlers[action];
|
|
60
92
|
if (!handler) return;
|
|
@@ -64,39 +96,61 @@ const createDispatcher = (options) => {
|
|
|
64
96
|
return { dispatch, handlers };
|
|
65
97
|
};
|
|
66
98
|
|
|
67
|
-
const createInput = (
|
|
99
|
+
const createInput = (ui) => {
|
|
68
100
|
const confirmations = {
|
|
69
|
-
confirmQuit:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
101
|
+
confirmQuit: {
|
|
102
|
+
ready: () => ui.finishQuit('ready'),
|
|
103
|
+
editing: () => ui.finishQuit('editing'),
|
|
104
|
+
cancel: () => ui.cancelQuit(),
|
|
105
|
+
},
|
|
106
|
+
confirmUpdate: {
|
|
107
|
+
accept: ui.updater.accept,
|
|
108
|
+
decline: ui.updater.decline,
|
|
109
|
+
},
|
|
110
|
+
confirmDrop: {
|
|
111
|
+
confirm: () => {
|
|
112
|
+
if (ui.commits.dropName) {
|
|
113
|
+
return void ui.commits.confirmDropCommit();
|
|
114
|
+
}
|
|
115
|
+
ui.gitBranches.confirmDropBranch();
|
|
116
|
+
},
|
|
117
|
+
cancel: () => {
|
|
118
|
+
if (ui.commits.dropName) {
|
|
119
|
+
return void ui.commits.cancelDropCommit();
|
|
120
|
+
}
|
|
121
|
+
ui.gitBranches.cancelDropBranch();
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
confirmPush: {
|
|
125
|
+
force: ui.gitBranches.onForcePush,
|
|
126
|
+
cancel: ui.gitBranches.cancelPush,
|
|
127
|
+
},
|
|
74
128
|
};
|
|
75
129
|
|
|
76
130
|
const confirmChoice = (key) => {
|
|
77
|
-
const mode =
|
|
131
|
+
const mode = ui.mode;
|
|
78
132
|
if (!CONFIRM_MODE.includes(mode)) return;
|
|
79
133
|
applyConfirm(mode, key, confirmations[mode]);
|
|
80
134
|
};
|
|
81
135
|
|
|
82
136
|
const handleKey = (key) => {
|
|
83
|
-
const mode =
|
|
137
|
+
const mode = ui.mode;
|
|
84
138
|
if (CONFIRM_MODE.includes(mode)) return void confirmChoice(key);
|
|
85
139
|
if (mode === 'compose') {
|
|
86
|
-
if (key === 'ctrl-c') return void
|
|
87
|
-
const command =
|
|
88
|
-
return void
|
|
140
|
+
if (key === 'ctrl-c') return void ui.onQuit();
|
|
141
|
+
const command = ui.composer.handleKey(key);
|
|
142
|
+
return void ui.runComposeCommand(command);
|
|
89
143
|
}
|
|
90
|
-
if (key === 'escape') return void
|
|
91
|
-
if (
|
|
92
|
-
const action = actionFromKey(key,
|
|
93
|
-
if (action)
|
|
144
|
+
if (key === 'escape') return void ui.filesPane.onEscape();
|
|
145
|
+
if (ui.composer.typeIntoTodo(key)) return;
|
|
146
|
+
const action = actionFromKey(key, ui.pane, ui.fileScope);
|
|
147
|
+
if (action) ui.dispatch(action);
|
|
94
148
|
};
|
|
95
149
|
|
|
96
150
|
const handleEvent = (event) => {
|
|
97
151
|
if (event.type === 'key') return void handleKey(event.key);
|
|
98
152
|
if (event.type !== 'mouse') return;
|
|
99
|
-
|
|
153
|
+
ui.pointer.handle(event);
|
|
100
154
|
};
|
|
101
155
|
|
|
102
156
|
return { handleEvent, confirmChoice };
|
|
@@ -2,146 +2,147 @@
|
|
|
2
2
|
|
|
3
3
|
const files = require('../files.js');
|
|
4
4
|
const { isTodosEntry, TODO_FILE } = files;
|
|
5
|
+
const unit = require('./unit.js');
|
|
6
|
+
const { setFileScope, openUnitFile, moveUnitBlock } = unit;
|
|
5
7
|
|
|
6
8
|
const LAYOUTS = ['unified', 'mixed', 'side'];
|
|
7
9
|
|
|
8
|
-
const current = (
|
|
9
|
-
options.nav.current(options.items(), options.todoItem());
|
|
10
|
+
const current = (ui) => ui.nav.current(ui.items, ui.todoItem);
|
|
10
11
|
|
|
11
|
-
const clampIndex = (
|
|
12
|
+
const clampIndex = (ui) => ui.nav.clampIndex(ui.items.length);
|
|
12
13
|
|
|
13
|
-
const syncReviewPath = (
|
|
14
|
-
options.nav.syncReviewPath(current(options));
|
|
14
|
+
const syncReviewPath = (ui) => ui.nav.syncReviewPath(current(ui));
|
|
15
15
|
|
|
16
|
-
const clampFileCursor = (
|
|
17
|
-
options.nav.clampFileCursor(options.fileList().length);
|
|
16
|
+
const clampFileCursor = (ui) => ui.nav.clampFileCursor(ui.fileList().length);
|
|
18
17
|
|
|
19
|
-
const followReviewPath = (
|
|
20
|
-
|
|
18
|
+
const followReviewPath = (ui) =>
|
|
19
|
+
ui.nav.followReviewPath(ui.fileList(), current(ui));
|
|
21
20
|
|
|
22
|
-
const syncFileCursor = (
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
followReviewPath(options);
|
|
21
|
+
const syncFileCursor = (ui) => {
|
|
22
|
+
if (ui.nav.pane === 'files') return void clampFileCursor(ui);
|
|
23
|
+
followReviewPath(ui);
|
|
28
24
|
};
|
|
29
25
|
|
|
30
|
-
const showFiles = (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
followReviewPath(
|
|
34
|
-
|
|
26
|
+
const showFiles = (ui) => {
|
|
27
|
+
ui.nav.pane = 'files';
|
|
28
|
+
ui.nav.clearSelection();
|
|
29
|
+
followReviewPath(ui);
|
|
30
|
+
ui.nav.todoOpen = false;
|
|
35
31
|
};
|
|
36
32
|
|
|
37
|
-
const onEscape = (
|
|
38
|
-
if (
|
|
39
|
-
showFiles(
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (options.nav.pane === 'files') {
|
|
43
|
-
options.onQuit();
|
|
44
|
-
return;
|
|
33
|
+
const onEscape = (ui) => {
|
|
34
|
+
if (ui.nav.pane === 'branches' || ui.nav.pane === 'commits') {
|
|
35
|
+
return void showFiles(ui);
|
|
45
36
|
}
|
|
46
|
-
|
|
37
|
+
if (ui.nav.pane === 'files') return void ui.onQuit();
|
|
38
|
+
showFiles(ui);
|
|
47
39
|
};
|
|
48
40
|
|
|
49
|
-
const onFiles = (
|
|
50
|
-
if (
|
|
51
|
-
if (!
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
const onFiles = (ui) => {
|
|
42
|
+
if (ui.nav.pane === 'files') {
|
|
43
|
+
if (!ui.nav.reviewPath) return;
|
|
44
|
+
if (ui.nav.fileScope === 'file') {
|
|
45
|
+
const list = ui.fileList();
|
|
46
|
+
const entry = list[ui.nav.fileCursor];
|
|
47
|
+
if (entry && !isTodosEntry(entry)) openUnitFile(ui, entry);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
ui.nav.pane = 'diff';
|
|
51
|
+
ui.nav.clearSelection();
|
|
52
|
+
if (ui.nav.reviewPath === TODO_FILE) ui.composer.openTodoPage();
|
|
55
53
|
return;
|
|
56
54
|
}
|
|
57
|
-
showFiles(
|
|
55
|
+
showFiles(ui);
|
|
58
56
|
};
|
|
59
57
|
|
|
60
|
-
const onOpenFile = (
|
|
61
|
-
if (
|
|
62
|
-
return void
|
|
58
|
+
const onOpenFile = (ui) => {
|
|
59
|
+
if (ui.nav.pane === 'branches') {
|
|
60
|
+
return void ui.gitBranches.onCheckoutBranch();
|
|
63
61
|
}
|
|
64
|
-
if (
|
|
65
|
-
|
|
62
|
+
if (ui.nav.pane === 'commits') return;
|
|
63
|
+
if (ui.nav.pane !== 'files') {
|
|
64
|
+
if (ui.nav.todoOpen) ui.composer.editFocusedTodo();
|
|
66
65
|
return;
|
|
67
66
|
}
|
|
68
|
-
const list =
|
|
69
|
-
const entry = list[
|
|
67
|
+
const list = ui.fileList();
|
|
68
|
+
const entry = list[ui.nav.fileCursor];
|
|
70
69
|
if (!entry) return;
|
|
71
70
|
if (isTodosEntry(entry)) {
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
ui.composer.openTodoPage();
|
|
72
|
+
ui.status = '';
|
|
74
73
|
return;
|
|
75
74
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
ui.nav.todoOpen = false;
|
|
76
|
+
ui.nav.index = entry.openIndex ?? entry.firstIndex;
|
|
77
|
+
if (ui.nav.fileScope === 'file') {
|
|
78
|
+
return void openUnitFile(ui, entry);
|
|
79
|
+
}
|
|
80
|
+
ui.nav.pane = 'diff';
|
|
81
|
+
ui.nav.scroll = 0;
|
|
82
|
+
ui.status = '';
|
|
83
|
+
ui.nav.clearSelection();
|
|
84
|
+
syncReviewPath(ui);
|
|
83
85
|
};
|
|
84
86
|
|
|
85
|
-
const onFileMove = (
|
|
86
|
-
const list =
|
|
87
|
+
const onFileMove = (ui, delta) => {
|
|
88
|
+
const list = ui.fileList();
|
|
87
89
|
if (!list.length) {
|
|
88
|
-
|
|
90
|
+
ui.status = 'nothing to review';
|
|
89
91
|
return;
|
|
90
92
|
}
|
|
91
93
|
const last = list.length - 1;
|
|
92
|
-
const moved =
|
|
94
|
+
const moved = ui.nav.fileCursor + delta;
|
|
93
95
|
const next = Math.min(last, Math.max(0, moved));
|
|
94
|
-
if (next ===
|
|
95
|
-
|
|
96
|
+
if (next === ui.nav.fileCursor) return;
|
|
97
|
+
ui.nav.fileCursor = next;
|
|
96
98
|
const entry = list[next];
|
|
97
99
|
if (isTodosEntry(entry)) {
|
|
98
|
-
|
|
100
|
+
ui.nav.reviewPath = TODO_FILE;
|
|
99
101
|
} else {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
ui.nav.reviewPath = entry.path;
|
|
103
|
+
ui.nav.index = entry.firstIndex;
|
|
102
104
|
}
|
|
103
|
-
|
|
105
|
+
ui.status = '';
|
|
104
106
|
};
|
|
105
107
|
|
|
106
|
-
const moveRemaining = (
|
|
107
|
-
const list =
|
|
108
|
+
const moveRemaining = (ui, step) => {
|
|
109
|
+
const list = ui.items;
|
|
108
110
|
if (!list.length) {
|
|
109
|
-
|
|
111
|
+
ui.status = 'nothing to review';
|
|
110
112
|
return;
|
|
111
113
|
}
|
|
112
|
-
const next =
|
|
114
|
+
const next = ui.nav.index + step;
|
|
113
115
|
if (next < 0 || next >= list.length) return;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
syncReviewPath(
|
|
116
|
+
ui.nav.index = next;
|
|
117
|
+
ui.nav.scroll = 0;
|
|
118
|
+
ui.status = '';
|
|
119
|
+
ui.nav.clearSelection();
|
|
120
|
+
syncReviewPath(ui);
|
|
119
121
|
};
|
|
120
122
|
|
|
121
|
-
const onNext = (
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
const onNext = (ui) => {
|
|
124
|
+
if (ui.nav.pane === 'unit') return void moveUnitBlock(ui, 1);
|
|
125
|
+
if (ui.nav.todoOpen) {
|
|
126
|
+
ui.composer.closeTodoPage();
|
|
127
|
+
if (ui.items.length) ui.nav.index = 0;
|
|
128
|
+
ui.nav.scroll = 0;
|
|
129
|
+
syncReviewPath(ui);
|
|
130
|
+
syncFileCursor(ui);
|
|
128
131
|
return;
|
|
129
132
|
}
|
|
130
|
-
moveRemaining(
|
|
133
|
+
moveRemaining(ui, 1);
|
|
131
134
|
};
|
|
132
135
|
|
|
133
|
-
const onPrev = (
|
|
134
|
-
if (
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
moveRemaining(options, -1);
|
|
136
|
+
const onPrev = (ui) => {
|
|
137
|
+
if (ui.nav.pane === 'unit') return void moveUnitBlock(ui, -1);
|
|
138
|
+
if (ui.nav.todoOpen) return;
|
|
139
|
+
if (ui.nav.index <= 0) return void ui.composer.openTodoPage();
|
|
140
|
+
moveRemaining(ui, -1);
|
|
140
141
|
};
|
|
141
142
|
|
|
142
|
-
const scrollStep = (
|
|
143
|
-
const frame =
|
|
144
|
-
const size =
|
|
143
|
+
const scrollStep = (ui, fraction) => {
|
|
144
|
+
const frame = ui.lastFrame;
|
|
145
|
+
const size = ui.lastSize ?? ui.getSize();
|
|
145
146
|
const rows = size.height ?? 24;
|
|
146
147
|
const fallback = Math.max(1, rows - 4);
|
|
147
148
|
const bodyH = frame?.bodyH ?? fallback;
|
|
@@ -152,83 +153,85 @@ const scrollStep = (options, fraction) => {
|
|
|
152
153
|
return n;
|
|
153
154
|
};
|
|
154
155
|
|
|
155
|
-
const onScroll = (
|
|
156
|
-
if (
|
|
157
|
-
if (
|
|
158
|
-
return void
|
|
156
|
+
const onScroll = (ui, delta) => {
|
|
157
|
+
if (ui.nav.pane === 'files') return void onFileMove(ui, delta);
|
|
158
|
+
if (ui.nav.pane === 'branches') {
|
|
159
|
+
return void ui.gitBranches.onBranchMove(delta);
|
|
159
160
|
}
|
|
160
|
-
if (
|
|
161
|
-
return void
|
|
161
|
+
if (ui.nav.pane === 'commits') {
|
|
162
|
+
return void ui.commits.onCommitMove(delta);
|
|
162
163
|
}
|
|
163
|
-
|
|
164
|
+
if (ui.nav.todoOpen && ui.composer.todoRowCount() > 1) {
|
|
165
|
+
return void ui.composer.moveTodoFocus(delta);
|
|
166
|
+
}
|
|
167
|
+
const frame = ui.lastFrame;
|
|
164
168
|
const max = frame ? frame.scrollMax : null;
|
|
165
|
-
const scroll =
|
|
169
|
+
const scroll = ui.nav.scroll;
|
|
166
170
|
const current = max === null ? scroll : Math.min(scroll, max);
|
|
167
171
|
const moved = current + delta;
|
|
168
172
|
const next = max === null ? moved : Math.min(max, moved);
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
ui.nav.scroll = Math.max(0, next);
|
|
174
|
+
ui.nav.clearSelection();
|
|
171
175
|
};
|
|
172
176
|
|
|
173
|
-
const onJump = (
|
|
174
|
-
if (
|
|
175
|
-
const list =
|
|
177
|
+
const onJump = (ui, toEnd) => {
|
|
178
|
+
if (ui.nav.pane === 'files') {
|
|
179
|
+
const list = ui.fileList();
|
|
176
180
|
if (!list.length) {
|
|
177
|
-
|
|
181
|
+
ui.status = 'nothing to review';
|
|
178
182
|
return;
|
|
179
183
|
}
|
|
180
184
|
const target = toEnd ? list.length - 1 : 0;
|
|
181
|
-
onFileMove(
|
|
182
|
-
return;
|
|
185
|
+
return void onFileMove(ui, target - ui.nav.fileCursor);
|
|
183
186
|
}
|
|
184
|
-
if (
|
|
187
|
+
if (ui.nav.pane === 'branches') {
|
|
185
188
|
const delta = toEnd ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER;
|
|
186
|
-
|
|
187
|
-
|
|
189
|
+
return void ui.gitBranches.onBranchMove(delta);
|
|
190
|
+
}
|
|
191
|
+
if (ui.nav.pane === 'commits') {
|
|
192
|
+
const delta = toEnd ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER;
|
|
193
|
+
return void ui.commits.onCommitMove(delta);
|
|
188
194
|
}
|
|
189
|
-
if (
|
|
190
|
-
const last =
|
|
195
|
+
if (ui.nav.todoOpen && ui.composer.todoRowCount() > 0) {
|
|
196
|
+
const last = ui.composer.todoRowCount() - 1;
|
|
191
197
|
const target = toEnd ? last : 0;
|
|
192
|
-
const at =
|
|
193
|
-
|
|
194
|
-
return;
|
|
198
|
+
const at = ui.composer.clampedTodoFocus();
|
|
199
|
+
return void ui.composer.moveTodoFocus(target - at);
|
|
195
200
|
}
|
|
196
|
-
const frame =
|
|
201
|
+
const frame = ui.lastFrame;
|
|
197
202
|
const max = frame ? frame.scrollMax : 0;
|
|
198
|
-
|
|
199
|
-
|
|
203
|
+
ui.nav.scroll = toEnd ? max : 0;
|
|
204
|
+
ui.nav.clearSelection();
|
|
200
205
|
};
|
|
201
206
|
|
|
202
|
-
const onLayout = (
|
|
203
|
-
const i = LAYOUTS.indexOf(
|
|
207
|
+
const onLayout = (ui) => {
|
|
208
|
+
const i = LAYOUTS.indexOf(ui.layout);
|
|
204
209
|
const next = (i < 0 ? 0 : i + 1) % LAYOUTS.length;
|
|
205
|
-
|
|
210
|
+
ui.layout = LAYOUTS[next];
|
|
206
211
|
const name = LAYOUTS[next] === 'side' ? 'side-by-side' : LAYOUTS[next];
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
212
|
+
ui.status = name;
|
|
213
|
+
ui.nav.scroll = 0;
|
|
214
|
+
ui.nav.clearSelection();
|
|
210
215
|
};
|
|
211
216
|
|
|
212
|
-
const createFilesPane = (
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
onEnd: () => onJump(options, true),
|
|
231
|
-
onLayout: () => onLayout(options),
|
|
217
|
+
const createFilesPane = (ui) => ({
|
|
218
|
+
clampIndex: () => clampIndex(ui),
|
|
219
|
+
syncReviewPath: () => syncReviewPath(ui),
|
|
220
|
+
syncFileCursor: () => syncFileCursor(ui),
|
|
221
|
+
showFiles: () => showFiles(ui),
|
|
222
|
+
onEscape: () => onEscape(ui),
|
|
223
|
+
onFiles: () => onFiles(ui),
|
|
224
|
+
onOpenFile: () => onOpenFile(ui),
|
|
225
|
+
onFileMove: (delta) => onFileMove(ui, delta),
|
|
226
|
+
onNext: () => onNext(ui),
|
|
227
|
+
onPrev: () => onPrev(ui),
|
|
228
|
+
scrollStep: (fraction) => scrollStep(ui, fraction),
|
|
229
|
+
onScroll: (delta) => onScroll(ui, delta),
|
|
230
|
+
onHome: () => onJump(ui, false),
|
|
231
|
+
onEnd: () => onJump(ui, true),
|
|
232
|
+
onLayout: () => onLayout(ui),
|
|
233
|
+
onFileScope: () => setFileScope(ui, 'file'),
|
|
234
|
+
onDiffScope: () => setFileScope(ui, 'diff'),
|
|
232
235
|
});
|
|
233
236
|
|
|
234
237
|
module.exports = { LAYOUTS, createFilesPane };
|