mellos-mapping 0.14.0 → 0.15.0
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/dist/server.mjs +12 -10
- package/dist/watch.mjs +91 -50
- package/package.json +1 -1
package/dist/server.mjs
CHANGED
|
@@ -21390,7 +21390,7 @@ function removeLayer(map, id) {
|
|
|
21390
21390
|
|
|
21391
21391
|
// src/render/render.ts
|
|
21392
21392
|
var ZOOM_MIN = -4;
|
|
21393
|
-
var ZOOM_MAX =
|
|
21393
|
+
var ZOOM_MAX = 2;
|
|
21394
21394
|
var ZOOM_DEFAULT = 0;
|
|
21395
21395
|
function clampZoom(n) {
|
|
21396
21396
|
return Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, Math.round(n)));
|
|
@@ -21668,10 +21668,14 @@ function neutralSkin(unicode) {
|
|
|
21668
21668
|
var BOX_H = 3;
|
|
21669
21669
|
var BOX_GAP = 2;
|
|
21670
21670
|
var LEFT_MARGIN = 2;
|
|
21671
|
+
var DETAIL_BUDGET = { innerMin: 22, innerMax: 32, noteRows: 3 };
|
|
21672
|
+
var DETAIL_PLUS_BUDGET = { innerMin: 30, innerMax: 48, noteRows: 12 };
|
|
21671
21673
|
function zoomGeometry(zoom) {
|
|
21672
21674
|
switch (zoom) {
|
|
21675
|
+
case 2:
|
|
21676
|
+
return { mode: "detail", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false, detail: DETAIL_PLUS_BUDGET };
|
|
21673
21677
|
case 1:
|
|
21674
|
-
return { mode: "detail", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false };
|
|
21678
|
+
return { mode: "detail", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false, detail: DETAIL_BUDGET };
|
|
21675
21679
|
case 0:
|
|
21676
21680
|
return { mode: "boxes", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false };
|
|
21677
21681
|
case -1:
|
|
@@ -21684,9 +21688,6 @@ function zoomGeometry(zoom) {
|
|
|
21684
21688
|
return { mode: "constellation", scale: 0, pad: 0, boxGap: BOX_GAP, breathe: 0, titleGap: 0, barGap: 1, bandCounts: true };
|
|
21685
21689
|
}
|
|
21686
21690
|
}
|
|
21687
|
-
var DETAIL_INNER_MIN = 22;
|
|
21688
|
-
var DETAIL_INNER_MAX = 32;
|
|
21689
|
-
var DETAIL_NOTE_ROWS = 3;
|
|
21690
21691
|
var LABEL_BUDGET_MIN = 4;
|
|
21691
21692
|
function boxSpec(node, geo, unicode, neutral) {
|
|
21692
21693
|
const glyph = node.kind !== void 0 ? kindGlyph(node.kind, unicode) : void 0;
|
|
@@ -21696,14 +21697,15 @@ function boxSpec(node, geo, unicode, neutral) {
|
|
|
21696
21697
|
if (geo.mode === "constellation") {
|
|
21697
21698
|
return { w: 3, h: 1, label: "", pad: 0, borderless: true, extra: [] };
|
|
21698
21699
|
}
|
|
21699
|
-
if (geo.mode === "detail") {
|
|
21700
|
-
const
|
|
21700
|
+
if (geo.mode === "detail" && geo.detail !== void 0) {
|
|
21701
|
+
const budget2 = geo.detail;
|
|
21702
|
+
const innerW = Math.min(Math.max(displayWidth(text2) + badgeW + 4, budget2.innerMin), budget2.innerMax);
|
|
21701
21703
|
const extra = [];
|
|
21702
21704
|
if (node.evidence !== void 0) extra.push({ text: fitWidth(` ${node.evidence}`, innerW), style: "faint" });
|
|
21703
21705
|
if (node.detail !== void 0) {
|
|
21704
21706
|
const wrapped = wrapWidth(node.detail, innerW - 2);
|
|
21705
|
-
for (let i = 0; i < Math.min(wrapped.length,
|
|
21706
|
-
const cut = i ===
|
|
21707
|
+
for (let i = 0; i < Math.min(wrapped.length, budget2.noteRows); i++) {
|
|
21708
|
+
const cut = i === budget2.noteRows - 1 && wrapped.length > budget2.noteRows;
|
|
21707
21709
|
extra.push({ text: ` ${cut ? fitWidth(wrapped[i] + "\u2026", innerW - 2) : wrapped[i]}`, style: "none" });
|
|
21708
21710
|
}
|
|
21709
21711
|
}
|
|
@@ -22513,7 +22515,7 @@ function summarize(map) {
|
|
|
22513
22515
|
|
|
22514
22516
|
// src/server/server.ts
|
|
22515
22517
|
var SERVER_NAME = "mellos-mapping";
|
|
22516
|
-
var SERVER_VERSION = "0.
|
|
22518
|
+
var SERVER_VERSION = "0.15.0";
|
|
22517
22519
|
var ID = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "lowercase letters, digits and dashes, 1-64 chars").describe("stable kebab-case identifier");
|
|
22518
22520
|
var PAGE = ID.optional().describe(
|
|
22519
22521
|
"page (parallel map) this call targets; omit for the default page. One effort = one page: start a NEW effort on its own page named after the effort, so concurrent sessions never write over each other and the pane can switch between pages."
|
package/dist/watch.mjs
CHANGED
|
@@ -201,13 +201,15 @@ function updateNode(map, input) {
|
|
|
201
201
|
|
|
202
202
|
// src/render/render.ts
|
|
203
203
|
var ZOOM_MIN = -4;
|
|
204
|
-
var ZOOM_MAX =
|
|
204
|
+
var ZOOM_MAX = 2;
|
|
205
205
|
var ZOOM_DEFAULT = 0;
|
|
206
206
|
function clampZoom(n) {
|
|
207
207
|
return Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, Math.round(n)));
|
|
208
208
|
}
|
|
209
209
|
function zoomLabel(zoom) {
|
|
210
210
|
switch (zoom) {
|
|
211
|
+
case 2:
|
|
212
|
+
return "detail+";
|
|
211
213
|
case 1:
|
|
212
214
|
return "detail";
|
|
213
215
|
case 0:
|
|
@@ -495,10 +497,14 @@ function neutralSkin(unicode) {
|
|
|
495
497
|
var BOX_H = 3;
|
|
496
498
|
var BOX_GAP = 2;
|
|
497
499
|
var LEFT_MARGIN = 2;
|
|
500
|
+
var DETAIL_BUDGET = { innerMin: 22, innerMax: 32, noteRows: 3 };
|
|
501
|
+
var DETAIL_PLUS_BUDGET = { innerMin: 30, innerMax: 48, noteRows: 12 };
|
|
498
502
|
function zoomGeometry(zoom) {
|
|
499
503
|
switch (zoom) {
|
|
504
|
+
case 2:
|
|
505
|
+
return { mode: "detail", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false, detail: DETAIL_PLUS_BUDGET };
|
|
500
506
|
case 1:
|
|
501
|
-
return { mode: "detail", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false };
|
|
507
|
+
return { mode: "detail", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false, detail: DETAIL_BUDGET };
|
|
502
508
|
case 0:
|
|
503
509
|
return { mode: "boxes", scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false };
|
|
504
510
|
case -1:
|
|
@@ -511,9 +517,6 @@ function zoomGeometry(zoom) {
|
|
|
511
517
|
return { mode: "constellation", scale: 0, pad: 0, boxGap: BOX_GAP, breathe: 0, titleGap: 0, barGap: 1, bandCounts: true };
|
|
512
518
|
}
|
|
513
519
|
}
|
|
514
|
-
var DETAIL_INNER_MIN = 22;
|
|
515
|
-
var DETAIL_INNER_MAX = 32;
|
|
516
|
-
var DETAIL_NOTE_ROWS = 3;
|
|
517
520
|
var LABEL_BUDGET_MIN = 4;
|
|
518
521
|
function boxSpec(node, geo, unicode, neutral) {
|
|
519
522
|
const glyph = node.kind !== void 0 ? kindGlyph(node.kind, unicode) : void 0;
|
|
@@ -523,14 +526,15 @@ function boxSpec(node, geo, unicode, neutral) {
|
|
|
523
526
|
if (geo.mode === "constellation") {
|
|
524
527
|
return { w: 3, h: 1, label: "", pad: 0, borderless: true, extra: [] };
|
|
525
528
|
}
|
|
526
|
-
if (geo.mode === "detail") {
|
|
527
|
-
const
|
|
529
|
+
if (geo.mode === "detail" && geo.detail !== void 0) {
|
|
530
|
+
const budget2 = geo.detail;
|
|
531
|
+
const innerW = Math.min(Math.max(displayWidth(text) + badgeW + 4, budget2.innerMin), budget2.innerMax);
|
|
528
532
|
const extra = [];
|
|
529
533
|
if (node.evidence !== void 0) extra.push({ text: fitWidth(` ${node.evidence}`, innerW), style: "faint" });
|
|
530
534
|
if (node.detail !== void 0) {
|
|
531
535
|
const wrapped = wrapWidth(node.detail, innerW - 2);
|
|
532
|
-
for (let i = 0; i < Math.min(wrapped.length,
|
|
533
|
-
const cut = i ===
|
|
536
|
+
for (let i = 0; i < Math.min(wrapped.length, budget2.noteRows); i++) {
|
|
537
|
+
const cut = i === budget2.noteRows - 1 && wrapped.length > budget2.noteRows;
|
|
534
538
|
extra.push({ text: ` ${cut ? fitWidth(wrapped[i] + "\u2026", innerW - 2) : wrapped[i]}`, style: "none" });
|
|
535
539
|
}
|
|
536
540
|
}
|
|
@@ -1175,7 +1179,7 @@ var KEY_PAN = {
|
|
|
1175
1179
|
function mouseEvent(code, x, y, final) {
|
|
1176
1180
|
if (code & WHEEL) {
|
|
1177
1181
|
const down = (code & 1) !== 0;
|
|
1178
|
-
return code & SHIFT ? { kind: "pan", dx: 0, dy: (down ? 1 : -1) * WHEEL_V_STEP } : { kind: "zoom", delta: down ? -1 : 1 };
|
|
1182
|
+
return code & SHIFT ? { kind: "pan", dx: 0, dy: (down ? 1 : -1) * WHEEL_V_STEP } : { kind: "zoom", delta: down ? -1 : 1, at: { x, y } };
|
|
1179
1183
|
}
|
|
1180
1184
|
const buttons = code & BUTTON_BITS;
|
|
1181
1185
|
if (final === "m") return buttons === 0 ? { kind: "mouse-up", x, y } : void 0;
|
|
@@ -1271,6 +1275,9 @@ var RESET = "\x1B[0m";
|
|
|
1271
1275
|
var PANEL_CONTENT_ROWS = 6;
|
|
1272
1276
|
var PANEL_ROWS_MIN = 2;
|
|
1273
1277
|
var MAP_ROWS_MIN = 4;
|
|
1278
|
+
function usableColumns(cols) {
|
|
1279
|
+
return Math.max(1, cols - 1);
|
|
1280
|
+
}
|
|
1274
1281
|
function clampPanelRows(wanted, totalRows, tabRows) {
|
|
1275
1282
|
const largest = totalRows - tabRows - MAP_ROWS_MIN - 2;
|
|
1276
1283
|
return Math.max(PANEL_ROWS_MIN, Math.min(wanted, largest));
|
|
@@ -1302,27 +1309,46 @@ function anchorOffsets(anchor, offset, before, after) {
|
|
|
1302
1309
|
y: before.h > 0 ? Math.round(offset.y * after.h / before.h) : 0
|
|
1303
1310
|
};
|
|
1304
1311
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
for (const [index, tab] of tabs.entries()) {
|
|
1309
|
-
const room = width - (col - 1);
|
|
1310
|
-
if (room <= 3) break;
|
|
1312
|
+
var TAB_INDICATOR_W = 3;
|
|
1313
|
+
function pageTabRow(tabs, width, unicode, scroll = 0) {
|
|
1314
|
+
const texts = tabs.map((tab) => {
|
|
1311
1315
|
const marker = tab.active ? unicode ? "\u25CF" : "*" : unicode ? "\u25CB" : "o";
|
|
1312
1316
|
const glyph = STATUS_GLYPH[tab.status][unicode ? 0 : 1];
|
|
1313
|
-
|
|
1317
|
+
return tab.neutral === true ? ` ${marker} ${tab.title} ` : ` ${marker} ${glyph} ${tab.title} `;
|
|
1318
|
+
});
|
|
1319
|
+
const sgrOf = (tab) => tab.neutral === true ? tab.active ? "1" : tab.fresh ? "36" : "90" : tab.active ? `${STATUS_SGR[tab.status]};1` : tab.fresh ? STATUS_SGR[tab.status] : "90";
|
|
1320
|
+
const widths = texts.map(displayWidth);
|
|
1321
|
+
const count = tabs.length;
|
|
1322
|
+
let lo = 0;
|
|
1323
|
+
let hi = count - 1;
|
|
1324
|
+
if (widths.reduce((a, b) => a + b, 0) > width) {
|
|
1325
|
+
lo = Math.max(0, Math.min(scroll, count - 1));
|
|
1326
|
+
hi = lo;
|
|
1327
|
+
const cost = (l, h) => widths.slice(l, h + 1).reduce((a, b) => a + b, 0) + (l > 0 ? TAB_INDICATOR_W : 0) + (h < count - 1 ? TAB_INDICATOR_W : 0);
|
|
1328
|
+
while (hi + 1 < count && cost(lo, hi + 1) <= width) hi++;
|
|
1329
|
+
}
|
|
1330
|
+
const segments = [];
|
|
1331
|
+
let col = 1;
|
|
1332
|
+
const push = (text, sgr, action) => {
|
|
1314
1333
|
const w = displayWidth(text);
|
|
1315
|
-
segments.push({
|
|
1316
|
-
text,
|
|
1317
|
-
sgr: tab.neutral === true ? tab.active ? "1" : tab.fresh ? "36" : "90" : tab.active ? `${STATUS_SGR[tab.status]};1` : tab.fresh ? STATUS_SGR[tab.status] : "90",
|
|
1318
|
-
lo: col,
|
|
1319
|
-
hi: col + w - 1,
|
|
1320
|
-
index
|
|
1321
|
-
});
|
|
1334
|
+
segments.push({ text, sgr, lo: col, hi: col + w - 1, action });
|
|
1322
1335
|
col += w;
|
|
1336
|
+
};
|
|
1337
|
+
if (lo > 0) push(unicode ? " \u2039 " : " < ", "90", { kind: "scroll", delta: -1 });
|
|
1338
|
+
const tail = hi < count - 1 ? TAB_INDICATOR_W : 0;
|
|
1339
|
+
for (let i = lo; i <= hi; i++) {
|
|
1340
|
+
push(fitWidth(texts[i], Math.max(1, width - (col - 1) - tail)), sgrOf(tabs[i]), { kind: "switch", index: i });
|
|
1323
1341
|
}
|
|
1342
|
+
if (hi < count - 1) push(unicode ? " \u203A " : " > ", "90", { kind: "scroll", delta: 1 });
|
|
1324
1343
|
return segments;
|
|
1325
1344
|
}
|
|
1345
|
+
function tabScrollFor(tabs, width, unicode, scroll, index) {
|
|
1346
|
+
if (index <= scroll) return Math.max(0, index);
|
|
1347
|
+
const visibleAt = (s2) => pageTabRow(tabs, width, unicode, s2).some((seg) => seg.action.kind === "switch" && seg.action.index === index);
|
|
1348
|
+
let s = Math.max(0, Math.min(scroll, tabs.length - 1));
|
|
1349
|
+
while (s < index && !visibleAt(s)) s++;
|
|
1350
|
+
return s;
|
|
1351
|
+
}
|
|
1326
1352
|
function topLevelFiles(defaultFile, files, mapOf) {
|
|
1327
1353
|
const refs = /* @__PURE__ */ new Set();
|
|
1328
1354
|
for (const m of mapOf.values()) {
|
|
@@ -1602,6 +1628,7 @@ function main() {
|
|
|
1602
1628
|
let activeFile;
|
|
1603
1629
|
let firstScan = true;
|
|
1604
1630
|
let lastTabSegments = [];
|
|
1631
|
+
let tabScroll = 0;
|
|
1605
1632
|
let offsetX = 0;
|
|
1606
1633
|
let offsetY = 0;
|
|
1607
1634
|
let zoom = ZOOM_DEFAULT;
|
|
@@ -1634,8 +1661,19 @@ function main() {
|
|
|
1634
1661
|
}
|
|
1635
1662
|
return false;
|
|
1636
1663
|
};
|
|
1664
|
+
const viewWidth = () => usableColumns(process.stdout.columns ?? 100);
|
|
1637
1665
|
const viewHeight = () => Math.max(1, (process.stdout.rows ?? 30) - (1 + panelContentRows) - 1 - tabRows());
|
|
1638
1666
|
const dividerY = () => tabRows() + viewHeight() + 1;
|
|
1667
|
+
const pageTabsOf = (files) => files.map((f) => {
|
|
1668
|
+
const m = pageData.get(f)?.map;
|
|
1669
|
+
return {
|
|
1670
|
+
title: m?.title ?? (pageIdOfFile(cfg.file, f) ?? "main"),
|
|
1671
|
+
status: m !== void 0 ? mapStatus(m) : "planned",
|
|
1672
|
+
active: f === activeFile,
|
|
1673
|
+
fresh: pageData.get(f)?.fresh ?? false,
|
|
1674
|
+
neutral: m !== void 0 && isNeutralKind(m)
|
|
1675
|
+
};
|
|
1676
|
+
});
|
|
1639
1677
|
const switchPage = (file) => {
|
|
1640
1678
|
if (activeFile !== void 0) pageViews.set(activeFile, { offsetX, offsetY, zoom, selectedId });
|
|
1641
1679
|
activeFile = file;
|
|
@@ -1649,10 +1687,14 @@ function main() {
|
|
|
1649
1687
|
if (entry !== void 0 && entry.fresh) pageData.set(file, { ...entry, fresh: false });
|
|
1650
1688
|
map = entry?.map;
|
|
1651
1689
|
notice = map === void 0 ? `waiting for ${file} ...` : "";
|
|
1690
|
+
const top = topFiles();
|
|
1691
|
+
const tabIndex = top.indexOf(file);
|
|
1692
|
+
if (tabIndex >= 0) tabScroll = tabScrollFor(pageTabsOf(top), viewWidth(), cfg.unicode, tabScroll, tabIndex);
|
|
1652
1693
|
};
|
|
1653
1694
|
const hitTest = (termX, termY) => {
|
|
1654
1695
|
const sx = termX - 1;
|
|
1655
1696
|
const sy = termY - 1 - tabRows();
|
|
1697
|
+
if (sx < 0 || sx >= viewWidth()) return void 0;
|
|
1656
1698
|
if (sy < 0 || sy >= viewHeight()) return void 0;
|
|
1657
1699
|
const cx = sx + offsetX;
|
|
1658
1700
|
const cy = sy + offsetY;
|
|
@@ -1667,6 +1709,7 @@ function main() {
|
|
|
1667
1709
|
process.on("SIGTERM", restore);
|
|
1668
1710
|
const paint = () => {
|
|
1669
1711
|
const cols = process.stdout.columns ?? 100;
|
|
1712
|
+
const viewW = viewWidth();
|
|
1670
1713
|
panelContentRows = clampPanelRows(panelContentRows, process.stdout.rows ?? 30, tabRows());
|
|
1671
1714
|
const viewH = viewHeight();
|
|
1672
1715
|
const focus = hoverId ?? selectedId;
|
|
@@ -1677,9 +1720,9 @@ function main() {
|
|
|
1677
1720
|
const windowed = renderMapWindow(
|
|
1678
1721
|
map,
|
|
1679
1722
|
{ color: cfg.color, unicode: cfg.unicode, spinnerFrame, focus, zoom },
|
|
1680
|
-
{ x: offsetX, y: offsetY, width:
|
|
1723
|
+
{ x: offsetX, y: offsetY, width: viewW, height: viewH }
|
|
1681
1724
|
);
|
|
1682
|
-
const maxX = Math.max(0, windowed.contentWidth -
|
|
1725
|
+
const maxX = Math.max(0, windowed.contentWidth - viewW);
|
|
1683
1726
|
const maxY = Math.max(0, windowed.contentHeight - viewH);
|
|
1684
1727
|
if (offsetX > maxX || offsetY > maxY || offsetX < 0 || offsetY < 0) {
|
|
1685
1728
|
offsetX = Math.min(Math.max(0, offsetX), maxX);
|
|
@@ -1693,10 +1736,10 @@ function main() {
|
|
|
1693
1736
|
lastContent = { w: windowed.contentWidth, h: windowed.contentHeight };
|
|
1694
1737
|
if (offsetX !== 0 || offsetY !== 0) panned = ` (+${offsetX},+${offsetY})`;
|
|
1695
1738
|
} else {
|
|
1696
|
-
body = (interactive ? splashFrame(notice, splashTick,
|
|
1739
|
+
body = (interactive ? splashFrame(notice, splashTick, viewW, viewH, cfg.unicode, cfg.color) : void 0) ?? [fitWidth(notice, viewW)];
|
|
1697
1740
|
}
|
|
1698
1741
|
if (notice !== "" && map !== void 0) {
|
|
1699
|
-
body[body.length - 1] = fitWidth(` ${notice}`,
|
|
1742
|
+
body[body.length - 1] = fitWidth(` ${notice}`, viewW);
|
|
1700
1743
|
}
|
|
1701
1744
|
const panelWidth = Math.max(10, cols - 2);
|
|
1702
1745
|
let panel;
|
|
@@ -1708,9 +1751,9 @@ function main() {
|
|
|
1708
1751
|
panel = mapPanel(map, cfg.unicode, panelWidth, panelContentRows);
|
|
1709
1752
|
}
|
|
1710
1753
|
const grip = cfg.unicode ? " \u22EF " : " ~ ";
|
|
1711
|
-
const bar = (cfg.unicode ? "\u2500" : "-").repeat(
|
|
1712
|
-
const gripAt = Math.max(0, Math.floor((
|
|
1713
|
-
const separator =
|
|
1754
|
+
const bar = (cfg.unicode ? "\u2500" : "-").repeat(viewW);
|
|
1755
|
+
const gripAt = Math.max(0, Math.floor((viewW - grip.length) / 2));
|
|
1756
|
+
const separator = viewW > grip.length + 2 ? bar.slice(0, gripAt) + grip + bar.slice(gripAt + grip.length) : bar;
|
|
1714
1757
|
const panelRows = [
|
|
1715
1758
|
cfg.color ? `\x1B[90m${separator}${RESET}` : separator,
|
|
1716
1759
|
...panel.map(
|
|
@@ -1726,29 +1769,19 @@ function main() {
|
|
|
1726
1769
|
const parentTitle = parentFile !== void 0 ? pageData.get(parentFile)?.map?.title ?? (pageIdOfFile(cfg.file, parentFile) ?? "main") : "main";
|
|
1727
1770
|
const nodeLabel = scanned?.label ?? map?.title ?? "";
|
|
1728
1771
|
const crumbHead = ` ${cfg.unicode ? "\u232B" : "<"} ${parentTitle} ${cfg.unicode ? "\u25B8" : ">"} `;
|
|
1729
|
-
const head = { text: crumbHead, sgr: "90", lo: 1, hi: displayWidth(crumbHead),
|
|
1730
|
-
const tailText = fitWidth(`${nodeLabel} `, Math.max(1,
|
|
1772
|
+
const head = { text: crumbHead, sgr: "90", lo: 1, hi: displayWidth(crumbHead), action: { kind: "back" } };
|
|
1773
|
+
const tailText = fitWidth(`${nodeLabel} `, Math.max(1, viewW - displayWidth(crumbHead)));
|
|
1731
1774
|
const tail = {
|
|
1732
1775
|
text: tailText,
|
|
1733
1776
|
sgr: "1",
|
|
1734
1777
|
lo: head.hi + 1,
|
|
1735
1778
|
hi: head.hi + displayWidth(tailText),
|
|
1736
|
-
|
|
1779
|
+
action: { kind: "back" }
|
|
1737
1780
|
};
|
|
1738
1781
|
lastTabSegments = [head, tail];
|
|
1739
1782
|
tabLine = lastTabSegments.map((s) => cfg.color && s.sgr !== "" ? `\x1B[${s.sgr}m${s.text}${RESET}` : s.text).join("");
|
|
1740
1783
|
} else if (tabRows() > 0) {
|
|
1741
|
-
const
|
|
1742
|
-
const m = pageData.get(f)?.map;
|
|
1743
|
-
return {
|
|
1744
|
-
title: m?.title ?? (pageIdOfFile(cfg.file, f) ?? "main"),
|
|
1745
|
-
status: m !== void 0 ? mapStatus(m) : "planned",
|
|
1746
|
-
active: f === activeFile,
|
|
1747
|
-
fresh: pageData.get(f)?.fresh ?? false,
|
|
1748
|
-
neutral: m !== void 0 && isNeutralKind(m)
|
|
1749
|
-
};
|
|
1750
|
-
});
|
|
1751
|
-
const segments = pageTabRow(tabs, cols, cfg.unicode);
|
|
1784
|
+
const segments = pageTabRow(pageTabsOf(lastTabFiles), viewW, cfg.unicode, tabScroll);
|
|
1752
1785
|
lastTabSegments = segments;
|
|
1753
1786
|
tabLine = segments.map((s) => cfg.color && s.sgr !== "" ? `\x1B[${s.sgr}m${s.text}${RESET}` : s.text).join("");
|
|
1754
1787
|
} else {
|
|
@@ -1756,7 +1789,7 @@ function main() {
|
|
|
1756
1789
|
}
|
|
1757
1790
|
const zoomTag = `${cfg.unicode ? "\u2295" : "zoom"} ${zoomLabel(zoom)}`;
|
|
1758
1791
|
const hint = !interactive ? cfg.file : (flash !== void 0 ? `${flash.text} \xB7 ` : "") + `${zoomTag} \xB7 wheel zoom \xB7 ` + (pannable ? "drag pan \xB7 " : "") + "hover/click \xB7 0 reset \xB7 q quit";
|
|
1759
|
-
const footerText = fitWidth(` ${hint}${panned}`,
|
|
1792
|
+
const footerText = fitWidth(` ${hint}${panned}`, viewW);
|
|
1760
1793
|
const footer = cfg.color ? `\x1B[90m${footerText}${RESET}` : footerText;
|
|
1761
1794
|
let frame = HOME;
|
|
1762
1795
|
if (tabLine !== void 0) frame += tabLine + ERASE_LINE_END + "\n";
|
|
@@ -1849,10 +1882,14 @@ function main() {
|
|
|
1849
1882
|
dirty = true;
|
|
1850
1883
|
break;
|
|
1851
1884
|
case "zoom": {
|
|
1885
|
+
if (event.at !== void 0 && event.at.y === 1 && tabRows() > 0 && !inSubmap()) {
|
|
1886
|
+
tabScroll = Math.max(0, Math.min(tabScroll + (event.delta === 1 ? -1 : 1), topFiles().length - 1));
|
|
1887
|
+
dirty = true;
|
|
1888
|
+
break;
|
|
1889
|
+
}
|
|
1852
1890
|
const next = clampZoom(zoom + event.delta);
|
|
1853
1891
|
if (next === zoom || map === void 0) break;
|
|
1854
|
-
const
|
|
1855
|
-
const anchorId = hoverId ?? selectedId ?? nearestHit(lastHits, offsetX + cols / 2, offsetY + viewHeight() / 2)?.id;
|
|
1892
|
+
const anchorId = hoverId ?? selectedId ?? nearestHit(lastHits, offsetX + viewWidth() / 2, offsetY + viewHeight() / 2)?.id;
|
|
1856
1893
|
const before = lastHits.find((h) => h.id === anchorId);
|
|
1857
1894
|
zoom = next;
|
|
1858
1895
|
const sized = renderMapWindow(
|
|
@@ -1916,10 +1953,12 @@ function main() {
|
|
|
1916
1953
|
if (press && !press.moved) {
|
|
1917
1954
|
const tabHit = tabRows() > 0 && event.y === 1 ? lastTabSegments.find((s) => event.x >= s.lo && event.x <= s.hi) : void 0;
|
|
1918
1955
|
if (tabHit !== void 0) {
|
|
1919
|
-
if (tabHit.
|
|
1956
|
+
if (tabHit.action.kind === "back") {
|
|
1920
1957
|
climbBack();
|
|
1958
|
+
} else if (tabHit.action.kind === "scroll") {
|
|
1959
|
+
tabScroll = Math.max(0, Math.min(tabScroll + tabHit.action.delta, lastTabFiles.length - 1));
|
|
1921
1960
|
} else {
|
|
1922
|
-
const target = lastTabFiles[tabHit.index];
|
|
1961
|
+
const target = lastTabFiles[tabHit.action.index];
|
|
1923
1962
|
if (target !== void 0 && target !== activeFile) switchPage(target);
|
|
1924
1963
|
}
|
|
1925
1964
|
} else {
|
|
@@ -2017,7 +2056,9 @@ export {
|
|
|
2017
2056
|
parseArgs,
|
|
2018
2057
|
splashArt,
|
|
2019
2058
|
splashFrame,
|
|
2059
|
+
tabScrollFor,
|
|
2020
2060
|
topLevelFiles,
|
|
2061
|
+
usableColumns,
|
|
2021
2062
|
waveAt,
|
|
2022
2063
|
waveHash,
|
|
2023
2064
|
waveLevel,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mellos-mapping",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"mcpName": "io.github.GuangminJu/mellos-mapping",
|
|
5
5
|
"description": "A live layered dependency map for bottom-up development — MCP server + terminal pane. Ghost the design first, then light nodes up from the bottom as they are built and verified.",
|
|
6
6
|
"type": "module",
|