@cristianormazabal/triton-latex 0.1.4 → 0.1.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/dist/cli.cjs CHANGED
@@ -10542,6 +10542,8 @@ function parse(input) {
10542
10542
  let indexSide = "before";
10543
10543
  let indexOrder = "normal";
10544
10544
  const ptrs = [];
10545
+ let highlights;
10546
+ let win;
10545
10547
  for (const line of lines(input)) {
10546
10548
  const t = tokenizeDirective(line);
10547
10549
  if (t.length === 0) continue;
@@ -10570,6 +10572,15 @@ function parse(input) {
10570
10572
  }
10571
10573
  continue;
10572
10574
  }
10575
+ if (t[0] === "highlight") {
10576
+ highlights = t.slice(1).map(Number).filter((n) => !isNaN(n) && Number.isInteger(n));
10577
+ continue;
10578
+ }
10579
+ if (t[0] === "window" && t[1]) {
10580
+ const m = t[1].match(/^(\d+)-(\d+)$/);
10581
+ if (m) win = { start: Number(m[1]), end: Number(m[2]) };
10582
+ continue;
10583
+ }
10573
10584
  if (t[0] === "ptr" && t.length >= 4 && t[2] === "->") {
10574
10585
  ptrs.push({ id: t[1], target: parsePointerTarget(t[3]), ...t[4] !== void 0 ? { label: t[4] } : {} });
10575
10586
  }
@@ -10579,7 +10590,9 @@ function parse(input) {
10579
10590
  axis,
10580
10591
  index: { show: indexShow, side: indexSide, order: indexOrder },
10581
10592
  cells: cells2,
10582
- ptrs
10593
+ ptrs,
10594
+ ...highlights !== void 0 && highlights.length > 0 ? { highlights } : {},
10595
+ ...win !== void 0 ? { window: win } : {}
10583
10596
  };
10584
10597
  }
10585
10598
  function parseCells(tokens) {
@@ -10678,9 +10691,15 @@ function layoutArray(inputDoc, theme) {
10678
10691
  elements.push(p.text("\u2026", slot.x + cellW / 2, slot.y + cellH / 2 + 5, font, palette.textMuted, { anchor: "middle", weight: "bold" }));
10679
10692
  return;
10680
10693
  }
10681
- elements.push(p.rect(slot, palette.surface, palette.border, 1.5, { rx: 3 }));
10682
- elements.push(p.text(cell.value, slot.x + cellW / 2, slot.y + cellH / 2 + 5, font, palette.text, { anchor: "middle", weight: "bold" }));
10683
- const logical = meta.physicalToLogical[physical];
10694
+ const logicalMaybe = meta.physicalToLogical[physical];
10695
+ const logical = logicalMaybe ?? null;
10696
+ const isHighlit = logical !== null && ((doc.highlights?.includes(logical) ?? false) || doc.window !== void 0 && logical >= doc.window.start && logical <= doc.window.end);
10697
+ if (isHighlit) {
10698
+ elements.push(p.rect(slot, palette.primary, palette.primary, 2, { rx: 3, fillOpacity: 0.22 }));
10699
+ } else {
10700
+ elements.push(p.rect(slot, palette.surface, palette.border, 1.5, { rx: 3 }));
10701
+ }
10702
+ elements.push(p.text(cell.value, slot.x + cellW / 2, slot.y + cellH / 2 + 5, font, isHighlit ? palette.primary : palette.text, { anchor: "middle", weight: "bold" }));
10684
10703
  if (doc.index.show && logical !== null) {
10685
10704
  elements.push(renderIndexText(p, theme, String(logical), slot, cellW, cellH, doc.axis, doc.index.side, indexPad));
10686
10705
  }
@@ -10736,7 +10755,9 @@ function normalizeArrayDoc(doc) {
10736
10755
  ptrs: (doc.ptrs ?? []).map((ptr) => {
10737
10756
  if ("idx" in ptr) return { id: ptr.name ?? ptr.id, target: { raw: String(ptr.idx), value: Number(ptr.idx) } };
10738
10757
  return ptr;
10739
- })
10758
+ }),
10759
+ ...Array.isArray(doc.highlights) && doc.highlights.length > 0 ? { highlights: doc.highlights } : {},
10760
+ ...doc.window !== void 0 ? { window: doc.window } : {}
10740
10761
  };
10741
10762
  }
