@adecore/editor 0.41.1 → 0.42.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/controller.d.ts +4 -0
- package/dist/controller.js +30 -3
- package/dist/editor.css +6 -0
- package/dist/engine.js +52 -2
- package/dist/fake.d.ts +13 -1
- package/dist/fake.js +35 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/keymap-table.d.ts +9 -1
- package/dist/keymap-table.js +10 -0
- package/dist/keymap.js +9 -1
- package/dist/overview.d.ts +1 -1
- package/dist/todos.d.ts +23 -0
- package/dist/todos.js +86 -0
- package/dist/types.d.ts +17 -2
- package/dist/view.d.ts +6 -0
- package/dist/view.js +40 -4
- package/dist/zoom.d.ts +18 -0
- package/dist/zoom.js +41 -0
- package/package.json +2 -2
- package/src/controller.ts +43 -5
- package/src/editor.css +6 -0
- package/src/engine.ts +66 -2
- package/src/fake.ts +47 -0
- package/src/index.ts +4 -0
- package/src/keymap-table.ts +20 -1
- package/src/keymap.ts +9 -1
- package/src/overview.ts +1 -1
- package/src/todos.ts +111 -0
- package/src/types.ts +40 -3
- package/src/view.ts +48 -4
- package/src/zoom.ts +62 -0
package/dist/controller.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface ControllerOptions {
|
|
|
7
7
|
apple: boolean;
|
|
8
8
|
save(): void;
|
|
9
9
|
blur(): void;
|
|
10
|
+
zoom(step: -1 | 0 | 1): void;
|
|
11
|
+
wheelZooms(): boolean;
|
|
10
12
|
}
|
|
11
13
|
export declare class InputController {
|
|
12
14
|
private readonly native;
|
|
@@ -25,6 +27,7 @@ export declare class InputController {
|
|
|
25
27
|
private selectionRanges;
|
|
26
28
|
private expansions;
|
|
27
29
|
private lastInputAt;
|
|
30
|
+
private readonly wheelZoom;
|
|
28
31
|
private desiredXs;
|
|
29
32
|
private keepDesiredXs;
|
|
30
33
|
private readonly view;
|
|
@@ -41,6 +44,7 @@ export declare class InputController {
|
|
|
41
44
|
private paste;
|
|
42
45
|
private commandOptions;
|
|
43
46
|
private viewCommand;
|
|
47
|
+
private wheel;
|
|
44
48
|
command(name: EditorRunCommand): boolean;
|
|
45
49
|
setSelectionRanges(provider: EditorSelectionRanges | null): void;
|
|
46
50
|
private expandThrough;
|
package/dist/controller.js
CHANGED
|
@@ -6,6 +6,7 @@ import { NativeInput } from './native-input.js';
|
|
|
6
6
|
import { columnSelections, sameCell } from './column-selection.js';
|
|
7
7
|
import { PointerSelection } from './pointer.js';
|
|
8
8
|
import { TouchSelection } from './touch.js';
|
|
9
|
+
import { WheelZoom } from './zoom.js';
|
|
9
10
|
const MODIFYING = new Set([
|
|
10
11
|
'deleteWordLeft',
|
|
11
12
|
'deleteWordRight',
|
|
@@ -28,7 +29,12 @@ const MODIFYING = new Set([
|
|
|
28
29
|
'outdent',
|
|
29
30
|
'insertNewline',
|
|
30
31
|
'smartBackspace',
|
|
31
|
-
'deleteForward'
|
|
32
|
+
'deleteForward',
|
|
33
|
+
'sortLines',
|
|
34
|
+
'reverseLines',
|
|
35
|
+
'uniqueLines',
|
|
36
|
+
'convertIndentsToSpaces',
|
|
37
|
+
'convertIndentsToTabs'
|
|
32
38
|
]);
|
|
33
39
|
const VIEW_COMMANDS = new Set([
|
|
34
40
|
'collapseRegion',
|
|
@@ -45,8 +51,12 @@ const VIEW_COMMANDS = new Set([
|
|
|
45
51
|
'expandAllToLevel3',
|
|
46
52
|
'expandAllToLevel4',
|
|
47
53
|
'expandAllToLevel5',
|
|
48
|
-
'toggleColumnMode'
|
|
54
|
+
'toggleColumnMode',
|
|
55
|
+
'increaseFontSize',
|
|
56
|
+
'decreaseFontSize',
|
|
57
|
+
'resetFontSize'
|
|
49
58
|
]);
|
|
59
|
+
const ZOOM_STEPS = { increaseFontSize: 1, decreaseFontSize: -1, resetFontSize: 0 };
|
|
50
60
|
/* The clipboard text of the last copy or cut of a bare caret, which pastes back as whole lines. Shared, since it can be pasted in another editor. */
|
|
51
61
|
let lineClip = null;
|
|
52
62
|
function selectionSignature(selections) {
|
|
@@ -79,6 +89,7 @@ export class InputController {
|
|
|
79
89
|
/* The Extend Selection presses that wait for a server's ranges, which are answered one after the other. */
|
|
80
90
|
expansions = Promise.resolve();
|
|
81
91
|
lastInputAt = 0;
|
|
92
|
+
wheelZoom = new WheelZoom();
|
|
82
93
|
desiredXs = [];
|
|
83
94
|
keepDesiredXs = false;
|
|
84
95
|
view;
|
|
@@ -180,7 +191,7 @@ export class InputController {
|
|
|
180
191
|
this.listen(input, 'copy', (event) => this.copy(event, false));
|
|
181
192
|
this.listen(input, 'cut', (event) => this.copy(event, true));
|
|
182
193
|
this.listen(viewport, 'scroll', () => this.view.scrolled());
|
|
183
|
-
this.listen(viewport, 'wheel', () => this.
|
|
194
|
+
this.listen(viewport, 'wheel', (event) => this.wheel(event));
|
|
184
195
|
this.listen(viewport, 'pointermove', (event) => this.view.hoverMoved(event));
|
|
185
196
|
this.listen(viewport, 'pointerleave', () => {
|
|
186
197
|
this.view.setHover(null);
|
|
@@ -300,6 +311,10 @@ export class InputController {
|
|
|
300
311
|
/* Folding is the view's, since it knows where the ranges are. */
|
|
301
312
|
viewCommand(name) {
|
|
302
313
|
const { view } = this;
|
|
314
|
+
if (name in ZOOM_STEPS) {
|
|
315
|
+
this.options.zoom(ZOOM_STEPS[name]);
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
303
318
|
if (view.settings.folding === false && name !== 'toggleColumnMode') {
|
|
304
319
|
return false;
|
|
305
320
|
}
|
|
@@ -323,6 +338,18 @@ export class InputController {
|
|
|
323
338
|
run[name]();
|
|
324
339
|
return true;
|
|
325
340
|
}
|
|
341
|
+
/* A pinch comes as the wheel with Ctrl, on every platform. */
|
|
342
|
+
wheel(event) {
|
|
343
|
+
this.view.cancelScroll();
|
|
344
|
+
if (!(event.ctrlKey || (this.options.apple && event.metaKey)) || !this.options.wheelZooms()) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
event.preventDefault();
|
|
348
|
+
const step = this.wheelZoom.step(event);
|
|
349
|
+
if (step !== 0) {
|
|
350
|
+
this.options.zoom(step);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
326
353
|
/* Runs a model command on every caret, with the folds that would hide its result opened first. */
|
|
327
354
|
command(name) {
|
|
328
355
|
if (VIEW_COMMANDS.has(name)) {
|
package/dist/editor.css
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
--editor-added: var(--status-idle);
|
|
18
18
|
--editor-modified: var(--accent);
|
|
19
19
|
--editor-deleted: var(--status-error);
|
|
20
|
+
--editor-todo: var(--status-running);
|
|
20
21
|
--editor-mark-number-mix: 72%;
|
|
21
22
|
--editor-mark-bar-width: 3px;
|
|
22
23
|
--editor-mark-gap: 4px;
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
--editor-margin: color-mix(in srgb, var(--text) 16%, transparent);
|
|
39
40
|
--editor-whitespace: color-mix(in srgb, var(--text) 32%, transparent);
|
|
40
41
|
--editor-hatch: color-mix(in srgb, var(--text) 10%, transparent);
|
|
42
|
+
--editor-todo: var(--status-idle);
|
|
41
43
|
--editor-mark-number-mix: 82%;
|
|
42
44
|
--editor-sticky-shadow: color-mix(in srgb, black 60%, transparent);
|
|
43
45
|
}
|
|
@@ -478,11 +480,15 @@
|
|
|
478
480
|
left: 6px;
|
|
479
481
|
background: var(--editor-occurrence);
|
|
480
482
|
}
|
|
483
|
+
.se-tick-todo,
|
|
481
484
|
.se-tick-error,
|
|
482
485
|
.se-tick-warning,
|
|
483
486
|
.se-tick-info {
|
|
484
487
|
left: 10px;
|
|
485
488
|
}
|
|
489
|
+
.se-tick-todo {
|
|
490
|
+
background: var(--editor-todo);
|
|
491
|
+
}
|
|
486
492
|
/* The only part of the track that takes the pointer, with a wider reach than the 4px it draws. */
|
|
487
493
|
.se-tick[data-offset] {
|
|
488
494
|
pointer-events: auto;
|
package/dist/engine.js
CHANGED
|
@@ -6,6 +6,7 @@ import { resolveSmartKeys } from './smart-keys.js';
|
|
|
6
6
|
import { emit, subscribe } from './listeners.js';
|
|
7
7
|
import { fillLens, lensSignature } from './lens.js';
|
|
8
8
|
import { EditorView } from './view.js';
|
|
9
|
+
import { clampFontSize, fontSizeRange } from './zoom.js';
|
|
9
10
|
const DEFAULT_TAB_SIZE = 4;
|
|
10
11
|
const DEFAULT_LABEL = 'Code editor';
|
|
11
12
|
const DEFAULT_WIDGET_OWNER = 'default';
|
|
@@ -23,6 +24,9 @@ class SmartEditor {
|
|
|
23
24
|
caretOffset = 0;
|
|
24
25
|
saves = new Set();
|
|
25
26
|
blurs = new Set();
|
|
27
|
+
fontSizes = new Set();
|
|
28
|
+
fontSizeRange;
|
|
29
|
+
fontSize = null;
|
|
26
30
|
subscription;
|
|
27
31
|
language;
|
|
28
32
|
theme;
|
|
@@ -35,6 +39,7 @@ class SmartEditor {
|
|
|
35
39
|
engine;
|
|
36
40
|
constructor(engine, element, options) {
|
|
37
41
|
this.engine = engine;
|
|
42
|
+
this.fontSizeRange = fontSizeRange(options.zoom);
|
|
38
43
|
this.model = new DocumentModel(options.text);
|
|
39
44
|
this.language = options.language;
|
|
40
45
|
this.theme = options.theme;
|
|
@@ -54,7 +59,8 @@ class SmartEditor {
|
|
|
54
59
|
whitespace: options.whitespace === true,
|
|
55
60
|
rightMargin: options.rightMargin ?? null,
|
|
56
61
|
foldOutline: options.foldOutline ?? 'hover',
|
|
57
|
-
folding: options.folding !== false
|
|
62
|
+
folding: options.folding !== false,
|
|
63
|
+
todoWords: options.todoWords
|
|
58
64
|
};
|
|
59
65
|
this.view = new EditorView(element, this.model, this.settings);
|
|
60
66
|
this.grammarPreparation = new GrammarPreparation(this.model, () => this.view.grammarChanged());
|
|
@@ -63,8 +69,13 @@ class SmartEditor {
|
|
|
63
69
|
keymap: engine.keymap,
|
|
64
70
|
apple: engine.apple ?? false,
|
|
65
71
|
save: () => emit(this.saves),
|
|
66
|
-
blur: () => emit(this.blurs)
|
|
72
|
+
blur: () => emit(this.blurs),
|
|
73
|
+
zoom: (step) => this.zoom(step),
|
|
74
|
+
wheelZooms: () => options.zoom?.wheel !== false
|
|
67
75
|
});
|
|
76
|
+
if (options.fontSize !== undefined) {
|
|
77
|
+
this.setFontSize(options.fontSize);
|
|
78
|
+
}
|
|
68
79
|
this.revision = this.model.getRevision();
|
|
69
80
|
this.caretOffset = this.model.getPrimary().head;
|
|
70
81
|
this.subscription = this.model.subscribe((snapshot) => {
|
|
@@ -273,6 +284,14 @@ class SmartEditor {
|
|
|
273
284
|
return false;
|
|
274
285
|
}
|
|
275
286
|
}
|
|
287
|
+
cleanUpWhitespace(options) {
|
|
288
|
+
const changed = !this.settings.readOnly && this.model.cleanUpWhitespace({ ...options, language: this.settings.language });
|
|
289
|
+
this.model.markSaved();
|
|
290
|
+
return changed;
|
|
291
|
+
}
|
|
292
|
+
markSaved() {
|
|
293
|
+
this.model.markSaved();
|
|
294
|
+
}
|
|
276
295
|
setMarkers(markers) {
|
|
277
296
|
this.view.setMarkers(markers.map((marker) => ({
|
|
278
297
|
severity: marker.severity,
|
|
@@ -655,6 +674,10 @@ class SmartEditor {
|
|
|
655
674
|
this.settings.label = label;
|
|
656
675
|
this.view.applySettings();
|
|
657
676
|
}
|
|
677
|
+
setTodoWords(words) {
|
|
678
|
+
this.settings.todoWords = [...words];
|
|
679
|
+
this.view.applySettings();
|
|
680
|
+
}
|
|
658
681
|
setFoldHints(hints) {
|
|
659
682
|
this.view.setFoldHints(hints === null ? null : this.foldHintsByOffset(hints));
|
|
660
683
|
}
|
|
@@ -700,6 +723,32 @@ class SmartEditor {
|
|
|
700
723
|
refreshFont() {
|
|
701
724
|
this.view.refreshFont();
|
|
702
725
|
}
|
|
726
|
+
setFontSize(size) {
|
|
727
|
+
const next = size === null || !Number.isFinite(size) ? null : clampFontSize(size, this.fontSizeRange);
|
|
728
|
+
if (next !== this.fontSize) {
|
|
729
|
+
this.fontSize = next;
|
|
730
|
+
this.view.setFontSize(next);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
getFontSize() {
|
|
734
|
+
return this.view.getFontSize();
|
|
735
|
+
}
|
|
736
|
+
onFontSizeChange(listener) {
|
|
737
|
+
return subscribe(this.fontSizes, listener);
|
|
738
|
+
}
|
|
739
|
+
/* Steps from the size on screen, so the first step from the page's size is one pixel away from it. */
|
|
740
|
+
zoom(step) {
|
|
741
|
+
const before = this.fontSize;
|
|
742
|
+
const current = this.view.getFontSize();
|
|
743
|
+
// A page size outside the range must not make a step the other way.
|
|
744
|
+
if (step !== 0 && Math.sign(clampFontSize(current + step, this.fontSizeRange) - current) !== step) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
this.setFontSize(step === 0 ? null : current + step);
|
|
748
|
+
if (this.fontSize !== before) {
|
|
749
|
+
emit(this.fontSizes, this.fontSize);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
703
752
|
setReadOnly(readOnly, reason) {
|
|
704
753
|
this.settings.readOnly = readOnly;
|
|
705
754
|
this.settings.readOnlyReason = reason;
|
|
@@ -728,6 +777,7 @@ class SmartEditor {
|
|
|
728
777
|
this.carets.clear();
|
|
729
778
|
this.saves.clear();
|
|
730
779
|
this.blurs.clear();
|
|
780
|
+
this.fontSizes.clear();
|
|
731
781
|
this.subscription.dispose();
|
|
732
782
|
this.controller.dispose();
|
|
733
783
|
this.view.dispose();
|
package/dist/fake.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Editor, EditorAttributionHover, EditorAttributionMark, EditorBlock, EditorCodeBlockOptions, EditorLineAction, EditorReplacement, EditorLineHighlight, LineToken, EditorChangeMark, EditorCodeVision, EditorClick, EditorClickHandler, EditorContextMenu, EditorContentChange, EditorEngine, EditorFindQuery, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterMarker, EditorHighlight, EditorHover, EditorIndentation, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorInputPopup, EditorMarker, EditorMessages, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorReveal, EditorRect, EditorRunCommand, EditorSelectionRanges, EditorFoldHints, EditorFoldOutline, EditorFolds, EditorSemanticToken, EditorSmartKeys, EditorApplyEditsOptions, EditorTextChange, EditorTrackedRange, EditorTheme, EditorWidget } from './types.ts';
|
|
1
|
+
import type { Editor, EditorAttributionHover, EditorAttributionMark, EditorBlock, EditorCodeBlockOptions, EditorLineAction, EditorReplacement, EditorLineHighlight, LineToken, EditorChangeMark, EditorCodeVision, EditorClick, EditorClickHandler, EditorContextMenu, EditorContentChange, EditorEngine, EditorFindQuery, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterMarker, EditorHighlight, EditorHover, EditorIndentation, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorInputPopup, EditorMarker, EditorMessages, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorReveal, EditorRect, EditorRunCommand, EditorSelectionRanges, EditorFoldHints, EditorFoldOutline, EditorFolds, EditorSemanticToken, EditorSmartKeys, EditorApplyEditsOptions, EditorTextChange, EditorTrackedRange, EditorTheme, EditorWhitespaceCleanup, EditorWidget } from './types.ts';
|
|
2
2
|
import { type Listener } from './listeners.ts';
|
|
3
3
|
export declare class FakeEditor implements Editor {
|
|
4
4
|
readonly element: HTMLElement;
|
|
@@ -139,6 +139,8 @@ export declare class FakeEditor implements Editor {
|
|
|
139
139
|
setFoldOutline(outline: EditorFoldOutline): void;
|
|
140
140
|
label: string;
|
|
141
141
|
setLabel(label: string): void;
|
|
142
|
+
todoWords: readonly string[] | undefined;
|
|
143
|
+
setTodoWords(words: readonly string[]): void;
|
|
142
144
|
setFoldHints(hints: EditorFoldHints | null): void;
|
|
143
145
|
setSmartKeys(keys: Partial<EditorSmartKeys>): void;
|
|
144
146
|
setIndentation(indentation: EditorIndentation): void;
|
|
@@ -224,8 +226,18 @@ export declare class FakeEditor implements Editor {
|
|
|
224
226
|
openContextMenu(menu: EditorContextMenu): void;
|
|
225
227
|
press(event: Pick<KeyboardEvent, 'key'> & Partial<KeyboardEvent>): boolean;
|
|
226
228
|
applyEdits(edits: readonly EditorContentChange[], options?: EditorApplyEditsOptions): boolean;
|
|
229
|
+
readonly cleanups: EditorWhitespaceCleanup[];
|
|
230
|
+
savedMarks: number;
|
|
231
|
+
cleanUpWhitespace(options: EditorWhitespaceCleanup): boolean;
|
|
232
|
+
markSaved(): void;
|
|
227
233
|
setTheme(theme: EditorTheme): void;
|
|
228
234
|
refreshFont(): void;
|
|
235
|
+
fontSize: number | null;
|
|
236
|
+
private readonly fontSizeListeners;
|
|
237
|
+
setFontSize(size: number | null): void;
|
|
238
|
+
getFontSize(): number;
|
|
239
|
+
onFontSizeChange(listener: (size: number | null) => void): () => void;
|
|
240
|
+
zoomTo(size: number | null): void;
|
|
229
241
|
setReadOnly(readOnly: boolean, reason?: string): void;
|
|
230
242
|
isReadOnly(): boolean;
|
|
231
243
|
readonly commands: EditorRunCommand[];
|
package/dist/fake.js
CHANGED
|
@@ -148,6 +148,8 @@ export class FakeEditor {
|
|
|
148
148
|
this.readOnly = options.readOnly ?? false;
|
|
149
149
|
this.readOnlyReason = options.readOnlyReason;
|
|
150
150
|
this.label = options.label ?? 'Code editor';
|
|
151
|
+
this.todoWords = options.todoWords;
|
|
152
|
+
this.fontSize = options.fontSize ?? null;
|
|
151
153
|
this.revealedLine = options.line ?? null;
|
|
152
154
|
this.column = options.column ?? null;
|
|
153
155
|
this.scrollTop = options.scrollTop ?? null;
|
|
@@ -572,6 +574,10 @@ export class FakeEditor {
|
|
|
572
574
|
setLabel(label) {
|
|
573
575
|
this.label = label;
|
|
574
576
|
}
|
|
577
|
+
todoWords;
|
|
578
|
+
setTodoWords(words) {
|
|
579
|
+
this.todoWords = [...words];
|
|
580
|
+
}
|
|
575
581
|
setFoldHints(hints) {
|
|
576
582
|
this.foldHints = hints;
|
|
577
583
|
}
|
|
@@ -810,12 +816,41 @@ export class FakeEditor {
|
|
|
810
816
|
}));
|
|
811
817
|
return this.edit(ordered, 'command', options.mergeUndo === true, place);
|
|
812
818
|
}
|
|
819
|
+
/* The options of every cleanup asked for, in order; the fake changes no text for them. */
|
|
820
|
+
cleanups = [];
|
|
821
|
+
/* How often the text was marked as saved, by a cleanup or on its own. */
|
|
822
|
+
savedMarks = 0;
|
|
823
|
+
cleanUpWhitespace(options) {
|
|
824
|
+
this.cleanups.push({ ...options });
|
|
825
|
+
this.markSaved();
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
markSaved() {
|
|
829
|
+
this.savedMarks += 1;
|
|
830
|
+
}
|
|
813
831
|
setTheme(theme) {
|
|
814
832
|
this.theme = theme;
|
|
815
833
|
}
|
|
816
834
|
refreshFont() {
|
|
817
835
|
this.fontRefreshes += 1;
|
|
818
836
|
}
|
|
837
|
+
/* The size `setFontSize` set, null for the page's. */
|
|
838
|
+
fontSize = null;
|
|
839
|
+
fontSizeListeners = new Set();
|
|
840
|
+
setFontSize(size) {
|
|
841
|
+
this.fontSize = size;
|
|
842
|
+
}
|
|
843
|
+
getFontSize() {
|
|
844
|
+
return this.fontSize ?? 13;
|
|
845
|
+
}
|
|
846
|
+
onFontSizeChange(listener) {
|
|
847
|
+
return subscribe(this.fontSizeListeners, listener);
|
|
848
|
+
}
|
|
849
|
+
/* What a person zooming would do: the new size goes to the listeners. */
|
|
850
|
+
zoomTo(size) {
|
|
851
|
+
this.fontSize = size;
|
|
852
|
+
emit(this.fontSizeListeners, size);
|
|
853
|
+
}
|
|
819
854
|
setReadOnly(readOnly, reason) {
|
|
820
855
|
this.readOnly = readOnly;
|
|
821
856
|
this.readOnlyReason = reason;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { MAX_REPLACEMENT_PAGE, MAX_REPLACEMENT_CHARACTERS } from './search-protocol.ts';
|
|
2
2
|
export { AGENT_COLORS } from './attribution.ts';
|
|
3
3
|
export { findDocComments, MAX_DOC_COMMENTS, type DocComment } from '@adecore/editor-core';
|
|
4
|
+
export { DEFAULT_TODO_WORDS, findTodos, type TodoMatch, type TodoOptions } from '@adecore/editor-core';
|
|
5
|
+
export { detectIndentation, type DetectedIndentation } from '@adecore/editor-core';
|
|
4
6
|
export { createSmartEditorEngine } from './engine.ts';
|
|
5
7
|
export { DEFAULT_SMART_KEYS } from './smart-keys.ts';
|
|
6
8
|
export { shikiScopeColors, shikiTokenizers } from './shiki.ts';
|
|
7
|
-
export type { Editor, EditorAttributionHover, EditorAttributionMark, EditorMarkColor, EditorBlock, EditorChangeKind, EditorChangeMark, EditorCodeVision, EditorCodeVisionEntry, EditorClick, EditorCodeBlockOptions, EditorClickHandler, EditorCommand, EditorContextMenu, EditorEngine, EditorFindQuery, EditorFoldHints, EditorFoldRangeHint, EditorFoldOutline, EditorFoldRange, EditorFoldSymbol, EditorFolds, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterIcon, EditorGutterMarker, EditorReplacement, EditorIndentation, EditorContentChange, EditorHighlight, EditorHighlightKind, EditorHover, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorLineAction, EditorLineHighlight, EditorMarker, EditorInputPopup, EditorMessages, EditorMarkerSeverity, EditorReveal, EditorRect, EditorSmartKeys, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorApplyEditsOptions, EditorTextChange, EditorTrackedRange, EditorRunCommand, EditorSelectionRanges, EditorTheme, EditorViewCommand, EditorWidget, FoldRole, KeyChord, LineToken, LineTokenKind, ScopeColorSource, ScopeColors, ScopeStyle, EditorSemanticToken, LineTokenizer, SmartEditorEngineOptions, TokenizedLine, TokenizerSource } from './types.ts';
|
|
9
|
+
export type { Editor, EditorAttributionHover, EditorAttributionMark, EditorMarkColor, EditorBlock, EditorChangeKind, EditorChangeMark, EditorCodeVision, EditorCodeVisionEntry, EditorClick, EditorCodeBlockOptions, EditorClickHandler, EditorCommand, EditorContextMenu, EditorEngine, EditorFindQuery, EditorFoldHints, EditorFoldRangeHint, EditorFoldOutline, EditorFoldRange, EditorFoldSymbol, EditorFolds, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterIcon, EditorGutterMarker, EditorReplacement, EditorIndentation, EditorContentChange, EditorHighlight, EditorHighlightKind, EditorHover, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorLineAction, EditorLineHighlight, EditorMarker, EditorInputPopup, EditorMessages, EditorMarkerSeverity, EditorReveal, EditorRect, EditorSmartKeys, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorApplyEditsOptions, EditorTextChange, EditorTrackedRange, EditorRunCommand, EditorSelectionRanges, EditorTheme, EditorViewCommand, EditorWhitespaceCleanup, EditorWidget, EditorZoom, FoldRole, KeyChord, LineToken, LineTokenKind, ScopeColorSource, ScopeColors, ScopeStyle, EditorSemanticToken, LineTokenizer, SmartEditorEngineOptions, TokenizedLine, TokenizerSource } from './types.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { MAX_REPLACEMENT_PAGE, MAX_REPLACEMENT_CHARACTERS } from './search-protocol.js';
|
|
2
2
|
export { AGENT_COLORS } from './attribution.js';
|
|
3
3
|
export { findDocComments, MAX_DOC_COMMENTS } from '@adecore/editor-core';
|
|
4
|
+
export { DEFAULT_TODO_WORDS, findTodos } from '@adecore/editor-core';
|
|
5
|
+
export { detectIndentation } from '@adecore/editor-core';
|
|
4
6
|
export { createSmartEditorEngine } from './engine.js';
|
|
5
7
|
export { DEFAULT_SMART_KEYS } from './smart-keys.js';
|
|
6
8
|
export { shikiScopeColors, shikiTokenizers } from './shiki.js';
|
package/dist/keymap-table.d.ts
CHANGED
|
@@ -26,6 +26,11 @@ export declare const KEYMAP: {
|
|
|
26
26
|
readonly splitLine: KeyBinding;
|
|
27
27
|
readonly toggleCase: KeyBinding;
|
|
28
28
|
readonly autoIndentLines: KeyBinding;
|
|
29
|
+
readonly sortLines: KeyBinding;
|
|
30
|
+
readonly reverseLines: KeyBinding;
|
|
31
|
+
readonly uniqueLines: KeyBinding;
|
|
32
|
+
readonly convertIndentsToSpaces: KeyBinding;
|
|
33
|
+
readonly convertIndentsToTabs: KeyBinding;
|
|
29
34
|
readonly expandSelection: KeyBinding;
|
|
30
35
|
readonly shrinkSelection: KeyBinding;
|
|
31
36
|
readonly matchBrace: KeyBinding;
|
|
@@ -64,6 +69,9 @@ export declare const KEYMAP: {
|
|
|
64
69
|
readonly expandAllToLevel3: KeyBinding;
|
|
65
70
|
readonly expandAllToLevel4: KeyBinding;
|
|
66
71
|
readonly expandAllToLevel5: KeyBinding;
|
|
72
|
+
readonly increaseFontSize: KeyBinding;
|
|
73
|
+
readonly decreaseFontSize: KeyBinding;
|
|
74
|
+
readonly resetFontSize: KeyBinding;
|
|
67
75
|
readonly triggerCompletion: KeyBinding;
|
|
68
76
|
readonly parameterInfo: KeyBinding;
|
|
69
77
|
readonly quickInfo: KeyBinding;
|
|
@@ -96,7 +104,7 @@ export declare const KEYMAP: {
|
|
|
96
104
|
readonly replace: KeyBinding;
|
|
97
105
|
};
|
|
98
106
|
export type KeymapId = keyof typeof KEYMAP;
|
|
99
|
-
export type OptionalKeymapId = 'toggleRenderedDocs';
|
|
107
|
+
export type OptionalKeymapId = 'toggleRenderedDocs' | 'increaseFontSize' | 'decreaseFontSize' | 'resetFontSize' | 'sortLines' | 'reverseLines' | 'uniqueLines' | 'convertIndentsToSpaces' | 'convertIndentsToTabs';
|
|
100
108
|
export type Keymap = Readonly<Record<Exclude<KeymapId, OptionalKeymapId>, KeyBinding> & Partial<Record<OptionalKeymapId, KeyBinding>>>;
|
|
101
109
|
export type KeymapOverrides = Partial<Record<KeymapId, Partial<KeyBinding>>>;
|
|
102
110
|
export declare const KEYMAP_IDS: KeymapId[];
|
package/dist/keymap-table.js
CHANGED
|
@@ -23,6 +23,12 @@ export const KEYMAP = {
|
|
|
23
23
|
splitLine: bind('Mod+Enter'),
|
|
24
24
|
toggleCase: bind('Mod+Shift+U'),
|
|
25
25
|
autoIndentLines: bind('Ctrl+Alt+I'),
|
|
26
|
+
// The platform binds no chord to these, so they live in the menu and the palette.
|
|
27
|
+
sortLines: bind(null),
|
|
28
|
+
reverseLines: bind(null),
|
|
29
|
+
uniqueLines: bind(null),
|
|
30
|
+
convertIndentsToSpaces: bind(null),
|
|
31
|
+
convertIndentsToTabs: bind(null),
|
|
26
32
|
expandSelection: bind('Alt+ArrowUp', 'Ctrl+W'),
|
|
27
33
|
shrinkSelection: bind('Alt+ArrowDown'),
|
|
28
34
|
matchBrace: bind('Ctrl+M', 'Ctrl+Shift+M'),
|
|
@@ -63,6 +69,10 @@ export const KEYMAP = {
|
|
|
63
69
|
expandAllToLevel3: bind(null),
|
|
64
70
|
expandAllToLevel4: bind(null),
|
|
65
71
|
expandAllToLevel5: bind(null),
|
|
72
|
+
// The platform binds no chord to these, and the zoom chords of other editors are the fold keys here.
|
|
73
|
+
increaseFontSize: bind(null),
|
|
74
|
+
decreaseFontSize: bind(null),
|
|
75
|
+
resetFontSize: bind(null),
|
|
66
76
|
triggerCompletion: bind('Ctrl+Space'),
|
|
67
77
|
parameterInfo: bind('Mod+P'),
|
|
68
78
|
quickInfo: bind('Ctrl+J', 'Ctrl+Q'),
|
package/dist/keymap.js
CHANGED
|
@@ -24,6 +24,11 @@ const ACTIONS = {
|
|
|
24
24
|
splitLine: command('splitLine'),
|
|
25
25
|
toggleCase: command('toggleCase'),
|
|
26
26
|
autoIndentLines: command('autoIndentLines'),
|
|
27
|
+
sortLines: command('sortLines'),
|
|
28
|
+
reverseLines: command('reverseLines'),
|
|
29
|
+
uniqueLines: command('uniqueLines'),
|
|
30
|
+
convertIndentsToSpaces: command('convertIndentsToSpaces'),
|
|
31
|
+
convertIndentsToTabs: command('convertIndentsToTabs'),
|
|
27
32
|
expandSelection: command('expandSelection'),
|
|
28
33
|
shrinkSelection: command('shrinkSelection'),
|
|
29
34
|
matchBrace: { type: 'bracket' },
|
|
@@ -59,7 +64,10 @@ const ACTIONS = {
|
|
|
59
64
|
expandAllToLevel3: view('expandAllToLevel3'),
|
|
60
65
|
expandAllToLevel4: view('expandAllToLevel4'),
|
|
61
66
|
expandAllToLevel5: view('expandAllToLevel5'),
|
|
62
|
-
toggleColumnMode: view('toggleColumnMode')
|
|
67
|
+
toggleColumnMode: view('toggleColumnMode'),
|
|
68
|
+
increaseFontSize: view('increaseFontSize'),
|
|
69
|
+
decreaseFontSize: view('decreaseFontSize'),
|
|
70
|
+
resetFontSize: view('resetFontSize')
|
|
63
71
|
};
|
|
64
72
|
const PUNCTUATION_CODES = {
|
|
65
73
|
',': 'Comma',
|
package/dist/overview.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type OverviewKind = 'added' | 'modified' | 'deleted' | 'find' | 'find-current' | 'occurrence' | 'info' | 'warning' | 'error';
|
|
1
|
+
export type OverviewKind = 'added' | 'modified' | 'deleted' | 'find' | 'find-current' | 'occurrence' | 'todo' | 'info' | 'warning' | 'error';
|
|
2
2
|
export interface OverviewSpan {
|
|
3
3
|
kind: OverviewKind;
|
|
4
4
|
top: number;
|
package/dist/todos.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type DocumentModel, type TodoMatch } from '@adecore/editor-core';
|
|
2
|
+
import type { LineToken } from './types.ts';
|
|
3
|
+
export type TodoMark = TodoMatch & {
|
|
4
|
+
readonly text: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class TodoMarks {
|
|
7
|
+
private readonly model;
|
|
8
|
+
private readonly changed;
|
|
9
|
+
private words;
|
|
10
|
+
private language;
|
|
11
|
+
private revision;
|
|
12
|
+
private readonly lines;
|
|
13
|
+
private timer;
|
|
14
|
+
private all;
|
|
15
|
+
version: number;
|
|
16
|
+
constructor(model: DocumentModel, changed: () => void);
|
|
17
|
+
get marks(): readonly TodoMark[];
|
|
18
|
+
configure(language: string | undefined, words: readonly string[] | undefined): void;
|
|
19
|
+
styled(line: number, base: readonly LineToken[] | null): readonly LineToken[] | null;
|
|
20
|
+
schedule(): void;
|
|
21
|
+
refresh(): void;
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
package/dist/todos.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { DEFAULT_TODO_WORDS } from '@adecore/editor-core';
|
|
2
|
+
import { overlayTokens } from './semantic.js';
|
|
3
|
+
const TODO_COLOR = 'var(--editor-todo)';
|
|
4
|
+
const ITALIC = 1;
|
|
5
|
+
/* The marks in the scroll track read the whole document, so they wait for a pause in editing as the folds do. */
|
|
6
|
+
const TODO_DELAY_MS = 300;
|
|
7
|
+
const TODO_LIMIT = 2_000_000;
|
|
8
|
+
const CACHED_LINES = 600;
|
|
9
|
+
/*
|
|
10
|
+
* The TODO comments of a view: drawn in their own color over the grammar's on the lines being painted,
|
|
11
|
+
* and listed for the whole document a moment after the last edit, for the ticks in the scroll track.
|
|
12
|
+
*/
|
|
13
|
+
export class TodoMarks {
|
|
14
|
+
model;
|
|
15
|
+
changed;
|
|
16
|
+
words = DEFAULT_TODO_WORDS;
|
|
17
|
+
/* Empty until the first `configure`, which reads the document. */
|
|
18
|
+
language = '';
|
|
19
|
+
revision = -1;
|
|
20
|
+
lines = new Map();
|
|
21
|
+
timer;
|
|
22
|
+
all = [];
|
|
23
|
+
/* Counts every new list, so a painter can tell its ticks are stale. */
|
|
24
|
+
version = 0;
|
|
25
|
+
constructor(model, changed) {
|
|
26
|
+
this.model = model;
|
|
27
|
+
this.changed = changed;
|
|
28
|
+
}
|
|
29
|
+
get marks() {
|
|
30
|
+
return this.all;
|
|
31
|
+
}
|
|
32
|
+
configure(language, words) {
|
|
33
|
+
const nextLanguage = language ?? 'plaintext';
|
|
34
|
+
const nextWords = words ?? DEFAULT_TODO_WORDS;
|
|
35
|
+
if (nextLanguage === this.language && nextWords.join('\n') === this.words.join('\n')) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.language = nextLanguage;
|
|
39
|
+
this.words = nextWords;
|
|
40
|
+
this.revision = -1;
|
|
41
|
+
this.refresh();
|
|
42
|
+
}
|
|
43
|
+
/* The line's tokens with its TODOs drawn over them, the same array for as long as neither changed. */
|
|
44
|
+
styled(line, base) {
|
|
45
|
+
if (this.words.length === 0) {
|
|
46
|
+
return base;
|
|
47
|
+
}
|
|
48
|
+
const revision = this.model.getRevision();
|
|
49
|
+
if (revision !== this.revision || this.lines.size > CACHED_LINES) {
|
|
50
|
+
this.revision = revision;
|
|
51
|
+
this.lines.clear();
|
|
52
|
+
}
|
|
53
|
+
const cached = this.lines.get(line);
|
|
54
|
+
if (cached !== undefined && cached.base === base) {
|
|
55
|
+
return cached.result;
|
|
56
|
+
}
|
|
57
|
+
const matches = this.model.findTodos(this.language, { words: this.words }, line, line);
|
|
58
|
+
let result = base;
|
|
59
|
+
if (matches.length > 0) {
|
|
60
|
+
const { start, end } = this.model.getLine(line);
|
|
61
|
+
const spans = matches.map((match) => ({ from: match.from - start, to: match.to - start, color: TODO_COLOR, fontStyle: ITALIC }));
|
|
62
|
+
result = overlayTokens(base ?? [{ length: end - start, color: '', fontStyle: 0 }], spans);
|
|
63
|
+
}
|
|
64
|
+
this.lines.set(line, { base, result });
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
schedule() {
|
|
68
|
+
clearTimeout(this.timer);
|
|
69
|
+
this.timer = setTimeout(() => this.refresh(), TODO_DELAY_MS);
|
|
70
|
+
}
|
|
71
|
+
/* Reads the TODOs of the whole document now, which otherwise waits for a pause in editing. */
|
|
72
|
+
refresh() {
|
|
73
|
+
clearTimeout(this.timer);
|
|
74
|
+
const found = this.words.length === 0 || this.model.getLength() > TODO_LIMIT ? [] : this.model.findTodos(this.language, { words: this.words });
|
|
75
|
+
const next = found.map((match) => ({ ...match, text: this.model.slice(match.from, match.to) }));
|
|
76
|
+
if (next.length === 0 && this.all.length === 0) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.all = next;
|
|
80
|
+
this.version++;
|
|
81
|
+
this.changed();
|
|
82
|
+
}
|
|
83
|
+
dispose() {
|
|
84
|
+
clearTimeout(this.timer);
|
|
85
|
+
}
|
|
86
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { EditorSearchClientOptions } from './search-client.ts';
|
|
2
2
|
import type { Keymap } from './keymap-table.ts';
|
|
3
|
-
import type { EditorCommand, FoldRole } from '@adecore/editor-core';
|
|
3
|
+
import type { EditorCommand, FoldRole, WhitespaceCleanupOptions } from '@adecore/editor-core';
|
|
4
4
|
export type { EditorCommand, FoldRole };
|
|
5
|
+
export type EditorWhitespaceCleanup = WhitespaceCleanupOptions;
|
|
5
6
|
export type EditorFoldOutline = 'off' | 'hover' | 'always';
|
|
6
|
-
export type EditorViewCommand = 'collapseRegion' | 'expandRegion' | 'collapseAllRegions' | 'expandAllRegions' | 'collapseRegionRecursively' | 'expandRegionRecursively' | 'foldSelection' | 'collapseDocComments' | 'expandDocComments' | 'expandAllToLevel1' | 'expandAllToLevel2' | 'expandAllToLevel3' | 'expandAllToLevel4' | 'expandAllToLevel5' | 'toggleColumnMode';
|
|
7
|
+
export type EditorViewCommand = 'collapseRegion' | 'expandRegion' | 'collapseAllRegions' | 'expandAllRegions' | 'collapseRegionRecursively' | 'expandRegionRecursively' | 'foldSelection' | 'collapseDocComments' | 'expandDocComments' | 'expandAllToLevel1' | 'expandAllToLevel2' | 'expandAllToLevel3' | 'expandAllToLevel4' | 'expandAllToLevel5' | 'toggleColumnMode' | 'increaseFontSize' | 'decreaseFontSize' | 'resetFontSize';
|
|
8
|
+
export interface EditorZoom {
|
|
9
|
+
readonly min?: number;
|
|
10
|
+
readonly max?: number;
|
|
11
|
+
readonly wheel?: boolean;
|
|
12
|
+
}
|
|
7
13
|
export type EditorRunCommand = EditorCommand | EditorViewCommand;
|
|
8
14
|
export interface EditorFoldRange {
|
|
9
15
|
readonly startLine: number;
|
|
@@ -38,6 +44,9 @@ export interface EditorOptions {
|
|
|
38
44
|
readonly line?: number;
|
|
39
45
|
readonly column?: number;
|
|
40
46
|
readonly scrollTop?: number;
|
|
47
|
+
readonly todoWords?: readonly string[];
|
|
48
|
+
readonly fontSize?: number;
|
|
49
|
+
readonly zoom?: EditorZoom;
|
|
41
50
|
}
|
|
42
51
|
export interface EditorMessages {
|
|
43
52
|
readonly noMoreOccurrences: string;
|
|
@@ -324,6 +333,7 @@ export interface Editor {
|
|
|
324
333
|
setWhitespace(whitespace: boolean): void;
|
|
325
334
|
setRightMargin(column: number | null): void;
|
|
326
335
|
setFoldOutline(outline: EditorFoldOutline): void;
|
|
336
|
+
setTodoWords?(words: readonly string[]): void;
|
|
327
337
|
setLabel(label: string): void;
|
|
328
338
|
setFoldHints(hints: EditorFoldHints | null): void;
|
|
329
339
|
setChangeMarks(marks: readonly EditorChangeMark[], layer?: string): void;
|
|
@@ -385,8 +395,13 @@ export interface Editor {
|
|
|
385
395
|
setSelectionRanges(provider: EditorSelectionRanges | null): void;
|
|
386
396
|
trackRange(range: EditorRange): EditorTrackedRange;
|
|
387
397
|
applyEdits(edits: readonly EditorContentChange[], options?: EditorApplyEditsOptions): boolean;
|
|
398
|
+
cleanUpWhitespace?(options: EditorWhitespaceCleanup): boolean;
|
|
399
|
+
markSaved?(): void;
|
|
388
400
|
setTheme(theme: EditorTheme): void;
|
|
389
401
|
refreshFont(): void;
|
|
402
|
+
setFontSize?(size: number | null): void;
|
|
403
|
+
getFontSize?(): number;
|
|
404
|
+
onFontSizeChange?(listener: (size: number | null) => void): () => void;
|
|
390
405
|
setReadOnly(readOnly: boolean, reason?: string): void;
|
|
391
406
|
isReadOnly?(): boolean;
|
|
392
407
|
runCommand(command: EditorRunCommand): boolean;
|
package/dist/view.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface ViewSettings {
|
|
|
22
22
|
foldOutline: 'off' | 'hover' | 'always';
|
|
23
23
|
folding?: boolean;
|
|
24
24
|
stickyScroll?: boolean;
|
|
25
|
+
todoWords?: readonly string[];
|
|
25
26
|
}
|
|
26
27
|
export type ViewFold = Omit<FoldingRange, 'kind'> & {
|
|
27
28
|
kind: FoldingRange['kind'] | 'custom';
|
|
@@ -59,6 +60,7 @@ export declare class EditorView {
|
|
|
59
60
|
readonly layout: EditorLayout;
|
|
60
61
|
readonly find: FindController;
|
|
61
62
|
readonly tokens: TokenCache;
|
|
63
|
+
private readonly todos;
|
|
62
64
|
private readonly content;
|
|
63
65
|
private readonly gutter;
|
|
64
66
|
private readonly gutterLines;
|
|
@@ -125,6 +127,7 @@ export declare class EditorView {
|
|
|
125
127
|
private caretTimer;
|
|
126
128
|
private caretKey;
|
|
127
129
|
private renderedScroll;
|
|
130
|
+
private fontSize;
|
|
128
131
|
private font;
|
|
129
132
|
private layoutVersion;
|
|
130
133
|
private revision;
|
|
@@ -171,6 +174,8 @@ export declare class EditorView {
|
|
|
171
174
|
applySettings(): void;
|
|
172
175
|
repaint(): void;
|
|
173
176
|
refreshFont(): void;
|
|
177
|
+
setFontSize(size: number | null): void;
|
|
178
|
+
getFontSize(): number;
|
|
174
179
|
setTokenizer(tokenizer: LineTokenizer | null): void;
|
|
175
180
|
grammarChanged(): void;
|
|
176
181
|
setLineTokens(tokens: ((line: number) => readonly LineToken[] | null | undefined) | null): void;
|
|
@@ -190,6 +195,7 @@ export declare class EditorView {
|
|
|
190
195
|
setSemanticTokens(tokens: readonly ViewSemanticToken[] | null): void;
|
|
191
196
|
setScopeColors(colors: ScopeColors | null): void;
|
|
192
197
|
private styledTokensOf;
|
|
198
|
+
private semanticTokensOf;
|
|
193
199
|
private semanticSpans;
|
|
194
200
|
setMarkers(markers: readonly ViewMarker[]): void;
|
|
195
201
|
setComposition(text: string | undefined): void;
|