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.
Files changed (95) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +27 -38
  3. package/bin/reslop.js +2 -2
  4. package/lib/ansi.js +6 -2
  5. package/lib/api.js +2 -2
  6. package/lib/capabilities.js +10 -14
  7. package/lib/cli.js +28 -47
  8. package/lib/clipboard.js +1 -1
  9. package/lib/deps-diff.js +712 -0
  10. package/lib/deps.js +556 -32
  11. package/lib/detect.js +1 -7
  12. package/lib/diff/align.js +7 -10
  13. package/lib/diff/diff.js +53 -0
  14. package/lib/diff/display.js +5 -4
  15. package/lib/diff/inline.js +26 -21
  16. package/lib/diff/items.js +6 -4
  17. package/lib/diff/patch.js +1 -3
  18. package/lib/diff/unit.js +392 -0
  19. package/lib/files.js +34 -8
  20. package/lib/{git/branches.js → git-branches.js} +103 -10
  21. package/lib/{git/dependencies.js → git-deps.js} +111 -38
  22. package/lib/git.js +592 -65
  23. package/lib/github.js +28 -197
  24. package/lib/gitlab.js +24 -195
  25. package/lib/highlight/bash.js +1 -3
  26. package/lib/highlight/css.js +1 -3
  27. package/lib/highlight/js.js +11 -14
  28. package/lib/highlight.js +6 -9
  29. package/lib/keys.js +22 -9
  30. package/lib/manifest.js +330 -0
  31. package/lib/remote.js +374 -0
  32. package/lib/render/branches.js +34 -66
  33. package/lib/render/chrome.js +57 -22
  34. package/lib/render/commits.js +85 -0
  35. package/lib/render/diff.js +16 -16
  36. package/lib/render/files.js +29 -37
  37. package/lib/render/frame.js +29 -13
  38. package/lib/render/notes.js +4 -3
  39. package/lib/render/primitives.js +46 -1
  40. package/lib/{render.js → render/render.js} +6 -7
  41. package/lib/render/unit.js +41 -0
  42. package/lib/review.js +750 -14
  43. package/lib/select.js +5 -10
  44. package/lib/session/accessors.js +9 -1
  45. package/lib/session/actions.js +93 -36
  46. package/lib/session/branches.js +130 -144
  47. package/lib/session/change-actions.js +206 -124
  48. package/lib/session/commit.js +217 -62
  49. package/lib/session/compose.js +158 -13
  50. package/lib/session/dispatch.js +109 -55
  51. package/lib/session/files-pane.js +145 -142
  52. package/lib/session/items.js +131 -34
  53. package/lib/session/lifecycle.js +82 -42
  54. package/lib/session/load.js +19 -33
  55. package/lib/session/navigation.js +15 -3
  56. package/lib/session/ops.js +28 -41
  57. package/lib/session/pointer.js +58 -54
  58. package/lib/session/review.js +23 -37
  59. package/lib/session/terminal.js +6 -12
  60. package/lib/session/todos.js +8 -12
  61. package/lib/session/unit.js +208 -0
  62. package/lib/session/update.js +33 -46
  63. package/lib/session/view.js +82 -11
  64. package/lib/session/watch.js +11 -19
  65. package/lib/session.js +29 -226
  66. package/lib/source.js +3 -3
  67. package/lib/update.js +40 -75
  68. package/lib/{git/proc.js → utilities.js} +75 -11
  69. package/lib/wrap.js +1 -3
  70. package/package.json +2 -2
  71. package/lib/deps/changes.js +0 -331
  72. package/lib/deps/items.js +0 -131
  73. package/lib/deps/manifest.js +0 -145
  74. package/lib/deps/merge.js +0 -120
  75. package/lib/deps/proposals.js +0 -164
  76. package/lib/deps/reports.js +0 -180
  77. package/lib/deps/rows.js +0 -177
  78. package/lib/deps/scan.js +0 -138
  79. package/lib/deps/usage.js +0 -68
  80. package/lib/deps/versions.js +0 -119
  81. package/lib/diff.js +0 -33
  82. package/lib/git/changes.js +0 -164
  83. package/lib/git/read.js +0 -253
  84. package/lib/git/run.js +0 -100
  85. package/lib/npm/commands.js +0 -100
  86. package/lib/remote/changes.js +0 -37
  87. package/lib/remote/headers.js +0 -36
  88. package/lib/remote/http.js +0 -122
  89. package/lib/remote/notes.js +0 -94
  90. package/lib/review/format.js +0 -434
  91. package/lib/review/storage.js +0 -150
  92. package/lib/review/store.js +0 -178
  93. package/lib/review/templates.js +0 -49
  94. package/lib/session/origins.js +0 -7
  95. package/lib/sys.js +0 -84
