@adecore/editor 0.21.1 → 0.22.0
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/code-block.js +26 -22
- package/dist/controller.d.ts +1 -0
- package/dist/controller.js +29 -43
- package/dist/engine.js +34 -42
- package/dist/fake.js +44 -97
- package/dist/keymap.d.ts +1 -2
- package/dist/keymap.js +18 -15
- package/dist/layout.d.ts +1 -1
- package/dist/layout.js +7 -6
- package/dist/listeners.d.ts +2 -2
- package/dist/listeners.js +2 -2
- package/dist/modifier-gesture.js +2 -2
- package/dist/native-input.d.ts +1 -0
- package/dist/native-input.js +5 -3
- package/dist/outline.js +2 -2
- package/dist/overview.js +0 -1
- package/dist/paint.js +11 -15
- package/dist/pointer.js +9 -2
- package/dist/testing.js +8 -5
- package/dist/tokens.d.ts +1 -0
- package/dist/tokens.js +9 -10
- package/dist/view.d.ts +1 -0
- package/dist/view.js +63 -92
- package/package.json +2 -2
- package/src/code-block.ts +27 -22
- package/src/controller.ts +32 -43
- package/src/engine.ts +37 -46
- package/src/fake.ts +44 -97
- package/src/keymap.ts +20 -17
- package/src/layout.ts +7 -6
- package/src/listeners.ts +3 -3
- package/src/modifier-gesture.ts +2 -2
- package/src/native-input.ts +6 -3
- package/src/outline.ts +2 -2
- package/src/overview.ts +0 -1
- package/src/paint.ts +12 -15
- package/src/pointer.ts +10 -2
- package/src/testing.ts +9 -5
- package/src/tokens.ts +10 -10
- package/src/types.ts +14 -8
- package/src/view.ts +73 -99
package/dist/testing.js
CHANGED
|
@@ -40,28 +40,31 @@ export function createPage() {
|
|
|
40
40
|
host: document.getElementById('host')
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
+
function createEvent(window, type) {
|
|
44
|
+
return new window.Event(type, { bubbles: true, cancelable: true });
|
|
45
|
+
}
|
|
43
46
|
/* Fires a keydown at the element and says whether the editor took the key. */
|
|
44
47
|
export function press(window, target, key, options = {}) {
|
|
45
|
-
const event =
|
|
48
|
+
const event = createEvent(window, 'keydown');
|
|
46
49
|
Object.assign(event, { key, ctrlKey: false, metaKey: false, altKey: false, shiftKey: false, isComposing: false, ...options });
|
|
47
50
|
target.dispatchEvent(event);
|
|
48
51
|
return event.defaultPrevented;
|
|
49
52
|
}
|
|
50
53
|
/* Fires a keyup at the element, the other half of `press`. */
|
|
51
54
|
export function release(window, target, key, options = {}) {
|
|
52
|
-
const event =
|
|
55
|
+
const event = createEvent(window, 'keyup');
|
|
53
56
|
Object.assign(event, { key, ctrlKey: false, metaKey: false, altKey: false, shiftKey: false, isComposing: false, ...options });
|
|
54
57
|
target.dispatchEvent(event);
|
|
55
58
|
}
|
|
56
59
|
/* What a browser sends before it puts text in a textarea. */
|
|
57
60
|
export function typeInto(window, target, text) {
|
|
58
|
-
const event =
|
|
61
|
+
const event = createEvent(window, 'beforeinput');
|
|
59
62
|
Object.assign(event, { inputType: 'insertText', data: text, isComposing: false });
|
|
60
63
|
target.dispatchEvent(event);
|
|
61
64
|
}
|
|
62
65
|
/* A clipboard event with the data it carries; what a copy or cut sets is read back through `data`. */
|
|
63
66
|
export function clipboard(window, target, type, data = { text: '' }) {
|
|
64
|
-
const event =
|
|
67
|
+
const event = createEvent(window, type);
|
|
65
68
|
Object.assign(event, {
|
|
66
69
|
clipboardData: {
|
|
67
70
|
getData: () => data.text,
|
|
@@ -75,7 +78,7 @@ export function clipboard(window, target, type, data = { text: '' }) {
|
|
|
75
78
|
}
|
|
76
79
|
/* A pointer event at a point of the screen; the page has no scroll or scale, so it is also the point of the content. */
|
|
77
80
|
export function pointer(window, target, type, x, y, options = {}) {
|
|
78
|
-
const event =
|
|
81
|
+
const event = createEvent(window, type);
|
|
79
82
|
Object.assign(event, {
|
|
80
83
|
clientX: x,
|
|
81
84
|
clientY: y,
|
package/dist/tokens.d.ts
CHANGED
package/dist/tokens.js
CHANGED
|
@@ -32,8 +32,7 @@ export class TokenCache {
|
|
|
32
32
|
this.lines = this.source.getLineCount();
|
|
33
33
|
this.entries = [];
|
|
34
34
|
this.frontier = 0;
|
|
35
|
-
this.
|
|
36
|
-
this.pivotLine = -1;
|
|
35
|
+
this.forgetPivot();
|
|
37
36
|
}
|
|
38
37
|
/* How far down the document has colors that are right for the text. */
|
|
39
38
|
get colored() {
|
|
@@ -71,8 +70,7 @@ export class TokenCache {
|
|
|
71
70
|
if (first === undefined) {
|
|
72
71
|
this.entries = [];
|
|
73
72
|
this.frontier = 0;
|
|
74
|
-
this.
|
|
75
|
-
this.pivotLine = -1;
|
|
73
|
+
this.forgetPivot();
|
|
76
74
|
return;
|
|
77
75
|
}
|
|
78
76
|
const firstLine = lineOf(first.from);
|
|
@@ -87,8 +85,7 @@ export class TokenCache {
|
|
|
87
85
|
this.frontier = Math.min(this.frontier, firstLine);
|
|
88
86
|
if (last === undefined || lastOld < firstLine || this.entries.length <= firstLine) {
|
|
89
87
|
this.entries.length = Math.min(this.entries.length, firstLine);
|
|
90
|
-
this.
|
|
91
|
-
this.pivotLine = -1;
|
|
88
|
+
this.forgetPivot();
|
|
92
89
|
return;
|
|
93
90
|
}
|
|
94
91
|
const old = this.entries[lastOld];
|
|
@@ -109,8 +106,7 @@ export class TokenCache {
|
|
|
109
106
|
}
|
|
110
107
|
if (tokenizer.stale?.() === true) {
|
|
111
108
|
this.frontier = 0;
|
|
112
|
-
this.
|
|
113
|
-
this.pivotLine = -1;
|
|
109
|
+
this.forgetPivot();
|
|
114
110
|
}
|
|
115
111
|
const count = this.source.getLineCount();
|
|
116
112
|
const limit = Math.min(until, count - 1);
|
|
@@ -135,8 +131,7 @@ export class TokenCache {
|
|
|
135
131
|
(previous !== undefined && line >= this.reusableFrom && tokenizer.sameState(previous.state, next.state));
|
|
136
132
|
if (settled) {
|
|
137
133
|
this.frontier = this.entries.length;
|
|
138
|
-
this.
|
|
139
|
-
this.pivotLine = -1;
|
|
134
|
+
this.forgetPivot();
|
|
140
135
|
break;
|
|
141
136
|
}
|
|
142
137
|
if (now() > deadline) {
|
|
@@ -145,6 +140,10 @@ export class TokenCache {
|
|
|
145
140
|
}
|
|
146
141
|
return this.frontier > from ? { from, to: this.frontier - 1 } : null;
|
|
147
142
|
}
|
|
143
|
+
forgetPivot() {
|
|
144
|
+
this.reusableFrom = Number.POSITIVE_INFINITY;
|
|
145
|
+
this.pivotLine = -1;
|
|
146
|
+
}
|
|
148
147
|
/* Whether lines through `line` are colored for the text as it is now. */
|
|
149
148
|
covers(line) {
|
|
150
149
|
return this.frontier > line || this.frontier >= this.source.getLineCount();
|
package/dist/view.d.ts
CHANGED
package/dist/view.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { replacementText, scanBrackets } from '@adecore/editor-core';
|
|
1
|
+
import { indentationColumn, replacementText, scanBrackets } from '@adecore/editor-core';
|
|
2
2
|
import { FindController } from './find.js';
|
|
3
3
|
import { EditorLayout, RIGHT_PADDING } from './layout.js';
|
|
4
4
|
import { createMetrics, readEditorFont } from './metrics.js';
|
|
5
5
|
import { AttributionRuns, colorValue, tintValue } from './attribution.js';
|
|
6
6
|
import { renderCodeBlock } from './code-block.js';
|
|
7
|
+
import { emit, subscribe } from './listeners.js';
|
|
7
8
|
import { mapOffset } from './offsets.js';
|
|
8
9
|
import { mapTrackedRange } from './tracked-range.js';
|
|
9
10
|
import { scrollPosition } from './scroll.js';
|
|
@@ -12,11 +13,23 @@ import { Outline, scopeChain, stickyCover, stickyPlacements, structuralEntries }
|
|
|
12
13
|
import { overviewTicks, paintOverview } from './overview.js';
|
|
13
14
|
import { paintCarets, paintGutter, paintOver, paintOverlays, paintRemoteCarets, paintSigns, paintSticky, RowPainter } from './paint.js';
|
|
14
15
|
import { overlayTokens } from './semantic.js';
|
|
15
|
-
import { indentationColumn } from '@adecore/editor-core';
|
|
16
16
|
import { TokenCache } from './tokens.js';
|
|
17
17
|
function sameRect(left, right) {
|
|
18
18
|
return left.left === right.left && left.top === right.top && left.right === right.right && left.bottom === right.bottom;
|
|
19
19
|
}
|
|
20
|
+
function mapRange(range, changes) {
|
|
21
|
+
return { ...range, from: mapOffset(range.from, changes), to: mapOffset(range.to, changes) };
|
|
22
|
+
}
|
|
23
|
+
function mapFoldHints(hints, changes) {
|
|
24
|
+
return {
|
|
25
|
+
symbols: hints.symbols?.map((hint) => mapRange(hint, changes)) ?? [],
|
|
26
|
+
ranges: hints.ranges?.map((hint) => ({
|
|
27
|
+
...mapRange(hint, changes),
|
|
28
|
+
...(hint.head === undefined ? {} : { head: mapOffset(hint.head, changes) }),
|
|
29
|
+
...(hint.tail === undefined ? {} : { tail: mapOffset(hint.tail, changes) })
|
|
30
|
+
})) ?? []
|
|
31
|
+
};
|
|
32
|
+
}
|
|
20
33
|
/* The lines past the visible ones that are colored ahead of the scroll, and how long one slice of that work may take. */
|
|
21
34
|
const COLOR_MARGIN = 80;
|
|
22
35
|
const MIN_OVERSCAN = 400;
|
|
@@ -436,37 +449,7 @@ export class EditorView {
|
|
|
436
449
|
this.layoutGhostParts();
|
|
437
450
|
}
|
|
438
451
|
for (const changes of batches) {
|
|
439
|
-
this.
|
|
440
|
-
for (const [owner, blocks] of this.blocks) {
|
|
441
|
-
this.blocks.set(owner, blocks.map((block) => ({ ...block, at: mapOffset(block.at, changes) })));
|
|
442
|
-
}
|
|
443
|
-
this.lenses = this.lenses.map((lens) => ({ ...lens, at: mapOffset(lens.at, changes) }));
|
|
444
|
-
this.collapsed = new Set([...this.collapsed].map((anchor) => mapOffset(anchor, changes)));
|
|
445
|
-
this.settled = new Set([...this.settled].map((anchor) => mapOffset(anchor, changes)));
|
|
446
|
-
if (this.foldHints !== null) {
|
|
447
|
-
this.foldHints = {
|
|
448
|
-
symbols: this.foldHints.symbols?.map((hint) => ({ ...hint, from: mapOffset(hint.from, changes), to: mapOffset(hint.to, changes) })) ?? [],
|
|
449
|
-
ranges: this.foldHints.ranges?.map((hint) => ({
|
|
450
|
-
...hint,
|
|
451
|
-
from: mapOffset(hint.from, changes),
|
|
452
|
-
to: mapOffset(hint.to, changes),
|
|
453
|
-
...(hint.head === undefined ? {} : { head: mapOffset(hint.head, changes) }),
|
|
454
|
-
...(hint.tail === undefined ? {} : { tail: mapOffset(hint.tail, changes) })
|
|
455
|
-
})) ?? []
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
this.customFolds = this.customFolds.map((fold) => ({ from: mapOffset(fold.from, changes), to: mapOffset(fold.to, changes) }));
|
|
459
|
-
this.find.mapBounds(changes);
|
|
460
|
-
this.changeMarks = this.changeMarks.map((mark) => ({ ...mark, from: mapOffset(mark.from, changes), to: mapOffset(mark.to, changes) }));
|
|
461
|
-
this.markers = this.markers.map((marker) => ({ ...marker, from: mapOffset(marker.from, changes), to: mapOffset(marker.to, changes) }));
|
|
462
|
-
this.mapTracked(changes);
|
|
463
|
-
this.attribution.map(changes);
|
|
464
|
-
this.highlights.map(changes);
|
|
465
|
-
this.remoteCarets = this.remoteCarets.map((caret) => ({ ...caret, at: mapOffset(caret.at, changes) }));
|
|
466
|
-
for (const [owner, entries] of this.lineActions) {
|
|
467
|
-
this.lineActions.set(owner, entries.map((entry) => ({ ...entry, at: mapOffset(entry.at, changes) })));
|
|
468
|
-
}
|
|
469
|
-
this.semantic = this.semantic.map((token) => ({ ...token, from: mapOffset(token.from, changes), to: mapOffset(token.to, changes) }));
|
|
452
|
+
this.followEdit(changes);
|
|
470
453
|
}
|
|
471
454
|
this.foldRanges = this.mappedFolds(batches);
|
|
472
455
|
this.semanticVersion++;
|
|
@@ -496,6 +479,31 @@ export class EditorView {
|
|
|
496
479
|
}
|
|
497
480
|
this.requestRender();
|
|
498
481
|
}
|
|
482
|
+
/* Moves everything anchored to an offset along with one batch of changes. */
|
|
483
|
+
followEdit(changes) {
|
|
484
|
+
this.inlays = this.inlays.map((inlay) => ({ ...inlay, at: mapOffset(inlay.at, changes) }));
|
|
485
|
+
for (const [owner, blocks] of this.blocks) {
|
|
486
|
+
this.blocks.set(owner, blocks.map((block) => ({ ...block, at: mapOffset(block.at, changes) })));
|
|
487
|
+
}
|
|
488
|
+
this.lenses = this.lenses.map((lens) => ({ ...lens, at: mapOffset(lens.at, changes) }));
|
|
489
|
+
this.collapsed = new Set([...this.collapsed].map((anchor) => mapOffset(anchor, changes)));
|
|
490
|
+
this.settled = new Set([...this.settled].map((anchor) => mapOffset(anchor, changes)));
|
|
491
|
+
if (this.foldHints !== null) {
|
|
492
|
+
this.foldHints = mapFoldHints(this.foldHints, changes);
|
|
493
|
+
}
|
|
494
|
+
this.customFolds = this.customFolds.map((fold) => mapRange(fold, changes));
|
|
495
|
+
this.find.mapBounds(changes);
|
|
496
|
+
this.changeMarks = this.changeMarks.map((mark) => mapRange(mark, changes));
|
|
497
|
+
this.markers = this.markers.map((marker) => mapRange(marker, changes));
|
|
498
|
+
this.mapTracked(changes);
|
|
499
|
+
this.attribution.map(changes);
|
|
500
|
+
this.highlights.map(changes);
|
|
501
|
+
this.remoteCarets = this.remoteCarets.map((caret) => ({ ...caret, at: mapOffset(caret.at, changes) }));
|
|
502
|
+
for (const [owner, entries] of this.lineActions) {
|
|
503
|
+
this.lineActions.set(owner, entries.map((entry) => ({ ...entry, at: mapOffset(entry.at, changes) })));
|
|
504
|
+
}
|
|
505
|
+
this.semantic = this.semantic.map((token) => mapRange(token, changes));
|
|
506
|
+
}
|
|
499
507
|
mapTracked(changes) {
|
|
500
508
|
for (const entry of this.tracked) {
|
|
501
509
|
const mapped = mapTrackedRange(entry.from, entry.to, changes);
|
|
@@ -622,9 +630,7 @@ export class EditorView {
|
|
|
622
630
|
this.outline.setStructure(structuralEntries(ranges, this.model, (from, to) => this.model.slice(from, to), (offset) => this.brackets().pairs.get(offset)));
|
|
623
631
|
const anchors = new Set(this.foldRanges.map((range) => range.from));
|
|
624
632
|
this.collapsed = new Set([...this.collapsed].filter((anchor) => anchors.has(anchor)));
|
|
625
|
-
this.
|
|
626
|
-
this.moveHiddenCarets();
|
|
627
|
-
this.render();
|
|
633
|
+
this.refoldLayout();
|
|
628
634
|
}
|
|
629
635
|
/* The folds a person made of a selection, which the document's own structure does not know, among the ones it does. */
|
|
630
636
|
withCustomFolds(ranges) {
|
|
@@ -968,9 +974,11 @@ export class EditorView {
|
|
|
968
974
|
if (!rect) {
|
|
969
975
|
return { x: clientX - this.gutterWidth + this.viewport.scrollLeft, y: clientY + this.viewport.scrollTop };
|
|
970
976
|
}
|
|
971
|
-
const
|
|
972
|
-
|
|
973
|
-
|
|
977
|
+
const scale = this.screenScale(rect);
|
|
978
|
+
return {
|
|
979
|
+
x: (clientX - rect.left) / scale.x - this.gutterWidth + this.viewport.scrollLeft,
|
|
980
|
+
y: (clientY - rect.top) / scale.y + this.viewport.scrollTop
|
|
981
|
+
};
|
|
974
982
|
}
|
|
975
983
|
offsetAtPoint(clientX, clientY) {
|
|
976
984
|
const point = this.contentPoint(clientX, clientY);
|
|
@@ -1059,12 +1067,8 @@ export class EditorView {
|
|
|
1059
1067
|
}
|
|
1060
1068
|
}
|
|
1061
1069
|
onHover(listener) {
|
|
1062
|
-
this.hoverListeners
|
|
1063
|
-
return () => {
|
|
1064
|
-
this.hoverListeners.delete(listener);
|
|
1065
|
-
};
|
|
1070
|
+
return subscribe(this.hoverListeners, listener);
|
|
1066
1071
|
}
|
|
1067
|
-
/* The pointer moved over the editor; a drag in progress is not a hover. */
|
|
1068
1072
|
/*
|
|
1069
1073
|
* The other places the selected text is, found without a language server: only for one selection that
|
|
1070
1074
|
* holds no line break and is not blank, and not at all when there are more than a few of them.
|
|
@@ -1268,6 +1272,7 @@ export class EditorView {
|
|
|
1268
1272
|
this.dropCaret = offset;
|
|
1269
1273
|
this.render();
|
|
1270
1274
|
}
|
|
1275
|
+
/* The pointer moved over the editor; a drag in progress is not a hover. */
|
|
1271
1276
|
hoverMoved(event) {
|
|
1272
1277
|
this.content.classList.toggle('se-over-selection', !this.settings.readOnly && event.buttons === 0 && this.selectionAtPoint(event.clientX, event.clientY) !== null);
|
|
1273
1278
|
this.setHover(event.buttons === 0 ? this.characterAtPoint(event.clientX, event.clientY, event.target) : null);
|
|
@@ -1277,15 +1282,10 @@ export class EditorView {
|
|
|
1277
1282
|
return;
|
|
1278
1283
|
}
|
|
1279
1284
|
this.hoverOffset = offset;
|
|
1280
|
-
|
|
1281
|
-
listener(offset);
|
|
1282
|
-
}
|
|
1285
|
+
emit(this.hoverListeners, offset);
|
|
1283
1286
|
}
|
|
1284
1287
|
onViewChange(listener) {
|
|
1285
|
-
this.viewListeners
|
|
1286
|
-
return () => {
|
|
1287
|
-
this.viewListeners.delete(listener);
|
|
1288
|
-
};
|
|
1288
|
+
return subscribe(this.viewListeners, listener);
|
|
1289
1289
|
}
|
|
1290
1290
|
announceView() {
|
|
1291
1291
|
const key = `${this.scrollTop}|${this.scrollLeft}|${this.clientWidth}|${this.clientHeight}|${this.layout.height}`;
|
|
@@ -1293,9 +1293,7 @@ export class EditorView {
|
|
|
1293
1293
|
return;
|
|
1294
1294
|
}
|
|
1295
1295
|
this.viewKey = key;
|
|
1296
|
-
|
|
1297
|
-
listener();
|
|
1298
|
-
}
|
|
1296
|
+
emit(this.viewListeners);
|
|
1299
1297
|
}
|
|
1300
1298
|
caretOf(head) {
|
|
1301
1299
|
return this.layout.caret(head, head === this.ghost?.at ? 'before' : 'after', head === this.rowEndCaret);
|
|
@@ -1304,14 +1302,12 @@ export class EditorView {
|
|
|
1304
1302
|
get scrollPlace() {
|
|
1305
1303
|
return this.scrollRun?.to ?? { x: this.viewport.scrollLeft, y: this.viewport.scrollTop };
|
|
1306
1304
|
}
|
|
1307
|
-
/* Stops a scroll on its way where it is. */
|
|
1308
1305
|
cancelScroll() {
|
|
1309
1306
|
if (this.scrollRun !== null) {
|
|
1310
1307
|
this.document.defaultView?.cancelAnimationFrame?.(this.scrollRun.frame);
|
|
1311
1308
|
this.scrollRun = null;
|
|
1312
1309
|
}
|
|
1313
1310
|
}
|
|
1314
|
-
/* Whether a person asked their system for less motion. */
|
|
1315
1311
|
reducedMotion() {
|
|
1316
1312
|
return this.document.defaultView?.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches === true;
|
|
1317
1313
|
}
|
|
@@ -1440,15 +1436,10 @@ export class EditorView {
|
|
|
1440
1436
|
this.render();
|
|
1441
1437
|
}
|
|
1442
1438
|
onFind(listener) {
|
|
1443
|
-
this.findListeners
|
|
1444
|
-
return () => {
|
|
1445
|
-
this.findListeners.delete(listener);
|
|
1446
|
-
};
|
|
1439
|
+
return subscribe(this.findListeners, listener);
|
|
1447
1440
|
}
|
|
1448
1441
|
announceFind() {
|
|
1449
|
-
|
|
1450
|
-
listener(this.find.state);
|
|
1451
|
-
}
|
|
1442
|
+
emit(this.findListeners, this.find.state);
|
|
1452
1443
|
}
|
|
1453
1444
|
revealFind() {
|
|
1454
1445
|
const mark = this.find.currentMark;
|
|
@@ -1837,10 +1828,7 @@ export class EditorView {
|
|
|
1837
1828
|
return this.attribution.linesIn(first, last, this.model.getLine(first).start, this.model.getLine(last).end, (offset) => this.model.positionAt(offset).line);
|
|
1838
1829
|
}
|
|
1839
1830
|
onAttributionHover(listener) {
|
|
1840
|
-
this.attributionListeners
|
|
1841
|
-
return () => {
|
|
1842
|
-
this.attributionListeners.delete(listener);
|
|
1843
|
-
};
|
|
1831
|
+
return subscribe(this.attributionListeners, listener);
|
|
1844
1832
|
}
|
|
1845
1833
|
/* The bar is three pixels wide, so the pointer finds it a few pixels to either side. */
|
|
1846
1834
|
wireAttribution() {
|
|
@@ -1860,9 +1848,7 @@ export class EditorView {
|
|
|
1860
1848
|
return;
|
|
1861
1849
|
}
|
|
1862
1850
|
this.attributionHover = next;
|
|
1863
|
-
|
|
1864
|
-
listener(next);
|
|
1865
|
-
}
|
|
1851
|
+
emit(this.attributionListeners, next);
|
|
1866
1852
|
}
|
|
1867
1853
|
attributionUnder(clientX, clientY) {
|
|
1868
1854
|
if (this.attribution.size === 0) {
|
|
@@ -1973,10 +1959,7 @@ export class EditorView {
|
|
|
1973
1959
|
this.render();
|
|
1974
1960
|
}
|
|
1975
1961
|
onScope(listener) {
|
|
1976
|
-
this.scopeListeners
|
|
1977
|
-
return () => {
|
|
1978
|
-
this.scopeListeners.delete(listener);
|
|
1979
|
-
};
|
|
1962
|
+
return subscribe(this.scopeListeners, listener);
|
|
1980
1963
|
}
|
|
1981
1964
|
announceScope() {
|
|
1982
1965
|
const line = this.model.positionAt(this.model.getPrimary().head).line;
|
|
@@ -1991,9 +1974,7 @@ export class EditorView {
|
|
|
1991
1974
|
return;
|
|
1992
1975
|
}
|
|
1993
1976
|
this.scopeKey = key;
|
|
1994
|
-
|
|
1995
|
-
listener(scope);
|
|
1996
|
-
}
|
|
1977
|
+
emit(this.scopeListeners, scope);
|
|
1997
1978
|
}
|
|
1998
1979
|
stickyLimit() {
|
|
1999
1980
|
return Math.min(STICKY_MAX_LINES, Math.floor(this.viewportHeight / this.layout.metrics.lineHeight / STICKY_ROW_SHARE));
|
|
@@ -2061,10 +2042,7 @@ export class EditorView {
|
|
|
2061
2042
|
this.render();
|
|
2062
2043
|
}
|
|
2063
2044
|
onGutterAction(listener) {
|
|
2064
|
-
this.gutterActionListeners
|
|
2065
|
-
return () => {
|
|
2066
|
-
this.gutterActionListeners.delete(listener);
|
|
2067
|
-
};
|
|
2045
|
+
return subscribe(this.gutterActionListeners, listener);
|
|
2068
2046
|
}
|
|
2069
2047
|
setGutterMarkers(owner, markers) {
|
|
2070
2048
|
const before = this.gutterMarkers.get(owner) ?? [];
|
|
@@ -2081,10 +2059,7 @@ export class EditorView {
|
|
|
2081
2059
|
this.render();
|
|
2082
2060
|
}
|
|
2083
2061
|
onGutterMarker(listener) {
|
|
2084
|
-
this.gutterMarkerListeners
|
|
2085
|
-
return () => {
|
|
2086
|
-
this.gutterMarkerListeners.delete(listener);
|
|
2087
|
-
};
|
|
2062
|
+
return subscribe(this.gutterMarkerListeners, listener);
|
|
2088
2063
|
}
|
|
2089
2064
|
/* The id of the host's gutter marker when the target is it. */
|
|
2090
2065
|
gutterMarkerIdOf(target) {
|
|
@@ -2092,11 +2067,9 @@ export class EditorView {
|
|
|
2092
2067
|
return button?.dataset.gutterMarker ?? null;
|
|
2093
2068
|
}
|
|
2094
2069
|
pressGutterMarker(id) {
|
|
2095
|
-
|
|
2096
|
-
listener(id);
|
|
2097
|
-
}
|
|
2070
|
+
emit(this.gutterMarkerListeners, id);
|
|
2098
2071
|
}
|
|
2099
|
-
/* One marker per line: where two owners mark the same line, the owner
|
|
2072
|
+
/* One marker per line: where two owners mark the same line, the owner that sorts first stays. */
|
|
2100
2073
|
markersByLine() {
|
|
2101
2074
|
const byLine = new Map();
|
|
2102
2075
|
for (const owner of [...this.gutterMarkers.keys()].sort()) {
|
|
@@ -2114,9 +2087,7 @@ export class EditorView {
|
|
|
2114
2087
|
return button ? Number(button.dataset.gutterAction) : null;
|
|
2115
2088
|
}
|
|
2116
2089
|
pressGutterAction(line) {
|
|
2117
|
-
|
|
2118
|
-
listener(line);
|
|
2119
|
-
}
|
|
2090
|
+
emit(this.gutterActionListeners, line);
|
|
2120
2091
|
}
|
|
2121
2092
|
/* Whether a click at this point of the gutter is on a fold control, and which line it folds. */
|
|
2122
2093
|
foldLineOf(target) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adecore/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"test": "bun test --conditions=source"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@adecore/editor-core": "0.
|
|
42
|
+
"@adecore/editor-core": "0.22.0",
|
|
43
43
|
"linkedom": "^0.18.13",
|
|
44
44
|
"shiki": "^4.4.3"
|
|
45
45
|
},
|
package/src/code-block.ts
CHANGED
|
@@ -25,28 +25,7 @@ export function renderCodeBlock(
|
|
|
25
25
|
if (options.color !== undefined) {
|
|
26
26
|
row.style.background = tintValue(options.color);
|
|
27
27
|
}
|
|
28
|
-
const gutter = document
|
|
29
|
-
gutter.className = 'se-code-gutter';
|
|
30
|
-
if (options.firstLine !== undefined) {
|
|
31
|
-
const number = document.createElement('span');
|
|
32
|
-
number.textContent = String(options.firstLine + index);
|
|
33
|
-
gutter.append(number);
|
|
34
|
-
}
|
|
35
|
-
if (options.sign) {
|
|
36
|
-
const sign = document.createElement('span');
|
|
37
|
-
sign.className = 'se-line-sign';
|
|
38
|
-
sign.textContent = options.sign;
|
|
39
|
-
if (options.color !== undefined) {
|
|
40
|
-
sign.style.color = colorValue(options.color);
|
|
41
|
-
}
|
|
42
|
-
gutter.append(sign);
|
|
43
|
-
}
|
|
44
|
-
if (options.color !== undefined) {
|
|
45
|
-
const bar = document.createElement('span');
|
|
46
|
-
bar.className = 'se-attribution';
|
|
47
|
-
bar.style.background = colorValue(options.color);
|
|
48
|
-
gutter.append(bar);
|
|
49
|
-
}
|
|
28
|
+
const gutter = codeGutter(document, options, index);
|
|
50
29
|
const code = document.createElement('div');
|
|
51
30
|
code.className = 'se-code-text';
|
|
52
31
|
if (options.faded) {
|
|
@@ -63,6 +42,32 @@ export function renderCodeBlock(
|
|
|
63
42
|
container.append(block);
|
|
64
43
|
}
|
|
65
44
|
|
|
45
|
+
function codeGutter(document: Document, options: EditorCodeBlockOptions, index: number): HTMLElement {
|
|
46
|
+
const gutter = document.createElement('div');
|
|
47
|
+
gutter.className = 'se-code-gutter';
|
|
48
|
+
if (options.firstLine !== undefined) {
|
|
49
|
+
const number = document.createElement('span');
|
|
50
|
+
number.textContent = String(options.firstLine + index);
|
|
51
|
+
gutter.append(number);
|
|
52
|
+
}
|
|
53
|
+
if (options.sign) {
|
|
54
|
+
const sign = document.createElement('span');
|
|
55
|
+
sign.className = 'se-line-sign';
|
|
56
|
+
sign.textContent = options.sign;
|
|
57
|
+
if (options.color !== undefined) {
|
|
58
|
+
sign.style.color = colorValue(options.color);
|
|
59
|
+
}
|
|
60
|
+
gutter.append(sign);
|
|
61
|
+
}
|
|
62
|
+
if (options.color !== undefined) {
|
|
63
|
+
const bar = document.createElement('span');
|
|
64
|
+
bar.className = 'se-attribution';
|
|
65
|
+
bar.style.background = colorValue(options.color);
|
|
66
|
+
gutter.append(bar);
|
|
67
|
+
}
|
|
68
|
+
return gutter;
|
|
69
|
+
}
|
|
70
|
+
|
|
66
71
|
function fill(element: HTMLElement, line: string, tokens: readonly LineToken[] | null, emphasis: ReadonlyArray<readonly [number, number]>): void {
|
|
67
72
|
if (tokens === null && emphasis.length === 0) {
|
|
68
73
|
element.textContent = line;
|