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.
Files changed (109) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/LICENSE +1 -1
  3. package/README.md +12 -13
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +32 -19
  6. package/lib/capabilities.js +8 -12
  7. package/lib/cli.js +40 -74
  8. package/lib/clipboard.js +48 -18
  9. package/lib/dashboard/git.js +128 -0
  10. package/lib/dashboard/model.js +332 -0
  11. package/lib/dashboard/npm.js +193 -0
  12. package/lib/dashboard/tree.js +278 -0
  13. package/lib/deps-diff.js +196 -404
  14. package/lib/deps.js +240 -399
  15. package/lib/detect.js +8 -18
  16. package/lib/diff/align.js +41 -113
  17. package/lib/diff/diff.js +12 -43
  18. package/lib/diff/display.js +25 -36
  19. package/lib/diff/edit.js +6 -20
  20. package/lib/diff/inline.js +138 -141
  21. package/lib/diff/items.js +33 -47
  22. package/lib/diff/parse.js +28 -56
  23. package/lib/diff/patch.js +12 -33
  24. package/lib/diff/unit.js +90 -206
  25. package/lib/editor.js +98 -55
  26. package/lib/files.js +86 -103
  27. package/lib/git-branches.js +254 -416
  28. package/lib/git-deps.js +182 -344
  29. package/lib/git-reword-todo.js +5 -13
  30. package/lib/git-worktree.js +141 -212
  31. package/lib/git.js +21 -49
  32. package/lib/github.js +67 -181
  33. package/lib/gitlab.js +40 -90
  34. package/lib/highlight/bash.js +55 -177
  35. package/lib/highlight/core.js +157 -132
  36. package/lib/highlight/css.js +25 -58
  37. package/lib/highlight/csv.js +19 -37
  38. package/lib/highlight/dart.js +72 -213
  39. package/lib/highlight/dot.js +16 -26
  40. package/lib/highlight/html.js +42 -63
  41. package/lib/highlight/js.js +177 -506
  42. package/lib/highlight/json.js +17 -37
  43. package/lib/highlight/log.js +22 -35
  44. package/lib/highlight/txt.js +9 -22
  45. package/lib/highlight.js +17 -46
  46. package/lib/keys.js +62 -85
  47. package/lib/manifest.js +67 -130
  48. package/lib/npm-commands.js +119 -189
  49. package/lib/remote.js +141 -197
  50. package/lib/render/branches.js +66 -73
  51. package/lib/render/chrome.js +264 -323
  52. package/lib/render/commits.js +187 -500
  53. package/lib/render/dash-activity.js +212 -0
  54. package/lib/render/dash-blocks.js +245 -0
  55. package/lib/render/dash-table.js +290 -0
  56. package/lib/render/dashboard.js +62 -0
  57. package/lib/render/diff.js +123 -228
  58. package/lib/render/files.js +45 -99
  59. package/lib/render/frame.js +129 -183
  60. package/lib/render/notes.js +144 -160
  61. package/lib/render/npm.js +234 -112
  62. package/lib/render/present.js +4 -11
  63. package/lib/render/primitives.js +131 -170
  64. package/lib/render/render.js +5 -14
  65. package/lib/render/report.js +43 -0
  66. package/lib/render/tiles.js +260 -0
  67. package/lib/render/unit.js +15 -28
  68. package/lib/report-model.js +110 -33
  69. package/lib/report-parse.js +56 -38
  70. package/lib/report-render.js +102 -59
  71. package/lib/report-run.js +87 -78
  72. package/lib/report-test.js +256 -141
  73. package/lib/report-tools.js +96 -161
  74. package/lib/review-merge.js +114 -152
  75. package/lib/review.js +115 -189
  76. package/lib/runs.js +225 -0
  77. package/lib/select.js +89 -75
  78. package/lib/session/accessors.js +14 -21
  79. package/lib/session/actions.js +82 -63
  80. package/lib/session/branches.js +193 -247
  81. package/lib/session/change-actions.js +171 -214
  82. package/lib/session/commit.js +280 -342
  83. package/lib/session/compose.js +559 -674
  84. package/lib/session/dashboard.js +385 -0
  85. package/lib/session/dispatch.js +164 -157
  86. package/lib/session/edit-click.js +57 -0
  87. package/lib/session/files-pane.js +85 -53
  88. package/lib/session/items.js +73 -104
  89. package/lib/session/lifecycle.js +403 -541
  90. package/lib/session/load.js +48 -68
  91. package/lib/session/navigation.js +96 -87
  92. package/lib/session/npm.js +409 -345
  93. package/lib/session/ops.js +196 -63
  94. package/lib/session/pointer.js +23 -15
  95. package/lib/session/progress.js +33 -21
  96. package/lib/session/review.js +33 -54
  97. package/lib/session/tasks.js +333 -0
  98. package/lib/session/templates.js +51 -59
  99. package/lib/session/terminal.js +85 -136
  100. package/lib/session/unit.js +3 -4
  101. package/lib/session/update.js +76 -97
  102. package/lib/session/view.js +52 -83
  103. package/lib/session/watch.js +208 -204
  104. package/lib/session.js +112 -237
  105. package/lib/update.js +45 -116
  106. package/lib/utilities.js +67 -89
  107. package/lib/wrap.js +33 -44
  108. package/package.json +1 -1
  109. package/lib/session/todos.js +0 -293
