@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.
- package/dist/cake/core/runtime.d.ts.map +1 -1
- package/dist/cake/core/runtime.js +342 -36
- package/dist/cake/extensions/bold/bold.d.ts.map +1 -1
- package/dist/cake/extensions/bold/bold.js +8 -3
- package/dist/cake/extensions/heading/heading.d.ts.map +1 -1
- package/dist/cake/extensions/heading/heading.js +1 -1
- package/dist/cake/extensions/italic/italic.d.ts.map +1 -1
- package/dist/cake/extensions/italic/italic.js +72 -10
- package/package.json +1 -1
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
1419
|
+
return null;
|
|
1340
1420
|
}
|
|
1341
1421
|
const block = getBlockAtPath(state.doc.blocks, line.path);
|
|
1342
1422
|
if (!block || block.type !== "paragraph") {
|
|
1343
|
-
return
|
|
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
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
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
|
-
|
|
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
|
|
1739
|
-
//
|
|
1740
|
-
//
|
|
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 &&
|
|
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
|
-
|
|
2055
|
+
insertOpenMarker +
|
|
1747
2056
|
placeholder +
|
|
1748
|
-
|
|
2057
|
+
insertCloseMarker +
|
|
1749
2058
|
source.slice(insertAt + placeholder.length)
|
|
1750
2059
|
: source.slice(0, insertAt) +
|
|
1751
|
-
|
|
2060
|
+
insertOpenMarker +
|
|
1752
2061
|
placeholder +
|
|
1753
|
-
|
|
2062
|
+
insertCloseMarker +
|
|
1754
2063
|
source.slice(insertAt);
|
|
1755
2064
|
const next = createState(nextSource);
|
|
1756
|
-
const placeholderStart = insertAt +
|
|
2065
|
+
const placeholderStart = insertAt + insertOpenLen;
|
|
1757
2066
|
const startCursor = next.map.sourceToCursor(placeholderStart, "forward");
|
|
1758
|
-
return {
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
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,
|
|
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
|
-
|
|
76
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
32
|
-
|
|
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
|
|
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;
|