@aardarch/aardink-web 0.6.0-rc1 → 0.6.0-rc3
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/README.md +25 -5
- package/index.d.ts +144 -13
- package/index.js +63 -23
- package/kotlin/aardink-web.import-object.mjs +17 -0
- package/kotlin/aardink-web.mjs +3 -0
- package/kotlin/aardink-web.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,18 @@ const savedAt = editor.getAlternativeVersionId(); // unsaved while it differs
|
|
|
44
44
|
editor.dispose();
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
`setValue` is for opening a file: it clears the undo history. A change the user should be able to
|
|
48
|
+
undo, such as an assistant's rewrite, goes through `replaceValue` (the whole text) or Monaco's
|
|
49
|
+
`executeEdits` (ranges). Either is one undo step that keeps the history before it, and changes
|
|
50
|
+
only what differs, so carets and folds in unchanged text stay put:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
editor.replaceValue(rewritten); // undo() brings the old text back
|
|
54
|
+
editor.executeEdits('assistant', [
|
|
55
|
+
{ range: { startLineNumber: 3, startColumn: 1, endLineNumber: 3, endColumn: 9 }, text: '<button/>' },
|
|
56
|
+
]);
|
|
57
|
+
```
|
|
58
|
+
|
|
47
59
|
A language of your own is a Monarch grammar registered before use, optionally extending a built-in
|
|
48
60
|
language's completions, diagnostics and folding, with Monaco's `defineTheme` for its colours:
|
|
49
61
|
|
|
@@ -52,14 +64,24 @@ import { defineTheme, registerLanguage } from '@aardarch/aardink-web';
|
|
|
52
64
|
|
|
53
65
|
await registerLanguage(
|
|
54
66
|
{ id: 'toy', extends: 'xml', grammar: { tokenizer: { root: [[/\bshout\b/, 'keyword']] } } },
|
|
55
|
-
{
|
|
67
|
+
{
|
|
68
|
+
triggerCharacters: ['{'], // besides XML's
|
|
69
|
+
provideCompletionItems: (text, line, column) => [{ label: 'shout', kind: 'element' }],
|
|
70
|
+
},
|
|
56
71
|
);
|
|
57
72
|
await defineTheme('toy-dark', { base: 'vs-dark', inherit: true, rules: [{ token: 'keyword', foreground: 'ff00ff' }] });
|
|
58
73
|
```
|
|
59
74
|
|
|
75
|
+
Completion items take Monaco's `filterText`, `sortText` and `range` too, and
|
|
76
|
+
`inheritCompletions: false` in the definition leaves out the extended language's completions
|
|
77
|
+
(XML's are Android-flavoured) while keeping its diagnostics and folding. A hover can carry an
|
|
78
|
+
`example`, shown as code.
|
|
79
|
+
|
|
60
80
|
The editor fills its container, so give the container a size. `createEditor` is async because
|
|
61
81
|
the first call loads the WebAssembly module (about 13 MB, 4.7 MB gzipped); every editor on the
|
|
62
|
-
page shares that one module.
|
|
82
|
+
page shares that one module. If that load fails, the call rejects and the next call loads again
|
|
83
|
+
(though Chrome keeps a failed module download until the page is reloaded). See
|
|
84
|
+
[`index.d.ts`](./index.d.ts) for the full API, and the
|
|
63
85
|
[integration guide](https://github.com/aardarch/aardink/blob/main/docs/WEB_INTEGRATION.md) for how
|
|
64
86
|
Monaco's options and calls map onto it.
|
|
65
87
|
|
|
@@ -102,9 +124,7 @@ the measurements and the device checklist.
|
|
|
102
124
|
- **A disposed editor is not fully released** (about 275 KB each) until Aardink moves to Compose
|
|
103
125
|
Multiplatform 1.13. Reuse one editor with `setValue` and `updateOptions` rather than mounting
|
|
104
126
|
one per view.
|
|
105
|
-
-
|
|
106
|
-
- Whitespace is not rendered (`renderWhitespace`), and a completion inserts plain text: snippet
|
|
107
|
-
placeholders such as `$1` are not expanded.
|
|
127
|
+
- A theme rule's `background` is ignored; its `foreground` and `fontStyle` apply.
|
|
108
128
|
|
|
109
129
|
## Licence
|
|
110
130
|
|
package/index.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export interface AardinkOptions {
|
|
|
35
35
|
insertSpaces?: boolean;
|
|
36
36
|
/** Monaco's `renderLineHighlight`: anything but `'none'` highlights each caret's line. */
|
|
37
37
|
renderLineHighlight?: 'none' | 'line' | 'gutter' | 'all';
|
|
38
|
+
/** Which spaces and tabs are drawn, as dots and arrows. `'selection'` by default. */
|
|
39
|
+
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
|
|
38
40
|
/** Colours brackets by nesting depth. On by default. */
|
|
39
41
|
bracketPairColorization?: { enabled?: boolean } | boolean;
|
|
40
42
|
/** A picture of the whole text at the side, with a slider over what is shown. Off by default. */
|
|
@@ -70,14 +72,49 @@ export interface AardinkContentChange {
|
|
|
70
72
|
versionId: number;
|
|
71
73
|
isUndoing: boolean;
|
|
72
74
|
isRedoing: boolean;
|
|
73
|
-
/** The whole text was replaced (`setValue`)
|
|
75
|
+
/** The whole text was replaced and the undo history cleared (`setValue`); `false` for `replaceValue` and `executeEdits`. */
|
|
74
76
|
isFlush: boolean;
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Monaco's `IIdentifiedSingleEditOperation`, for `executeEdits`: replaces `range` with `text`.
|
|
81
|
+
* `null` or `''` deletes the range; an empty range inserts. A position past the end of its line is
|
|
82
|
+
* the line's end, and one past the last line the end of the text, as Monaco validates them.
|
|
83
|
+
*/
|
|
84
|
+
export interface AardinkEditOperation {
|
|
85
|
+
range: AardinkRange;
|
|
86
|
+
text: string | null;
|
|
87
|
+
/** Accepted for Monaco's shape, and ignored. */
|
|
88
|
+
forceMoveMarkers?: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
77
91
|
export interface AardinkEditor {
|
|
78
92
|
getValue(): string;
|
|
79
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Replaces the whole text and clears undo history, as when a file is opened. Fires the change
|
|
95
|
+
* listeners with `isFlush: true`. For a change the user should be able to undo, use
|
|
96
|
+
* `replaceValue` or `executeEdits`.
|
|
97
|
+
*/
|
|
80
98
|
setValue(text: string): void;
|
|
99
|
+
/**
|
|
100
|
+
* Replaces the whole text as one undo step, keeping the history before it: for a rewrite the user
|
|
101
|
+
* should be able to undo, such as an assistant's. Only what differs changes (lines compared, then
|
|
102
|
+
* characters), so carets, folds and diagnostics in unchanged text stay where they are. The change
|
|
103
|
+
* listeners get it with `isFlush: false` and a new `versionId`; `undo()` brings the old text back,
|
|
104
|
+
* and `getAlternativeVersionId()` its value then. Works in a read-only editor, as `setValue` does.
|
|
105
|
+
* Returns whether the text changed.
|
|
106
|
+
*/
|
|
107
|
+
replaceValue(text: string): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Monaco's `executeEdits`: applies `edits` (which must not overlap) as one undo step, keeping the
|
|
110
|
+
* history, each reduced to the characters it really changes so carets and folds elsewhere stay
|
|
111
|
+
* put. Then selects `endCursorState` when given (positions in the text after the edits, as in
|
|
112
|
+
* Monaco), else carries the selections through the edits;
|
|
113
|
+
* a cursor-state computer function is not called. `source` is accepted for Monaco's shape.
|
|
114
|
+
* Returns `false`, changing nothing, in a read-only editor, as Monaco does; throws for edits that
|
|
115
|
+
* overlap. Reported to the change listeners as for `replaceValue`.
|
|
116
|
+
*/
|
|
117
|
+
executeEdits(source: string | null | undefined, edits: AardinkEditOperation[], endCursorState?: AardinkSelection[] | ((...args: unknown[]) => unknown)): boolean;
|
|
81
118
|
updateOptions(options: Partial<AardinkOptions>): void;
|
|
82
119
|
/** Full text after every change, at most once per frame, and what the change was. Returns an unsubscribe function. */
|
|
83
120
|
onDidChangeContent(listener: (text: string, change: AardinkContentChange) => void): () => void;
|
|
@@ -90,11 +127,24 @@ export interface AardinkEditor {
|
|
|
90
127
|
setDiagnostics(diagnostics: AardinkDiagnostic[] | null): void;
|
|
91
128
|
/**
|
|
92
129
|
* The language's own diagnostics each time they are collected: 500 ms after the editor appears,
|
|
93
|
-
*
|
|
130
|
+
* after each pause in typing, and on `revalidate()`. Not called while a list from
|
|
131
|
+
* `setDiagnostics` is shown.
|
|
94
132
|
* Returns an unsubscribe function.
|
|
95
133
|
*/
|
|
96
134
|
onDidChangeDiagnostics(listener: (diagnostics: AardinkDiagnostic[]) => void): () => void;
|
|
135
|
+
/**
|
|
136
|
+
* Collects the language's own diagnostics again now, without waiting for an edit: for when what
|
|
137
|
+
* your `provideDiagnostics` depends on outside the text has changed (another file, a setting).
|
|
138
|
+
* They reach `onDidChangeDiagnostics` as usual. Does nothing while a list from `setDiagnostics`
|
|
139
|
+
* is shown.
|
|
140
|
+
*/
|
|
141
|
+
revalidate(): void;
|
|
97
142
|
revealPosition(line: number, column: number): void;
|
|
143
|
+
/**
|
|
144
|
+
* Opens the find panel and moves the keyboard focus to its find field, from wherever on the
|
|
145
|
+
* page it was. Enter goes to the next match, Shift+Enter to the previous one, and Escape closes
|
|
146
|
+
* the panel and gives the focus back to the text.
|
|
147
|
+
*/
|
|
98
148
|
showFind(): void;
|
|
99
149
|
undo(): boolean;
|
|
100
150
|
redo(): boolean;
|
|
@@ -131,29 +181,104 @@ export interface AardinkLanguageDefinition {
|
|
|
131
181
|
grammar: object;
|
|
132
182
|
/** A built-in or registered language whose completions, diagnostics, hover and folding this one takes too, e.g. `'xml'`. */
|
|
133
183
|
extends?: string;
|
|
184
|
+
/**
|
|
185
|
+
* With `extends`: `false` leaves out that language's completions (and, when the providers give
|
|
186
|
+
* `triggerCharacters`, its trigger characters), keeping its diagnostics, hover, folding and the
|
|
187
|
+
* rest. `true` by default. To leave them out for one request only, answer with
|
|
188
|
+
* `{ suggestions, exclusive: true }`.
|
|
189
|
+
*/
|
|
190
|
+
inheritCompletions?: boolean;
|
|
134
191
|
displayName?: string;
|
|
135
192
|
extensions?: string[];
|
|
136
193
|
/** As in Monaco's language configuration: what Ctrl/Cmd+/ comments with. */
|
|
137
194
|
comments?: { lineComment?: string; blockComment?: [string, string] };
|
|
138
195
|
}
|
|
139
196
|
|
|
197
|
+
/** Monaco's flags for a completion's `insertText`. */
|
|
198
|
+
export declare const CompletionItemInsertTextRule: {
|
|
199
|
+
readonly None: 0;
|
|
200
|
+
/** Insert the snippet's whitespace as written, rather than indented as the line it lands on. */
|
|
201
|
+
readonly KeepWhitespace: 1;
|
|
202
|
+
/** `insertText` is a snippet: `$1`, `${1:placeholder}` and `${1|a,b|}` are tab stops, `$0` the final caret. */
|
|
203
|
+
readonly InsertAsSnippet: 4;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/** Monaco's `IRange`: 1-based lines and columns, `endColumn` exclusive. */
|
|
207
|
+
export interface AardinkRange {
|
|
208
|
+
startLineNumber: number;
|
|
209
|
+
startColumn: number;
|
|
210
|
+
endLineNumber: number;
|
|
211
|
+
endColumn: number;
|
|
212
|
+
}
|
|
213
|
+
|
|
140
214
|
export interface AardinkCompletionItem {
|
|
141
215
|
label: string;
|
|
142
|
-
/** What accepting it types; the label when absent. */
|
|
216
|
+
/** What accepting it types; the label when absent. A snippet with `InsertAsSnippet`. */
|
|
143
217
|
insertText?: string;
|
|
144
|
-
|
|
218
|
+
/** `CompletionItemInsertTextRule` flags, as in Monaco. */
|
|
219
|
+
insertTextRules?: number;
|
|
220
|
+
/**
|
|
221
|
+
* The icon. `'function'` is another name for `'transform'`, and `'color'` for `'colorRef'`, as
|
|
222
|
+
* Monaco calls them; any other name shows as `'value'`.
|
|
223
|
+
*/
|
|
224
|
+
kind?: 'element' | 'attribute' | 'value' | 'snippet' | 'module' | 'property' | 'transform' | 'function' | 'colorRef' | 'color';
|
|
225
|
+
/** Shown beside the label when there is no `documentation`. */
|
|
145
226
|
detail?: string;
|
|
146
|
-
|
|
227
|
+
/** Shown beside the label; Monaco's `{ value }` is shown as plain text. */
|
|
228
|
+
documentation?: string | { value: string };
|
|
229
|
+
/**
|
|
230
|
+
* What the text typed so far is matched against, as in Monaco: its characters in order, ignoring
|
|
231
|
+
* case, the first at the start of `filterText` or of a word in it. Typed so far is the text from
|
|
232
|
+
* the start of what the item replaces to the caret. Without it the item is not filtered: your
|
|
233
|
+
* provider is asked again on each letter typed, and offers what fits.
|
|
234
|
+
*/
|
|
235
|
+
filterText?: string;
|
|
236
|
+
/** When any item has one, your items are ordered by it (by `label` where it is missing), as in Monaco. */
|
|
237
|
+
sortText?: string;
|
|
238
|
+
/**
|
|
239
|
+
* The text accepting the item replaces, which must contain the caret, as in Monaco. Of
|
|
240
|
+
* `{ insert, replace }`, `replace` is used. Without it the item replaces the word before the
|
|
241
|
+
* caret, back to the first of `< > { } ( ) [ ] " ' = , ; . @ | :` or whitespace.
|
|
242
|
+
*/
|
|
243
|
+
range?: AardinkRange | { insert: AardinkRange; replace: AardinkRange };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Monaco's `CompletionList`, plus `exclusive`: `true` leaves out the extended language's completions for this request. */
|
|
247
|
+
export interface AardinkCompletionList {
|
|
248
|
+
suggestions: AardinkCompletionItem[];
|
|
249
|
+
exclusive?: boolean;
|
|
250
|
+
/** Accepted for Monaco's shape, and ignored: your provider is asked again on each letter typed anyway. */
|
|
251
|
+
incomplete?: boolean;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface AardinkHover {
|
|
255
|
+
title?: string;
|
|
256
|
+
/** Plain text. */
|
|
257
|
+
contents: string;
|
|
258
|
+
/** Shown as code below `contents`. */
|
|
259
|
+
example?: string;
|
|
147
260
|
}
|
|
148
261
|
|
|
149
262
|
/**
|
|
150
263
|
* What a registered language knows beyond its grammar. Each gets the whole text and, where it
|
|
151
264
|
* asks about a place, a 1-based line and column; each may answer at once or with a Promise. With
|
|
152
|
-
* `extends`, the built-in language's answers come after these
|
|
265
|
+
* `extends`, the built-in language's answers come after these, less any completion with the same
|
|
266
|
+
* `kind` and `label` as one of yours (see `inheritCompletions` to leave them all out).
|
|
153
267
|
*/
|
|
154
268
|
export interface AardinkLanguageProviders {
|
|
155
|
-
|
|
156
|
-
|
|
269
|
+
/**
|
|
270
|
+
* Characters that open the completion list when typed, as on Monaco's completion provider, e.g.
|
|
271
|
+
* `['{', '|', '@', '$']`. With `extends` they add to that language's (`'xml'`: `< / space : " =`),
|
|
272
|
+
* or replace them with `inheritCompletions: false`; without, that language's apply. Letters and
|
|
273
|
+
* digits always ask again while the list is open.
|
|
274
|
+
*/
|
|
275
|
+
triggerCharacters?: string[];
|
|
276
|
+
provideCompletionItems?(
|
|
277
|
+
text: string,
|
|
278
|
+
line: number,
|
|
279
|
+
column: number,
|
|
280
|
+
): AardinkCompletionItem[] | AardinkCompletionList | null | Promise<AardinkCompletionItem[] | AardinkCompletionList | null>;
|
|
281
|
+
provideHover?(text: string, line: number, column: number): AardinkHover | null | Promise<AardinkHover | null>;
|
|
157
282
|
provideDiagnostics?(text: string): AardinkDiagnostic[] | Promise<AardinkDiagnostic[]>;
|
|
158
283
|
}
|
|
159
284
|
|
|
@@ -161,9 +286,10 @@ export interface AardinkLanguageProviders {
|
|
|
161
286
|
export function registerLanguage(definition: AardinkLanguageDefinition, providers?: AardinkLanguageProviders): Promise<void>;
|
|
162
287
|
|
|
163
288
|
/**
|
|
164
|
-
* Monaco's `defineTheme` data. Token rules name
|
|
165
|
-
* `tag
|
|
166
|
-
*
|
|
289
|
+
* Monaco's `defineTheme` data. Token rules name tokens as Monaco does, and the longest matching
|
|
290
|
+
* prefix wins: `tag` also colours `tag.aardflex`, `comment.doc` only documentation comments. A
|
|
291
|
+
* rule's `fontStyle` (`'bold'`, `'italic'`, `'underline'`, `'strikethrough'`, or `''` for none)
|
|
292
|
+
* applies too; its `background` is accepted, so Monaco theme data passes as it is, and ignored.
|
|
167
293
|
*/
|
|
168
294
|
export interface AardinkThemeData {
|
|
169
295
|
base: 'vs' | 'vs-dark' | 'hc-black' | 'hc-light';
|
|
@@ -191,7 +317,12 @@ export function createEditor(
|
|
|
191
317
|
/** For debugging a grammar: the tokens of `text` in `languageId`, per line, as Monaco's `tokenize` gives them. */
|
|
192
318
|
export function tokenize(text: string, languageId: string): Promise<{ offset: number; type: string }[][]>;
|
|
193
319
|
|
|
194
|
-
/**
|
|
320
|
+
/**
|
|
321
|
+
* Starts loading the WebAssembly module without mounting anything. Every call shares one load.
|
|
322
|
+
* When it fails (a network error, say), this and every call waiting on it reject, and the next
|
|
323
|
+
* call of any function here starts a new load. A browser may still hold on to a module whose
|
|
324
|
+
* download failed until the page is reloaded (Chrome does), so that new load can fail the same way.
|
|
325
|
+
*/
|
|
195
326
|
export function preloadAardink(): Promise<void>;
|
|
196
327
|
|
|
197
328
|
/** The Aardink version this package was built from. */
|
package/index.js
CHANGED
|
@@ -17,20 +17,30 @@
|
|
|
17
17
|
// Adapts the Kotlin module's integer-handle exports (aardinkCreate, aardinkGetValue, ...) into
|
|
18
18
|
// the Monaco-shaped object described in index.d.ts.
|
|
19
19
|
|
|
20
|
-
export const version = '0.6.0-
|
|
20
|
+
export const version = '0.6.0-rc3';
|
|
21
|
+
|
|
22
|
+
/** Monaco's flags for a completion's `insertText`. */
|
|
23
|
+
export const CompletionItemInsertTextRule = Object.freeze({ None: 0, KeepWhitespace: 1, InsertAsSnippet: 4 });
|
|
21
24
|
|
|
22
25
|
let kotlinModule;
|
|
23
26
|
|
|
24
27
|
function load() {
|
|
25
|
-
// Memoised: every editor on the page shares one WebAssembly instance.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
// Memoised: every editor on the page shares one WebAssembly instance. A failed load is
|
|
29
|
+
// forgotten, so the next call tries again rather than repeating one network blip for the
|
|
30
|
+
// page's life.
|
|
31
|
+
kotlinModule ??= import('./kotlin/aardink-web.mjs')
|
|
32
|
+
.then((k) => {
|
|
33
|
+
// Compose looks for resources relative to the page, not this package. A literal
|
|
34
|
+
// new URL(..., import.meta.url) is also what makes a bundler (Vite) emit the font file.
|
|
35
|
+
k.aardinkSetBundledFontUrl(
|
|
36
|
+
new URL('./kotlin/composeResources/com.aardarch.aardink.web.res/font/jetbrains_mono_regular.ttf', import.meta.url).href,
|
|
37
|
+
);
|
|
38
|
+
return k;
|
|
39
|
+
})
|
|
40
|
+
.catch((error) => {
|
|
41
|
+
kotlinModule = undefined;
|
|
42
|
+
throw error;
|
|
43
|
+
});
|
|
34
44
|
return kotlinModule;
|
|
35
45
|
}
|
|
36
46
|
|
|
@@ -54,6 +64,25 @@ function withRange(s) {
|
|
|
54
64
|
};
|
|
55
65
|
}
|
|
56
66
|
|
|
67
|
+
/** The fields of a Monaco `ISelection` the Kotlin side reads. */
|
|
68
|
+
function toKotlinSelection(s) {
|
|
69
|
+
return {
|
|
70
|
+
selectionStartLineNumber: s.selectionStartLineNumber,
|
|
71
|
+
selectionStartColumn: s.selectionStartColumn,
|
|
72
|
+
positionLineNumber: s.positionLineNumber,
|
|
73
|
+
positionColumn: s.positionColumn,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The fields of a Monaco edit operation the Kotlin side reads; a Monaco `Range` is a class, so copy them. */
|
|
78
|
+
function toKotlinEdit(edit) {
|
|
79
|
+
const r = edit.range;
|
|
80
|
+
return {
|
|
81
|
+
range: { startLineNumber: r.startLineNumber, startColumn: r.startColumn, endLineNumber: r.endLineNumber, endColumn: r.endColumn },
|
|
82
|
+
text: edit.text ?? null,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
57
86
|
/** For debugging a grammar: the tokens of `text` in `languageId`, per line, as Monaco's tokenize gives them. */
|
|
58
87
|
export async function tokenize(text, languageId) {
|
|
59
88
|
const k = await load();
|
|
@@ -95,6 +124,9 @@ export async function registerLanguage(definition, providers = {}) {
|
|
|
95
124
|
extends: definition.extends,
|
|
96
125
|
displayName: definition.displayName,
|
|
97
126
|
extensions: definition.extensions,
|
|
127
|
+
inheritCompletions: definition.inheritCompletions,
|
|
128
|
+
// On the providers, as on Monaco's completion provider; the Kotlin side reads it with the definition.
|
|
129
|
+
triggerCharacters: providers.triggerCharacters,
|
|
98
130
|
grammar,
|
|
99
131
|
}),
|
|
100
132
|
(text, line, column) => answer(providers.provideCompletionItems, text, line, column),
|
|
@@ -112,9 +144,16 @@ function toVsCodeTheme(theme) {
|
|
|
112
144
|
type: base === 'vscode-light' ? 'light' : 'dark',
|
|
113
145
|
base: theme.inherit === false ? undefined : base,
|
|
114
146
|
colors: theme.colors ?? {},
|
|
147
|
+
// A rule's colour and font style; its background is not drawn.
|
|
115
148
|
tokenColors: theme.rules
|
|
116
|
-
.filter((rule) => rule.foreground)
|
|
117
|
-
.map((rule) => ({
|
|
149
|
+
.filter((rule) => rule.foreground || rule.fontStyle !== undefined)
|
|
150
|
+
.map((rule) => ({
|
|
151
|
+
scope: rule.token,
|
|
152
|
+
settings: {
|
|
153
|
+
...(rule.foreground ? { foreground: `#${rule.foreground.replace(/^#/, '')}` } : {}),
|
|
154
|
+
...(rule.fontStyle !== undefined ? { fontStyle: rule.fontStyle } : {}),
|
|
155
|
+
},
|
|
156
|
+
})),
|
|
118
157
|
};
|
|
119
158
|
}
|
|
120
159
|
|
|
@@ -134,7 +173,7 @@ export const defineTheme = registerTheme;
|
|
|
134
173
|
*/
|
|
135
174
|
function toKotlinOptions(options) {
|
|
136
175
|
const out = {};
|
|
137
|
-
for (const key of ['language', 'theme', 'fontSize', 'readOnly', 'showGutter', 'showLineNumbers', 'showFoldMarkers', 'tabSize', 'insertSpaces', 'highlightCurrentLine']) {
|
|
176
|
+
for (const key of ['language', 'theme', 'fontSize', 'readOnly', 'showGutter', 'showLineNumbers', 'showFoldMarkers', 'tabSize', 'insertSpaces', 'highlightCurrentLine', 'renderWhitespace']) {
|
|
138
177
|
if (options[key] !== undefined) out[key] = options[key];
|
|
139
178
|
}
|
|
140
179
|
if (options.wordWrap !== undefined) out.wordWrap = options.wordWrap === 'on';
|
|
@@ -172,6 +211,15 @@ export async function createEditor(container, onChange, options = {}) {
|
|
|
172
211
|
return {
|
|
173
212
|
getValue: () => k.aardinkGetValue(id),
|
|
174
213
|
setValue: (text) => k.aardinkSetValue(id, text),
|
|
214
|
+
replaceValue: (text) => k.aardinkReplaceValue(id, text),
|
|
215
|
+
executeEdits(source, edits, endCursorState) {
|
|
216
|
+
// `source` only names the edit in Monaco; a cursor-state computer function is not called.
|
|
217
|
+
const selections = Array.isArray(endCursorState) && endCursorState.length ? endCursorState.map(toKotlinSelection) : null;
|
|
218
|
+
const result = k.aardinkExecuteEdits(id, JSON.stringify(edits.map(toKotlinEdit)), JSON.stringify(selections));
|
|
219
|
+
if (result === 'read-only') return false;
|
|
220
|
+
if (result) throw new Error(`Aardink: ${result}`);
|
|
221
|
+
return true;
|
|
222
|
+
},
|
|
175
223
|
updateOptions: (patch) => k.aardinkUpdateOptions(id, JSON.stringify(toKotlinOptions(patch))),
|
|
176
224
|
onDidChangeContent(listener) {
|
|
177
225
|
contentListeners.add(listener);
|
|
@@ -186,21 +234,13 @@ export async function createEditor(container, onChange, options = {}) {
|
|
|
186
234
|
diagnosticsListeners.add(listener);
|
|
187
235
|
return () => diagnosticsListeners.delete(listener);
|
|
188
236
|
},
|
|
237
|
+
revalidate: () => k.aardinkRevalidate(id),
|
|
189
238
|
revealPosition: (line, column) => k.aardinkRevealPosition(id, line, column),
|
|
190
239
|
setBaseline: (text) => k.aardinkSetBaseline(id, text ?? ''),
|
|
191
240
|
format: () => new Promise((resolve) => k.aardinkFormat(id, resolve)),
|
|
192
241
|
focus: () => k.aardinkFocus(id),
|
|
193
242
|
getSelections: () => JSON.parse(k.aardinkGetSelections(id)).map(withRange),
|
|
194
|
-
setSelections: (selections) =>
|
|
195
|
-
k.aardinkSetSelections(
|
|
196
|
-
id,
|
|
197
|
-
JSON.stringify(selections.map((s) => ({
|
|
198
|
-
selectionStartLineNumber: s.selectionStartLineNumber,
|
|
199
|
-
selectionStartColumn: s.selectionStartColumn,
|
|
200
|
-
positionLineNumber: s.positionLineNumber,
|
|
201
|
-
positionColumn: s.positionColumn,
|
|
202
|
-
}))),
|
|
203
|
-
),
|
|
243
|
+
setSelections: (selections) => k.aardinkSetSelections(id, JSON.stringify(selections.map(toKotlinSelection))),
|
|
204
244
|
canUndo: () => k.aardinkCanUndo(id),
|
|
205
245
|
canRedo: () => k.aardinkCanRedo(id),
|
|
206
246
|
pushUndoStop: () => k.aardinkPushUndoStop(id),
|
|
@@ -561,6 +561,23 @@ const js_code = {
|
|
|
561
561
|
'androidx.compose.material3.internal.set_$external_fun' : (_this, p0, p1) => _this.set(p0, p1),
|
|
562
562
|
'androidx.compose.material3.internal.get_$external_fun' : (_this, p0) => _this.get(p0),
|
|
563
563
|
'com.aardarch.aardink.platform.readClipboardText' : () => navigator.clipboard.readText(),
|
|
564
|
+
'com.aardarch.aardink.web.followSize' : (element) => {
|
|
565
|
+
let last = element.clientWidth + 'x' + element.clientHeight;
|
|
566
|
+
let frame = 0;
|
|
567
|
+
const observer = new ResizeObserver(() => {
|
|
568
|
+
const size = element.clientWidth + 'x' + element.clientHeight;
|
|
569
|
+
if (size === last) return;
|
|
570
|
+
last = size;
|
|
571
|
+
cancelAnimationFrame(frame);
|
|
572
|
+
frame = requestAnimationFrame(() => window.dispatchEvent(new Event('resize')));
|
|
573
|
+
});
|
|
574
|
+
observer.observe(element);
|
|
575
|
+
return () => {
|
|
576
|
+
cancelAnimationFrame(frame);
|
|
577
|
+
observer.disconnect();
|
|
578
|
+
};
|
|
579
|
+
},
|
|
580
|
+
'com.aardarch.aardink.web.callStop' : (stop) => stop(),
|
|
564
581
|
'com.aardarch.aardink.sampleweb.__callJsClosure_((String)->Unit)' : (f, p0) => f(p0),
|
|
565
582
|
'com.aardarch.aardink.sampleweb.__callJsClosure_((Int,Int)->Unit)' : (f, p0, p1) => f(p0, p1),
|
|
566
583
|
'com.aardarch.aardink.sampleweb.__callJsClosure_((String,Int,Int)->Js)' : (f, p0, p1, p2) => f(p0, p1, p2),
|
package/kotlin/aardink-web.mjs
CHANGED
|
@@ -81,11 +81,14 @@ export const {
|
|
|
81
81
|
aardinkCreate,
|
|
82
82
|
aardinkGetValue,
|
|
83
83
|
aardinkSetValue,
|
|
84
|
+
aardinkReplaceValue,
|
|
85
|
+
aardinkExecuteEdits,
|
|
84
86
|
aardinkUpdateOptions,
|
|
85
87
|
aardinkOnChange,
|
|
86
88
|
aardinkOnCursorChange,
|
|
87
89
|
aardinkSetDiagnostics,
|
|
88
90
|
aardinkOnDiagnosticsChange,
|
|
91
|
+
aardinkRevalidate,
|
|
89
92
|
aardinkRegisterLanguage,
|
|
90
93
|
aardinkRegisterTheme,
|
|
91
94
|
aardinkOnContentChange,
|
package/kotlin/aardink-web.wasm
CHANGED
|
Binary file
|
package/package.json
CHANGED