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.
- package/CHANGELOG.md +25 -1
- package/LICENSE +1 -1
- package/README.md +12 -13
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -12
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +48 -18
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +332 -0
- package/lib/dashboard/npm.js +193 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +196 -404
- package/lib/deps.js +240 -399
- package/lib/detect.js +8 -18
- package/lib/diff/align.js +41 -113
- package/lib/diff/diff.js +12 -43
- package/lib/diff/display.js +25 -36
- package/lib/diff/edit.js +6 -20
- package/lib/diff/inline.js +138 -141
- package/lib/diff/items.js +33 -47
- package/lib/diff/parse.js +28 -56
- package/lib/diff/patch.js +12 -33
- package/lib/diff/unit.js +90 -206
- package/lib/editor.js +98 -55
- package/lib/files.js +86 -103
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +182 -344
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +141 -212
- package/lib/git.js +21 -49
- package/lib/github.js +67 -181
- package/lib/gitlab.js +40 -90
- package/lib/highlight/bash.js +55 -177
- package/lib/highlight/core.js +157 -132
- package/lib/highlight/css.js +25 -58
- package/lib/highlight/csv.js +19 -37
- package/lib/highlight/dart.js +72 -213
- package/lib/highlight/dot.js +16 -26
- package/lib/highlight/html.js +42 -63
- package/lib/highlight/js.js +177 -506
- package/lib/highlight/json.js +17 -37
- package/lib/highlight/log.js +22 -35
- package/lib/highlight/txt.js +9 -22
- package/lib/highlight.js +17 -46
- package/lib/keys.js +62 -85
- package/lib/manifest.js +67 -130
- package/lib/npm-commands.js +119 -189
- package/lib/remote.js +141 -197
- package/lib/render/branches.js +66 -73
- package/lib/render/chrome.js +264 -323
- package/lib/render/commits.js +187 -500
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +245 -0
- package/lib/render/dash-table.js +290 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -228
- package/lib/render/files.js +45 -99
- package/lib/render/frame.js +129 -183
- package/lib/render/notes.js +144 -160
- package/lib/render/npm.js +234 -112
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +131 -170
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/tiles.js +260 -0
- package/lib/render/unit.js +15 -28
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -38
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -78
- package/lib/report-test.js +256 -141
- package/lib/report-tools.js +96 -161
- package/lib/review-merge.js +114 -152
- package/lib/review.js +115 -189
- package/lib/runs.js +225 -0
- package/lib/select.js +89 -75
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +82 -63
- package/lib/session/branches.js +193 -247
- package/lib/session/change-actions.js +171 -214
- package/lib/session/commit.js +280 -342
- package/lib/session/compose.js +559 -674
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +164 -157
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +85 -53
- package/lib/session/items.js +73 -104
- package/lib/session/lifecycle.js +403 -541
- package/lib/session/load.js +48 -68
- package/lib/session/navigation.js +96 -87
- package/lib/session/npm.js +409 -345
- package/lib/session/ops.js +196 -63
- package/lib/session/pointer.js +23 -15
- package/lib/session/progress.js +33 -21
- package/lib/session/review.js +33 -54
- package/lib/session/tasks.js +333 -0
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -136
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +52 -83
- package/lib/session/watch.js +208 -204
- package/lib/session.js +112 -237
- package/lib/update.js +45 -116
- package/lib/utilities.js +67 -89
- package/lib/wrap.js +33 -44
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
package/lib/render/npm.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const ansi = require('../ansi.js');
|
|
4
|
+
const npmCommands = require('../npm-commands.js');
|
|
5
|
+
const wrap = require('../wrap.js');
|
|
4
6
|
const chrome = require('./chrome.js');
|
|
5
7
|
const primitives = require('./primitives.js');
|
|
6
|
-
const npmCommands = require('../npm-commands.js');
|
|
7
8
|
|
|
8
|
-
const { THEME, paint, visibleWidth, truncateVisible
|
|
9
|
-
const {
|
|
10
|
-
const {
|
|
9
|
+
const { THEME, CODE_FG, paint, visibleWidth, truncateVisible } = ansi;
|
|
10
|
+
const { trimVisible, seq, EL, RESET, fg } = ansi;
|
|
11
|
+
const { clipAnsi, stripAnsi, foregroundOn } = ansi;
|
|
11
12
|
const { TABLE_KEY, TABLE_VAL } = npmCommands;
|
|
12
|
-
const {
|
|
13
|
-
const {
|
|
13
|
+
const { wrapPlain } = wrap;
|
|
14
|
+
const { formatBusyStatus } = chrome;
|
|
15
|
+
const { fill, MARK_W, markPrefix, editSpan } = primitives;
|
|
16
|
+
const { paneResult, paintCursorList, fieldWindow } = primitives;
|
|
14
17
|
|
|
15
18
|
const EDGE = 2;
|
|
16
19
|
const TAIL = 1;
|
|
@@ -18,98 +21,140 @@ const LOG_PAD_Y = 1;
|
|
|
18
21
|
const LOG_PAD_X = 2;
|
|
19
22
|
const NPM_NAME_MAX = 24;
|
|
20
23
|
|
|
24
|
+
const TABLE_INK = {
|
|
25
|
+
actual: THEME.errorFg,
|
|
26
|
+
expected: THEME.addLineFg,
|
|
27
|
+
code: THEME.shaFg,
|
|
28
|
+
type: CODE_FG.className,
|
|
29
|
+
count: THEME.warnFg,
|
|
30
|
+
omitted: THEME.warnFg,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const COUNT_INK = {
|
|
34
|
+
failed: THEME.errorFg,
|
|
35
|
+
errors: THEME.errorFg,
|
|
36
|
+
passed: THEME.addLineFg,
|
|
37
|
+
};
|
|
38
|
+
|
|
21
39
|
const logViewRows = (bodyH) => {
|
|
22
40
|
const height = Math.max(1, bodyH);
|
|
23
41
|
if (height >= LOG_PAD_Y * 2 + 1) return height - LOG_PAD_Y * 2;
|
|
24
42
|
return height;
|
|
25
43
|
};
|
|
26
44
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const npmNameWidth = (commands) => {
|
|
30
|
-
let width = 0;
|
|
45
|
+
const npmNameWidth = (commands, typed = '') => {
|
|
46
|
+
let width = visibleWidth(typed);
|
|
31
47
|
for (const entry of commands) {
|
|
32
48
|
width = Math.max(width, visibleWidth(`${entry.name ?? ''}`));
|
|
33
49
|
}
|
|
34
50
|
return Math.min(NPM_NAME_MAX, width);
|
|
35
51
|
};
|
|
36
52
|
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const prefix = ` ${mark} `;
|
|
41
|
-
const prefixW = visibleWidth(prefix);
|
|
42
|
-
const rest = Math.max(1, inner - prefixW);
|
|
43
|
-
const detail = entry.kind === 'bin' ? 'bin' : entry.command;
|
|
44
|
-
const nameW = Math.min(Math.max(0, nameCol), rest);
|
|
45
|
-
const name = truncateVisible(entry.name, nameW);
|
|
53
|
+
const npmColumns = (width, nameCol) => {
|
|
54
|
+
const rest = Math.max(1, width - EDGE - TAIL - MARK_W);
|
|
55
|
+
const nameW = Math.min(nameCol, rest);
|
|
46
56
|
const gap = rest > nameW + 2 ? ' ' : '';
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
57
|
+
return { rest, nameW, gap, detailW: rest - nameW - gap.length };
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const paintNpmLine = (cols, name, detail, color, selected, bin) => {
|
|
61
|
+
const prefix = markPrefix(selected);
|
|
62
|
+
const namePad = ' '.repeat(Math.max(0, cols.nameW - visibleWidth(name)));
|
|
63
|
+
const mid = `${name}${namePad}`;
|
|
64
|
+
const after = `${cols.gap}${detail}`;
|
|
65
|
+
const pad = ' '.repeat(Math.max(0, cols.rest - visibleWidth(mid + after)));
|
|
55
66
|
const tail = ' '.repeat(TAIL);
|
|
67
|
+
const fgRgb = selected ? THEME.chromeFg : THEME.mutedFg;
|
|
68
|
+
const bgRgb = selected ? THEME.buttonBg : THEME.ctxBg;
|
|
56
69
|
const edge = fill(EDGE, fgRgb, THEME.ctxBg, color);
|
|
57
|
-
if (!color) return `${
|
|
70
|
+
if (!color) return `${prefix}${mid}${after}${pad}${tail}${edge}`;
|
|
71
|
+
const nameFg = bin ? THEME.shaFg : THEME.buttonHotFg;
|
|
58
72
|
let out = `${seq(fgRgb, bgRgb)}${EL}`;
|
|
59
73
|
out += paint(prefix, fgRgb, bgRgb, color);
|
|
60
|
-
const bin = entry.kind === 'bin';
|
|
61
|
-
const nameFg = bin ? THEME.shaFg : THEME.buttonHotFg;
|
|
62
74
|
out += paint(mid, nameFg, bgRgb, color, !bin);
|
|
63
|
-
out += paint(`${after}${
|
|
75
|
+
out += paint(`${after}${pad}${tail}`, fgRgb, bgRgb, color);
|
|
64
76
|
return out + edge;
|
|
65
77
|
};
|
|
66
78
|
|
|
79
|
+
const paintNpmRow = (entry, width, color, selected, nameCol) => {
|
|
80
|
+
const cols = npmColumns(width, nameCol);
|
|
81
|
+
const bin = entry.kind === 'bin';
|
|
82
|
+
const name = trimVisible(entry.name, cols.nameW);
|
|
83
|
+
const detail = trimVisible(bin ? 'bin' : entry.command, cols.detailW);
|
|
84
|
+
return paintNpmLine(cols, name, detail, color, selected, bin);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const editingName = (view) => view.npmEditField !== 'command';
|
|
88
|
+
|
|
89
|
+
const editWindow = (compose, live, draft, width) => {
|
|
90
|
+
const value = `${(live ? compose.text : draft) ?? ''}`.replaceAll('\n', ' ');
|
|
91
|
+
const win = live
|
|
92
|
+
? fieldWindow(value, compose.cursor, compose.scrollCol, width)
|
|
93
|
+
: fieldWindow(value, 0, 0, width);
|
|
94
|
+
return { ...win, value };
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const paintNpmEdit = (view, width, color, nameCol) => {
|
|
98
|
+
const { compose } = view;
|
|
99
|
+
const isName = editingName(view);
|
|
100
|
+
const cols = npmColumns(width, nameCol);
|
|
101
|
+
const { npmDraftName: draftName, npmDraftCommand: draftCommand } = view;
|
|
102
|
+
const name = editWindow(compose, isName, draftName, cols.nameW);
|
|
103
|
+
const command = editWindow(compose, !isName, draftCommand, cols.detailW);
|
|
104
|
+
const row = paintNpmLine(cols, name.text, command.text, color, true, false);
|
|
105
|
+
const nameX = MARK_W + 1;
|
|
106
|
+
const commandX = nameX + cols.nameW + cols.gap.length;
|
|
107
|
+
const active = isName ? name : command;
|
|
108
|
+
const cursor = {
|
|
109
|
+
x: (isName ? nameX : commandX) + active.col,
|
|
110
|
+
scroll: active.scroll,
|
|
111
|
+
};
|
|
112
|
+
const edits = [
|
|
113
|
+
{
|
|
114
|
+
field: 'name',
|
|
115
|
+
...editSpan(1, nameX, commandX, 0, name.value),
|
|
116
|
+
scroll: name.scroll,
|
|
117
|
+
live: isName,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
field: 'command',
|
|
121
|
+
...editSpan(commandX, commandX, width + 1, 0, command.value),
|
|
122
|
+
scroll: command.scroll,
|
|
123
|
+
live: !isName,
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
return { row, cursor, edits };
|
|
127
|
+
};
|
|
128
|
+
|
|
67
129
|
const paintNpmList = (view, width, color, bodyH, headerLines) => {
|
|
68
130
|
const commands = view.npmCommands ?? [];
|
|
69
|
-
const
|
|
131
|
+
const { compose } = view;
|
|
132
|
+
const editing = compose?.kind === 'npm';
|
|
133
|
+
const typed = editingName(view) ? compose?.text : view.npmDraftName;
|
|
134
|
+
const nameW = npmNameWidth(commands, editing ? `${typed ?? ''}` : '');
|
|
70
135
|
const cursor = view.npmCursor ?? 0;
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
paintNpmRow(entry, rowWidth, rowColor, selected, nameW);
|
|
136
|
+
const pane = { width, color, bodyH, headerLines, offset: view.listScroll };
|
|
137
|
+
const paintRow = (entry, selected) =>
|
|
138
|
+
paintNpmRow(entry, width, color, selected, nameW);
|
|
75
139
|
let extra = null;
|
|
76
140
|
if (editing) {
|
|
77
|
-
const painted =
|
|
141
|
+
const painted = paintNpmEdit(view, width, color, nameW);
|
|
78
142
|
const at = view.npmEditName ? 'replace' : 'end';
|
|
79
|
-
extra = {
|
|
143
|
+
extra = { ...painted, at, index: cursor };
|
|
80
144
|
}
|
|
81
|
-
return paintCursorList(
|
|
82
|
-
commands,
|
|
83
|
-
cursor,
|
|
84
|
-
width,
|
|
85
|
-
color,
|
|
86
|
-
bodyH,
|
|
87
|
-
headerLines,
|
|
88
|
-
paintRow,
|
|
89
|
-
extra,
|
|
90
|
-
view.listScroll,
|
|
91
|
-
);
|
|
145
|
+
return paintCursorList(commands, cursor, pane, paintRow, extra);
|
|
92
146
|
};
|
|
93
147
|
|
|
94
148
|
const logStart = (view, count, rows) => {
|
|
95
149
|
const maxStart = Math.max(0, count - rows);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (start > maxStart) start = maxStart;
|
|
99
|
-
if (start < 0) start = 0;
|
|
100
|
-
return start;
|
|
150
|
+
const start = view.npmFollow ? maxStart : view.npmScroll;
|
|
151
|
+
return Math.max(0, Math.min(start ?? 0, maxStart));
|
|
101
152
|
};
|
|
102
153
|
|
|
103
154
|
const isTableLine = (line) => `${line ?? ''}`.startsWith(TABLE_KEY);
|
|
104
155
|
|
|
105
|
-
const mixRgb = (from, to, part) =>
|
|
106
|
-
|
|
107
|
-
for (let i = 0; i < 3; i++) {
|
|
108
|
-
const next = from[i] + (to[i] - from[i]) * part;
|
|
109
|
-
out[i] = Math.round(next);
|
|
110
|
-
}
|
|
111
|
-
return out;
|
|
112
|
-
};
|
|
156
|
+
const mixRgb = (from, to, part) =>
|
|
157
|
+
from.map((value, i) => Math.round(value + (to[i] - value) * part));
|
|
113
158
|
|
|
114
159
|
const tableTone = (index) => {
|
|
115
160
|
const lift = index % 2 === 0 ? 0.035 : 0.07;
|
|
@@ -120,65 +165,157 @@ const tableTone = (index) => {
|
|
|
120
165
|
};
|
|
121
166
|
|
|
122
167
|
const tableIndex = (lines, index) => {
|
|
123
|
-
let at = index;
|
|
124
168
|
let row = 0;
|
|
125
|
-
while (
|
|
126
|
-
at -= 1;
|
|
127
|
-
row += 1;
|
|
128
|
-
}
|
|
169
|
+
while (index - row > 0 && isTableLine(lines[index - row - 1])) row += 1;
|
|
129
170
|
return row;
|
|
130
171
|
};
|
|
131
172
|
|
|
132
|
-
const
|
|
173
|
+
const tableInk = (key, value) => {
|
|
174
|
+
const name = key.trim();
|
|
175
|
+
if (Object.hasOwn(COUNT_INK, name)) {
|
|
176
|
+
return Number(value) > 0 ? COUNT_INK[name] : THEME.mutedFg;
|
|
177
|
+
}
|
|
178
|
+
return Object.hasOwn(TABLE_INK, name) ? TABLE_INK[name] : THEME.chromeFg;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const tableParts = (line, width) => {
|
|
133
182
|
const raw = line.slice(TABLE_KEY.length);
|
|
134
183
|
const at = raw.indexOf(TABLE_VAL);
|
|
135
184
|
const key = at < 0 ? raw : raw.slice(0, at);
|
|
136
185
|
const rest = at < 0 ? '' : raw.slice(at + TABLE_VAL.length);
|
|
137
186
|
const gap = rest.startsWith(' ') ? ' ' : '';
|
|
138
187
|
const value = rest.slice(gap.length);
|
|
139
|
-
const edge = 1;
|
|
140
|
-
const inner = Math.max(
|
|
141
|
-
const keyW = visibleWidth(key);
|
|
142
|
-
const gapW = visibleWidth(gap);
|
|
188
|
+
const edge = Math.min(1, Math.floor(width / 2));
|
|
189
|
+
const inner = Math.max(0, width - edge * 2);
|
|
190
|
+
const keyW = Math.min(visibleWidth(key), inner);
|
|
191
|
+
const gapW = Math.min(visibleWidth(gap), Math.max(0, inner - keyW));
|
|
143
192
|
const valueW = Math.max(0, inner - keyW - gapW);
|
|
144
|
-
|
|
145
|
-
|
|
193
|
+
return { key, gap, value, edge, keyW, gapW, valueW };
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const wrapTableLine = (line, width) => {
|
|
197
|
+
const part = tableParts(line, width);
|
|
198
|
+
if (part.valueW < 1) return [line];
|
|
199
|
+
const trimmed = part.value.trimEnd();
|
|
200
|
+
const lead = trimmed.startsWith(' ') ? ' ' : '';
|
|
201
|
+
const body = trimmed.slice(lead.length);
|
|
202
|
+
const budget = Math.max(1, part.valueW - visibleWidth(lead));
|
|
203
|
+
if (visibleWidth(body) <= budget) return [line];
|
|
204
|
+
const blank = ' '.repeat(visibleWidth(part.key));
|
|
205
|
+
return wrapPlain(body, budget).map((piece, index) => {
|
|
206
|
+
const name = index === 0 ? part.key : blank;
|
|
207
|
+
return `${TABLE_KEY}${name}${TABLE_VAL}${part.gap}${lead}${piece}`;
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const wrapLogText = (line, inner) => {
|
|
212
|
+
const mark = line.startsWith('│ ') ? '│ ' : '';
|
|
213
|
+
const rest = line.slice(mark.length);
|
|
214
|
+
const budget = Math.max(1, inner - visibleWidth(mark));
|
|
215
|
+
if (visibleWidth(rest) <= budget) return [line];
|
|
216
|
+
return wrapPlain(rest, budget).map((piece) => `${mark}${piece}`);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const expandLogLines = (text, width) => {
|
|
220
|
+
const lines = `${text ?? ''}`.split('\n');
|
|
221
|
+
if (lines.at(-1) === '') lines.pop();
|
|
222
|
+
const inner = Math.max(1, width - LOG_PAD_X * 2);
|
|
223
|
+
return lines.flatMap((line) => {
|
|
224
|
+
if (isTableLine(line)) return wrapTableLine(line, width);
|
|
225
|
+
return wrapLogText(line, inner);
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const paintPlainTable = (line, width) => {
|
|
230
|
+
const part = tableParts(line, width);
|
|
231
|
+
const name = trimVisible(part.key, part.keyW);
|
|
232
|
+
const namePad = ' '.repeat(Math.max(0, part.keyW - visibleWidth(name)));
|
|
233
|
+
const shown = trimVisible(part.value, part.valueW);
|
|
234
|
+
const pad = ' '.repeat(Math.max(0, part.valueW - visibleWidth(shown)));
|
|
235
|
+
const edge = ' '.repeat(part.edge);
|
|
236
|
+
const gap = part.gap.slice(0, part.gapW);
|
|
237
|
+
return `${edge}${name}${namePad}${gap}${shown}${pad}${edge}`;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const paintTableLine = (line, width, index) => {
|
|
241
|
+
const part = tableParts(line, width);
|
|
242
|
+
const shownKey = trimVisible(part.key, part.keyW);
|
|
243
|
+
const shown = trimVisible(part.value, part.valueW);
|
|
244
|
+
const pad = ' '.repeat(Math.max(0, part.valueW - visibleWidth(shown)));
|
|
146
245
|
const tone = tableTone(index);
|
|
147
246
|
const ink = THEME.ctxFg;
|
|
148
|
-
|
|
149
|
-
out
|
|
150
|
-
out += paint(
|
|
151
|
-
out += paint(
|
|
152
|
-
|
|
247
|
+
const valueFg = tableInk(part.key, part.value);
|
|
248
|
+
let out = fill(part.edge, ink, tone.frame, true);
|
|
249
|
+
out += paint(shownKey, ink, tone.keyBg, true);
|
|
250
|
+
out += paint(part.gap.slice(0, part.gapW), ink, tone.frame, true);
|
|
251
|
+
out += paint(`${shown}${pad}`, valueFg, tone.valueBg, true);
|
|
252
|
+
return out + fill(part.edge, ink, tone.frame, true);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const paintLogSource = (line) => {
|
|
256
|
+
if (line !== stripAnsi(line)) return line;
|
|
257
|
+
if (/^[✖✔△] /.test(line)) {
|
|
258
|
+
const ink = line[0] === '✔' ? THEME.addLineFg : THEME.errorFg;
|
|
259
|
+
const color = line[0] === '△' ? THEME.warnFg : ink;
|
|
260
|
+
return paint(line, color, THEME.ctxBg, true, true);
|
|
261
|
+
}
|
|
262
|
+
if (line.startsWith('│')) {
|
|
263
|
+
return `${fg(THEME.shaFg)}│${fg(THEME.ctxFg)}${line.slice(1)}`;
|
|
264
|
+
}
|
|
265
|
+
if (/^(Stack|Related failures|Stderr)$/.test(line)) {
|
|
266
|
+
return paint(line, THEME.chromeFg, THEME.ctxBg, true, true);
|
|
267
|
+
}
|
|
268
|
+
if (!/^\s+(at|↳)\s/.test(line)) return line;
|
|
269
|
+
const source = line.replace(
|
|
270
|
+
/([^\s()|]+)(:\d+:\d+)(?=[\s)|]|$)/g,
|
|
271
|
+
(match, file, position) => {
|
|
272
|
+
const path = `${fg(THEME.shaFg)}${file}`;
|
|
273
|
+
const point = `${fg(THEME.mutedFg)}${position}`;
|
|
274
|
+
return `${path}${point}${fg(THEME.ctxFg)}`;
|
|
275
|
+
},
|
|
276
|
+
);
|
|
277
|
+
const frame = /^(\s+at\s+)(.*?)(\s+\(.+\))$/.exec(source);
|
|
278
|
+
if (!frame) return source;
|
|
279
|
+
return (
|
|
280
|
+
`${fg(THEME.mutedFg)}${frame[1]}${fg(CODE_FG.function)}${frame[2]}` +
|
|
281
|
+
`${fg(THEME.ctxFg)}${frame[3]}`
|
|
282
|
+
);
|
|
153
283
|
};
|
|
154
284
|
|
|
155
285
|
const paintLogLine = (line, width, color, fgRgb = THEME.ctxFg) => {
|
|
156
286
|
const inner = Math.max(1, width - LOG_PAD_X * 2);
|
|
157
|
-
const source = color ? `${line ?? ''}` : stripAnsi(line);
|
|
158
|
-
const clip = (value) =>
|
|
159
|
-
color ? clipAnsi(value, inner) : truncateVisible(value, inner);
|
|
160
|
-
const body = color ? foregroundOn(clip(source), THEME.ctxBg) : clip(source);
|
|
161
287
|
const lead = ' '.repeat(LOG_PAD_X);
|
|
288
|
+
if (!color) {
|
|
289
|
+
const body = truncateVisible(stripAnsi(line), inner);
|
|
290
|
+
const pad = Math.max(0, width - LOG_PAD_X - visibleWidth(body));
|
|
291
|
+
return `${lead}${body}${' '.repeat(pad)}`;
|
|
292
|
+
}
|
|
293
|
+
const source = paintLogSource(`${line ?? ''}`);
|
|
294
|
+
const body = foregroundOn(clipAnsi(source, inner), THEME.ctxBg);
|
|
162
295
|
const pad = Math.max(0, width - LOG_PAD_X - visibleWidth(body));
|
|
163
|
-
const tail = ' '.repeat(pad);
|
|
164
|
-
if (!color) return `${lead}${body}${tail}`;
|
|
165
296
|
const base = seq(fgRgb, THEME.ctxBg);
|
|
166
297
|
let out = `${base}${EL}${lead}${body}`;
|
|
167
|
-
if (pad) out += `${RESET}${base}${
|
|
298
|
+
if (pad) out += `${RESET}${base}${' '.repeat(pad)}`;
|
|
168
299
|
return `${out}${RESET}`;
|
|
169
300
|
};
|
|
170
301
|
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
302
|
+
const paintLogRow = (view, lines, index, width, color) => {
|
|
303
|
+
if (index < lines.length) {
|
|
304
|
+
const line = lines[index];
|
|
305
|
+
if (!isTableLine(line)) return paintLogLine(line, width, color);
|
|
306
|
+
if (!color) return paintPlainTable(line, width);
|
|
307
|
+
return paintTableLine(line, width, tableIndex(lines, index));
|
|
308
|
+
}
|
|
309
|
+
if (view.npmRunning === true && index === lines.length) {
|
|
310
|
+
const label = formatBusyStatus('running', view.progressFrame ?? 0);
|
|
311
|
+
return paintLogLine(label, width, color, THEME.chromeFg);
|
|
312
|
+
}
|
|
313
|
+
return fill(width, THEME.ctxFg, THEME.ctxBg, color);
|
|
174
314
|
};
|
|
175
315
|
|
|
176
316
|
const paintNpmLog = (view, width, color, bodyH) => {
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
if (lines.length && lines.at(-1) === '') lines.pop();
|
|
180
|
-
const running = view.npmRunning === true;
|
|
181
|
-
const count = lines.length + (running ? 1 : 0);
|
|
317
|
+
const lines = expandLogLines(view.npmOutput ?? '', width);
|
|
318
|
+
const count = lines.length + (view.npmRunning === true ? 1 : 0);
|
|
182
319
|
const rows = logViewRows(bodyH);
|
|
183
320
|
const padY = bodyH - rows;
|
|
184
321
|
const top = padY ? 1 : 0;
|
|
@@ -187,25 +324,10 @@ const paintNpmLog = (view, width, color, bodyH) => {
|
|
|
187
324
|
const body = [];
|
|
188
325
|
for (let i = 0; i < top; i++) body.push(blank);
|
|
189
326
|
for (let i = 0; i < rows; i++) {
|
|
190
|
-
|
|
191
|
-
if (index < lines.length) {
|
|
192
|
-
const line = lines[index];
|
|
193
|
-
if (color && isTableLine(line)) {
|
|
194
|
-
const row = tableIndex(lines, index);
|
|
195
|
-
body.push(paintTableLine(line, width, row));
|
|
196
|
-
} else {
|
|
197
|
-
body.push(paintLogLine(line, width, color));
|
|
198
|
-
}
|
|
199
|
-
} else if (running && index === lines.length) {
|
|
200
|
-
body.push(paintRunBar(width, color, view.progressFrame ?? 0));
|
|
201
|
-
} else {
|
|
202
|
-
body.push(blank);
|
|
203
|
-
}
|
|
327
|
+
body.push(paintLogRow(view, lines, start + i, width, color));
|
|
204
328
|
}
|
|
205
329
|
for (let i = 0; i < padY - top; i++) body.push(blank);
|
|
206
|
-
return paneResult({
|
|
207
|
-
body,
|
|
208
|
-
});
|
|
330
|
+
return paneResult({ body });
|
|
209
331
|
};
|
|
210
332
|
|
|
211
333
|
const paintBodyNpm = (view, width, color, bodyH, headerLines) => {
|
|
@@ -213,4 +335,4 @@ const paintBodyNpm = (view, width, color, bodyH, headerLines) => {
|
|
|
213
335
|
return paintNpmList(view, width, color, bodyH, headerLines);
|
|
214
336
|
};
|
|
215
337
|
|
|
216
|
-
module.exports = { paintBodyNpm, logViewRows };
|
|
338
|
+
module.exports = { paintBodyNpm, logViewRows, expandLogLines };
|
package/lib/render/present.js
CHANGED
|
@@ -10,17 +10,10 @@ const presentCursor = (cursor) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
const presentRows = (rows, options = {}) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
for (let i = 0; i < rows.length; i++) {
|
|
18
|
-
parts.push(`${ESC}[${i + 1};1H`);
|
|
19
|
-
parts.push(rows[i]);
|
|
20
|
-
}
|
|
21
|
-
parts.push(`${ESC}[?2026l`);
|
|
22
|
-
parts.push(presentCursor(cursor));
|
|
23
|
-
return parts.join('');
|
|
13
|
+
let out = `${ESC}[?25l${ESC}[?2026h`;
|
|
14
|
+
if (options.clear === true) out += `${ESC}[H${ESC}[2J`;
|
|
15
|
+
for (let i = 0; i < rows.length; i++) out += `${ESC}[${i + 1};1H${rows[i]}`;
|
|
16
|
+
return `${out}${ESC}[?2026l${presentCursor(options.cursor)}`;
|
|
24
17
|
};
|
|
25
18
|
|
|
26
19
|
module.exports = { presentCursor, presentRows };
|