@adecore/editor 0.41.1 → 0.43.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 +13 -2
- package/dist/controller.js +110 -9
- package/dist/editor.css +19 -0
- package/dist/engine.js +82 -5
- package/dist/fake.d.ts +31 -2
- package/dist/fake.js +100 -3
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -0
- package/dist/keymap-table.d.ts +28 -1
- package/dist/keymap-table.js +34 -3
- package/dist/keymap.js +23 -1
- package/dist/layout.d.ts +2 -0
- package/dist/layout.js +6 -1
- package/dist/outline.d.ts +1 -0
- package/dist/outline.js +10 -0
- package/dist/overview.d.ts +1 -1
- package/dist/paint.js +12 -2
- package/dist/todos.d.ts +23 -0
- package/dist/todos.js +86 -0
- package/dist/types.d.ts +34 -3
- package/dist/view.d.ts +17 -0
- package/dist/view.js +113 -12
- package/dist/zoom.d.ts +18 -0
- package/dist/zoom.js +41 -0
- package/package.json +2 -2
- package/src/controller.ts +150 -11
- package/src/editor.css +19 -0
- package/src/engine.ts +103 -5
- package/src/fake.ts +132 -3
- package/src/index.ts +7 -0
- package/src/keymap-table.ts +63 -4
- package/src/keymap.ts +23 -1
- package/src/layout.ts +9 -1
- package/src/outline.ts +13 -0
- package/src/overview.ts +1 -1
- package/src/paint.ts +11 -2
- package/src/todos.ts +111 -0
- package/src/types.ts +76 -4
- package/src/view.ts +143 -13
- package/src/zoom.ts +62 -0
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' | 'methodUp' | 'methodDown' | 'nextChange' | 'previousChange' | 'pasteAsPlainText';
|
|
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;
|
|
@@ -130,6 +139,15 @@ export interface EditorContentChange {
|
|
|
130
139
|
readonly range: EditorRange;
|
|
131
140
|
readonly text: string;
|
|
132
141
|
}
|
|
142
|
+
export interface EditorCopy {
|
|
143
|
+
readonly text: string;
|
|
144
|
+
readonly wholeLines: boolean;
|
|
145
|
+
readonly cut: boolean;
|
|
146
|
+
}
|
|
147
|
+
export interface EditorPasteOptions {
|
|
148
|
+
readonly wholeLines?: boolean;
|
|
149
|
+
readonly reindent?: boolean;
|
|
150
|
+
}
|
|
133
151
|
export interface EditorApplyEditsOptions {
|
|
134
152
|
readonly mapSelections?: (range: EditorRange) => EditorRange;
|
|
135
153
|
readonly mergeUndo?: boolean;
|
|
@@ -231,6 +249,7 @@ export interface EditorInlayHint {
|
|
|
231
249
|
readonly parts?: readonly string[];
|
|
232
250
|
readonly paddingLeft?: boolean;
|
|
233
251
|
readonly paddingRight?: boolean;
|
|
252
|
+
readonly swatch?: string;
|
|
234
253
|
}
|
|
235
254
|
export interface EditorInlayTarget {
|
|
236
255
|
readonly id: string;
|
|
@@ -324,8 +343,15 @@ export interface Editor {
|
|
|
324
343
|
setWhitespace(whitespace: boolean): void;
|
|
325
344
|
setRightMargin(column: number | null): void;
|
|
326
345
|
setFoldOutline(outline: EditorFoldOutline): void;
|
|
346
|
+
setTodoWords?(words: readonly string[]): void;
|
|
327
347
|
setLabel(label: string): void;
|
|
328
348
|
setFoldHints(hints: EditorFoldHints | null): void;
|
|
349
|
+
setDeclarations?(positions: readonly EditorPosition[] | null): void;
|
|
350
|
+
onNavigate?(listener: (from: EditorPosition) => void): () => void;
|
|
351
|
+
hasFocus?(): boolean;
|
|
352
|
+
setWordSources?(source: (() => readonly string[]) | null): void;
|
|
353
|
+
onCopy?(listener: (copy: EditorCopy) => void): () => void;
|
|
354
|
+
paste?(text: string, options?: EditorPasteOptions): boolean;
|
|
329
355
|
setChangeMarks(marks: readonly EditorChangeMark[], layer?: string): void;
|
|
330
356
|
setBlocks(blocks: readonly EditorBlock[] | null): void;
|
|
331
357
|
onScope(listener: (scope: readonly EditorBlock[]) => void): () => void;
|
|
@@ -341,7 +367,7 @@ export interface Editor {
|
|
|
341
367
|
setHighlights(highlights: readonly EditorHighlight[]): void;
|
|
342
368
|
setLink(range: EditorRange | null): void;
|
|
343
369
|
setSemanticTokens(tokens: readonly EditorSemanticToken[] | null): void;
|
|
344
|
-
setInlayHints(hints: readonly EditorInlayHint[]): void;
|
|
370
|
+
setInlayHints(hints: readonly EditorInlayHint[], owner?: string): void;
|
|
345
371
|
onInlayHover?(listener: (target: EditorInlayTarget | null) => void): () => void;
|
|
346
372
|
onInlayClick?(handler: EditorInlayClickHandler): () => void;
|
|
347
373
|
setInlayLink?(target: {
|
|
@@ -385,8 +411,13 @@ export interface Editor {
|
|
|
385
411
|
setSelectionRanges(provider: EditorSelectionRanges | null): void;
|
|
386
412
|
trackRange(range: EditorRange): EditorTrackedRange;
|
|
387
413
|
applyEdits(edits: readonly EditorContentChange[], options?: EditorApplyEditsOptions): boolean;
|
|
414
|
+
cleanUpWhitespace?(options: EditorWhitespaceCleanup): boolean;
|
|
415
|
+
markSaved?(): void;
|
|
388
416
|
setTheme(theme: EditorTheme): void;
|
|
389
417
|
refreshFont(): void;
|
|
418
|
+
setFontSize?(size: number | null): void;
|
|
419
|
+
getFontSize?(): number;
|
|
420
|
+
onFontSizeChange?(listener: (size: number | null) => void): () => void;
|
|
390
421
|
setReadOnly(readOnly: boolean, reason?: string): void;
|
|
391
422
|
isReadOnly?(): boolean;
|
|
392
423
|
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;
|
|
@@ -140,6 +143,7 @@ export declare class EditorView {
|
|
|
140
143
|
private lenses;
|
|
141
144
|
private readonly replacements;
|
|
142
145
|
private occurrences;
|
|
146
|
+
private hippieSource;
|
|
143
147
|
private replacePreview;
|
|
144
148
|
private dropCaret;
|
|
145
149
|
private activeGuideCache;
|
|
@@ -154,6 +158,7 @@ export declare class EditorView {
|
|
|
154
158
|
private customFolds;
|
|
155
159
|
private collapsed;
|
|
156
160
|
private foldHints;
|
|
161
|
+
private declarations;
|
|
157
162
|
private defaultRoles;
|
|
158
163
|
private settled;
|
|
159
164
|
private foldTimer;
|
|
@@ -171,6 +176,8 @@ export declare class EditorView {
|
|
|
171
176
|
applySettings(): void;
|
|
172
177
|
repaint(): void;
|
|
173
178
|
refreshFont(): void;
|
|
179
|
+
setFontSize(size: number | null): void;
|
|
180
|
+
getFontSize(): number;
|
|
174
181
|
setTokenizer(tokenizer: LineTokenizer | null): void;
|
|
175
182
|
grammarChanged(): void;
|
|
176
183
|
setLineTokens(tokens: ((line: number) => readonly LineToken[] | null | undefined) | null): void;
|
|
@@ -183,6 +190,10 @@ export declare class EditorView {
|
|
|
183
190
|
setLenses(lenses: readonly BlockWidget[]): void;
|
|
184
191
|
private allBlocks;
|
|
185
192
|
setOccurrences(occurrences: readonly Occurrence[]): void;
|
|
193
|
+
setHippieSource(range: {
|
|
194
|
+
from: number;
|
|
195
|
+
to: number;
|
|
196
|
+
} | null): void;
|
|
186
197
|
setLink(link: {
|
|
187
198
|
from: number;
|
|
188
199
|
to: number;
|
|
@@ -190,6 +201,7 @@ export declare class EditorView {
|
|
|
190
201
|
setSemanticTokens(tokens: readonly ViewSemanticToken[] | null): void;
|
|
191
202
|
setScopeColors(colors: ScopeColors | null): void;
|
|
192
203
|
private styledTokensOf;
|
|
204
|
+
private semanticTokensOf;
|
|
193
205
|
private semanticSpans;
|
|
194
206
|
setMarkers(markers: readonly ViewMarker[]): void;
|
|
195
207
|
setComposition(text: string | undefined): void;
|
|
@@ -233,6 +245,7 @@ export declare class EditorView {
|
|
|
233
245
|
private foldStates;
|
|
234
246
|
private scheduleFolds;
|
|
235
247
|
refreshFolds(): void;
|
|
248
|
+
structureRanges(): FoldingRange[];
|
|
236
249
|
private withCustomFolds;
|
|
237
250
|
private closerOf;
|
|
238
251
|
private foldAt;
|
|
@@ -268,6 +281,10 @@ export declare class EditorView {
|
|
|
268
281
|
endLine: number;
|
|
269
282
|
}[];
|
|
270
283
|
} | null, defaults?: readonly FoldRole[]): void;
|
|
284
|
+
setDeclarations(offsets: readonly number[] | null): void;
|
|
285
|
+
private methodStops;
|
|
286
|
+
goToChange(direction: -1 | 1): boolean;
|
|
287
|
+
goToMethod(direction: -1 | 1): boolean;
|
|
271
288
|
setFoldHints(hints: FoldHints | null): void;
|
|
272
289
|
private applyFoldDefaults;
|
|
273
290
|
foldRole(role: FoldRole, collapse: boolean): void;
|
package/dist/view.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createSearchClient } from './search-client.js';
|
|
|
5
5
|
import { FindController } from './find.js';
|
|
6
6
|
import { EditorLayout, RIGHT_PADDING, subRowBand } from './layout.js';
|
|
7
7
|
import { createMetrics, readEditorFont } from './metrics.js';
|
|
8
|
+
import { zoomedFont } from './zoom.js';
|
|
8
9
|
import { AttributionRuns, colorValue, tintValue } from './attribution.js';
|
|
9
10
|
import { renderCodeBlock } from './code-block.js';
|
|
10
11
|
import { emit, subscribe } from './listeners.js';
|
|
@@ -16,6 +17,7 @@ import { Outline, scopeChain, stickyCover, stickyPlacements, structuralEntries }
|
|
|
16
17
|
import { overviewTicks, paintOverview } from './overview.js';
|
|
17
18
|
import { paintCarets, paintGutter, paintOver, paintOverlays, paintRemoteCarets, paintSigns, paintSticky, RowPainter } from './paint.js';
|
|
18
19
|
import { overlayTokens } from './semantic.js';
|
|
20
|
+
import { TodoMarks } from './todos.js';
|
|
19
21
|
import { TokenCache } from './tokens.js';
|
|
20
22
|
function sameRect(left, right) {
|
|
21
23
|
return left.left === right.left && left.top === right.top && left.right === right.right && left.bottom === right.bottom;
|
|
@@ -79,6 +81,7 @@ export class EditorView {
|
|
|
79
81
|
layout;
|
|
80
82
|
find;
|
|
81
83
|
tokens;
|
|
84
|
+
todos;
|
|
82
85
|
content;
|
|
83
86
|
gutter;
|
|
84
87
|
gutterLines;
|
|
@@ -147,6 +150,8 @@ export class EditorView {
|
|
|
147
150
|
caretTimer;
|
|
148
151
|
caretKey = '';
|
|
149
152
|
renderedScroll = { top: -1, left: -1 };
|
|
153
|
+
/* A size the code is zoomed to, over the page's; null draws it at the page's. */
|
|
154
|
+
fontSize = null;
|
|
150
155
|
font;
|
|
151
156
|
layoutVersion = 0;
|
|
152
157
|
revision;
|
|
@@ -163,6 +168,7 @@ export class EditorView {
|
|
|
163
168
|
lenses = [];
|
|
164
169
|
replacements = new Map();
|
|
165
170
|
occurrences = [];
|
|
171
|
+
hippieSource = null;
|
|
166
172
|
replacePreview = null;
|
|
167
173
|
dropCaret = null;
|
|
168
174
|
activeGuideCache;
|
|
@@ -181,6 +187,7 @@ export class EditorView {
|
|
|
181
187
|
collapsed = new Set();
|
|
182
188
|
/* What a language server said about the folds, in offsets that follow the text through edits. */
|
|
183
189
|
foldHints = null;
|
|
190
|
+
declarations = null;
|
|
184
191
|
/* The roles that fold by themselves while the file is as it was opened; null once a person edited or the file opened with folds of its own. */
|
|
185
192
|
defaultRoles = null;
|
|
186
193
|
/* The folds somebody already decided on, a person or the defaults, so a later answer of a server leaves them as they are. */
|
|
@@ -281,6 +288,7 @@ export class EditorView {
|
|
|
281
288
|
}
|
|
282
289
|
});
|
|
283
290
|
this.tokens = new TokenCache({ getLineCount: () => model.getLineCount(), getLineText: (line) => model.getLine(line).text });
|
|
291
|
+
this.todos = new TodoMarks(model, () => this.requestRender());
|
|
284
292
|
const ResizeObserverClass = document.defaultView?.ResizeObserver;
|
|
285
293
|
this.blockObserver = ResizeObserverClass
|
|
286
294
|
? new ResizeObserverClass((entries) => {
|
|
@@ -311,6 +319,7 @@ export class EditorView {
|
|
|
311
319
|
this.root.dataset.readonly = String(this.settings.readOnly);
|
|
312
320
|
this.root.dataset.wrap = String(this.settings.wrap);
|
|
313
321
|
this.root.dataset.foldOutline = this.settings.foldOutline;
|
|
322
|
+
this.todos.configure(this.settings.language, this.settings.todoWords);
|
|
314
323
|
this.layoutVersion++;
|
|
315
324
|
this.layout.configure({ metrics: createMetrics(this.font, this.settings.tabSize, this.document) });
|
|
316
325
|
this.render();
|
|
@@ -320,8 +329,26 @@ export class EditorView {
|
|
|
320
329
|
this.render();
|
|
321
330
|
}
|
|
322
331
|
refreshFont() {
|
|
323
|
-
|
|
324
|
-
|
|
332
|
+
const style = this.root.style;
|
|
333
|
+
style.removeProperty('--code-font-size');
|
|
334
|
+
style.removeProperty('--code-line-height');
|
|
335
|
+
const base = readEditorFont(this.root);
|
|
336
|
+
this.font = this.fontSize === null ? base : zoomedFont(base, this.fontSize);
|
|
337
|
+
// On the element itself, so everything the editor draws at the code's size follows, and the page's size stays the base.
|
|
338
|
+
if (this.fontSize !== null) {
|
|
339
|
+
style.setProperty('--code-font-size', `${this.font.size}px`);
|
|
340
|
+
style.setProperty('--code-line-height', `${this.font.lineHeight}px`);
|
|
341
|
+
}
|
|
342
|
+
this.anchorScroll(() => this.applySettings());
|
|
343
|
+
}
|
|
344
|
+
/* Draws the code at a size of its own in whole pixels; null goes back to the page's. */
|
|
345
|
+
setFontSize(size) {
|
|
346
|
+
this.fontSize = size;
|
|
347
|
+
this.refreshFont();
|
|
348
|
+
}
|
|
349
|
+
/* The size the code is drawn at, in pixels. */
|
|
350
|
+
getFontSize() {
|
|
351
|
+
return this.font.size;
|
|
325
352
|
}
|
|
326
353
|
setTokenizer(tokenizer) {
|
|
327
354
|
this.tokens.setTokenizer(tokenizer);
|
|
@@ -402,6 +429,14 @@ export class EditorView {
|
|
|
402
429
|
this.occurrences = [...occurrences];
|
|
403
430
|
this.render();
|
|
404
431
|
}
|
|
432
|
+
/* The word Hippie completion took from this document, shown until the next key or edit; null takes the mark away. */
|
|
433
|
+
setHippieSource(range) {
|
|
434
|
+
if (range === null && this.hippieSource === null) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
this.hippieSource = range;
|
|
438
|
+
this.render();
|
|
439
|
+
}
|
|
405
440
|
/* A name underlined as a link a press follows, with the pointer to match; null takes it away. */
|
|
406
441
|
setLink(link) {
|
|
407
442
|
this.link = link;
|
|
@@ -421,8 +456,12 @@ export class EditorView {
|
|
|
421
456
|
this.semanticLines.clear();
|
|
422
457
|
this.render();
|
|
423
458
|
}
|
|
424
|
-
/* The
|
|
459
|
+
/* The colors of a line with its TODOs drawn over them, the same object for as long as nothing under them changed. */
|
|
425
460
|
styledTokensOf(line) {
|
|
461
|
+
return this.todos.styled(line, this.semanticTokensOf(line));
|
|
462
|
+
}
|
|
463
|
+
/* The grammar's colors of a line with the servers' laid over them, the same object for as long as neither changed. */
|
|
464
|
+
semanticTokensOf(line) {
|
|
426
465
|
const base = this.lineTokenProvider === null ? this.tokens.tokensOf(line) : (this.lineTokenProvider(line) ?? null);
|
|
427
466
|
if (base === null || this.semantic.length === 0 || this.scopeColors === null) {
|
|
428
467
|
return base;
|
|
@@ -592,6 +631,7 @@ export class EditorView {
|
|
|
592
631
|
this.markerVersion++;
|
|
593
632
|
const anchor = this.topAnchor;
|
|
594
633
|
this.occurrences = [];
|
|
634
|
+
this.hippieSource = null;
|
|
595
635
|
this.link = null;
|
|
596
636
|
this.content.classList.remove('se-content-link');
|
|
597
637
|
this.outline.edited(batches);
|
|
@@ -615,6 +655,7 @@ export class EditorView {
|
|
|
615
655
|
this.find.refresh();
|
|
616
656
|
this.announceFind();
|
|
617
657
|
this.scheduleFolds();
|
|
658
|
+
this.todos.schedule();
|
|
618
659
|
this.colorAhead(true);
|
|
619
660
|
}
|
|
620
661
|
if (this.rowEndCaret !== null && this.model.getPrimary().head !== this.rowEndCaret) {
|
|
@@ -638,6 +679,9 @@ export class EditorView {
|
|
|
638
679
|
if (this.foldHints !== null) {
|
|
639
680
|
this.foldHints = mapFoldHints(this.foldHints, map);
|
|
640
681
|
}
|
|
682
|
+
if (this.declarations !== null) {
|
|
683
|
+
this.declarations = this.declarations.map((offset) => map(offset));
|
|
684
|
+
}
|
|
641
685
|
this.customFolds = this.customFolds.map((fold) => mapRange(fold, map));
|
|
642
686
|
this.find.mapBounds(changes);
|
|
643
687
|
for (const [layer, marks] of this.changeLayers) {
|
|
@@ -771,20 +815,25 @@ export class EditorView {
|
|
|
771
815
|
if (this.disposed || this.settings.folding === false) {
|
|
772
816
|
return;
|
|
773
817
|
}
|
|
774
|
-
const ranges = this.
|
|
775
|
-
? []
|
|
776
|
-
: this.model.getFoldingRanges({
|
|
777
|
-
indentation: /^(python|py|yaml|yml)$/.test(this.settings.language ?? ''),
|
|
778
|
-
tabSize: this.settings.tabSize,
|
|
779
|
-
...(this.settings.language === undefined ? {} : { language: this.settings.language }),
|
|
780
|
-
...(this.foldHints === null ? {} : { hints: this.foldHints })
|
|
781
|
-
});
|
|
818
|
+
const ranges = this.structureRanges();
|
|
782
819
|
this.foldRanges = this.withCustomFolds(ranges);
|
|
783
820
|
this.outline.setStructure(structuralEntries(ranges, this.model, (from, to) => this.model.slice(from, to), (offset) => this.model.matchBracket(offset, this.settings.language)?.mate));
|
|
784
821
|
const anchors = new Set(this.foldRanges.map((range) => range.from));
|
|
785
822
|
this.collapsed = new Set([...this.collapsed].filter((anchor) => anchors.has(anchor)));
|
|
786
823
|
this.refoldLayout();
|
|
787
824
|
}
|
|
825
|
+
/* The folding ranges the document has now, a server's included, whether or not the folds are drawn. */
|
|
826
|
+
structureRanges() {
|
|
827
|
+
if (this.model.getLength() > FOLD_LIMIT) {
|
|
828
|
+
return [];
|
|
829
|
+
}
|
|
830
|
+
return this.model.getFoldingRanges({
|
|
831
|
+
indentation: /^(python|py|yaml|yml)$/.test(this.settings.language ?? ''),
|
|
832
|
+
tabSize: this.settings.tabSize,
|
|
833
|
+
...(this.settings.language === undefined ? {} : { language: this.settings.language }),
|
|
834
|
+
...(this.foldHints === null ? {} : { hints: this.foldHints })
|
|
835
|
+
});
|
|
836
|
+
}
|
|
788
837
|
/* The folds a person made of a selection, which the document's own structure does not know, among the ones it does. */
|
|
789
838
|
withCustomFolds(ranges) {
|
|
790
839
|
const custom = this.customFolds.flatMap((fold) => {
|
|
@@ -993,6 +1042,49 @@ export class EditorView {
|
|
|
993
1042
|
this.applyFoldDefaults();
|
|
994
1043
|
this.refoldLayout();
|
|
995
1044
|
}
|
|
1045
|
+
/* The places Method Up and Down stop at; they follow their text through edits until set again, and null goes back to the editor's own reading. */
|
|
1046
|
+
setDeclarations(offsets) {
|
|
1047
|
+
this.declarations = offsets === null ? null : [...new Set(offsets)].sort((left, right) => left - right);
|
|
1048
|
+
}
|
|
1049
|
+
methodStops() {
|
|
1050
|
+
if (this.declarations !== null) {
|
|
1051
|
+
return this.declarations;
|
|
1052
|
+
}
|
|
1053
|
+
const sections = this.foldRanges.filter((range) => range.kind === 'section').map((range) => this.model.getLine(range.startLine).start);
|
|
1054
|
+
return [...new Set([...this.outline.declarationStops(this.model), ...sections])].sort((left, right) => left - right);
|
|
1055
|
+
}
|
|
1056
|
+
/* Moves the one caret to the first line of the next or previous change mark, of any layer. False when there is none. */
|
|
1057
|
+
goToChange(direction) {
|
|
1058
|
+
const line = this.model.positionAt(this.model.getPrimary().head).line;
|
|
1059
|
+
const { runs } = this.resolvedChanges();
|
|
1060
|
+
// A run the caret is in is where it already is; a deleted run is the line its mark sits on.
|
|
1061
|
+
const target = direction === 1 ? runs.find((run) => run.start > line) : runs.findLast((run) => (run.kind === 'deleted' ? run.start : run.end) < line);
|
|
1062
|
+
if (target === undefined) {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
const offset = this.model.getLine(Math.min(target.start, this.model.getLineCount() - 1)).start;
|
|
1066
|
+
this.model.setSelections([{ anchor: offset, head: offset }]);
|
|
1067
|
+
this.revealOffset(offset, 'center');
|
|
1068
|
+
return true;
|
|
1069
|
+
}
|
|
1070
|
+
/* Moves the one caret to the previous or next declaration on another line. False when there is none. */
|
|
1071
|
+
goToMethod(direction) {
|
|
1072
|
+
// The structure is read after a pause in typing, so a press right after an edit reads it now.
|
|
1073
|
+
if (this.declarations === null) {
|
|
1074
|
+
this.refreshFolds();
|
|
1075
|
+
}
|
|
1076
|
+
const line = this.model.positionAt(this.model.getPrimary().head).line;
|
|
1077
|
+
const stops = this.methodStops();
|
|
1078
|
+
const target = direction === 1
|
|
1079
|
+
? stops.find((offset) => this.model.positionAt(offset).line > line)
|
|
1080
|
+
: stops.findLast((offset) => this.model.positionAt(offset).line < line);
|
|
1081
|
+
if (target === undefined) {
|
|
1082
|
+
return false;
|
|
1083
|
+
}
|
|
1084
|
+
this.model.setSelections([{ anchor: target, head: target }]);
|
|
1085
|
+
this.revealOffset(target, direction === 1 ? 'centerDown' : 'centerUp');
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
996
1088
|
/* Hands over what a language server knows about the folds; null forgets it. The defaults fold what the answer names, once. */
|
|
997
1089
|
setFoldHints(hints) {
|
|
998
1090
|
this.foldHints = hints;
|
|
@@ -1836,6 +1928,9 @@ export class EditorView {
|
|
|
1836
1928
|
});
|
|
1837
1929
|
}
|
|
1838
1930
|
}
|
|
1931
|
+
if (this.hippieSource !== null) {
|
|
1932
|
+
marks.push({ className: 'se-hippie-source', rects: this.paintRectangles(this.hippieSource.from, this.hippieSource.to, rows) });
|
|
1933
|
+
}
|
|
1839
1934
|
const marginX = this.settings.rightMargin === null ? null : this.settings.rightMargin * this.layout.metrics.charWidth;
|
|
1840
1935
|
// A margin past the content would stretch the scroll extent to itself, so it shows only where the text or the view reaches it.
|
|
1841
1936
|
if (marginX !== null && marginX < Math.max(this.layout.width, this.viewportWidth)) {
|
|
@@ -2228,7 +2323,7 @@ export class EditorView {
|
|
|
2228
2323
|
const matches = this.find.matches;
|
|
2229
2324
|
const current = this.find.current;
|
|
2230
2325
|
const alike = this.selectionOccurrences();
|
|
2231
|
-
const key = `${this.revision}|${this.changeVersion}|${this.markerVersion}|${this.layout.height}|${trackHeight}|${matches.length}|${current}|${matches[0]?.from}|${matches.at(-1)?.from}|${this.selectionOccurrenceCache.key}`;
|
|
2326
|
+
const key = `${this.revision}|${this.changeVersion}|${this.markerVersion}|${this.todos.version}|${this.layout.height}|${trackHeight}|${matches.length}|${current}|${matches[0]?.from}|${matches.at(-1)?.from}|${this.selectionOccurrenceCache.key}`;
|
|
2232
2327
|
if (key === this.overviewKey) {
|
|
2233
2328
|
return;
|
|
2234
2329
|
}
|
|
@@ -2255,6 +2350,11 @@ export class EditorView {
|
|
|
2255
2350
|
});
|
|
2256
2351
|
}
|
|
2257
2352
|
}
|
|
2353
|
+
for (const todo of this.todos.marks) {
|
|
2354
|
+
if (todo.line < this.model.getLineCount()) {
|
|
2355
|
+
spans.push({ kind: 'todo', top: rowTop(todo.line), bottom: rowBottom(todo.line), offset: todo.from, title: todo.text });
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2258
2358
|
for (const range of alike) {
|
|
2259
2359
|
const line = this.model.positionAt(range.from).line;
|
|
2260
2360
|
spans.push({ kind: 'occurrence', top: rowTop(line), bottom: rowBottom(line) });
|
|
@@ -2427,6 +2527,7 @@ export class EditorView {
|
|
|
2427
2527
|
this.blockObserver?.disconnect();
|
|
2428
2528
|
clearTimeout(this.bracketTimer);
|
|
2429
2529
|
clearTimeout(this.foldTimer);
|
|
2530
|
+
this.todos.dispose();
|
|
2430
2531
|
clearTimeout(this.colorTimer);
|
|
2431
2532
|
clearTimeout(this.noticeTimer);
|
|
2432
2533
|
clearTimeout(this.liveTimer);
|
package/dist/zoom.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EditorFont } from './metrics.ts';
|
|
2
|
+
import type { EditorZoom } from './types.ts';
|
|
3
|
+
export declare const MIN_FONT_SIZE = 12;
|
|
4
|
+
export declare const MAX_FONT_SIZE = 90;
|
|
5
|
+
export interface FontSizeRange {
|
|
6
|
+
readonly min: number;
|
|
7
|
+
readonly max: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function fontSizeRange(zoom: EditorZoom | undefined): FontSizeRange;
|
|
10
|
+
export declare function clampFontSize(size: number, range: FontSizeRange): number;
|
|
11
|
+
export declare function zoomedFont(base: EditorFont, size: number): EditorFont;
|
|
12
|
+
export declare class WheelZoom {
|
|
13
|
+
private pending;
|
|
14
|
+
step(event: {
|
|
15
|
+
deltaY: number;
|
|
16
|
+
deltaMode: number;
|
|
17
|
+
}): number;
|
|
18
|
+
}
|
package/dist/zoom.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/* Nothing a person reads is smaller. */
|
|
2
|
+
export const MIN_FONT_SIZE = 12;
|
|
3
|
+
export const MAX_FONT_SIZE = 90;
|
|
4
|
+
/* A trackpad or a pinch sends the wheel in small steps; this many pixels of them are one step of the size. */
|
|
5
|
+
const PIXELS_PER_STEP = 20;
|
|
6
|
+
export function fontSizeRange(zoom) {
|
|
7
|
+
const min = Math.max(MIN_FONT_SIZE, Math.round(zoom?.min ?? MIN_FONT_SIZE));
|
|
8
|
+
return { min, max: Math.max(min, Math.round(zoom?.max ?? MAX_FONT_SIZE)) };
|
|
9
|
+
}
|
|
10
|
+
/* In whole pixels inside the range. */
|
|
11
|
+
export function clampFontSize(size, range) {
|
|
12
|
+
return Math.min(range.max, Math.max(range.min, Math.round(size)));
|
|
13
|
+
}
|
|
14
|
+
/* The face at another size, with the line as much taller as the page's line is to its text, in whole pixels. */
|
|
15
|
+
export function zoomedFont(base, size) {
|
|
16
|
+
return { family: base.family, size, lineHeight: Math.round((size * base.lineHeight) / base.size) };
|
|
17
|
+
}
|
|
18
|
+
/* Turns the wheel with the zoom modifier, or a pinch, into steps of one pixel: up and apart make the text larger. */
|
|
19
|
+
export class WheelZoom {
|
|
20
|
+
pending = 0;
|
|
21
|
+
/* -1, 0 or 1. A mouse notch is one step however far the platform says it went. */
|
|
22
|
+
step(event) {
|
|
23
|
+
if (event.deltaY === 0) {
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
if (event.deltaMode !== 0 || Math.abs(event.deltaY) >= PIXELS_PER_STEP) {
|
|
27
|
+
this.pending = 0;
|
|
28
|
+
return event.deltaY < 0 ? 1 : -1;
|
|
29
|
+
}
|
|
30
|
+
if (Math.sign(this.pending) !== 0 && Math.sign(this.pending) !== Math.sign(event.deltaY)) {
|
|
31
|
+
this.pending = 0;
|
|
32
|
+
}
|
|
33
|
+
this.pending += event.deltaY;
|
|
34
|
+
if (Math.abs(this.pending) < PIXELS_PER_STEP) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
const direction = this.pending < 0 ? 1 : -1;
|
|
38
|
+
this.pending = 0;
|
|
39
|
+
return direction;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adecore/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"test": "bun test --conditions=source"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@adecore/editor-core": "0.
|
|
57
|
+
"@adecore/editor-core": "0.43.0",
|
|
58
58
|
"linkedom": "^0.18.14",
|
|
59
59
|
"shiki": "^4.5.0"
|
|
60
60
|
},
|