@silverbulletmd/silverbullet 2.8.1 → 2.10.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 +42 -25
- package/client/plugos/hooks/syscall.ts +24 -10
- 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 +1432 -700
- package/client/plugos/syscalls/event.ts +46 -13
- package/client/plugos/syscalls/fetch.ts +123 -82
- package/client/plugos/syscalls/index.ts +243 -114
- package/client/plugos/syscalls/jsonschema.ts +107 -8
- package/client/plugos/syscalls/language.ts +38 -12
- package/client/plugos/syscalls/markdown.ts +166 -50
- package/client/plugos/syscalls/mq.ts +93 -20
- package/client/plugos/syscalls/schema_introspection.ts +33 -0
- package/client/plugos/syscalls/service_registry.ts +74 -20
- package/client/plugos/syscalls/shell.ts +51 -20
- package/client/plugos/syscalls/space.ts +169 -113
- package/client/plugos/syscalls/sync.ts +50 -19
- package/client/plugos/syscalls/system.ts +236 -139
- package/client/plugos/system.ts +21 -5
- package/client/space_lua/api_documentation.ts +107 -0
- package/client/space_lua/ast.ts +13 -0
- package/client/space_lua/eval.ts +12 -4
- package/client/space_lua/parse.ts +254 -119
- package/client/space_lua/pretty_print.ts +465 -0
- package/client/space_lua/query_collection.ts +3 -3
- package/client/space_lua/render_widget.ts +156 -0
- package/client/space_lua/runtime.ts +83 -22
- package/client/space_lua/stdlib/crypto.ts +8 -3
- package/client/space_lua/stdlib/encoding.ts +27 -9
- package/client/space_lua/stdlib/js.ts +137 -22
- package/client/space_lua/stdlib/load.ts +26 -17
- package/client/space_lua/stdlib/math.ts +323 -118
- package/client/space_lua/stdlib/net.ts +57 -9
- package/client/space_lua/stdlib/os.ts +111 -44
- package/client/space_lua/stdlib/space_lua.ts +397 -13
- package/client/space_lua/stdlib/string.ts +282 -104
- package/client/space_lua/stdlib/string_pack.ts +58 -19
- package/client/space_lua/stdlib/table.ts +195 -40
- package/client/space_lua/stdlib.ts +336 -94
- package/client/space_lua/syscalls.ts +270 -0
- package/dist/plug-compile.js +1 -1
- package/package.json +12 -4
- package/plug-api/lib/ref.ts +96 -0
- package/plug-api/lib/shortcut.ts +2 -1
- package/plug-api/syscalls/config.ts +5 -3
- package/plug-api/syscalls/editor.ts +23 -2
- package/plug-api/syscalls/index.ts +24 -1
- package/plug-api/syscalls/jsonschema.ts +9 -0
- package/plug-api/syscalls/lua.ts +28 -1
- package/plug-api/syscalls/shell.ts +0 -1
- package/plug-api/syscalls/system.ts +7 -0
- package/plug-api/system_mock.ts +2 -2
- package/plug-api/types/config.ts +1 -1
- package/plug-api/types/index.ts +52 -1
- package/plug-api/types/manifest.ts +22 -4
- package/plug-api/ui/cx.ts +4 -0
- package/plug-api/ui/index.ts +22 -0
- package/plug-api/ui/panel_styles.ts +33 -0
- package/plug-api/ui/slugify.ts +44 -0
- package/plugs/builtin_plugs.ts +1 -0
- package/client/plugos/syscalls/lua.ts +0 -58
|
@@ -282,38 +282,71 @@ function luaFormatTime(fmt: string, d: Date, utc: boolean): string {
|
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
export const osApi = new LuaTable({
|
|
285
|
-
time: new LuaBuiltinFunction(
|
|
286
|
-
|
|
287
|
-
if (
|
|
288
|
-
|
|
285
|
+
time: new LuaBuiltinFunction({
|
|
286
|
+
callback: (_sf, tbl?: LuaTable) => {
|
|
287
|
+
if (tbl) {
|
|
288
|
+
if (!tbl.has("year")) {
|
|
289
|
+
throw new Error("time(): year is required");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!tbl.has("month")) {
|
|
293
|
+
throw new Error("time(): month is required");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!tbl.has("day")) {
|
|
297
|
+
throw new Error("time(): day is required");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const year = tbl.get("year");
|
|
301
|
+
const month = tbl.get("month");
|
|
302
|
+
const day = tbl.get("day");
|
|
303
|
+
const hour = tbl.get("hour") ?? 12;
|
|
304
|
+
const min = tbl.get("min") ?? 0;
|
|
305
|
+
const sec = tbl.get("sec") ?? 0;
|
|
306
|
+
const date = new Date(year, month - 1, day, hour, min, sec);
|
|
307
|
+
|
|
308
|
+
return Math.floor(date.getTime() / 1000);
|
|
289
309
|
}
|
|
290
310
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
+
return Math.floor(Date.now() / 1000);
|
|
312
|
+
},
|
|
313
|
+
description:
|
|
314
|
+
"Returns the current Unix timestamp or one built from a local date table.",
|
|
315
|
+
signatures: ["os.time(): integer", "os.time(dateTable): integer"],
|
|
316
|
+
parameters: [
|
|
317
|
+
{
|
|
318
|
+
name: "dateTable",
|
|
319
|
+
type: "table",
|
|
320
|
+
description:
|
|
321
|
+
"Local date fields `year`, `month`, `day`, and optional `hour`, `min`, and `sec`.",
|
|
322
|
+
optional: true,
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
returns: [
|
|
326
|
+
{ type: "integer", description: "Seconds since the Unix epoch." },
|
|
327
|
+
],
|
|
328
|
+
examples: [
|
|
329
|
+
{
|
|
330
|
+
code: "local timestamp = os.time({year = 2020, month = 1, day = 1})",
|
|
331
|
+
},
|
|
332
|
+
],
|
|
311
333
|
}),
|
|
312
334
|
|
|
313
335
|
// Returns the difference, from time `t1` to time `t2` in seconds
|
|
314
336
|
// In POSIX and some other systems, this value is exactly $t2-t1$.
|
|
315
|
-
difftime: new LuaBuiltinFunction(
|
|
316
|
-
|
|
337
|
+
difftime: new LuaBuiltinFunction({
|
|
338
|
+
callback: (_sf, t2: number, t1: number): number => {
|
|
339
|
+
return t2 - t1;
|
|
340
|
+
},
|
|
341
|
+
description:
|
|
342
|
+
"Returns the difference in seconds from timestamp `t1` to `t2`.",
|
|
343
|
+
parameters: [
|
|
344
|
+
{ name: "t2", type: "number" },
|
|
345
|
+
{ name: "t1", type: "number" },
|
|
346
|
+
],
|
|
347
|
+
returns: [
|
|
348
|
+
{ type: "number", description: "The value `t2 - t1` in seconds." },
|
|
349
|
+
],
|
|
317
350
|
}),
|
|
318
351
|
|
|
319
352
|
// Returns a string or a table containing date and time, formatted
|
|
@@ -336,29 +369,63 @@ export const osApi = new LuaTable({
|
|
|
336
369
|
// Otherwise, format specifiers follow ISO C `strftime`.
|
|
337
370
|
//
|
|
338
371
|
// If format is absent, it defaults to `%c`.
|
|
339
|
-
date: new LuaBuiltinFunction(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
372
|
+
date: new LuaBuiltinFunction({
|
|
373
|
+
callback: (_sf, format?: string, timestamp?: number) => {
|
|
374
|
+
let fmt = format ?? "%c";
|
|
375
|
+
let utc = false;
|
|
376
|
+
|
|
377
|
+
if (fmt.startsWith("!")) {
|
|
378
|
+
utc = true;
|
|
379
|
+
fmt = fmt.slice(1);
|
|
380
|
+
}
|
|
347
381
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
382
|
+
const d =
|
|
383
|
+
timestamp !== undefined && timestamp !== null
|
|
384
|
+
? new Date(timestamp * 1000)
|
|
385
|
+
: new Date();
|
|
352
386
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
387
|
+
if (fmt === "*t") {
|
|
388
|
+
return dateTable(d, utc);
|
|
389
|
+
}
|
|
356
390
|
|
|
357
|
-
|
|
391
|
+
return luaFormatTime(fmt, d, utc);
|
|
392
|
+
},
|
|
393
|
+
description:
|
|
394
|
+
"Formats a timestamp as a date string or date table, optionally in UTC.",
|
|
395
|
+
parameters: [
|
|
396
|
+
{
|
|
397
|
+
name: "format",
|
|
398
|
+
type: "string",
|
|
399
|
+
description:
|
|
400
|
+
"`strftime`-style format, `*t` for a table, and optional leading `!` for UTC.",
|
|
401
|
+
optional: true,
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
name: "timestamp",
|
|
405
|
+
type: "number",
|
|
406
|
+
description: "Unix timestamp; defaults to the current time.",
|
|
407
|
+
optional: true,
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
returns: [
|
|
411
|
+
{ type: "string|table", description: "Formatted date or date fields." },
|
|
412
|
+
],
|
|
413
|
+
examples: [
|
|
414
|
+
{ code: 'print(os.date("%Y-%m-%d"))\nlocal utc = os.date("!*t")' },
|
|
415
|
+
],
|
|
358
416
|
}),
|
|
359
417
|
|
|
360
418
|
// Returns an approximation of CPU time used by the program in seconds.
|
|
361
|
-
clock: new LuaBuiltinFunction(
|
|
362
|
-
|
|
419
|
+
clock: new LuaBuiltinFunction({
|
|
420
|
+
callback: (_sf): number => {
|
|
421
|
+
return performance.now() / 1000.0;
|
|
422
|
+
},
|
|
423
|
+
description: "Returns a high-resolution elapsed time value in seconds.",
|
|
424
|
+
returns: [
|
|
425
|
+
{
|
|
426
|
+
type: "number",
|
|
427
|
+
description: "Browser performance timer in seconds.",
|
|
428
|
+
},
|
|
429
|
+
],
|
|
363
430
|
}),
|
|
364
431
|
});
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { LuaFunctionInfo } from "../../../plug-api/types/index.ts";
|
|
2
|
+
import { renderApiDocumentationMarkdown } from "../api_documentation.ts";
|
|
3
|
+
import type { LuaBlock, LuaExpression } from "../ast.ts";
|
|
3
4
|
import { evalExpression } from "../eval.ts";
|
|
5
|
+
import { parseBlock, parseExpressionString } from "../parse.ts";
|
|
4
6
|
import {
|
|
7
|
+
type PrintOptions,
|
|
8
|
+
prettyPrintBlock,
|
|
9
|
+
prettyPrintExpression,
|
|
10
|
+
} from "../pretty_print.ts";
|
|
11
|
+
import {
|
|
12
|
+
type ILuaFunction,
|
|
13
|
+
isILuaFunction,
|
|
5
14
|
jsToLuaValue,
|
|
6
15
|
LuaBuiltinFunction,
|
|
7
16
|
LuaEnv,
|
|
@@ -40,6 +49,112 @@ function createAugmentedEnv(
|
|
|
40
49
|
return env;
|
|
41
50
|
}
|
|
42
51
|
|
|
52
|
+
function globalEnv(sf: LuaStackFrame): LuaEnv {
|
|
53
|
+
const env = sf.threadLocal.get("_GLOBAL");
|
|
54
|
+
if (!(env instanceof LuaEnv)) {
|
|
55
|
+
throw new Error("_GLOBAL not defined");
|
|
56
|
+
}
|
|
57
|
+
return env;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveApiValue(
|
|
61
|
+
sf: LuaStackFrame,
|
|
62
|
+
path: string,
|
|
63
|
+
): ILuaFunction | LuaTable | LuaEnv | null {
|
|
64
|
+
let value: any = globalEnv(sf);
|
|
65
|
+
for (const part of path.split(".")) {
|
|
66
|
+
if (value instanceof LuaEnv || value instanceof LuaTable) {
|
|
67
|
+
value = value.get(part, sf);
|
|
68
|
+
} else {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (value && typeof value.then === "function") {
|
|
72
|
+
throw new Error("Cannot describe asynchronously resolved API values");
|
|
73
|
+
}
|
|
74
|
+
if (value === null || value === undefined) return null;
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function functionInfo(
|
|
80
|
+
value: unknown,
|
|
81
|
+
resolvedName?: string,
|
|
82
|
+
): LuaFunctionInfo | null {
|
|
83
|
+
if (!isILuaFunction(value)) return null;
|
|
84
|
+
return {
|
|
85
|
+
...(value.info ?? { kind: "builtin" }),
|
|
86
|
+
name: value.info?.name ?? resolvedName,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function describeFunction(
|
|
91
|
+
value: unknown,
|
|
92
|
+
resolvedName?: string,
|
|
93
|
+
): LuaTable | null {
|
|
94
|
+
const info = functionInfo(value, resolvedName);
|
|
95
|
+
return info ? (jsToLuaValue(info) as LuaTable) : null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function listFunctionInfo(
|
|
99
|
+
sf: LuaStackFrame,
|
|
100
|
+
target?: LuaTable | string,
|
|
101
|
+
): LuaFunctionInfo[] {
|
|
102
|
+
let namespace: LuaTable | LuaEnv;
|
|
103
|
+
let prefix = "";
|
|
104
|
+
if (typeof target === "string") {
|
|
105
|
+
const resolved = resolveApiValue(sf, target);
|
|
106
|
+
if (!(resolved instanceof LuaTable) && !(resolved instanceof LuaEnv)) {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
namespace = resolved;
|
|
110
|
+
prefix = `${target}.`;
|
|
111
|
+
} else if (target instanceof LuaTable) {
|
|
112
|
+
namespace = target;
|
|
113
|
+
} else {
|
|
114
|
+
namespace = globalEnv(sf);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const functions: LuaFunctionInfo[] = [];
|
|
118
|
+
for (const key of [...new Set(namespace.keys())].sort()) {
|
|
119
|
+
const value = namespace.get(key, sf);
|
|
120
|
+
if (value && typeof (value as any).then === "function") continue;
|
|
121
|
+
const info = functionInfo(value, `${prefix}${key}`);
|
|
122
|
+
if (info) functions.push(info);
|
|
123
|
+
}
|
|
124
|
+
return functions;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function functionNamespace(info: LuaFunctionInfo): string | undefined {
|
|
128
|
+
const separator = info.name?.lastIndexOf(".") ?? -1;
|
|
129
|
+
return separator > 0 ? info.name!.slice(0, separator) : undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function apiDocumentationTarget(
|
|
133
|
+
sf: LuaStackFrame,
|
|
134
|
+
target?: ILuaFunction | LuaTable | string,
|
|
135
|
+
): { functions: LuaFunctionInfo[]; context?: string } {
|
|
136
|
+
if (typeof target === "string") {
|
|
137
|
+
const resolved = resolveApiValue(sf, target);
|
|
138
|
+
const info = functionInfo(resolved, target);
|
|
139
|
+
if (info) {
|
|
140
|
+
return { functions: [info], context: functionNamespace(info) };
|
|
141
|
+
}
|
|
142
|
+
if (resolved instanceof LuaTable || resolved instanceof LuaEnv) {
|
|
143
|
+
return { functions: listFunctionInfo(sf, target), context: target };
|
|
144
|
+
}
|
|
145
|
+
return { functions: [], context: target };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const info = functionInfo(target);
|
|
149
|
+
if (info) {
|
|
150
|
+
return { functions: [info], context: functionNamespace(info) };
|
|
151
|
+
}
|
|
152
|
+
if (target instanceof LuaTable) {
|
|
153
|
+
return { functions: listFunctionInfo(sf, target) };
|
|
154
|
+
}
|
|
155
|
+
return { functions: listFunctionInfo(sf) };
|
|
156
|
+
}
|
|
157
|
+
|
|
43
158
|
/**
|
|
44
159
|
* Interpolates a string with lua expressions and returns the result.
|
|
45
160
|
*
|
|
@@ -101,7 +216,113 @@ export async function interpolateLuaString(
|
|
|
101
216
|
return result;
|
|
102
217
|
}
|
|
103
218
|
|
|
219
|
+
/**
|
|
220
|
+
* Converts an optional Lua options table into a `PrintOptions` object,
|
|
221
|
+
* keeping only the recognised keys with the expected types.
|
|
222
|
+
*/
|
|
223
|
+
function toPrintOptions(
|
|
224
|
+
sf: LuaStackFrame,
|
|
225
|
+
opts?: LuaTable,
|
|
226
|
+
): PrintOptions | undefined {
|
|
227
|
+
if (!opts) return undefined;
|
|
228
|
+
const js = luaValueToJS(opts, sf) as Record<string, unknown>;
|
|
229
|
+
const result: PrintOptions = {};
|
|
230
|
+
if (typeof js.indentWidth === "number") result.indentWidth = js.indentWidth;
|
|
231
|
+
if (js.quote === "double" || js.quote === "single") result.quote = js.quote;
|
|
232
|
+
if (typeof js.trailingComma === "boolean") {
|
|
233
|
+
result.trailingComma = js.trailingComma;
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
|
|
104
238
|
export const spaceluaApi = new LuaTable({
|
|
239
|
+
describe: new LuaBuiltinFunction({
|
|
240
|
+
callback: (sf, target: ILuaFunction | string) => {
|
|
241
|
+
const value =
|
|
242
|
+
typeof target === "string" ? resolveApiValue(sf, target) : target;
|
|
243
|
+
return describeFunction(
|
|
244
|
+
value,
|
|
245
|
+
typeof target === "string" ? target : undefined,
|
|
246
|
+
);
|
|
247
|
+
},
|
|
248
|
+
description:
|
|
249
|
+
"Returns structured documentation for a Lua function value or dotted API name.",
|
|
250
|
+
parameters: [
|
|
251
|
+
{
|
|
252
|
+
name: "functionOrName",
|
|
253
|
+
type: "function|string",
|
|
254
|
+
description: "Function value or dotted API name to inspect.",
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
returns: [
|
|
258
|
+
{
|
|
259
|
+
type: "table|nil",
|
|
260
|
+
description:
|
|
261
|
+
"Structured function metadata, or `nil` when the target is not a function.",
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
examples: [
|
|
265
|
+
{
|
|
266
|
+
code: 'local info = spacelua.describe(editor.getText)\nprint(info.name, info.kind, info.see)\n\nlocal sameInfo = spacelua.describe("editor.getText")',
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
see: "API/spacelua",
|
|
270
|
+
}),
|
|
271
|
+
listFunctions: new LuaBuiltinFunction({
|
|
272
|
+
callback: (sf, target?: LuaTable | string) =>
|
|
273
|
+
jsToLuaValue(listFunctionInfo(sf, target)),
|
|
274
|
+
description:
|
|
275
|
+
"Lists documented functions in the global environment or an API namespace.",
|
|
276
|
+
parameters: [
|
|
277
|
+
{
|
|
278
|
+
name: "namespace",
|
|
279
|
+
type: "table|string",
|
|
280
|
+
description: "Namespace table or dotted name; omit for globals.",
|
|
281
|
+
optional: true,
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
returns: [{ type: "table", description: "Function metadata records." }],
|
|
285
|
+
examples: [
|
|
286
|
+
{
|
|
287
|
+
code: 'for info in each(spacelua.listFunctions("editor")) do\n print(info.name, info.description or info.see)\nend',
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
see: "API/spacelua",
|
|
291
|
+
}),
|
|
292
|
+
renderApiDocumentation: new LuaBuiltinFunction({
|
|
293
|
+
callback: (sf, target?: ILuaFunction | LuaTable | string): string => {
|
|
294
|
+
const selection = apiDocumentationTarget(sf, target);
|
|
295
|
+
return renderApiDocumentationMarkdown(
|
|
296
|
+
selection.functions,
|
|
297
|
+
selection.context,
|
|
298
|
+
);
|
|
299
|
+
},
|
|
300
|
+
description:
|
|
301
|
+
"Renders API documentation for a function, namespace, or the global environment as Markdown.",
|
|
302
|
+
parameters: [
|
|
303
|
+
{
|
|
304
|
+
name: "target",
|
|
305
|
+
type: "function|table|string",
|
|
306
|
+
description:
|
|
307
|
+
"Function value, namespace table, or dotted API name to document; omit for globals.",
|
|
308
|
+
optional: true,
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
returns: [{ type: "string", description: "Rendered Markdown." }],
|
|
312
|
+
examples: [
|
|
313
|
+
{
|
|
314
|
+
code: '${spacelua.renderApiDocumentation("lua")}',
|
|
315
|
+
description: "Render a namespace as a live API-page directive.",
|
|
316
|
+
language: "markdown",
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
code: '${spacelua.renderApiDocumentation("editor.getText")}',
|
|
320
|
+
description: "Render one function by its dotted API name.",
|
|
321
|
+
language: "markdown",
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
see: "API/spacelua",
|
|
325
|
+
}),
|
|
105
326
|
/**
|
|
106
327
|
* Parses a lua expression and returns the parsed expression.
|
|
107
328
|
*
|
|
@@ -109,8 +330,116 @@ export const spaceluaApi = new LuaTable({
|
|
|
109
330
|
* @param luaExpression - The lua expression to parse.
|
|
110
331
|
* @returns The parsed expression.
|
|
111
332
|
*/
|
|
112
|
-
parseExpression: new LuaBuiltinFunction(
|
|
113
|
-
|
|
333
|
+
parseExpression: new LuaBuiltinFunction({
|
|
334
|
+
callback: (_sf, luaExpression: string) => {
|
|
335
|
+
return parseExpressionString(luaExpression);
|
|
336
|
+
},
|
|
337
|
+
description: "Parses a Lua expression and returns its AST.",
|
|
338
|
+
parameters: [
|
|
339
|
+
{
|
|
340
|
+
name: "luaExpression",
|
|
341
|
+
type: "string",
|
|
342
|
+
description: "Lua expression to parse.",
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
returns: [{ type: "table", description: "Parsed expression AST." }],
|
|
346
|
+
examples: [
|
|
347
|
+
{
|
|
348
|
+
code: 'local parsed = spacelua.parseExpression("1 + 1")',
|
|
349
|
+
},
|
|
350
|
+
],
|
|
351
|
+
see: "API/spacelua",
|
|
352
|
+
}),
|
|
353
|
+
/**
|
|
354
|
+
* Parses a lua chunk (block) and returns the parsed AST block.
|
|
355
|
+
*
|
|
356
|
+
* @param sf - The current space_lua state.
|
|
357
|
+
* @param code - The lua code to parse.
|
|
358
|
+
* @returns The parsed block.
|
|
359
|
+
*/
|
|
360
|
+
parseBlock: new LuaBuiltinFunction({
|
|
361
|
+
callback: (_sf, code: string): LuaBlock => {
|
|
362
|
+
return parseBlock(code);
|
|
363
|
+
},
|
|
364
|
+
description:
|
|
365
|
+
"Parses a Lua chunk and returns its AST. Blocks retain comments in source order with their exact text, kind, and source range.",
|
|
366
|
+
parameters: [
|
|
367
|
+
{ name: "code", type: "string", description: "Lua code to parse." },
|
|
368
|
+
],
|
|
369
|
+
returns: [{ type: "table", description: "Parsed block AST." }],
|
|
370
|
+
examples: [
|
|
371
|
+
{
|
|
372
|
+
code: 'local parsed = spacelua.parseBlock("local x = 1\\nreturn x + 2")',
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
see: "API/spacelua",
|
|
376
|
+
}),
|
|
377
|
+
/**
|
|
378
|
+
* Pretty-prints a parsed lua block AST back to formatted source.
|
|
379
|
+
*
|
|
380
|
+
* @param sf - The current space_lua state.
|
|
381
|
+
* @param block - The parsed lua block.
|
|
382
|
+
* @param opts - Optional formatting options.
|
|
383
|
+
* @returns The formatted lua source.
|
|
384
|
+
*/
|
|
385
|
+
prettyPrintBlock: new LuaBuiltinFunction({
|
|
386
|
+
callback: (sf, block: LuaBlock, opts?: LuaTable): string => {
|
|
387
|
+
return prettyPrintBlock(block, toPrintOptions(sf, opts));
|
|
388
|
+
},
|
|
389
|
+
description:
|
|
390
|
+
"Pretty-prints a parsed Lua block AST. Comments are preserved while their placement and indentation are normalized.",
|
|
391
|
+
parameters: [
|
|
392
|
+
{ name: "block", type: "table", description: "Parsed block AST." },
|
|
393
|
+
{
|
|
394
|
+
name: "options",
|
|
395
|
+
type: "table",
|
|
396
|
+
description:
|
|
397
|
+
"Formatting options: `indentWidth`, `quote`, and `trailingComma`.",
|
|
398
|
+
optional: true,
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
returns: [{ type: "string", description: "Formatted Lua source." }],
|
|
402
|
+
examples: [
|
|
403
|
+
{
|
|
404
|
+
code: 'local formatted = spacelua.prettyPrintBlock(spacelua.parseBlock("if a then return 1 end"))\nprint(formatted)',
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
see: "API/spacelua",
|
|
408
|
+
}),
|
|
409
|
+
/**
|
|
410
|
+
* Pretty-prints a parsed lua expression AST back to formatted source.
|
|
411
|
+
*
|
|
412
|
+
* @param sf - The current space_lua state.
|
|
413
|
+
* @param expr - The parsed lua expression.
|
|
414
|
+
* @param opts - Optional formatting options.
|
|
415
|
+
* @returns The formatted lua source.
|
|
416
|
+
*/
|
|
417
|
+
prettyPrintExpression: new LuaBuiltinFunction({
|
|
418
|
+
callback: (sf, expr: LuaExpression, opts?: LuaTable): string => {
|
|
419
|
+
return prettyPrintExpression(expr, toPrintOptions(sf, opts));
|
|
420
|
+
},
|
|
421
|
+
description: "Pretty-prints a parsed Lua expression AST.",
|
|
422
|
+
parameters: [
|
|
423
|
+
{
|
|
424
|
+
name: "parsedExpr",
|
|
425
|
+
type: "table",
|
|
426
|
+
description: "Parsed expression AST.",
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
name: "options",
|
|
430
|
+
type: "table",
|
|
431
|
+
description:
|
|
432
|
+
"Formatting options: `indentWidth`, `quote`, and `trailingComma`.",
|
|
433
|
+
optional: true,
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
returns: [{ type: "string", description: "Formatted Lua source." }],
|
|
437
|
+
examples: [
|
|
438
|
+
{
|
|
439
|
+
code: 'local parsed = spacelua.parseExpression("{a=1,b=2}")\nprint(spacelua.prettyPrintExpression(parsed))',
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
see: "API/spacelua",
|
|
114
443
|
}),
|
|
115
444
|
/**
|
|
116
445
|
* Evaluates a parsed lua expression and returns the result.
|
|
@@ -120,28 +449,83 @@ export const spaceluaApi = new LuaTable({
|
|
|
120
449
|
* @param envAugmentation - An optional environment to augment the global environment with.
|
|
121
450
|
* @returns The result of the evaluated expression.
|
|
122
451
|
*/
|
|
123
|
-
evalExpression: new LuaBuiltinFunction(
|
|
124
|
-
async (
|
|
452
|
+
evalExpression: new LuaBuiltinFunction({
|
|
453
|
+
callback: async (
|
|
454
|
+
sf,
|
|
455
|
+
parsedExpr: LuaExpression,
|
|
456
|
+
envAugmentation?: LuaTable,
|
|
457
|
+
) => {
|
|
125
458
|
const env = createAugmentedEnv(sf, envAugmentation);
|
|
126
459
|
return luaValueToJS(await evalExpression(parsedExpr, env, sf), sf);
|
|
127
460
|
},
|
|
128
|
-
|
|
461
|
+
description:
|
|
462
|
+
"Evaluates a parsed Lua expression, optionally with additional environment values.",
|
|
463
|
+
parameters: [
|
|
464
|
+
{
|
|
465
|
+
name: "parsedExpr",
|
|
466
|
+
type: "table",
|
|
467
|
+
description: "Parsed expression AST.",
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
name: "envAugmentation",
|
|
471
|
+
type: "table",
|
|
472
|
+
description: "Values added to the expression environment.",
|
|
473
|
+
optional: true,
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
returns: [{ description: "Evaluated result." }],
|
|
477
|
+
examples: [
|
|
478
|
+
{
|
|
479
|
+
code: 'local parsed = spacelua.parseExpression("x + y")\nlocal result = spacelua.evalExpression(parsed, {x = 1, y = 2})\nprint(result)',
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
see: "API/spacelua",
|
|
483
|
+
}),
|
|
129
484
|
/**
|
|
130
485
|
* Interpolates a string with lua expressions and returns the result.
|
|
131
486
|
*/
|
|
132
|
-
interpolate: new LuaBuiltinFunction(
|
|
133
|
-
(sf, template: string, envAugmentation?: LuaTable | any) => {
|
|
487
|
+
interpolate: new LuaBuiltinFunction({
|
|
488
|
+
callback: (sf, template: string, envAugmentation?: LuaTable | any) => {
|
|
134
489
|
if (envAugmentation && !(envAugmentation instanceof LuaTable)) {
|
|
135
490
|
envAugmentation = jsToLuaValue(envAugmentation);
|
|
136
491
|
}
|
|
137
492
|
return interpolateLuaString(sf, template, envAugmentation);
|
|
138
493
|
},
|
|
139
|
-
|
|
494
|
+
description:
|
|
495
|
+
"Interpolates `${...}` Lua expressions in a string, optionally with additional environment values.",
|
|
496
|
+
parameters: [
|
|
497
|
+
{
|
|
498
|
+
name: "template",
|
|
499
|
+
type: "string",
|
|
500
|
+
description: "Template containing `${...}` expressions.",
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
name: "envAugmentation",
|
|
504
|
+
type: "table",
|
|
505
|
+
description: "Values added to the interpolation environment.",
|
|
506
|
+
optional: true,
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
returns: [{ type: "string", description: "Interpolated string." }],
|
|
510
|
+
examples: [
|
|
511
|
+
{
|
|
512
|
+
code: 'local greeting = spacelua.interpolate("Hello ${name}!", {name = "Pete"})\nprint(greeting)',
|
|
513
|
+
},
|
|
514
|
+
],
|
|
515
|
+
see: "API/spacelua",
|
|
516
|
+
}),
|
|
140
517
|
/**
|
|
141
518
|
* Returns your SilverBullet instance's base URL
|
|
142
519
|
*/
|
|
143
|
-
baseUrl: new LuaBuiltinFunction(
|
|
144
|
-
|
|
145
|
-
|
|
520
|
+
baseUrl: new LuaBuiltinFunction({
|
|
521
|
+
callback: () => {
|
|
522
|
+
//NOTE: Removing trailing slash to stay compatible with original code: `location.protocol + "//" + location.host;`
|
|
523
|
+
return document.baseURI.replace(/\/*$/, "");
|
|
524
|
+
},
|
|
525
|
+
description:
|
|
526
|
+
"Returns the SilverBullet instance's base URL, or `nil` when run on the server.",
|
|
527
|
+
returns: [{ type: "string|nil" }],
|
|
528
|
+
examples: [{ code: "local url = spacelua.baseUrl()\nprint(url)" }],
|
|
529
|
+
see: "API/spacelua",
|
|
146
530
|
}),
|
|
147
531
|
});
|