10742
10763
  function buildSlots(count, origin, cellW, cellH, axis) {
@@ -11001,7 +11022,8 @@ function layoutPoster(ir, theme) {
11001
11022
  const contentW = colW - inset * 2;
11002
11023
  const scale = Math.min(contentW / Math.max(result.scene.viewBox.width, 1), 1);
11003
11024
  const effectiveScale = Math.max(scale, MIN_EMBED_SCALE);
11004
- const neededH = result.scene.viewBox.height * effectiveScale + cellTitleH + inset * 2;
11025
+ const captionH = cell.caption ? reservedCaptionHeight(cellTheme) : 0;
11026
+ const neededH = result.scene.viewBox.height * effectiveScale + cellTitleH + captionH + inset * 2;
11005
11027
  rowHeights[row] = Math.max(rowHeights[row], neededH);
11006
11028
  }
11007
11029
  }
@@ -11050,8 +11072,23 @@ function layoutPoster(ir, theme) {
11050
11072
  textOccupied.push(t.occupied);
11051
11073
  }
11052
11074
  const inset = unit / 2;
11053
- const contentRect = { x: cellX + inset, y: cellY + reservedTop + inset, width: cellW - inset * 2, height: cellH - reservedTop - inset * 2 };
11075
+ const captionH = cell.caption ? reservedCaptionHeight(cellTheme) : 0;
11076
+ const contentRect = {
11077
+ x: cellX + inset,
11078
+ y: cellY + reservedTop + inset,
11079
+ width: cellW - inset * 2,
11080
+ height: cellH - reservedTop - captionH - inset * 2
11081
+ };
11054
11082
  cellContent.push(embedScene(result.scene, contentRect));
11083
+ if (cell.caption) {
11084
+ const captionY = cellY + cellH - inset / 2;
11085
+ cellContent.push({ type: "text", content: cell.caption, position: { x: cellX + cellW / 2, y: captionY }, fontSize: cellTheme.typography.smallFontSize, fontFamily: cellTheme.typography.fontFamily, fill: cellTheme.palette.textMuted, anchor: "middle" });
11086
+ }
11087
+ if (cell.notes && cell.notes.length > 0) {
11088
+ for (const note of cell.notes) {
11089
+ cellContent.push(...buildNoteOverlay(note, contentRect, cellTheme));
11090
+ }
11091
+ }
11055
11092
  const scaleX = contentRect.width / Math.max(result.scene.viewBox.width, 1);
11056
11093
  const scaleY = contentRect.height / Math.max(result.scene.viewBox.height, 1);
11057
11094
  const scale = Math.min(scaleX, scaleY, 1);
@@ -11262,6 +11299,47 @@ function titleBoxHeight(theme) {
11262
11299
  const padY = theme.panel.titleChrome === "none" ? 0 : theme.spacing.unit * 0.4;
11263
11300
  return fs + padY * 2;
11264
11301
  }
