@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.
Files changed (123) hide show
  1. package/README.md +38 -25
  2. package/client/asset_bundle/bundle.ts +0 -1
  3. package/client/config.ts +343 -0
  4. package/client/markdown_parser/constants.ts +3 -1
  5. package/client/plugos/hooks/command.ts +0 -5
  6. package/client/plugos/hooks/event.ts +0 -6
  7. package/client/plugos/hooks/mq.ts +0 -3
  8. package/client/plugos/hooks/slash_command.ts +1 -7
  9. package/client/plugos/hooks/syscall.ts +24 -14
  10. package/client/plugos/manifest_cache.ts +0 -32
  11. package/client/plugos/plug.ts +0 -3
  12. package/client/plugos/plug_compile.ts +3 -13
  13. package/client/plugos/sandboxes/worker_sandbox.ts +19 -9
  14. package/client/plugos/syscalls/asset.ts +61 -23
  15. package/client/plugos/syscalls/clientStore.ts +32 -6
  16. package/client/plugos/syscalls/client_code_widget.ts +9 -4
  17. package/client/plugos/syscalls/code_widget.ts +26 -11
  18. package/client/plugos/syscalls/config.ts +146 -30
  19. package/client/plugos/syscalls/datastore.ts +146 -40
  20. package/client/plugos/syscalls/editor.ts +1518 -722
  21. package/client/plugos/syscalls/event.ts +44 -13
  22. package/client/plugos/syscalls/fetch.ts +120 -83
  23. package/client/plugos/syscalls/icon.ts +46 -0
  24. package/client/plugos/syscalls/index.ts +267 -121
  25. package/client/plugos/syscalls/jsonschema.ts +107 -9
  26. package/client/plugos/syscalls/language.ts +38 -12
  27. package/client/plugos/syscalls/markdown.ts +166 -50
  28. package/client/plugos/syscalls/mq.ts +92 -20
  29. package/client/plugos/syscalls/navigator.ts +143 -0
  30. package/client/plugos/syscalls/schema_introspection.ts +33 -0
  31. package/client/plugos/syscalls/search.ts +44 -0
  32. package/client/plugos/syscalls/service_registry.ts +74 -20
  33. package/client/plugos/syscalls/shell.ts +51 -21
  34. package/client/plugos/syscalls/space.ts +412 -113
  35. package/client/plugos/syscalls/sync.ts +103 -20
  36. package/client/plugos/syscalls/system.ts +274 -139
  37. package/client/plugos/system.ts +28 -10
  38. package/client/plugos/worker_runtime.ts +0 -2
  39. package/client/space_lua/aggregates.ts +0 -16
  40. package/client/space_lua/api_documentation.ts +107 -0
  41. package/client/space_lua/ast.ts +13 -5
  42. package/client/space_lua/ast_narrow.ts +0 -5
  43. package/client/space_lua/budget.ts +113 -0
  44. package/client/space_lua/budget_ui.ts +49 -0
  45. package/client/space_lua/eval.ts +125 -92
  46. package/client/space_lua/labels.ts +0 -4
  47. package/client/space_lua/numeric.ts +0 -5
  48. package/client/space_lua/parse.ts +243 -125
  49. package/client/space_lua/pretty_print.ts +128 -54
  50. package/client/space_lua/quarantine.ts +127 -0
  51. package/client/space_lua/query_collection.ts +7 -51
  52. package/client/space_lua/query_env.ts +0 -2
  53. package/client/space_lua/render_lua_markdown.ts +2 -7
  54. package/client/space_lua/render_widget.ts +173 -0
  55. package/client/space_lua/runtime.ts +133 -92
  56. package/client/space_lua/stdlib/crypto.ts +8 -3
  57. package/client/space_lua/stdlib/encoding.ts +27 -9
  58. package/client/space_lua/stdlib/format.ts +0 -12
  59. package/client/space_lua/stdlib/js.ts +136 -23
  60. package/client/space_lua/stdlib/load.ts +24 -16
  61. package/client/space_lua/stdlib/math.ts +331 -133
  62. package/client/space_lua/stdlib/net.ts +57 -13
  63. package/client/space_lua/stdlib/os.ts +111 -54
  64. package/client/space_lua/stdlib/pattern.ts +10 -15
  65. package/client/space_lua/stdlib/space_lua.ts +344 -21
  66. package/client/space_lua/stdlib/string.ts +282 -104
  67. package/client/space_lua/stdlib/string_pack.ts +58 -22
  68. package/client/space_lua/stdlib/table.ts +195 -45
  69. package/client/space_lua/stdlib.ts +354 -125
  70. package/client/space_lua/syscalls.ts +270 -0
  71. package/client/space_lua/tonumber.ts +0 -9
  72. package/dist/plug-compile.js +2 -3
  73. package/package.json +15 -5
  74. package/plug-api/lib/async.ts +1 -6
  75. package/plug-api/lib/collation.ts +22 -0
  76. package/plug-api/lib/crypto.ts +16 -15
  77. package/plug-api/lib/dates.ts +33 -0
  78. package/plug-api/lib/fuzzy.ts +282 -0
  79. package/plug-api/lib/json.ts +0 -6
  80. package/plug-api/lib/limited_map.ts +0 -2
  81. package/plug-api/lib/link_write.ts +27 -0
  82. package/plug-api/{ui → lib}/panel_styles.ts +4 -3
  83. package/plug-api/lib/ref.ts +124 -5
  84. package/plug-api/lib/resolve.ts +0 -1
  85. package/plug-api/lib/resolve_path.ts +290 -0
  86. package/plug-api/lib/shortcut.ts +17 -1
  87. package/plug-api/lib/tags.ts +0 -3
  88. package/plug-api/lib/transclusion.ts +28 -1
  89. package/plug-api/lib/tree.ts +0 -5
  90. package/plug-api/lib/yaml.ts +3 -42
  91. package/plug-api/syscall.ts +1 -5
  92. package/plug-api/syscalls/config.ts +7 -5
  93. package/plug-api/syscalls/editor.ts +70 -208
  94. package/plug-api/syscalls/icon.ts +18 -0
  95. package/plug-api/syscalls/index.ts +39 -5
  96. package/plug-api/syscalls/jsonschema.ts +9 -0
  97. package/plug-api/syscalls/lua.ts +7 -0
  98. package/plug-api/syscalls/search.ts +11 -0
  99. package/plug-api/syscalls/shell.ts +0 -1
  100. package/plug-api/syscalls/space.ts +122 -5
  101. package/plug-api/syscalls/sync.ts +23 -2
  102. package/plug-api/syscalls/system.ts +53 -0
  103. package/plug-api/syscalls.ts +2 -0
  104. package/plug-api/system_mock.ts +15 -2
  105. package/plug-api/types/client.ts +4 -3
  106. package/plug-api/types/datastore.ts +11 -2
  107. package/plug-api/types/index.ts +62 -1
  108. package/plug-api/types/manifest.ts +22 -4
  109. package/plug-api/types/profile.ts +13 -0
  110. package/plug-api/types/revisions.ts +67 -0
  111. package/plug-api/ui/cx.ts +1 -3
  112. package/plug-api/ui/description.ts +64 -0
  113. package/plug-api/ui/hover.ts +69 -0
  114. package/plug-api/ui/index.ts +61 -2
  115. package/plug-api/ui/scroll.ts +30 -0
  116. package/plug-api/ui/slugify.ts +44 -0
  117. package/plug-api/ui/tree_model.ts +263 -0
  118. package/plug-api/ui/tree_types.ts +66 -0
  119. package/plug-api/ui/use_fit_collapse.ts +67 -0
  120. package/plugs/builtin_plugs.ts +0 -1
  121. package/plugs/index/types.ts +9 -0
  122. package/client/plugos/syscalls/lua.ts +0 -81
  123. package/plug-api/lib/memory_cache.ts +0 -21