@@ -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 createDispatcher = (options) => {
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: options.changeActions.onAdd,
11
- unstage: options.changeActions.onUnstage,
12
- revert: options.changeActions.onRevert,
13
- next: options.onNext,
14
- prev: options.onPrev,
15
- layout: options.onLayout,
16
- files: options.onFiles,
17
- feedback: options.composer.onFeedback,
18
- todo: options.composer.onTodo,
19
- code: options.composer.onCode,
20
- reload: options.onReload,
21
- commit: options.commits.onCommit,
22
- branch: options.gitBranches.onBranch,
23
- pull: options.gitBranches.onPull,
24
- push: options.gitBranches.onPush,
25
- newBranch: options.gitBranches.onNewBranch,
26
- rebase: options.gitBranches.onRebaseBranch,
27
- drop: options.gitBranches.onDropBranch,
28
- open: options.onOpenFile,
29
- removeTodo: options.composer.removeFocusedTodo,
30
- quit: options.onQuit,
31
- scrollUp: () => options.onScroll(-1),
32
- scrollDown: () => options.onScroll(1),
33
- pageUp: () => options.onScroll(options.scrollStep(-1)),
34
- pageDown: () => options.onScroll(options.scrollStep(1)),
35
- halfUp: () => options.onScroll(options.scrollStep(-0.5)),
36
- halfDown: () => options.onScroll(options.scrollStep(0.5)),
37
- home: options.onHome,
38
- end: options.onEnd,
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(options.getMode())) return;
43
- if (options.getMode() === 'compose') {
70
+ if (CONFIRM_MODE.includes(ui.mode)) return;
71
+ if (ui.mode === 'compose') {
44
72
  if (!COMPOSE_LEAVE.includes(action)) return;
45
- const result = options.composer.saveCompose();
73
+ const result = ui.composer.saveCompose();
46
74
  if (result && result.kind === 'error') return;
47
75
  }
48
- const pane = options.getPane();
76
+ const pane = ui.pane;
49
77
  if (pane === 'files') {
50
- if (action === 'next') return void options.onFileMove(1);
51
- if (action === 'prev') return void options.onFileMove(-1);
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 options.onBranchMove(1);
55
- if (action === 'prev') return void options.onBranchMove(-1);
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, options.currentTarget());
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 = (options) => {
99
+ const createInput = (ui) => {
68
100
  const confirmations = {
69
- confirmQuit: options.quit,
70
- confirmCommit: options.commit,
71
- confirmUpdate: options.update,
72
- confirmDrop: options.drop,
73
- confirmPush: options.push,
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 = options.getMode();
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 = options.getMode();
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 options.onQuit();
87
- const command = options.composer.handleKey(key);
88
- return void options.runComposeCommand(command);
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 options.onEscape();
91
- if (options.composer.typeIntoTodo(key)) return;
92
- const action = actionFromKey(key, options.getPane());
93
- if (action) options.dispatch(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
- options.pointer.handle(event);
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 = (options) =>
9
- options.nav.current(options.items(), options.todoItem());
10
+ const current = (ui) => ui.nav.current(ui.items, ui.todoItem);
10
11
 
11
- const clampIndex = (options) => options.nav.clampIndex(options.items().length);
12
+ const clampIndex = (ui) => ui.nav.clampIndex(ui.items.length);
12
13
 
13
- const syncReviewPath = (options) =>
14
- options.nav.syncReviewPath(current(options));
14
+ const syncReviewPath = (ui) => ui.nav.syncReviewPath(current(ui));
15
15
 
16
- const clampFileCursor = (options) =>
17
- options.nav.clampFileCursor(options.fileList().length);
16
+ const clampFileCursor = (ui) => ui.nav.clampFileCursor(ui.fileList().length);
18
17
 
19
- const followReviewPath = (options) =>
20
- options.nav.followReviewPath(options.fileList(), current(options));
18
+ const followReviewPath = (ui) =>
19
+ ui.nav.followReviewPath(ui.fileList(), current(ui));
21
20
 
22
- const syncFileCursor = (options) => {
23
- if (options.nav.pane === 'files') {
24
- clampFileCursor(options);
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 = (options) => {
31
- options.nav.pane = 'files';
32
- options.nav.clearSelection();
33
- followReviewPath(options);
34
- options.nav.todoOpen = false;
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 = (options) => {
38
- if (options.nav.pane === 'branches') {
39
- showFiles(options);
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
- showFiles(options);
37
+ if (ui.nav.pane === 'files') return void ui.onQuit();
38
+ showFiles(ui);
47
39
  };
48
40
 
49
- const onFiles = (options) => {
50
- if (options.nav.pane === 'files') {
51
- if (!options.nav.reviewPath) return;
52
- options.nav.pane = 'diff';
53
- options.nav.clearSelection();
54
- if (options.nav.reviewPath === TODO_FILE) options.composer.openTodoPage();
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(options);
55
+ showFiles(ui);
58
56
  };
59
57
 
60
- const onOpenFile = (options) => {
61
- if (options.nav.pane === 'branches') {
62
- return void options.onCheckoutBranch();
58
+ const onOpenFile = (ui) => {
59
+ if (ui.nav.pane === 'branches') {
60
+ return void ui.gitBranches.onCheckoutBranch();
63
61
  }
64
- if (options.nav.pane !== 'files') {
65
- if (options.nav.todoOpen) options.composer.editFocusedTodo();
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 = options.fileList();
69
- const entry = list[options.nav.fileCursor];
67
+ const list = ui.fileList();
68
+ const entry = list[ui.nav.fileCursor];
70
69
  if (!entry) return;
71
70
  if (isTodosEntry(entry)) {
72
- options.composer.openTodoPage();
73
- options.setStatus('');
71
+ ui.composer.openTodoPage();
72
+ ui.status = '';
74
73
  return;
75
74
  }
76
- options.nav.todoOpen = false;
77
- options.nav.index = entry.openIndex ?? entry.firstIndex;
78
- options.nav.pane = 'diff';
79
- options.nav.scroll = 0;
80
- options.setStatus('');
81
- options.nav.clearSelection();
82
- syncReviewPath(options);
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 = (options, delta) => {
86
- const list = options.fileList();
87
+ const onFileMove = (ui, delta) => {
88
+ const list = ui.fileList();
87
89
  if (!list.length) {
88
- options.setStatus('nothing to review');
90
+ ui.status = 'nothing to review';
89
91
  return;
90
92
  }
91
93
  const last = list.length - 1;
92
- const moved = options.nav.fileCursor + delta;
94
+ const moved = ui.nav.fileCursor + delta;
93
95
  const next = Math.min(last, Math.max(0, moved));
94
- if (next === options.nav.fileCursor) return;
95
- options.nav.fileCursor = next;
96
+ if (next === ui.nav.fileCursor) return;
97
+ ui.nav.fileCursor = next;
96
98
  const entry = list[next];
97
99
  if (isTodosEntry(entry)) {
98
- options.nav.reviewPath = TODO_FILE;
100
+ ui.nav.reviewPath = TODO_FILE;
99
101
  } else {
100
- options.nav.reviewPath = entry.path;
101
- options.nav.index = entry.firstIndex;
102
+ ui.nav.reviewPath = entry.path;
103
+ ui.nav.index = entry.firstIndex;
102
104
  }
103
- options.setStatus('');
105
+ ui.status = '';
104
106
  };
105
107
 
106
- const moveRemaining = (options, step) => {
107
- const list = options.items();
108
+ const moveRemaining = (ui, step) => {
109
+ const list = ui.items;
108
110
  if (!list.length) {
109
- options.setStatus('nothing to review');
111
+ ui.status = 'nothing to review';
110
112
  return;
111
113
  }
112
- const next = options.nav.index + step;
114
+ const next = ui.nav.index + step;
113
115
  if (next < 0 || next >= list.length) return;
114
- options.nav.index = next;
115
- options.nav.scroll = 0;
116
- options.setStatus('');
117
- options.nav.clearSelection();
118
- syncReviewPath(options);
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 = (options) => {
122
- if (options.nav.todoOpen) {
123
- options.composer.closeTodoPage();
124
- if (options.items().length) options.nav.index = 0;
125
- options.nav.scroll = 0;
126
- syncReviewPath(options);
127
- syncFileCursor(options);
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(options, 1);
133
+ moveRemaining(ui, 1);
131
134
  };
132
135
 
133
- const onPrev = (options) => {
134
- if (options.nav.todoOpen) return;
135
- if (options.nav.index <= 0) {
136
- options.composer.openTodoPage();
137
- return;
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 = (options, fraction) => {
143
- const frame = options.lastFrame();
144
- const size = options.getSize();
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 = (options, delta) => {
156
- if (options.nav.pane === 'files') return void onFileMove(options, delta);
157
- if (options.nav.pane === 'branches') {
158
- return void options.onBranchMove(delta);
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 (options.nav.todoOpen && options.composer.todoRowCount() > 1) {
161
- return void options.composer.moveTodoFocus(delta);
161
+ if (ui.nav.pane === 'commits') {
162
+ return void ui.commits.onCommitMove(delta);
162
163
  }
163
- const frame = options.lastFrame();
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 = options.nav.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
- options.nav.scroll = Math.max(0, next);
170
- options.nav.clearSelection();
173
+ ui.nav.scroll = Math.max(0, next);
174
+ ui.nav.clearSelection();
171
175
  };
172
176
 
173
- const onJump = (options, toEnd) => {
174
- if (options.nav.pane === 'files') {
175
- const list = options.fileList();
177
+ const onJump = (ui, toEnd) => {
178
+ if (ui.nav.pane === 'files') {
179
+ const list = ui.fileList();
176
180
  if (!list.length) {
177
- options.setStatus('nothing to review');
181
+ ui.status = 'nothing to review';
178
182
  return;
179
183
  }
180
184
  const target = toEnd ? list.length - 1 : 0;
181
- onFileMove(options, target - options.nav.fileCursor);
182
- return;
185
+ return void onFileMove(ui, target - ui.nav.fileCursor);
183
186
  }
184
- if (options.nav.pane === 'branches') {
187
+ if (ui.nav.pane === 'branches') {
185
188
  const delta = toEnd ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER;
186
- options.onBranchMove(delta);
187
- return;
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 (options.nav.todoOpen && options.composer.todoRowCount() > 0) {
190
- const last = options.composer.todoRowCount() - 1;
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 = options.composer.clampedTodoFocus();
193
- options.composer.moveTodoFocus(target - at);
194
- return;
198
+ const at = ui.composer.clampedTodoFocus();
199
+ return void ui.composer.moveTodoFocus(target - at);
195
200
  }
196
- const frame = options.lastFrame();
201
+ const frame = ui.lastFrame;
197
202
  const max = frame ? frame.scrollMax : 0;
198
- options.nav.scroll = toEnd ? max : 0;
199
- options.nav.clearSelection();
203
+ ui.nav.scroll = toEnd ? max : 0;
204
+ ui.nav.clearSelection();
200
205
  };
201
206
 
202
- const onLayout = (options) => {
203
- const i = LAYOUTS.indexOf(options.layout());
207
+ const onLayout = (ui) => {
208
+ const i = LAYOUTS.indexOf(ui.layout);
204
209
  const next = (i < 0 ? 0 : i + 1) % LAYOUTS.length;
205
- options.setLayout(LAYOUTS[next]);
210
+ ui.layout = LAYOUTS[next];
206
211
  const name = LAYOUTS[next] === 'side' ? 'side-by-side' : LAYOUTS[next];
207
- options.setStatus(name);
208
- options.nav.scroll = 0;
209
- options.nav.clearSelection();
212
+ ui.status = name;
213
+ ui.nav.scroll = 0;
214
+ ui.nav.clearSelection();
210
215
  };
211
216
 
212
- const createFilesPane = (options) => ({
213
- current: () => current(options),
214
- clampIndex: () => clampIndex(options),
215
- syncReviewPath: () => syncReviewPath(options),
216
- clampFileCursor: () => clampFileCursor(options),
217
- followReviewPath: () => followReviewPath(options),
218
- syncFileCursor: () => syncFileCursor(options),
219
- showFiles: () => showFiles(options),
220
- onEscape: () => onEscape(options),
221
- onFiles: () => onFiles(options),
222
- onOpenFile: () => onOpenFile(options),
223
- onFileMove: (delta) => onFileMove(options, delta),
224
- moveRemaining: (step) => moveRemaining(options, step),
225
- onNext: () => onNext(options),
226
- onPrev: () => onPrev(options),
227
- scrollStep: (fraction) => scrollStep(options, fraction),
228
- onScroll: (delta) => onScroll(options, delta),
229
- onHome: () => onJump(options, false),
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 };