11302
+ function reservedCaptionHeight(theme) {
11303
+ return theme.typography.smallFontSize + theme.spacing.unit;
11304
+ }
11305
+ function buildNoteOverlay(note, rect, theme) {
11306
+ const { palette, typography, spacing } = theme;
11307
+ const fs = typography.smallFontSize;
11308
+ const pad = spacing.unit * 0.5;
11309
+ const textW = note.text.length * fs * 0.62 + pad * 2;
11310
+ const boxH = fs + pad * 2;
11311
+ const pos = note.position ?? "top-right";
11312
+ let bx, by;
11313
+ switch (pos) {
11314
+ case "top-left":
11315
+ bx = rect.x + spacing.unit * 0.5;
11316
+ by = rect.y + spacing.unit * 0.5;
11317
+ break;
11318
+ case "top-right":
11319
+ bx = rect.x + rect.width - textW - spacing.unit * 0.5;
11320
+ by = rect.y + spacing.unit * 0.5;
11321
+ break;
11322
+ case "bottom-left":
11323
+ bx = rect.x + spacing.unit * 0.5;
11324
+ by = rect.y + rect.height - boxH - spacing.unit * 0.5;
11325
+ break;
11326
+ case "bottom-right":
11327
+ bx = rect.x + rect.width - textW - spacing.unit * 0.5;
11328
+ by = rect.y + rect.height - boxH - spacing.unit * 0.5;
11329
+ break;
11330
+ case "center":
11331
+ bx = rect.x + (rect.width - textW) / 2;
11332
+ by = rect.y + (rect.height - boxH) / 2;
11333
+ break;
11334
+ default:
11335
+ bx = rect.x + rect.width - textW - spacing.unit * 0.5;
11336
+ by = rect.y + spacing.unit * 0.5;
11337
+ }
11338
+ return [
11339
+ { type: "rect", bounds: { x: bx, y: by, width: textW, height: boxH }, fill: palette.surface, stroke: palette.primary, strokeWidth: 1, rx: boxH / 2, fillOpacity: 0.88 },
11340
+ { type: "text", content: note.text, position: { x: bx + textW / 2, y: by + pad + fs * 0.8 }, fontSize: fs, fontFamily: typography.fontFamily, fontWeight: "bold", fill: palette.primary, anchor: "middle" }
11341
+ ];
11342
+ }
11265
11343
  function buildCellTitle(title, cellX, cellY, cellW, theme) {
11266
11344
  const { palette, typography, panel, spacing } = theme;
11267
11345
  const unit = spacing.unit;
@@ -13980,8 +14058,18 @@ var poster = {
13980
14058
  parseMermaid(input) {
13981
14059
  const raw = peg$parse3(input);
13982
14060
  const cells2 = raw.cells.map((c) => {
13983
- const content = parseCell(c);
13984
- return { id: c.id, title: c.title, content, colSpan: c.span?.colSpan, rowSpan: c.span?.rowSpan, theme: c.theme };
14061
+ const { rawContent, caption, notes } = extractCellAnnotations(c.rawContent);
14062
+ const content = parseCell({ ...c, rawContent });
14063
+ return {
14064
+ id: c.id,
14065
+ title: c.title,
14066
+ content,
14067
+ colSpan: c.span?.colSpan,
14068
+ rowSpan: c.span?.rowSpan,
14069
+ theme: c.theme,
14070
+ ...caption ? { caption } : {},
14071
+ ...notes.length > 0 ? { notes } : {}
14072
+ };
13985
14073
  });
13986
14074
  const explicitLinks = raw.links ?? [];
13987
14075
  const allLinks = [...explicitLinks];
@@ -14036,6 +14124,7 @@ function inferCellKind(rawContent) {
14036
14124
  if (keyword.startsWith("nodegraph")) return "nodegraph";
14037
14125
  if (keyword.startsWith("plan")) return "plan";
14038
14126
  if (keyword.startsWith("btree")) return "btree";
14127
+ if (keyword.startsWith("tree")) return "tree";
14039
14128
  if (keyword.startsWith("page")) return "page";
14040
14129
  if (keyword.startsWith("memory")) return "memory";
14041
14130
  if (keyword.startsWith("linkedlist")) return "linkedlist";
@@ -14060,6 +14149,28 @@ function inferCellKind(rawContent) {
14060
14149
  if (trimmed.includes("|")) return "stat";
14061
14150
  return "text";
14062
14151
  }
14152
+ var CAPTION_RE = /^[ \t]*caption[ \t]+"([^"]*)"[ \t]*$/;
14153
+ var NOTE_RE = /^[ \t]*note[ \t]+"([^"]*)"(?:[ \t]+at[ \t]+(top-left|top-right|bottom-left|bottom-right|center))?[ \t]*$/;
14154
+ function extractCellAnnotations(rawContent) {
14155
+ const inputLines = rawContent.split("\n");
14156
+ const outLines = [];
14157
+ let caption;
14158
+ const notes = [];
14159
+ for (const line of inputLines) {
14160
+ const cm = line.match(CAPTION_RE);
14161
+ if (cm) {
14162
+ caption = cm[1];
14163
+ continue;
14164
+ }
14165
+ const nm = line.match(NOTE_RE);
14166
+ if (nm) {
14167
+ notes.push({ text: nm[1], ...nm[2] ? { position: nm[2] } : {} });
14168
+ continue;
14169
+ }
14170
+ outLines.push(line);
14171
+ }
14172
+ return { rawContent: outLines.join("\n"), caption, notes };
14173
+ }
14063
14174
 
14064
14175
  // ../src/diagrams/mermaid/pie/layout.ts
14065
14176
  function fmtNum(n) {
@@ -39343,18 +39454,22 @@ function layoutTree(ir, theme) {
39343
39454
  ));
39344
39455
  }
39345
39456
  const byId = new Map(ir.nodes.map((n) => [n.id, n]));
