@blankdotpage/cake 0.1.67 → 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 +6 -0
- package/dist/cake/core/runtime.d.ts.map +1 -1
- package/dist/cake/core/runtime.js +344 -221
- 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 +11 -2
- package/dist/cake/editor/cake-editor.d.ts.map +1 -1
- package/dist/cake/editor/cake-editor.js +178 -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/index.d.ts +2 -1
- package/dist/cake/extensions/index.d.ts.map +1 -1
- package/dist/cake/extensions/index.js +3 -1
- 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.d.ts +7 -0
- package/dist/cake/extensions/shared/structural-reparse-policy.d.ts.map +1 -0
- package/dist/cake/extensions/shared/structural-reparse-policy.js +16 -0
- 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
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Block, Doc, Selection } from "../../core/types";
|
|
2
|
+
export type LineInfo = {
|
|
3
|
+
lineIndex: number;
|
|
4
|
+
lineStartOffset: number;
|
|
5
|
+
text: string;
|
|
6
|
+
cursorLength: number;
|
|
7
|
+
hasNewline: boolean;
|
|
8
|
+
cursorToCodeUnit: number[];
|
|
9
|
+
isAtomic: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type LineOffsetResolution = {
|
|
12
|
+
lineIndex: number;
|
|
13
|
+
offsetInLine: number;
|
|
14
|
+
};
|
|
15
|
+
export type StructuralLineInfo = LineInfo & {
|
|
16
|
+
path: number[];
|
|
17
|
+
parentPath: number[];
|
|
18
|
+
indexInParent: number;
|
|
19
|
+
block: Block;
|
|
20
|
+
};
|
|
21
|
+
export declare class EditorTextModel {
|
|
22
|
+
private lines;
|
|
23
|
+
private lineOffsets;
|
|
24
|
+
private visibleText;
|
|
25
|
+
private cursorLength;
|
|
26
|
+
constructor(doc?: Doc);
|
|
27
|
+
rebuild(doc: Doc): void;
|
|
28
|
+
getLines(): LineInfo[];
|
|
29
|
+
getStructuralLines(): readonly StructuralLineInfo[];
|
|
30
|
+
getLineOffsets(): readonly number[];
|
|
31
|
+
getVisibleText(): string;
|
|
32
|
+
getCursorLength(): number;
|
|
33
|
+
resolveOffsetToLine(offset: number): LineOffsetResolution;
|
|
34
|
+
visibleOffsetToCursorOffset(visibleOffset: number): number | null;
|
|
35
|
+
cursorOffsetToVisibleOffset(cursorOffset: number): number;
|
|
36
|
+
getTextSelection(selection: Selection): {
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
};
|
|
40
|
+
getTextBeforeCursor(selection: Selection, maxChars: number): string;
|
|
41
|
+
getTextAroundCursor(selection: Selection, before: number, after: number): {
|
|
42
|
+
before: string;
|
|
43
|
+
after: string;
|
|
44
|
+
};
|
|
45
|
+
getTextForCursorRange(start: number, end: number): string;
|
|
46
|
+
getGraphemeAtCursor(cursorOffset: number): string | null;
|
|
47
|
+
}
|
|
48
|
+
export declare function getEditorTextModelForDoc(doc: Doc): EditorTextModel;
|
|
49
|
+
//# sourceMappingURL=editor-text-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-text-model.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/internal/editor-text-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGtE,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG;IAC1C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AA+KF,qBAAa,eAAe;IAC1B,OAAO,CAAC,KAAK,CAcX;IACF,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,YAAY,CAAK;gBAEb,GAAG,CAAC,EAAE,GAAG;IAMrB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IASvB,QAAQ,IAAI,QAAQ,EAAE;IAItB,kBAAkB,IAAI,SAAS,kBAAkB,EAAE;IAInD,cAAc,IAAI,SAAS,MAAM,EAAE;IAInC,cAAc,IAAI,MAAM;IAIxB,eAAe,IAAI,MAAM;IAIzB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB;IAOzD,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAiCjE,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IA0BzD,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;IAOtE,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAUnE,mBAAmB,CACjB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAepC,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAQzD,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAYzD;AAID,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,GAAG,eAAe,CAQlE"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { graphemeSegments } from "../../shared/segmenter";
|
|
2
|
+
function computeLineOffsets(lines) {
|
|
3
|
+
return lines.map((line) => line.lineStartOffset);
|
|
4
|
+
}
|
|
5
|
+
function resolveOffsetInLines(params) {
|
|
6
|
+
const { lines } = params;
|
|
7
|
+
if (lines.length === 0) {
|
|
8
|
+
return { lineIndex: 0, offsetInLine: 0 };
|
|
9
|
+
}
|
|
10
|
+
const lastLineIndex = lines.length - 1;
|
|
11
|
+
const lastLine = lines[lastLineIndex] ?? {
|
|
12
|
+
lineStartOffset: 0,
|
|
13
|
+
cursorLength: 0,
|
|
14
|
+
};
|
|
15
|
+
const totalLength = lastLine.lineStartOffset + (lastLine.cursorLength ?? 0);
|
|
16
|
+
const clampedOffset = Math.max(0, Math.min(params.offset, totalLength));
|
|
17
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
18
|
+
const line = lines[lineIndex];
|
|
19
|
+
const lineStart = line.lineStartOffset;
|
|
20
|
+
const lineEnd = lineStart + line.cursorLength;
|
|
21
|
+
if (clampedOffset <= lineEnd || lineIndex === lastLineIndex) {
|
|
22
|
+
return {
|
|
23
|
+
lineIndex,
|
|
24
|
+
offsetInLine: clampedOffset - lineStart,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
lineIndex: lastLineIndex,
|
|
30
|
+
offsetInLine: lines[lastLineIndex]?.cursorLength ?? 0,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function cursorOffsetFromCodeUnit(line, codeUnitOffset) {
|
|
34
|
+
const maxCodeUnit = line.cursorToCodeUnit[line.cursorToCodeUnit.length - 1] ?? 0;
|
|
35
|
+
const clamped = Math.max(0, Math.min(codeUnitOffset, maxCodeUnit));
|
|
36
|
+
for (let i = 0; i < line.cursorToCodeUnit.length; i += 1) {
|
|
37
|
+
if (line.cursorToCodeUnit[i] === clamped) {
|
|
38
|
+
return i;
|
|
39
|
+
}
|
|
40
|
+
if (line.cursorToCodeUnit[i] > clamped) {
|
|
41
|
+
return Math.max(0, i - 1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return line.cursorLength;
|
|
45
|
+
}
|
|
46
|
+
function flattenDocToLines(doc) {
|
|
47
|
+
const lines = [];
|
|
48
|
+
const appendBlock = (block, path) => {
|
|
49
|
+
if (block.type === "paragraph") {
|
|
50
|
+
lines.push({
|
|
51
|
+
path,
|
|
52
|
+
parentPath: path.slice(0, -1),
|
|
53
|
+
indexInParent: path[path.length - 1] ?? 0,
|
|
54
|
+
block,
|
|
55
|
+
text: block.content.map(flattenInline).join(""),
|
|
56
|
+
isAtomic: false,
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (block.type === "block-wrapper") {
|
|
61
|
+
block.blocks.forEach((child, index) => appendBlock(child, [...path, index]));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (block.type === "block-atom") {
|
|
65
|
+
// Atomic blocks occupy one cursor unit and are treated as empty layout lines.
|
|
66
|
+
lines.push({
|
|
67
|
+
path,
|
|
68
|
+
parentPath: path.slice(0, -1),
|
|
69
|
+
indexInParent: path[path.length - 1] ?? 0,
|
|
70
|
+
block,
|
|
71
|
+
text: "",
|
|
72
|
+
isAtomic: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
doc.blocks.forEach((block, index) => appendBlock(block, [index]));
|
|
77
|
+
if (lines.length === 0) {
|
|
78
|
+
const block = { type: "paragraph", content: [] };
|
|
79
|
+
lines.push({
|
|
80
|
+
path: [0],
|
|
81
|
+
parentPath: [],
|
|
82
|
+
indexInParent: 0,
|
|
83
|
+
block,
|
|
84
|
+
text: "",
|
|
85
|
+
isAtomic: false,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return lines;
|
|
89
|
+
}
|
|
90
|
+
function flattenInline(inline) {
|
|
91
|
+
if (inline.type === "text") {
|
|
92
|
+
return inline.text;
|
|
93
|
+
}
|
|
94
|
+
if (inline.type === "inline-wrapper") {
|
|
95
|
+
return inline.children.map(flattenInline).join("");
|
|
96
|
+
}
|
|
97
|
+
if (inline.type === "inline-atom") {
|
|
98
|
+
return " ";
|
|
99
|
+
}
|
|
100
|
+
return "";
|
|
101
|
+
}
|
|
102
|
+
function buildCursorToCodeUnit(text) {
|
|
103
|
+
const mapping = [0];
|
|
104
|
+
for (const segment of graphemeSegments(text)) {
|
|
105
|
+
mapping.push(segment.index + segment.segment.length);
|
|
106
|
+
}
|
|
107
|
+
if (mapping.length === 0) {
|
|
108
|
+
mapping.push(0);
|
|
109
|
+
}
|
|
110
|
+
return mapping;
|
|
111
|
+
}
|
|
112
|
+
function buildLines(doc) {
|
|
113
|
+
const flattenedLines = flattenDocToLines(doc);
|
|
114
|
+
let lineStartOffset = 0;
|
|
115
|
+
return flattenedLines.map((line, lineIndex) => {
|
|
116
|
+
const cursorToCodeUnit = buildCursorToCodeUnit(line.text);
|
|
117
|
+
const cursorLength = Math.max(0, cursorToCodeUnit.length - 1);
|
|
118
|
+
const hasNewline = lineIndex < flattenedLines.length - 1;
|
|
119
|
+
const builtLine = {
|
|
120
|
+
lineIndex,
|
|
121
|
+
lineStartOffset,
|
|
122
|
+
path: line.path,
|
|
123
|
+
parentPath: line.parentPath,
|
|
124
|
+
indexInParent: line.indexInParent,
|
|
125
|
+
block: line.block,
|
|
126
|
+
text: line.text,
|
|
127
|
+
cursorLength,
|
|
128
|
+
hasNewline,
|
|
129
|
+
cursorToCodeUnit,
|
|
130
|
+
isAtomic: line.isAtomic,
|
|
131
|
+
};
|
|
132
|
+
lineStartOffset += cursorLength + (hasNewline ? 1 : 0);
|
|
133
|
+
return builtLine;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
export class EditorTextModel {
|
|
137
|
+
constructor(doc) {
|
|
138
|
+
this.lines = [
|
|
139
|
+
{
|
|
140
|
+
lineIndex: 0,
|
|
141
|
+
lineStartOffset: 0,
|
|
142
|
+
path: [0],
|
|
143
|
+
parentPath: [],
|
|
144
|
+
indexInParent: 0,
|
|
145
|
+
block: { type: "paragraph", content: [] },
|
|
146
|
+
text: "",
|
|
147
|
+
cursorLength: 0,
|
|
148
|
+
hasNewline: false,
|
|
149
|
+
cursorToCodeUnit: [0],
|
|
150
|
+
isAtomic: false,
|
|
151
|
+
},
|
|
152
|
+
];
|
|
153
|
+
this.lineOffsets = [0];
|
|
154
|
+
this.visibleText = "";
|
|
155
|
+
this.cursorLength = 0;
|
|
156
|
+
if (doc) {
|
|
157
|
+
this.rebuild(doc);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
rebuild(doc) {
|
|
161
|
+
this.lines = buildLines(doc);
|
|
162
|
+
this.lineOffsets = computeLineOffsets(this.lines);
|
|
163
|
+
this.visibleText = this.lines.map((line) => line.text).join("\n");
|
|
164
|
+
const lastLine = this.lines[this.lines.length - 1];
|
|
165
|
+
const lastStart = this.lineOffsets[this.lineOffsets.length - 1] ?? 0;
|
|
166
|
+
this.cursorLength = lastStart + (lastLine?.cursorLength ?? 0);
|
|
167
|
+
}
|
|
168
|
+
getLines() {
|
|
169
|
+
return this.lines;
|
|
170
|
+
}
|
|
171
|
+
getStructuralLines() {
|
|
172
|
+
return this.lines;
|
|
173
|
+
}
|
|
174
|
+
getLineOffsets() {
|
|
175
|
+
return this.lineOffsets;
|
|
176
|
+
}
|
|
177
|
+
getVisibleText() {
|
|
178
|
+
return this.visibleText;
|
|
179
|
+
}
|
|
180
|
+
getCursorLength() {
|
|
181
|
+
return this.cursorLength;
|
|
182
|
+
}
|
|
183
|
+
resolveOffsetToLine(offset) {
|
|
184
|
+
return resolveOffsetInLines({
|
|
185
|
+
lines: this.lines,
|
|
186
|
+
offset,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
visibleOffsetToCursorOffset(visibleOffset) {
|
|
190
|
+
if (this.lines.length === 0) {
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
const clampedOffset = Math.max(0, visibleOffset);
|
|
194
|
+
let codeUnitIndex = 0;
|
|
195
|
+
for (let lineIndex = 0; lineIndex < this.lines.length; lineIndex += 1) {
|
|
196
|
+
const line = this.lines[lineIndex];
|
|
197
|
+
const lineStart = codeUnitIndex;
|
|
198
|
+
const lineEnd = lineStart + line.text.length;
|
|
199
|
+
if (clampedOffset <= lineEnd || lineIndex === this.lines.length - 1) {
|
|
200
|
+
const offsetInLine = Math.max(0, Math.min(clampedOffset - lineStart, line.text.length));
|
|
201
|
+
const cursorOffsetInLine = cursorOffsetFromCodeUnit(line, offsetInLine);
|
|
202
|
+
const lineStartOffset = this.lineOffsets[lineIndex] ?? 0;
|
|
203
|
+
return lineStartOffset + cursorOffsetInLine;
|
|
204
|
+
}
|
|
205
|
+
codeUnitIndex = lineEnd + (line.hasNewline ? 1 : 0);
|
|
206
|
+
if (line.hasNewline && clampedOffset === codeUnitIndex) {
|
|
207
|
+
const lineStartOffset = this.lineOffsets[lineIndex] ?? 0;
|
|
208
|
+
return lineStartOffset + line.cursorLength + 1;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
cursorOffsetToVisibleOffset(cursorOffset) {
|
|
214
|
+
if (this.lines.length === 0) {
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
const { lineIndex, offsetInLine } = this.resolveOffsetToLine(cursorOffset);
|
|
218
|
+
let codeUnitIndex = 0;
|
|
219
|
+
for (let index = 0; index < this.lines.length; index += 1) {
|
|
220
|
+
const line = this.lines[index];
|
|
221
|
+
if (index === lineIndex) {
|
|
222
|
+
const clampedOffset = Math.max(0, Math.min(offsetInLine, line.cursorLength));
|
|
223
|
+
return codeUnitIndex + (line.cursorToCodeUnit[clampedOffset] ?? 0);
|
|
224
|
+
}
|
|
225
|
+
codeUnitIndex += line.text.length + (line.hasNewline ? 1 : 0);
|
|
226
|
+
}
|
|
227
|
+
const lastLine = this.lines[this.lines.length - 1];
|
|
228
|
+
const lastStart = this.lineOffsets[this.lineOffsets.length - 1] ?? 0;
|
|
229
|
+
const lastOffset = Math.max(0, cursorOffset - lastStart);
|
|
230
|
+
return (codeUnitIndex +
|
|
231
|
+
(lastLine?.cursorToCodeUnit[lastOffset] ?? lastLine?.text.length ?? 0));
|
|
232
|
+
}
|
|
233
|
+
getTextSelection(selection) {
|
|
234
|
+
return {
|
|
235
|
+
start: this.cursorOffsetToVisibleOffset(selection.start),
|
|
236
|
+
end: this.cursorOffsetToVisibleOffset(selection.end),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
getTextBeforeCursor(selection, maxChars) {
|
|
240
|
+
const text = this.visibleText;
|
|
241
|
+
const cursor = Math.max(0, Math.min(this.cursorOffsetToVisibleOffset(selection.start), text.length));
|
|
242
|
+
const length = Math.max(0, maxChars);
|
|
243
|
+
return text.slice(Math.max(0, cursor - length), cursor);
|
|
244
|
+
}
|
|
245
|
+
getTextAroundCursor(selection, before, after) {
|
|
246
|
+
const text = this.visibleText;
|
|
247
|
+
const cursor = Math.max(0, Math.min(this.cursorOffsetToVisibleOffset(selection.start), text.length));
|
|
248
|
+
const beforeLength = Math.max(0, before);
|
|
249
|
+
const afterLength = Math.max(0, after);
|
|
250
|
+
return {
|
|
251
|
+
before: text.slice(Math.max(0, cursor - beforeLength), cursor),
|
|
252
|
+
after: text.slice(cursor, Math.min(text.length, cursor + afterLength)),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
getTextForCursorRange(start, end) {
|
|
256
|
+
const normalizedStart = Math.min(start, end);
|
|
257
|
+
const normalizedEnd = Math.max(start, end);
|
|
258
|
+
const visibleStart = this.cursorOffsetToVisibleOffset(normalizedStart);
|
|
259
|
+
const visibleEnd = this.cursorOffsetToVisibleOffset(normalizedEnd);
|
|
260
|
+
return this.visibleText.slice(visibleStart, visibleEnd);
|
|
261
|
+
}
|
|
262
|
+
getGraphemeAtCursor(cursorOffset) {
|
|
263
|
+
if (this.lines.length === 0) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
const { lineIndex, offsetInLine } = this.resolveOffsetToLine(cursorOffset);
|
|
267
|
+
const line = this.lines[lineIndex];
|
|
268
|
+
if (!line || offsetInLine >= line.cursorLength) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const segments = graphemeSegments(line.text);
|
|
272
|
+
return segments[offsetInLine]?.segment ?? null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const textModelByDoc = new WeakMap();
|
|
276
|
+
export function getEditorTextModelForDoc(doc) {
|
|
277
|
+
const cached = textModelByDoc.get(doc);
|
|
278
|
+
if (cached) {
|
|
279
|
+
return cached;
|
|
280
|
+
}
|
|
281
|
+
const model = new EditorTextModel(doc);
|
|
282
|
+
textModelByDoc.set(doc, model);
|
|
283
|
+
return model;
|
|
284
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Selection } from "../../core/types";
|
|
2
|
-
import {
|
|
2
|
+
import type { LineInfo } from "./selection-layout";
|
|
3
3
|
import { type SelectionRect } from "./selection-geometry";
|
|
4
4
|
export type SelectionGeometry = {
|
|
5
5
|
selectionRects: SelectionRect[];
|
|
@@ -11,6 +11,10 @@ export declare function getSelectionGeometry(params: {
|
|
|
11
11
|
container: HTMLElement;
|
|
12
12
|
docLines: LineInfo[];
|
|
13
13
|
selection: Selection;
|
|
14
|
+
resolveOffsetToLine: (offset: number) => {
|
|
15
|
+
lineIndex: number;
|
|
16
|
+
offsetInLine: number;
|
|
17
|
+
};
|
|
14
18
|
}): SelectionGeometry;
|
|
15
19
|
export declare function getCaretRect(params: {
|
|
16
20
|
lineElement: HTMLElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-geometry-dom.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-geometry-dom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,
|
|
1
|
+
{"version":3,"file":"selection-geometry-dom.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-geometry-dom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAUnD,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;CACjC,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,mBAAmB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QACvC,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,GAAG,iBAAiB,CAoHpB;AAMD,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;CACnC,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAuO9C"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { resolveOffsetToLine } from "./selection-layout";
|
|
2
1
|
import { createOffsetToXMeasurer, cursorOffsetToDomOffset, getLineElement, groupDomRectsByRow, measureLayoutModelRangeFromDom, resolveDomPosition, toLayoutRect, } from "./selection-layout-dom";
|
|
3
2
|
import { computeCaretRect, computeSelectionRects, } from "./selection-geometry";
|
|
4
3
|
export function getSelectionGeometry(params) {
|
|
@@ -12,8 +11,8 @@ export function getSelectionGeometry(params) {
|
|
|
12
11
|
};
|
|
13
12
|
const layout = shouldMeasureLayout(normalized)
|
|
14
13
|
? (() => {
|
|
15
|
-
const startLine = resolveOffsetToLine(
|
|
16
|
-
const endLine = resolveOffsetToLine(
|
|
14
|
+
const startLine = params.resolveOffsetToLine(normalized.start);
|
|
15
|
+
const endLine = params.resolveOffsetToLine(normalized.end);
|
|
17
16
|
return measureLayoutModelRangeFromDom({
|
|
18
17
|
lines: docLines,
|
|
19
18
|
root,
|
|
@@ -25,7 +24,7 @@ export function getSelectionGeometry(params) {
|
|
|
25
24
|
: null;
|
|
26
25
|
const containerRect = container.getBoundingClientRect();
|
|
27
26
|
const scroll = { top: container.scrollTop, left: container.scrollLeft };
|
|
28
|
-
const startLine = resolveOffsetToLine(
|
|
27
|
+
const startLine = params.resolveOffsetToLine(normalized.start);
|
|
29
28
|
const hasSelection = normalized.start !== normalized.end;
|
|
30
29
|
if (!hasSelection) {
|
|
31
30
|
const lineInfo = docLines[startLine.lineIndex];
|
|
@@ -73,7 +72,7 @@ export function getSelectionGeometry(params) {
|
|
|
73
72
|
lines: docLines,
|
|
74
73
|
});
|
|
75
74
|
const focusOffset = normalized.affinity === "backward" ? normalized.start : normalized.end;
|
|
76
|
-
const focusLine = resolveOffsetToLine(
|
|
75
|
+
const focusLine = params.resolveOffsetToLine(focusOffset);
|
|
77
76
|
const focusLineElement = getLineElement(root, focusLine.lineIndex);
|
|
78
77
|
let focusRect = null;
|
|
79
78
|
if (focusLineElement) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-layout-dom.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-layout-dom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,UAAU,EAEV,QAAQ,EAET,MAAM,oBAAoB,CAAC;AAG5B,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC,GAAG,UAAU,CAOb;AAqBD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CA2B9D;AA6VD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,GAAG,cAAc,GAAG,IAAI,CA+CxB;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;CACxB,GAAG,WAAW,GAAG,IAAI,CAUrB;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"selection-layout-dom.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-layout-dom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,UAAU,EAEV,QAAQ,EAET,MAAM,oBAAoB,CAAC;AAG5B,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC,GAAG,UAAU,CAOb;AAqBD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CA2B9D;AA6VD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,GAAG,cAAc,GAAG,IAAI,CA+CxB;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;CACxB,GAAG,WAAW,GAAG,IAAI,CAUrB;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,WAAW,GAAG,IAAI,CA2CrB;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,GAChB,WAAW,GAAG,IAAI,CAEpB;AAMD,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,MAAM,GACnB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAiBhC;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAiC7D;AAED,wBAAgB,uBAAuB,CACrC,gBAAgB,EAAE,MAAM,EAAE,EAC1B,MAAM,EAAE,MAAM,GACb,MAAM,CAER;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,GAAG,aAAa,GAAG,IAAI,CAoZvB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildLayoutModel
|
|
1
|
+
import { buildLayoutModel } from "./selection-layout";
|
|
2
2
|
export function toLayoutRect(params) {
|
|
3
3
|
return {
|
|
4
4
|
top: params.rect.top - params.containerRect.top + params.scroll.top,
|
|
@@ -402,8 +402,6 @@ export function measureLayoutModelRangeFromDom(params) {
|
|
|
402
402
|
}
|
|
403
403
|
const clampedStart = Math.max(0, Math.min(params.startLineIndex, params.lines.length - 1));
|
|
404
404
|
const clampedEnd = Math.max(clampedStart, Math.min(params.endLineIndex, params.lines.length - 1));
|
|
405
|
-
const lineOffsets = getLineOffsets(params.lines);
|
|
406
|
-
let lineStartOffset = lineOffsets[clampedStart] ?? 0;
|
|
407
405
|
const layouts = [];
|
|
408
406
|
for (let lineIndex = clampedStart; lineIndex <= clampedEnd; lineIndex += 1) {
|
|
409
407
|
const lineInfo = params.lines[lineIndex];
|
|
@@ -419,13 +417,12 @@ export function measureLayoutModelRangeFromDom(params) {
|
|
|
419
417
|
});
|
|
420
418
|
layouts.push({
|
|
421
419
|
lineIndex: lineInfo.lineIndex,
|
|
422
|
-
lineStartOffset,
|
|
420
|
+
lineStartOffset: lineInfo.lineStartOffset,
|
|
423
421
|
lineLength: lineInfo.cursorLength,
|
|
424
422
|
lineHasNewline: lineInfo.hasNewline,
|
|
425
423
|
lineBox: measurement.lineBox,
|
|
426
424
|
rows: measurement.rows,
|
|
427
425
|
});
|
|
428
|
-
lineStartOffset += lineInfo.cursorLength + (lineInfo.hasNewline ? 1 : 0);
|
|
429
426
|
}
|
|
430
427
|
return { container: measurer.container, lines: layouts };
|
|
431
428
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LineInfo } from "../internal/editor-text-model";
|
|
2
2
|
export type LayoutRect = {
|
|
3
3
|
top: number;
|
|
4
4
|
left: number;
|
|
@@ -42,19 +42,6 @@ export type LayoutMeasurer = {
|
|
|
42
42
|
container: LayoutRect;
|
|
43
43
|
measureLine: (input: LineMeasurementInput) => LineMeasurement;
|
|
44
44
|
};
|
|
45
|
-
export type LineInfo
|
|
46
|
-
lineIndex: number;
|
|
47
|
-
text: string;
|
|
48
|
-
cursorLength: number;
|
|
49
|
-
hasNewline: boolean;
|
|
50
|
-
cursorToCodeUnit: number[];
|
|
51
|
-
isAtomic: boolean;
|
|
52
|
-
};
|
|
45
|
+
export type { LineInfo };
|
|
53
46
|
export declare function buildLayoutModel(lines: LineInfo[], measurer: LayoutMeasurer): LayoutModel;
|
|
54
|
-
export declare function getDocLines(doc: Doc): LineInfo[];
|
|
55
|
-
export declare function getLineOffsets(lines: LineInfo[]): number[];
|
|
56
|
-
export declare function resolveOffsetToLine(lines: LineInfo[], offset: number): {
|
|
57
|
-
lineIndex: number;
|
|
58
|
-
offsetInLine: number;
|
|
59
|
-
};
|
|
60
47
|
//# sourceMappingURL=selection-layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-layout.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"selection-layout.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,6EAA6E;IAC7E,SAAS,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,UAAU,CAAC;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,UAAU,CAAC;IACtB,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,eAAe,CAAC;CAC/D,CAAC;AAEF,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,EAAE,EACjB,QAAQ,EAAE,cAAc,GACvB,WAAW,CAqCb"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { graphemeSegments } from "../../shared/segmenter";
|
|
2
1
|
export function buildLayoutModel(lines, measurer) {
|
|
3
2
|
const layouts = [];
|
|
4
3
|
let top = measurer.container.top;
|
|
5
|
-
let lineStartOffset = 0;
|
|
6
4
|
lines.forEach((line) => {
|
|
7
5
|
const measurement = measurer.measureLine({
|
|
8
6
|
lineIndex: line.lineIndex,
|
|
@@ -13,14 +11,13 @@ export function buildLayoutModel(lines, measurer) {
|
|
|
13
11
|
});
|
|
14
12
|
layouts.push({
|
|
15
13
|
lineIndex: line.lineIndex,
|
|
16
|
-
lineStartOffset,
|
|
14
|
+
lineStartOffset: line.lineStartOffset,
|
|
17
15
|
lineLength: line.cursorLength,
|
|
18
16
|
lineHasNewline: line.hasNewline,
|
|
19
17
|
lineBox: measurement.lineBox,
|
|
20
18
|
rows: measurement.rows,
|
|
21
19
|
});
|
|
22
20
|
top = measurement.lineBox.top + measurement.lineBox.height;
|
|
23
|
-
lineStartOffset += line.cursorLength + (line.hasNewline ? 1 : 0);
|
|
24
21
|
});
|
|
25
22
|
const height = Math.max(measurer.container.height, top - measurer.container.top);
|
|
26
23
|
return {
|
|
@@ -31,98 +28,3 @@ export function buildLayoutModel(lines, measurer) {
|
|
|
31
28
|
lines: layouts,
|
|
32
29
|
};
|
|
33
30
|
}
|
|
34
|
-
export function getDocLines(doc) {
|
|
35
|
-
const flattenedLines = flattenBlocksWithAtomicInfo(doc.blocks);
|
|
36
|
-
return flattenedLines.map((line, index) => {
|
|
37
|
-
const cursorToCodeUnit = buildCursorToCodeUnit(line.text);
|
|
38
|
-
const cursorLength = Math.max(0, cursorToCodeUnit.length - 1);
|
|
39
|
-
return {
|
|
40
|
-
lineIndex: index,
|
|
41
|
-
text: line.text,
|
|
42
|
-
cursorLength,
|
|
43
|
-
hasNewline: index < flattenedLines.length - 1,
|
|
44
|
-
cursorToCodeUnit,
|
|
45
|
-
isAtomic: line.isAtomic,
|
|
46
|
-
};
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
function flattenBlocksWithAtomicInfo(blocks) {
|
|
50
|
-
const lines = [];
|
|
51
|
-
blocks.forEach((block) => {
|
|
52
|
-
lines.push(...flattenBlockWithAtomicInfo(block));
|
|
53
|
-
});
|
|
54
|
-
if (lines.length === 0) {
|
|
55
|
-
lines.push({ text: "", isAtomic: false });
|
|
56
|
-
}
|
|
57
|
-
return lines;
|
|
58
|
-
}
|
|
59
|
-
function flattenBlockWithAtomicInfo(block) {
|
|
60
|
-
if (block.type === "paragraph") {
|
|
61
|
-
return [
|
|
62
|
-
{ text: block.content.map(flattenInline).join(""), isAtomic: false },
|
|
63
|
-
];
|
|
64
|
-
}
|
|
65
|
-
if (block.type === "block-wrapper") {
|
|
66
|
-
return flattenBlocksWithAtomicInfo(block.blocks);
|
|
67
|
-
}
|
|
68
|
-
if (block.type === "block-atom") {
|
|
69
|
-
// Atomic blocks are represented as empty lines for layout purposes
|
|
70
|
-
return [{ text: "", isAtomic: true }];
|
|
71
|
-
}
|
|
72
|
-
return [];
|
|
73
|
-
}
|
|
74
|
-
export function getLineOffsets(lines) {
|
|
75
|
-
const offsets = [];
|
|
76
|
-
let current = 0;
|
|
77
|
-
lines.forEach((line) => {
|
|
78
|
-
offsets.push(current);
|
|
79
|
-
current += line.cursorLength;
|
|
80
|
-
if (line.hasNewline) {
|
|
81
|
-
current += 1;
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
return offsets;
|
|
85
|
-
}
|
|
86
|
-
export function resolveOffsetToLine(lines, offset) {
|
|
87
|
-
if (lines.length === 0) {
|
|
88
|
-
return { lineIndex: 0, offsetInLine: 0 };
|
|
89
|
-
}
|
|
90
|
-
const lineOffsets = getLineOffsets(lines);
|
|
91
|
-
const totalLength = lineOffsets[lineOffsets.length - 1] + lines[lines.length - 1].cursorLength;
|
|
92
|
-
const clamped = Math.max(0, Math.min(offset, totalLength));
|
|
93
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
94
|
-
const lineStart = lineOffsets[index];
|
|
95
|
-
const lineEnd = lineStart + lines[index].cursorLength;
|
|
96
|
-
if (clamped <= lineEnd || index === lines.length - 1) {
|
|
97
|
-
return { lineIndex: index, offsetInLine: clamped - lineStart };
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const lastIndex = lines.length - 1;
|
|
101
|
-
return {
|
|
102
|
-
lineIndex: lastIndex,
|
|
103
|
-
offsetInLine: lines[lastIndex].cursorLength,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function flattenInline(inline) {
|
|
107
|
-
if (inline.type === "text") {
|
|
108
|
-
return inline.text;
|
|
109
|
-
}
|
|
110
|
-
if (inline.type === "inline-wrapper") {
|
|
111
|
-
return inline.children.map(flattenInline).join("");
|
|
112
|
-
}
|
|
113
|
-
if (inline.type === "inline-atom") {
|
|
114
|
-
return " ";
|
|
115
|
-
}
|
|
116
|
-
return "";
|
|
117
|
-
}
|
|
118
|
-
function buildCursorToCodeUnit(text) {
|
|
119
|
-
const segments = graphemeSegments(text);
|
|
120
|
-
const mapping = [0];
|
|
121
|
-
for (const segment of segments) {
|
|
122
|
-
mapping.push(segment.index + segment.segment.length);
|
|
123
|
-
}
|
|
124
|
-
if (mapping.length === 0) {
|
|
125
|
-
mapping.push(0);
|
|
126
|
-
}
|
|
127
|
-
return mapping;
|
|
128
|
-
}
|
|
@@ -9,6 +9,10 @@ export declare function moveSelectionVertically(params: {
|
|
|
9
9
|
lines: LineInfo[];
|
|
10
10
|
layout: LayoutModel;
|
|
11
11
|
selection: Selection;
|
|
12
|
+
resolveOffsetToLine: (offset: number) => {
|
|
13
|
+
lineIndex: number;
|
|
14
|
+
offsetInLine: number;
|
|
15
|
+
};
|
|
12
16
|
direction: "up" | "down";
|
|
13
17
|
goalX: number | null;
|
|
14
18
|
focusRowIndex?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-navigation.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAa,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"selection-navigation.d.ts","sourceRoot":"","sources":["../../../../src/cake/editor/selection/selection-navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAa,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE3E,KAAK,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAEvC,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAsIF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,mBAAmB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QACvC,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,SAAS,EAAE,IAAI,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,CAChB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,KACN;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC7E,GAAG,wBAAwB,GAAG,IAAI,CAmKlC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { resolveOffsetToLine } from "./selection-layout";
|
|
2
1
|
function rectRight(rect) {
|
|
3
2
|
return rect.left + rect.width;
|
|
4
3
|
}
|
|
@@ -103,7 +102,7 @@ export function moveSelectionVertically(params) {
|
|
|
103
102
|
}
|
|
104
103
|
const affinity = resolveSelectionAffinity(params.selection);
|
|
105
104
|
const { anchor, focus } = resolveSelectionAnchorAndFocus(params.selection);
|
|
106
|
-
const focusResolved = resolveOffsetToLine(
|
|
105
|
+
const focusResolved = params.resolveOffsetToLine(focus);
|
|
107
106
|
const focusLineLayout = layout.lines[focusResolved.lineIndex];
|
|
108
107
|
if (!focusLineLayout) {
|
|
109
108
|
return null;
|
|
@@ -11,7 +11,8 @@ import { scrollbarExtension } from "./scrollbar";
|
|
|
11
11
|
import { strikethroughExtension } from "./strikethrough/strikethrough";
|
|
12
12
|
import { underlineExtension } from "./underline/underline";
|
|
13
13
|
import { mentionExtension } from "./mention/mention";
|
|
14
|
-
|
|
14
|
+
import { structuralReparsePolicyExtension } from "./shared/structural-reparse-policy";
|
|
15
|
+
export { boldExtension, combinedEmphasisExtension, linkExtension, blockquoteExtension, italicExtension, headingExtension, imageExtension, plainTextListExtension, scrollbarExtension, strikethroughExtension, underlineExtension, mentionExtension, structuralReparsePolicyExtension, };
|
|
15
16
|
export declare const bundledExtensionsWithoutImage: import("../..").CakeExtension[];
|
|
16
17
|
export declare const bundledExtensions: import("../..").CakeExtension[];
|
|
17
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cake/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cake/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,gCAAgC,EAAE,MAAM,oCAAoC,CAAC;AAEtF,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,gCAAgC,GACjC,CAAC;AAEF,eAAO,MAAM,6BAA6B,iCAWzC,CAAC;AAEF,eAAO,MAAM,iBAAiB,iCAG7B,CAAC"}
|
|
@@ -10,8 +10,10 @@ import { scrollbarExtension } from "./scrollbar";
|
|
|
10
10
|
import { strikethroughExtension } from "./strikethrough/strikethrough";
|
|
11
11
|
import { underlineExtension } from "./underline/underline";
|
|
12
12
|
import { mentionExtension } from "./mention/mention";
|
|
13
|
-
|
|
13
|
+
import { structuralReparsePolicyExtension } from "./shared/structural-reparse-policy";
|
|
14
|
+
export { boldExtension, combinedEmphasisExtension, linkExtension, blockquoteExtension, italicExtension, headingExtension, imageExtension, plainTextListExtension, scrollbarExtension, strikethroughExtension, underlineExtension, mentionExtension, structuralReparsePolicyExtension, };
|
|
14
15
|
export const bundledExtensionsWithoutImage = [
|
|
16
|
+
structuralReparsePolicyExtension,
|
|
15
17
|
blockquoteExtension,
|
|
16
18
|
headingExtension,
|
|
17
19
|
plainTextListExtension,
|