@blankdotpage/cake 0.1.75 → 0.1.76

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.
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/cake/core/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/cake/core/runtime.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,7 @@ export function isApplyEditCommand(command) {
19
19
  command.type === "delete-forward");
20
20
  }
21
21
  const defaultSelection = { start: 0, end: 0, affinity: "forward" };
22
+ const WORD_CHARACTER_PATTERN = /[\p{L}\p{N}_]/u;
22
23
  function removeFromArray(arr, value) {
23
24
  const index = arr.indexOf(value);
24
25
  if (index === -1) {
@@ -347,13 +348,17 @@ export function createRuntimeFromRegistry(registry) {
347
348
  }
348
349
  content.push(normalizedInline);
349
350
  }
351
+ const mergedContent = mergeAdjacentInlines(content);
352
+ if (mergedContent !== content) {
353
+ changed = true;
354
+ }
350
355
  if (!changed) {
351
356
  normalizedBlockCache.set(block, next);
352
357
  return next;
353
358
  }
354
359
  const normalized = {
355
360
  ...next,
356
- content,
361
+ content: mergedContent,
357
362
  };
358
363
  normalizedBlockCache.set(block, normalized);
359
364
  return normalized;
@@ -409,17 +414,52 @@ export function createRuntimeFromRegistry(registry) {
409
414
  }
410
415
  let next = pre;
411
416
  if (next.type === "inline-wrapper") {
417
+ const children = mergeAdjacentInlines(next.children
418
+ .map((child) => normalizeInline(child))
419
+ .filter((child) => child !== null));
412
420
  next = {
413
421
  ...next,
414
- children: next.children
415
- .map((child) => normalizeInline(child))
416
- .filter((child) => child !== null),
422
+ children,
417
423
  };
418
424
  }
419
425
  const normalized = applyInlineNormalizers(next);
420
426
  normalizedInlineCache.set(inline, normalized ?? removedInlineSentinel);
421
427
  return normalized;
422
428
  }