39457
+ const activeEdgeSet = new Set((ir.activePaths ?? []).map(([a, b]) => `${a}:${b}`));
39346
39458
  for (const node of ir.nodes) {
39347
39459
  const pb = box(node.id);
39348
39460
  for (const cid of node.children) {
39349
39461
  const cb = box(cid);
39350
39462
  const { start, end } = connectSlots(pb, cb);
39351
- elements.push(p.path(`M ${rhu(start.x)} ${rhu(start.y)} L ${rhu(end.x)} ${rhu(end.y)}`, palette.textMuted, 1.5));
39463
+ const isActive = activeEdgeSet.has(`${node.id}:${cid}`);
39464
+ const edgeColor = isActive ? palette.primary : palette.textMuted;
39465
+ const edgeWidth = isActive ? 2.5 : 1.5;
39466
+ elements.push(p.path(`M ${rhu(start.x)} ${rhu(start.y)} L ${rhu(end.x)} ${rhu(end.y)}`, edgeColor, edgeWidth));
39352
39467
  const child = byId.get(cid);
39353
39468
  if (child.edgeLabel) {
39354
39469
  const mx = (start.x + end.x) / 2, my = (start.y + end.y) / 2;
39355
39470
  const w = measureText(child.edgeLabel, smallFont).width + 8;
39356
39471
  elements.push(p.rect({ x: mx - w / 2, y: my - 9, width: w, height: 16 }, palette.background, palette.background, 0, { rx: 3 }));
39357
- elements.push(p.text(child.edgeLabel, mx, my + 3, smallFont, palette.primary, { anchor: "middle", weight: "bold" }));
39472
+ elements.push(p.text(child.edgeLabel, mx, my + 3, smallFont, isActive ? palette.primary : palette.textMuted, { anchor: "middle", weight: "bold" }));
39358
39473
  }
39359
39474
  }
39360
39475
  }
@@ -40857,14 +40972,46 @@ function buildNodes(lines2) {
40857
40972
  }
40858
40973
 
40859
40974
  // ../src/diagrams/triton/ds/tree/index.ts
