reslop 0.2.5 → 0.2.7
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 +22 -1
- package/LICENSE +1 -1
- package/README.md +11 -11
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +72 -19
- package/lib/api.js +1 -1
- package/lib/capabilities.js +8 -8
- package/lib/cli.js +61 -75
- package/lib/clipboard.js +39 -47
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +357 -0
- package/lib/dashboard/npm.js +290 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +197 -402
- package/lib/deps.js +113 -240
- 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 +76 -144
- 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 +79 -178
- package/lib/editor.js +52 -69
- package/lib/files.js +79 -91
- package/lib/find.js +61 -0
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +148 -272
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +161 -214
- 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 +155 -141
- 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 +14 -14
- 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 +19 -25
- package/lib/highlight/txt.js +7 -10
- package/lib/highlight.js +17 -46
- package/lib/keys.js +75 -83
- package/lib/manifest.js +67 -126
- package/lib/npm-commands.js +120 -169
- package/lib/remote.js +140 -190
- package/lib/render/branches.js +63 -61
- package/lib/render/chrome.js +412 -347
- package/lib/render/commits.js +160 -361
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +496 -0
- package/lib/render/dash-table.js +295 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -258
- package/lib/render/files.js +60 -86
- package/lib/render/frame.js +82 -117
- package/lib/render/notes.js +150 -210
- package/lib/render/npm.js +213 -177
- package/lib/render/packages.js +93 -0
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +77 -172
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/repos.js +226 -0
- package/lib/render/search.js +25 -0
- package/lib/render/tiles.js +355 -0
- package/lib/render/unit.js +15 -31
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -37
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -77
- package/lib/report-test.js +221 -99
- package/lib/report-tools.js +96 -154
- package/lib/review-merge.js +33 -41
- package/lib/review.js +69 -129
- package/lib/runs.js +225 -0
- package/lib/select.js +53 -91
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +189 -65
- package/lib/session/branches.js +164 -222
- package/lib/session/change-actions.js +49 -119
- package/lib/session/commit.js +298 -352
- package/lib/session/compose.js +572 -715
- package/lib/session/dashboard.js +530 -0
- package/lib/session/dispatch.js +197 -171
- package/lib/session/files-pane.js +92 -45
- package/lib/session/find.js +94 -0
- package/lib/session/items.js +6 -17
- package/lib/session/lifecycle.js +420 -466
- package/lib/session/load.js +1 -14
- package/lib/session/navigation.js +4 -2
- package/lib/session/npm.js +403 -420
- package/lib/session/ops.js +5 -13
- package/lib/session/packages.js +143 -0
- package/lib/session/pointer.js +30 -14
- package/lib/session/progress.js +39 -30
- package/lib/session/review.js +1 -3
- package/lib/session/tasks.js +277 -236
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -132
- package/lib/session/view.js +59 -80
- package/lib/session/watch.js +201 -212
- package/lib/session/workspace.js +455 -0
- package/lib/session.js +95 -161
- package/lib/update.js +44 -111
- package/lib/utilities.js +46 -88
- package/lib/workspace.js +166 -0
- package/lib/wrap.js +29 -55
- package/package.json +1 -1
package/lib/render/files.js
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
const ansi = require('../ansi.js');
|
|
4
4
|
const files = require('../files.js');
|
|
5
5
|
const primitives = require('./primitives.js');
|
|
6
|
-
const { measureColumns, padColumns } = primitives;
|
|
7
6
|
|
|
8
7
|
const { isTasksEntry, shortAge } = files;
|
|
9
|
-
const { THEME, paint, visibleWidth,
|
|
10
|
-
const { fill,
|
|
8
|
+
const { THEME, paint, visibleWidth, trimVisible, seq, EL } = ansi;
|
|
9
|
+
const { fill, markPrefix, paintCursorList } = primitives;
|
|
10
|
+
const { measureColumns, padColumns } = primitives;
|
|
11
|
+
const searchPaint = require('./search.js');
|
|
12
|
+
const { paintPathText } = searchPaint;
|
|
13
|
+
const locate = require('../find.js');
|
|
14
|
+
const { activeHit, spansFor } = locate;
|
|
11
15
|
|
|
12
16
|
const FILE_STATUS_FG = {
|
|
13
17
|
unstaged: THEME.delLineFg,
|
|
@@ -27,115 +31,85 @@ const FILE_COL_ALIGN = {
|
|
|
27
31
|
|
|
28
32
|
const FILE_DATE_GAP = ' ';
|
|
29
33
|
|
|
30
|
-
const signedCount = (sign, n) => `${sign}${n ?? 0}`;
|
|
31
|
-
|
|
32
34
|
const fileRowFields = (entry) => {
|
|
35
|
+
const n = `${entry.staged ?? 0}`;
|
|
36
|
+
const m = `${entry.remaining ?? 0}`;
|
|
33
37
|
if (isTasksEntry(entry)) {
|
|
34
|
-
const n = `${entry.staged ?? 0}`;
|
|
35
|
-
const m = `${entry.remaining ?? 0}`;
|
|
36
38
|
return { add: '', del: '', status: '', n, m, date: '' };
|
|
37
39
|
}
|
|
38
|
-
const {
|
|
39
|
-
const
|
|
40
|
-
const del = signedCount('-', removed);
|
|
40
|
+
const add = `+${entry.added ?? 0}`;
|
|
41
|
+
const del = `-${entry.removed ?? 0}`;
|
|
41
42
|
const status = entry.status ?? '';
|
|
42
|
-
|
|
43
|
-
const m = `${remaining ?? 0}`;
|
|
44
|
-
const date = shortAge(entry.date ?? '');
|
|
45
|
-
return { add, del, status, n, m, date };
|
|
43
|
+
return { add, del, status, n, m, date: shortAge(entry.date) };
|
|
46
44
|
};
|
|
47
45
|
|
|
48
|
-
const fileRowFg = (
|
|
49
|
-
|
|
46
|
+
const fileRowFg = (entry, selected) => {
|
|
47
|
+
if (isTasksEntry(entry)) return THEME.buttonHotFg;
|
|
48
|
+
const statusFg = FILE_STATUS_FG[entry.status];
|
|
50
49
|
if (statusFg) return statusFg;
|
|
51
|
-
|
|
52
|
-
return THEME.mutedFg;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const joinFileDate = (parts, cols) => {
|
|
56
|
-
if (!cols?.date) return '';
|
|
57
|
-
return `${FILE_DATE_GAP}${parts.date}`;
|
|
50
|
+
return selected ? THEME.chromeFg : THEME.mutedFg;
|
|
58
51
|
};
|
|
59
52
|
|
|
60
|
-
const
|
|
61
|
-
const { add, del, status, n, m } = parts;
|
|
62
|
-
return ` ${add} ${del} ${status} ${n}/${m}`;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const paintFileSuffix = (parts, cols, fgRgb, bgRgb, color) => {
|
|
66
|
-
const { add, del, status, n, m } = parts;
|
|
53
|
+
const paintFileMeta = (parts, fgRgb, bgRgb, color) => {
|
|
67
54
|
const gap = paint(' ', fgRgb, bgRgb, color);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const counts = addText + gap + delText;
|
|
75
|
-
const meta = statusText + gap + nText + slash + mText;
|
|
76
|
-
if (!cols?.date) return gap + counts + gap + meta;
|
|
77
|
-
const dateGap = paint(FILE_DATE_GAP, fgRgb, bgRgb, color);
|
|
78
|
-
const age = paint(parts.date, THEME.mutedFg, bgRgb, color);
|
|
79
|
-
return gap + counts + gap + meta + dateGap + age;
|
|
55
|
+
let out = gap + paint(parts.add, THEME.addLineFg, bgRgb, color);
|
|
56
|
+
out += gap + paint(parts.del, THEME.delLineFg, bgRgb, color);
|
|
57
|
+
out += gap + paint(parts.status, fgRgb, bgRgb, color);
|
|
58
|
+
out += gap + paint(parts.n, fgRgb, bgRgb, color);
|
|
59
|
+
out += paint('/', fgRgb, bgRgb, color);
|
|
60
|
+
return out + paint(parts.m, fgRgb, bgRgb, color);
|
|
80
61
|
};
|
|
81
62
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
const parts = padColumns(fileRowFields(entry), cols, FILE_COL_ALIGN);
|
|
87
|
-
const meta = joinFileMeta(parts);
|
|
88
|
-
const dated = joinFileDate(parts, cols);
|
|
89
|
-
const suffix = `${meta}${dated}`;
|
|
90
|
-
const pathW = Math.max(1, inner - visibleWidth(prefix + suffix));
|
|
91
|
-
const clipped = truncateVisible(entry.path, pathW);
|
|
92
|
-
const pad = Math.max(0, pathW - visibleWidth(clipped));
|
|
93
|
-
const left = `${prefix}${clipped}${' '.repeat(pad)}`;
|
|
94
|
-
const fgRgb = THEME.buttonHotFg;
|
|
95
|
-
const bgRgb = selected ? THEME.buttonBg : THEME.ctxBg;
|
|
96
|
-
const edge = fill(1, fgRgb, bgRgb, color);
|
|
97
|
-
if (!color) return `${left}${suffix}${edge}`;
|
|
98
|
-
let out = `${seq(fgRgb, bgRgb)}${EL}`;
|
|
99
|
-
out += paint(left, fgRgb, bgRgb, color, true);
|
|
100
|
-
out += paint(meta, fgRgb, bgRgb, color, true);
|
|
101
|
-
if (!dated) return out + edge;
|
|
102
|
-
out += paint(FILE_DATE_GAP, fgRgb, bgRgb, color);
|
|
103
|
-
out += paint(parts.date, THEME.mutedFg, bgRgb, color);
|
|
104
|
-
return out + edge;
|
|
63
|
+
const rowSpans = (entry, path, marks) => {
|
|
64
|
+
if (!marks || !marks.query) return [];
|
|
65
|
+
const hit = marks.hit && marks.hit.index === marks.index ? marks.hit : null;
|
|
66
|
+
return spansFor(path, entry.path ?? '', marks.query, hit);
|
|
105
67
|
};
|
|
106
68
|
|
|
107
|
-
const paintFileRow = (entry, width, color, selected, cols) => {
|
|
108
|
-
|
|
109
|
-
return paintTodosRow(entry, width, color, selected, cols);
|
|
110
|
-
}
|
|
69
|
+
const paintFileRow = (entry, width, color, selected, cols, marks) => {
|
|
70
|
+
const tasks = isTasksEntry(entry);
|
|
111
71
|
const inner = Math.max(1, width - 1);
|
|
112
|
-
const
|
|
113
|
-
const prefix = ` ${mark} `;
|
|
72
|
+
const prefix = markPrefix(selected);
|
|
114
73
|
const parts = padColumns(fileRowFields(entry), cols, FILE_COL_ALIGN);
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
const
|
|
74
|
+
const { add, del, status, n, m } = parts;
|
|
75
|
+
const meta = ` ${add} ${del} ${status} ${n}/${m}`;
|
|
76
|
+
const date = cols.date ? `${FILE_DATE_GAP}${parts.date}` : '';
|
|
77
|
+
const pathW = Math.max(1, inner - visibleWidth(prefix + meta + date));
|
|
78
|
+
const path = trimVisible(entry.path, pathW);
|
|
79
|
+
const pad = ' '.repeat(Math.max(0, pathW - visibleWidth(path)));
|
|
80
|
+
const left = `${prefix}${path}${pad}`;
|
|
81
|
+
const fgRgb = fileRowFg(entry, selected);
|
|
122
82
|
const bgRgb = selected ? THEME.buttonBg : THEME.ctxBg;
|
|
123
83
|
const edge = fill(1, fgRgb, bgRgb, color);
|
|
124
|
-
if (!color) return `${left}${
|
|
84
|
+
if (!color) return `${left}${meta}${date}${edge}`;
|
|
85
|
+
const spans = rowSpans(entry, path, marks);
|
|
125
86
|
let out = `${seq(fgRgb, bgRgb)}${EL}`;
|
|
126
|
-
out += paint(
|
|
127
|
-
out +=
|
|
87
|
+
out += paint(prefix, fgRgb, bgRgb, color, tasks);
|
|
88
|
+
out += paintPathText(path, fgRgb, bgRgb, color, tasks, spans);
|
|
89
|
+
out += paint(pad, fgRgb, bgRgb, color, tasks);
|
|
90
|
+
if (tasks) out += paint(meta, fgRgb, bgRgb, color, true);
|
|
91
|
+
else out += paintFileMeta(parts, fgRgb, bgRgb, color);
|
|
92
|
+
if (date) {
|
|
93
|
+
out += paint(FILE_DATE_GAP, fgRgb, bgRgb, color);
|
|
94
|
+
out += paint(parts.date, THEME.mutedFg, bgRgb, color);
|
|
95
|
+
}
|
|
128
96
|
return out + edge;
|
|
129
97
|
};
|
|
130
98
|
|
|
131
99
|
const paintBodyFiles = (view, width, color, bodyH, headerLines) => {
|
|
132
|
-
const
|
|
133
|
-
const cols = measureColumns(
|
|
100
|
+
const entries = view.files ?? [];
|
|
101
|
+
const cols = measureColumns(entries, fileRowFields, FILE_COL_ALIGN);
|
|
134
102
|
const cursor = view.fileCursor ?? 0;
|
|
135
103
|
const pane = { width, color, bodyH, headerLines, offset: view.listScroll };
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
104
|
+
const hit = activeHit(entries, view.find);
|
|
105
|
+
const query = view.find && view.find.query ? view.find.query : '';
|
|
106
|
+
const paintRow = (entry, selected, index) =>
|
|
107
|
+
paintFileRow(entry, width, color, selected, cols, {
|
|
108
|
+
query,
|
|
109
|
+
hit,
|
|
110
|
+
index,
|
|
111
|
+
});
|
|
112
|
+
return paintCursorList(entries, cursor, pane, paintRow);
|
|
139
113
|
};
|
|
140
114
|
|
|
141
115
|
module.exports = { paintBodyFiles };
|
package/lib/render/frame.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const ansi = require('../ansi.js');
|
|
4
4
|
const select = require('../select.js');
|
|
5
|
-
const { overlayRows, markEditorSelection } = select;
|
|
6
5
|
const primitives = require('./primitives.js');
|
|
7
6
|
const chrome = require('./chrome.js');
|
|
8
7
|
const files = require('./files.js');
|
|
@@ -12,91 +11,58 @@ const notes = require('./notes.js');
|
|
|
12
11
|
const npm = require('./npm.js');
|
|
13
12
|
const diff = require('./diff.js');
|
|
14
13
|
const unit = require('./unit.js');
|
|
14
|
+
const dashboard = require('./dashboard.js');
|
|
15
|
+
const packages = require('./packages.js');
|
|
16
|
+
const repos = require('./repos.js');
|
|
15
17
|
|
|
16
18
|
const { RESET } = ansi;
|
|
17
|
-
const {
|
|
19
|
+
const { overlayRows, markEditorSelection } = select;
|
|
20
|
+
const { isListPane, isTaskView, paintBodyFill, paneResult } = primitives;
|
|
18
21
|
const { paintHeader, paintFooter, footerHits, paintStatusLine } = chrome;
|
|
19
22
|
const { footerLayout, statusBranchHit, statusChoiceHits } = chrome;
|
|
20
23
|
const { paintNotePanel, paintBodyTodo } = notes;
|
|
21
|
-
const { paintBodyFiles } = files;
|
|
22
|
-
const { paintBodyBranches } = branches;
|
|
23
|
-
const { paintBodyCommits } = commits;
|
|
24
|
-
const { paintBodyNpm } = npm;
|
|
25
24
|
const { paintBodyDiff } = diff;
|
|
26
|
-
const { paintBodyUnit } = unit;
|
|
27
25
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
const PANE_BODY = {
|
|
27
|
+
dashboard: dashboard.paintBodyDashboard,
|
|
28
|
+
repos: repos.paintBodyRepos,
|
|
29
|
+
files: files.paintBodyFiles,
|
|
30
|
+
branches: branches.paintBodyBranches,
|
|
31
|
+
commits: commits.paintBodyCommits,
|
|
32
|
+
npm: npm.paintBodyNpm,
|
|
33
|
+
packages: packages.paintBodyPackages,
|
|
34
|
+
unit: unit.paintBodyUnit,
|
|
35
|
+
tasks: paintBodyTodo,
|
|
38
36
|
};
|
|
39
37
|
|
|
40
38
|
const paintBodyEmpty = () => paneResult();
|
|
41
39
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
npm: paintBodyNpm,
|
|
47
|
-
empty: paintBodyEmpty,
|
|
48
|
-
tasks: paintBodyTodo,
|
|
49
|
-
diff: paintBodyDiff,
|
|
50
|
-
unit: paintBodyUnit,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const paintFrameBody = (view, width, color, bodyH, headerLines) => {
|
|
54
|
-
const paint = BODY_PAINT[bodyKind(view)];
|
|
55
|
-
return paint(view, width, color, bodyH, headerLines);
|
|
40
|
+
const bodyPainter = (view) => {
|
|
41
|
+
if (Object.hasOwn(PANE_BODY, view.pane)) return PANE_BODY[view.pane];
|
|
42
|
+
if (!view.item) return paintBodyEmpty;
|
|
43
|
+
return paintBodyDiff;
|
|
56
44
|
};
|
|
57
45
|
|
|
58
46
|
const frameNotes = (view, width, height, color) => {
|
|
59
47
|
const notesCap = Math.max(0, height - 4);
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
return { notesWanted, noteRows, noteCursor, bodyH };
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const bodyFillKind = (listPane, splitBody) => {
|
|
70
|
-
if (listPane) return 'files';
|
|
71
|
-
if (splitBody) return 'split';
|
|
72
|
-
return 'plain';
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const ownerSpan = (owners, focus) => {
|
|
76
|
-
let first = -1;
|
|
77
|
-
let last = -1;
|
|
78
|
-
for (let i = 0; i < owners.length; i++) {
|
|
79
|
-
if (owners[i] !== focus) continue;
|
|
80
|
-
if (first < 0) first = i;
|
|
81
|
-
last = i;
|
|
82
|
-
}
|
|
83
|
-
return { first, last };
|
|
48
|
+
const panel = paintNotePanel(view, width, color, notesCap);
|
|
49
|
+
const rows = panel.rows.slice(0, notesCap);
|
|
50
|
+
const inside = panel.cursor && panel.cursor.row < rows.length;
|
|
51
|
+
const cursor = inside ? panel.cursor : null;
|
|
52
|
+
const bodyH = Math.max(1, height - 3 - rows.length);
|
|
53
|
+
return { panel, rows, cursor, bodyH };
|
|
84
54
|
};
|
|
85
55
|
|
|
86
56
|
const revealScroll = (owners, focus, height, prefer) => {
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
57
|
+
const first = owners.indexOf(focus);
|
|
58
|
+
if (first < 0) return prefer;
|
|
59
|
+
const last = owners.lastIndexOf(focus);
|
|
89
60
|
const room = Math.max(1, height);
|
|
90
|
-
let start = prefer;
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
const fits = span.last - span.first + 1 <= room;
|
|
94
|
-
start = fits ? span.last - room + 1 : span.first;
|
|
61
|
+
let start = Math.min(prefer, first);
|
|
62
|
+
if (last >= start + room) {
|
|
63
|
+
start = last - first + 1 <= room ? last - room + 1 : first;
|
|
95
64
|
}
|
|
96
|
-
|
|
97
|
-
if (start > maxStart) start = maxStart;
|
|
98
|
-
if (start < 0) start = 0;
|
|
99
|
-
return start;
|
|
65
|
+
return Math.max(0, Math.min(start, owners.length - room));
|
|
100
66
|
};
|
|
101
67
|
|
|
102
68
|
const windowY = (win, row) => {
|
|
@@ -123,20 +89,25 @@ const mapBodyCursor = (cursor, win) => {
|
|
|
123
89
|
return point;
|
|
124
90
|
};
|
|
125
91
|
|
|
126
|
-
const
|
|
92
|
+
const bodyFillKind = (listPane, splitBody) => {
|
|
93
|
+
if (listPane) return 'files';
|
|
94
|
+
return splitBody ? 'split' : 'plain';
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const windowBody = (view, painted, frame) => {
|
|
127
98
|
const { width, color, bodyH, headerLines } = frame;
|
|
128
|
-
const listPane =
|
|
129
|
-
const fillKind = bodyFillKind(listPane,
|
|
99
|
+
const listPane = isListPane(view.pane);
|
|
100
|
+
const fillKind = bodyFillKind(listPane, painted.splitBody);
|
|
130
101
|
const filler = paintBodyFill(width, color, fillKind);
|
|
131
|
-
const shift = !listPane &&
|
|
102
|
+
const shift = !listPane && painted.body.length > 0 ? 1 : 0;
|
|
132
103
|
const lead = (items, first) =>
|
|
133
104
|
shift && items.length ? [first, ...items] : items;
|
|
134
|
-
const body = lead(
|
|
135
|
-
const taskOwners = lead(
|
|
136
|
-
const taskChecks = lead(
|
|
105
|
+
const body = lead(painted.body, filler);
|
|
106
|
+
const taskOwners = lead(painted.taskOwners, null);
|
|
107
|
+
const taskChecks = lead(painted.taskChecks, false);
|
|
137
108
|
const scrollMax = Math.max(0, body.length - bodyH);
|
|
138
109
|
let scroll = listPane ? 0 : Math.min(view.scroll ?? 0, scrollMax);
|
|
139
|
-
if (view
|
|
110
|
+
if (isTaskView(view)) {
|
|
140
111
|
scroll = revealScroll(taskOwners, view.tasksFocus ?? 0, bodyH, scroll);
|
|
141
112
|
}
|
|
142
113
|
const slice = body.slice(scroll, scroll + bodyH);
|
|
@@ -151,85 +122,79 @@ const windowBody = (view, paintedBody, frame) => {
|
|
|
151
122
|
}
|
|
152
123
|
taskHits.push({ y, cursor: owner });
|
|
153
124
|
}
|
|
154
|
-
const cursor = mapBodyCursor(paintedBody.cursor, win);
|
|
155
|
-
const editHits = mapEditHits(paintedBody.editHits, win);
|
|
156
125
|
while (slice.length < bodyH) slice.push(filler);
|
|
157
|
-
const { listScroll, fileHits } = paintedBody;
|
|
158
126
|
return {
|
|
159
127
|
slice,
|
|
160
128
|
scroll,
|
|
161
129
|
scrollMax,
|
|
162
|
-
listScroll,
|
|
130
|
+
listScroll: painted.listScroll,
|
|
163
131
|
taskHits,
|
|
164
|
-
fileHits,
|
|
165
|
-
editHits,
|
|
166
|
-
cursor,
|
|
132
|
+
fileHits: painted.fileHits,
|
|
133
|
+
editHits: mapEditHits(painted.editHits, win),
|
|
134
|
+
cursor: mapBodyCursor(painted.cursor, win),
|
|
167
135
|
};
|
|
168
136
|
};
|
|
169
137
|
|
|
170
138
|
const notePointerHits = (notes, bodyH) => {
|
|
171
|
-
const {
|
|
139
|
+
const { panel, rows, cursor } = notes;
|
|
172
140
|
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;
|
|
176
141
|
const templateHits = [];
|
|
177
|
-
for (const hit of
|
|
178
|
-
if (hit.row
|
|
179
|
-
|
|
142
|
+
for (const hit of panel.templateHits) {
|
|
143
|
+
if (hit.row < rows.length) {
|
|
144
|
+
templateHits.push({ y: top + hit.row, cursor: hit.cursor });
|
|
145
|
+
}
|
|
180
146
|
}
|
|
181
147
|
const editHits = [];
|
|
182
|
-
for (const hit of
|
|
183
|
-
if (hit.row
|
|
184
|
-
editHits.push({ ...hit, y: top + hit.row });
|
|
148
|
+
for (const hit of panel.editHits) {
|
|
149
|
+
if (hit.row < rows.length) editHits.push({ ...hit, y: top + hit.row });
|
|
185
150
|
}
|
|
186
|
-
|
|
151
|
+
const point = cursor ? { x: cursor.x, y: top + cursor.row } : null;
|
|
152
|
+
return { cursor: point, templateHits, editHits };
|
|
187
153
|
};
|
|
188
154
|
|
|
189
155
|
const renderFrame = (view, options = {}) => {
|
|
190
156
|
const width = Math.max(20, options.width ?? 80);
|
|
191
157
|
const height = Math.max(6, options.height ?? 24);
|
|
192
158
|
const color = options.color ?? true;
|
|
193
|
-
const
|
|
159
|
+
const headerLines = 1;
|
|
194
160
|
const layout = footerLayout(view, width);
|
|
195
161
|
const notes = frameNotes(view, width, height, color);
|
|
196
|
-
const headerLines = 1;
|
|
197
162
|
const { bodyH } = notes;
|
|
198
|
-
const
|
|
163
|
+
const paint = bodyPainter(view);
|
|
164
|
+
const painted = paint(view, width, color, bodyH, headerLines);
|
|
199
165
|
const frame = { width, color, bodyH, headerLines };
|
|
200
|
-
const windowed = windowBody(view,
|
|
201
|
-
const rows =
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
166
|
+
const windowed = windowBody(view, painted, frame);
|
|
167
|
+
const rows = overlayRows(
|
|
168
|
+
[
|
|
169
|
+
paintHeader(view, width, color),
|
|
170
|
+
...windowed.slice,
|
|
171
|
+
...notes.rows,
|
|
172
|
+
paintStatusLine(view, view.status ?? '', width, color),
|
|
173
|
+
paintFooter(view, layout, width, color),
|
|
174
|
+
],
|
|
175
|
+
view.selection,
|
|
176
|
+
);
|
|
209
177
|
const hits = notePointerHits(notes, bodyH);
|
|
210
|
-
const statusY =
|
|
178
|
+
const statusY = rows.length - 1;
|
|
211
179
|
const branchHit = statusBranchHit(view, width, statusY);
|
|
212
180
|
const statusHits = branchHit ? [branchHit] : statusChoiceHits(view, statusY);
|
|
213
|
-
const { fileHits, taskHits, scroll, scrollMax, listScroll } = windowed;
|
|
214
|
-
const { templateHits } = hits;
|
|
215
181
|
const editHits = [...windowed.editHits, ...hits.editHits];
|
|
216
|
-
const shown = markEditorSelection(
|
|
182
|
+
const shown = markEditorSelection(rows, view, editHits, color);
|
|
217
183
|
const text = shown.map((row) => (color ? row + RESET : row)).join('\n');
|
|
218
|
-
const footerY = painted.length;
|
|
219
184
|
return {
|
|
220
185
|
text,
|
|
221
186
|
rows: shown,
|
|
222
187
|
buttons: footerHits(view, layout),
|
|
223
|
-
fileHits,
|
|
224
|
-
taskHits,
|
|
225
|
-
templateHits,
|
|
188
|
+
fileHits: windowed.fileHits,
|
|
189
|
+
taskHits: windowed.taskHits,
|
|
190
|
+
templateHits: hits.templateHits,
|
|
226
191
|
editHits,
|
|
227
192
|
statusHits,
|
|
228
|
-
footerY,
|
|
229
|
-
height:
|
|
230
|
-
scroll,
|
|
231
|
-
scrollMax,
|
|
232
|
-
listScroll,
|
|
193
|
+
footerY: rows.length,
|
|
194
|
+
height: rows.length,
|
|
195
|
+
scroll: windowed.scroll,
|
|
196
|
+
scrollMax: windowed.scrollMax,
|
|
197
|
+
listScroll: windowed.listScroll,
|
|
233
198
|
cursor: hits.cursor ?? windowed.cursor,
|
|
234
199
|
bodyH,
|
|
235
200
|
};
|