@@ -28,22 +28,35 @@ function capturesToLua(caps: CaptureResult[]): any {
28
28
  }
29
29
 
30
30
  export const stringApi = new LuaTable({
31
- byte: new LuaBuiltinFunction((_sf, s: string, i?: number, j?: number) => {
32
- i = i ?? 1;
33
- j = j ?? i;
34
- if (j > s.length) j = s.length;
35
- if (i < 1) i = 1;
36
- const result = [];
37
- for (let k = i; k <= j; k++) {
38
- result.push(s.charCodeAt(k - 1));
39
- }
40
- return new LuaMultiRes(result);
41
- }),
42
- char: new LuaBuiltinFunction((_sf, ...args: number[]) => {
43
- return String.fromCharCode(...args);
44
- }),
45
- find: new LuaBuiltinFunction(
46
- (_sf, s: string, pattern: string, init = 1, plain = false) => {
31
+ byte: new LuaBuiltinFunction({
32
+ callback: (_sf, s: string, i?: number, j?: number) => {
33
+ i = i ?? 1;
34
+ j = j ?? i;
35
+ if (j > s.length) j = s.length;
36
+ if (i < 1) i = 1;
37
+ const result = [];
38
+ for (let k = i; k <= j; k++) {
39
+ result.push(s.charCodeAt(k - 1));
40
+ }
41
+ return new LuaMultiRes(result);
42
+ },
43
+ description:
44
+ "Returns the numeric character codes in the inclusive range from `i` to `j`.",
45
+ parameters: [
46
+ { name: "s", type: "string" },
47
+ { name: "i", type: "integer", optional: true },
48
+ { name: "j", type: "integer", optional: true },
49
+ ],
50
+ returns: [{ type: "integer", description: "One result per character." }],
51
+ }),
52
+ char: new LuaBuiltinFunction({
53
+ callback: (_sf, ...args: number[]) => String.fromCharCode(...args),
54
+ description: "Creates a string from numeric character codes.",
55
+ signatures: ["string.char(...): string"],
56
+ returns: [{ type: "string" }],
57
+ }),
58
+ find: new LuaBuiltinFunction({
59
+ callback: (_sf, s: string, pattern: string, init = 1, plain = false) => {
47
60
  const r = patternFind(s, pattern, init, plain);
48
61
  if (!r) return null;
49
62
  const result: any[] = [r.start, r.end];
@@ -52,15 +65,42 @@ export const stringApi = new LuaTable({
52
65
  }
53
66
  return new LuaMultiRes(result);
54
67
  },
55
- ),
56
- format: new LuaBuiltinFunction((_sf, format: string, ...args: any[]) => {
57
- for (let i = 0; i < args.length; i++) {
58
- args[i] = untagNumber(args[i]);
59
- }
60
- return luaFormat(format, ...args);
61
- }),
62
- gmatch: new LuaBuiltinFunction(
63
- (_sf, s: string, pattern: string, init = 1) => {
68
+ description:
69
+ "Finds the first Lua-pattern match and returns its bounds followed by captures.",
70
+ parameters: [
71
+ { name: "s", type: "string" },
72
+ { name: "pattern", type: "string" },
73
+ { name: "init", type: "integer", optional: true },
74
+ { name: "plain", type: "boolean", optional: true },
75
+ ],
76
+ returns: [
77
+ { type: "integer|nil", description: "Start index or `nil`." },
78
+ { type: "integer", description: "End index." },
79
+ ],
80
+ }),
81
+ format: new LuaBuiltinFunction({
82
+ callback: (_sf, format: string, ...args: any[]) => {
83
+ for (let i = 0; i < args.length; i++) {
84
+ args[i] = untagNumber(args[i]);
85
+ }
86
+ return luaFormat(format, ...args);
87
+ },
88
+ description: "Formats values according to a C-style format string.",
89
+ signatures: ["string.format(format, ...): string"],
90
+ parameters: [
91
+ { name: "format", type: "string" },
92
+ {
93
+ name: "...",
94
+ description: "Values consumed by conversion specifiers.",
95
+ },
96
+ ],
97
+ returns: [{ type: "string" }],
98
+ examples: [
99
+ { code: 'print(string.format("Name: %s, score: %.1f", "Ada", 9.5))' },
100
+ ],
101
+ }),
102
+ gmatch: new LuaBuiltinFunction({
103
+ callback: (_sf, s: string, pattern: string, init = 1) => {
64
104
  const iter = patternGmatch(s, pattern, init);
65
105
  return () => {
66
106
  const caps = iter();
@@ -68,9 +108,22 @@ export const stringApi = new LuaTable({
68
108
  return capturesToLua(caps);
69
109
  };
70
110
  },
71
- ),
72
- gsub: new LuaBuiltinFunction(
73
- async (sf, s: string, pattern: string, repl: any, n?: number) => {
111
+ description:
112
+ "Returns an iterator over successive Lua-pattern matches and captures.",
113
+ parameters: [
114
+ { name: "s", type: "string" },
115
+ { name: "pattern", type: "string" },
116
+ { name: "init", type: "integer", optional: true },
117
+ ],
118
+ returns: [{ type: "function", description: "Match iterator." }],
119
+ examples: [
120
+ {
121
+ code: 'for word in string.gmatch("hello world", "%w+") do\n print(word)\nend',
122
+ },
123
+ ],
124
+ }),
125
+ gsub: new LuaBuiltinFunction({
126
+ callback: async (sf, s: string, pattern: string, repl: any, n?: number) => {
74
127
  const callbacks: GsubCallbacks = {};
75
128
  if (typeof repl === "string") {
76
129
  callbacks.replString = repl;
@@ -103,61 +156,135 @@ export const stringApi = new LuaTable({
103
156
  const [result, count] = await patternGsub(s, pattern, callbacks, n);
104
157
  return new LuaMultiRes([result, count]);
105
158
  },
106
- ),
107
- len: new LuaBuiltinFunction((_sf, s: string) => {
108
- return s.length;
109
- }),
110
- lower: new LuaBuiltinFunction((_sf, s: string) => {
111
- return luaToString(s.toLowerCase());
112
- }),
113
- upper: new LuaBuiltinFunction((_sf, s: string) => {
114
- return luaToString(s.toUpperCase());
115
- }),
116
- match: new LuaBuiltinFunction((_sf, s: string, pattern: string, init = 1) => {
117
- const caps = patternMatch(s, pattern, init);
118
- if (!caps) return null;
119
- return capturesToLua(caps);
120
- }),
121
- rep: new LuaBuiltinFunction((_sf, s: string, n: number, sep?: string) => {
122
- if (n <= 0) return "";
123
- sep = sep ?? "";
124
- const parts: string[] = [];
125
- for (let i = 0; i < n; i++) {
126
- parts.push(s);
127
- }
128
- return parts.join(sep);
129
- }),
130
- reverse: new LuaBuiltinFunction((_sf, s: string) => {
131
- return s.split("").reverse().join("");
132
- }),
133
- sub: new LuaBuiltinFunction((_sf, s: string, i: number, j?: number) => {
134
- const len = s.length;
135
- let start: number;
136
- if (i > 0) {
137
- start = i;
138
- } else if (i < -len) {
139
- start = 1;
140
- } else {
141
- start = i === 0 ? 1 : len + i + 1;
142
- }
143
- let end: number;
144
- if (j === undefined || j === null || j > len) {
145
- end = len;
146
- } else if (j >= 0) {
147
- end = j;
148
- } else if (j < -len) {
149
- end = 0;
150
- } else {
151
- end = len + j + 1;
152
- }
153
- if (start <= end) {
154
- return s.substring(start - 1, end);
155
- }
156
- return "";
159
+ description:
160
+ "Replaces Lua-pattern matches using a string, table, or function replacement.",
161
+ parameters: [
162
+ { name: "s", type: "string" },
163
+ { name: "pattern", type: "string" },
164
+ { name: "replacement", type: "string|table|function" },
165
+ { name: "n", type: "integer", optional: true },
166
+ ],
167
+ returns: [
168
+ { type: "string", description: "Result string." },
169
+ { type: "integer", description: "Number of replacements." },
170
+ ],
171
+ examples: [
172
+ {
173
+ code: 'local result, count = string.gsub("hello hello", "hello", "hi", 1)\nprint(result, count) -- hi hello 1',
174
+ },
175
+ ],
176
+ }),
177
+ len: new LuaBuiltinFunction({
178
+ callback: (_sf, s: string) => s.length,
179
+ description: "Returns the length of a string.",
180
+ parameters: [{ name: "s", type: "string" }],
181
+ returns: [{ type: "integer" }],
182
+ }),
183
+ lower: new LuaBuiltinFunction({
184
+ callback: (_sf, s: string) => luaToString(s.toLowerCase()),
185
+ description: "Returns a copy of a string converted to lowercase.",
186
+ parameters: [{ name: "s", type: "string" }],
187
+ returns: [{ type: "string" }],
188
+ }),
189
+ upper: new LuaBuiltinFunction({
190
+ callback: (_sf, s: string) => luaToString(s.toUpperCase()),
191
+ description: "Returns a copy of a string converted to uppercase.",
192
+ parameters: [{ name: "s", type: "string" }],
193
+ returns: [{ type: "string" }],
194
+ }),
195
+ match: new LuaBuiltinFunction({
196
+ callback: (_sf, s: string, pattern: string, init = 1) => {
197
+ const caps = patternMatch(s, pattern, init);
198
+ if (!caps) return null;
199
+ return capturesToLua(caps);
200
+ },
201
+ description:
202
+ "Returns captures from the first Lua-pattern match, or `nil` when none is found.",
203
+ parameters: [
204
+ { name: "s", type: "string" },
205
+ { name: "pattern", type: "string" },
206
+ { name: "init", type: "integer", optional: true },
207
+ ],
208
+ returns: [{ description: "Pattern captures, whole match, or `nil`." }],
209
+ examples: [
210
+ { code: 'local year, month = string.match("2024-03", "(%d+)%-(%d+)")' },
211
+ ],
212
+ }),
213
+ rep: new LuaBuiltinFunction({
214
+ callback: (_sf, s: string, n: number, sep?: string) => {
215
+ if (n <= 0) return "";
216
+ sep = sep ?? "";
217
+ const parts: string[] = [];
218
+ for (let i = 0; i < n; i++) {
219
+ parts.push(s);
220
+ }
221
+ return parts.join(sep);
222
+ },
223
+ description:
224
+ "Returns `n` copies of a string joined by an optional separator.",
225
+ parameters: [
226
+ { name: "s", type: "string" },
227
+ { name: "n", type: "integer" },
228
+ { name: "sep", type: "string", optional: true },
229
+ ],
230
+ returns: [{ type: "string" }],
231
+ }),
232
+ reverse: new LuaBuiltinFunction({
233
+ callback: (_sf, s: string) => s.split("").reverse().join(""),
234
+ description: "Returns a string with its characters in reverse order.",
235
+ parameters: [{ name: "s", type: "string" }],
236
+ returns: [{ type: "string" }],
237
+ }),
238
+ sub: new LuaBuiltinFunction({
239
+ callback: (_sf, s: string, i: number, j?: number) => {
240
+ const len = s.length;
241
+ let start: number;
242
+ if (i > 0) {
243
+ start = i;
244
+ } else if (i < -len) {
245
+ start = 1;
246
+ } else {
247
+ start = i === 0 ? 1 : len + i + 1;
248
+ }
249
+ let end: number;
250
+ if (j === undefined || j === null || j > len) {
251
+ end = len;
252
+ } else if (j >= 0) {
253
+ end = j;
254
+ } else if (j < -len) {
255
+ end = 0;
256
+ } else {
257
+ end = len + j + 1;
258
+ }
259
+ if (start <= end) {
260
+ return s.substring(start - 1, end);
261
+ }
262
+ return "";
263
+ },
264
+ description:
265
+ "Returns the substring from inclusive index `i` through `j`, supporting negative indices.",
266
+ parameters: [
267
+ { name: "s", type: "string" },
268
+ { name: "i", type: "integer" },
269
+ { name: "j", type: "integer", optional: true },
270
+ ],
271
+ returns: [{ type: "string" }],
157
272
  }),
158
273
 
159
- split: new LuaBuiltinFunction((_sf, s: string, sep: string) => {
160
- return s.split(sep);
274
+ split: new LuaBuiltinFunction({
275
+ callback: (_sf, s: string, sep: string) => s.split(sep),
276
+ description:
277
+ "Splits a string on a literal separator and returns the substrings.",
278
+ parameters: [
279
+ { name: "s", type: "string" },
280
+ { name: "sep", type: "string" },
281
+ ],
282
+ returns: [{ type: "table" }],
283
+ examples: [
284
+ {
285
+ code: 'for part in each(string.split("a,b,c", ",")) do\n print(part)\nend',
286
+ },
287
+ ],
161
288
  }),
162
289
 
163
290
  pack: strPackFn,
@@ -165,34 +292,85 @@ export const stringApi = new LuaTable({
165
292
  packsize: strPackSizeFn,
166
293
 
167
294
  // Non-standard extensions
168
- startsWith: new LuaBuiltinFunction((_sf, s: string, prefix: string) => {
169
- return s.startsWith(prefix);
295
+ startsWith: new LuaBuiltinFunction({
296
+ callback: (_sf, s: string, prefix: string) => s.startsWith(prefix),
297
+ description: "Returns whether a string starts with a literal prefix.",
298
+ parameters: [
299
+ { name: "s", type: "string" },
300
+ { name: "prefix", type: "string" },
301
+ ],
302
+ returns: [{ type: "boolean" }],
170
303
  }),
171
- endsWith: new LuaBuiltinFunction((_sf, s: string, suffix: string) => {
172
- return s.endsWith(suffix);
304
+ endsWith: new LuaBuiltinFunction({
305
+ callback: (_sf, s: string, suffix: string) => s.endsWith(suffix),
306
+ description: "Returns whether a string ends with a literal suffix.",
307
+ parameters: [
308
+ { name: "s", type: "string" },
309
+ { name: "suffix", type: "string" },
310
+ ],
311
+ returns: [{ type: "boolean" }],
173
312
  }),
174
- trim: new LuaBuiltinFunction((_sf, s: string) => {
175
- return s.trim();
313
+ trim: new LuaBuiltinFunction({
314
+ callback: (_sf, s: string) => s.trim(),
315
+ description: "Removes whitespace from both ends of a string.",
316
+ parameters: [{ name: "s", type: "string" }],
317
+ returns: [{ type: "string" }],
176
318
  }),
177
- trimStart: new LuaBuiltinFunction((_sf, s: string) => {
178
- return s.trimStart();
319
+ trimStart: new LuaBuiltinFunction({
320
+ callback: (_sf, s: string) => s.trimStart(),
321
+ description: "Removes whitespace from the beginning of a string.",
322
+ parameters: [{ name: "s", type: "string" }],
323
+ returns: [{ type: "string" }],
179
324
  }),
180
- trimEnd: new LuaBuiltinFunction((_sf, s: string) => {
181
- return s.trimEnd();
325
+ trimEnd: new LuaBuiltinFunction({
326
+ callback: (_sf, s: string) => s.trimEnd(),
327
+ description: "Removes whitespace from the end of a string.",
328
+ parameters: [{ name: "s", type: "string" }],
329
+ returns: [{ type: "string" }],
182
330
  }),
183
- matchRegex: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
184
- const regex = new RegExp(pattern);
185
- const result = s.match(regex);
186
- return jsToLuaValue(result);
331
+ matchRegex: new LuaBuiltinFunction({
332
+ callback: (_sf, s: string, pattern: string) => {
333
+ const regex = new RegExp(pattern);
334
+ const result = s.match(regex);
335
+ return jsToLuaValue(result);
336
+ },
337
+ description:
338
+ "Matches a string with a JavaScript regular expression and returns the match array.",
339
+ parameters: [
340
+ { name: "s", type: "string" },
341
+ { name: "pattern", type: "string" },
342
+ ],
343
+ returns: [{ type: "table|nil" }],
344
+ examples: [
345
+ {
346
+ code: 'local match = string.matchRegex("hello123", "([a-z]+)([0-9]+)")\nprint(match[1], match[2], match[3])',
347
+ },
348
+ ],
187
349
  }),
188
- matchRegexAll: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
189
- const regex = new RegExp(pattern, "g");
190
- return () => {
191
- const match = regex.exec(s);
192
- if (!match) {
193
- return;
194
- }
195
- return jsToLuaValue(match);
196
- };
350
+ matchRegexAll: new LuaBuiltinFunction({
351
+ callback: (_sf, s: string, pattern: string) => {
352
+ const regex = new RegExp(pattern, "g");
353
+ return () => {
354
+ const match = regex.exec(s);
355
+ if (!match) {
356
+ return;
357
+ }
358
+ return jsToLuaValue(match);
359
+ };
360
+ },
361
+ description:
362
+ "Returns an iterator over all JavaScript regular-expression matches.",
363
+ parameters: [
364
+ { name: "s", type: "string" },
365
+ { name: "pattern", type: "string" },
366
+ ],
367
+ returns: [
368
+ { type: "function", description: "Iterator yielding match arrays." },
369
+ ],
370
+ examples: [
371
+ {
372
+ code: 'for match in string.matchRegexAll("a1b2", "([a-z])([0-9])") do\n print(match[1], match[2], match[3])\nend',
373
+ },
374
+ ],
197
375
  }),
198
376
  });
@@ -145,7 +145,6 @@ function getOption(
145
145
  }
146
146
  }
147
147
 
148
- // Compute alignment padding
149
148
  function getDetails(
150
149
  fmt: string,
151
150
  pos: number,
@@ -252,8 +251,8 @@ function unpackFloat64(
252
251
  );
253
252
  }
254
253
 
255
- export const strPackFn = new LuaBuiltinFunction(
256
- (sf, fmt: string, ...args: any[]) => {
254
+ export const strPackFn = new LuaBuiltinFunction({
255
+ callback: (sf, fmt: string, ...args: any[]) => {
257
256
  const h = makeHeader();
258
257
  const parts: Uint8Array[] = [];
259
258
  let totalsize = 0;
@@ -264,7 +263,6 @@ export const strPackFn = new LuaBuiltinFunction(
264
263
  let opt: ParsedOption;
265
264
  [opt, pos] = getDetails(fmt, pos, h, totalsize);
266
265
 
267
- // alignment padding
268
266
  if (opt.ntoalign > 0) {
269
267
  parts.push(new Uint8Array(opt.ntoalign));
270
268
  totalsize += opt.ntoalign;
@@ -349,7 +347,6 @@ export const strPackFn = new LuaBuiltinFunction(
349
347
  }
350
348
  }
351
349
 
352
- // Concatenate all parts into one binary string (latin-1 encoding)
353
350
  let total = 0;
354
351
  for (const p of parts) total += p.length;
355
352
  const out = new Uint8Array(total);
@@ -364,10 +361,18 @@ export const strPackFn = new LuaBuiltinFunction(
364
361
  for (let i = 0; i < out.length; i++) result += String.fromCharCode(out[i]);
365
362
  return result;
366
363
  },
367
- );
364
+ description:
365
+ "Packs values into a binary string according to a Lua 5.4 format string.",
366
+ signatures: ["string.pack(format, ...): string"],
367
+ parameters: [
368
+ { name: "format", type: "string", description: "Binary packing format." },
369
+ { name: "...", description: "Values consumed by the format options." },
370
+ ],
371
+ returns: [{ type: "string", description: "Packed binary string." }],
372
+ });
368
373
 
369
- export const strUnpackFn = new LuaBuiltinFunction(
370
- (sf, fmt: string, data: string, init?: number) => {
374
+ export const strUnpackFn = new LuaBuiltinFunction({
375
+ callback: (sf, fmt: string, data: string, init?: number) => {
371
376
  const h = makeHeader();
372
377
 
373
378
  const buf = new Uint8Array(data.length);
@@ -468,23 +473,54 @@ export const strUnpackFn = new LuaBuiltinFunction(
468
473
  results.push(pos + 1);
469
474
  return new LuaMultiRes(results);
470
475
  },
471
- );
476
+ description:
477
+ "Unpacks values from a binary string according to a Lua 5.4 format string.",
478
+ parameters: [
479
+ {
480
+ name: "format",
481
+ type: "string",
482
+ description: "Binary unpacking format.",
483
+ },
484
+ { name: "data", type: "string", description: "Packed binary string." },
485
+ {
486
+ name: "init",
487
+ type: "integer",
488
+ description: "One-based starting position.",
489
+ optional: true,
490
+ },
491
+ ],
492
+ returns: [
493
+ { description: "Unpacked values followed by the next unread position." },
494
+ ],
495
+ });
472
496
 
473
- export const strPackSizeFn = new LuaBuiltinFunction((_sf, fmt: string) => {
474
- const h = makeHeader();
475
- let totalsize = 0;
476
- let pos = 0;
497
+ export const strPackSizeFn = new LuaBuiltinFunction({
498
+ callback: (_sf, fmt: string) => {
499
+ const h = makeHeader();
500
+ let totalsize = 0;
501
+ let pos = 0;
477
502
 
478
- while (pos < fmt.length) {
479
- let opt: ParsedOption;
480
- [opt, pos] = getDetails(fmt, pos, h, totalsize);
503
+ while (pos < fmt.length) {
504
+ let opt: ParsedOption;
505
+ [opt, pos] = getDetails(fmt, pos, h, totalsize);
481
506
 
482
- if (opt.opt === "string" || opt.opt === "zstr") {
483
- throw new LuaRuntimeError("variable-length format", _sf);
484
- }
507
+ if (opt.opt === "string" || opt.opt === "zstr") {
508
+ throw new LuaRuntimeError("variable-length format", _sf);
509
+ }
485
510
 
486
- totalsize += opt.ntoalign + opt.size;
487
- }
511
+ totalsize += opt.ntoalign + opt.size;
512
+ }
488
513
 
489
- return totalsize;
514
+ return totalsize;
515
+ },
516
+ description:
517
+ "Returns the byte size of a fixed-length Lua 5.4 packing format.",
518
+ parameters: [
519
+ {
520
+ name: "format",
521
+ type: "string",
522
+ description: "Fixed-length binary packing format.",
523
+ },
524
+ ],
525
+ returns: [{ type: "integer", description: "Packed byte count." }],
490
526
  });