@blankdotpage/cake 0.1.68 → 0.1.69
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/mapping/cursor-source-map.d.ts +11 -0
- package/dist/cake/core/mapping/cursor-source-map.d.ts.map +1 -1
- package/dist/cake/core/mapping/cursor-source-map.js +159 -21
- package/dist/cake/core/runtime.d.ts +4 -0
- package/dist/cake/core/runtime.d.ts.map +1 -1
- package/dist/cake/core/runtime.js +332 -215
- package/dist/cake/dom/render.d.ts +32 -2
- package/dist/cake/dom/render.d.ts.map +1 -1
- package/dist/cake/dom/render.js +401 -118
- package/dist/cake/editor/cake-editor.d.ts +8 -1
- package/dist/cake/editor/cake-editor.d.ts.map +1 -1
- package/dist/cake/editor/cake-editor.js +172 -100
- package/dist/cake/editor/internal/editor-text-model.d.ts +49 -0
- package/dist/cake/editor/internal/editor-text-model.d.ts.map +1 -0
- package/dist/cake/editor/internal/editor-text-model.js +284 -0
- package/dist/cake/editor/selection/selection-geometry-dom.d.ts +5 -1
- package/dist/cake/editor/selection/selection-geometry-dom.d.ts.map +1 -1
- package/dist/cake/editor/selection/selection-geometry-dom.js +4 -5
- package/dist/cake/editor/selection/selection-layout-dom.d.ts.map +1 -1
- package/dist/cake/editor/selection/selection-layout-dom.js +2 -5
- package/dist/cake/editor/selection/selection-layout.d.ts +2 -15
- package/dist/cake/editor/selection/selection-layout.d.ts.map +1 -1
- package/dist/cake/editor/selection/selection-layout.js +1 -99
- package/dist/cake/editor/selection/selection-navigation.d.ts +4 -0
- package/dist/cake/editor/selection/selection-navigation.d.ts.map +1 -1
- package/dist/cake/editor/selection/selection-navigation.js +1 -2
- package/dist/cake/extensions/link/link.d.ts.map +1 -1
- package/dist/cake/extensions/link/link.js +1 -7
- package/dist/cake/extensions/shared/structural-reparse-policy.js +2 -2
- package/package.json +5 -2
- package/dist/cake/editor/selection/visible-text.d.ts +0 -5
- package/dist/cake/editor/selection/visible-text.d.ts.map +0 -1
- package/dist/cake/editor/selection/visible-text.js +0 -66
- package/dist/cake/engine/cake-engine.d.ts +0 -230
- package/dist/cake/engine/cake-engine.d.ts.map +0 -1
- package/dist/cake/engine/cake-engine.js +0 -3589
- package/dist/cake/engine/selection/selection-geometry-dom.d.ts +0 -24
- package/dist/cake/engine/selection/selection-geometry-dom.d.ts.map +0 -1
- package/dist/cake/engine/selection/selection-geometry-dom.js +0 -302
- package/dist/cake/engine/selection/selection-geometry.d.ts +0 -22
- package/dist/cake/engine/selection/selection-geometry.d.ts.map +0 -1
- package/dist/cake/engine/selection/selection-geometry.js +0 -158
- package/dist/cake/engine/selection/selection-layout-dom.d.ts +0 -50
- package/dist/cake/engine/selection/selection-layout-dom.d.ts.map +0 -1
- package/dist/cake/engine/selection/selection-layout-dom.js +0 -781
- package/dist/cake/engine/selection/selection-layout.d.ts +0 -55
- package/dist/cake/engine/selection/selection-layout.d.ts.map +0 -1
- package/dist/cake/engine/selection/selection-layout.js +0 -128
- package/dist/cake/engine/selection/selection-navigation.d.ts +0 -22
- package/dist/cake/engine/selection/selection-navigation.d.ts.map +0 -1
- package/dist/cake/engine/selection/selection-navigation.js +0 -229
- package/dist/cake/engine/selection/visible-text.d.ts +0 -5
- package/dist/cake/engine/selection/visible-text.d.ts.map +0 -1
- package/dist/cake/engine/selection/visible-text.js +0 -66
- package/dist/cake/react/CakeEditor.d.ts +0 -58
- package/dist/cake/react/CakeEditor.d.ts.map +0 -1
- package/dist/cake/react/CakeEditor.js +0 -225
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { isApplyEditCommand, createRuntimeFromRegistry, } from "../core/runtime";
|
|
2
|
-
import { renderDocContent } from "../dom/render";
|
|
2
|
+
import { renderDocContent, } from "../dom/render";
|
|
3
3
|
import { applyDomSelection, readDomSelection } from "../dom/dom-selection";
|
|
4
4
|
import { bundledExtensions } from "../extensions";
|
|
5
5
|
import { getCaretRect as getDomCaretRect, getSelectionGeometry, } from "./selection/selection-geometry-dom";
|
|
6
|
-
import { getDocLines, getLineOffsets, resolveOffsetToLine, } from "./selection/selection-layout";
|
|
7
|
-
import { cursorOffsetToVisibleOffset, getVisibleText, visibleOffsetToCursorOffset, } from "./selection/visible-text";
|
|
8
6
|
import { hitTestFromLayout, measureLayoutModelFromDom, } from "./selection/selection-layout-dom";
|
|
9
7
|
import { moveSelectionVertically as moveSelectionVerticallyInLayout } from "./selection/selection-navigation";
|
|
8
|
+
import { EditorTextModel, } from "./internal/editor-text-model";
|
|
10
9
|
import { isMacPlatform } from "../shared/platform";
|
|
11
10
|
import { graphemeCount } from "../shared/segmenter";
|
|
12
11
|
import { getWordBoundaries, nextWordBreak, prevWordBreak, } from "../shared/word-break";
|
|
@@ -15,6 +14,47 @@ const defaultSelection = { start: 0, end: 0, affinity: "forward" };
|
|
|
15
14
|
const COMPOSITION_COMMIT_CLEAR_DELAY_MS = 50;
|
|
16
15
|
const HISTORY_GROUPING_INTERVAL_MS = 500;
|
|
17
16
|
const MAX_UNDO_STACK_SIZE = 100;
|
|
17
|
+
function computeDirtyCursorRange(previous, next) {
|
|
18
|
+
if (!previous) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const prevSource = previous.source;
|
|
22
|
+
const nextSource = next.source;
|
|
23
|
+
if (prevSource === nextSource) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const prevLength = prevSource.length;
|
|
27
|
+
const nextLength = nextSource.length;
|
|
28
|
+
let prefix = 0;
|
|
29
|
+
while (prefix < prevLength &&
|
|
30
|
+
prefix < nextLength &&
|
|
31
|
+
prevSource.charCodeAt(prefix) === nextSource.charCodeAt(prefix)) {
|
|
32
|
+
prefix += 1;
|
|
33
|
+
}
|
|
34
|
+
let prevSuffix = prevLength;
|
|
35
|
+
let nextSuffix = nextLength;
|
|
36
|
+
while (prevSuffix > prefix &&
|
|
37
|
+
nextSuffix > prefix &&
|
|
38
|
+
prevSource.charCodeAt(prevSuffix - 1) ===
|
|
39
|
+
nextSource.charCodeAt(nextSuffix - 1)) {
|
|
40
|
+
prevSuffix -= 1;
|
|
41
|
+
nextSuffix -= 1;
|
|
42
|
+
}
|
|
43
|
+
const previousStart = previous.map.sourceToCursor(prefix, "forward").cursorOffset;
|
|
44
|
+
const previousEnd = previous.map.sourceToCursor(prevSuffix, "backward").cursorOffset;
|
|
45
|
+
const nextStart = next.map.sourceToCursor(prefix, "forward").cursorOffset;
|
|
46
|
+
const nextEnd = next.map.sourceToCursor(nextSuffix, "backward").cursorOffset;
|
|
47
|
+
return {
|
|
48
|
+
previous: {
|
|
49
|
+
start: previousStart,
|
|
50
|
+
end: previousEnd,
|
|
51
|
+
},
|
|
52
|
+
next: {
|
|
53
|
+
start: nextStart,
|
|
54
|
+
end: nextEnd,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
18
58
|
function removeFromArray(arr, value) {
|
|
19
59
|
const index = arr.indexOf(value);
|
|
20
60
|
if (index === -1) {
|
|
@@ -27,7 +67,11 @@ export class CakeEditor {
|
|
|
27
67
|
return this._state;
|
|
28
68
|
}
|
|
29
69
|
set state(value) {
|
|
70
|
+
const previousDoc = this._state?.doc;
|
|
30
71
|
this._state = value;
|
|
72
|
+
if (previousDoc !== value.doc) {
|
|
73
|
+
this.textModel.rebuild(value.doc);
|
|
74
|
+
}
|
|
31
75
|
}
|
|
32
76
|
getLastRenderPerf() {
|
|
33
77
|
return this.lastRenderPerf;
|
|
@@ -78,6 +122,7 @@ export class CakeEditor {
|
|
|
78
122
|
this.domBlockRenderers = [];
|
|
79
123
|
this.uiComponents = [];
|
|
80
124
|
this.extensionDisposers = [];
|
|
125
|
+
this.textModel = new EditorTextModel();
|
|
81
126
|
this.contentRoot = null;
|
|
82
127
|
this.domMap = null;
|
|
83
128
|
this.isApplyingSelection = false;
|
|
@@ -117,6 +162,8 @@ export class CakeEditor {
|
|
|
117
162
|
this.lastFocusRect = null;
|
|
118
163
|
this.verticalNavGoalX = null;
|
|
119
164
|
this.lastRenderPerf = null;
|
|
165
|
+
this.renderSnapshot = null;
|
|
166
|
+
this.lastRenderedState = null;
|
|
120
167
|
this.history = {
|
|
121
168
|
undoStack: [],
|
|
122
169
|
redoStack: [],
|
|
@@ -368,16 +415,26 @@ export class CakeEditor {
|
|
|
368
415
|
return this.state.selection;
|
|
369
416
|
}
|
|
370
417
|
getText() {
|
|
371
|
-
|
|
372
|
-
return getVisibleText(lines);
|
|
418
|
+
return this.textModel.getVisibleText();
|
|
373
419
|
}
|
|
374
420
|
getTextSelection() {
|
|
375
|
-
const lines = getDocLines(this.state.doc);
|
|
376
421
|
return {
|
|
377
|
-
start: cursorOffsetToVisibleOffset(
|
|
378
|
-
end: cursorOffsetToVisibleOffset(
|
|
422
|
+
start: this.textModel.cursorOffsetToVisibleOffset(this.state.selection.start),
|
|
423
|
+
end: this.textModel.cursorOffsetToVisibleOffset(this.state.selection.end),
|
|
379
424
|
};
|
|
380
425
|
}
|
|
426
|
+
rebuildTextModelFallback() {
|
|
427
|
+
// Single fallback branch for complex cases where cursor/visible mapping misses.
|
|
428
|
+
this.textModel.rebuild(this.state.doc);
|
|
429
|
+
}
|
|
430
|
+
visibleOffsetToCursorOffset(visibleOffset) {
|
|
431
|
+
const resolved = this.textModel.visibleOffsetToCursorOffset(visibleOffset);
|
|
432
|
+
if (resolved !== null) {
|
|
433
|
+
return resolved;
|
|
434
|
+
}
|
|
435
|
+
this.rebuildTextModelFallback();
|
|
436
|
+
return this.textModel.visibleOffsetToCursorOffset(visibleOffset);
|
|
437
|
+
}
|
|
381
438
|
getActiveMarks() {
|
|
382
439
|
const { start, end } = this.state.selection;
|
|
383
440
|
if (start === end) {
|
|
@@ -690,9 +747,8 @@ export class CakeEditor {
|
|
|
690
747
|
return { found: false, marks: [], nextOffset: offset };
|
|
691
748
|
}
|
|
692
749
|
setTextSelection(selection) {
|
|
693
|
-
const
|
|
694
|
-
const
|
|
695
|
-
const end = visibleOffsetToCursorOffset(lines, selection.end);
|
|
750
|
+
const start = this.visibleOffsetToCursorOffset(selection.start);
|
|
751
|
+
const end = this.visibleOffsetToCursorOffset(selection.end);
|
|
696
752
|
if (start === null || end === null) {
|
|
697
753
|
return;
|
|
698
754
|
}
|
|
@@ -705,34 +761,25 @@ export class CakeEditor {
|
|
|
705
761
|
});
|
|
706
762
|
}
|
|
707
763
|
getTextBeforeCursor(maxChars = Number.POSITIVE_INFINITY) {
|
|
708
|
-
|
|
709
|
-
const { start } = this.getTextSelection();
|
|
710
|
-
const cursor = Math.max(0, Math.min(start, text.length));
|
|
711
|
-
const length = Math.max(0, maxChars);
|
|
712
|
-
return text.slice(Math.max(0, cursor - length), cursor);
|
|
764
|
+
return this.textModel.getTextBeforeCursor(this.state.selection, maxChars);
|
|
713
765
|
}
|
|
714
766
|
getTextAroundCursor(before, after) {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
const afterLength = Math.max(0, after);
|
|
720
|
-
const beforeText = text.slice(Math.max(0, cursor - beforeLength), cursor);
|
|
721
|
-
const afterText = text.slice(cursor, Math.min(text.length, cursor + afterLength));
|
|
722
|
-
return { before: beforeText, after: afterText };
|
|
767
|
+
return this.textModel.getTextAroundCursor(this.state.selection, before, after);
|
|
768
|
+
}
|
|
769
|
+
getTextForCursorRange(start, end) {
|
|
770
|
+
return this.textModel.getTextForCursorRange(start, end);
|
|
723
771
|
}
|
|
724
772
|
replaceTextBeforeCursor(chars, replacement) {
|
|
725
|
-
const lines = getDocLines(this.state.doc);
|
|
726
773
|
const selection = this.state.selection;
|
|
727
774
|
const focus = selection.start === selection.end
|
|
728
775
|
? selection.start
|
|
729
776
|
: selection.affinity === "backward"
|
|
730
777
|
? selection.start
|
|
731
778
|
: selection.end;
|
|
732
|
-
const focusVisible = cursorOffsetToVisibleOffset(
|
|
779
|
+
const focusVisible = this.textModel.cursorOffsetToVisibleOffset(focus);
|
|
733
780
|
const length = Math.max(0, chars);
|
|
734
781
|
const startVisible = Math.max(0, focusVisible - length);
|
|
735
|
-
const startCursor = visibleOffsetToCursorOffset(
|
|
782
|
+
const startCursor = this.visibleOffsetToCursorOffset(startVisible);
|
|
736
783
|
if (startCursor === null) {
|
|
737
784
|
return;
|
|
738
785
|
}
|
|
@@ -757,7 +804,7 @@ export class CakeEditor {
|
|
|
757
804
|
this.scheduleScrollCaretIntoView();
|
|
758
805
|
}
|
|
759
806
|
getCursorLength() {
|
|
760
|
-
return this.
|
|
807
|
+
return this.textModel.getCursorLength();
|
|
761
808
|
}
|
|
762
809
|
getFocusRect() {
|
|
763
810
|
return this.lastFocusRect;
|
|
@@ -786,12 +833,13 @@ export class CakeEditor {
|
|
|
786
833
|
if (!this.contentRoot) {
|
|
787
834
|
return null;
|
|
788
835
|
}
|
|
789
|
-
const lines =
|
|
836
|
+
const lines = this.textModel.getLines();
|
|
790
837
|
const geometry = getSelectionGeometry({
|
|
791
838
|
root: this.contentRoot,
|
|
792
839
|
container: this.container,
|
|
793
840
|
docLines: lines,
|
|
794
841
|
selection: this.state.selection,
|
|
842
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
795
843
|
});
|
|
796
844
|
const focus = geometry.caretRect ?? geometry.focusRect;
|
|
797
845
|
if (!focus) {
|
|
@@ -821,12 +869,13 @@ export class CakeEditor {
|
|
|
821
869
|
if (!this.contentRoot) {
|
|
822
870
|
return [];
|
|
823
871
|
}
|
|
824
|
-
const lines =
|
|
872
|
+
const lines = this.textModel.getLines();
|
|
825
873
|
const geometry = getSelectionGeometry({
|
|
826
874
|
root: this.contentRoot,
|
|
827
875
|
container: this.container,
|
|
828
876
|
docLines: lines,
|
|
829
877
|
selection: this.state.selection,
|
|
878
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
830
879
|
});
|
|
831
880
|
if (geometry.selectionRects.length === 0) {
|
|
832
881
|
return [];
|
|
@@ -850,7 +899,7 @@ export class CakeEditor {
|
|
|
850
899
|
}));
|
|
851
900
|
}
|
|
852
901
|
getLines() {
|
|
853
|
-
return
|
|
902
|
+
return this.textModel.getLines();
|
|
854
903
|
}
|
|
855
904
|
getOverlayRoot() {
|
|
856
905
|
return this.ensureExtensionsRoot();
|
|
@@ -1248,7 +1297,11 @@ export class CakeEditor {
|
|
|
1248
1297
|
if (perfEnabled) {
|
|
1249
1298
|
renderStart = performance.now();
|
|
1250
1299
|
}
|
|
1251
|
-
const
|
|
1300
|
+
const dirtyCursorRange = computeDirtyCursorRange(this.lastRenderedState, this.state);
|
|
1301
|
+
const { content, map, snapshot } = renderDocContent(this.state.doc, this.runtime.dom, this.contentRoot, {
|
|
1302
|
+
previousSnapshot: this.renderSnapshot,
|
|
1303
|
+
dirtyCursorRange,
|
|
1304
|
+
});
|
|
1252
1305
|
const existingChildren = Array.from(this.contentRoot.childNodes);
|
|
1253
1306
|
const isManagedChild = (node) => node instanceof Element &&
|
|
1254
1307
|
(node.hasAttribute("data-line-index") ||
|
|
@@ -1263,6 +1316,11 @@ export class CakeEditor {
|
|
|
1263
1316
|
this.contentRoot.replaceChildren(...content, ...preservedChildren);
|
|
1264
1317
|
}
|
|
1265
1318
|
this.domMap = map;
|
|
1319
|
+
this.renderSnapshot = snapshot;
|
|
1320
|
+
this.lastRenderedState = {
|
|
1321
|
+
source: this.state.source,
|
|
1322
|
+
map: this.state.map,
|
|
1323
|
+
};
|
|
1266
1324
|
if (perfEnabled) {
|
|
1267
1325
|
renderAndMapMs = performance.now() - renderStart;
|
|
1268
1326
|
}
|
|
@@ -1524,9 +1582,9 @@ export class CakeEditor {
|
|
|
1524
1582
|
if (selection.start !== selection.end) {
|
|
1525
1583
|
return selection;
|
|
1526
1584
|
}
|
|
1527
|
-
const lines =
|
|
1528
|
-
const lineOffsets = getLineOffsets(
|
|
1529
|
-
const { lineIndex } = resolveOffsetToLine(
|
|
1585
|
+
const lines = this.textModel.getLines();
|
|
1586
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
1587
|
+
const { lineIndex } = this.textModel.resolveOffsetToLine(selection.start);
|
|
1530
1588
|
const lineInfo = lines[lineIndex];
|
|
1531
1589
|
if (!lineInfo || !lineInfo.isAtomic) {
|
|
1532
1590
|
return selection;
|
|
@@ -1572,13 +1630,13 @@ export class CakeEditor {
|
|
|
1572
1630
|
if (Number.isNaN(lineIndex)) {
|
|
1573
1631
|
return null;
|
|
1574
1632
|
}
|
|
1575
|
-
const lines =
|
|
1633
|
+
const lines = this.textModel.getLines();
|
|
1576
1634
|
const lineInfo = lines[lineIndex];
|
|
1577
1635
|
if (!lineInfo || !lineInfo.isAtomic) {
|
|
1578
1636
|
return null;
|
|
1579
1637
|
}
|
|
1580
1638
|
// Calculate the selection range for the entire line including newline
|
|
1581
|
-
const lineOffsets = getLineOffsets(
|
|
1639
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
1582
1640
|
const lineStart = lineOffsets[lineIndex] ?? 0;
|
|
1583
1641
|
const lineEnd = lineStart + lineInfo.cursorLength + (lineInfo.hasNewline ? 1 : 0);
|
|
1584
1642
|
return {
|
|
@@ -1709,10 +1767,10 @@ export class CakeEditor {
|
|
|
1709
1767
|
if (!hit) {
|
|
1710
1768
|
return;
|
|
1711
1769
|
}
|
|
1712
|
-
const lines =
|
|
1770
|
+
const lines = this.textModel.getLines();
|
|
1713
1771
|
if (event.detail === 2) {
|
|
1714
|
-
const lineOffsets = getLineOffsets(
|
|
1715
|
-
const { lineIndex } = resolveOffsetToLine(
|
|
1772
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
1773
|
+
const { lineIndex } = this.textModel.resolveOffsetToLine(hit.cursorOffset);
|
|
1716
1774
|
const lineInfo = lines[lineIndex];
|
|
1717
1775
|
if (lineInfo && lineInfo.cursorLength === 0) {
|
|
1718
1776
|
const lineStart = lineOffsets[lineIndex] ?? 0;
|
|
@@ -1730,11 +1788,11 @@ export class CakeEditor {
|
|
|
1730
1788
|
this.suppressSelectionChange = false;
|
|
1731
1789
|
return;
|
|
1732
1790
|
}
|
|
1733
|
-
const visibleText = getVisibleText(
|
|
1734
|
-
const visibleOffset = cursorOffsetToVisibleOffset(
|
|
1791
|
+
const visibleText = this.textModel.getVisibleText();
|
|
1792
|
+
const visibleOffset = this.textModel.cursorOffsetToVisibleOffset(hit.cursorOffset);
|
|
1735
1793
|
const wordBounds = getWordBoundaries(visibleText, visibleOffset);
|
|
1736
|
-
const start = visibleOffsetToCursorOffset(
|
|
1737
|
-
const end = visibleOffsetToCursorOffset(
|
|
1794
|
+
const start = this.visibleOffsetToCursorOffset(wordBounds.start);
|
|
1795
|
+
const end = this.visibleOffsetToCursorOffset(wordBounds.end);
|
|
1738
1796
|
if (start === null || end === null) {
|
|
1739
1797
|
this.suppressSelectionChange = false;
|
|
1740
1798
|
return;
|
|
@@ -1754,8 +1812,8 @@ export class CakeEditor {
|
|
|
1754
1812
|
return;
|
|
1755
1813
|
}
|
|
1756
1814
|
if (event.detail >= 3) {
|
|
1757
|
-
const lineOffsets = getLineOffsets(
|
|
1758
|
-
const { lineIndex } = resolveOffsetToLine(
|
|
1815
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
1816
|
+
const { lineIndex } = this.textModel.resolveOffsetToLine(hit.cursorOffset);
|
|
1759
1817
|
const lineInfo = lines[lineIndex];
|
|
1760
1818
|
if (!lineInfo) {
|
|
1761
1819
|
this.suppressSelectionChange = false;
|
|
@@ -2182,8 +2240,7 @@ export class CakeEditor {
|
|
|
2182
2240
|
if (this.compositionCommit && event.inputType === "insertText") {
|
|
2183
2241
|
this.clearCompositionCommit();
|
|
2184
2242
|
const domText = this.readDomText();
|
|
2185
|
-
const
|
|
2186
|
-
const modelText = getVisibleText(lines);
|
|
2243
|
+
const modelText = this.textModel.getVisibleText();
|
|
2187
2244
|
if (domText === modelText) {
|
|
2188
2245
|
if (this.domMap) {
|
|
2189
2246
|
const domSelection = readDomSelection(this.domMap);
|
|
@@ -2209,8 +2266,7 @@ export class CakeEditor {
|
|
|
2209
2266
|
// we must not drop the edit; reconcile if the DOM diverged from the model.
|
|
2210
2267
|
if (this.beforeInputHandled) {
|
|
2211
2268
|
const domText = this.readDomText();
|
|
2212
|
-
const
|
|
2213
|
-
const modelText = getVisibleText(lines);
|
|
2269
|
+
const modelText = this.textModel.getVisibleText();
|
|
2214
2270
|
if (domText === modelText) {
|
|
2215
2271
|
return;
|
|
2216
2272
|
}
|
|
@@ -2418,8 +2474,8 @@ export class CakeEditor {
|
|
|
2418
2474
|
return false;
|
|
2419
2475
|
}
|
|
2420
2476
|
const lineIndex = this.selectedAtomicLineIndex;
|
|
2421
|
-
const lines =
|
|
2422
|
-
const lineOffsets = getLineOffsets(
|
|
2477
|
+
const lines = this.textModel.getLines();
|
|
2478
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
2423
2479
|
const lineInfo = lines[lineIndex];
|
|
2424
2480
|
if (!lineInfo || !lineInfo.isAtomic) {
|
|
2425
2481
|
this.selectedAtomicLineIndex = null;
|
|
@@ -2467,8 +2523,8 @@ export class CakeEditor {
|
|
|
2467
2523
|
if (selection.start !== selection.end) {
|
|
2468
2524
|
return false;
|
|
2469
2525
|
}
|
|
2470
|
-
const lines =
|
|
2471
|
-
const lineOffsets = getLineOffsets(
|
|
2526
|
+
const lines = this.textModel.getLines();
|
|
2527
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
2472
2528
|
const lineIndex = lineOffsets.findIndex((offset) => offset === selection.start);
|
|
2473
2529
|
if (lineIndex === -1) {
|
|
2474
2530
|
return false;
|
|
@@ -2508,8 +2564,11 @@ export class CakeEditor {
|
|
|
2508
2564
|
sourceLines[swapB] = aSource;
|
|
2509
2565
|
const newSource = sourceLines.join("\n");
|
|
2510
2566
|
const nextState = this.runtime.createState(newSource);
|
|
2511
|
-
|
|
2512
|
-
|
|
2567
|
+
let lineStartSource = 0;
|
|
2568
|
+
for (let index = 0; index < swapA; index += 1) {
|
|
2569
|
+
lineStartSource += (sourceLines[index]?.length ?? 0) + 1;
|
|
2570
|
+
}
|
|
2571
|
+
const cursorPos = nextState.map.sourceToCursor(lineStartSource, "forward").cursorOffset;
|
|
2513
2572
|
this.recordHistory("delete-backward");
|
|
2514
2573
|
this.state = {
|
|
2515
2574
|
...nextState,
|
|
@@ -2560,7 +2619,7 @@ export class CakeEditor {
|
|
|
2560
2619
|
if (!this.contentRoot) {
|
|
2561
2620
|
return null;
|
|
2562
2621
|
}
|
|
2563
|
-
const lines =
|
|
2622
|
+
const lines = this.textModel.getLines();
|
|
2564
2623
|
const layout = measureLayoutModelFromDom({
|
|
2565
2624
|
lines,
|
|
2566
2625
|
root: this.contentRoot,
|
|
@@ -2591,6 +2650,7 @@ export class CakeEditor {
|
|
|
2591
2650
|
layout,
|
|
2592
2651
|
offset: currentPos,
|
|
2593
2652
|
affinity: currentAffinity,
|
|
2653
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2594
2654
|
});
|
|
2595
2655
|
// Arrow left at start of visual row (not at document start):
|
|
2596
2656
|
// Stay at same position but change to backward affinity
|
|
@@ -2604,6 +2664,7 @@ export class CakeEditor {
|
|
|
2604
2664
|
layout,
|
|
2605
2665
|
offset: currentPos,
|
|
2606
2666
|
affinity: "backward",
|
|
2667
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2607
2668
|
});
|
|
2608
2669
|
// If backward affinity puts us on a different row, just change affinity
|
|
2609
2670
|
if (prevBoundaries.rowEnd !== rowEnd ||
|
|
@@ -2622,6 +2683,7 @@ export class CakeEditor {
|
|
|
2622
2683
|
layout,
|
|
2623
2684
|
offset: currentPos,
|
|
2624
2685
|
affinity: "forward",
|
|
2686
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2625
2687
|
});
|
|
2626
2688
|
// If forward affinity puts us on a different row, just change affinity
|
|
2627
2689
|
if (nextBoundaries.rowEnd !== rowEnd ||
|
|
@@ -2638,8 +2700,8 @@ export class CakeEditor {
|
|
|
2638
2700
|
}
|
|
2639
2701
|
moveOffsetByChar(offset, direction) {
|
|
2640
2702
|
const cursorLength = this.state.map.cursorLength;
|
|
2641
|
-
const lines =
|
|
2642
|
-
const lineOffsets = getLineOffsets(
|
|
2703
|
+
const lines = this.textModel.getLines();
|
|
2704
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
2643
2705
|
let nextPos;
|
|
2644
2706
|
if (direction === "forward") {
|
|
2645
2707
|
if (offset >= cursorLength) {
|
|
@@ -2653,7 +2715,7 @@ export class CakeEditor {
|
|
|
2653
2715
|
}
|
|
2654
2716
|
nextPos = offset - 1;
|
|
2655
2717
|
}
|
|
2656
|
-
const { lineIndex: nextLineIndex } = resolveOffsetToLine(
|
|
2718
|
+
const { lineIndex: nextLineIndex } = this.textModel.resolveOffsetToLine(nextPos);
|
|
2657
2719
|
const nextLineInfo = lines[nextLineIndex];
|
|
2658
2720
|
if (nextLineInfo && nextLineInfo.isAtomic) {
|
|
2659
2721
|
const lineStart = lineOffsets[nextLineIndex] ?? 0;
|
|
@@ -2680,7 +2742,7 @@ export class CakeEditor {
|
|
|
2680
2742
|
}
|
|
2681
2743
|
}
|
|
2682
2744
|
const { focus } = resolveSelectionAnchorAndFocus(this.state.selection);
|
|
2683
|
-
const focusResolved = resolveOffsetToLine(
|
|
2745
|
+
const focusResolved = this.textModel.resolveOffsetToLine(focus);
|
|
2684
2746
|
const focusLineLayout = layout.lines[focusResolved.lineIndex];
|
|
2685
2747
|
let focusRowIndex = undefined;
|
|
2686
2748
|
if (focusLineLayout?.rows.length && this.lastFocusRect) {
|
|
@@ -2707,6 +2769,7 @@ export class CakeEditor {
|
|
|
2707
2769
|
lines,
|
|
2708
2770
|
layout,
|
|
2709
2771
|
selection: this.state.selection,
|
|
2772
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2710
2773
|
direction,
|
|
2711
2774
|
goalX: this.verticalNavGoalX,
|
|
2712
2775
|
focusRowIndex,
|
|
@@ -2715,7 +2778,7 @@ export class CakeEditor {
|
|
|
2715
2778
|
if (!hit || !this.contentRoot) {
|
|
2716
2779
|
return null;
|
|
2717
2780
|
}
|
|
2718
|
-
const resolved = resolveOffsetToLine(
|
|
2781
|
+
const resolved = this.textModel.resolveOffsetToLine(hit.cursorOffset);
|
|
2719
2782
|
const lineInfo = lines[resolved.lineIndex];
|
|
2720
2783
|
const lineElement = this.contentRoot.querySelector(`[data-line-index="${resolved.lineIndex}"]`);
|
|
2721
2784
|
if (!lineInfo || !(lineElement instanceof HTMLElement)) {
|
|
@@ -2759,6 +2822,7 @@ export class CakeEditor {
|
|
|
2759
2822
|
layout,
|
|
2760
2823
|
offset: focus,
|
|
2761
2824
|
affinity: "backward",
|
|
2825
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2762
2826
|
});
|
|
2763
2827
|
let target = rowStart;
|
|
2764
2828
|
if (focus === rowStart && focus > 0) {
|
|
@@ -2767,6 +2831,7 @@ export class CakeEditor {
|
|
|
2767
2831
|
layout,
|
|
2768
2832
|
offset: focus - 1,
|
|
2769
2833
|
affinity: "backward",
|
|
2834
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2770
2835
|
});
|
|
2771
2836
|
target = previous.rowStart;
|
|
2772
2837
|
}
|
|
@@ -2788,6 +2853,7 @@ export class CakeEditor {
|
|
|
2788
2853
|
layout,
|
|
2789
2854
|
offset: focus,
|
|
2790
2855
|
affinity: "forward",
|
|
2856
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2791
2857
|
});
|
|
2792
2858
|
let target = rowEnd;
|
|
2793
2859
|
if (focus === rowEnd && focus < this.state.map.cursorLength) {
|
|
@@ -2796,6 +2862,7 @@ export class CakeEditor {
|
|
|
2796
2862
|
layout,
|
|
2797
2863
|
offset: focus + 1,
|
|
2798
2864
|
affinity: "forward",
|
|
2865
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2799
2866
|
});
|
|
2800
2867
|
target = next.rowEnd;
|
|
2801
2868
|
}
|
|
@@ -2815,6 +2882,7 @@ export class CakeEditor {
|
|
|
2815
2882
|
layout,
|
|
2816
2883
|
offset: focus,
|
|
2817
2884
|
affinity,
|
|
2885
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2818
2886
|
});
|
|
2819
2887
|
let target = rowStart;
|
|
2820
2888
|
if (focus === rowStart && focus > 0) {
|
|
@@ -2823,6 +2891,7 @@ export class CakeEditor {
|
|
|
2823
2891
|
layout,
|
|
2824
2892
|
offset: focus - 1,
|
|
2825
2893
|
affinity: "backward",
|
|
2894
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2826
2895
|
});
|
|
2827
2896
|
target = previous.rowStart;
|
|
2828
2897
|
}
|
|
@@ -2842,6 +2911,7 @@ export class CakeEditor {
|
|
|
2842
2911
|
layout,
|
|
2843
2912
|
offset: focus,
|
|
2844
2913
|
affinity,
|
|
2914
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2845
2915
|
});
|
|
2846
2916
|
let target = rowEnd;
|
|
2847
2917
|
if (focus === rowEnd && focus < this.state.map.cursorLength) {
|
|
@@ -2850,6 +2920,7 @@ export class CakeEditor {
|
|
|
2850
2920
|
layout,
|
|
2851
2921
|
offset: focus + 1,
|
|
2852
2922
|
affinity: "forward",
|
|
2923
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2853
2924
|
});
|
|
2854
2925
|
target = next.rowEnd;
|
|
2855
2926
|
}
|
|
@@ -2868,8 +2939,8 @@ export class CakeEditor {
|
|
|
2868
2939
|
if (selection.start === selection.end) {
|
|
2869
2940
|
return null;
|
|
2870
2941
|
}
|
|
2871
|
-
const lines =
|
|
2872
|
-
const lineOffsets = getLineOffsets(
|
|
2942
|
+
const lines = this.textModel.getLines();
|
|
2943
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
2873
2944
|
const selStart = Math.min(selection.start, selection.end);
|
|
2874
2945
|
const selEnd = Math.max(selection.start, selection.end);
|
|
2875
2946
|
const fullLineInfo = this.detectFullLineSelection(selStart, selEnd, lines, lineOffsets);
|
|
@@ -2924,26 +2995,25 @@ export class CakeEditor {
|
|
|
2924
2995
|
return selectionFromAnchor(anchor, nextFocus, direction);
|
|
2925
2996
|
}
|
|
2926
2997
|
moveOffsetByWord(offset, direction) {
|
|
2927
|
-
const
|
|
2928
|
-
const visibleText = getVisibleText(lines);
|
|
2998
|
+
const visibleText = this.textModel.getVisibleText();
|
|
2929
2999
|
if (!visibleText) {
|
|
2930
3000
|
return 0;
|
|
2931
3001
|
}
|
|
2932
|
-
const visibleOffset = cursorOffsetToVisibleOffset(
|
|
3002
|
+
const visibleOffset = this.textModel.cursorOffsetToVisibleOffset(offset);
|
|
2933
3003
|
const nextVisibleOffset = direction === "backward"
|
|
2934
3004
|
? prevWordBreak(visibleText, visibleOffset)
|
|
2935
3005
|
: nextWordBreak(visibleText, visibleOffset);
|
|
2936
|
-
return visibleOffsetToCursorOffset(
|
|
3006
|
+
return this.visibleOffsetToCursorOffset(nextVisibleOffset) ?? offset;
|
|
2937
3007
|
}
|
|
2938
3008
|
deleteToVisualRowStart() {
|
|
2939
3009
|
const selection = this.state.selection;
|
|
2940
|
-
const lines =
|
|
2941
|
-
const { lineIndex, offsetInLine } = resolveOffsetToLine(
|
|
3010
|
+
const lines = this.textModel.getLines();
|
|
3011
|
+
const { lineIndex, offsetInLine } = this.textModel.resolveOffsetToLine(selection.start);
|
|
2942
3012
|
const lineInfo = lines[lineIndex];
|
|
2943
3013
|
if (!lineInfo) {
|
|
2944
3014
|
return;
|
|
2945
3015
|
}
|
|
2946
|
-
const lineOffsets = getLineOffsets(
|
|
3016
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
2947
3017
|
const lineStart = lineOffsets[lineIndex] ?? 0;
|
|
2948
3018
|
const isLineStart = offsetInLine === 0;
|
|
2949
3019
|
const isCollapsed = selection.start === selection.end;
|
|
@@ -2968,6 +3038,7 @@ export class CakeEditor {
|
|
|
2968
3038
|
layout,
|
|
2969
3039
|
offset: selection.start,
|
|
2970
3040
|
affinity: "backward",
|
|
3041
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
2971
3042
|
});
|
|
2972
3043
|
const isVisualRowStart = selection.start === rowStart;
|
|
2973
3044
|
if (isCollapsed && isVisualRowStart) {
|
|
@@ -2984,11 +3055,11 @@ export class CakeEditor {
|
|
|
2984
3055
|
}
|
|
2985
3056
|
handleIndent() {
|
|
2986
3057
|
const selection = this.state.selection;
|
|
2987
|
-
const lines =
|
|
3058
|
+
const lines = this.textModel.getLines();
|
|
2988
3059
|
const TAB_SPACES = " ";
|
|
2989
3060
|
const isCollapsed = selection.start === selection.end;
|
|
2990
|
-
const startLineIndex = resolveOffsetToLine(
|
|
2991
|
-
const endLineIndex = resolveOffsetToLine(
|
|
3061
|
+
const startLineIndex = this.textModel.resolveOffsetToLine(selection.start).lineIndex;
|
|
3062
|
+
const endLineIndex = this.textModel.resolveOffsetToLine(Math.max(selection.start, selection.end - 1)).lineIndex;
|
|
2992
3063
|
const affectsMultipleLines = endLineIndex > startLineIndex;
|
|
2993
3064
|
// Check if the current line is a list item by checking source text
|
|
2994
3065
|
const sourceLines = this.state.source.split("\n");
|
|
@@ -3009,7 +3080,7 @@ export class CakeEditor {
|
|
|
3009
3080
|
// insert at caret position. Otherwise indent at line start.
|
|
3010
3081
|
if (isCollapsed) {
|
|
3011
3082
|
// Check if caret is in middle/end of line (not at start)
|
|
3012
|
-
const lineOffsets = getLineOffsets(
|
|
3083
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
3013
3084
|
const lineStart = lineOffsets[startLineIndex] ?? 0;
|
|
3014
3085
|
const offsetInLine = selection.start - lineStart;
|
|
3015
3086
|
if (offsetInLine > 0) {
|
|
@@ -3061,10 +3132,10 @@ export class CakeEditor {
|
|
|
3061
3132
|
}
|
|
3062
3133
|
handleOutdent() {
|
|
3063
3134
|
const selection = this.state.selection;
|
|
3064
|
-
const lines =
|
|
3135
|
+
const lines = this.textModel.getLines();
|
|
3065
3136
|
const TAB_SPACES = " ";
|
|
3066
|
-
const startLineIndex = resolveOffsetToLine(
|
|
3067
|
-
const endLineIndex = resolveOffsetToLine(
|
|
3137
|
+
const startLineIndex = this.textModel.resolveOffsetToLine(selection.start).lineIndex;
|
|
3138
|
+
const endLineIndex = this.textModel.resolveOffsetToLine(Math.max(selection.start, selection.end - 1)).lineIndex;
|
|
3068
3139
|
const sourceLines = this.state.source.split("\n");
|
|
3069
3140
|
// Check if the current line is a list item by checking source text
|
|
3070
3141
|
const startSourceLine = sourceLines[startLineIndex] ?? "";
|
|
@@ -3158,8 +3229,7 @@ export class CakeEditor {
|
|
|
3158
3229
|
*/
|
|
3159
3230
|
reconcileDomChanges(selection) {
|
|
3160
3231
|
const domText = this.readDomText();
|
|
3161
|
-
const
|
|
3162
|
-
const modelText = getVisibleText(lines);
|
|
3232
|
+
const modelText = this.textModel.getVisibleText();
|
|
3163
3233
|
if (domText === modelText) {
|
|
3164
3234
|
return false;
|
|
3165
3235
|
}
|
|
@@ -3181,8 +3251,8 @@ export class CakeEditor {
|
|
|
3181
3251
|
// The replacement text from DOM
|
|
3182
3252
|
const replacementText = domText.slice(prefixLen, domText.length - suffixLen);
|
|
3183
3253
|
// Convert visible text offsets to cursor offsets
|
|
3184
|
-
const cursorStart = visibleOffsetToCursorOffset(
|
|
3185
|
-
const cursorEnd = visibleOffsetToCursorOffset(
|
|
3254
|
+
const cursorStart = this.visibleOffsetToCursorOffset(prefixLen);
|
|
3255
|
+
const cursorEnd = this.visibleOffsetToCursorOffset(modelText.length - suffixLen);
|
|
3186
3256
|
if (cursorStart === null || cursorEnd === null) {
|
|
3187
3257
|
// Fallback: rebuild state from scratch (loses formatting)
|
|
3188
3258
|
// History was already recorded above
|
|
@@ -3470,12 +3540,13 @@ export class CakeEditor {
|
|
|
3470
3540
|
this.syncSelectionRects([]);
|
|
3471
3541
|
return;
|
|
3472
3542
|
}
|
|
3473
|
-
const lines =
|
|
3543
|
+
const lines = this.textModel.getLines();
|
|
3474
3544
|
const geometry = getSelectionGeometry({
|
|
3475
3545
|
root: this.contentRoot,
|
|
3476
3546
|
container: this.container,
|
|
3477
3547
|
docLines: lines,
|
|
3478
3548
|
selection,
|
|
3549
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
3479
3550
|
});
|
|
3480
3551
|
this.lastFocusRect = geometry.focusRect;
|
|
3481
3552
|
this.syncSelectionRects(geometry.selectionRects);
|
|
@@ -3489,12 +3560,13 @@ export class CakeEditor {
|
|
|
3489
3560
|
return;
|
|
3490
3561
|
}
|
|
3491
3562
|
this.contentRoot.classList.remove("cake-touch-mode");
|
|
3492
|
-
const lines =
|
|
3563
|
+
const lines = this.textModel.getLines();
|
|
3493
3564
|
const geometry = getSelectionGeometry({
|
|
3494
3565
|
root: this.contentRoot,
|
|
3495
3566
|
container: this.container,
|
|
3496
3567
|
docLines: lines,
|
|
3497
3568
|
selection: this.state.selection,
|
|
3569
|
+
resolveOffsetToLine: (offset) => this.textModel.resolveOffsetToLine(offset),
|
|
3498
3570
|
});
|
|
3499
3571
|
this.lastFocusRect = geometry.focusRect;
|
|
3500
3572
|
this.syncSelectionRects(geometry.selectionRects);
|
|
@@ -3679,7 +3751,7 @@ export class CakeEditor {
|
|
|
3679
3751
|
if (!this.contentRoot) {
|
|
3680
3752
|
return null;
|
|
3681
3753
|
}
|
|
3682
|
-
const lines =
|
|
3754
|
+
const lines = this.textModel.getLines();
|
|
3683
3755
|
const hit = hitTestFromLayout({
|
|
3684
3756
|
clientX,
|
|
3685
3757
|
clientY,
|
|
@@ -3742,10 +3814,10 @@ export class CakeEditor {
|
|
|
3742
3814
|
const lineIndexAttr = blockElement?.getAttribute("data-line-index") ?? null;
|
|
3743
3815
|
if (lineIndexAttr !== null) {
|
|
3744
3816
|
const lineIndex = Number.parseInt(lineIndexAttr, 10);
|
|
3745
|
-
const lines =
|
|
3817
|
+
const lines = this.textModel.getLines();
|
|
3746
3818
|
const lineInfo = lines[lineIndex];
|
|
3747
3819
|
if (lineInfo?.isAtomic) {
|
|
3748
|
-
const lineOffsets = getLineOffsets(
|
|
3820
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
3749
3821
|
const lineStart = lineOffsets[lineIndex] ?? 0;
|
|
3750
3822
|
const lineEnd = lineStart + lineInfo.cursorLength + (lineInfo.hasNewline ? 1 : 0);
|
|
3751
3823
|
const atomicSelection = {
|
|
@@ -3851,8 +3923,8 @@ export class CakeEditor {
|
|
|
3851
3923
|
return;
|
|
3852
3924
|
}
|
|
3853
3925
|
// Check if this is a full line selection (required for line drag)
|
|
3854
|
-
const lines =
|
|
3855
|
-
const lineOffsets = getLineOffsets(
|
|
3926
|
+
const lines = this.textModel.getLines();
|
|
3927
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
3856
3928
|
// Find which line the selection starts on
|
|
3857
3929
|
// We need to handle the case where selStart might be at the newline position
|
|
3858
3930
|
// of the previous line (offset - 1) due to DOM selection normalization
|
|
@@ -4264,10 +4336,10 @@ export class CakeEditor {
|
|
|
4264
4336
|
return;
|
|
4265
4337
|
}
|
|
4266
4338
|
// Get the plain text and source text for the selection
|
|
4267
|
-
const lines =
|
|
4268
|
-
const visibleText = getVisibleText(
|
|
4269
|
-
const visibleStart = cursorOffsetToVisibleOffset(
|
|
4270
|
-
const visibleEnd = cursorOffsetToVisibleOffset(
|
|
4339
|
+
const lines = this.textModel.getLines();
|
|
4340
|
+
const visibleText = this.textModel.getVisibleText();
|
|
4341
|
+
const visibleStart = this.textModel.cursorOffsetToVisibleOffset(start);
|
|
4342
|
+
const visibleEnd = this.textModel.cursorOffsetToVisibleOffset(end);
|
|
4271
4343
|
const plainText = visibleText.slice(visibleStart, visibleEnd);
|
|
4272
4344
|
// Get source text for the selection (use backward/forward to capture full markdown syntax)
|
|
4273
4345
|
const cursorSourceMap = this.state.map;
|
|
@@ -4329,10 +4401,10 @@ export class CakeEditor {
|
|
|
4329
4401
|
if (selection.start !== selection.end) {
|
|
4330
4402
|
const start = Math.min(selection.start, selection.end);
|
|
4331
4403
|
const end = Math.max(selection.start, selection.end);
|
|
4332
|
-
const lines =
|
|
4333
|
-
const visibleText = getVisibleText(
|
|
4334
|
-
const visibleStart = cursorOffsetToVisibleOffset(
|
|
4335
|
-
const visibleEnd = cursorOffsetToVisibleOffset(
|
|
4404
|
+
const lines = this.textModel.getLines();
|
|
4405
|
+
const visibleText = this.textModel.getVisibleText();
|
|
4406
|
+
const visibleStart = this.textModel.cursorOffsetToVisibleOffset(start);
|
|
4407
|
+
const visibleEnd = this.textModel.cursorOffsetToVisibleOffset(end);
|
|
4336
4408
|
const plainText = visibleText.slice(visibleStart, visibleEnd);
|
|
4337
4409
|
const cursorSourceMap = this.state.map;
|
|
4338
4410
|
const sourceStart = cursorSourceMap.cursorToSource(start, "backward");
|
|
@@ -4354,8 +4426,8 @@ export class CakeEditor {
|
|
|
4354
4426
|
return;
|
|
4355
4427
|
}
|
|
4356
4428
|
// Check if this is a full-line selection - if so, use line-level move
|
|
4357
|
-
const lines =
|
|
4358
|
-
const lineOffsets = getLineOffsets(
|
|
4429
|
+
const lines = this.textModel.getLines();
|
|
4430
|
+
const lineOffsets = this.textModel.getLineOffsets();
|
|
4359
4431
|
const fullLineInfo = this.detectFullLineSelection(dragStart, dragEnd, lines, lineOffsets);
|
|
4360
4432
|
if (fullLineInfo) {
|
|
4361
4433
|
// Full line drag - use line-level move
|
|
@@ -4506,7 +4578,7 @@ function getVisualRowBoundaries(params) {
|
|
|
4506
4578
|
if (!layout || layout.lines.length === 0) {
|
|
4507
4579
|
return { rowStart: 0, rowEnd: 0 };
|
|
4508
4580
|
}
|
|
4509
|
-
const resolved = resolveOffsetToLine(
|
|
4581
|
+
const resolved = params.resolveOffsetToLine(offset);
|
|
4510
4582
|
const line = layout.lines[resolved.lineIndex];
|
|
4511
4583
|
if (!line) {
|
|
4512
4584
|
return { rowStart: 0, rowEnd: 0 };
|