@silverbulletmd/silverbullet 2.6.1 → 2.7.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 +0 -1
- package/client/markdown_parser/constants.ts +1 -0
- package/client/plugos/hooks/command.ts +46 -16
- package/client/plugos/hooks/slash_command.ts +3 -1
- package/client/plugos/plug.ts +5 -2
- package/client/plugos/plug_compile.ts +52 -2
- package/client/plugos/sandboxes/worker_sandbox.ts +11 -1
- package/client/plugos/syscalls/config.ts +9 -2
- package/client/plugos/syscalls/editor.ts +136 -0
- package/client/plugos/syscalls/index.ts +1 -1
- package/client/plugos/syscalls/jsonschema.ts +1 -19
- package/client/plugos/syscalls/system.ts +13 -0
- package/client/plugos/system.ts +14 -10
- package/client/plugos/types.ts +25 -0
- package/client/plugos/util.ts +20 -0
- package/client/space_lua/aggregates.ts +2 -2
- package/client/space_lua/query_collection.ts +4 -4
- package/client/space_lua/render_lua_markdown.ts +1 -1
- package/client/space_lua/runtime.ts +1 -1
- package/client/space_lua/{liq_null.ts → sliq_null.ts} +2 -2
- package/client/space_lua/stdlib/space_lua.ts +1 -1
- package/client/space_lua/stdlib.ts +1 -1
- package/dist/plug-compile.js +44 -2
- package/package.json +1 -1
- package/plug-api/constants.ts +20 -0
- package/plug-api/lib/ref.ts +9 -2
- package/plug-api/lib/shortcut.ts +16 -0
- package/plug-api/lib/tree.ts +35 -4
- package/plug-api/syscalls/config.ts +37 -0
- package/plug-api/syscalls/editor.ts +155 -0
- package/plug-api/syscalls/index.ts +18 -0
- package/plug-api/syscalls/system.ts +15 -0
- package/plug-api/types/manifest.ts +63 -0
- package/plugs/builtin_plugs.ts +1 -1
- package/client/plugos/sandboxes/web_worker_sandbox.ts +0 -17
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
type LuaValue,
|
|
27
27
|
singleResult,
|
|
28
28
|
} from "./runtime.ts";
|
|
29
|
-
import { isSqlNull,
|
|
29
|
+
import { isSqlNull, SLIQ_NULL } from "./sliq_null.ts";
|
|
30
30
|
import { evalExpression, luaOp } from "./eval.ts";
|
|
31
31
|
import { asyncMergeSort } from "./util.ts";
|
|
32
32
|
import type { DataStore } from "../data/datastore.ts";
|
|
@@ -295,7 +295,7 @@ function containsAggregate(expr: LuaExpression, config?: Config): boolean {
|
|
|
295
295
|
// Wrap a value for select result tables so that the column key survives
|
|
296
296
|
// in the `LuaTable`
|
|
297
297
|
function selectVal(v: LuaValue): LuaValue {
|
|
298
|
-
return v === null || v === undefined ?
|
|
298
|
+
return v === null || v === undefined ? SLIQ_NULL : v;
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
/**
|
|
@@ -491,7 +491,7 @@ function normalizeSelectResults(results: any[]): any[] {
|
|
|
491
491
|
const rebuilt = new LuaTable();
|
|
492
492
|
for (const k of canonicalKeys) {
|
|
493
493
|
const v = item.rawGet(k);
|
|
494
|
-
void rebuilt.rawSet(k, v === undefined || v === null ?
|
|
494
|
+
void rebuilt.rawSet(k, v === undefined || v === null ? SLIQ_NULL : v);
|
|
495
495
|
}
|
|
496
496
|
for (const k of luaKeys(item)) {
|
|
497
497
|
if (typeof k !== "string") {
|
|
@@ -675,7 +675,7 @@ async function evalSelectExpression(
|
|
|
675
675
|
for (const k of luaKeys(result)) {
|
|
676
676
|
const v = result.rawGet(k);
|
|
677
677
|
if (v === null || v === undefined) {
|
|
678
|
-
void result.rawSet(k,
|
|
678
|
+
void result.rawSet(k, SLIQ_NULL);
|
|
679
679
|
}
|
|
680
680
|
}
|
|
681
681
|
return result;
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
escapeRegularPipes,
|
|
4
4
|
jsonToMDTable,
|
|
5
5
|
} from "../markdown_renderer/result_render.ts";
|
|
6
|
-
import { isSqlNull } from "../space_lua/
|
|
6
|
+
import { isSqlNull } from "../space_lua/sliq_null.ts";
|
|
7
7
|
import { isTaggedFloat } from "../space_lua/numeric.ts";
|
|
8
8
|
import { LuaTable, luaFormatNumber } from "../space_lua/runtime.ts";
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import { evalStatement } from "./eval.ts";
|
|
|
3
3
|
import { asyncQuickSort } from "./util.ts";
|
|
4
4
|
import { isPromise, rpAll } from "./rp.ts";
|
|
5
5
|
import { isNegativeZero, isTaggedFloat } from "./numeric.ts";
|
|
6
|
-
import { isSqlNull } from "./
|
|
6
|
+
import { isSqlNull } from "./sliq_null.ts";
|
|
7
7
|
import { luaFormat } from "./stdlib/format.ts";
|
|
8
8
|
|
|
9
9
|
export type LuaType =
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Sentinel value representing SQL NULL in query results.
|
|
2
|
-
export const
|
|
2
|
+
export const SLIQ_NULL = Symbol.for("silverbullet.sqlNull");
|
|
3
3
|
|
|
4
4
|
export function isSqlNull(v: any): boolean {
|
|
5
|
-
return v ===
|
|
5
|
+
return v === SLIQ_NULL;
|
|
6
6
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
luaValueToJS,
|
|
13
13
|
singleResult,
|
|
14
14
|
} from "../runtime.ts";
|
|
15
|
-
import { isSqlNull } from "../
|
|
15
|
+
import { isSqlNull } from "../sliq_null.ts";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* These are Space Lua specific functions that are available to all scripts, but are not part of the standard Lua language.
|
|
@@ -35,7 +35,7 @@ import { cryptoApi } from "./stdlib/crypto.ts";
|
|
|
35
35
|
import { netApi } from "./stdlib/net.ts";
|
|
36
36
|
import { isTaggedFloat, makeLuaFloat } from "./numeric.ts";
|
|
37
37
|
import { isPromise } from "./rp.ts";
|
|
38
|
-
import { isSqlNull } from "./
|
|
38
|
+
import { isSqlNull } from "./sliq_null.ts";
|
|
39
39
|
|
|
40
40
|
const printFunction = new LuaBuiltinFunction(async (_sf, ...args) => {
|
|
41
41
|
console.log("[Lua]", ...(await Promise.all(args.map((v) => luaToString(v)))));
|
package/dist/plug-compile.js
CHANGED
|
@@ -4,14 +4,22 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
6
|
// version.ts
|
|
7
|
-
var version = "2.
|
|
7
|
+
var version = "2.7.0";
|
|
8
8
|
|
|
9
9
|
// client/plugos/plug_compile.ts
|
|
10
10
|
import * as path from "node:path";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
copyFile,
|
|
13
|
+
mkdir,
|
|
14
|
+
mkdtemp,
|
|
15
|
+
readFile as readFile2,
|
|
16
|
+
rm,
|
|
17
|
+
writeFile
|
|
18
|
+
} from "node:fs/promises";
|
|
12
19
|
import { tmpdir } from "node:os";
|
|
13
20
|
import * as YAML from "js-yaml";
|
|
14
21
|
import * as esbuild from "esbuild";
|
|
22
|
+
import * as sass from "sass";
|
|
15
23
|
|
|
16
24
|
// client/asset_bundle/builder.ts
|
|
17
25
|
import { readFile, readdir } from "node:fs/promises";
|
|
@@ -1339,6 +1347,12 @@ async function compileManifest(manifestPath, destPath, options = {}) {
|
|
|
1339
1347
|
if (!manifest.name) {
|
|
1340
1348
|
throw new Error(`Missing 'name' in ${manifestPath}`);
|
|
1341
1349
|
}
|
|
1350
|
+
if (manifest.build) {
|
|
1351
|
+
await Promise.all(
|
|
1352
|
+
manifest.build.map((step) => runBuildStep(step, rootPath, options))
|
|
1353
|
+
);
|
|
1354
|
+
delete manifest.build;
|
|
1355
|
+
}
|
|
1342
1356
|
const assetsBundle = await bundleAssets(
|
|
1343
1357
|
path.resolve(rootPath),
|
|
1344
1358
|
manifest.assets || []
|
|
@@ -1435,6 +1449,34 @@ async function compileManifests(manifestFiles, dist, options = {}) {
|
|
|
1435
1449
|
}
|
|
1436
1450
|
await buildAll();
|
|
1437
1451
|
}
|
|
1452
|
+
async function runBuildStep(step, rootPath, options) {
|
|
1453
|
+
const type = step.type ?? "esbuild";
|
|
1454
|
+
const inFile = path.resolve(rootPath, step.in);
|
|
1455
|
+
const outFile = path.resolve(rootPath, step.out);
|
|
1456
|
+
await mkdir(path.dirname(outFile), { recursive: true });
|
|
1457
|
+
if (type === "esbuild") {
|
|
1458
|
+
await esbuild.build({
|
|
1459
|
+
entryPoints: [inFile],
|
|
1460
|
+
bundle: true,
|
|
1461
|
+
format: "iife",
|
|
1462
|
+
platform: "browser",
|
|
1463
|
+
minify: !options.debug,
|
|
1464
|
+
outfile: outFile,
|
|
1465
|
+
treeShaking: true
|
|
1466
|
+
});
|
|
1467
|
+
} else if (type === "sass") {
|
|
1468
|
+
const scss = await readFile2(inFile, "utf-8");
|
|
1469
|
+
const result = sass.compileString(scss, {
|
|
1470
|
+
loadPaths: [path.dirname(inFile)],
|
|
1471
|
+
style: options.debug ? "expanded" : "compressed"
|
|
1472
|
+
});
|
|
1473
|
+
await writeFile(outFile, result.css, "utf-8");
|
|
1474
|
+
} else if (type === "copy") {
|
|
1475
|
+
await copyFile(inFile, outFile);
|
|
1476
|
+
} else {
|
|
1477
|
+
throw new Error(`Unsupported build step type: ${type}`);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1438
1480
|
function patchBundledJS(code) {
|
|
1439
1481
|
return code.replaceAll("/(?<=\\n)/", "/()/");
|
|
1440
1482
|
}
|
package/package.json
CHANGED
package/plug-api/constants.ts
CHANGED
|
@@ -8,3 +8,23 @@ export const wrongSpacePathError: Error = new Error(
|
|
|
8
8
|
);
|
|
9
9
|
export const pingTimeout: number = 2000;
|
|
10
10
|
export const pingInterval: number = 5000;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Determines if an error thrown by fetch() is a network-level error
|
|
14
|
+
* (as opposed to a server-side or application error).
|
|
15
|
+
*
|
|
16
|
+
* Browser-specific error messages when there is no internet connection:
|
|
17
|
+
* - Firefox: "NetworkError when attempting to fetch resource"
|
|
18
|
+
* - Safari (service worker): "FetchEvent.respondWith received an error: TypeError: Load failed"
|
|
19
|
+
* - Safari (no service worker): "Load failed"
|
|
20
|
+
* - Chrome: "Failed to fetch"
|
|
21
|
+
*/
|
|
22
|
+
export function isNetworkError(e: any): boolean {
|
|
23
|
+
const msg = (e?.message || "").toLowerCase();
|
|
24
|
+
return (
|
|
25
|
+
msg.includes("fetch") ||
|
|
26
|
+
msg.includes("load failed") ||
|
|
27
|
+
msg.includes("networkerror") ||
|
|
28
|
+
msg.includes("unavailable")
|
|
29
|
+
);
|
|
30
|
+
}
|
package/plug-api/lib/ref.ts
CHANGED
|
@@ -23,7 +23,8 @@ export type Ref = {
|
|
|
23
23
|
details?:
|
|
24
24
|
| { type: "position"; pos: number }
|
|
25
25
|
| { type: "linecolumn"; line: number; column: number }
|
|
26
|
-
| { type: "header"; header: string }
|
|
26
|
+
| { type: "header"; header: string }
|
|
27
|
+
| { type: "anchor"; name: string };
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -96,7 +97,7 @@ export function isValidPath(path: string): path is Path {
|
|
|
96
97
|
* TO THE INNER WORKINGS OF SILVERBULLET AND CHANGES COULD INTRODUCE MAJOR BUGS
|
|
97
98
|
*/
|
|
98
99
|
const refRegex =
|
|
99
|
-
/^(?<meta>\^)?(?<path>(?!.*\.[a-zA-Z0-9]+\.md$)(?!\/?(\.|\^))(?!.*(?:\/|^)\.{1,2}(?:\/|$)|.*\/{2})(?!.*(?:\]\]|\[\[))[
|
|
100
|
+
/^(?<meta>\^)?(?<path>(?!.*\.[a-zA-Z0-9]+\.md$)(?!\/?(\.|\^))(?!.*(?:\/|^)\.{1,2}(?:\/|$)|.*\/{2})(?!.*(?:\]\]|\[\[))[^@#|<>$]*)(@(?<pos>\d+)|@[Ll](?<line>\d+)(?:[Cc](?<col>\d+))?|#\s*(?<header>.*)|\$(?<anchor>[A-Za-z_][A-Za-z0-9_/:-]*))?$/;
|
|
100
101
|
|
|
101
102
|
/**
|
|
102
103
|
* Parses a reference string into a ref object.
|
|
@@ -132,6 +133,8 @@ export function parseToRef(stringRef: string): Ref | null {
|
|
|
132
133
|
type: "header",
|
|
133
134
|
header: groups.header,
|
|
134
135
|
};
|
|
136
|
+
} else if (groups.anchor !== undefined) {
|
|
137
|
+
ref.details = { type: "anchor", name: groups.anchor };
|
|
135
138
|
}
|
|
136
139
|
|
|
137
140
|
return ref;
|
|
@@ -158,6 +161,8 @@ export function encodeRef(ref: Ref): string {
|
|
|
158
161
|
stringRef += `@${ref.details.pos}`;
|
|
159
162
|
} else if (ref.details?.type === "header") {
|
|
160
163
|
stringRef += `#${ref.details.header}`;
|
|
164
|
+
} else if (ref.details?.type === "anchor") {
|
|
165
|
+
stringRef += `$${ref.details.name}`;
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
return stringRef;
|
|
@@ -191,6 +196,8 @@ export function getOffsetFromRef(
|
|
|
191
196
|
case "header": {
|
|
192
197
|
return getOffsetFromHeader(parseTree, ref.details.header);
|
|
193
198
|
}
|
|
199
|
+
case "anchor":
|
|
200
|
+
return -1;
|
|
194
201
|
}
|
|
195
202
|
}
|
|
196
203
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const isMacLike = typeof navigator !== "undefined" &&
|
|
2
|
+
/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);
|
|
3
|
+
|
|
4
|
+
export function prettifyShortcut(shortcut: string): string {
|
|
5
|
+
if (!isMacLike) return shortcut;
|
|
6
|
+
const pretty = shortcut
|
|
7
|
+
.replace(/Mod-/g, "⌘")
|
|
8
|
+
.replace(/Cmd-/g, "⌘")
|
|
9
|
+
.replace(/Ctrl-/g, "⌃")
|
|
10
|
+
.replace(/Alt-/g, "⌥")
|
|
11
|
+
.replace(/Shift-/g, "⇧");
|
|
12
|
+
return pretty.replace(
|
|
13
|
+
/([⌘⌃⌥⇧])([a-z])$/,
|
|
14
|
+
(_, mod, key) => mod + key.toUpperCase(),
|
|
15
|
+
);
|
|
16
|
+
}
|
package/plug-api/lib/tree.ts
CHANGED
|
@@ -191,13 +191,29 @@ export function traverseTree(
|
|
|
191
191
|
tree: ParseTree,
|
|
192
192
|
// Return value = should stop traversal into children?
|
|
193
193
|
matchFn: (tree: ParseTree) => boolean,
|
|
194
|
+
// Just log errors on exceptions, but don't stop traversal
|
|
195
|
+
catchVisitorErrors = false,
|
|
194
196
|
): void {
|
|
195
|
-
|
|
197
|
+
let stop = false;
|
|
198
|
+
if (catchVisitorErrors) {
|
|
199
|
+
try {
|
|
200
|
+
stop = matchFn(tree);
|
|
201
|
+
} catch (e: any) {
|
|
202
|
+
console.error(
|
|
203
|
+
`traverseTree visitor failed at node ${tree.type}@${tree.from}:`,
|
|
204
|
+
e?.stack ?? e,
|
|
205
|
+
);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
stop = matchFn(tree);
|
|
210
|
+
}
|
|
211
|
+
if (stop) {
|
|
196
212
|
return;
|
|
197
213
|
}
|
|
198
214
|
if (tree.children) {
|
|
199
215
|
for (const child of tree.children) {
|
|
200
|
-
traverseTree(child, matchFn);
|
|
216
|
+
traverseTree(child, matchFn, catchVisitorErrors);
|
|
201
217
|
}
|
|
202
218
|
}
|
|
203
219
|
}
|
|
@@ -206,13 +222,28 @@ export async function traverseTreeAsync(
|
|
|
206
222
|
tree: ParseTree,
|
|
207
223
|
// Return value = should stop traversal into children?
|
|
208
224
|
matchFn: (tree: ParseTree) => Promise<boolean>,
|
|
225
|
+
catchVisitorErrors = false,
|
|
209
226
|
): Promise<void> {
|
|
210
|
-
|
|
227
|
+
let stop = false;
|
|
228
|
+
if (catchVisitorErrors) {
|
|
229
|
+
try {
|
|
230
|
+
stop = await matchFn(tree);
|
|
231
|
+
} catch (e: any) {
|
|
232
|
+
console.error(
|
|
233
|
+
`traverseTreeAsync visitor failed at node ${tree.type}@${tree.from}:`,
|
|
234
|
+
e?.stack ?? e,
|
|
235
|
+
);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
stop = await matchFn(tree);
|
|
240
|
+
}
|
|
241
|
+
if (stop) {
|
|
211
242
|
return;
|
|
212
243
|
}
|
|
213
244
|
if (tree.children) {
|
|
214
245
|
for (const child of tree.children) {
|
|
215
|
-
await traverseTreeAsync(child, matchFn);
|
|
246
|
+
await traverseTreeAsync(child, matchFn, catchVisitorErrors);
|
|
216
247
|
}
|
|
217
248
|
}
|
|
218
249
|
}
|
|
@@ -53,3 +53,40 @@ export function has(path: string): Promise<boolean> {
|
|
|
53
53
|
export function define(key: string, schema: any): Promise<void> {
|
|
54
54
|
return syscall("config.define", key, schema);
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Defines (or updates) a UI category for the configuration manager. Categories
|
|
59
|
+
* are referenced by name from a schema field's `ui.category` and are sorted in
|
|
60
|
+
* ascending `order` (default 0); unknown categories fall to the bottom in
|
|
61
|
+
* alphabetical order.
|
|
62
|
+
*/
|
|
63
|
+
export function defineCategory(
|
|
64
|
+
definition: { name: string; description?: string; order?: number },
|
|
65
|
+
): Promise<void> {
|
|
66
|
+
return syscall("config.defineCategory", definition);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Gets all config values as a single object.
|
|
71
|
+
* @returns The entire config values object
|
|
72
|
+
*/
|
|
73
|
+
export function getValues(): Promise<Record<string, any>> {
|
|
74
|
+
return syscall("config.getValues");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Gets all defined config schemas.
|
|
79
|
+
* @returns The schema definitions object
|
|
80
|
+
*/
|
|
81
|
+
export function getSchemas(): Promise<Record<string, any>> {
|
|
82
|
+
return syscall("config.getSchemas");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Gets all registered UI categories for the configuration manager.
|
|
87
|
+
*/
|
|
88
|
+
export function getCategories(): Promise<
|
|
89
|
+
Record<string, { name: string; description?: string; order?: number }>
|
|
90
|
+
> {
|
|
91
|
+
return syscall("config.getCategories");
|
|
92
|
+
}
|
|
@@ -269,6 +269,13 @@ export function hidePanel(id: "lhs" | "rhs" | "bhs" | "modal"): Promise<void> {
|
|
|
269
269
|
return syscall("editor.hidePanel", id);
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Returns focus to the main editor.
|
|
274
|
+
*/
|
|
275
|
+
export function focus(): Promise<void> {
|
|
276
|
+
return syscall("editor.focus");
|
|
277
|
+
}
|
|
278
|
+
|
|
272
279
|
export function showProgress(
|
|
273
280
|
progressPercentage?: number,
|
|
274
281
|
progressType?: string,
|
|
@@ -466,6 +473,27 @@ export function deleteLine(): Promise<void> {
|
|
|
466
473
|
return syscall("editor.deleteLine");
|
|
467
474
|
}
|
|
468
475
|
|
|
476
|
+
/**
|
|
477
|
+
* Select the entire document
|
|
478
|
+
*/
|
|
479
|
+
export function selectAll(): Promise<void> {
|
|
480
|
+
return syscall("editor.selectAll");
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Increase indentation of the current line or selection
|
|
485
|
+
*/
|
|
486
|
+
export function indentMore(): Promise<void> {
|
|
487
|
+
return syscall("editor.indentMore");
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Decrease indentation of the current line or selection
|
|
492
|
+
*/
|
|
493
|
+
export function indentLess(): Promise<void> {
|
|
494
|
+
return syscall("editor.indentLess");
|
|
495
|
+
}
|
|
496
|
+
|
|
469
497
|
/**
|
|
470
498
|
* Comment or uncomment the current line in the editor
|
|
471
499
|
*/
|
|
@@ -481,6 +509,133 @@ export function moveLineDown(): Promise<void> {
|
|
|
481
509
|
return syscall("editor.moveLineDown");
|
|
482
510
|
}
|
|
483
511
|
|
|
512
|
+
// Cursor motion syscalls (wrappers around @codemirror/commands functions)
|
|
513
|
+
export function cursorCharLeft(): Promise<void> {
|
|
514
|
+
return syscall("editor.cursorCharLeft");
|
|
515
|
+
}
|
|
516
|
+
export function cursorCharRight(): Promise<void> {
|
|
517
|
+
return syscall("editor.cursorCharRight");
|
|
518
|
+
}
|
|
519
|
+
export function cursorGroupLeft(): Promise<void> {
|
|
520
|
+
return syscall("editor.cursorGroupLeft");
|
|
521
|
+
}
|
|
522
|
+
export function cursorGroupRight(): Promise<void> {
|
|
523
|
+
return syscall("editor.cursorGroupRight");
|
|
524
|
+
}
|
|
525
|
+
export function cursorLineBoundaryLeft(): Promise<void> {
|
|
526
|
+
return syscall("editor.cursorLineBoundaryLeft");
|
|
527
|
+
}
|
|
528
|
+
export function cursorLineBoundaryRight(): Promise<void> {
|
|
529
|
+
return syscall("editor.cursorLineBoundaryRight");
|
|
530
|
+
}
|
|
531
|
+
export function cursorLineStart(): Promise<void> {
|
|
532
|
+
return syscall("editor.cursorLineStart");
|
|
533
|
+
}
|
|
534
|
+
export function cursorLineEnd(): Promise<void> {
|
|
535
|
+
return syscall("editor.cursorLineEnd");
|
|
536
|
+
}
|
|
537
|
+
export function cursorDocStart(): Promise<void> {
|
|
538
|
+
return syscall("editor.cursorDocStart");
|
|
539
|
+
}
|
|
540
|
+
export function cursorDocEnd(): Promise<void> {
|
|
541
|
+
return syscall("editor.cursorDocEnd");
|
|
542
|
+
}
|
|
543
|
+
export function cursorLineUp(): Promise<void> {
|
|
544
|
+
return syscall("editor.cursorLineUp");
|
|
545
|
+
}
|
|
546
|
+
export function cursorLineDown(): Promise<void> {
|
|
547
|
+
return syscall("editor.cursorLineDown");
|
|
548
|
+
}
|
|
549
|
+
export function cursorPageUp(): Promise<void> {
|
|
550
|
+
return syscall("editor.cursorPageUp");
|
|
551
|
+
}
|
|
552
|
+
export function cursorPageDown(): Promise<void> {
|
|
553
|
+
return syscall("editor.cursorPageDown");
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Selection-extending motions
|
|
557
|
+
export function selectCharLeft(): Promise<void> {
|
|
558
|
+
return syscall("editor.selectCharLeft");
|
|
559
|
+
}
|
|
560
|
+
export function selectCharRight(): Promise<void> {
|
|
561
|
+
return syscall("editor.selectCharRight");
|
|
562
|
+
}
|
|
563
|
+
export function selectGroupLeft(): Promise<void> {
|
|
564
|
+
return syscall("editor.selectGroupLeft");
|
|
565
|
+
}
|
|
566
|
+
export function selectGroupRight(): Promise<void> {
|
|
567
|
+
return syscall("editor.selectGroupRight");
|
|
568
|
+
}
|
|
569
|
+
export function selectLineBoundaryLeft(): Promise<void> {
|
|
570
|
+
return syscall("editor.selectLineBoundaryLeft");
|
|
571
|
+
}
|
|
572
|
+
export function selectLineBoundaryRight(): Promise<void> {
|
|
573
|
+
return syscall("editor.selectLineBoundaryRight");
|
|
574
|
+
}
|
|
575
|
+
export function selectLineStart(): Promise<void> {
|
|
576
|
+
return syscall("editor.selectLineStart");
|
|
577
|
+
}
|
|
578
|
+
export function selectLineEnd(): Promise<void> {
|
|
579
|
+
return syscall("editor.selectLineEnd");
|
|
580
|
+
}
|
|
581
|
+
export function selectDocStart(): Promise<void> {
|
|
582
|
+
return syscall("editor.selectDocStart");
|
|
583
|
+
}
|
|
584
|
+
export function selectDocEnd(): Promise<void> {
|
|
585
|
+
return syscall("editor.selectDocEnd");
|
|
586
|
+
}
|
|
587
|
+
export function selectLineUp(): Promise<void> {
|
|
588
|
+
return syscall("editor.selectLineUp");
|
|
589
|
+
}
|
|
590
|
+
export function selectLineDown(): Promise<void> {
|
|
591
|
+
return syscall("editor.selectLineDown");
|
|
592
|
+
}
|
|
593
|
+
export function selectPageUp(): Promise<void> {
|
|
594
|
+
return syscall("editor.selectPageUp");
|
|
595
|
+
}
|
|
596
|
+
export function selectPageDown(): Promise<void> {
|
|
597
|
+
return syscall("editor.selectPageDown");
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Delete
|
|
601
|
+
export function deleteCharBackward(): Promise<void> {
|
|
602
|
+
return syscall("editor.deleteCharBackward");
|
|
603
|
+
}
|
|
604
|
+
export function deleteCharForward(): Promise<void> {
|
|
605
|
+
return syscall("editor.deleteCharForward");
|
|
606
|
+
}
|
|
607
|
+
export function deleteGroupBackward(): Promise<void> {
|
|
608
|
+
return syscall("editor.deleteGroupBackward");
|
|
609
|
+
}
|
|
610
|
+
export function deleteGroupForward(): Promise<void> {
|
|
611
|
+
return syscall("editor.deleteGroupForward");
|
|
612
|
+
}
|
|
613
|
+
export function deleteLineBoundaryBackward(): Promise<void> {
|
|
614
|
+
return syscall("editor.deleteLineBoundaryBackward");
|
|
615
|
+
}
|
|
616
|
+
export function deleteLineBoundaryForward(): Promise<void> {
|
|
617
|
+
return syscall("editor.deleteLineBoundaryForward");
|
|
618
|
+
}
|
|
619
|
+
export function transposeChars(): Promise<void> {
|
|
620
|
+
return syscall("editor.transposeChars");
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Enter: accepts completion if popup open, else inserts newline
|
|
624
|
+
export function insertNewline(): Promise<void> {
|
|
625
|
+
return syscall("editor.insertNewline");
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Completion popup
|
|
629
|
+
export function acceptCompletion(): Promise<boolean> {
|
|
630
|
+
return syscall("editor.acceptCompletion");
|
|
631
|
+
}
|
|
632
|
+
export function startCompletion(): Promise<void> {
|
|
633
|
+
return syscall("editor.startCompletion");
|
|
634
|
+
}
|
|
635
|
+
export function closeCompletion(): Promise<void> {
|
|
636
|
+
return syscall("editor.closeCompletion");
|
|
637
|
+
}
|
|
638
|
+
|
|
484
639
|
// Vim-mode specific syscalls
|
|
485
640
|
|
|
486
641
|
/**
|
|
@@ -75,3 +75,21 @@ export function deleteObject(
|
|
|
75
75
|
): Promise<void> {
|
|
76
76
|
return syscall("index.deleteObject", page, tag, ref);
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
export type {
|
|
80
|
+
AnchorHit,
|
|
81
|
+
ResolveAnchorResult,
|
|
82
|
+
} from "../../plugs/index/types.ts";
|
|
83
|
+
import type { ResolveAnchorResult } from "../../plugs/index/types.ts";
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Resolves a `$name` anchor to its host. Returns `ok: true` with page +
|
|
87
|
+
* hostTag + range on success, or `ok: false` with `missing`/`duplicate`
|
|
88
|
+
* reason. When `page` is provided, the lookup is filtered to that page.
|
|
89
|
+
*/
|
|
90
|
+
export function resolveAnchor(
|
|
91
|
+
name: string,
|
|
92
|
+
page?: string,
|
|
93
|
+
): Promise<ResolveAnchorResult> {
|
|
94
|
+
return syscall("index.resolveAnchor", name, page);
|
|
95
|
+
}
|
|
@@ -51,6 +51,21 @@ export function reloadPlugs(): Promise<void> {
|
|
|
51
51
|
return syscall("system.reloadPlugs");
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Load (or reload) a single plug from a space file path.
|
|
56
|
+
*/
|
|
57
|
+
export function loadPlug(path: string): Promise<void> {
|
|
58
|
+
return syscall("system.loadPlug", path);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Unload a plug previously loaded from the given space file path.
|
|
63
|
+
* Returns true if a plug was unloaded.
|
|
64
|
+
*/
|
|
65
|
+
export function unloadPlug(path: string): Promise<boolean> {
|
|
66
|
+
return syscall("system.unloadPlug", path);
|
|
67
|
+
}
|
|
68
|
+
|
|
54
69
|
/**
|
|
55
70
|
* Returns the current mode of the system, either "ro" (read-only) or "rw" (read-write)
|
|
56
71
|
*/
|
|
@@ -6,6 +6,48 @@ export type CodeWidgetT = {
|
|
|
6
6
|
renderMode?: "iframe";
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Predefined native menu items. Ignored in PWA builds; used by the
|
|
11
|
+
* SilverBullet desktop app to emit OS-native menu items (Cut/Copy/Paste,
|
|
12
|
+
* Quit, About, etc.) instead of a command-dispatching item.
|
|
13
|
+
*/
|
|
14
|
+
export type PredefinedMenuKind =
|
|
15
|
+
| "quit" | "about" | "services" | "hide" | "hideOthers" | "showAll"
|
|
16
|
+
| "closeWindow" | "minimize" | "maximize" | "fullscreen"
|
|
17
|
+
| "separator"
|
|
18
|
+
| "undo" | "redo" | "cut" | "copy" | "paste" | "selectAll";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A single native-menu placement for a command or submenu.
|
|
22
|
+
* Desktop-app only; ignored in PWA builds.
|
|
23
|
+
*
|
|
24
|
+
* - `location`: id of the target menu or submenu (e.g. "file",
|
|
25
|
+
* "edit.format").
|
|
26
|
+
* - `group`: sort-prefix convention "1_new", "2_dashboard", "9_close". Items
|
|
27
|
+
* are partitioned by group within a location; groups sort alphabetically
|
|
28
|
+
* with separators auto-inserted between them.
|
|
29
|
+
* - `order`: ascending within a group; tiebreak by label.
|
|
30
|
+
* - `label`: overrides the command's display label in the menu only.
|
|
31
|
+
* - `predefined`: emit an OS-native predefined item instead of a
|
|
32
|
+
* command-dispatching item.
|
|
33
|
+
* - `icon`: optional icon identifier; platform support varies.
|
|
34
|
+
*/
|
|
35
|
+
export type MenuContribution = {
|
|
36
|
+
location: string;
|
|
37
|
+
group?: string;
|
|
38
|
+
order?: number;
|
|
39
|
+
label?: string;
|
|
40
|
+
predefined?: PredefinedMenuKind;
|
|
41
|
+
icon?: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A menu placement value: a single contribution, an array (multiple
|
|
46
|
+
* placements), or `null` (hide this entry on the matching platform).
|
|
47
|
+
* Desktop-app only.
|
|
48
|
+
*/
|
|
49
|
+
export type MenuPlacement = MenuContribution | MenuContribution[] | null;
|
|
50
|
+
|
|
9
51
|
export type CommandDef = {
|
|
10
52
|
name: string;
|
|
11
53
|
|
|
@@ -21,6 +63,27 @@ export type CommandDef = {
|
|
|
21
63
|
hide?: boolean;
|
|
22
64
|
requireMode?: "rw" | "ro";
|
|
23
65
|
requireEditor?: "any" | "page" | "notpage" | string;
|
|
66
|
+
|
|
67
|
+
// When true, this binding is NOT registered while vim mode is active,
|
|
68
|
+
// so the key falls through to vim.
|
|
69
|
+
disableInVim?: boolean;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Desktop-app only. Native menu placement for this command.
|
|
73
|
+
*
|
|
74
|
+
* Naming note: the existing `key`/`mac` pair uses a bare platform name
|
|
75
|
+
* for the override. That pattern doesn't extend cleanly here — bare
|
|
76
|
+
* `mac` is already taken by the keybinding override, and `windows` /
|
|
77
|
+
* `linux` as top-level fields would be ambiguous. The `menu` + capital
|
|
78
|
+
* platform suffix pattern keeps overrides unambiguous.
|
|
79
|
+
*/
|
|
80
|
+
menu?: MenuPlacement;
|
|
81
|
+
/** Platform-specific override: replaces `menu` on macOS. */
|
|
82
|
+
menuMac?: MenuPlacement;
|
|
83
|
+
/** Platform-specific override: replaces `menu` on Windows. */
|
|
84
|
+
menuWindows?: MenuPlacement;
|
|
85
|
+
/** Platform-specific override: replaces `menu` on Linux. */
|
|
86
|
+
menuLinux?: MenuPlacement;
|
|
24
87
|
};
|
|
25
88
|
export type CommandHookT = {
|
|
26
89
|
command?: CommandDef;
|