reslop 0.2.7 → 0.3.1
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 +30 -1
- package/README.md +16 -14
- package/bin/reslop.js +8 -5
- package/lib/agents/agents.js +573 -0
- package/lib/agents/allow.js +71 -0
- package/lib/agents/allow.json +17 -0
- package/lib/agents/models.js +467 -0
- package/lib/api.js +15 -12
- package/lib/cli.js +43 -68
- package/lib/{files.js → common/files.js} +48 -55
- package/lib/{find.js → common/find.js} +1 -1
- package/lib/common/format.js +101 -0
- package/lib/{utilities.js → common/process.js} +7 -95
- package/lib/common/tasks.json +27 -0
- package/lib/common/utilities.js +112 -0
- package/lib/dashboard/git.js +9 -16
- package/lib/dashboard/model.js +90 -49
- package/lib/dashboard/npm.js +17 -13
- package/lib/dashboard/tree.js +27 -30
- package/lib/{session → dashboard}/watch.js +36 -31
- package/lib/{workspace.js → dashboard/workspace.js} +23 -38
- package/lib/{deps.js → deps/deps.js} +31 -45
- package/lib/{deps-diff.js → deps/diff.js} +35 -25
- package/lib/{manifest.js → deps/manifest.js} +47 -30
- package/lib/diff/align.js +1 -2
- package/lib/diff/diff.js +2 -2
- package/lib/diff/display.js +29 -5
- package/lib/diff/inline.js +10 -14
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +39 -3
- package/lib/diff/unit.js +45 -16
- package/lib/{git-branches.js → git/branches.js} +53 -48
- package/lib/{git-deps.js → git/deps.js} +151 -95
- package/lib/git/git.js +71 -0
- package/lib/git/worktree.js +504 -0
- package/lib/highlight/bash.js +1 -2
- package/lib/highlight/csv.js +1 -2
- package/lib/highlight/dot.js +1 -2
- package/lib/{highlight.js → highlight/highlight.js} +42 -11
- package/lib/highlight/html.js +20 -18
- package/lib/highlight/json.js +1 -2
- package/lib/highlight/log.js +1 -2
- package/lib/highlight/txt.js +1 -2
- package/lib/{session → input}/actions.js +114 -48
- package/lib/{editor.js → input/editor.js} +16 -8
- package/lib/{keys.js → input/keys.js} +24 -45
- package/lib/input/line-edit.js +78 -0
- package/lib/input/menu-pick.js +70 -0
- package/lib/render/agents.js +642 -0
- package/lib/render/branches.js +4 -5
- package/lib/render/commits.js +54 -64
- package/lib/render/{dash-activity.js → dashboard/activity.js} +25 -40
- package/lib/render/{dash-blocks.js → dashboard/blocks.js} +131 -137
- package/lib/render/{dashboard.js → dashboard/dashboard.js} +25 -22
- package/lib/render/diff.js +166 -45
- package/lib/render/field.js +131 -0
- package/lib/render/files.js +9 -14
- package/lib/render/footer.js +385 -0
- package/lib/render/frame.js +123 -25
- package/lib/render/header.js +176 -0
- package/lib/render/log.js +320 -0
- package/lib/render/menu.js +60 -0
- package/lib/render/notes.js +16 -11
- package/lib/render/npm.js +322 -196
- package/lib/render/packages.js +9 -13
- package/lib/render/primitives.js +101 -15
- package/lib/render/render.js +7 -11
- package/lib/render/repos.js +13 -25
- package/lib/render/status.js +370 -0
- package/lib/render/status.json +85 -0
- package/lib/render/{dash-table.js → table.js} +13 -60
- package/lib/render/tiles.js +109 -48
- package/lib/render/unit.js +32 -13
- package/lib/{report-model.js → report/model.js} +4 -6
- package/lib/{report-parse.js → report/parse.js} +9 -14
- package/lib/{report-render.js → report/render.js} +48 -19
- package/lib/{report-run.js → report/run.js} +42 -30
- package/lib/{report-test.js → report/test.js} +56 -55
- package/lib/{report-tools.js → report/tools.js} +24 -33
- package/lib/review/agent-instructions.md +14 -0
- package/lib/review/format.js +420 -0
- package/lib/{review-merge.js → review/merge.js} +9 -8
- package/lib/review/review.js +190 -0
- package/lib/review/store.js +281 -0
- package/lib/review/templates.js +83 -0
- package/lib/runs/commands.js +14 -0
- package/lib/runs/logs.js +299 -0
- package/lib/runs/output.js +174 -0
- package/lib/runs/process.js +113 -0
- package/lib/{runs.js → runs/runs.js} +84 -36
- package/lib/runs/scripts.js +150 -0
- package/lib/session/agents/agents.js +976 -0
- package/lib/session/agents/job.js +320 -0
- package/lib/session/agents/jobs.js +355 -0
- package/lib/session/agents/options.js +153 -0
- package/lib/session/agents/plans.js +83 -0
- package/lib/session/branches.js +33 -40
- package/lib/session/change-actions.js +34 -100
- package/lib/session/commit.js +91 -52
- package/lib/session/compose.js +189 -147
- package/lib/session/dashboard.js +23 -22
- package/lib/session/dispatch.js +86 -21
- package/lib/session/files-pane.js +47 -26
- package/lib/session/find.js +16 -29
- package/lib/session/import.js +93 -0
- package/lib/session/items.js +8 -17
- package/lib/session/lifecycle.js +78 -72
- package/lib/session/load.js +2 -4
- package/lib/session/navigation.js +6 -3
- package/lib/session/npm/history.js +250 -0
- package/lib/session/npm/npm.js +836 -0
- package/lib/session/{packages.js → npm/packages.js} +21 -14
- package/lib/session/ops.js +125 -34
- package/lib/session/pointer.js +202 -10
- package/lib/session/prefs.js +112 -0
- package/lib/session/reads.js +109 -0
- package/lib/session/review.js +28 -10
- package/lib/session/run-panel.js +40 -0
- package/lib/{session.js → session/session.js} +158 -63
- package/lib/session/tasks.js +321 -66
- package/lib/session/templates.js +1 -1
- package/lib/session/terminal.js +94 -12
- package/lib/session/unit.js +35 -30
- package/lib/session/update.js +194 -6
- package/lib/session/view.js +65 -65
- package/lib/session/workspace.js +39 -78
- package/lib/{capabilities.js → source/capabilities.js} +3 -12
- package/lib/{github.js → source/github.js} +102 -32
- package/lib/{gitlab.js → source/gitlab.js} +87 -10
- package/lib/{remote.js → source/remote.js} +144 -40
- package/lib/source/review-threads.graphql +20 -0
- package/lib/source/source.js +74 -0
- package/lib/term/ansi.js +396 -0
- package/lib/{clipboard.js → term/clipboard.js} +3 -6
- package/lib/{select.js → term/select.js} +4 -3
- package/lib/term/themes/dark.json +122 -0
- package/lib/term/themes/light.json +122 -0
- package/lib/term/wide.txt +21 -0
- package/lib/{wrap.js → term/wrap.js} +4 -4
- package/package.json +2 -2
- package/lib/ansi.js +0 -545
- package/lib/detect.js +0 -34
- package/lib/diff/edit.js +0 -33
- package/lib/git-worktree.js +0 -455
- package/lib/git.js +0 -79
- package/lib/npm-commands.js +0 -522
- package/lib/render/chrome.js +0 -806
- package/lib/render/present.js +0 -19
- package/lib/render/report.js +0 -43
- package/lib/render/search.js +0 -25
- package/lib/review.js +0 -745
- package/lib/session/accessors.js +0 -26
- package/lib/session/edit-click.js +0 -57
- package/lib/session/npm.js +0 -452
- package/lib/session/progress.js +0 -41
- package/lib/source.js +0 -36
- package/lib/update.js +0 -192
- /package/lib/{git-reword-todo.js → git/reword-todo.js} +0 -0
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const LIST_PANES = [
|
|
3
|
+
const LIST_PANES = [
|
|
4
|
+
'files',
|
|
5
|
+
'branches',
|
|
6
|
+
'commits',
|
|
7
|
+
'npm',
|
|
8
|
+
'packages',
|
|
9
|
+
'agents',
|
|
10
|
+
];
|
|
4
11
|
|
|
5
12
|
const ACTIONS = {
|
|
6
13
|
add: ['a'],
|
|
@@ -51,37 +58,65 @@ const NPM_ACTIONS = {
|
|
|
51
58
|
npmNew: ['insert'],
|
|
52
59
|
npmDrop: ['delete'],
|
|
53
60
|
npmLogs: ['l'],
|
|
54
|
-
npmStop: ['
|
|
61
|
+
npmStop: ['s'],
|
|
55
62
|
npmVerbose: ['v'],
|
|
56
63
|
npmRerun: ['r'],
|
|
57
64
|
};
|
|
58
65
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
const AGENT_ACTIONS = {
|
|
67
|
+
agentModel: ['m'],
|
|
68
|
+
agentEffort: ['e'],
|
|
69
|
+
agentFast: ['a'],
|
|
70
|
+
agentContext: ['t'],
|
|
71
|
+
agentReview: ['p'],
|
|
72
|
+
agentContinue: ['c'],
|
|
73
|
+
agentStop: ['s'],
|
|
74
|
+
agentRerun: ['r'],
|
|
67
75
|
};
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
dashTasks: 'tasks',
|
|
76
|
+
|
|
77
|
+
const AGENT_LIST_ACTIONS = {
|
|
78
|
+
agentModel: AGENT_ACTIONS.agentModel,
|
|
79
|
+
agentEffort: AGENT_ACTIONS.agentEffort,
|
|
80
|
+
agentFast: AGENT_ACTIONS.agentFast,
|
|
81
|
+
agentContext: AGENT_ACTIONS.agentContext,
|
|
82
|
+
agentReview: AGENT_ACTIONS.agentReview,
|
|
83
|
+
agentContinue: AGENT_ACTIONS.agentContinue,
|
|
77
84
|
};
|
|
78
|
-
|
|
85
|
+
|
|
86
|
+
const DASH_TILES = [
|
|
87
|
+
{ id: 'files', key: 'f', action: 'dashFiles', footer: true },
|
|
88
|
+
{ id: 'diffs', key: 'd', action: 'dashDiffs', footer: true },
|
|
89
|
+
{ id: 'tasks', key: 't', action: 'dashTasks', footer: true },
|
|
90
|
+
{ id: 'branches', key: 'b', action: 'dashBranches', footer: true },
|
|
91
|
+
{ id: 'commits', key: 'c', action: 'dashCommits', footer: true },
|
|
92
|
+
{ id: 'run', key: 'r', action: 'dashRun', footer: true },
|
|
93
|
+
{ id: 'npm', key: 'n', action: 'dashNpm', footer: true },
|
|
94
|
+
{ id: 'agents', key: 'a', action: 'dashAgents', footer: false },
|
|
95
|
+
];
|
|
96
|
+
const DASH_ACTIONS = {};
|
|
97
|
+
const DASH_BLOCKS = {};
|
|
98
|
+
const DASH_KEYS = {};
|
|
99
|
+
for (const tile of DASH_TILES) {
|
|
100
|
+
if (tile.footer) DASH_ACTIONS[tile.action] = [tile.key];
|
|
101
|
+
DASH_BLOCKS[tile.action] = tile.id;
|
|
102
|
+
DASH_KEYS[tile.key] = tile.action;
|
|
103
|
+
}
|
|
104
|
+
const DASH_IDS = Object.keys(DASH_ACTIONS);
|
|
105
|
+
const DASH_ALLOWED = [
|
|
106
|
+
...Object.keys(DASH_BLOCKS),
|
|
107
|
+
'back',
|
|
108
|
+
'pull',
|
|
109
|
+
'push',
|
|
110
|
+
'quit',
|
|
111
|
+
'theme',
|
|
112
|
+
];
|
|
79
113
|
const REPOS_ALLOWED = [
|
|
80
114
|
'repoLeft',
|
|
81
115
|
'repoRight',
|
|
82
116
|
'repoUp',
|
|
83
117
|
'repoDown',
|
|
84
118
|
'open',
|
|
119
|
+
'back',
|
|
85
120
|
'quit',
|
|
86
121
|
'theme',
|
|
87
122
|
];
|
|
@@ -95,10 +130,16 @@ const ACTION_HOT = {
|
|
|
95
130
|
newCommit: 'ins',
|
|
96
131
|
feedback: 'q',
|
|
97
132
|
check: 'space',
|
|
133
|
+
taskUp: 'ctrl+up',
|
|
134
|
+
taskDown: 'ctrl+down',
|
|
135
|
+
taskNudge: 'up/dn',
|
|
136
|
+
plan: 'p',
|
|
137
|
+
import: 'i',
|
|
98
138
|
theme: 'l',
|
|
139
|
+
lines: '+l',
|
|
99
140
|
npmNew: 'ins',
|
|
100
141
|
npmDrop: 'del',
|
|
101
|
-
npmStop: '
|
|
142
|
+
npmStop: 's',
|
|
102
143
|
packageNew: 'ins',
|
|
103
144
|
packageDrop: 'del',
|
|
104
145
|
};
|
|
@@ -107,7 +148,13 @@ const ACTION_LABEL = {
|
|
|
107
148
|
...DASH_BLOCKS,
|
|
108
149
|
revert: 'drop',
|
|
109
150
|
check: 'space',
|
|
151
|
+
taskUp: 'ctrl+up',
|
|
152
|
+
taskDown: 'ctrl+down',
|
|
153
|
+
taskNudge: 'ctrl+up/dn',
|
|
154
|
+
plan: 'plan',
|
|
155
|
+
import: 'import',
|
|
110
156
|
theme: 'light',
|
|
157
|
+
lines: 'ctrl+l',
|
|
111
158
|
layout: 'mode',
|
|
112
159
|
tasks: 'tasks',
|
|
113
160
|
view: 'view',
|
|
@@ -125,9 +172,17 @@ const ACTION_LABEL = {
|
|
|
125
172
|
packageDrop: 'delete',
|
|
126
173
|
packageWanted: 'wanted',
|
|
127
174
|
packageLatest: 'latest',
|
|
128
|
-
npmStop: '
|
|
175
|
+
npmStop: 'stop',
|
|
129
176
|
npmVerbose: 'verbose',
|
|
130
177
|
npmRerun: 're-run',
|
|
178
|
+
agentModel: 'model',
|
|
179
|
+
agentEffort: 'effort',
|
|
180
|
+
agentFast: 'fast',
|
|
181
|
+
agentContext: 'context',
|
|
182
|
+
agentReview: 'plan',
|
|
183
|
+
agentContinue: 'continue',
|
|
184
|
+
agentStop: 'stop',
|
|
185
|
+
agentRerun: 're-run',
|
|
131
186
|
quit: 'q',
|
|
132
187
|
prev: '←',
|
|
133
188
|
next: '→',
|
|
@@ -193,8 +248,12 @@ const BRANCHES_DISABLED = [
|
|
|
193
248
|
const COMMITS_DISABLED = BRANCHES_DISABLED.filter((id) => id !== 'commit');
|
|
194
249
|
const NPM_DISABLED = [...BRANCHES_DISABLED, 'pull', 'push'];
|
|
195
250
|
|
|
196
|
-
const isTasksTarget = (item) =>
|
|
197
|
-
|
|
251
|
+
const isTasksTarget = (item) => {
|
|
252
|
+
if (!item) return false;
|
|
253
|
+
const tasks = item.kind === 'tasks';
|
|
254
|
+
const task = item.origin === 'task';
|
|
255
|
+
return tasks || task;
|
|
256
|
+
};
|
|
198
257
|
|
|
199
258
|
const DIFF_MOVE_IDS = ['add', 'unstage', 'revert'];
|
|
200
259
|
|
|
@@ -214,8 +273,10 @@ const entryHasDiff = (entry) => {
|
|
|
214
273
|
return total > 0;
|
|
215
274
|
};
|
|
216
275
|
|
|
217
|
-
const lineHasDiff = (line) =>
|
|
218
|
-
|
|
276
|
+
const lineHasDiff = (line) => {
|
|
277
|
+
if (!line) return false;
|
|
278
|
+
return line.type === 'add' || line.type === 'del';
|
|
279
|
+
};
|
|
219
280
|
|
|
220
281
|
const withoutMoves = (off, hasDiff) => {
|
|
221
282
|
if (hasDiff) return off;
|
|
@@ -286,7 +347,9 @@ const disabledActions = (pane, item) => {
|
|
|
286
347
|
if (pane === 'commits') {
|
|
287
348
|
return [...COMMITS_DISABLED, ...commitWriteDisabled(item)];
|
|
288
349
|
}
|
|
289
|
-
if (pane === 'npm' || pane === 'packages')
|
|
350
|
+
if (pane === 'npm' || pane === 'packages' || pane === 'agents') {
|
|
351
|
+
return NPM_DISABLED;
|
|
352
|
+
}
|
|
290
353
|
if (pane === 'tasks' || onTodos) return TASKS_DISABLED;
|
|
291
354
|
return [...DIFF_DISABLED, ...diffGitDisabled(item)];
|
|
292
355
|
};
|
|
@@ -323,7 +386,7 @@ const keysForActions = (actions) => {
|
|
|
323
386
|
|
|
324
387
|
const PANE_ONLY = ['branch', 'file', 'diff'];
|
|
325
388
|
const REVIEW_DROP = { d: 'revert' };
|
|
326
|
-
const DIFF_KEYS = { ...REVIEW_DROP, q: 'feedback' };
|
|
389
|
+
const DIFF_KEYS = { ...REVIEW_DROP, q: 'feedback', 'ctrl-l': 'lines' };
|
|
327
390
|
const BRANCH_KEYS = keysForActions(BRANCH_ACTIONS);
|
|
328
391
|
const COMMIT_KEYS = { ...keysForActions(COMMIT_ACTIONS), s: 'push' };
|
|
329
392
|
const NPM_KEYS = {
|
|
@@ -332,8 +395,7 @@ const NPM_KEYS = {
|
|
|
332
395
|
delete: 'npmDrop',
|
|
333
396
|
l: 'npmLogs',
|
|
334
397
|
};
|
|
335
|
-
const
|
|
336
|
-
const SCREEN_KEYS = DASH_KEYS;
|
|
398
|
+
const SCREEN_KEYS = keysForActions(DASH_ACTIONS);
|
|
337
399
|
const PANE_KEYS = {
|
|
338
400
|
dashboard: { ...DASH_KEYS, p: 'pull', s: 'push' },
|
|
339
401
|
files: REVIEW_DROP,
|
|
@@ -343,7 +405,8 @@ const PANE_KEYS = {
|
|
|
343
405
|
commits: COMMIT_KEYS,
|
|
344
406
|
npm: NPM_KEYS,
|
|
345
407
|
packages: keysForActions(PACKAGE_ACTIONS),
|
|
346
|
-
|
|
408
|
+
agents: keysForActions(AGENT_LIST_ACTIONS),
|
|
409
|
+
tasks: { delete: 'drop', p: 'plan', i: 'import' },
|
|
347
410
|
repos: {
|
|
348
411
|
left: 'repoLeft',
|
|
349
412
|
right: 'repoRight',
|
|
@@ -376,14 +439,17 @@ const actionFromKey = (key, pane) => {
|
|
|
376
439
|
return KEY_TO_ACTION[key] ?? null;
|
|
377
440
|
};
|
|
378
441
|
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
NPM_ACTIONS
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
442
|
+
const ACTION_KEYS = {
|
|
443
|
+
...DASH_ACTIONS,
|
|
444
|
+
...AGENT_ACTIONS,
|
|
445
|
+
...PACKAGE_ACTIONS,
|
|
446
|
+
...NPM_ACTIONS,
|
|
447
|
+
...COMMIT_ACTIONS,
|
|
448
|
+
...BRANCH_ACTIONS,
|
|
449
|
+
...ACTIONS,
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
const actionKeys = (id) => ACTION_KEYS[id] ?? [];
|
|
387
453
|
|
|
388
454
|
const actionLetter = (id) => ACTION_HOT[id] ?? actionKeys(id)[0];
|
|
389
455
|
|
|
@@ -401,15 +467,13 @@ const YES_NO = [
|
|
|
401
467
|
|
|
402
468
|
const CONFIRM = {
|
|
403
469
|
confirmQuit: {
|
|
404
|
-
choices:
|
|
405
|
-
|
|
406
|
-
{ letter: 'c', label: 'continue next time', lead: ' ' },
|
|
407
|
-
],
|
|
470
|
+
choices: YES_NO,
|
|
471
|
+
prefix: (view) => view.quitWarning || ' exit will terminate subprocesses',
|
|
408
472
|
keys: {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
'ctrl-c': 'ready',
|
|
473
|
+
y: 'confirm',
|
|
474
|
+
n: 'cancel',
|
|
412
475
|
escape: 'cancel',
|
|
476
|
+
'ctrl-c': 'cancel',
|
|
413
477
|
},
|
|
414
478
|
},
|
|
415
479
|
confirmUpdate: {
|
|
@@ -445,6 +509,7 @@ const CONFIRM = {
|
|
|
445
509
|
confirmCommit: {
|
|
446
510
|
choices: [
|
|
447
511
|
{ letter: 'esc', label: 'esc cancel', lead: ' ' },
|
|
512
|
+
{ letter: 'u', label: 'update', lead: ' ' },
|
|
448
513
|
{ letter: 'c', label: 'commit', lead: ' ' },
|
|
449
514
|
{ letter: 'a', label: 'amend', lead: ' ' },
|
|
450
515
|
{ letter: 'f', label: 'fixup', lead: ' ' },
|
|
@@ -453,6 +518,8 @@ const CONFIRM = {
|
|
|
453
518
|
keys: {
|
|
454
519
|
esc: 'cancel',
|
|
455
520
|
escape: 'cancel',
|
|
521
|
+
enter: 'update',
|
|
522
|
+
u: 'update',
|
|
456
523
|
c: 'commit',
|
|
457
524
|
a: 'amend',
|
|
458
525
|
f: 'fixup',
|
|
@@ -479,6 +546,7 @@ const promptFromChoices = (choices) =>
|
|
|
479
546
|
|
|
480
547
|
module.exports = {
|
|
481
548
|
LIST_PANES,
|
|
549
|
+
DASH_TILES,
|
|
482
550
|
DASH_IDS,
|
|
483
551
|
DASH_BLOCKS,
|
|
484
552
|
DASH_ALLOWED,
|
|
@@ -486,8 +554,6 @@ module.exports = {
|
|
|
486
554
|
REPOS_ALLOWED,
|
|
487
555
|
ACTIONS,
|
|
488
556
|
ACTION_IDS,
|
|
489
|
-
BRANCH_ACTIONS,
|
|
490
|
-
COMMIT_ACTIONS,
|
|
491
557
|
DIFF_DISABLED,
|
|
492
558
|
UNIT_DISABLED,
|
|
493
559
|
FILES_DISABLED,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const { graphemes, visibleWidth } = ansi;
|
|
5
|
-
const
|
|
6
|
-
const { wrapMove } = wrap;
|
|
3
|
+
const { clamp } = require('../common/utilities.js');
|
|
4
|
+
const { graphemes, visibleWidth } = require('../term/ansi.js');
|
|
5
|
+
const { wrapMove } = require('../term/wrap.js');
|
|
7
6
|
|
|
8
7
|
const UNDO_CAP = 100;
|
|
9
8
|
const WORD_RE = /[\p{L}\p{N}_]/u;
|
|
@@ -127,7 +126,7 @@ class Editor {
|
|
|
127
126
|
place(offset) {
|
|
128
127
|
this.wantCol = null;
|
|
129
128
|
this.anchor = null;
|
|
130
|
-
this.cursor =
|
|
129
|
+
this.cursor = clamp(offset, 0, this.text.length);
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
backspace() {
|
|
@@ -140,13 +139,22 @@ class Editor {
|
|
|
140
139
|
this.edit(next, this.cursor - size);
|
|
141
140
|
}
|
|
142
141
|
|
|
142
|
+
backspaceWord() {
|
|
143
|
+
this.wantCol = null;
|
|
144
|
+
if (this.removeSpan()) return;
|
|
145
|
+
const { parts, i } = graphemeIndex(this.text, this.cursor);
|
|
146
|
+
const start = offsetAt(parts, wordIndex(parts, i, -1));
|
|
147
|
+
if (start === this.cursor) return;
|
|
148
|
+
this.edit(this.text.slice(0, start) + this.text.slice(this.cursor), start);
|
|
149
|
+
}
|
|
150
|
+
|
|
143
151
|
delete() {
|
|
144
152
|
this.wantCol = null;
|
|
145
153
|
if (this.removeSpan()) return;
|
|
146
154
|
const { parts, i, pos } = graphemeIndex(this.text, this.cursor);
|
|
147
155
|
if (i >= parts.length) return;
|
|
148
|
-
const
|
|
149
|
-
|
|
156
|
+
const size = parts[i].length;
|
|
157
|
+
const next = this.text.slice(0, pos) + this.text.slice(pos + size);
|
|
150
158
|
this.edit(next, this.cursor);
|
|
151
159
|
}
|
|
152
160
|
|
|
@@ -206,7 +214,7 @@ class Editor {
|
|
|
206
214
|
}
|
|
207
215
|
const rows = this.text.split('\n');
|
|
208
216
|
const { line, col } = this.linePos();
|
|
209
|
-
const next =
|
|
217
|
+
const next = clamp(line + delta, 0, rows.length - 1);
|
|
210
218
|
if (next === line) return;
|
|
211
219
|
let cursor = 0;
|
|
212
220
|
for (let i = 0; i < next; i++) cursor += rows[i].length + 1;
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const actions = require('./
|
|
4
|
-
|
|
5
|
-
const { ACTIONS
|
|
6
|
-
const { DASH_IDS, DASH_HIDDEN } = actions;
|
|
7
|
-
const { DIFF_DISABLED, FILES_GIT_DISABLED, FILES_HIDDEN } = actions;
|
|
8
|
-
const { TASKS_DISABLED, BRANCHES_DISABLED } = actions;
|
|
9
|
-
const { COMMITS_DISABLED, UNIT_DISABLED, NPM_DISABLED } = actions;
|
|
10
|
-
const { diffGitDisabled, branchGitDisabled, commitGitDisabled } = actions;
|
|
11
|
-
const { entryHasDiff, lineHasDiff, withoutMoves } = actions;
|
|
12
|
-
const { actionLetter, buttonWord } = actions;
|
|
13
|
-
const { CONFIRM, confirmPrefix, promptFromChoices } = actions;
|
|
3
|
+
const actions = require('./actions.js');
|
|
4
|
+
|
|
5
|
+
const { ACTIONS } = actions;
|
|
14
6
|
|
|
15
7
|
const CSI_KEYS = {
|
|
16
8
|
A: 'up',
|
|
@@ -19,6 +11,7 @@ const CSI_KEYS = {
|
|
|
19
11
|
D: 'left',
|
|
20
12
|
H: 'home',
|
|
21
13
|
F: 'end',
|
|
14
|
+
Z: 'shift-tab',
|
|
22
15
|
};
|
|
23
16
|
|
|
24
17
|
const SS3_KEYS = {
|
|
@@ -52,6 +45,10 @@ const CSI_TILDE = {
|
|
|
52
45
|
24: 'f12',
|
|
53
46
|
};
|
|
54
47
|
|
|
48
|
+
const CSI_U = {
|
|
49
|
+
127: 'backspace',
|
|
50
|
+
};
|
|
51
|
+
|
|
55
52
|
const CSI_MAX = 16;
|
|
56
53
|
|
|
57
54
|
const LITERAL_KEY = {
|
|
@@ -68,19 +65,22 @@ const MOUSE_WHEEL = {
|
|
|
68
65
|
65: 'wheelDown',
|
|
69
66
|
};
|
|
70
67
|
|
|
68
|
+
const ARROW_KEYS = ['left', 'right', 'up', 'down'];
|
|
69
|
+
const EDGE_KEYS = ['home', 'end'];
|
|
70
|
+
|
|
71
71
|
const NEED_MORE = { needMore: true };
|
|
72
72
|
|
|
73
73
|
const keyAt = (key, end) => ({ event: { type: 'key', key }, end });
|
|
74
74
|
|
|
75
75
|
const modifiedKey = (base, modText) => {
|
|
76
|
-
const arrow =
|
|
77
|
-
|
|
78
|
-
const end = base === 'home' || base === 'end';
|
|
79
|
-
if (!arrow && !end) return base;
|
|
76
|
+
const arrow = ARROW_KEYS.includes(base);
|
|
77
|
+
const end = EDGE_KEYS.includes(base);
|
|
80
78
|
const mod = parseInt(modText, 10);
|
|
81
79
|
const bits = Number.isFinite(mod) ? mod - 1 : 0;
|
|
82
80
|
const ctrl = (bits & 4) !== 0;
|
|
83
81
|
const shift = (bits & 1) !== 0;
|
|
82
|
+
if (base === 'backspace' && ctrl) return 'ctrl-backspace';
|
|
83
|
+
if (!arrow && !end) return base;
|
|
84
84
|
if (ctrl && shift && arrow) return `ctrl-shift-${base}`;
|
|
85
85
|
if (ctrl && arrow) return `ctrl-${base}`;
|
|
86
86
|
if (shift) return `shift-${base}`;
|
|
@@ -89,7 +89,9 @@ const modifiedKey = (base, modText) => {
|
|
|
89
89
|
|
|
90
90
|
const keyFromCsi = (paramsText, final) => {
|
|
91
91
|
const params = paramsText ? paramsText.split(';') : [];
|
|
92
|
-
|
|
92
|
+
let base = CSI_KEYS[final];
|
|
93
|
+
if (final === '~') base = CSI_TILDE[params[0]];
|
|
94
|
+
if (final === 'u') base = CSI_U[params[0]];
|
|
93
95
|
if (!base) return null;
|
|
94
96
|
if (params.length < 2) return base;
|
|
95
97
|
return modifiedKey(base, params[1]);
|
|
@@ -183,6 +185,11 @@ const decodeChunk = (text, carry = '') => {
|
|
|
183
185
|
return { events, carry: '' };
|
|
184
186
|
};
|
|
185
187
|
|
|
188
|
+
const isTextKey = (key) => {
|
|
189
|
+
if (!key || key.length !== 1) return false;
|
|
190
|
+
return key.charCodeAt(0) >= 32;
|
|
191
|
+
};
|
|
192
|
+
|
|
186
193
|
const hitAction = (hits, x) => {
|
|
187
194
|
for (const hit of hits) {
|
|
188
195
|
if (x >= hit.x0 && x < hit.x1) return hit.id;
|
|
@@ -190,32 +197,4 @@ const hitAction = (hits, x) => {
|
|
|
190
197
|
return null;
|
|
191
198
|
};
|
|
192
199
|
|
|
193
|
-
module.exports = {
|
|
194
|
-
ACTIONS,
|
|
195
|
-
ACTION_IDS,
|
|
196
|
-
DASH_IDS,
|
|
197
|
-
DASH_HIDDEN,
|
|
198
|
-
BRANCH_ACTIONS,
|
|
199
|
-
COMMIT_ACTIONS,
|
|
200
|
-
DIFF_DISABLED,
|
|
201
|
-
FILES_HIDDEN,
|
|
202
|
-
FILES_GIT_DISABLED,
|
|
203
|
-
TASKS_DISABLED,
|
|
204
|
-
BRANCHES_DISABLED,
|
|
205
|
-
COMMITS_DISABLED,
|
|
206
|
-
NPM_DISABLED,
|
|
207
|
-
UNIT_DISABLED,
|
|
208
|
-
diffGitDisabled,
|
|
209
|
-
entryHasDiff,
|
|
210
|
-
lineHasDiff,
|
|
211
|
-
withoutMoves,
|
|
212
|
-
branchGitDisabled,
|
|
213
|
-
commitGitDisabled,
|
|
214
|
-
decodeChunk,
|
|
215
|
-
actionLetter,
|
|
216
|
-
buttonWord,
|
|
217
|
-
hitAction,
|
|
218
|
-
CONFIRM,
|
|
219
|
-
confirmPrefix,
|
|
220
|
-
promptFromChoices,
|
|
221
|
-
};
|
|
200
|
+
module.exports = { ACTIONS, decodeChunk, hitAction, isTextKey };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Editor } = require('./editor.js');
|
|
4
|
+
const { isTextKey } = require('./keys.js');
|
|
5
|
+
const clipboard = require('../term/clipboard.js');
|
|
6
|
+
|
|
7
|
+
const copyLine = (editor, ui) => {
|
|
8
|
+
const text = editor.selectedText();
|
|
9
|
+
if (!text) return;
|
|
10
|
+
const ok = clipboard.copyText(text, ui.stdout);
|
|
11
|
+
ui.status = ok ? 'copied' : 'copy failed';
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const cutLine = (editor, ui) => {
|
|
15
|
+
if (!editor.hasSelect()) return;
|
|
16
|
+
copyLine(editor, ui);
|
|
17
|
+
editor.removeSpan();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const pasteLine = (editor) => {
|
|
21
|
+
const raw = clipboard.pasteText() ?? '';
|
|
22
|
+
const text = `${raw}`.replaceAll('\r', '').replaceAll('\n', '');
|
|
23
|
+
if (text) editor.insert(text);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const EDIT_OP = {
|
|
27
|
+
left: (editor) => editor.move(-1),
|
|
28
|
+
right: (editor) => editor.move(1),
|
|
29
|
+
'shift-left': (editor) => editor.move(-1, true),
|
|
30
|
+
'shift-right': (editor) => editor.move(1, true),
|
|
31
|
+
'ctrl-left': (editor) => editor.moveWord(-1),
|
|
32
|
+
'ctrl-right': (editor) => editor.moveWord(1),
|
|
33
|
+
'ctrl-shift-left': (editor) => editor.moveWord(-1, true),
|
|
34
|
+
'ctrl-shift-right': (editor) => editor.moveWord(1, true),
|
|
35
|
+
backspace: (editor) => editor.backspace(),
|
|
36
|
+
'ctrl-backspace': (editor) => editor.backspaceWord(),
|
|
37
|
+
delete: (editor) => editor.delete(),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const LINE_OP = {
|
|
41
|
+
...EDIT_OP,
|
|
42
|
+
'ctrl-x': cutLine,
|
|
43
|
+
'ctrl-v': (editor) => pasteLine(editor),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const END_OP = {
|
|
47
|
+
home: (editor) => editor.home(),
|
|
48
|
+
end: (editor) => editor.end(),
|
|
49
|
+
'shift-home': (editor) => editor.home(true),
|
|
50
|
+
'shift-end': (editor) => editor.end(true),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const LINE_ENDS = { ...LINE_OP, ...END_OP };
|
|
54
|
+
|
|
55
|
+
const lineKey = (editor, key, ui, ends) => {
|
|
56
|
+
if (key === 'ctrl-c') {
|
|
57
|
+
copyLine(editor, ui);
|
|
58
|
+
return 'caret';
|
|
59
|
+
}
|
|
60
|
+
const op = (ends ? LINE_ENDS : LINE_OP)[key];
|
|
61
|
+
if (!op && !isTextKey(key)) return null;
|
|
62
|
+
const before = editor.text;
|
|
63
|
+
if (op) op(editor, ui);
|
|
64
|
+
else editor.insert(key);
|
|
65
|
+
return editor.text === before ? 'caret' : 'text';
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const lineField = (name, text = '') => {
|
|
69
|
+
const editor = new Editor(text);
|
|
70
|
+
return {
|
|
71
|
+
editor,
|
|
72
|
+
get [name]() {
|
|
73
|
+
return editor.text;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
module.exports = { EDIT_OP, copyLine, cutLine, lineKey, lineField };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { clamp } = require('../common/utilities.js');
|
|
4
|
+
const { Editor } = require('./editor.js');
|
|
5
|
+
|
|
6
|
+
const MENU_ROWS = 8;
|
|
7
|
+
|
|
8
|
+
const menuRows = (bodyH, fraction = 1) => {
|
|
9
|
+
const height = Math.min(bodyH > 0 ? bodyH : MENU_ROWS, MENU_ROWS);
|
|
10
|
+
return Math.max(1, Math.floor(height * fraction));
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const pickDelta = (key, page, half) => {
|
|
14
|
+
const steps = {
|
|
15
|
+
up: -1,
|
|
16
|
+
down: 1,
|
|
17
|
+
pageUp: -page,
|
|
18
|
+
pageDown: page,
|
|
19
|
+
'ctrl-b': -page,
|
|
20
|
+
'ctrl-f': page,
|
|
21
|
+
'ctrl-u': -half,
|
|
22
|
+
'ctrl-d': half,
|
|
23
|
+
home: -Infinity,
|
|
24
|
+
end: Infinity,
|
|
25
|
+
};
|
|
26
|
+
return Object.hasOwn(steps, key) ? steps[key] : 0;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
class MenuPick {
|
|
30
|
+
constructor(field, cursor) {
|
|
31
|
+
this.field = field;
|
|
32
|
+
this.cursor = cursor;
|
|
33
|
+
this.scroll = 0;
|
|
34
|
+
this.editor = new Editor('');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get query() {
|
|
38
|
+
return this.editor.text;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
filter(items) {
|
|
42
|
+
const query = this.query.trim().toLowerCase();
|
|
43
|
+
if (!query) return items;
|
|
44
|
+
return items.filter((name) => name.toLowerCase().includes(query));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
touch() {
|
|
48
|
+
this.cursor = 0;
|
|
49
|
+
this.scroll = 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
move(delta, items, isOff) {
|
|
53
|
+
const last = items.length - 1;
|
|
54
|
+
const step = delta < 0 ? -1 : 1;
|
|
55
|
+
const goal = clamp(this.cursor + delta, 0, last);
|
|
56
|
+
let cursor = this.cursor;
|
|
57
|
+
for (let next = cursor; next !== goal;) {
|
|
58
|
+
next += step;
|
|
59
|
+
if (!isOff(items[next])) cursor = next;
|
|
60
|
+
}
|
|
61
|
+
if (isOff(items[cursor])) {
|
|
62
|
+
let scan = goal;
|
|
63
|
+
while (scan >= 0 && scan <= last && isOff(items[scan])) scan += step;
|
|
64
|
+
if (scan >= 0 && scan <= last) cursor = scan;
|
|
65
|
+
}
|
|
66
|
+
this.cursor = cursor;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { menuRows, pickDelta, MenuPick };
|