40975
+ function extractPathDirectives(input) {
40976
+ const cleanLines = [];
40977
+ const paths = [];
40978
+ const PATH_RE = /^[ \t]*path[ \t]+(.+)$/;
40979
+ for (const line of input.split("\n")) {
40980
+ const m = line.match(PATH_RE);
40981
+ if (m && m[1].includes("->")) {
40982
+ const nodes = m[1].split("->").map((s) => s.trim()).filter(Boolean);
40983
+ if (nodes.length >= 2) {
40984
+ paths.push(nodes);
40985
+ continue;
40986
+ }
40987
+ }
40988
+ cleanLines.push(line);
40989
+ }
40990
+ return { clean: cleanLines.join("\n"), paths };
40991
+ }
40860
40992
  var tree = {
40861
40993
  parseMermaid(input) {
40862
- const raw = parseLines(input);
40994
+ const { clean, paths } = extractPathDirectives(input);
40995
+ const raw = parseLines(clean);
40996
+ const nodes = buildNodes(raw.lines);
40997
+ const labelToId = /* @__PURE__ */ new Map();
40998
+ for (const node of nodes) {
40999
+ if (!labelToId.has(node.label)) labelToId.set(node.label, node.id);
41000
+ }
41001
+ const activePairs = [];
41002
+ for (const seg of paths) {
41003
+ for (let i = 0; i < seg.length - 1; i++) {
41004
+ const fromId = labelToId.get(seg[i]);
41005
+ const toId = labelToId.get(seg[i + 1]);
41006
+ if (fromId && toId) activePairs.push([fromId, toId]);
41007
+ }
41008
+ }
40863
41009
  return {
40864
41010
  version: raw.version,
40865
41011
  metadata: raw.metadata ?? {},
40866
41012
  direction: raw.direction,
40867
- nodes: buildNodes(raw.lines)
41013
+ nodes,
41014
+ ...activePairs.length > 0 ? { activePaths: activePairs } : {}
40868
41015
  };
40869
41016
  },
40870
41017
  parseYaml(input) {
@@ -41616,7 +41763,7 @@ function buildStrip(pen2, theme, cells2, options) {
41616
41763
  const y = origin.y + (horizontal ? 0 : i * step);
41617
41764
  const slot = { x, y, width: cellWidth, height: cellHeight };
41618
41765
  slots.push(slot);
41619
- elements.push(pen2.rect(slot, cell.fill ?? palette.surface, palette.border, 1.5, { rx: 3 }));
41766
+ elements.push(pen2.rect(slot, cell.fill ?? palette.surface, cell.stroke ?? palette.border, 1.5, { rx: 3, ...cell.fillOpacity !== void 0 ? { fillOpacity: cell.fillOpacity } : {} }));
41620
41767
  if (cell.label !== void 0) {
41621
41768
  elements.push(pen2.text(
41622
41769
  cell.label,
@@ -42455,6 +42602,7 @@ function parse11(input) {
42455
42602
  let title;
42456
42603
  const rows = [];
42457
42604
  let showIndex = true;
42605
+ const highlights = [];
42458
42606
  for (const line of input.split(/\r?\n/).map((l) => l.trimEnd())) {
42459
42607
  const trimmed = line.trim();
42460
42608
  if (!trimmed) continue;
@@ -42479,8 +42627,15 @@ function parse11(input) {
42479
42627
  rows.push(t.slice(1));
42480
42628
  continue;
42481
42629
  }
42630
+ if (t[0] === "highlight") {
42631
+ for (const tok of t.slice(1)) {
42632
+ const m = tok.match(/^(\d+),(\d+)$/);
42633
+ if (m) highlights.push([Number(m[1]), Number(m[2])]);
42634
+ }
42635
+ continue;
42636
+ }
42482
42637
  }
42483
- return { ...title !== void 0 ? { title } : {}, rows, showIndex };
42638
+ return { ...title !== void 0 ? { title } : {}, rows, showIndex, ...highlights.length > 0 ? { highlights } : {} };
42484
42639
  }
42485
42640
  function layoutMatrix(doc, theme) {
42486
42641
  const { palette, typography, spacing } = theme;
@@ -42503,7 +42658,10 @@ function layoutMatrix(doc, theme) {
42503
42658
  const anchors = {};
42504
42659
  grid.forEach((row, r) => {
42505
42660
  const rowOrigin = { x: origin.x, y: origin.y + r * cellH };
42506
- const cellInputs = row.map((v) => ({ label: v }));
42661
+ const cellInputs = row.map((v, c) => {
42662
+ const isHighlit = doc.highlights?.some(([hr, hc]) => hr === r && hc === c) ?? false;
42663
+ return isHighlit ? { label: v, fill: palette.primary, fillOpacity: 0.22, stroke: palette.primary } : { label: v };
42664
+ });
42507
42665
  const strip = buildStrip(p, theme, cellInputs, { origin: rowOrigin, cellWidth: cellW, cellHeight: cellH });
42508
42666
  elements.push(...strip.elements);
42509
42667
  strip.slots.forEach((slot, c) => {
@@ -42621,9 +42779,15 @@ function parse12(input) {
42621
42779
  const m = line.match(EDGE_RE);
42622
42780
  if (m) {
42623
42781
  const from = m[1], to = m[3];
42782
+ const rawLabel = m[4]?.trim();
42783
+ let label;
42784
+ let kind;
42785
+ if (rawLabel === "active") kind = "active";
42786
+ else if (rawLabel === "dashed") kind = "dashed";
42787
+ else label = rawLabel;
42624
42788
  ensure(from);
42625
42789
  ensure(to);
42626
- edges2.push({ from, to, ...m[4] ? { label: m[4].trim() } : {} });
42790
+ edges2.push({ from, to, ...label ? { label } : {}, ...kind ? { kind } : {} });
42627
42791
  }
42628
42792
  }
42629
42793
  const nodes = order.map((id) => ({ id, label: labels.get(id) }));
@@ -42654,13 +42818,19 @@ function layoutGraph(doc, theme) {
42654
42818
  const b = placed.boxes.has(e.to) ? box(e.to) : void 0;
42655
42819
  if (!a || !b) continue;
42656
42820
  const { start, end } = connectSlots(a, b);
42657
- const opts2 = doc.directed ? { markerEnd: ARROW_ID2 } : {};
42658
- elements.push(p.path(`M ${rhu(start.x)} ${rhu(start.y)} L ${rhu(end.x)} ${rhu(end.y)}`, palette.textMuted, 1.5, opts2));
42821
+ const isActive = e.kind === "active";
42822
+ const edgeColor = isActive ? palette.primary : palette.textMuted;
42823
+ const edgeWidth = isActive ? 2.5 : 1.5;
42824
+ const pathOpts = {
42825
+ ...doc.directed ? { markerEnd: ARROW_ID2 } : {},
42826
+ ...e.kind === "dashed" ? { dash: "6 3" } : {}
42827
+ };
42828
+ elements.push(p.path(`M ${rhu(start.x)} ${rhu(start.y)} L ${rhu(end.x)} ${rhu(end.y)}`, edgeColor, edgeWidth, pathOpts));
42659
42829
  if (e.label) {
42660
42830
  const mx = (start.x + end.x) / 2, my = (start.y + end.y) / 2;
42661
42831
  const w = measureText(e.label, small).width + 8;
42662
42832
  elements.push(p.rect({ x: mx - w / 2, y: my - 9, width: w, height: 16 }, palette.background, palette.background, 0, { rx: 3 }));
42663
- elements.push(p.text(e.label, mx, my + 3, small, palette.primary, { anchor: "middle", weight: "bold" }));
42833
+ elements.push(p.text(e.label, mx, my + 3, small, isActive ? palette.primary : palette.textMuted, { anchor: "middle", weight: "bold" }));
42664
42834
  }
42665
42835
  }
42666
42836
  const anchors = {};