reslop 0.2.4 → 0.2.5
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 +14 -1
- package/README.md +1 -2
- package/lib/capabilities.js +0 -4
- package/lib/clipboard.js +39 -1
- package/lib/deps-diff.js +0 -3
- package/lib/deps.js +144 -176
- package/lib/diff/inline.js +66 -1
- package/lib/diff/unit.js +11 -28
- package/lib/editor.js +69 -9
- package/lib/files.js +17 -16
- package/lib/git-deps.js +58 -95
- package/lib/github.js +7 -7
- package/lib/gitlab.js +3 -3
- package/lib/highlight/core.js +11 -0
- package/lib/highlight/dot.js +2 -12
- package/lib/highlight/log.js +4 -11
- package/lib/highlight/txt.js +2 -12
- package/lib/keys.js +22 -12
- package/lib/manifest.js +0 -4
- package/lib/npm-commands.js +1 -22
- package/lib/remote.js +1 -7
- package/lib/render/branches.js +4 -13
- package/lib/render/chrome.js +85 -31
- package/lib/render/commits.js +95 -207
- package/lib/render/diff.js +31 -1
- package/lib/render/files.js +7 -16
- package/lib/render/frame.js +95 -110
- package/lib/render/notes.js +71 -16
- package/lib/render/npm.js +104 -18
- package/lib/render/primitives.js +108 -45
- package/lib/render/unit.js +4 -1
- package/lib/report-parse.js +0 -1
- package/lib/report-run.js +0 -1
- package/lib/report-test.js +40 -47
- package/lib/report-tools.js +0 -7
- package/lib/review-merge.js +101 -131
- package/lib/review.js +64 -77
- package/lib/select.js +52 -0
- package/lib/session/actions.js +23 -22
- package/lib/session/branches.js +5 -3
- package/lib/session/change-actions.js +173 -146
- package/lib/session/commit.js +32 -13
- package/lib/session/compose.js +120 -77
- package/lib/session/dispatch.js +36 -21
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +24 -24
- package/lib/session/items.js +69 -89
- package/lib/session/lifecycle.js +31 -96
- package/lib/session/load.js +51 -58
- package/lib/session/navigation.js +105 -96
- package/lib/session/npm.js +158 -77
- package/lib/session/ops.js +192 -51
- package/lib/session/pointer.js +11 -5
- package/lib/session/progress.js +9 -6
- package/lib/session/review.js +35 -54
- package/lib/session/tasks.js +292 -0
- package/lib/session/terminal.js +13 -17
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +17 -14
- package/lib/session/watch.js +47 -27
- package/lib/session.js +34 -79
- package/lib/update.js +1 -5
- package/lib/utilities.js +21 -1
- package/lib/wrap.js +15 -0
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
package/lib/render/frame.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const ansi = require('../ansi.js');
|
|
4
4
|
const select = require('../select.js');
|
|
5
|
-
const { overlayRows } = select;
|
|
5
|
+
const { overlayRows, markEditorSelection } = select;
|
|
6
6
|
const primitives = require('./primitives.js');
|
|
7
7
|
const chrome = require('./chrome.js');
|
|
8
8
|
const files = require('./files.js');
|
|
@@ -16,8 +16,7 @@ const unit = require('./unit.js');
|
|
|
16
16
|
const { RESET } = ansi;
|
|
17
17
|
const { LIST_PANES, paintBodyFill, paneResult } = primitives;
|
|
18
18
|
const { paintHeader, paintFooter, footerHits, paintStatusLine } = chrome;
|
|
19
|
-
const {
|
|
20
|
-
const { hiddenActions, dimFooterActions, extraFooterActions } = chrome;
|
|
19
|
+
const { footerLayout, statusBranchHit, statusChoiceHits } = chrome;
|
|
21
20
|
const { paintNotePanel, paintBodyTodo } = notes;
|
|
22
21
|
const { paintBodyFiles } = files;
|
|
23
22
|
const { paintBodyBranches } = branches;
|
|
@@ -34,7 +33,7 @@ const bodyKind = (view) => {
|
|
|
34
33
|
if (pane === 'npm') return 'npm';
|
|
35
34
|
if (pane === 'unit') return 'unit';
|
|
36
35
|
if (!view.item) return 'empty';
|
|
37
|
-
if (view.item.origin === '
|
|
36
|
+
if (view.item.origin === 'task') return 'tasks';
|
|
38
37
|
return 'diff';
|
|
39
38
|
};
|
|
40
39
|
|
|
@@ -46,7 +45,7 @@ const BODY_PAINT = {
|
|
|
46
45
|
commits: paintBodyCommits,
|
|
47
46
|
npm: paintBodyNpm,
|
|
48
47
|
empty: paintBodyEmpty,
|
|
49
|
-
|
|
48
|
+
tasks: paintBodyTodo,
|
|
50
49
|
diff: paintBodyDiff,
|
|
51
50
|
unit: paintBodyUnit,
|
|
52
51
|
};
|
|
@@ -100,145 +99,131 @@ const revealScroll = (owners, focus, height, prefer) => {
|
|
|
100
99
|
return start;
|
|
101
100
|
};
|
|
102
101
|
|
|
103
|
-
const
|
|
102
|
+
const windowY = (win, row) => {
|
|
103
|
+
const at = row + win.shift - win.scroll;
|
|
104
|
+
if (at < 0 || at >= win.shown) return -1;
|
|
105
|
+
return win.headerLines + at + 1;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const mapEditHits = (hits, win) => {
|
|
109
|
+
const out = [];
|
|
110
|
+
for (const hit of hits) {
|
|
111
|
+
const y = windowY(win, hit.row);
|
|
112
|
+
if (y >= 0) out.push({ ...hit, y });
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const mapBodyCursor = (cursor, win) => {
|
|
104
118
|
if (!cursor) return null;
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
};
|
|
119
|
+
const y = windowY(win, cursor.row);
|
|
120
|
+
if (y < 0) return null;
|
|
121
|
+
const point = { x: cursor.x, y };
|
|
122
|
+
if (typeof cursor.scroll === 'number') point.scroll = cursor.scroll;
|
|
123
|
+
return point;
|
|
111
124
|
};
|
|
112
125
|
|
|
113
|
-
const windowBody = (view,
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
const splitBody = paintedBody.splitBody === true;
|
|
118
|
-
const pane = view.pane ?? 'diff';
|
|
119
|
-
const listPane = LIST_PANES.includes(pane);
|
|
120
|
-
const fillKind = bodyFillKind(listPane, splitBody);
|
|
126
|
+
const windowBody = (view, paintedBody, frame) => {
|
|
127
|
+
const { width, color, bodyH, headerLines } = frame;
|
|
128
|
+
const listPane = LIST_PANES.includes(view.pane ?? 'diff');
|
|
129
|
+
const fillKind = bodyFillKind(listPane, paintedBody.splitBody);
|
|
121
130
|
const filler = paintBodyFill(width, color, fillKind);
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
shift = 1;
|
|
129
|
-
}
|
|
130
|
-
for (let i = 0; i < sourceBody.length; i++) body[bodyAt++] = sourceBody[i];
|
|
131
|
-
const ownerLead = lead && sourceOwners.length;
|
|
132
|
-
const todoOwners = new Array(sourceOwners.length + (ownerLead ? 1 : 0));
|
|
133
|
-
let ownerAt = 0;
|
|
134
|
-
if (ownerLead) todoOwners[ownerAt++] = null;
|
|
135
|
-
for (let i = 0; i < sourceOwners.length; i++) {
|
|
136
|
-
todoOwners[ownerAt++] = sourceOwners[i];
|
|
137
|
-
}
|
|
138
|
-
const checkLead = lead && sourceChecks.length;
|
|
139
|
-
const todoChecks = new Array(sourceChecks.length + (checkLead ? 1 : 0));
|
|
140
|
-
let checkAt = 0;
|
|
141
|
-
if (checkLead) todoChecks[checkAt++] = false;
|
|
142
|
-
for (let i = 0; i < sourceChecks.length; i++) {
|
|
143
|
-
todoChecks[checkAt++] = sourceChecks[i];
|
|
144
|
-
}
|
|
145
|
-
const scrollRaw = view.scroll ?? 0;
|
|
131
|
+
const shift = !listPane && paintedBody.body.length > 0 ? 1 : 0;
|
|
132
|
+
const lead = (items, first) =>
|
|
133
|
+
shift && items.length ? [first, ...items] : items;
|
|
134
|
+
const body = lead(paintedBody.body, filler);
|
|
135
|
+
const taskOwners = lead(paintedBody.taskOwners, null);
|
|
136
|
+
const taskChecks = lead(paintedBody.taskChecks, false);
|
|
146
137
|
const scrollMax = Math.max(0, body.length - bodyH);
|
|
147
|
-
let scroll = listPane ? 0 : Math.min(
|
|
148
|
-
if (view.item && view.item.origin === '
|
|
149
|
-
scroll = revealScroll(
|
|
138
|
+
let scroll = listPane ? 0 : Math.min(view.scroll ?? 0, scrollMax);
|
|
139
|
+
if (view.item && view.item.origin === 'task') {
|
|
140
|
+
scroll = revealScroll(taskOwners, view.tasksFocus ?? 0, bodyH, scroll);
|
|
150
141
|
}
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
for (let i = 0; i <
|
|
155
|
-
|
|
156
|
-
for (let i = 0; i < copied; i++) {
|
|
157
|
-
const owner = todoOwners[scroll + i];
|
|
142
|
+
const slice = body.slice(scroll, scroll + bodyH);
|
|
143
|
+
const win = { shift, scroll, shown: slice.length, headerLines };
|
|
144
|
+
const taskHits = [];
|
|
145
|
+
for (let i = 0; i < slice.length; i++) {
|
|
146
|
+
const owner = taskOwners[scroll + i];
|
|
158
147
|
if (owner === undefined || owner === null) continue;
|
|
159
148
|
const y = headerLines + i + 1;
|
|
160
|
-
if (
|
|
161
|
-
|
|
149
|
+
if (taskChecks[scroll + i]) {
|
|
150
|
+
taskHits.push({ y, cursor: owner, x0: 1, x1: 4, check: true });
|
|
162
151
|
}
|
|
163
|
-
|
|
152
|
+
taskHits.push({ y, cursor: owner });
|
|
164
153
|
}
|
|
165
|
-
const cursor = mapBodyCursor(
|
|
166
|
-
|
|
167
|
-
|
|
154
|
+
const cursor = mapBodyCursor(paintedBody.cursor, win);
|
|
155
|
+
const editHits = mapEditHits(paintedBody.editHits, win);
|
|
156
|
+
while (slice.length < bodyH) slice.push(filler);
|
|
157
|
+
const { listScroll, fileHits } = paintedBody;
|
|
158
|
+
return {
|
|
159
|
+
slice,
|
|
168
160
|
scroll,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
161
|
+
scrollMax,
|
|
162
|
+
listScroll,
|
|
163
|
+
taskHits,
|
|
164
|
+
fileHits,
|
|
165
|
+
editHits,
|
|
166
|
+
cursor,
|
|
167
|
+
};
|
|
176
168
|
};
|
|
177
169
|
|
|
178
|
-
const notePointerHits = (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
170
|
+
const notePointerHits = (notes, bodyH) => {
|
|
171
|
+
const { notesWanted, noteRows, noteCursor } = notes;
|
|
172
|
+
const top = 2 + bodyH;
|
|
173
|
+
const x = noteCursor ? noteCursor.x : 0;
|
|
174
|
+
const y = noteCursor ? top + noteCursor.row : 0;
|
|
175
|
+
const cursor = noteCursor ? { x, y } : null;
|
|
183
176
|
const templateHits = [];
|
|
184
177
|
for (const hit of notesWanted.templateHits ?? []) {
|
|
185
178
|
if (hit.row >= noteRows.length) continue;
|
|
186
|
-
templateHits.push({ y:
|
|
179
|
+
templateHits.push({ y: top + hit.row, cursor: hit.cursor });
|
|
187
180
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const status = view.status ?? '';
|
|
195
|
-
rows.push(paintStatusLine(view, status, width, color));
|
|
196
|
-
rows.push(paintFooter(view, layout, width, color));
|
|
197
|
-
return overlayRows(rows, view.selection);
|
|
181
|
+
const editHits = [];
|
|
182
|
+
for (const hit of notesWanted.editHits ?? []) {
|
|
183
|
+
if (hit.row >= noteRows.length) continue;
|
|
184
|
+
editHits.push({ ...hit, y: top + hit.row });
|
|
185
|
+
}
|
|
186
|
+
return { cursor, templateHits, editHits };
|
|
198
187
|
};
|
|
199
188
|
|
|
200
189
|
const renderFrame = (view, options = {}) => {
|
|
201
190
|
const width = Math.max(20, options.width ?? 80);
|
|
202
191
|
const height = Math.max(6, options.height ?? 24);
|
|
203
192
|
const color = options.color ?? true;
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
const hidden = hiddenActions(view);
|
|
207
|
-
const dimmed = dimFooterActions(view);
|
|
208
|
-
const layout = layoutButtons(width, false, hidden, extra, dimmed);
|
|
193
|
+
const header = paintHeader(view, width, color);
|
|
194
|
+
const layout = footerLayout(view, width);
|
|
209
195
|
const notes = frameNotes(view, width, height, color);
|
|
210
|
-
const headerLines =
|
|
211
|
-
const bodyH = notes
|
|
196
|
+
const headerLines = 1;
|
|
197
|
+
const { bodyH } = notes;
|
|
212
198
|
const paintedBody = paintFrameBody(view, width, color, bodyH, headerLines);
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
const hits = notePointerHits(
|
|
224
|
-
notes.notesWanted,
|
|
225
|
-
notes.noteRows,
|
|
226
|
-
notes.noteCursor,
|
|
227
|
-
bodyH,
|
|
228
|
-
);
|
|
199
|
+
const frame = { width, color, bodyH, headerLines };
|
|
200
|
+
const windowed = windowBody(view, paintedBody, frame);
|
|
201
|
+
const rows = [
|
|
202
|
+
header,
|
|
203
|
+
...windowed.slice,
|
|
204
|
+
...notes.noteRows,
|
|
205
|
+
paintStatusLine(view, view.status ?? '', width, color),
|
|
206
|
+
paintFooter(view, layout, width, color),
|
|
207
|
+
];
|
|
208
|
+
const painted = overlayRows(rows, view.selection);
|
|
209
|
+
const hits = notePointerHits(notes, bodyH);
|
|
229
210
|
const statusY = painted.length - 1;
|
|
230
211
|
const branchHit = statusBranchHit(view, width, statusY);
|
|
231
212
|
const statusHits = branchHit ? [branchHit] : statusChoiceHits(view, statusY);
|
|
232
|
-
const { fileHits,
|
|
213
|
+
const { fileHits, taskHits, scroll, scrollMax, listScroll } = windowed;
|
|
233
214
|
const { templateHits } = hits;
|
|
215
|
+
const editHits = [...windowed.editHits, ...hits.editHits];
|
|
216
|
+
const shown = markEditorSelection(painted, view, editHits, color);
|
|
217
|
+
const text = shown.map((row) => (color ? row + RESET : row)).join('\n');
|
|
234
218
|
const footerY = painted.length;
|
|
235
219
|
return {
|
|
236
220
|
text,
|
|
237
|
-
rows:
|
|
221
|
+
rows: shown,
|
|
238
222
|
buttons: footerHits(view, layout),
|
|
239
223
|
fileHits,
|
|
240
|
-
|
|
224
|
+
taskHits,
|
|
241
225
|
templateHits,
|
|
226
|
+
editHits,
|
|
242
227
|
statusHits,
|
|
243
228
|
footerY,
|
|
244
229
|
height: footerY,
|
|
@@ -250,4 +235,4 @@ const renderFrame = (view, options = {}) => {
|
|
|
250
235
|
};
|
|
251
236
|
};
|
|
252
237
|
|
|
253
|
-
module.exports = {
|
|
238
|
+
module.exports = { renderFrame };
|
package/lib/render/notes.js
CHANGED
|
@@ -5,8 +5,8 @@ const wrap = require('../wrap.js');
|
|
|
5
5
|
const files = require('../files.js');
|
|
6
6
|
const primitives = require('./primitives.js');
|
|
7
7
|
|
|
8
|
-
const {
|
|
9
|
-
const { wrapMultiline, cursorInWrap } = wrap;
|
|
8
|
+
const { REPO_TASKS_LABEL } = files;
|
|
9
|
+
const { wrapMultiline, wrapDoc, cursorInWrap } = wrap;
|
|
10
10
|
const { THEME, truncateVisible } = ansi;
|
|
11
11
|
const { paintBar, paintCheckBar, windowRows } = primitives;
|
|
12
12
|
const { LIST_PANES, CHECK_LEAD, paneResult } = primitives;
|
|
@@ -53,11 +53,35 @@ const todoCursor = (text, edit, inner, rowStart) => {
|
|
|
53
53
|
return { x: pos.col + lead + 2, row: rowStart + pos.row };
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
+
const taskEditHits = (text, inner, rowStart, width) => {
|
|
57
|
+
const lead = checkLeadLen(text);
|
|
58
|
+
const body = text.slice(lead);
|
|
59
|
+
const bodyWidth = Math.max(1, inner - lead);
|
|
60
|
+
const doc = wrapDoc(body, bodyWidth);
|
|
61
|
+
const textX = lead + 2;
|
|
62
|
+
const hits = [];
|
|
63
|
+
for (let line = 0; line < doc.length; line++) {
|
|
64
|
+
const piece = doc[line];
|
|
65
|
+
hits.push({
|
|
66
|
+
row: rowStart + line,
|
|
67
|
+
x0: lead + 1,
|
|
68
|
+
textX,
|
|
69
|
+
x1: width + 1,
|
|
70
|
+
start: piece.start,
|
|
71
|
+
text: piece.text,
|
|
72
|
+
limit: piece.start + piece.text.length,
|
|
73
|
+
live: true,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return hits;
|
|
77
|
+
};
|
|
78
|
+
|
|
56
79
|
const paintTodoList = (texts, focus, width, color, edit) => {
|
|
57
80
|
const inner = todoInnerWidth(width);
|
|
58
81
|
const rows = [];
|
|
59
82
|
const owners = [];
|
|
60
83
|
const checks = [];
|
|
84
|
+
const editHits = [];
|
|
61
85
|
let cursor = null;
|
|
62
86
|
for (let i = 0; i < texts.length; i++) {
|
|
63
87
|
const selected = i === focus;
|
|
@@ -81,8 +105,10 @@ const paintTodoList = (texts, focus, width, color, edit) => {
|
|
|
81
105
|
}
|
|
82
106
|
if (!edit || !selected) continue;
|
|
83
107
|
cursor = todoCursor(text, edit, inner, rowStart);
|
|
108
|
+
const hits = taskEditHits(text, inner, rowStart, width);
|
|
109
|
+
for (const hit of hits) editHits.push(hit);
|
|
84
110
|
}
|
|
85
|
-
return { rows, owners, checks, cursor };
|
|
111
|
+
return { rows, owners, checks, cursor, editHits };
|
|
86
112
|
};
|
|
87
113
|
|
|
88
114
|
const noteInnerWidth = (width) => Math.max(1, width - NOTE_PAD * 2);
|
|
@@ -101,11 +127,23 @@ const paintTemplateRow = (text, selected, width, color) => {
|
|
|
101
127
|
return paintNoteLine(text, width, fgRgb, bgRgb, color);
|
|
102
128
|
};
|
|
103
129
|
|
|
130
|
+
const noteEditHit = (piece, row, width) => ({
|
|
131
|
+
row,
|
|
132
|
+
x0: 1,
|
|
133
|
+
textX: NOTE_PAD + 1,
|
|
134
|
+
x1: width + 1,
|
|
135
|
+
start: piece.start,
|
|
136
|
+
text: piece.text,
|
|
137
|
+
limit: piece.start + piece.text.length,
|
|
138
|
+
live: true,
|
|
139
|
+
});
|
|
140
|
+
|
|
104
141
|
const paintComposeNote = (view, width, color, cap) => {
|
|
105
142
|
const inner = noteInnerWidth(width);
|
|
106
143
|
const bgRgb = THEME.noteBg;
|
|
107
144
|
const compose = view.compose;
|
|
108
|
-
const
|
|
145
|
+
const doc = wrapDoc(compose.text ?? '', inner);
|
|
146
|
+
const wrapped = doc.map((piece) => piece.text);
|
|
109
147
|
const { row, col } = cursorInWrap(compose.text, compose.cursor ?? 0, inner);
|
|
110
148
|
const shown = windowRows(wrapped, row, INPUT_MAX);
|
|
111
149
|
const rows = [];
|
|
@@ -124,8 +162,19 @@ const paintComposeNote = (view, width, color, cap) => {
|
|
|
124
162
|
}
|
|
125
163
|
}
|
|
126
164
|
const templateCount = rows.length;
|
|
127
|
-
|
|
128
|
-
|
|
165
|
+
const editHits = [];
|
|
166
|
+
for (let i = 0; i < shown.rows.length; i++) {
|
|
167
|
+
const piece = doc[shown.offset + i];
|
|
168
|
+
const painted = paintNoteLine(
|
|
169
|
+
shown.rows[i],
|
|
170
|
+
width,
|
|
171
|
+
THEME.chromeFg,
|
|
172
|
+
bgRgb,
|
|
173
|
+
color,
|
|
174
|
+
);
|
|
175
|
+
rows.push(painted);
|
|
176
|
+
if (!piece) continue;
|
|
177
|
+
editHits.push(noteEditHit(piece, templateCount + i, width));
|
|
129
178
|
}
|
|
130
179
|
return {
|
|
131
180
|
rows,
|
|
@@ -134,11 +183,12 @@ const paintComposeNote = (view, width, color, cap) => {
|
|
|
134
183
|
row: templateCount + row - shown.offset,
|
|
135
184
|
},
|
|
136
185
|
templateHits,
|
|
186
|
+
editHits,
|
|
137
187
|
};
|
|
138
188
|
};
|
|
139
189
|
|
|
140
190
|
const paintIdleNote = (view, width, color) => {
|
|
141
|
-
const empty = { rows: [], cursor: null, templateHits: [] };
|
|
191
|
+
const empty = { rows: [], cursor: null, templateHits: [], editHits: [] };
|
|
142
192
|
const text = view.noteText;
|
|
143
193
|
if (!text) return empty;
|
|
144
194
|
const inner = noteInnerWidth(width);
|
|
@@ -159,7 +209,7 @@ const paintIdleNote = (view, width, color) => {
|
|
|
159
209
|
};
|
|
160
210
|
|
|
161
211
|
const paintNotePanel = (view, width, color, cap) => {
|
|
162
|
-
const empty = { rows: [], cursor: null, templateHits: [] };
|
|
212
|
+
const empty = { rows: [], cursor: null, templateHits: [], editHits: [] };
|
|
163
213
|
const compose = view.compose;
|
|
164
214
|
if (compose && NOTE_COMPOSE.includes(compose.kind)) {
|
|
165
215
|
return paintComposeNote(view, width, color, cap);
|
|
@@ -170,34 +220,39 @@ const paintNotePanel = (view, width, color, cap) => {
|
|
|
170
220
|
};
|
|
171
221
|
|
|
172
222
|
const paintTodoCaption = (width, color) =>
|
|
173
|
-
paintBar(` ${
|
|
223
|
+
paintBar(` ${REPO_TASKS_LABEL}`, width, THEME.mutedFg, THEME.ctxBg, color);
|
|
174
224
|
|
|
175
225
|
const paintBodyTodo = (view, width, color) => {
|
|
176
|
-
const texts = view.
|
|
226
|
+
const texts = view.tasks ?? [];
|
|
177
227
|
let lines = texts;
|
|
178
228
|
if (!lines.length && view.noteText) lines = [view.noteText];
|
|
179
229
|
const painted = paintTodoList(
|
|
180
230
|
lines,
|
|
181
|
-
view.
|
|
231
|
+
view.tasksFocus ?? 0,
|
|
182
232
|
width,
|
|
183
233
|
color,
|
|
184
|
-
view.
|
|
234
|
+
view.taskEdit,
|
|
185
235
|
);
|
|
186
236
|
const caption = paintTodoCaption(width, color);
|
|
187
237
|
const body = [caption, ...painted.rows];
|
|
188
|
-
const
|
|
189
|
-
const
|
|
238
|
+
const taskOwners = [null, ...painted.owners];
|
|
239
|
+
const taskChecks = [false, ...painted.checks];
|
|
190
240
|
let cursor = null;
|
|
191
241
|
if (painted.cursor) {
|
|
192
242
|
cursor = { x: painted.cursor.x, row: painted.cursor.row + 1 };
|
|
193
243
|
}
|
|
244
|
+
const editHits = [];
|
|
245
|
+
for (const hit of painted.editHits) {
|
|
246
|
+
editHits.push({ ...hit, row: hit.row + 1 });
|
|
247
|
+
}
|
|
194
248
|
const fileHits = [];
|
|
195
249
|
const splitBody = false;
|
|
196
250
|
return paneResult({
|
|
197
251
|
body,
|
|
198
252
|
fileHits,
|
|
199
|
-
|
|
200
|
-
|
|
253
|
+
editHits,
|
|
254
|
+
taskOwners,
|
|
255
|
+
taskChecks,
|
|
201
256
|
cursor,
|
|
202
257
|
splitBody,
|
|
203
258
|
});
|
package/lib/render/npm.js
CHANGED
|
@@ -10,7 +10,7 @@ const { clipAnsi, stripAnsi, RESET, foregroundOn } = ansi;
|
|
|
10
10
|
const { formatBusyStatus } = chrome;
|
|
11
11
|
const { TABLE_KEY, TABLE_VAL } = npmCommands;
|
|
12
12
|
const { fill, FILE_MARK, paneResult, paintCursorList } = primitives;
|
|
13
|
-
const {
|
|
13
|
+
const { fieldWindow } = primitives;
|
|
14
14
|
|
|
15
15
|
const EDGE = 2;
|
|
16
16
|
const TAIL = 1;
|
|
@@ -64,31 +64,117 @@ const paintNpmRow = (entry, width, color, selected, nameCol = 0) => {
|
|
|
64
64
|
return out + edge;
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
+
const editNameSource = (view, compose, field) => {
|
|
68
|
+
if (field === 'name') return compose.text;
|
|
69
|
+
return view.npmDraftName ?? '';
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const editNameWidth = (commands, live) => {
|
|
73
|
+
const typed = visibleWidth(`${live ?? ''}`);
|
|
74
|
+
return Math.min(NPM_NAME_MAX, Math.max(npmNameWidth(commands), typed));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const paintNpmEdit = (view, width, color, nameW) => {
|
|
78
|
+
const compose = view.compose;
|
|
79
|
+
const field = view.npmEditField === 'command' ? 'command' : 'name';
|
|
80
|
+
const nameSource = editNameSource(view, compose, field);
|
|
81
|
+
const draft = view.npmDraftCommand ?? '';
|
|
82
|
+
const commandSource = field === 'command' ? compose.text : draft;
|
|
83
|
+
const inner = Math.max(1, width - EDGE - TAIL);
|
|
84
|
+
const prefix = ` ${FILE_MARK} `;
|
|
85
|
+
const prefixW = visibleWidth(prefix);
|
|
86
|
+
const rest = Math.max(1, inner - prefixW);
|
|
87
|
+
const colW = Math.min(Math.max(0, nameW), rest);
|
|
88
|
+
const flatName = `${nameSource ?? ''}`.replaceAll('\n', ' ');
|
|
89
|
+
const nameAt = field === 'name' ? compose.cursor : 0;
|
|
90
|
+
const nameScroll = field === 'name' ? compose.scrollCol : 0;
|
|
91
|
+
const nameWin = fieldWindow(flatName, nameAt, nameScroll, colW);
|
|
92
|
+
const name = nameWin.text;
|
|
93
|
+
const gap = rest > colW + 2 ? ' ' : '';
|
|
94
|
+
const gapW = visibleWidth(gap);
|
|
95
|
+
const detailW = Math.max(0, rest - colW - gapW);
|
|
96
|
+
const flatCommand = `${commandSource ?? ''}`.replaceAll('\n', ' ');
|
|
97
|
+
const commandAt = field === 'command' ? compose.cursor : 0;
|
|
98
|
+
const commandScroll = field === 'command' ? compose.scrollCol : 0;
|
|
99
|
+
const commandWin = fieldWindow(
|
|
100
|
+
flatCommand,
|
|
101
|
+
commandAt,
|
|
102
|
+
commandScroll,
|
|
103
|
+
detailW,
|
|
104
|
+
);
|
|
105
|
+
const command = commandWin.text;
|
|
106
|
+
const namePad = ' '.repeat(Math.max(0, colW - visibleWidth(name)));
|
|
107
|
+
const mid = `${name}${namePad}`;
|
|
108
|
+
const after = `${gap}${command}`;
|
|
109
|
+
const pad = Math.max(0, rest - visibleWidth(mid + after));
|
|
110
|
+
const tail = ' '.repeat(TAIL);
|
|
111
|
+
const left = `${prefix}${mid}${after}${' '.repeat(pad)}`;
|
|
112
|
+
const fgRgb = THEME.chromeFg;
|
|
113
|
+
const bgRgb = THEME.buttonBg;
|
|
114
|
+
const edge = fill(EDGE, fgRgb, THEME.ctxBg, color);
|
|
115
|
+
let row = `${left}${tail}${edge}`;
|
|
116
|
+
if (color) {
|
|
117
|
+
row = `${seq(fgRgb, bgRgb)}${EL}`;
|
|
118
|
+
row += paint(prefix, fgRgb, bgRgb, color);
|
|
119
|
+
row += paint(mid, THEME.buttonHotFg, bgRgb, color, true);
|
|
120
|
+
row += paint(`${after}${' '.repeat(pad)}${tail}`, fgRgb, bgRgb, color);
|
|
121
|
+
row += edge;
|
|
122
|
+
}
|
|
123
|
+
const active = field === 'name' ? nameWin : commandWin;
|
|
124
|
+
const lead = field === 'name' ? 0 : colW + gapW;
|
|
125
|
+
const nameX = prefixW + 1;
|
|
126
|
+
const commandX = prefixW + colW + gapW + 1;
|
|
127
|
+
const edits = [
|
|
128
|
+
{
|
|
129
|
+
field: 'name',
|
|
130
|
+
x0: 1,
|
|
131
|
+
textX: nameX,
|
|
132
|
+
x1: commandX,
|
|
133
|
+
start: 0,
|
|
134
|
+
text: flatName,
|
|
135
|
+
limit: flatName.length,
|
|
136
|
+
scroll: nameWin.scroll,
|
|
137
|
+
live: field === 'name',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
field: 'command',
|
|
141
|
+
x0: commandX,
|
|
142
|
+
textX: commandX,
|
|
143
|
+
x1: width + 1,
|
|
144
|
+
start: 0,
|
|
145
|
+
text: flatCommand,
|
|
146
|
+
limit: flatCommand.length,
|
|
147
|
+
scroll: commandWin.scroll,
|
|
148
|
+
live: field === 'command',
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
const cursor = {
|
|
152
|
+
x: prefixW + lead + active.col + 1,
|
|
153
|
+
scroll: active.scroll,
|
|
154
|
+
};
|
|
155
|
+
return { row, cursor, edits };
|
|
156
|
+
};
|
|
157
|
+
|
|
67
158
|
const paintNpmList = (view, width, color, bodyH, headerLines) => {
|
|
68
159
|
const commands = view.npmCommands ?? [];
|
|
69
|
-
const nameW = npmNameWidth(commands);
|
|
70
|
-
const cursor = view.npmCursor ?? 0;
|
|
71
160
|
const compose = view.compose;
|
|
72
161
|
const editing = compose && compose.kind === 'npm';
|
|
73
|
-
const
|
|
74
|
-
|
|
162
|
+
const field = view.npmEditField === 'command' ? 'command' : 'name';
|
|
163
|
+
const live = editing ? editNameSource(view, compose, field) : '';
|
|
164
|
+
const nameW = editing
|
|
165
|
+
? editNameWidth(commands, live)
|
|
166
|
+
: npmNameWidth(commands);
|
|
167
|
+
const cursor = view.npmCursor ?? 0;
|
|
168
|
+
const pane = { width, color, bodyH, headerLines, offset: view.listScroll };
|
|
169
|
+
const paintRow = (entry, selected) =>
|
|
170
|
+
paintNpmRow(entry, width, color, selected, nameW);
|
|
75
171
|
let extra = null;
|
|
76
172
|
if (editing) {
|
|
77
|
-
const painted =
|
|
173
|
+
const painted = paintNpmEdit(view, width, color, nameW);
|
|
78
174
|
const at = view.npmEditName ? 'replace' : 'end';
|
|
79
|
-
extra = {
|
|
175
|
+
extra = { ...painted, at, index: cursor };
|
|
80
176
|
}
|
|
81
|
-
return paintCursorList(
|
|
82
|
-
commands,
|
|
83
|
-
cursor,
|
|
84
|
-
width,
|
|
85
|
-
color,
|
|
86
|
-
bodyH,
|
|
87
|
-
headerLines,
|
|
88
|
-
paintRow,
|
|
89
|
-
extra,
|
|
90
|
-
view.listScroll,
|
|
91
|
-
);
|
|
177
|
+
return paintCursorList(commands, cursor, pane, paintRow, extra);
|
|
92
178
|
};
|
|
93
179
|
|
|
94
180
|
const logStart = (view, count, rows) => {
|