@@ -1,51 +1,31 @@
1
1
  'use strict';
2
2
 
3
3
  const core = require('./core.js');
4
- const { emit, readString } = core;
4
+ const { emit, wordStyles, scanWhile, stringEnd } = core;
5
5
 
6
- const JSON_LITERAL = {
7
- true: 'literal',
8
- false: 'literal',
9
- null: 'literal',
10
- };
6
+ const JSON_LITERAL = wordStyles({ literal: ['true', 'false', 'null'] });
11
7
 
12
8
  const highlight = (source) => {
13
9
  const out = [];
14
10
  let i = 0;
15
- const n = source.length;
16
- while (i < n) {
11
+ const take = (style, end) => {
12
+ emit(out, style, source.slice(i, end));
13
+ i = end;
14
+ };
15
+ while (i < source.length) {
17
16
  const ch = source[i];
18
17
  if (ch === '"') {
19
- const { text, end } = readString(source, i);
20
- let k = end;
21
- while (k < n && /\s/.test(source[k])) k += 1;
22
- const kind = source[k] === ':' ? 'property' : 'string';
23
- emit(out, kind, text);
24
- i = end;
25
- continue;
26
- }
27
- if (/[0-9-]/.test(ch)) {
28
- let j = i;
29
- while (j < n && /[0-9.eE+-]/.test(source[j])) j += 1;
30
- emit(out, 'number', source.slice(i, j));
31
- i = j;
32
- continue;
33
- }
34
- if (/[a-z]/.test(ch)) {
35
- let j = i;
36
- while (j < n && /[a-z]/.test(source[j])) j += 1;
37
- const word = source.slice(i, j);
38
- emit(out, JSON_LITERAL[word] ?? 'plain', word);
39
- i = j;
40
- continue;
41
- }
42
- if (/[{}[\],:]/.test(ch)) {
43
- emit(out, 'punct', ch);
44
- i += 1;
45
- continue;
18
+ const end = stringEnd(source, i);
19
+ const after = source[scanWhile(source, end, /\s/)];
20
+ take(after === ':' ? 'property' : 'string', end);
21
+ } else if (/[0-9-]/.test(ch)) {
22
+ take('number', scanWhile(source, i, /[0-9.eE+-]/));
23
+ } else if (/[a-z]/.test(ch)) {
24
+ const end = scanWhile(source, i, /[a-z]/);
25
+ take(JSON_LITERAL[source.slice(i, end)] ?? 'plain', end);
26
+ } else {
27
+ take(/[{}[\],:]/.test(ch) ? 'punct' : 'plain', i + 1);
46
28
  }
47
- emit(out, 'plain', ch);
48
- i += 1;
49
29
  }
50
30
  return out;
51
31
  };
@@ -1,59 +1,46 @@
1
1
  'use strict';
2
2
 
3
3
  const core = require('./core.js');
4
- const { emit } = core;
4
+ const { emit, highlightLines, wordStyles } = core;
5
5
 
6
6
  const LOG_DATETIME_RE = new RegExp(
7
7
  '^(\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}' +
8
8
  '(?:\\.\\d+)?(?:Z|[+-]\\d{2}:?\\d{2})?)',
9
9
  );
10
10
 
11
- const LOG_TAG_STYLE = {
12
- error: 'logError',
13
- err: 'logError',
14
- warn: 'logWarn',
15
- warning: 'logWarn',
16
- info: 'logInfo',
17
- debug: 'logDebug',
18
- log: 'plain',
19
- };
11
+ const LOG_TAG_RE = /^(\s*)(\[[^\]]+\])/;
12
+
13
+ const LOG_TAG_STYLE = wordStyles({
14
+ logError: ['error', 'err'],
15
+ logWarn: ['warn', 'warning'],
16
+ logInfo: ['info'],
17
+ logDebug: ['debug'],
18
+ });
20
19
 
