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,73 +1,53 @@
1
1
  'use strict';
2
2
 
3
- const accessors = require('./accessors.js');
4
- const { stateView } = accessors;
5
-
6
- const utilities = require('../utilities.js');
7
- const { isAbort: isAbortError } = utilities;
8
-
9
- const createLoadCoordinator = () => {
10
- const state = {
11
- gen: 0,
12
- abort: null,
13
- promise: null,
14
- pendingExtras: false,
15
- didLoad: false,
16
- };
17
-
18
- const bump = () => {
19
- state.gen += 1;
20
- state.abort?.abort();
21
- state.abort = new AbortController();
22
- return state.gen;
23
- };
24
-
25
- const isCurrent = (gen, done = false) => gen === state.gen && !done;
26
- const accept = isCurrent;
27
-
28
- const abort = () => {
29
- state.abort?.abort();
30
- };
31
-
32
- const reset = () => {
33
- abort();
34
- state.gen += 1;
35
- state.abort = null;
36
- state.promise = null;
37
- state.pendingExtras = false;
38
- state.didLoad = false;
39
- };
40
-
41
- const tag = (loaded, gen) => ({ ...loaded, generation: gen });
42
-
43
- const fetchSnapshot = async (repo, cwd, paths, options) => {
44
- if (repo.loadAsync) return repo.loadAsync(cwd, paths, options);
45
- return repo.load(cwd, paths, options);
46
- };
47
-
48
- const fetchExtras = async (repo, loaded, extra) => {
49
- if (!repo.loadExtras) return null;
50
- return repo.loadExtras(loaded, extra);
51
- };
3
+ class LoadCoordinator {
4
+ constructor() {
5
+ this.gen = 0;
6
+ this.abortController = null;
7
+ this.promise = null;
8
+ this.pendingExtras = false;
9
+ this.didLoad = false;
10
+ }
11
+
12
+ get signal() {
13
+ return this.abortController?.signal;
14
+ }
15
+
16
+ bump() {
17
+ this.gen += 1;
18
+ this.abortController?.abort();
19
+ this.abortController = new AbortController();
20
+ return this.gen;
21
+ }
22
+
23
+ isCurrent(gen, done = false) {
24
+ return gen === this.gen && !done;
25
+ }
26
+
27
+ abort() {
28
+ this.abortController?.abort();
29
+ }
30
+
31
+ reset() {
32
+ this.abort();
33
+ this.gen += 1;
34
+ this.abortController = null;
35
+ this.promise = null;
36
+ this.pendingExtras = false;
37
+ this.didLoad = false;
38
+ }
39
+ }
40
+
41
+ const tagLoaded = (loaded, gen) => ({ ...loaded, generation: gen });
42
+
43
+ const fetchSnapshot = async (repo, cwd, paths, options) => {
44
+ if (repo.loadAsync) return repo.loadAsync(cwd, paths, options);
45
+ return repo.load(cwd, paths, options);
46
+ };
52
47
 
53
- return stateView(
54
- state,
55
- {
56
- get signal() {
57
- return state.abort?.signal;
58
- },
59
- bump,
60
- isCurrent,
61
- accept,
62
- abort,
63
- reset,
64
- tag,
65
- fetchSnapshot,
66
- fetchExtras,
67
- },
68
- ['promise', 'pendingExtras', 'didLoad'],
69
- ['gen'],
70
- );
48
+ const fetchExtras = async (repo, loaded, extra) => {
49
+ if (!repo.loadExtras) return null;
50
+ return repo.loadExtras(loaded, extra);
71
51
  };
72
52
 
73
- module.exports = { isAbortError, createLoadCoordinator };
53
+ module.exports = { LoadCoordinator, tagLoaded, fetchSnapshot, fetchExtras };
@@ -1,107 +1,116 @@
1
1
  'use strict';
2
2
 
3
3
  const files = require('../files.js');
4
- const { listPath, isTodoItem, isTodosEntry, TODO_FILE } = files;
4
+ const { listPath, isTaskItem, isTasksEntry, TASKS_FILE } = files;
5
+ const actions = require('./actions.js');
6
+ const { LIST_PANES } = actions;
5
7
 
6
- const initialState = (options = {}) => ({
7
- pane: options.startPane ?? 'files',
8
- index: 0,
9
- fileCursor: 0,
10
- branchCursor: 0,
11
- commitCursor: 0,
12
- npmCursor: 0,
13
- scroll: 0,
14
- listScroll: 0,
15
- reviewPath: null,
16
- fileScope: 'diff',
17
- unitLine: 0,
18
- selection: null,
19
- mouseAnchor: null,
20
- pendingClick: null,
21
- lastClick: null,
22
- todoOpen: false,
23
- todoFocus: 0,
24
- });
8
+ const freshListScroll = () =>
9
+ Object.fromEntries(LIST_PANES.map((pane) => [pane, 0]));
25
10
 
26
- const clampIndex = (nav, length) => {
27
- if (!length) {
28
- nav.index = 0;
29
- return;
11
+ class Navigation {
12
+ constructor(options = {}) {
13
+ this.reset(options.startPane ?? 'files');
30
14
  }
31
- if (nav.index < 0) nav.index = 0;
32
- if (nav.index >= length) nav.index = length - 1;
33
- };
34
15
 
35
- const current = (nav, items, todoItem) => {
36
- if (nav.todoOpen) return todoItem;
37
- if (nav.pane === 'unit' && nav.reviewPath) {
38
- const item = items[nav.index];
39
- if (item && listPath(item) === nav.reviewPath) return item;
40
- for (const entry of items) {
41
- if (listPath(entry) === nav.reviewPath) return entry;
16
+ reset(startPane = this.pane) {
17
+ this.pane = startPane;
18
+ this.index = 0;
19
+ this.fileCursor = 0;
20
+ this.branchCursor = 0;
21
+ this.commitCursor = 0;
22
+ this.npmCursor = 0;
23
+ this.scroll = 0;
24
+ this.listScrollByPane = freshListScroll();
25
+ this.reviewPath = null;
26
+ this.fileScope = 'diff';
27
+ this.unitLine = 0;
28
+ this.selection = null;
29
+ this.mouseAnchor = null;
30
+ this.pendingClick = null;
31
+ this.lastClick = null;
32
+ this.tasksOpen = false;
33
+ this.tasksFocus = 0;
34
+ }
35
+
36
+ clampIndex(length) {
37
+ if (!length) {
38
+ this.index = 0;
39
+ return;
42
40
  }
43
- return null;
41
+ if (this.index < 0) this.index = 0;
42
+ if (this.index >= length) this.index = length - 1;
44
43
  }
45
- return items[nav.index] ?? null;
46
- };
47
44
 
48
- const syncReviewPath = (nav, item) => {
49
- if (nav.pane !== 'diff' && nav.pane !== 'unit') return;
50
- if (nav.pane === 'unit' && nav.reviewPath) return;
51
- nav.reviewPath = item ? listPath(item) : null;
52
- };
45
+ current(items, tasksItem) {
46
+ if (this.tasksOpen) return tasksItem;
47
+ if (this.pane === 'unit' && this.reviewPath) {
48
+ const item = items[this.index];
49
+ if (item && listPath(item) === this.reviewPath) return item;
50
+ for (const entry of items) {
51
+ if (listPath(entry) === this.reviewPath) return entry;
52
+ }
53
+ return null;
54
+ }
55
+ return items[this.index] ?? null;
56
+ }
53
57
 
54
- const clampFileCursor = (nav, length) => {
55
- if (!length) {
56
- nav.fileCursor = 0;
57
- return;
58
+ syncReviewPath(item) {
59
+ if (this.pane !== 'diff' && this.pane !== 'unit') return;
60
+ if (this.pane === 'unit' && this.reviewPath) return;
61
+ this.reviewPath = item ? listPath(item) : null;
58
62
  }
59
- if (nav.fileCursor >= length) nav.fileCursor = length - 1;
60
- };
61
63
 
62
- const followReviewPath = (nav, fileList, item) => {
63
- if (!fileList.length) {
64
- nav.fileCursor = 0;
65
- return;
64
+ clampFileCursor(length) {
65
+ if (!length) {
66
+ this.fileCursor = 0;
67
+ return;
68
+ }
69
+ if (this.fileCursor >= length) this.fileCursor = length - 1;
66
70
  }
67
- let idx = fileList.findIndex(
68
- (entry) => !isTodosEntry(entry) && entry.path === nav.reviewPath,
69
- );
70
- if (nav.reviewPath === TODO_FILE || isTodoItem(item)) {
71
- idx = fileList.findIndex((entry) => isTodosEntry(entry));
71
+
72
+ followReviewPath(fileList, item) {
73
+ if (!fileList.length) {
74
+ this.fileCursor = 0;
75
+ return;
76
+ }
77
+ let idx = fileList.findIndex(
78
+ (entry) => !isTasksEntry(entry) && entry.path === this.reviewPath,
79
+ );
80
+ if (this.reviewPath === TASKS_FILE || isTaskItem(item)) {
81
+ idx = fileList.findIndex((entry) => isTasksEntry(entry));
82
+ }
83
+ if (idx >= 0) {
84
+ this.fileCursor = idx;
85
+ return;
86
+ }
87
+ this.clampFileCursor(fileList.length);
72
88
  }
73
- if (idx >= 0) {
74
- nav.fileCursor = idx;
75
- return;
89
+
90
+ restoreFileCursor(fileList) {
91
+ if (this.pane !== 'files') return;
92
+ this.followReviewPath(fileList, null);
76
93
  }
77
- clampFileCursor(nav, fileList.length);
78
- };
79
94
 
80
- const restoreFileCursor = (nav, fileList) => {
81
- if (nav.pane !== 'files') return;
82
- followReviewPath(nav, fileList, null);
83
- };
95
+ clearSelection() {
96
+ this.selection = null;
97
+ this.mouseAnchor = null;
98
+ this.pendingClick = null;
99
+ }
84
100
 
85
- const clearSelection = (nav) => {
86
- nav.selection = null;
87
- nav.mouseAnchor = null;
88
- nav.pendingClick = null;
89
- };
101
+ get listScroll() {
102
+ return this.listScrollByPane[this.pane] ?? 0;
103
+ }
90
104
 
91
- const createNavigation = (options = {}) => {
92
- const nav = initialState(options);
93
- nav.reset = (startPane) => {
94
- const pane = startPane ?? nav.pane;
95
- Object.assign(nav, initialState({ startPane: pane }));
96
- };
97
- nav.clampIndex = (length) => clampIndex(nav, length);
98
- nav.current = (items, todoItem) => current(nav, items, todoItem);
99
- nav.syncReviewPath = (item) => syncReviewPath(nav, item);
100
- nav.clampFileCursor = (length) => clampFileCursor(nav, length);
101
- nav.followReviewPath = (list, item) => followReviewPath(nav, list, item);
102
- nav.restoreFileCursor = (list) => restoreFileCursor(nav, list);
103
- nav.clearSelection = () => clearSelection(nav);
104
- return nav;
105
- };
105
+ set listScroll(value) {
106
+ if (!LIST_PANES.includes(this.pane)) return;
107
+ this.listScrollByPane[this.pane] = value ?? 0;
108
+ }
109
+
110
+ resetListScroll(pane = this.pane) {
111
+ if (!LIST_PANES.includes(pane)) return;
112
+ this.listScrollByPane[pane] = 0;
113
+ }
114
+ }
106
115
 
107
- module.exports = { createNavigation };
116
+ module.exports = { Navigation };