429
+ function mergeAdjacentInlines(inlines) {
430
+ if (inlines.length < 2) {
431
+ return inlines;
432
+ }
433
+ const merged = [];
434
+ let changed = false;
435
+ for (const inline of inlines) {
436
+ const previous = merged[merged.length - 1];
437
+ if (previous?.type === "text" && inline.type === "text") {
438
+ merged[merged.length - 1] = {
439
+ ...previous,
440
+ text: previous.text + inline.text,
441
+ };
442
+ changed = true;
443
+ continue;
444
+ }
445
+ if (previous?.type === "inline-wrapper" &&
446
+ inline.type === "inline-wrapper" &&
447
+ previous.kind === inline.kind &&
448
+ stableStringify(previous.data) === stableStringify(inline.data)) {
449
+ merged[merged.length - 1] = {
450
+ ...previous,
451
+ children: mergeAdjacentInlines([
452
+ ...previous.children,
453
+ ...inline.children,
454
+ ]),
455
+ };
456
+ changed = true;
457
+ continue;
458
+ }
459
+ merged.push(inline);
460
+ }
461
+ return changed ? merged : inlines;
462
+ }
423
463
  function createTopLevelBlockSegment(block) {
424
464
  const serialized = serializeBlock(block);
425
465
  return {
@@ -571,9 +611,15 @@ export function createRuntimeFromRegistry(registry) {
571
611
  ? previousSegmented
572
612
  : undefined;
573
613
  const segmented = buildSegmentedDocState(normalized, reusablePrevious);
614
+ const cursorLength = segmented.map.cursorLength;
615
+ const clampedSelection = {
616
+ ...selection,
617
+ start: Math.max(0, Math.min(cursorLength, selection.start)),
618
+ end: Math.max(0, Math.min(cursorLength, selection.end)),
619
+ };
574
620
  return {
575
621
  source: segmented.source,
576
- selection,
622
+ selection: normalizeSelection(clampedSelection),
577
623
  map: segmented.map,
578
624
  doc: normalized,
579
625
  runtime: runtime,
@@ -725,7 +771,8 @@ export function createRuntimeFromRegistry(registry) {
725
771
  previousState: useIncrementalSegmentedDerivation ? state : undefined,
726
772
  });
727
773
  const interimAffinity = structural.nextAffinity ?? "forward";
728
- const caretSource = interim.map.cursorToSource(structural.nextCursor, interimAffinity);
774
+ const interimCursor = Math.max(0, Math.min(interim.map.cursorLength, structural.nextCursor));
775
+ const caretSource = interim.map.cursorToSource(interimCursor, interimAffinity);
729
776
  if (useIncrementalSegmentedDerivation) {
730
777
  const caretCursor = interim.map.sourceToCursor(caretSource, interimAffinity);
731
778
  return {
@@ -812,6 +859,27 @@ export function createRuntimeFromRegistry(registry) {
812
859
  replaceText.length > 0 &&
813
860
  range.start === range.end &&
814
861
  textModel.getGraphemeAtCursor(range.start) === "\u200B";
862
+ if (command.type === "insert" && shouldReplacePlaceholder) {
863
+ const leadingWhitespace = replaceText.match(/^\s+/)?.[0] ?? "";
864
+ const around = marksAroundCursor(doc, range.start);
865
+ if (leadingWhitespace.length > 0) {
866
+ if (isMarksPrefix(around.left, around.right) &&
867
+ around.right.length > around.left.length) {
868
+ const whitespaceInsert = insertTextBeforePendingPlaceholderInDoc(doc, range.start, leadingWhitespace, around.left);
869
+ if (whitespaceInsert) {
870
+ const trailingText = replaceText.slice(leadingWhitespace.length);
871
+ if (trailingText.length === 0) {
872
+ return whitespaceInsert;
873
+ }
874
+ return applyStructuralEdit({ type: "insert", text: trailingText }, whitespaceInsert.doc, {
875
+ start: whitespaceInsert.nextCursor,
876
+ end: whitespaceInsert.nextCursor,
877
+ affinity: whitespaceInsert.nextAffinity,
878
+ });
879
+ }
880
+ }
881
+ }
882
+ }
815
883
  const effectiveRange = shouldReplacePlaceholder
816
884
  ? { start: range.start, end: Math.min(docCursorLength, range.start + 1) }
817
885
  : range;
@@ -1174,6 +1242,18 @@ export function createRuntimeFromRegistry(registry) {
1174
1242
  return true;
1175
1243
  });
1176
1244
  }
1245
+ function mergeMarksPreservingOrder(...groups) {
1246
+ const next = [];
1247
+ for (const group of groups) {
1248
+ for (const mark of group) {
1249
+ if (next.some((existing) => existing.key === mark.key)) {
1250
+ continue;
1251
+ }
1252
+ next.push(mark);
1253
+ }
1254
+ }
1255
+ return next;
1256
+ }
1177
1257
  function sliceRuns(runs, startCursor, endCursor) {
1178
1258
  const [left, rest] = splitRunsAt(runs, startCursor);
1179
1259
  const [selected, right] = splitRunsAt(rest, Math.max(0, endCursor - startCursor));
@@ -1330,27 +1410,188 @@ export function createRuntimeFromRegistry(registry) {
1330
1410
  },
1331
1411
  };
1332
1412
  }
1333
- function canPreserveRemainingMarksAtBoundary(state, cursorOffset, targetKind, remainingMarks) {
1413
+ function rewritePendingPlaceholderAtCursor(state, cursorOffset, marks) {
1334
1414
  const textModel = getEditorTextModelForDoc(state.doc);
1335
1415
  const lines = textModel.getStructuralLines();
1336
1416
  const loc = textModel.resolveOffsetToLine(cursorOffset);
1337
1417
  const line = lines[loc.lineIndex];
1338
1418
  if (!line) {
1339
- return false;
1419
+ return null;
1340
1420
  }
1341
1421
  const block = getBlockAtPath(state.doc.blocks, line.path);
1342
1422
  if (!block || block.type !== "paragraph") {
1343
- return false;
1423
+ return null;
1344
1424
  }
1425
+ const placeholder = "\u200B";
1345
1426
  const runs = paragraphToRuns(block);
1346
- const { before } = sliceRuns(runs, loc.offsetInLine, loc.offsetInLine);
1347
- const remainingKeys = remainingMarks.map((mark) => mark.key);
1348
- return before.every((run) => {
1349
- if (!run.marks.some((mark) => mark.kind === targetKind)) {
1350
- return true;
1427
+ const { before, after } = sliceRuns(runs, loc.offsetInLine, loc.offsetInLine);
1428
+ const replacement = [];
1429
+ const firstAfter = after[0];
1430
+ if (firstAfter?.type === "text" && firstAfter.text.startsWith(placeholder)) {
1431
+ if (marks && marks.length > 0) {
1432
+ replacement.push({ type: "text", text: placeholder, marks });
1433
+ }
1434
+ if (firstAfter.text.length > placeholder.length) {
1435
+ replacement.push({
1436
+ ...firstAfter,
1437
+ text: firstAfter.text.slice(placeholder.length),
1438
+ });
1351
1439
  }
1352
- return remainingKeys.every((key) => run.marks.some((mark) => mark.key === key));
1353
- });
1440
+ replacement.push(...after.slice(1));
1441
+ }
1442
+ else {
1443
+ const lastBefore = before[before.length - 1];
1444
+ if (lastBefore?.type !== "text" ||
1445
+ !lastBefore.text.endsWith(placeholder)) {
1446
+ return null;
1447
+ }
1448
+ const prefix = lastBefore.text.slice(0, -placeholder.length);
1449
+ if (prefix) {
1450
+ replacement.push({ ...lastBefore, text: prefix });
1451
+ }
1452
+ if (marks && marks.length > 0) {
1453
+ replacement.push({ type: "text", text: placeholder, marks });
1454
+ }
1455
+ replacement.push(...after);
1456
+ before.pop();
1457
+ }
1458
+ const mergedRuns = normalizeRuns([...before, ...replacement]);
1459
+ const nextBlock = {
1460
+ ...block,
1461
+ content: runsToInlines(mergedRuns),
1462
+ };
1463
+ const parentPath = line.path.slice(0, -1);
1464
+ const indexInParent = line.path[line.path.length - 1] ?? 0;
1465
+ const nextDoc = {
1466
+ ...state.doc,
1467
+ blocks: updateBlocksAtPath(state.doc.blocks, parentPath, (blocks) => blocks.map((child, index) => index === indexInParent ? nextBlock : child)),
1468
+ };
1469
+ const next = createStateFromDoc(nextDoc);
1470
+ return {
1471
+ ...next,
1472
+ selection: {
1473
+ start: cursorOffset,
1474
+ end: cursorOffset,
1475
+ affinity: marks && marks.length > 0 ? "forward" : "backward",
1476
+ },
1477
+ };
1478
+ }
1479
+ function updatePendingPlaceholderMarksAtCursor(state, cursorOffset, marks) {
1480
+ return rewritePendingPlaceholderAtCursor(state, cursorOffset, marks);
1481
+ }
1482
+ function removePendingPlaceholderAtCursor(state, cursorOffset) {
1483
+ return rewritePendingPlaceholderAtCursor(state, cursorOffset, null);
1484
+ }
1485
+ function getPendingPlaceholderMarksAtCursor(state, cursorOffset) {
1486
+ const textModel = getEditorTextModelForDoc(state.doc);
1487
+ const lines = textModel.getStructuralLines();
1488
+ const loc = textModel.resolveOffsetToLine(cursorOffset);
1489
+ const line = lines[loc.lineIndex];
1490
+ if (!line) {
1491
+ return null;
1492
+ }
1493
+ const block = getBlockAtPath(state.doc.blocks, line.path);
1494
+ if (!block || block.type !== "paragraph") {
1495
+ return null;
1496
+ }
1497
+ const placeholder = "\u200B";
1498
+ const runs = paragraphToRuns(block);
1499
+ const { before, after } = sliceRuns(runs, loc.offsetInLine, loc.offsetInLine);
1500
+ const firstAfter = after[0];
1501
+ if (firstAfter?.type === "text" && firstAfter.text.startsWith(placeholder)) {
1502
+ return firstAfter.marks;
1503
+ }
1504
+ const lastBefore = before[before.length - 1];
1505
+ if (lastBefore?.type === "text" &&
1506
+ lastBefore.text.endsWith(placeholder)) {
1507
+ return lastBefore.marks;
1508
+ }
1509
+ return null;
1510
+ }
1511
+ function insertTextBeforePendingPlaceholderInDoc(doc, cursorOffset, text, marks) {
1512
+ const textModel = getEditorTextModelForDoc(doc);
1513
+ const lines = textModel.getStructuralLines();
1514
+ const loc = textModel.resolveOffsetToLine(cursorOffset);
1515
+ const line = lines[loc.lineIndex];
1516
+ if (!line) {
1517
+ return null;
1518
+ }
1519
+ const block = getBlockAtPath(doc.blocks, line.path);
1520
+ if (!block || block.type !== "paragraph") {
1521
+ return null;
1522
+ }
1523
+ const placeholder = "\u200B";
1524
+ const runs = paragraphToRuns(block);
1525
+ const { before, after } = sliceRuns(runs, loc.offsetInLine, loc.offsetInLine);
1526
+ const firstAfter = after[0];
1527
+ if (firstAfter?.type !== "text" ||
1528
+ !firstAfter.text.startsWith(placeholder)) {
1529
+ return null;
1530
+ }
1531
+ const mergedRuns = normalizeRuns([
1532
+ ...before,
1533
+ ...(text.length > 0 ? [{ type: "text", text, marks }] : []),
1534
+ firstAfter,
1535
+ ...after.slice(1),
1536
+ ]);
1537
+ const nextBlock = {
1538
+ ...block,
1539
+ content: runsToInlines(mergedRuns),
1540
+ };
1541
+ const parentPath = line.path.slice(0, -1);
1542
+ const indexInParent = line.path[line.path.length - 1] ?? 0;
1543
+ const nextDoc = {
1544
+ ...doc,
1545
+ blocks: updateBlocksAtPath(doc.blocks, parentPath, (blocks) => blocks.map((child, index) => index === indexInParent ? nextBlock : child)),
1546
+ };
1547
+ return {
1548
+ doc: nextDoc,
1549
+ nextCursor: cursorOffset + Array.from(graphemeSegments(text)).length,
1550
+ nextAffinity: "forward",
1551
+ };
1552
+ }
1553
+ function hasInlineMarkerBoundaryBefore(source, markerStart) {
1554
+ if (markerStart <= 0) {
1555
+ return true;
1556
+ }
1557
+ return !WORD_CHARACTER_PATTERN.test(source[markerStart - 1] ?? "");
1558
+ }
1559
+ function pickSafeCollapsedToggleMarkerSpec(params) {
1560
+ const { defaultSpec, source, insertAt, affinity } = params;
1561
+ const candidates = Array.from(toggleMarkerToSpec.values()).filter((spec, index, all) => spec.kind === defaultSpec.kind &&
1562
+ all.findIndex((candidate) => candidate.kind === spec.kind &&
1563
+ candidate.open === spec.open &&
1564
+ candidate.close === spec.close) === index);
1565
+ if (candidates.length <= 1) {
1566
+ return defaultSpec;
1567
+ }
1568
+ const previousChar = source[insertAt - 1] ?? "";
1569
+ const nextChar = source[insertAt] ?? "";
1570
+ let bestSpec = defaultSpec;
1571
+ let bestScore = Number.POSITIVE_INFINITY;
1572
+ for (const spec of candidates) {
1573
+ if (spec.open === "_" &&
1574
+ !hasInlineMarkerBoundaryBefore(source, insertAt)) {
1575
+ continue;
1576
+ }
1577
+ let score = 0;
1578
+ if (previousChar && spec.open[0] === previousChar) {
1579
+ score += affinity === "forward" ? 8 : 3;
1580
+ }
1581
+ if (nextChar &&
1582
+ spec.close[spec.close.length - 1] === nextChar) {
1583
+ score += affinity === "backward" ? 8 : 3;
1584
+ }
1585
+ if (spec.open === defaultSpec.open &&
1586
+ spec.close === defaultSpec.close) {
1587
+ score -= 0.5;
1588
+ }
1589
+ if (score < bestScore) {
1590
+ bestSpec = spec;
1591
+ bestScore = score;
1592
+ }
1593
+ }
1594
+ return bestSpec;
1354
1595
  }
1355
1596
  function preferredAffinityAtGap(left, right, fallback) {
1356
1597
  if (isMarksPrefix(left, right) && right.length > left.length) {
@@ -1611,18 +1852,39 @@ export function createRuntimeFromRegistry(registry) {
1611
1852
  };
1612
1853
  if (selection.start === selection.end) {
1613
1854
  const caret = selection.start;
1855
+ const pendingPlaceholderMarks = getPendingPlaceholderMarksAtCursor(state, caret);
1856
+ if (pendingPlaceholderMarks) {
1857
+ const hasMarker = pendingPlaceholderMarks.some((mark) => mark.kind === markerKind);
1858
+ const around = marksAroundCursor(state.doc, caret);
1859
+ const nextMarks = hasMarker
1860
+ ? removeMarkByKind(pendingPlaceholderMarks, markerKind)
1861
+ : mergeMarksPreservingOrder(around.left, pendingPlaceholderMarks, [markerMark]);
1862
+ const next = nextMarks.length > 0
1863
+ ? updatePendingPlaceholderMarksAtCursor(state, caret, nextMarks)
1864
+ : removePendingPlaceholderAtCursor(state, caret);
1865
+ if (next) {
1866
+ return {
1867
+ ...next,
1868
+ selection: {
1869
+ start: caret,
1870
+ end: caret,
1871
+ affinity: "forward",
1872
+ },
1873
+ };
1874
+ }
1875
+ }
1614
1876
  // When the caret is at the end boundary of an inline wrapper, toggling the
1615
1877
  // wrapper should "exit" it (so the next character types outside). This is
1616
1878
  // best expressed in cursor space by flipping affinity to "forward" when we
1617
1879
  // are leaving a wrapper of the requested kind.
1618
1880
  const around = marksAroundCursor(state.doc, caret);
1619
1881
  if (isMarksPrefix(around.right, around.left) &&
1620
- around.left.length > around.right.length) {
1882
+ around.left.length > around.right.length &&
1883
+ (selection.affinity ?? "forward") === "backward") {
1621
1884
  const exiting = around.left.slice(around.right.length);
1622
1885
  if (exiting.some((mark) => mark.kind === markerKind)) {
1623
1886
  const remainingMarks = removeMarkByKind(around.left, markerKind);
1624
- if (!marksEqual(remainingMarks, around.right) &&
1625
- canPreserveRemainingMarksAtBoundary(state, caret, markerKind, remainingMarks)) {
1887
+ if (!marksEqual(remainingMarks, around.right)) {
1626
1888
  const next = createPendingPlaceholderStateAtCursor(state, caret, remainingMarks);
1627
1889
  if (next) {
1628
1890
  return next;
@@ -1645,6 +1907,20 @@ export function createRuntimeFromRegistry(registry) {
1645
1907
  around.right.length > around.left.length) {
1646
1908
  const entering = around.right.slice(around.left.length);
1647
1909
  if (entering.some((mark) => mark.kind === markerKind)) {
1910
+ const remainingMarks = removeMarkByKind(around.right, markerKind);
1911
+ const next = remainingMarks.length > 0
1912
+ ? updatePendingPlaceholderMarksAtCursor(state, caret, remainingMarks)
1913
+ : removePendingPlaceholderAtCursor(state, caret);
1914
+ if (next) {
1915
+ return {
1916
+ ...next,
1917
+ selection: {
1918
+ start: caret,
1919
+ end: caret,
1920
+ affinity: "backward",
1921
+ },
1922
+ };
1923
+ }
1648
1924
  const insertAtBackward = map.cursorToSource(caret, "backward");
1649
1925
  const insertAtForward = map.cursorToSource(caret, "forward");
1650
1926
  const after = source.slice(insertAtBackward);
@@ -1705,6 +1981,7 @@ export function createRuntimeFromRegistry(registry) {
1705
1981
  }
1706
1982
  if (isMarksPrefix(around.right, around.left) &&
1707
1983
  around.left.length > around.right.length &&
1984
+ (selection.affinity ?? "forward") === "backward" &&
1708
1985
  !around.left.some((mark) => mark.kind === markerKind)) {
1709
1986
  const next = createPendingPlaceholderStateAtCursor(state, caret, [
1710
1987
  ...around.left,
@@ -1735,34 +2012,63 @@ export function createRuntimeFromRegistry(registry) {
1735
2012
  return null;
1736
2013
  })();
1737
2014
  // When at a boundary between cursor positions (insertAtBackward !== insertAtForward),
1738
- // prefer insertAtBackward to keep new markers inside the current formatting context.
1739
- // However, only do this if the new marker length is <= the boundary marker length,
1740
- // otherwise we create ambiguous marker sequences (e.g., *italic**​*** doesn't parse).
2015
+ // only prefer insertAtBackward if the caret is intentionally anchored inside the
2016
+ // left formatting context. If the caret affinity is forward, the user explicitly
2017
+ // exited that wrapper and new markers belong on the forward side of the gap.
2018
+ // Still guard against inserting a longer marker into a shorter boundary run,
2019
+ // which would create ambiguous source (e.g., *italic**​***).
1741
2020
  const betweenLen = insertAtForward - insertAtBackward;
1742
- const preferBackward = insertAtBackward !== insertAtForward && openLen <= betweenLen;
2021
+ const preferBackward = insertAtBackward !== insertAtForward &&
2022
+ (selection.affinity ?? "forward") === "backward" &&
2023
+ openLen <= betweenLen;
1743
2024
  const insertAt = placeholderPos ?? (preferBackward ? insertAtBackward : insertAtForward);
2025
+ const insertMarkerSpec = placeholderPos === null
2026
+ ? pickSafeCollapsedToggleMarkerSpec({
2027
+ defaultSpec: markerSpec,
2028
+ source,
2029
+ insertAt,
2030
+ affinity: selection.affinity ?? "forward",
2031
+ })
2032
+ : markerSpec;
2033
+ const insertOpenMarker = insertMarkerSpec.open;
2034
+ const insertCloseMarker = insertMarkerSpec.close;
2035
+ const insertOpenLen = insertOpenMarker.length;
2036
+ const baseMarks = (selection.affinity ?? "forward") === "backward"
2037
+ ? around.left
2038
+ : around.right;
2039
+ const nextMarks = [
2040
+ ...baseMarks.filter((mark) => mark.kind !== markerKind),
2041
+ markerMark,
2042
+ ];
2043
+ if (placeholderPos !== null) {
2044
+ const next = updatePendingPlaceholderMarksAtCursor(state, caret, nextMarks);
2045
+ if (next) {
2046
+ return next;
2047
+ }
2048
+ }
2049
+ const docInserted = createPendingPlaceholderStateAtCursor(state, caret, nextMarks);
2050
+ if (docInserted) {
2051
+ return docInserted;
2052
+ }
1744
2053
  const nextSource = placeholderPos !== null
1745
2054
  ? source.slice(0, insertAt) +
1746
- openMarker +
2055
+ insertOpenMarker +
1747
2056
  placeholder +
1748
- closeMarker +
2057
+ insertCloseMarker +
1749
2058
  source.slice(insertAt + placeholder.length)
1750
2059
  : source.slice(0, insertAt) +
1751
- openMarker +
2060
+ insertOpenMarker +
1752
2061
  placeholder +
1753
- closeMarker +
2062
+ insertCloseMarker +
1754
2063
  source.slice(insertAt);
1755
2064
  const next = createState(nextSource);
1756
- const placeholderStart = insertAt + openLen;
2065
+ const placeholderStart = insertAt + insertOpenLen;
1757
2066
  const startCursor = next.map.sourceToCursor(placeholderStart, "forward");
1758
- return {
1759
- ...next,
1760
- selection: {
1761
- start: startCursor.cursorOffset,
1762
- end: startCursor.cursorOffset,
1763
- affinity: "forward",
1764
- },
1765
- };
2067
+ return createStateFromDoc(next.doc, {
2068
+ start: startCursor.cursorOffset,
2069
+ end: startCursor.cursorOffset,
2070
+ affinity: "forward",
2071
+ });
1766
2072
  }
1767
2073
  const cursorStart = Math.min(selection.start, selection.end);
1768
2074
  const cursorEnd = Math.max(selection.start, selection.end);
@@ -1 +1 @@
1
- {"version":3,"file":"bold.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/bold/bold.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,oBAAoB,CAAC;AAU5B,eAAO,MAAM,aAAa,EAAE,aA2I3B,CAAC"}
1
+ {"version":3,"file":"bold.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/bold/bold.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,oBAAoB,CAAC;AAU5B,eAAO,MAAM,aAAa,EAAE,aAkJ3B,CAAC"}
@@ -69,14 +69,19 @@ export const boldExtension = (editor) => {
69
69
  }
70
70
  const builder = new CursorSourceBuilder();
71
71
  builder.appendSourceOnly("**");
72
+ const defaultChildResults = inline.children.map((child) => context.serializeInline(child));
73
+ let previousSource = "";
72
74
  inline.children.forEach((child, index) => {
75
+ const nextSource = defaultChildResults[index + 1]?.source ?? "";
73
76
  const serialized = child.type === "inline-wrapper" &&
74
77
  child.kind === "italic" &&
75
- index === 0 &&
76
- inline.children.length > 1
78
+ (previousSource.endsWith("*") ||
79
+ nextSource.startsWith("*") ||
80
+ (index === 0 && inline.children.length > 1))
77
81
  ? serializeItalicInlineWithMarker(child, context, "_")
78
- : context.serializeInline(child);
82
+ : (defaultChildResults[index] ?? context.serializeInline(child));
79
83
  builder.appendSerialized(serialized);
84
+ previousSource = serialized.source;
80
85
  });
81
86
  builder.appendSourceOnly("**");
82
87
  return builder.build();
@@ -1 +1 @@
1
- {"version":3,"file":"heading.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/heading/heading.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,oBAAoB,CAAC;AAwa5B,eAAO,MAAM,gBAAgB,EAAE,aAwM9B,CAAC"}
1
+ {"version":3,"file":"heading.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/heading/heading.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,oBAAoB,CAAC;AAwa5B,eAAO,MAAM,gBAAgB,EAAE,aA2M9B,CAAC"}
@@ -351,7 +351,7 @@ export const headingExtension = (editor) => {
351
351
  if (selection.start !== selection.end) {
352
352
  return null;
353
353
  }
354
- const cursorPos = selection.start;
354
+ const cursorPos = Math.max(0, Math.min(map.cursorLength, selection.start));
355
355
  const sourcePos = map.cursorToSource(cursorPos, selection.affinity ?? "forward");
356
356
  const lineStart = findLineStartInSource(source, sourcePos);
357
357
  const prefix = source.slice(lineStart, sourcePos);
@@ -1 +1 @@
1
- {"version":3,"file":"italic.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/italic/italic.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAGlB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAmB/C,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,EAC3C,OAAO,EAAE;IACP,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,qBAAqB,CAAC;CAC5D,EACD,MAAM,EAAE,GAAG,GAAG,GAAG,GAChB,qBAAqB,CAGvB;AAkCD,eAAO,MAAM,eAAe,EAAE,aAqI7B,CAAC"}
1
+ {"version":3,"file":"italic.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/italic/italic.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAIlB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAS,MAAM,EAAE,MAAM,kBAAkB,CAAC;AA+BtD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,EAC3C,OAAO,EAAE;IACP,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,qBAAqB,CAAC;CAC5D,EACD,MAAM,EAAE,GAAG,GAAG,GAAG,GAChB,qBAAqB,CAGvB;AAmGD,eAAO,MAAM,eAAe,EAAE,aAsJ7B,CAAC"}
@@ -10,29 +10,83 @@ function buildItalicSerialization(childResults, marker) {
10
10
  builder.appendSourceOnly(marker);
11
11
  return builder.build();
12
12
  }
13
+ function canParseSerializedUnderscoreRun(source, start, close) {
14
+ return (source[start + 1] === "*" ||
15
+ source[close - 1] === "*" ||
16
+ source[close + 1] === "*");
17
+ }
13
18
  export function serializeItalicInlineWithMarker(inline, context, marker) {
14
19
  const childResults = inline.children.map((child) => context.serializeInline(child));
15
20
  return buildItalicSerialization(childResults, marker);
16
21
  }
22
+ function serializeInlineSequenceWithSafeItalic(inlines, context) {
23
+ const builder = new CursorSourceBuilder();
24
+ const defaultResults = inlines.map((inline) => context.serializeInline(inline));
25
+ let previousSource = "";
26
+ inlines.forEach((inline, index) => {
27
+ const nextSource = defaultResults[index + 1]?.source ?? "";
28
+ const serialized = inline.type === "inline-wrapper" &&
29
+ inline.kind === ITALIC_KIND &&
30
+ (previousSource.endsWith("*") || nextSource.startsWith("*"))
31
+ ? serializeItalicInlineWithMarker(inline, context, "_")
32
+ : (defaultResults[index] ?? context.serializeInline(inline));
33
+ builder.appendSerialized(serialized);
34
+ previousSource = serialized.source;
35
+ });
36
+ return builder.build();
37
+ }
17
38
  function findItalicClose(source, start, end, marker) {
18
39
  if (marker === "_") {
19
40
  return source.indexOf("_", start + 1);
20
41
  }
21
- let fallback = -1;
22
42
  for (let i = start + 1; i < end; i += 1) {
23
43
  if (source[i] !== "*") {
24
44
  continue;
25
45
  }
26
- const prevIsStar = source[i - 1] === "*";
27
- const nextIsStar = source[i + 1] === "*";
28
- if (!prevIsStar && !nextIsStar) {
46
+ let runStart = i;
47
+ while (runStart > start + 1 && source[runStart - 1] === "*") {
48
+ runStart -= 1;
49
+ }
50
+ let runEnd = i;
51
+ while (runEnd + 1 < end && source[runEnd + 1] === "*") {
52
+ runEnd += 1;
53
+ }
54
+ const runLength = runEnd - runStart + 1;
55
+ if (runLength === 1) {
56
+ if (hasUnmatchedBoldRun(source, start + 1, i)) {
57
+ continue;
58
+ }
29
59
  return i;
30
60
  }
31
- if (fallback === -1) {
32
- fallback = i;
61
+ const hasUnmatchedBold = hasUnmatchedBoldRun(source, start + 1, runStart);
62
+ const hasBoldCloserAhead = source.indexOf("**", runEnd + 1) !== -1;
63
+ if (!hasBoldCloserAhead) {
64
+ if (runLength === 2 && hasUnmatchedBold) {
65
+ i = runEnd;
66
+ continue;
67
+ }
68
+ if (runLength >= 3 && hasUnmatchedBold) {
69
+ return runEnd;
70
+ }
71
+ return runStart;
72
+ }
73
+ i = runEnd;
74
+ }
75
+ return -1;
76
+ }
77
+ function hasUnmatchedBoldRun(source, start, end) {
78
+ let parity = 0;
79
+ for (let i = start; i < end; i += 1) {
80
+ if (source[i] !== "*" || source[i + 1] !== "*") {
81
+ continue;
82
+ }
83
+ if (source[i - 1] === "*" || source[i + 2] === "*") {
84
+ continue;
33
85
  }
86
+ parity ^= 1;
87
+ i += 1;
34
88
  }
35
- return fallback;
89
+ return parity === 1;
36
90
  }
37
91
  export const italicExtension = (editor) => {
38
92
  const disposers = [];
@@ -58,9 +112,6 @@ export const italicExtension = (editor) => {
58
112
  if (char !== "_" && char !== "*") {
59
113
  return null;
60
114
  }
61
- if (char === "_" && !hasInlineMarkerBoundaryBefore(source, start)) {
62
- return null;
63
- }
64
115
  // Don't match ** (that's bold)
65
116
  if (char === "*" && source[start + 1] === "*") {
66
117
  return null;
@@ -75,6 +126,11 @@ export const italicExtension = (editor) => {
75
126
  if (close === -1 || close >= end) {
76
127
  return null;
77
128
  }
129
+ if (char === "_" &&
130
+ !hasInlineMarkerBoundaryBefore(source, start) &&
131
+ !canParseSerializedUnderscoreRun(source, start, close)) {
132
+ return null;
133
+ }
78
134
  // Don't match empty delimiters like ** that could be start of bold
79
135
  if (close === start + 1 && close + 1 < end) {
80
136
  return null;
@@ -89,6 +145,12 @@ export const italicExtension = (editor) => {
89
145
  nextPos: close + 1,
90
146
  };
91
147
  }));
148
+ disposers.push(editor.registerSerializeBlock((block, context) => {
149
+ if (block.type !== "paragraph") {
150
+ return null;
151
+ }
152
+ return serializeInlineSequenceWithSafeItalic(block.content, context);
153
+ }));
92
154
  disposers.push(editor.registerSerializeInline((inline, context) => {
93
155
  if (inline.type !== "inline-wrapper" || inline.kind !== ITALIC_KIND) {
94
156
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blankdotpage/cake",
3
- "version": "0.1.75",
3
+ "version": "0.1.76",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",