21
20
  const highlightLogLine = (line) => {
22
- if (!line) return [];
23
21
  const out = [];
24
22
  let rest = line;
25
- const dm = rest.match(LOG_DATETIME_RE);
26
- if (dm) {
27
- emit(out, 'logDate', dm[1]);
28
- rest = rest.slice(dm[1].length);
23
+ const date = LOG_DATETIME_RE.exec(rest);
24
+ if (date) {
25
+ emit(out, 'logDate', date[1]);
26
+ rest = rest.slice(date[1].length);
29
27
  }
30
- const tag = rest.match(/^(\s*)(\[[^\]]+\])/);
28
+ const tag = LOG_TAG_RE.exec(rest);
31
29
  if (tag) {
32
30
  emit(out, 'plain', tag[1]);
33
- const name = tag[2].replace(/^\[|\]$/g, '').toLowerCase();
31
+ const name = tag[2].slice(1, -1).toLowerCase();
34
32
  emit(out, LOG_TAG_STYLE[name] || 'plain', tag[2]);
35
33
  rest = rest.slice(tag[0].length);
36
34
  }
37
- if (rest.includes('\t')) {
38
- const parts = rest.split('\t');
39
- for (let i = 0; i < parts.length; i += 1) {
40
- if (i) emit(out, 'plain', '\t');
41
- emit(out, `logCol${i}`, parts[i]);
42
- }
43
- return out;
35
+ const columns = rest.split('\t');
36
+ for (let i = 0; i < columns.length; i += 1) {
37
+ if (i) emit(out, 'plain', '\t');
38
+ emit(out, `logCol${i}`, columns[i]);
44
39
  }
45
- if (rest) emit(out, 'logCol0', rest);
46
40
  return out;
47
41
  };
48
42
 
49
- const highlight = (source) => {
50
- const lines = source.split('\n');
51
- const out = [];
52
- for (let i = 0; i < lines.length; i += 1) {
53
- if (i) emit(out, 'plain', '\n');
54
- for (const t of highlightLogLine(lines[i])) out.push(t);
55
- }
56
- return out;
43
+ module.exports = {
44
+ langs: ['log'],
45
+ highlight: highlightLines(highlightLogLine),
57
46
  };
58
-
59
- module.exports = { langs: ['log'], highlight };
@@ -1,37 +1,24 @@
1
1
  'use strict';
2
2
 
3
3
  const core = require('./core.js');
4
- const { emit } = core;
4
+ const { emit, highlightLines } = core;
5
+
6
+ const URL_RE = /https?:\/\/[^\s<>"']+|www\.[^\s<>"']+/g;
5
7
 
6
8
  const highlightTxtLine = (line) => {
7
- if (!line) return [];
8
9
  const out = [];
9
- const re = /(https?:\/\/[^\s<>"']+|www\.[^\s<>"']+)/g;
10
10
  let last = 0;
11
- let m = re.exec(line);
12
- while (m !== null) {
13
- if (m.index > last) emit(out, 'plain', line.slice(last, m.index));
14
- emit(out, 'string', m[0]);
15
- last = m.index + m[0].length;
16
- m = re.exec(line);
17
- }
18
- if (last < line.length) emit(out, 'plain', line.slice(last));
19
- if (!out.length) emit(out, 'plain', line);
20
- return out;
21
- };
22
-
23
- const highlight = (source) => {
24
- const lines = source.split('\n');
25
- const out = [];
26
- for (let i = 0; i < lines.length; i += 1) {
27
- if (i) emit(out, 'plain', '\n');
28
- for (const t of highlightTxtLine(lines[i])) out.push(t);
11
+ for (const match of line.matchAll(URL_RE)) {
12
+ emit(out, 'plain', line.slice(last, match.index));
13
+ emit(out, 'string', match[0]);
14
+ last = match.index + match[0].length;
29
15
  }
16
+ emit(out, 'plain', line.slice(last));
30
17
  return out;
31
18
  };
32
19
 
33
20
  module.exports = {
34
21
  langs: ['txt', 'py', 'md'],
35
22
  aliases: { text: 'txt', plain: 'txt', markdown: 'md', python: 'py' },
36
- highlight,
23
+ highlight: highlightLines(highlightTxtLine),
37
24
  };
package/lib/highlight.js CHANGED
@@ -1,40 +1,21 @@
1
1
  'use strict';
2
2
 
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
-
6
3
  const core = require('./highlight/core.js');
7
- const { tokensText } = core;
4
+ const { tokensText, words } = core;
8
5
 
9
- const PLUGIN_DIR = path.join(__dirname, 'highlight');
10
- const SKIP = ['core.js'];
6
+ const PLUGIN_NAMES = words('bash css csv dart dot html js json log txt');
11
7
 
12
- const loadPlugins = () => {
13
- const names = fs
14
- .readdirSync(PLUGIN_DIR)
15
- .filter((name) => name.endsWith('.js') && !SKIP.includes(name));
16
- names.sort();
17
- return names.map((file) => require(path.join(PLUGIN_DIR, file)));
18
- };
8
+ const HIGHLIGHTERS = Object.create(null);
9
+ const LANG = Object.create(null);
19
10
 
20
- const indexPlugins = (plugins) => {
21
- const highlighters = Object.create(null);
22
- const lang = Object.create(null);
23
- for (const plugin of plugins) {
24
- for (const id of plugin.langs) {
25
- highlighters[id] = plugin.highlight;
26
- lang[id] = id;
27
- }
28
- const aliases = plugin.aliases ?? {};
29
- for (const name of Object.keys(aliases)) lang[name] = aliases[name];
11
+ for (const name of PLUGIN_NAMES) {
12
+ const plugin = require(`./highlight/${name}.js`);
13
+ for (const id of plugin.langs) {
14
+ HIGHLIGHTERS[id] = plugin.highlight;
15
+ LANG[id] = id;
30
16
  }
31
- return { highlighters, lang };
32
- };
33
-
34
- const PLUGINS = loadPlugins();
35
- const registry = indexPlugins(PLUGINS);
36
- const HIGHLIGHTERS = registry.highlighters;
37
- const LANG = registry.lang;
17
+ Object.assign(LANG, plugin.aliases);
18
+ }
38
19
 
39
20
  const mapLang = (name) => {
40
21
  if (!name) return 'txt';
@@ -42,10 +23,8 @@ const mapLang = (name) => {
42
23
  };
43
24
 
44
25
  const tokenize = (lang, source) => {
45
- const text = source ?? '';
46
26
  const key = mapLang(lang);
47
- const highlight = HIGHLIGHTERS[key] || HIGHLIGHTERS.txt;
48
- return highlight(text, key);
27
+ return HIGHLIGHTERS[key](source ?? '', key);
49
28
  };
50
29
 
51
30
  const overlayTokens = (tokens, spans) => {
@@ -61,14 +40,12 @@ const overlayTokens = (tokens, spans) => {
61
40
  const span = diff[spanIndex];
62
41
  const tokenText = token.text ?? '';
63
42
  const spanText = span.text ?? '';
64
- const tokenLeft = tokenText.length - tokenOff;
65
- const spanLeft = spanText.length - spanOff;
66
- const n = Math.min(tokenLeft, spanLeft);
43
+ const n = Math.min(tokenText.length - tokenOff, spanText.length - spanOff);
67
44
  if (n > 0) {
68
- const name = typeof token.style === 'string' ? token.style : 'plain';
45
+ const style = typeof token.style === 'string' && token.style;
69
46
  pieces.push({
70
47
  text: tokenText.slice(tokenOff, tokenOff + n),
71
- style: name || 'plain',
48
+ style: style || 'plain',
72
49
  changed: span.changed === true,
73
50
  });
74
51
  }
@@ -83,21 +60,15 @@ const overlayTokens = (tokens, spans) => {
83
60
  spanOff = 0;
84
61
  }
85
62
  }
86
- while (spanIndex < diff.length) {
63
+ for (; spanIndex < diff.length; spanIndex++) {
87
64
  const span = diff[spanIndex];
88
65
  const text = (span.text ?? '').slice(spanOff);
89
66
  if (text) {
90
67
  pieces.push({ text, style: 'plain', changed: span.changed === true });
91
68
  }
92
- spanIndex += 1;
93
69
  spanOff = 0;
94
70
  }
95
71
  return pieces;
96
72
  };
97
73
 
98
- module.exports = {
99
- tokensText,
100
- tokenize,
101
- overlayTokens,
102
- mapLang,
103
- };
74
+ module.exports = { tokensText, tokenize, overlayTokens, mapLang };
package/lib/keys.js CHANGED
@@ -3,15 +3,13 @@
3
3
  const actions = require('./session/actions.js');
4
4
 
5
5
  const { ACTIONS, ACTION_IDS, BRANCH_ACTIONS, COMMIT_ACTIONS } = actions;
6
- const { DIFF_DISABLED, FILES_DISABLED, FILES_GIT_DISABLED } = actions;
7
- const { FILES_HIDDEN, FILES_TODO_DISABLED } = actions;
8
- const { TODO_DISABLED, BRANCHES_DISABLED } = 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
9
  const { COMMITS_DISABLED, UNIT_DISABLED, NPM_DISABLED } = actions;
10
- const { disabledActions, diffGitDisabled, branchGitDisabled } = actions;
11
- const { commitGitDisabled } = actions;
12
- const { actionFromKey, actionHot, actionLetter, buttonWord } = actions;
13
- const { CONFIRM, CONFIRM_MODE, confirmKey, applyConfirm } = actions;
14
- const { confirmPrefix, promptFromChoices } = actions;
10
+ const { diffGitDisabled, branchGitDisabled, commitGitDisabled } = actions;
11
+ const { actionLetter, buttonWord } = actions;
12
+ const { CONFIRM, confirmPrefix, promptFromChoices } = actions;
15
13
 
16
14
  const CSI_KEYS = {
17
15
  A: 'up',
@@ -48,46 +46,52 @@ const MOUSE_WHEEL = {
48
46
  65: 'wheelDown',
49
47
  };
50
48
 
51
- const parseCsiSeq = (rest) => {
52
- const body = rest.slice(2);
53
- let i = 0;
54
- while (i < body.length) {
55
- const code = body.charCodeAt(i);
56
- if (code >= 64 && code <= 126) break;
57
- i += 1;
58
- }
59
- if (i >= body.length) {
60
- if (rest.length > CSI_MAX) {
61
- return { event: { type: 'key', key: 'escape' }, eat: 1 };
62
- }
63
- return { needMore: true };
64
- }
65
- return { params: body.slice(0, i), final: body[i], eat: 2 + i + 1 };
66
- };
49
+ const NEED_MORE = { needMore: true };
67
50
 
68
- const ctrlHeld = (modText) => {
51
+ const keyAt = (key, end) => ({ event: { type: 'key', key }, end });
52
+
53
+ const modifiedKey = (base, modText) => {
54
+ const arrow =
55
+ base === 'left' || base === 'right' || base === 'up' || base === 'down';
56
+ const end = base === 'home' || base === 'end';
57
+ if (!arrow && !end) return base;
69
58
  const mod = parseInt(modText, 10);
70
- return Number.isFinite(mod) && ((mod - 1) & 4) !== 0;
59
+ const bits = Number.isFinite(mod) ? mod - 1 : 0;
60
+ const ctrl = (bits & 4) !== 0;
61
+ const shift = (bits & 1) !== 0;
62
+ if (ctrl && shift && arrow) return `ctrl-shift-${base}`;
63
+ if (ctrl && arrow) return `ctrl-${base}`;
64
+ if (shift) return `shift-${base}`;
65
+ return base;
71
66
  };
72
67
 
73
68
  const keyFromCsi = (paramsText, final) => {
74
69
  const params = paramsText ? paramsText.split(';') : [];
75
- if (final === '~') return CSI_TILDE[params[0]] ?? null;
76
- const base = CSI_KEYS[final];
70
+ const base = final === '~' ? CSI_TILDE[params[0]] : CSI_KEYS[final];
77
71
  if (!base) return null;
78
72
  if (params.length < 2) return base;
79
- const arrow =
80
- base === 'left' || base === 'right' || base === 'up' || base === 'down';
81
- if (ctrlHeld(params[1]) && arrow) return `ctrl-${base}`;
82
- return base;
73
+ return modifiedKey(base, params[1]);
83
74
  };
84
75
 
85
- const mouseKindFromButton = (button, press) => {
76
+ const parseCsi = (rest, start) => {
77
+ let i = 2;
78
+ while (i < rest.length) {
79
+ const code = rest.charCodeAt(i);
80
+ if (code >= 64 && code <= 126) break;
81
+ i += 1;
82
+ }
83
+ if (i >= rest.length) {
84
+ return rest.length > CSI_MAX ? keyAt('escape', start + 1) : NEED_MORE;
85
+ }
86
+ const key = keyFromCsi(rest.slice(2, i), rest[i]);
87
+ return key ? keyAt(key, start + i + 1) : keyAt('escape', start + 1);
88
+ };
89
+
90
+ const mouseKind = (button, press) => {
86
91
  const wheel = MOUSE_WHEEL[button];
87
92
  if (wheel) return wheel;
88
93
  if (!press) return 'release';
89
- if (button & 32) return 'drag';
90
- return 'press';
94
+ return button & 32 ? 'drag' : 'press';
91
95
  };
92
96
 
93
97
  const parseMouse = (body, flag) => {
@@ -100,81 +104,60 @@ const parseMouse = (body, flag) => {
100
104
  return null;
101
105
  }
102
106
  const press = flag === 'M';
103
- const kind = mouseKindFromButton(button, press);
107
+ const kind = mouseKind(button, press);
104
108
  return { type: 'mouse', button, x, y, press, kind, btn: button & 3 };
105
109
  };
106
110
 
107
111
  const parseEsc = (text, start) => {
108
112
  const rest = text.slice(start);
109
- if (rest === '\x1b') return { needMore: true };
110
- if (rest.startsWith('\x1b[') && rest.length === 2) return { needMore: true };
113
+ if (rest === '\x1b' || rest === '\x1b[') return NEED_MORE;
111
114
  if (rest.startsWith('\x1b[<')) {
112
115
  const endM = rest.search(/[Mm]/);
113
- if (endM < 0) return { needMore: true };
114
- const kind = rest[endM];
115
- const body = rest.slice(3, endM);
116
- const mouse = parseMouse(body, kind);
117
- if (!mouse) {
118
- return { event: { type: 'key', key: 'escape' }, end: start + endM + 1 };
119
- }
120
- return { event: mouse, end: start + endM + 1 };
121
- }
122
- if (rest.startsWith('\x1b[')) {
123
- const csi = parseCsiSeq(rest);
124
- if (csi.needMore) return csi;
125
- if (csi.event) return { event: csi.event, end: start + csi.eat };
126
- const key = keyFromCsi(csi.params, csi.final);
127
- if (key) return { event: { type: 'key', key }, end: start + csi.eat };
128
- return { event: { type: 'key', key: 'escape' }, end: start + 1 };
116
+ if (endM < 0) return NEED_MORE;
117
+ const mouse = parseMouse(rest.slice(3, endM), rest[endM]);
118
+ const end = start + endM + 1;
119
+ return mouse ? { event: mouse, end } : keyAt('escape', end);
129
120
  }
121
+ if (rest.startsWith('\x1b[')) return parseCsi(rest, start);
130
122
  if (rest.startsWith('\x1bO')) {
131
- if (rest.length < 3) return { needMore: true };
123
+ if (rest.length < 3) return NEED_MORE;
132
124
  const key = CSI_KEYS[rest[2]];
133
- if (key) return { event: { type: 'key', key }, end: start + 3 };
134
- return { event: { type: 'key', key: 'escape' }, end: start + 1 };
125
+ return key ? keyAt(key, start + 3) : keyAt('escape', start + 1);
135
126
  }
136
- return { event: { type: 'key', key: 'escape' }, end: start + 1 };
127
+ return keyAt('escape', start + 1);
137
128
  };
138
129
 
139
130
  const decodeChunk = (text, carry = '') => {
140
131
  const source = carry + text;
141
- const events = new Array(source.length);
142
- let n = 0;
132
+ const events = [];
143
133
  let i = 0;
144
134
  while (i < source.length) {
145
135
  const ch = source[i];
146
136
  if (ch === '\x1b') {
147
137
  const parsed = parseEsc(source, i);
148
- if (parsed.needMore) {
149
- events.length = n;
150
- return { events, carry: source.slice(i) };
151
- }
152
- events[n++] = parsed.event;
138
+ if (parsed.needMore) return { events, carry: source.slice(i) };
139
+ events.push(parsed.event);
153
140
  i = parsed.end;
154
141
  continue;
155
142
  }
156
143
  const named = LITERAL_KEY[ch];
144
+ const code = source.charCodeAt(i);
157
145
  if (named) {
158
- events[n++] = { type: 'key', key: named };
146
+ events.push({ type: 'key', key: named });
159
147
  i += 1;
160
148
  continue;
161
149
  }
162
- const code = source.charCodeAt(i);
163
150
  if (code >= 1 && code <= 26) {
164
151
  const letter = String.fromCharCode(96 + code);
165
- events[n++] = { type: 'key', key: `ctrl-${letter}` };
152
+ events.push({ type: 'key', key: `ctrl-${letter}` });
166
153
  i += 1;
167
154
  continue;
168
155
  }
169
- if (code >= 0xd800 && code <= 0xdbff && i + 1 < source.length) {
170
- events[n++] = { type: 'key', key: source.slice(i, i + 2) };
171
- i += 2;
172
- continue;
173
- }
174
- events[n++] = { type: 'key', key: ch };
175
- i += 1;
156
+ const isPair = code >= 0xd800 && code <= 0xdbff && i + 1 < source.length;
157
+ const size = isPair ? 2 : 1;
158
+ events.push({ type: 'key', key: source.slice(i, i + size) });
159
+ i += size;
176
160
  }
177
- events.length = n;
178
161
  return { events, carry: '' };
179
162
  };
180
163
 
@@ -188,32 +171,26 @@ const hitAction = (hits, x) => {
188
171
  module.exports = {
189
172
  ACTIONS,
190
173
  ACTION_IDS,
174
+ DASH_IDS,
175
+ DASH_HIDDEN,
191
176
  BRANCH_ACTIONS,
192
177
  COMMIT_ACTIONS,
193
178
  DIFF_DISABLED,
194
- FILES_DISABLED,
195
179
  FILES_HIDDEN,
196
180
  FILES_GIT_DISABLED,
197
- FILES_TODO_DISABLED,
198
- TODO_DISABLED,
181
+ TASKS_DISABLED,
199
182
  BRANCHES_DISABLED,
200
183
  COMMITS_DISABLED,
201
184
  NPM_DISABLED,
202
185
  UNIT_DISABLED,
203
- disabledActions,
204
186
  diffGitDisabled,
205
187
  branchGitDisabled,
206
188
  commitGitDisabled,
207
189
  decodeChunk,
208
- actionFromKey,
209
- actionHot,
210
190
  actionLetter,
211
191
  buttonWord,
212
192
  hitAction,
213
193
  CONFIRM,
214
- CONFIRM_MODE,
215
- confirmKey,
216
- applyConfirm,
217
194
  confirmPrefix,
218
195
  promptFromChoices,
219
196
  };