@silverbulletmd/silverbullet 2.9.0 → 2.11.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/README.md +38 -25
- package/client/asset_bundle/bundle.ts +0 -1
- package/client/config.ts +343 -0
- package/client/markdown_parser/constants.ts +3 -1
- package/client/plugos/hooks/command.ts +0 -5
- package/client/plugos/hooks/event.ts +0 -6
- package/client/plugos/hooks/mq.ts +0 -3
- package/client/plugos/hooks/slash_command.ts +1 -7
- package/client/plugos/hooks/syscall.ts +24 -14
- package/client/plugos/manifest_cache.ts +0 -32
- package/client/plugos/plug.ts +0 -3
- package/client/plugos/plug_compile.ts +3 -13
- package/client/plugos/sandboxes/worker_sandbox.ts +19 -9
- package/client/plugos/syscalls/asset.ts +61 -23
- package/client/plugos/syscalls/clientStore.ts +32 -6
- package/client/plugos/syscalls/client_code_widget.ts +9 -4
- package/client/plugos/syscalls/code_widget.ts +26 -11
- package/client/plugos/syscalls/config.ts +146 -30
- package/client/plugos/syscalls/datastore.ts +146 -40
- package/client/plugos/syscalls/editor.ts +1518 -722
- package/client/plugos/syscalls/event.ts +44 -13
- package/client/plugos/syscalls/fetch.ts +120 -83
- package/client/plugos/syscalls/icon.ts +46 -0
- package/client/plugos/syscalls/index.ts +267 -121
- package/client/plugos/syscalls/jsonschema.ts +107 -9
- package/client/plugos/syscalls/language.ts +38 -12
- package/client/plugos/syscalls/markdown.ts +166 -50
- package/client/plugos/syscalls/mq.ts +92 -20
- package/client/plugos/syscalls/navigator.ts +143 -0
- package/client/plugos/syscalls/schema_introspection.ts +33 -0
- package/client/plugos/syscalls/search.ts +44 -0
- package/client/plugos/syscalls/service_registry.ts +74 -20
- package/client/plugos/syscalls/shell.ts +51 -21
- package/client/plugos/syscalls/space.ts +412 -113
- package/client/plugos/syscalls/sync.ts +103 -20
- package/client/plugos/syscalls/system.ts +274 -139
- package/client/plugos/system.ts +28 -10
- package/client/plugos/worker_runtime.ts +0 -2
- package/client/space_lua/aggregates.ts +0 -16
- package/client/space_lua/api_documentation.ts +107 -0
- package/client/space_lua/ast.ts +13 -5
- package/client/space_lua/ast_narrow.ts +0 -5
- package/client/space_lua/budget.ts +113 -0
- package/client/space_lua/budget_ui.ts +49 -0
- package/client/space_lua/eval.ts +125 -92
- package/client/space_lua/labels.ts +0 -4
- package/client/space_lua/numeric.ts +0 -5
- package/client/space_lua/parse.ts +243 -125
- package/client/space_lua/pretty_print.ts +128 -54
- package/client/space_lua/quarantine.ts +127 -0
- package/client/space_lua/query_collection.ts +7 -51
- package/client/space_lua/query_env.ts +0 -2
- package/client/space_lua/render_lua_markdown.ts +2 -7
- package/client/space_lua/render_widget.ts +173 -0
- package/client/space_lua/runtime.ts +133 -92
- package/client/space_lua/stdlib/crypto.ts +8 -3
- package/client/space_lua/stdlib/encoding.ts +27 -9
- package/client/space_lua/stdlib/format.ts +0 -12
- package/client/space_lua/stdlib/js.ts +136 -23
- package/client/space_lua/stdlib/load.ts +24 -16
- package/client/space_lua/stdlib/math.ts +331 -133
- package/client/space_lua/stdlib/net.ts +57 -13
- package/client/space_lua/stdlib/os.ts +111 -54
- package/client/space_lua/stdlib/pattern.ts +10 -15
- package/client/space_lua/stdlib/space_lua.ts +344 -21
- package/client/space_lua/stdlib/string.ts +282 -104
- package/client/space_lua/stdlib/string_pack.ts +58 -22
- package/client/space_lua/stdlib/table.ts +195 -45
- package/client/space_lua/stdlib.ts +354 -125
- package/client/space_lua/syscalls.ts +270 -0
- package/client/space_lua/tonumber.ts +0 -9
- package/dist/plug-compile.js +2 -3
- package/package.json +15 -5
- package/plug-api/lib/async.ts +1 -6
- package/plug-api/lib/collation.ts +22 -0
- package/plug-api/lib/crypto.ts +16 -15
- package/plug-api/lib/dates.ts +33 -0
- package/plug-api/lib/fuzzy.ts +282 -0
- package/plug-api/lib/json.ts +0 -6
- package/plug-api/lib/limited_map.ts +0 -2
- package/plug-api/lib/link_write.ts +27 -0
- package/plug-api/{ui → lib}/panel_styles.ts +4 -3
- package/plug-api/lib/ref.ts +124 -5
- package/plug-api/lib/resolve.ts +0 -1
- package/plug-api/lib/resolve_path.ts +290 -0
- package/plug-api/lib/shortcut.ts +17 -1
- package/plug-api/lib/tags.ts +0 -3
- package/plug-api/lib/transclusion.ts +28 -1
- package/plug-api/lib/tree.ts +0 -5
- package/plug-api/lib/yaml.ts +3 -42
- package/plug-api/syscall.ts +1 -5
- package/plug-api/syscalls/config.ts +7 -5
- package/plug-api/syscalls/editor.ts +70 -208
- package/plug-api/syscalls/icon.ts +18 -0
- package/plug-api/syscalls/index.ts +39 -5
- package/plug-api/syscalls/jsonschema.ts +9 -0
- package/plug-api/syscalls/lua.ts +7 -0
- package/plug-api/syscalls/search.ts +11 -0
- package/plug-api/syscalls/shell.ts +0 -1
- package/plug-api/syscalls/space.ts +122 -5
- package/plug-api/syscalls/sync.ts +23 -2
- package/plug-api/syscalls/system.ts +53 -0
- package/plug-api/syscalls.ts +2 -0
- package/plug-api/system_mock.ts +15 -2
- package/plug-api/types/client.ts +4 -3
- package/plug-api/types/datastore.ts +11 -2
- package/plug-api/types/index.ts +62 -1
- package/plug-api/types/manifest.ts +22 -4
- package/plug-api/types/profile.ts +13 -0
- package/plug-api/types/revisions.ts +67 -0
- package/plug-api/ui/cx.ts +1 -3
- package/plug-api/ui/description.ts +64 -0
- package/plug-api/ui/hover.ts +69 -0
- package/plug-api/ui/index.ts +61 -2
- package/plug-api/ui/scroll.ts +30 -0
- package/plug-api/ui/slugify.ts +44 -0
- package/plug-api/ui/tree_model.ts +263 -0
- package/plug-api/ui/tree_types.ts +66 -0
- package/plug-api/ui/use_fit_collapse.ts +67 -0
- package/plugs/builtin_plugs.ts +0 -1
- package/plugs/index/types.ts +9 -0
- package/client/plugos/syscalls/lua.ts +0 -81
- package/plug-api/lib/memory_cache.ts +0 -21
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { copyToClipboard } from "../../clipboard.ts";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "@codemirror/language";
|
|
3
|
+
acceptCompletion,
|
|
4
|
+
closeCompletion,
|
|
5
|
+
moveCompletionSelection,
|
|
6
|
+
startCompletion,
|
|
7
|
+
} from "@codemirror/autocomplete";
|
|
9
8
|
import {
|
|
10
9
|
cursorCharLeft,
|
|
11
10
|
cursorCharRight,
|
|
@@ -54,773 +53,1570 @@ import {
|
|
|
54
53
|
transposeChars,
|
|
55
54
|
undo,
|
|
56
55
|
} from "@codemirror/commands";
|
|
56
|
+
import { insertNewlineContinueMarkup } from "@codemirror/lang-markdown";
|
|
57
57
|
import {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
foldAll,
|
|
59
|
+
foldCode,
|
|
60
|
+
toggleFold,
|
|
61
|
+
unfoldAll,
|
|
62
|
+
unfoldCode,
|
|
63
|
+
} from "@codemirror/language";
|
|
64
|
+
import { forceLinting } from "@codemirror/lint";
|
|
65
|
+
import { openSearchPanel } from "@codemirror/search";
|
|
63
66
|
import type { Transaction } from "@codemirror/state";
|
|
64
67
|
import { EditorView } from "@codemirror/view";
|
|
65
|
-
import {
|
|
66
|
-
|
|
68
|
+
import {
|
|
69
|
+
coerceAndValidateRef,
|
|
70
|
+
type Ref,
|
|
71
|
+
} from "@silverbulletmd/silverbullet/lib/ref";
|
|
67
72
|
import type {
|
|
68
73
|
FilterOption,
|
|
69
74
|
NotificationAction,
|
|
70
75
|
NotificationType,
|
|
76
|
+
PanelMode,
|
|
71
77
|
UploadFile,
|
|
72
78
|
} from "@silverbulletmd/silverbullet/type/client";
|
|
73
|
-
import { openSearchPanel } from "@codemirror/search";
|
|
74
|
-
import { forceLinting } from "@codemirror/lint";
|
|
75
|
-
import { refreshLintEffect } from "../../codemirror/lint.ts";
|
|
76
|
-
import {
|
|
77
|
-
isValidPath,
|
|
78
|
-
parseToRef,
|
|
79
|
-
type Path,
|
|
80
|
-
type Ref,
|
|
81
|
-
} from "@silverbulletmd/silverbullet/lib/ref";
|
|
82
|
-
import { insertNewlineContinueMarkup } from "@codemirror/lang-markdown";
|
|
83
79
|
import type { VimConfig } from "@silverbulletmd/silverbullet/type/config";
|
|
84
80
|
import type { PageMeta } from "@silverbulletmd/silverbullet/type/index";
|
|
81
|
+
import { updateBakedSections } from "../../baked_sections/bake.ts";
|
|
82
|
+
import type { Client } from "../../client.ts";
|
|
83
|
+
import { refreshLintEffect } from "../../codemirror/lint.ts";
|
|
84
|
+
import { isMobileDevice, isNarrowScreen } from "../../lib/mobile.ts";
|
|
85
|
+
import { hide as hideNavigatorSlot } from "../../navigator/navigator.ts";
|
|
86
|
+
import type { PanelSlot } from "../../types/ui.ts";
|
|
87
|
+
import { getVimModule } from "../../vim_loader.ts";
|
|
88
|
+
import type { SysCallMapping } from "../system.ts";
|
|
85
89
|
|
|
86
90
|
export function editorSyscalls(client: Client): SysCallMapping {
|
|
87
91
|
const syscalls: SysCallMapping = {
|
|
88
|
-
"editor.getCurrentPage":
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
},
|
|
131
|
-
"editor.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
selection.to,
|
|
136
|
-
);
|
|
137
|
-
return {
|
|
138
|
-
from: selection.from,
|
|
139
|
-
to: selection.to,
|
|
140
|
-
text,
|
|
141
|
-
};
|
|
142
|
-
},
|
|
143
|
-
"editor.save": () => {
|
|
144
|
-
return client.save(true);
|
|
145
|
-
},
|
|
146
|
-
"editor.navigate": async (
|
|
147
|
-
_ctx,
|
|
148
|
-
ref: Ref | string,
|
|
149
|
-
replaceState = false,
|
|
150
|
-
newWindow = false,
|
|
151
|
-
) => {
|
|
152
|
-
if (typeof ref === "string") {
|
|
153
|
-
const parsedRef = parseToRef(ref);
|
|
154
|
-
if (!parsedRef) {
|
|
155
|
-
throw new Error(
|
|
156
|
-
"Unable to parse string provided to `editor.navigate` as ref",
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
ref = parsedRef;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (
|
|
163
|
-
// @ts-expect-error: Legacy support
|
|
164
|
-
ref.page !== undefined
|
|
165
|
-
) {
|
|
166
|
-
console.warn(
|
|
167
|
-
"You are using legacy navigation syntax with `editor.navigate()`, this will be phased out in the future",
|
|
92
|
+
"editor.getCurrentPage": {
|
|
93
|
+
callback: (): string => {
|
|
94
|
+
return client.currentName();
|
|
95
|
+
},
|
|
96
|
+
description:
|
|
97
|
+
"Returns the name of the page or document currently open in the editor.",
|
|
98
|
+
returns: [{ type: "string", description: "The current page name." }],
|
|
99
|
+
},
|
|
100
|
+
"editor.getCurrentPageMeta": {
|
|
101
|
+
callback: (): Promise<PageMeta | undefined> => {
|
|
102
|
+
const name = client.currentName();
|
|
103
|
+
return client.objectIndex.getObjectByRef(name, "page", name);
|
|
104
|
+
},
|
|
105
|
+
description:
|
|
106
|
+
"Returns metadata for the page or document currently open in the editor.",
|
|
107
|
+
returns: [
|
|
108
|
+
{
|
|
109
|
+
type: "PageMeta | undefined",
|
|
110
|
+
description: "The current page metadata, if indexed.",
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
"editor.getCurrentPath": {
|
|
115
|
+
callback: (_ctx): string => {
|
|
116
|
+
return client.currentPath();
|
|
117
|
+
},
|
|
118
|
+
description:
|
|
119
|
+
"Returns the path of the page or document currently open in the editor.",
|
|
120
|
+
returns: [{ type: "string", description: "The current page path." }],
|
|
121
|
+
},
|
|
122
|
+
"editor.getCurrentEditor": {
|
|
123
|
+
callback: (): string => {
|
|
124
|
+
return client.contentManager.documentEditor?.name || "page";
|
|
125
|
+
},
|
|
126
|
+
description:
|
|
127
|
+
"Returns the name of the currently active editor implementation.",
|
|
128
|
+
returns: [
|
|
129
|
+
{
|
|
130
|
+
type: "string",
|
|
131
|
+
description: "The editor name, or `page` for the page editor.",
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
"editor.getRecentlyOpenedPages": {
|
|
136
|
+
callback: (): PageMeta[] => {
|
|
137
|
+
return client.ui.viewState.allPages.sort(
|
|
138
|
+
(a, b) => (b.lastOpened || 0) - (a.lastOpened || 0),
|
|
168
139
|
);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
let details: Ref["details"];
|
|
181
|
-
|
|
182
|
-
if (typeof legacyRef.pos === "number") {
|
|
183
|
-
details = {
|
|
184
|
-
type: "position",
|
|
185
|
-
pos: legacyRef.pos,
|
|
186
|
-
};
|
|
187
|
-
} else if (legacyRef.pos) {
|
|
188
|
-
details = {
|
|
189
|
-
type: "linecolumn",
|
|
190
|
-
line: legacyRef.pos.line,
|
|
191
|
-
column: legacyRef.pos.column,
|
|
192
|
-
};
|
|
193
|
-
} else if (legacyRef.header) {
|
|
194
|
-
details = {
|
|
195
|
-
type: "header",
|
|
196
|
-
header: legacyRef.header,
|
|
197
|
-
};
|
|
140
|
+
},
|
|
141
|
+
description:
|
|
142
|
+
"Returns page metadata ordered from most to least recently opened.",
|
|
143
|
+
returns: [{ type: "PageMeta[]", description: "Recently opened pages." }],
|
|
144
|
+
},
|
|
145
|
+
"editor.getLastOpenedMap": {
|
|
146
|
+
callback: (): Record<string, number> => {
|
|
147
|
+
const out: Record<string, number> = {};
|
|
148
|
+
for (const pageMeta of client.ui.viewState.allPages) {
|
|
149
|
+
if (pageMeta.lastOpened) out[pageMeta.name] = pageMeta.lastOpened;
|
|
198
150
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
151
|
+
return out;
|
|
152
|
+
},
|
|
153
|
+
description: `Returns a map of page name to the time it was last opened (epoch milliseconds), for the pages that have ever been opened on this client. This lives outside the object index.`,
|
|
154
|
+
returns: [
|
|
155
|
+
{
|
|
156
|
+
type: "Record<string, number>",
|
|
157
|
+
description: "Page name to last-opened timestamp.",
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
"editor.getViewableExtensions": {
|
|
162
|
+
callback: (): string[] => {
|
|
163
|
+
return [
|
|
164
|
+
...new Set(
|
|
165
|
+
Array.from(
|
|
166
|
+
client.clientSystem.documentEditorHook.documentEditors.values(),
|
|
167
|
+
).flatMap(({ extensions }) => extensions),
|
|
168
|
+
),
|
|
169
|
+
];
|
|
170
|
+
},
|
|
171
|
+
description: `Returns the file extensions that have a document editor registered, i.e. the documents this client can actually open. Extensions carry no leading dot. Which editors are loaded depends on the plugs installed, so this is a property of the client rather than of the space.`,
|
|
172
|
+
returns: [
|
|
173
|
+
{
|
|
174
|
+
type: "string[]",
|
|
175
|
+
description: "Extensions with a registered document editor.",
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
"editor.getText": {
|
|
180
|
+
callback: () => {
|
|
181
|
+
return client.editorView.state.sliceDoc();
|
|
182
|
+
},
|
|
183
|
+
description:
|
|
184
|
+
"Returns the full text of the currently open page or document.",
|
|
185
|
+
returns: [{ type: "string", description: "The editor contents." }],
|
|
186
|
+
},
|
|
187
|
+
"editor.getCurrentLine": {
|
|
188
|
+
callback: (): {
|
|
189
|
+
from: number;
|
|
190
|
+
to: number;
|
|
191
|
+
text: string;
|
|
192
|
+
textWithCursor: string;
|
|
193
|
+
} => {
|
|
194
|
+
const pos = client.editorView.state.selection.main.from;
|
|
195
|
+
const line = client.editorView.state.doc.lineAt(pos);
|
|
196
|
+
return {
|
|
197
|
+
...line,
|
|
198
|
+
textWithCursor:
|
|
199
|
+
line.text.slice(0, pos - line.from) +
|
|
200
|
+
"|^|" +
|
|
201
|
+
line.text.slice(pos - line.from),
|
|
206
202
|
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
203
|
+
},
|
|
204
|
+
description:
|
|
205
|
+
"Returns the current line's range and text, including a `|^|` cursor marker variant.",
|
|
206
|
+
returns: [
|
|
207
|
+
{
|
|
208
|
+
type: "{ from: number; to: number; text: string; textWithCursor: string }",
|
|
209
|
+
description: "The line containing the main selection head.",
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
"editor.setText": {
|
|
214
|
+
callback: (_ctx, newText: string, shouldIsolateHistory = false) => {
|
|
215
|
+
client.contentManager.setEditorText(newText, shouldIsolateHistory);
|
|
216
|
+
},
|
|
217
|
+
description:
|
|
218
|
+
"Updates the editor text with a minimal diff while preserving the cursor when possible.",
|
|
219
|
+
parameters: [
|
|
220
|
+
{
|
|
221
|
+
name: "newText",
|
|
222
|
+
type: "string",
|
|
223
|
+
description: "The complete replacement text.",
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: "shouldIsolateHistory",
|
|
227
|
+
type: "boolean",
|
|
228
|
+
description: "Whether to isolate the change in undo history.",
|
|
229
|
+
optional: true,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
"editor.getCursor": {
|
|
234
|
+
callback: (): number => {
|
|
235
|
+
return client.editorView.state.selection.main.from;
|
|
236
|
+
},
|
|
237
|
+
description:
|
|
238
|
+
"Returns the cursor position as a character offset from the start of the document.",
|
|
239
|
+
returns: [{ type: "number", description: "The cursor offset." }],
|
|
240
|
+
},
|
|
241
|
+
"editor.getSelection": {
|
|
242
|
+
callback: (): { from: number; to: number; text: string } => {
|
|
243
|
+
const selection = client.editorView.state.selection.main;
|
|
244
|
+
const text = client.editorView.state.sliceDoc(
|
|
245
|
+
selection.from,
|
|
246
|
+
selection.to,
|
|
219
247
|
);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
248
|
+
return {
|
|
249
|
+
from: selection.from,
|
|
250
|
+
to: selection.to,
|
|
251
|
+
text,
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
description: "Returns the current selection range and selected text.",
|
|
255
|
+
returns: [
|
|
256
|
+
{
|
|
257
|
+
type: "{ from: number; to: number; text: string }",
|
|
258
|
+
description: "The main editor selection.",
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
"editor.save": {
|
|
263
|
+
callback: () => {
|
|
264
|
+
return client.save(true);
|
|
265
|
+
},
|
|
266
|
+
description: "Forces the current page or document to be saved.",
|
|
267
|
+
},
|
|
268
|
+
"editor.navigate": {
|
|
269
|
+
callback: async (
|
|
270
|
+
_ctx,
|
|
271
|
+
ref: Ref | string,
|
|
272
|
+
replaceState = false,
|
|
273
|
+
newWindow = false,
|
|
274
|
+
) => {
|
|
275
|
+
await client.navigate(
|
|
276
|
+
coerceAndValidateRef(ref),
|
|
277
|
+
replaceState,
|
|
278
|
+
newWindow,
|
|
228
279
|
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
"
|
|
280
|
+
},
|
|
281
|
+
description:
|
|
282
|
+
"Navigates to a page reference without restoring its remembered cursor and scroll position.",
|
|
283
|
+
parameters: [
|
|
284
|
+
{
|
|
285
|
+
name: "ref",
|
|
286
|
+
type: "Ref | string",
|
|
287
|
+
description: "The page reference to navigate to.",
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
name: "replaceState",
|
|
291
|
+
type: "boolean",
|
|
292
|
+
description: "Whether to replace the current browser history state.",
|
|
293
|
+
optional: true,
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: "newWindow",
|
|
297
|
+
type: "boolean",
|
|
298
|
+
description: "Whether to open the reference in a new window.",
|
|
299
|
+
optional: true,
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
examples: [{ code: 'editor.navigate("CHANGELOG@123")' }],
|
|
303
|
+
},
|
|
304
|
+
"editor.open": {
|
|
305
|
+
callback: async (
|
|
306
|
+
_ctx,
|
|
307
|
+
ref: Ref | string,
|
|
308
|
+
replaceState = false,
|
|
309
|
+
newWindow = false,
|
|
310
|
+
) => {
|
|
311
|
+
await client.open(coerceAndValidateRef(ref), replaceState, newWindow);
|
|
312
|
+
},
|
|
313
|
+
description:
|
|
314
|
+
"Opens a page reference and restores its remembered cursor and scroll position when possible.",
|
|
315
|
+
parameters: [
|
|
316
|
+
{
|
|
317
|
+
name: "ref",
|
|
318
|
+
type: "Ref | string",
|
|
319
|
+
description: "The page reference to open.",
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
name: "replaceState",
|
|
323
|
+
type: "boolean",
|
|
324
|
+
description: "Whether to replace the current browser history state.",
|
|
325
|
+
optional: true,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "newWindow",
|
|
329
|
+
type: "boolean",
|
|
330
|
+
description: "Whether to open the reference in a new window.",
|
|
331
|
+
optional: true,
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
examples: [{ code: 'editor.open("CHANGELOG")' }],
|
|
335
|
+
},
|
|
336
|
+
"editor.reloadPage": {
|
|
337
|
+
callback: async () => {
|
|
338
|
+
await client.reloadEditor();
|
|
339
|
+
},
|
|
340
|
+
description: "Force reloads the current page in the editor.",
|
|
341
|
+
},
|
|
342
|
+
"editor.forceLint": {
|
|
343
|
+
callback: () => {
|
|
344
|
+
// `forceLinting` alone is a no-op on unchanged content after the
|
|
345
|
+
// linter's internal "scheduled" flag has been cleared; the effect
|
|
346
|
+
// re-arms it via `needsRefresh`.
|
|
347
|
+
client.editorView.dispatch({
|
|
348
|
+
effects: refreshLintEffect.of(null),
|
|
349
|
+
});
|
|
350
|
+
forceLinting(client.editorView);
|
|
351
|
+
},
|
|
352
|
+
description:
|
|
353
|
+
"Forces editor linting to run, including when the content has not changed.",
|
|
354
|
+
},
|
|
355
|
+
"editor.reloadUI": {
|
|
356
|
+
callback: () => {
|
|
357
|
+
location.reload();
|
|
358
|
+
},
|
|
359
|
+
description: "Force reloads the browser UI.",
|
|
360
|
+
},
|
|
361
|
+
"editor.rebuildEditorState": {
|
|
362
|
+
callback: () => {
|
|
363
|
+
client.rebuildEditorState();
|
|
364
|
+
},
|
|
365
|
+
description:
|
|
366
|
+
"Rebuilds the CodeMirror editor state from the current client configuration.",
|
|
367
|
+
},
|
|
368
|
+
"editor.reloadConfigAndCommands": {
|
|
369
|
+
callback: async () => {
|
|
370
|
+
await client.clientSystem.system.localSyscall("system.loadScripts", []);
|
|
371
|
+
await client.clientSystem.system.localSyscall(
|
|
372
|
+
"system.loadSpaceStyles",
|
|
373
|
+
[],
|
|
374
|
+
);
|
|
375
|
+
client.rebuildEditorState();
|
|
376
|
+
},
|
|
377
|
+
description:
|
|
378
|
+
"Reloads space scripts and styles, then rebuilds the editor state.",
|
|
379
|
+
},
|
|
380
|
+
"editor.invokeCommand": {
|
|
381
|
+
callback: (_ctx, name: string, args?: string[]) => {
|
|
382
|
+
return client.runCommandByName(name, args);
|
|
383
|
+
},
|
|
384
|
+
description: "Invokes a client command by name.",
|
|
385
|
+
parameters: [
|
|
386
|
+
{ name: "name", type: "string", description: "The command name." },
|
|
387
|
+
{
|
|
388
|
+
name: "args",
|
|
389
|
+
type: "string[]",
|
|
390
|
+
description: "Arguments passed to the command.",
|
|
391
|
+
optional: true,
|
|
392
|
+
},
|
|
393
|
+
],
|
|
394
|
+
},
|
|
395
|
+
"editor.updateBakedSections": {
|
|
396
|
+
callback: (): Promise<void> => {
|
|
397
|
+
return updateBakedSections(client);
|
|
398
|
+
},
|
|
399
|
+
description:
|
|
400
|
+
"Re-evaluates every baked section on the current page and replaces each body with its latest output.",
|
|
401
|
+
},
|
|
402
|
+
"editor.openUrl": {
|
|
403
|
+
callback: (_ctx, url: string, existingWindow = false) => {
|
|
404
|
+
client.openUrl(url, existingWindow);
|
|
405
|
+
},
|
|
406
|
+
description: "Opens a URL in the browser.",
|
|
407
|
+
parameters: [
|
|
408
|
+
{ name: "url", type: "string", description: "The URL to open." },
|
|
409
|
+
{
|
|
410
|
+
name: "existingWindow",
|
|
411
|
+
type: "boolean",
|
|
412
|
+
description: "Whether to reuse an existing window.",
|
|
413
|
+
optional: true,
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
},
|
|
417
|
+
"editor.newWindow": {
|
|
418
|
+
callback: () => {
|
|
419
|
+
globalThis.open(
|
|
420
|
+
location.href,
|
|
421
|
+
`rnd${Math.random()}`,
|
|
422
|
+
`width=${globalThis.innerWidth},heigh=${globalThis.innerHeight}`,
|
|
248
423
|
);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
424
|
+
},
|
|
425
|
+
description:
|
|
426
|
+
"Opens the current SilverBullet URL in a new browser window.",
|
|
427
|
+
},
|
|
428
|
+
"editor.goHistory": {
|
|
429
|
+
callback: (_ctx, delta: number) => {
|
|
430
|
+
globalThis.history.go(delta);
|
|
431
|
+
},
|
|
432
|
+
description: "Moves backward or forward through browser history.",
|
|
433
|
+
parameters: [
|
|
434
|
+
{
|
|
435
|
+
name: "delta",
|
|
436
|
+
type: "number",
|
|
437
|
+
description:
|
|
438
|
+
"The relative history offset; negative moves backward and positive moves forward.",
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
},
|
|
442
|
+
"editor.downloadFile": {
|
|
443
|
+
callback: (_ctx, filename: string, dataUrl: string) => {
|
|
444
|
+
const link = document.createElement("a");
|
|
445
|
+
link.href = dataUrl;
|
|
446
|
+
link.download = filename;
|
|
447
|
+
link.click();
|
|
448
|
+
},
|
|
449
|
+
description:
|
|
450
|
+
"Triggers a browser download of a data URL under the given filename.",
|
|
451
|
+
parameters: [
|
|
452
|
+
{
|
|
453
|
+
name: "filename",
|
|
454
|
+
type: "string",
|
|
455
|
+
description: "The downloaded filename.",
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
name: "dataUrl",
|
|
459
|
+
type: "string",
|
|
460
|
+
description: "The data URL to download.",
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
examples: [
|
|
464
|
+
{
|
|
465
|
+
code: 'editor.downloadFile("test.txt", "data:text/plain;base64,SGVsbG8=")',
|
|
466
|
+
},
|
|
467
|
+
],
|
|
468
|
+
},
|
|
469
|
+
"editor.uploadFile": {
|
|
470
|
+
callback: (
|
|
471
|
+
_ctx,
|
|
472
|
+
accept?: string,
|
|
473
|
+
capture?: string,
|
|
474
|
+
): Promise<UploadFile> => {
|
|
475
|
+
return new Promise<UploadFile>((resolve, reject) => {
|
|
476
|
+
const input = document.createElement("input");
|
|
477
|
+
input.type = "file";
|
|
478
|
+
if (accept) {
|
|
479
|
+
input.accept = accept;
|
|
480
|
+
}
|
|
481
|
+
if (capture) {
|
|
482
|
+
input.capture = capture;
|
|
483
|
+
}
|
|
255
484
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
},
|
|
284
|
-
"editor.invokeCommand": (_ctx, name: string, args?: string[]) => {
|
|
285
|
-
return client.runCommandByName(name, args);
|
|
286
|
-
},
|
|
287
|
-
"editor.openUrl": (_ctx, url: string, existingWindow = false) => {
|
|
288
|
-
client.openUrl(url, existingWindow);
|
|
289
|
-
},
|
|
290
|
-
"editor.newWindow": () => {
|
|
291
|
-
globalThis.open(
|
|
292
|
-
location.href,
|
|
293
|
-
`rnd${Math.random()}`,
|
|
294
|
-
`width=${globalThis.innerWidth},heigh=${globalThis.innerHeight}`,
|
|
295
|
-
);
|
|
296
|
-
},
|
|
297
|
-
"editor.goHistory": (_ctx, delta: number) => {
|
|
298
|
-
globalThis.history.go(delta);
|
|
299
|
-
},
|
|
300
|
-
"editor.downloadFile": (_ctx, filename: string, dataUrl: string) => {
|
|
301
|
-
const link = document.createElement("a");
|
|
302
|
-
link.href = dataUrl;
|
|
303
|
-
link.download = filename;
|
|
304
|
-
link.click();
|
|
305
|
-
},
|
|
306
|
-
"editor.uploadFile": (
|
|
307
|
-
_ctx,
|
|
308
|
-
accept?: string,
|
|
309
|
-
capture?: string,
|
|
310
|
-
): Promise<UploadFile> => {
|
|
311
|
-
return new Promise<UploadFile>((resolve, reject) => {
|
|
312
|
-
const input = document.createElement("input");
|
|
313
|
-
input.type = "file";
|
|
314
|
-
if (accept) {
|
|
315
|
-
input.accept = accept;
|
|
316
|
-
}
|
|
317
|
-
if (capture) {
|
|
318
|
-
input.capture = capture;
|
|
319
|
-
}
|
|
485
|
+
input.onchange = () => {
|
|
486
|
+
const file = input.files?.item(0);
|
|
487
|
+
if (!file) {
|
|
488
|
+
reject(new Error("No file found"));
|
|
489
|
+
} else {
|
|
490
|
+
const reader = new FileReader();
|
|
491
|
+
reader.readAsArrayBuffer(file);
|
|
492
|
+
reader.onloadend = async (evt) => {
|
|
493
|
+
if (evt.target?.readyState === FileReader.DONE) {
|
|
494
|
+
resolve({
|
|
495
|
+
name: file.name,
|
|
496
|
+
contentType: file.type,
|
|
497
|
+
content: new Uint8Array(await file.arrayBuffer()),
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
reader.onabort = (e) => {
|
|
502
|
+
reject(e);
|
|
503
|
+
};
|
|
504
|
+
reader.onerror = (e) => {
|
|
505
|
+
reject(e);
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
input.onabort = (e) => {
|
|
510
|
+
reject(e);
|
|
511
|
+
};
|
|
320
512
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
513
|
+
input.style.display = "none";
|
|
514
|
+
document.body.appendChild(input);
|
|
515
|
+
input.click();
|
|
516
|
+
setTimeout(() => document.body.removeChild(input), 1000);
|
|
517
|
+
});
|
|
518
|
+
},
|
|
519
|
+
description:
|
|
520
|
+
"Opens the browser's native file picker and returns the selected file's bytes and metadata.",
|
|
521
|
+
parameters: [
|
|
522
|
+
{
|
|
523
|
+
name: "accept",
|
|
524
|
+
type: "string",
|
|
525
|
+
description: "Accepted file types for the file input.",
|
|
526
|
+
optional: true,
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
name: "capture",
|
|
530
|
+
type: "string",
|
|
531
|
+
description: "The media capture mode for the file input.",
|
|
532
|
+
optional: true,
|
|
533
|
+
},
|
|
534
|
+
],
|
|
535
|
+
returns: [
|
|
536
|
+
{
|
|
537
|
+
type: "UploadFile",
|
|
538
|
+
description: "The selected file's name, content type, and bytes.",
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
examples: [
|
|
542
|
+
{
|
|
543
|
+
code: 'local file = editor.uploadFile(".txt")\nprint(file.name)',
|
|
544
|
+
},
|
|
545
|
+
],
|
|
546
|
+
},
|
|
547
|
+
"editor.flashNotification": {
|
|
548
|
+
callback: (
|
|
549
|
+
_ctx,
|
|
550
|
+
message: string,
|
|
551
|
+
type: NotificationType = "info",
|
|
552
|
+
options?: { timeout?: number; actions?: NotificationAction[] },
|
|
553
|
+
) => {
|
|
554
|
+
client.ui.flashNotification(message, type, options);
|
|
555
|
+
},
|
|
556
|
+
description: "Shows a flash notification in the editor UI.",
|
|
557
|
+
parameters: [
|
|
558
|
+
{
|
|
559
|
+
name: "message",
|
|
560
|
+
type: "string",
|
|
561
|
+
description: "The message to display.",
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
name: "type",
|
|
565
|
+
type: "NotificationType",
|
|
566
|
+
description:
|
|
567
|
+
'The notification severity: "info", "error", or "warning".',
|
|
568
|
+
optional: true,
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: "options",
|
|
572
|
+
type: "{ timeout?: number; actions?: NotificationAction[] }",
|
|
573
|
+
description:
|
|
574
|
+
"Optional timeout and action buttons. A timeout of 0 keeps the notification visible until dismissed.",
|
|
575
|
+
optional: true,
|
|
576
|
+
},
|
|
577
|
+
],
|
|
578
|
+
examples: [
|
|
579
|
+
{
|
|
580
|
+
code: 'editor.flashNotification("Update available", "warning", {\n timeout = 0,\n actions = {{\n name = "Reload",\n run = function() editor.reloadUI() end\n }}\n})',
|
|
581
|
+
},
|
|
582
|
+
],
|
|
583
|
+
},
|
|
584
|
+
"editor.filterBox": {
|
|
585
|
+
callback: (
|
|
586
|
+
_ctx,
|
|
587
|
+
label: string,
|
|
588
|
+
options: FilterOption[],
|
|
589
|
+
helpText = "",
|
|
590
|
+
placeHolder = "",
|
|
591
|
+
): Promise<FilterOption | undefined> => {
|
|
592
|
+
return client.ui.filterBox(label, options, helpText, placeHolder);
|
|
593
|
+
},
|
|
594
|
+
description:
|
|
595
|
+
"Shows a filterable option picker similar to the page navigator.",
|
|
596
|
+
parameters: [
|
|
597
|
+
{
|
|
598
|
+
name: "label",
|
|
599
|
+
type: "string",
|
|
600
|
+
description: "The label shown beside the filter input.",
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
name: "options",
|
|
604
|
+
type: "FilterOption[]",
|
|
605
|
+
description: "The available options.",
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
name: "helpText",
|
|
609
|
+
type: "string",
|
|
610
|
+
description: "Help text shown below the picker.",
|
|
611
|
+
optional: true,
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
name: "placeHolder",
|
|
615
|
+
type: "string",
|
|
616
|
+
description: "Placeholder text for the filter input.",
|
|
617
|
+
optional: true,
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
returns: [
|
|
621
|
+
{
|
|
622
|
+
type: "FilterOption | undefined",
|
|
623
|
+
description: "The selected option, or undefined if dismissed.",
|
|
624
|
+
},
|
|
625
|
+
],
|
|
626
|
+
examples: [
|
|
627
|
+
{
|
|
628
|
+
code: 'local result = editor.filterBox("Select:", {\n {name = "Option 1", value = "1"},\n {name = "Option 2", value = "2", description = "More details"}\n})',
|
|
629
|
+
},
|
|
630
|
+
],
|
|
631
|
+
},
|
|
632
|
+
"editor.showPanel": {
|
|
633
|
+
callback: async (
|
|
634
|
+
_ctx,
|
|
635
|
+
id: string,
|
|
636
|
+
mode: PanelMode,
|
|
637
|
+
html: HTMLElement | HTMLElement[] | string,
|
|
638
|
+
script: string,
|
|
639
|
+
) => {
|
|
640
|
+
// The other half of the shared-slot arbitration in editor_ui.tsx: a
|
|
641
|
+
// plug opening one of these slots closes the navigator's occupant.
|
|
642
|
+
if (id === "modal" || id === "bhs") {
|
|
643
|
+
await hideNavigatorSlot(id, undefined, {
|
|
644
|
+
restoreDisplaced: false,
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
client.ui.viewDispatch({
|
|
648
|
+
type: "show-panel",
|
|
649
|
+
id: id as any,
|
|
650
|
+
config: { html, script, mode },
|
|
651
|
+
});
|
|
652
|
+
setTimeout(() => {
|
|
653
|
+
// Dummy dispatch to rerender the editor and toggle the panel
|
|
654
|
+
client.editorView.dispatch({});
|
|
655
|
+
});
|
|
656
|
+
},
|
|
657
|
+
description: "Shows an HTML panel in a specified editor UI location.",
|
|
658
|
+
parameters: [
|
|
659
|
+
{
|
|
660
|
+
name: "id",
|
|
661
|
+
type: "string",
|
|
662
|
+
description: "The panel location identifier.",
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
name: "mode",
|
|
666
|
+
type: "number | string",
|
|
667
|
+
description: "The panel display mode or size.",
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
name: "html",
|
|
671
|
+
type: "HTMLElement | HTMLElement[] | string",
|
|
672
|
+
description: "The panel content.",
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
name: "script",
|
|
676
|
+
type: "string",
|
|
677
|
+
description: "A script associated with the panel content.",
|
|
678
|
+
},
|
|
679
|
+
],
|
|
680
|
+
},
|
|
681
|
+
"editor.focus": {
|
|
682
|
+
callback: () => {
|
|
683
|
+
client.focus();
|
|
684
|
+
},
|
|
685
|
+
description: "Returns focus to the main editor.",
|
|
686
|
+
},
|
|
687
|
+
"editor.getFocusedPanelSlot": {
|
|
688
|
+
callback: (): PanelSlot | undefined => {
|
|
689
|
+
const active = document.activeElement;
|
|
690
|
+
if (!(active instanceof HTMLIFrameElement)) return undefined;
|
|
691
|
+
const slot = active.dataset.slot;
|
|
692
|
+
return slot === "lhs" ||
|
|
693
|
+
slot === "rhs" ||
|
|
694
|
+
slot === "bhs" ||
|
|
695
|
+
slot === "modal"
|
|
696
|
+
? slot
|
|
697
|
+
: undefined;
|
|
698
|
+
},
|
|
699
|
+
description:
|
|
700
|
+
"Returns the slot of the panel (keyed or legacy) whose iframe currently holds focus, or undefined if none does.",
|
|
701
|
+
returns: [
|
|
702
|
+
{
|
|
703
|
+
type: '"lhs" | "rhs" | "bhs" | "modal" | undefined',
|
|
704
|
+
description:
|
|
705
|
+
"The focused panel's slot, or undefined if no panel iframe has focus.",
|
|
706
|
+
},
|
|
707
|
+
],
|
|
708
|
+
},
|
|
709
|
+
"editor.hidePanel": {
|
|
710
|
+
callback: async (_ctx, id: string) => {
|
|
711
|
+
// The navigator owns this slot whenever it is the thing showing
|
|
712
|
+
// there, so "hide the panel at this location" has to reach it too.
|
|
713
|
+
await hideNavigatorSlot(id);
|
|
714
|
+
client.ui.viewDispatch({
|
|
715
|
+
type: "hide-panel",
|
|
716
|
+
id: id as any,
|
|
717
|
+
});
|
|
718
|
+
setTimeout(() => {
|
|
719
|
+
// Dummy dispatch to rerender the editor and toggle the panel
|
|
720
|
+
client.editorView.dispatch({});
|
|
721
|
+
});
|
|
722
|
+
},
|
|
723
|
+
description: "Hides the panel at a specified editor UI location.",
|
|
724
|
+
parameters: [
|
|
725
|
+
{
|
|
726
|
+
name: "id",
|
|
727
|
+
type: "string",
|
|
728
|
+
description: "The panel location identifier.",
|
|
729
|
+
},
|
|
730
|
+
],
|
|
731
|
+
},
|
|
732
|
+
"editor.showProgress": {
|
|
733
|
+
callback: (
|
|
734
|
+
_ctx,
|
|
735
|
+
progressType: "sync" | "index",
|
|
736
|
+
progressPercentage?: number,
|
|
737
|
+
) => {
|
|
738
|
+
client.ui.showProgress(progressType, progressPercentage);
|
|
739
|
+
},
|
|
740
|
+
description:
|
|
741
|
+
"Shows, updates, or hides a sync or indexing progress indicator.",
|
|
742
|
+
parameters: [
|
|
743
|
+
{
|
|
744
|
+
name: "progressType",
|
|
745
|
+
type: "sync | index",
|
|
746
|
+
description: "The operation represented by the indicator.",
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
name: "progressPercentage",
|
|
750
|
+
type: "number",
|
|
751
|
+
description:
|
|
752
|
+
"Completion percentage, or undefined to hide the indicator.",
|
|
753
|
+
optional: true,
|
|
754
|
+
},
|
|
755
|
+
],
|
|
756
|
+
},
|
|
757
|
+
"editor.insertAtPos": {
|
|
758
|
+
callback: (
|
|
759
|
+
_ctx,
|
|
760
|
+
text: string,
|
|
761
|
+
pos: number,
|
|
762
|
+
cursorPlaceHolder = false,
|
|
763
|
+
) => {
|
|
764
|
+
let cursorPlaceholderPos = -1;
|
|
765
|
+
if (cursorPlaceHolder) {
|
|
766
|
+
cursorPlaceholderPos = text.indexOf("|^|");
|
|
767
|
+
if (cursorPlaceholderPos !== -1) {
|
|
768
|
+
text =
|
|
769
|
+
text.slice(0, cursorPlaceholderPos) +
|
|
770
|
+
text.slice(cursorPlaceholderPos + 3);
|
|
325
771
|
} else {
|
|
326
|
-
|
|
327
|
-
reader.readAsArrayBuffer(file);
|
|
328
|
-
reader.onloadend = async (evt) => {
|
|
329
|
-
if (evt.target?.readyState === FileReader.DONE) {
|
|
330
|
-
resolve({
|
|
331
|
-
name: file.name,
|
|
332
|
-
contentType: file.type,
|
|
333
|
-
content: new Uint8Array(await file.arrayBuffer()),
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
reader.onabort = (e) => {
|
|
338
|
-
reject(e);
|
|
339
|
-
};
|
|
340
|
-
reader.onerror = (e) => {
|
|
341
|
-
reject(e);
|
|
342
|
-
};
|
|
772
|
+
cursorPlaceHolder = false;
|
|
343
773
|
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
client.focus();
|
|
391
|
-
},
|
|
392
|
-
"editor.hidePanel": (_ctx, id: string) => {
|
|
393
|
-
client.ui.viewDispatch({
|
|
394
|
-
type: "hide-panel",
|
|
395
|
-
id: id as any,
|
|
396
|
-
});
|
|
397
|
-
setTimeout(() => {
|
|
398
|
-
// Dummy dispatch to rerender the editor and toggle the panel
|
|
399
|
-
client.editorView.dispatch({});
|
|
400
|
-
});
|
|
401
|
-
},
|
|
402
|
-
"editor.showProgress": (
|
|
403
|
-
_ctx,
|
|
404
|
-
progressPercentage?: number,
|
|
405
|
-
progressType?: "sync" | "index",
|
|
406
|
-
) => {
|
|
407
|
-
client.ui.showProgress(progressPercentage, progressType);
|
|
408
|
-
},
|
|
409
|
-
"editor.insertAtPos": (
|
|
410
|
-
_ctx,
|
|
411
|
-
text: string,
|
|
412
|
-
pos: number,
|
|
413
|
-
cursorPlaceHolder = false,
|
|
414
|
-
) => {
|
|
415
|
-
let cursorPlaceholderPos = -1;
|
|
416
|
-
if (cursorPlaceHolder) {
|
|
417
|
-
cursorPlaceholderPos = text.indexOf("|^|");
|
|
418
|
-
if (cursorPlaceholderPos !== -1) {
|
|
774
|
+
}
|
|
775
|
+
client.editorView.dispatch({
|
|
776
|
+
changes: {
|
|
777
|
+
insert: text,
|
|
778
|
+
from: pos,
|
|
779
|
+
},
|
|
780
|
+
});
|
|
781
|
+
if (cursorPlaceHolder) {
|
|
782
|
+
const cursorPos = pos + cursorPlaceholderPos;
|
|
783
|
+
client.editorView.dispatch({
|
|
784
|
+
selection: {
|
|
785
|
+
anchor: cursorPos,
|
|
786
|
+
},
|
|
787
|
+
effects: [EditorView.scrollIntoView(cursorPos)],
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
description:
|
|
792
|
+
"Inserts text at a character offset, optionally placing the cursor at a `|^|` marker.",
|
|
793
|
+
parameters: [
|
|
794
|
+
{ name: "text", type: "string", description: "The text to insert." },
|
|
795
|
+
{
|
|
796
|
+
name: "pos",
|
|
797
|
+
type: "number",
|
|
798
|
+
description: "The character offset at which to insert.",
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
name: "cursorPlaceHolder",
|
|
802
|
+
type: "boolean",
|
|
803
|
+
description:
|
|
804
|
+
"Whether to remove `|^|` and move the cursor to its position.",
|
|
805
|
+
optional: true,
|
|
806
|
+
},
|
|
807
|
+
],
|
|
808
|
+
},
|
|
809
|
+
"editor.replaceRange": {
|
|
810
|
+
callback: (
|
|
811
|
+
_ctx,
|
|
812
|
+
from: number,
|
|
813
|
+
to: number,
|
|
814
|
+
text: string,
|
|
815
|
+
cursorPlaceHolder = false,
|
|
816
|
+
) => {
|
|
817
|
+
let cursorPlaceholderPos = -1;
|
|
818
|
+
if (cursorPlaceHolder) {
|
|
819
|
+
cursorPlaceholderPos = text.indexOf("|^|");
|
|
419
820
|
text =
|
|
420
821
|
text.slice(0, cursorPlaceholderPos) +
|
|
421
822
|
text.slice(cursorPlaceholderPos + 3);
|
|
422
|
-
} else {
|
|
423
|
-
cursorPlaceHolder = false;
|
|
424
823
|
}
|
|
425
|
-
}
|
|
426
|
-
client.editorView.dispatch({
|
|
427
|
-
changes: {
|
|
428
|
-
insert: text,
|
|
429
|
-
from: pos,
|
|
430
|
-
},
|
|
431
|
-
});
|
|
432
|
-
if (cursorPlaceHolder) {
|
|
433
|
-
const cursorPos = pos + cursorPlaceholderPos;
|
|
434
824
|
client.editorView.dispatch({
|
|
435
|
-
|
|
436
|
-
|
|
825
|
+
changes: {
|
|
826
|
+
insert: text,
|
|
827
|
+
from: from,
|
|
828
|
+
to: to,
|
|
437
829
|
},
|
|
438
|
-
effects: [EditorView.scrollIntoView(cursorPos)],
|
|
439
830
|
});
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
831
|
+
if (cursorPlaceHolder) {
|
|
832
|
+
const cursorPos = from + cursorPlaceholderPos;
|
|
833
|
+
client.editorView.dispatch({
|
|
834
|
+
selection: {
|
|
835
|
+
anchor: cursorPos,
|
|
836
|
+
},
|
|
837
|
+
effects: [EditorView.scrollIntoView(cursorPos)],
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
},
|
|
841
|
+
description:
|
|
842
|
+
"Replaces a text range, optionally placing the cursor at a `|^|` marker in the replacement.",
|
|
843
|
+
parameters: [
|
|
844
|
+
{
|
|
845
|
+
name: "from",
|
|
846
|
+
type: "number",
|
|
847
|
+
description: "The start offset of the range.",
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
name: "to",
|
|
851
|
+
type: "number",
|
|
852
|
+
description: "The end offset of the range.",
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
name: "text",
|
|
856
|
+
type: "string",
|
|
857
|
+
description: "The replacement text.",
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
name: "cursorPlaceHolder",
|
|
861
|
+
type: "boolean",
|
|
862
|
+
description:
|
|
863
|
+
"Whether to remove `|^|` and move the cursor to its position.",
|
|
864
|
+
optional: true,
|
|
865
|
+
},
|
|
866
|
+
],
|
|
867
|
+
},
|
|
868
|
+
"editor.moveCursor": {
|
|
869
|
+
callback: (_ctx, pos: number, center = false) => {
|
|
870
|
+
// Always scroll into view so callers don't strand the cursor
|
|
871
|
+
// off-screen; `nearest` (default) is a no-op when already visible.
|
|
872
|
+
client.editorView.dispatch({
|
|
873
|
+
selection: { anchor: pos },
|
|
874
|
+
effects: [
|
|
875
|
+
EditorView.scrollIntoView(pos, center ? { y: "center" } : {}),
|
|
876
|
+
],
|
|
877
|
+
});
|
|
878
|
+
client.editorView.focus();
|
|
879
|
+
},
|
|
880
|
+
description:
|
|
881
|
+
"Moves and focuses the cursor at a character offset, scrolling it into view.",
|
|
882
|
+
parameters: [
|
|
883
|
+
{
|
|
884
|
+
name: "pos",
|
|
885
|
+
type: "number",
|
|
886
|
+
description: "The character offset to move to.",
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
name: "center",
|
|
890
|
+
type: "boolean",
|
|
891
|
+
description: "Whether to vertically center the cursor.",
|
|
892
|
+
optional: true,
|
|
893
|
+
},
|
|
894
|
+
],
|
|
895
|
+
},
|
|
896
|
+
"editor.moveCursorToLine": {
|
|
897
|
+
callback: (_ctx, line: number, column = 1, center = false) => {
|
|
898
|
+
const cmLine = client.editorView.state.doc.line(line);
|
|
899
|
+
const offset = Math.max(0, Math.min(cmLine.length, column - 1));
|
|
900
|
+
const moveCursor = syscalls["editor.moveCursor"];
|
|
901
|
+
const moveCursorCallback =
|
|
902
|
+
typeof moveCursor === "function" ? moveCursor : moveCursor.callback;
|
|
903
|
+
moveCursorCallback(_ctx, cmLine.from + offset, center);
|
|
904
|
+
},
|
|
905
|
+
description:
|
|
906
|
+
"Moves the cursor to a one-based line and column, clamping the column to the line length.",
|
|
907
|
+
parameters: [
|
|
908
|
+
{
|
|
909
|
+
name: "line",
|
|
910
|
+
type: "number",
|
|
911
|
+
description: "The one-based line number.",
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
name: "column",
|
|
915
|
+
type: "number",
|
|
916
|
+
description: "The one-based column number.",
|
|
917
|
+
optional: true,
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
name: "center",
|
|
921
|
+
type: "boolean",
|
|
922
|
+
description: "Whether to vertically center the cursor.",
|
|
923
|
+
optional: true,
|
|
924
|
+
},
|
|
925
|
+
],
|
|
926
|
+
},
|
|
927
|
+
"editor.setSelection": {
|
|
928
|
+
callback: (_ctx, from: number, to: number) => {
|
|
465
929
|
client.editorView.dispatch({
|
|
466
930
|
selection: {
|
|
467
|
-
anchor:
|
|
931
|
+
anchor: from,
|
|
932
|
+
head: to,
|
|
468
933
|
},
|
|
469
|
-
effects: [EditorView.scrollIntoView(cursorPos)],
|
|
470
934
|
});
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
_ctx,
|
|
486
|
-
line: number,
|
|
487
|
-
column = 1,
|
|
488
|
-
center = false,
|
|
489
|
-
) => {
|
|
490
|
-
// CodeMirror already keeps information about lines
|
|
491
|
-
const cmLine = client.editorView.state.doc.line(line);
|
|
492
|
-
// How much to move inside the line, column number starts from 1
|
|
493
|
-
const offset = Math.max(0, Math.min(cmLine.length, column - 1));
|
|
494
|
-
// Just reuse the implementation above
|
|
495
|
-
syscalls["editor.moveCursor"](_ctx, cmLine.from + offset, center);
|
|
496
|
-
},
|
|
497
|
-
"editor.setSelection": (_ctx, from: number, to: number) => {
|
|
498
|
-
client.editorView.dispatch({
|
|
499
|
-
selection: {
|
|
500
|
-
anchor: from,
|
|
501
|
-
head: to,
|
|
502
|
-
},
|
|
503
|
-
});
|
|
935
|
+
},
|
|
936
|
+
description: "Sets the main editor selection to a character range.",
|
|
937
|
+
parameters: [
|
|
938
|
+
{
|
|
939
|
+
name: "from",
|
|
940
|
+
type: "number",
|
|
941
|
+
description: "The selection anchor offset.",
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
name: "to",
|
|
945
|
+
type: "number",
|
|
946
|
+
description: "The selection head offset.",
|
|
947
|
+
},
|
|
948
|
+
],
|
|
504
949
|
},
|
|
505
950
|
|
|
506
|
-
"editor.insertAtCursor":
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
text
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
},
|
|
555
|
-
"editor.
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
951
|
+
"editor.insertAtCursor": {
|
|
952
|
+
callback: (
|
|
953
|
+
_ctx,
|
|
954
|
+
text: string,
|
|
955
|
+
scrollIntoView = false,
|
|
956
|
+
cursorPlaceHolder = false,
|
|
957
|
+
) => {
|
|
958
|
+
const editorView = client.editorView;
|
|
959
|
+
const from = editorView.state.selection.main.from;
|
|
960
|
+
const cursorPlaceholderPos = text.indexOf("|^|");
|
|
961
|
+
if (cursorPlaceHolder && cursorPlaceholderPos !== -1) {
|
|
962
|
+
text =
|
|
963
|
+
text.slice(0, cursorPlaceholderPos) +
|
|
964
|
+
text.slice(cursorPlaceholderPos + 3);
|
|
965
|
+
} else {
|
|
966
|
+
cursorPlaceHolder = false;
|
|
967
|
+
}
|
|
968
|
+
editorView.dispatch({
|
|
969
|
+
changes: {
|
|
970
|
+
insert: text,
|
|
971
|
+
from: from,
|
|
972
|
+
},
|
|
973
|
+
selection: {
|
|
974
|
+
anchor: cursorPlaceHolder
|
|
975
|
+
? from + cursorPlaceholderPos
|
|
976
|
+
: from + text.length,
|
|
977
|
+
},
|
|
978
|
+
scrollIntoView,
|
|
979
|
+
});
|
|
980
|
+
},
|
|
981
|
+
description:
|
|
982
|
+
"Inserts text at the cursor and moves the cursor after it or to an optional `|^|` marker.",
|
|
983
|
+
parameters: [
|
|
984
|
+
{ name: "text", type: "string", description: "The text to insert." },
|
|
985
|
+
{
|
|
986
|
+
name: "scrollIntoView",
|
|
987
|
+
type: "boolean",
|
|
988
|
+
description: "Whether to scroll the new cursor position into view.",
|
|
989
|
+
optional: true,
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
name: "cursorPlaceHolder",
|
|
993
|
+
type: "boolean",
|
|
994
|
+
description:
|
|
995
|
+
"Whether to remove `|^|` and move the cursor to its position.",
|
|
996
|
+
optional: true,
|
|
997
|
+
},
|
|
998
|
+
],
|
|
999
|
+
},
|
|
1000
|
+
"editor.dispatch": {
|
|
1001
|
+
callback: (_ctx, change: Transaction) => {
|
|
1002
|
+
client.editorView.dispatch(change);
|
|
1003
|
+
},
|
|
1004
|
+
description: "Dispatches a CodeMirror transaction to the editor view.",
|
|
1005
|
+
parameters: [
|
|
1006
|
+
{
|
|
1007
|
+
name: "change",
|
|
1008
|
+
type: "Transaction",
|
|
1009
|
+
description: "The CodeMirror transaction to dispatch.",
|
|
1010
|
+
},
|
|
1011
|
+
],
|
|
1012
|
+
},
|
|
1013
|
+
"editor.prompt": {
|
|
1014
|
+
callback: (
|
|
1015
|
+
_ctx,
|
|
1016
|
+
message: string,
|
|
1017
|
+
defaultValue = "",
|
|
1018
|
+
): Promise<string | undefined> => {
|
|
1019
|
+
return client.ui.prompt(message, defaultValue);
|
|
1020
|
+
},
|
|
1021
|
+
description: "Prompts the user for text input.",
|
|
1022
|
+
parameters: [
|
|
1023
|
+
{
|
|
1024
|
+
name: "message",
|
|
1025
|
+
type: "string",
|
|
1026
|
+
description: "The prompt message.",
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
name: "defaultValue",
|
|
1030
|
+
type: "string",
|
|
1031
|
+
description: "The initial input value.",
|
|
1032
|
+
optional: true,
|
|
1033
|
+
},
|
|
1034
|
+
],
|
|
1035
|
+
returns: [
|
|
1036
|
+
{
|
|
1037
|
+
type: "string | undefined",
|
|
1038
|
+
description: "The entered text, or undefined if dismissed.",
|
|
1039
|
+
},
|
|
1040
|
+
],
|
|
1041
|
+
},
|
|
1042
|
+
"editor.confirm": {
|
|
1043
|
+
callback: (
|
|
1044
|
+
_ctx,
|
|
1045
|
+
message: string,
|
|
1046
|
+
options?: { destructive?: boolean },
|
|
1047
|
+
): Promise<boolean> => {
|
|
1048
|
+
return client.ui.confirm(message, options);
|
|
1049
|
+
},
|
|
1050
|
+
description: "Prompts the user to confirm or cancel an action.",
|
|
1051
|
+
parameters: [
|
|
1052
|
+
{
|
|
1053
|
+
name: "message",
|
|
1054
|
+
type: "string",
|
|
1055
|
+
description: "The confirmation message.",
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
name: "options",
|
|
1059
|
+
type: "{ destructive?: boolean }",
|
|
1060
|
+
description: "Optional dialog styling settings.",
|
|
1061
|
+
optional: true,
|
|
1062
|
+
},
|
|
1063
|
+
],
|
|
1064
|
+
returns: [
|
|
1065
|
+
{ type: "boolean", description: "Whether the user confirmed." },
|
|
1066
|
+
],
|
|
1067
|
+
},
|
|
1068
|
+
"editor.alert": {
|
|
1069
|
+
callback: (_ctx, message: string) => {
|
|
1070
|
+
alert(message);
|
|
1071
|
+
},
|
|
1072
|
+
description: "Shows a browser alert dialog.",
|
|
1073
|
+
parameters: [
|
|
1074
|
+
{
|
|
1075
|
+
name: "message",
|
|
1076
|
+
type: "string",
|
|
1077
|
+
description: "The alert message.",
|
|
1078
|
+
},
|
|
1079
|
+
],
|
|
1080
|
+
},
|
|
1081
|
+
"editor.getUiOption": {
|
|
1082
|
+
callback: (_ctx, key: string): any => {
|
|
1083
|
+
return (client.ui.viewState.uiOptions as any)[key];
|
|
1084
|
+
},
|
|
1085
|
+
description: "Returns the current value of an editor UI option.",
|
|
1086
|
+
parameters: [
|
|
1087
|
+
{ name: "key", type: "string", description: "The UI option key." },
|
|
1088
|
+
],
|
|
1089
|
+
returns: [{ type: "any", description: "The option value." }],
|
|
1090
|
+
},
|
|
1091
|
+
"editor.setUiOption": {
|
|
1092
|
+
callback: (_ctx, key: string, value: any) => {
|
|
1093
|
+
client.ui.viewDispatch({
|
|
1094
|
+
type: "set-ui-option",
|
|
1095
|
+
key,
|
|
1096
|
+
value,
|
|
1097
|
+
});
|
|
1098
|
+
void client.reloadEditor();
|
|
1099
|
+
},
|
|
1100
|
+
description: "Sets an editor UI option and reloads the editor.",
|
|
1101
|
+
parameters: [
|
|
1102
|
+
{ name: "key", type: "string", description: "The UI option key." },
|
|
1103
|
+
{ name: "value", type: "any", description: "The option value." },
|
|
1104
|
+
],
|
|
1105
|
+
},
|
|
1106
|
+
"editor.vimEx": {
|
|
1107
|
+
callback: (_ctx, exCommand: string) => {
|
|
1108
|
+
const vimMod = getVimModule();
|
|
1109
|
+
if (!vimMod) {
|
|
1110
|
+
throw new Error("Vim module not loaded.");
|
|
1111
|
+
}
|
|
1112
|
+
const cm = vimMod.getCM(client.editorView);
|
|
1113
|
+
if (cm?.state.vim) {
|
|
1114
|
+
return vimMod.Vim.handleEx(cm as any, exCommand);
|
|
609
1115
|
} else {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
1116
|
+
throw new Error("Vim mode not active or not initialized.");
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
description: "Executes a Vim Ex command in the active Vim-mode editor.",
|
|
1120
|
+
parameters: [
|
|
1121
|
+
{
|
|
1122
|
+
name: "exCommand",
|
|
1123
|
+
type: "string",
|
|
1124
|
+
description: "The Ex command to execute.",
|
|
1125
|
+
},
|
|
1126
|
+
],
|
|
1127
|
+
},
|
|
1128
|
+
"editor.configureVimMode": {
|
|
1129
|
+
callback: () => {
|
|
1130
|
+
const vimMod = getVimModule();
|
|
1131
|
+
if (!vimMod) {
|
|
1132
|
+
throw new Error("Vim module not loaded.");
|
|
1133
|
+
}
|
|
1134
|
+
const { Vim } = vimMod;
|
|
1135
|
+
Vim.mapCommand("o", "action", "newline-continue-markup", {}, {});
|
|
1136
|
+
Vim.mapCommand("O", "action", "back-newline-continue-markup", {}, {});
|
|
1137
|
+
Vim.unmap("<C-q>", undefined as any);
|
|
1138
|
+
Vim.defineAction("newline-continue-markup", (cm) => {
|
|
614
1139
|
Vim.handleKey(cm, "A", "+input");
|
|
615
|
-
// Insert a newline using the continue markup thing
|
|
616
1140
|
insertNewlineContinueMarkup(client.editorView) ||
|
|
617
1141
|
insertNewlineAndIndent(client.editorView);
|
|
618
|
-
}
|
|
619
|
-
|
|
1142
|
+
});
|
|
1143
|
+
Vim.defineAction("back-newline-continue-markup", (cm) => {
|
|
1144
|
+
const pos = client.editorView.state.selection.main.from;
|
|
1145
|
+
const line = client.editorView.state.doc.lineAt(pos).number;
|
|
1146
|
+
if (line === 1) {
|
|
1147
|
+
Vim.handleKey(cm, "0", "+input");
|
|
1148
|
+
insertNewline(client.editorView);
|
|
1149
|
+
Vim.handleKey(cm, "k", "+input");
|
|
1150
|
+
Vim.handleKey(cm, "i", "+input");
|
|
1151
|
+
} else {
|
|
1152
|
+
Vim.handleKey(cm, "k", "+input");
|
|
1153
|
+
Vim.handleKey(cm, "A", "+input");
|
|
1154
|
+
insertNewlineContinueMarkup(client.editorView) ||
|
|
1155
|
+
insertNewlineAndIndent(client.editorView);
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
620
1158
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
1159
|
+
const config = client.config.get<VimConfig>("vim", {});
|
|
1160
|
+
if (config) {
|
|
1161
|
+
config.unmap?.forEach((binding) => {
|
|
1162
|
+
if (typeof binding === "string") {
|
|
1163
|
+
console.log(`Unmapping ${binding}`);
|
|
1164
|
+
// @ts-expect-error: unmap expects a string for the mode, this is problematic with Ex mappings which requires undefined or false
|
|
1165
|
+
Vim.unmap(binding, undefined);
|
|
1166
|
+
} else if (binding.key) {
|
|
1167
|
+
console.log(
|
|
1168
|
+
`Unmapping ${binding.key} in ${binding.mode ?? "normal"}`,
|
|
1169
|
+
);
|
|
1170
|
+
Vim.unmap(binding.key, binding.mode ?? "normal");
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
config.map?.forEach(({ map, to, mode }) => {
|
|
1174
|
+
console.log(`Mapping ${map} to ${to} for ${mode ?? "normal"}`);
|
|
1175
|
+
Vim.map(map, to, mode ?? "normal");
|
|
1176
|
+
});
|
|
1177
|
+
config.noremap?.forEach(({ map, to, mode }) => {
|
|
1178
|
+
console.log(`Noremapping ${map} to ${to} for ${mode ?? "normal"}`);
|
|
1179
|
+
Vim.noremap(map, to, mode ?? "normal");
|
|
1180
|
+
});
|
|
1181
|
+
config.commands?.forEach(({ ex, command }) => {
|
|
1182
|
+
console.log(`Mapping command '${command}' to Ex ${ex}`);
|
|
1183
|
+
Vim.defineEx(ex, "", (_, params) =>
|
|
1184
|
+
client.runCommandByName(command, params.args),
|
|
632
1185
|
);
|
|
633
|
-
|
|
634
|
-
|
|
1186
|
+
});
|
|
1187
|
+
} else {
|
|
1188
|
+
console.log("No vim config found");
|
|
1189
|
+
}
|
|
1190
|
+
},
|
|
1191
|
+
description:
|
|
1192
|
+
"Configures CodeMirror Vim mode from the current SilverBullet Vim settings.",
|
|
1193
|
+
},
|
|
1194
|
+
"editor.openPageNavigator": {
|
|
1195
|
+
callback: (_ctx, mode: "page" | "meta" | "document" | "all" = "page") => {
|
|
1196
|
+
void client.startPageNavigate(mode);
|
|
1197
|
+
},
|
|
1198
|
+
description: `Opens the page picker in the requested browsing mode. Each mode maps to a segment of the \`std.pages\` navigator view.`,
|
|
1199
|
+
parameters: [
|
|
1200
|
+
{
|
|
1201
|
+
name: "mode",
|
|
1202
|
+
type: "page | meta | document | all",
|
|
1203
|
+
description: "The navigator mode.",
|
|
1204
|
+
optional: true,
|
|
1205
|
+
},
|
|
1206
|
+
],
|
|
1207
|
+
},
|
|
1208
|
+
"editor.openCommandPalette": {
|
|
1209
|
+
callback: () => {
|
|
1210
|
+
void client.startCommandPalette();
|
|
1211
|
+
},
|
|
1212
|
+
description: "Opens the command palette.",
|
|
1213
|
+
},
|
|
1214
|
+
"editor.openNavigator": {
|
|
1215
|
+
callback: (
|
|
1216
|
+
_ctx,
|
|
1217
|
+
name: string,
|
|
1218
|
+
opts?: {
|
|
1219
|
+
segment?: string;
|
|
1220
|
+
phrase?: string;
|
|
1221
|
+
dropdown?: unknown;
|
|
1222
|
+
focus?: boolean;
|
|
1223
|
+
},
|
|
1224
|
+
) => client.openNavigatorView(name, opts),
|
|
1225
|
+
description: `Opens a navigator view, returning whether it opened. False means the view isn't there to open -- typically because it's defined in Space Lua that hasn't been indexed yet -- so a caller can fall back to something else.`,
|
|
1226
|
+
parameters: [
|
|
1227
|
+
{ name: "name", type: "string", description: "The view's name." },
|
|
1228
|
+
{
|
|
1229
|
+
name: "opts",
|
|
1230
|
+
type: "table",
|
|
1231
|
+
description:
|
|
1232
|
+
"Optional `segment` (segment label), `phrase`, `dropdown` (dropdown value to select), and `focus` (`false` opens without taking focus).",
|
|
1233
|
+
optional: true,
|
|
1234
|
+
},
|
|
1235
|
+
],
|
|
1236
|
+
returns: [{ type: "boolean", description: "Whether a view opened." }],
|
|
1237
|
+
},
|
|
1238
|
+
"editor.deleteLine": {
|
|
1239
|
+
callback: () => {
|
|
1240
|
+
deleteLine(client.editorView);
|
|
1241
|
+
},
|
|
1242
|
+
description:
|
|
1243
|
+
"Deletes the current line or the lines touched by the selection.",
|
|
1244
|
+
},
|
|
1245
|
+
"editor.selectAll": {
|
|
1246
|
+
callback: () => {
|
|
1247
|
+
return selectAll({
|
|
1248
|
+
state: client.editorView.state,
|
|
1249
|
+
dispatch: client.editorView.dispatch,
|
|
635
1250
|
});
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
1251
|
+
},
|
|
1252
|
+
description: "Selects the entire editor document.",
|
|
1253
|
+
},
|
|
1254
|
+
"editor.indentMore": {
|
|
1255
|
+
callback: () => {
|
|
1256
|
+
return indentMore({
|
|
1257
|
+
state: client.editorView.state,
|
|
1258
|
+
dispatch: client.editorView.dispatch,
|
|
639
1259
|
});
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
1260
|
+
},
|
|
1261
|
+
description: "Increases indentation for the current line or selection.",
|
|
1262
|
+
},
|
|
1263
|
+
"editor.indentLess": {
|
|
1264
|
+
callback: () => {
|
|
1265
|
+
return indentLess({
|
|
1266
|
+
state: client.editorView.state,
|
|
1267
|
+
dispatch: client.editorView.dispatch,
|
|
643
1268
|
});
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
1269
|
+
},
|
|
1270
|
+
description: "Decreases indentation for the current line or selection.",
|
|
1271
|
+
},
|
|
1272
|
+
"editor.toggleComment": {
|
|
1273
|
+
callback: () => {
|
|
1274
|
+
return toggleComment({
|
|
1275
|
+
state: client.editorView.state,
|
|
1276
|
+
dispatch: client.editorView.dispatch,
|
|
649
1277
|
});
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
},
|
|
718
|
-
"editor.
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
"editor.
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
"editor.
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
"editor.
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
},
|
|
753
|
-
"editor.
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
"editor.
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
"editor.
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
},
|
|
798
|
-
"editor.
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1278
|
+
},
|
|
1279
|
+
description: "Comments or uncomments the current line or selection.",
|
|
1280
|
+
},
|
|
1281
|
+
"editor.moveLineUp": {
|
|
1282
|
+
callback: () => {
|
|
1283
|
+
return moveLineUp({
|
|
1284
|
+
state: client.editorView.state,
|
|
1285
|
+
dispatch: client.editorView.dispatch,
|
|
1286
|
+
});
|
|
1287
|
+
},
|
|
1288
|
+
description: "Moves the current line or selected lines upward.",
|
|
1289
|
+
},
|
|
1290
|
+
"editor.moveLineDown": {
|
|
1291
|
+
callback: () => {
|
|
1292
|
+
return moveLineDown({
|
|
1293
|
+
state: client.editorView.state,
|
|
1294
|
+
dispatch: client.editorView.dispatch,
|
|
1295
|
+
});
|
|
1296
|
+
},
|
|
1297
|
+
description: "Moves the current line or selected lines downward.",
|
|
1298
|
+
},
|
|
1299
|
+
"editor.fold": {
|
|
1300
|
+
callback: () => {
|
|
1301
|
+
foldCode(client.editorView);
|
|
1302
|
+
},
|
|
1303
|
+
description: "Folds the code or markup region at the cursor.",
|
|
1304
|
+
},
|
|
1305
|
+
"editor.unfold": {
|
|
1306
|
+
callback: () => {
|
|
1307
|
+
unfoldCode(client.editorView);
|
|
1308
|
+
},
|
|
1309
|
+
description: "Unfolds the folded region at the cursor.",
|
|
1310
|
+
},
|
|
1311
|
+
"editor.toggleFold": {
|
|
1312
|
+
callback: () => {
|
|
1313
|
+
toggleFold(client.editorView);
|
|
1314
|
+
},
|
|
1315
|
+
description: "Toggles folding for the region at the cursor.",
|
|
1316
|
+
},
|
|
1317
|
+
"editor.foldAll": {
|
|
1318
|
+
callback: () => {
|
|
1319
|
+
foldAll(client.editorView);
|
|
1320
|
+
},
|
|
1321
|
+
description: "Folds all foldable regions in the editor.",
|
|
1322
|
+
},
|
|
1323
|
+
"editor.unfoldAll": {
|
|
1324
|
+
callback: () => {
|
|
1325
|
+
unfoldAll(client.editorView);
|
|
1326
|
+
},
|
|
1327
|
+
description: "Unfolds all folded regions in the editor.",
|
|
1328
|
+
},
|
|
1329
|
+
"editor.undo": {
|
|
1330
|
+
callback: () => {
|
|
1331
|
+
return undo(client.editorView);
|
|
1332
|
+
},
|
|
1333
|
+
description: "Undoes the most recent editor change.",
|
|
1334
|
+
},
|
|
1335
|
+
"editor.redo": {
|
|
1336
|
+
callback: () => {
|
|
1337
|
+
return redo(client.editorView);
|
|
1338
|
+
},
|
|
1339
|
+
description: "Redoes the most recently undone editor change.",
|
|
1340
|
+
},
|
|
1341
|
+
"editor.cursorCharLeft": {
|
|
1342
|
+
callback: () => cursorCharLeft(client.editorView),
|
|
1343
|
+
description:
|
|
1344
|
+
"Moves the cursor one character left, respecting bidirectional text.",
|
|
1345
|
+
},
|
|
1346
|
+
"editor.cursorCharRight": {
|
|
1347
|
+
callback: () => cursorCharRight(client.editorView),
|
|
1348
|
+
description:
|
|
1349
|
+
"Moves the cursor one character right, respecting bidirectional text.",
|
|
1350
|
+
},
|
|
1351
|
+
"editor.cursorGroupLeft": {
|
|
1352
|
+
callback: () => cursorGroupLeft(client.editorView),
|
|
1353
|
+
description: "Moves the cursor left by one character group or word.",
|
|
1354
|
+
},
|
|
1355
|
+
"editor.cursorGroupRight": {
|
|
1356
|
+
callback: () => cursorGroupRight(client.editorView),
|
|
1357
|
+
description: "Moves the cursor right by one character group or word.",
|
|
1358
|
+
},
|
|
1359
|
+
"editor.cursorLineBoundaryLeft": {
|
|
1360
|
+
callback: () => cursorLineBoundaryLeft(client.editorView),
|
|
1361
|
+
description:
|
|
1362
|
+
"Moves the cursor to the left visual boundary of the current line.",
|
|
1363
|
+
},
|
|
1364
|
+
"editor.cursorLineBoundaryRight": {
|
|
1365
|
+
callback: () => cursorLineBoundaryRight(client.editorView),
|
|
1366
|
+
description:
|
|
1367
|
+
"Moves the cursor to the right visual boundary of the current line.",
|
|
1368
|
+
},
|
|
1369
|
+
"editor.cursorLineStart": {
|
|
1370
|
+
callback: () => cursorLineStart(client.editorView),
|
|
1371
|
+
description: "Moves the cursor to the start of the current logical line.",
|
|
1372
|
+
},
|
|
1373
|
+
"editor.cursorLineEnd": {
|
|
1374
|
+
callback: () => cursorLineEnd(client.editorView),
|
|
1375
|
+
description: "Moves the cursor to the end of the current logical line.",
|
|
1376
|
+
},
|
|
1377
|
+
"editor.cursorDocStart": {
|
|
1378
|
+
callback: () => cursorDocStart(client.editorView),
|
|
1379
|
+
description: "Moves the cursor to the start of the document.",
|
|
1380
|
+
},
|
|
1381
|
+
"editor.cursorDocEnd": {
|
|
1382
|
+
callback: () => cursorDocEnd(client.editorView),
|
|
1383
|
+
description: "Moves the cursor to the end of the document.",
|
|
1384
|
+
},
|
|
1385
|
+
"editor.cursorLineUp": {
|
|
1386
|
+
callback: () => {
|
|
1387
|
+
const view = client.editorView;
|
|
1388
|
+
if (moveCompletionSelection(false)(view)) return true;
|
|
1389
|
+
return cursorLineUp(view);
|
|
1390
|
+
},
|
|
1391
|
+
description:
|
|
1392
|
+
"Moves completion selection up when open, otherwise moves the cursor up one visual line.",
|
|
1393
|
+
},
|
|
1394
|
+
"editor.cursorLineDown": {
|
|
1395
|
+
callback: () => {
|
|
1396
|
+
const view = client.editorView;
|
|
1397
|
+
if (moveCompletionSelection(true)(view)) return true;
|
|
1398
|
+
return cursorLineDown(view);
|
|
1399
|
+
},
|
|
1400
|
+
description:
|
|
1401
|
+
"Moves completion selection down when open, otherwise moves the cursor down one visual line.",
|
|
1402
|
+
},
|
|
1403
|
+
"editor.cursorPageUp": {
|
|
1404
|
+
callback: () => {
|
|
1405
|
+
const view = client.editorView;
|
|
1406
|
+
if (moveCompletionSelection(false, "page")(view)) return true;
|
|
1407
|
+
return cursorPageUp(view);
|
|
1408
|
+
},
|
|
1409
|
+
description:
|
|
1410
|
+
"Moves completion selection up one page when open, otherwise moves the cursor up one viewport page.",
|
|
1411
|
+
},
|
|
1412
|
+
"editor.cursorPageDown": {
|
|
1413
|
+
callback: () => {
|
|
1414
|
+
const view = client.editorView;
|
|
1415
|
+
if (moveCompletionSelection(true, "page")(view)) return true;
|
|
1416
|
+
return cursorPageDown(view);
|
|
1417
|
+
},
|
|
1418
|
+
description:
|
|
1419
|
+
"Moves completion selection down one page when open, otherwise moves the cursor down one viewport page.",
|
|
1420
|
+
},
|
|
1421
|
+
"editor.selectCharLeft": {
|
|
1422
|
+
callback: () => selectCharLeft(client.editorView),
|
|
1423
|
+
description:
|
|
1424
|
+
"Extends the selection one character left, respecting bidirectional text.",
|
|
1425
|
+
},
|
|
1426
|
+
"editor.selectCharRight": {
|
|
1427
|
+
callback: () => selectCharRight(client.editorView),
|
|
1428
|
+
description:
|
|
1429
|
+
"Extends the selection one character right, respecting bidirectional text.",
|
|
1430
|
+
},
|
|
1431
|
+
"editor.selectGroupLeft": {
|
|
1432
|
+
callback: () => selectGroupLeft(client.editorView),
|
|
1433
|
+
description: "Extends the selection left by one character group or word.",
|
|
1434
|
+
},
|
|
1435
|
+
"editor.selectGroupRight": {
|
|
1436
|
+
callback: () => selectGroupRight(client.editorView),
|
|
1437
|
+
description:
|
|
1438
|
+
"Extends the selection right by one character group or word.",
|
|
1439
|
+
},
|
|
1440
|
+
"editor.selectLineBoundaryLeft": {
|
|
1441
|
+
callback: () => selectLineBoundaryLeft(client.editorView),
|
|
1442
|
+
description:
|
|
1443
|
+
"Extends the selection to the left visual boundary of the current line.",
|
|
1444
|
+
},
|
|
1445
|
+
"editor.selectLineBoundaryRight": {
|
|
1446
|
+
callback: () => selectLineBoundaryRight(client.editorView),
|
|
1447
|
+
description:
|
|
1448
|
+
"Extends the selection to the right visual boundary of the current line.",
|
|
1449
|
+
},
|
|
1450
|
+
"editor.selectLineStart": {
|
|
1451
|
+
callback: () => selectLineStart(client.editorView),
|
|
1452
|
+
description:
|
|
1453
|
+
"Extends the selection to the start of the current logical line.",
|
|
1454
|
+
},
|
|
1455
|
+
"editor.selectLineEnd": {
|
|
1456
|
+
callback: () => selectLineEnd(client.editorView),
|
|
1457
|
+
description:
|
|
1458
|
+
"Extends the selection to the end of the current logical line.",
|
|
1459
|
+
},
|
|
1460
|
+
"editor.selectDocStart": {
|
|
1461
|
+
callback: () => selectDocStart(client.editorView),
|
|
1462
|
+
description: "Extends the selection to the start of the document.",
|
|
1463
|
+
},
|
|
1464
|
+
"editor.selectDocEnd": {
|
|
1465
|
+
callback: () => selectDocEnd(client.editorView),
|
|
1466
|
+
description: "Extends the selection to the end of the document.",
|
|
1467
|
+
},
|
|
1468
|
+
"editor.selectLineUp": {
|
|
1469
|
+
callback: () => selectLineUp(client.editorView),
|
|
1470
|
+
description: "Extends the selection upward by one visual line.",
|
|
1471
|
+
},
|
|
1472
|
+
"editor.selectLineDown": {
|
|
1473
|
+
callback: () => selectLineDown(client.editorView),
|
|
1474
|
+
description: "Extends the selection downward by one visual line.",
|
|
1475
|
+
},
|
|
1476
|
+
"editor.selectPageUp": {
|
|
1477
|
+
callback: () => selectPageUp(client.editorView),
|
|
1478
|
+
description: "Extends the selection upward by one viewport page.",
|
|
1479
|
+
},
|
|
1480
|
+
"editor.selectPageDown": {
|
|
1481
|
+
callback: () => selectPageDown(client.editorView),
|
|
1482
|
+
description: "Extends the selection downward by one viewport page.",
|
|
1483
|
+
},
|
|
1484
|
+
"editor.deleteCharBackward": {
|
|
1485
|
+
callback: () => deleteCharBackward(client.editorView),
|
|
1486
|
+
description: "Deletes the selection or the character before the cursor.",
|
|
1487
|
+
},
|
|
1488
|
+
"editor.deleteCharForward": {
|
|
1489
|
+
callback: () => deleteCharForward(client.editorView),
|
|
1490
|
+
description: "Deletes the selection or the character after the cursor.",
|
|
1491
|
+
},
|
|
1492
|
+
"editor.deleteGroupBackward": {
|
|
1493
|
+
callback: () => deleteGroupBackward(client.editorView),
|
|
1494
|
+
description:
|
|
1495
|
+
"Deletes the selection or the character group before the cursor.",
|
|
1496
|
+
},
|
|
1497
|
+
"editor.deleteGroupForward": {
|
|
1498
|
+
callback: () => deleteGroupForward(client.editorView),
|
|
1499
|
+
description:
|
|
1500
|
+
"Deletes the selection or the character group after the cursor.",
|
|
1501
|
+
},
|
|
1502
|
+
"editor.deleteLineBoundaryBackward": {
|
|
1503
|
+
callback: () => deleteLineBoundaryBackward(client.editorView),
|
|
1504
|
+
description:
|
|
1505
|
+
"Deletes the selection or text back to the current line boundary.",
|
|
1506
|
+
},
|
|
1507
|
+
"editor.deleteLineBoundaryForward": {
|
|
1508
|
+
callback: () => deleteLineBoundaryForward(client.editorView),
|
|
1509
|
+
description:
|
|
1510
|
+
"Deletes the selection or text forward to the current line boundary.",
|
|
1511
|
+
},
|
|
1512
|
+
"editor.transposeChars": {
|
|
1513
|
+
callback: () => transposeChars(client.editorView),
|
|
1514
|
+
description: "Transposes the characters around the cursor.",
|
|
1515
|
+
},
|
|
1516
|
+
"editor.insertNewline": {
|
|
1517
|
+
callback: () => {
|
|
1518
|
+
const view = client.editorView;
|
|
1519
|
+
if (acceptCompletion(view)) return true;
|
|
1520
|
+
return insertNewlineAndIndent(view);
|
|
1521
|
+
},
|
|
1522
|
+
description:
|
|
1523
|
+
"Accepts the active completion, or inserts a newline with appropriate indentation.",
|
|
1524
|
+
},
|
|
1525
|
+
"editor.acceptCompletion": {
|
|
1526
|
+
callback: () => acceptCompletion(client.editorView),
|
|
1527
|
+
description:
|
|
1528
|
+
"Accepts the currently selected completion when the completion popup is active.",
|
|
1529
|
+
returns: [
|
|
1530
|
+
{
|
|
1531
|
+
type: "boolean",
|
|
1532
|
+
description: "Whether an active completion was accepted.",
|
|
1533
|
+
},
|
|
1534
|
+
],
|
|
1535
|
+
},
|
|
1536
|
+
"editor.startCompletion": {
|
|
1537
|
+
callback: () => startCompletion(client.editorView),
|
|
1538
|
+
description: "Explicitly starts editor completion at the cursor.",
|
|
1539
|
+
},
|
|
1540
|
+
"editor.closeCompletion": {
|
|
1541
|
+
callback: () => closeCompletion(client.editorView),
|
|
1542
|
+
description: "Closes the active editor completion popup.",
|
|
1543
|
+
},
|
|
1544
|
+
"editor.openSearchPanel": {
|
|
1545
|
+
callback: () => {
|
|
1546
|
+
openSearchPanel(client.editorView);
|
|
1547
|
+
},
|
|
1548
|
+
description: "Opens the editor's native search panel.",
|
|
1549
|
+
},
|
|
1550
|
+
"editor.copyToClipboard": {
|
|
1551
|
+
callback: async (_ctx, data: string | Blob) => {
|
|
1552
|
+
try {
|
|
1553
|
+
await copyToClipboard(data);
|
|
1554
|
+
} catch (e) {
|
|
1555
|
+
console.error(e);
|
|
1556
|
+
client.ui.flashNotification(`Could not copy to clipboard: ${e}`);
|
|
806
1557
|
}
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
1558
|
+
},
|
|
1559
|
+
description:
|
|
1560
|
+
"Copies text or binary Blob data to the system clipboard. Binary clipboard access requires HTTPS or localhost; text copying also works over HTTP when supported by the browser.",
|
|
1561
|
+
parameters: [
|
|
1562
|
+
{
|
|
1563
|
+
name: "data",
|
|
1564
|
+
type: "string | Blob",
|
|
1565
|
+
description: "The text or Blob to copy.",
|
|
1566
|
+
},
|
|
1567
|
+
],
|
|
1568
|
+
examples: [{ code: 'editor.copyToClipboard("Copied text")' }],
|
|
811
1569
|
},
|
|
812
|
-
"editor.sendMessage":
|
|
813
|
-
|
|
1570
|
+
"editor.sendMessage": {
|
|
1571
|
+
callback: (_ctx, type: string, data: any) => {
|
|
1572
|
+
if (!client.contentManager.isDocumentEditor()) return;
|
|
814
1573
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
1574
|
+
client.contentManager.documentEditor.sendPublicMessage({
|
|
1575
|
+
type,
|
|
1576
|
+
data,
|
|
1577
|
+
});
|
|
1578
|
+
},
|
|
1579
|
+
description:
|
|
1580
|
+
"Sends a public message to the active document editor, if one is open.",
|
|
1581
|
+
parameters: [
|
|
1582
|
+
{ name: "type", type: "string", description: "The message type." },
|
|
1583
|
+
{
|
|
1584
|
+
name: "data",
|
|
1585
|
+
type: "any",
|
|
1586
|
+
description: "Data attached to the message.",
|
|
1587
|
+
optional: true,
|
|
1588
|
+
},
|
|
1589
|
+
],
|
|
1590
|
+
},
|
|
1591
|
+
|
|
1592
|
+
"editor.isMobile": {
|
|
1593
|
+
callback: () => isMobileDevice(),
|
|
1594
|
+
description:
|
|
1595
|
+
"Checks whether the current device lacks a fine pointer and should be treated as mobile.",
|
|
1596
|
+
returns: [
|
|
1597
|
+
{
|
|
1598
|
+
type: "boolean",
|
|
1599
|
+
description:
|
|
1600
|
+
"Whether the editor is running in a mobile-style pointer environment.",
|
|
1601
|
+
},
|
|
1602
|
+
],
|
|
819
1603
|
},
|
|
820
1604
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1605
|
+
// Deliberately separate from `editor.isMobile`: that one answers "what
|
|
1606
|
+
// kind of pointer is this", which is the right question for touch
|
|
1607
|
+
// affordances and the wrong one for layout. A narrow window on a desktop
|
|
1608
|
+
// gets the narrow layout with a mouse attached; a tablet in landscape gets
|
|
1609
|
+
// the wide one without.
|
|
1610
|
+
"editor.isNarrowScreen": {
|
|
1611
|
+
callback: () => isNarrowScreen(),
|
|
1612
|
+
description:
|
|
1613
|
+
"Checks whether the client is currently laid out for a narrow screen, i.e. below the breakpoint where sidebar panels become full-width drawers.",
|
|
1614
|
+
returns: [
|
|
1615
|
+
{
|
|
1616
|
+
type: "boolean",
|
|
1617
|
+
description: "Whether the narrow-screen layout is in effect.",
|
|
1618
|
+
},
|
|
1619
|
+
],
|
|
824
1620
|
},
|
|
825
1621
|
};
|
|
826
1622
|
|