@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
@@ -10,6 +10,7 @@ import {
10
10
  type MarkdownExpandOptions,
11
11
  } from "../../markdown_renderer/inline.ts";
12
12
  import type { Client } from "../../client.ts";
13
+ import { bakeSectionsInText } from "../../baked_sections/bake.ts";
13
14
  import {
14
15
  type MarkdownRenderOptions,
15
16
  renderMarkdownToHtml,
@@ -22,62 +23,177 @@ import * as TagConstants from "../../../plugs/index/constants.ts";
22
23
 
23
24
  export function markdownSyscalls(client: Client): SysCallMapping {
24
25
  return {
25
- "markdown.parseMarkdown": (_ctx, text: string): ParseTree => {
26
- return parse(markdownLanguageWithUserExtensions(client), text);
26
+ "markdown.parseMarkdown": {
27
+ callback: (_ctx, text: string): ParseTree => {
28
+ return parse(markdownLanguageWithUserExtensions(client), text);
29
+ },
30
+ description: "Parses Markdown text into a syntax tree.",
31
+ parameters: [
32
+ { name: "text", type: "string", description: "Markdown source." },
33
+ ],
34
+ returns: [{ type: "table", description: "Parsed Markdown tree." }],
35
+ examples: [{ code: 'local tree = markdown.parseMarkdown("# Title")' }],
27
36
  },
28
- "markdown.renderParseTree": (_ctx, tree: ParseTree): string => {
29
- return renderToText(tree);
37
+ "markdown.renderParseTree": {
38
+ callback: (_ctx, tree: ParseTree): string => {
39
+ return renderToText(tree);
40
+ },
41
+ description: "Renders a Markdown syntax tree back to source text.",
42
+ parameters: [
43
+ { name: "tree", type: "table", description: "Markdown syntax tree." },
44
+ ],
45
+ returns: [{ type: "string", description: "Rendered Markdown." }],
46
+ examples: [
47
+ {
48
+ code: 'local tree = markdown.parseMarkdown("# Title")\nprint(markdown.renderParseTree(tree))',
49
+ },
50
+ ],
30
51
  },
31
- "markdown.expandMarkdown": async (
32
- _ctx,
33
- treeOrText: ParseTree | string,
34
- options?: MarkdownExpandOptions,
35
- ): Promise<ParseTree | string> => {
36
- const outputString = typeof treeOrText === "string";
37
- if (typeof treeOrText === "string") {
38
- treeOrText = parse(
39
- markdownLanguageWithUserExtensions(client),
52
+ "markdown.expandMarkdown": {
53
+ callback: async (
54
+ _ctx,
55
+ treeOrText: ParseTree | string,
56
+ options?: MarkdownExpandOptions,
57
+ ): Promise<ParseTree | string> => {
58
+ const outputString = typeof treeOrText === "string";
59
+ if (typeof treeOrText === "string") {
60
+ treeOrText = parse(
61
+ markdownLanguageWithUserExtensions(client),
62
+ treeOrText,
63
+ );
64
+ }
65
+ const result = await expandMarkdownWithClient(
66
+ client,
40
67
  treeOrText,
68
+ options,
41
69
  );
42
- }
43
- const result = await expandMarkdownWithClient(
44
- client,
45
- treeOrText,
46
- options,
47
- );
48
- if (outputString) {
49
- return renderToText(result);
50
- } else {
51
- return result;
52
- }
70
+ if (outputString) {
71
+ return renderToText(result);
72
+ } else {
73
+ return result;
74
+ }
75
+ },
76
+ description:
77
+ "Expands Markdown transclusions, Lua directives, and task references.",
78
+ signatures: [
79
+ "markdown.expandMarkdown(text, options?)",
80
+ "markdown.expandMarkdown(tree, options?)",
81
+ ],
82
+ parameters: [
83
+ { name: "textOrTree", description: "Markdown text or parsed tree." },
84
+ {
85
+ name: "options",
86
+ type: "table",
87
+ description:
88
+ "Expansion switches: expandTransclusions, expandLuaDirectives, and rewriteTasks; all default to true.",
89
+ optional: true,
90
+ },
91
+ ],
92
+ returns: [
93
+ { description: "Expanded text or tree, matching the input form." },
94
+ ],
95
+ examples: [
96
+ {
97
+ code: 'local expanded = markdown.expandMarkdown("This is some Lua: ${1 + 2}")',
98
+ },
99
+ ],
53
100
  },
54
- "markdown.markdownToHtml": async (
55
- _ctx,
56
- text: string,
57
- options: MarkdownRenderOptions = {},
58
- ) => {
59
- let mdTree = parse(markdownLanguageWithUserExtensions(client), text);
60
- if (options.expand) {
61
- mdTree = await expandMarkdownWithClient(client, mdTree);
62
- }
63
- if (!options.resolveTagHref) {
64
- options.resolveTagHref = (tagName: string) => {
65
- return client.config.get<string | null>(
66
- ["tags", tagName, "tagPage"],
67
- null,
68
- ) ?? TagConstants.tagPrefix + tagName;
69
- };
70
- }
71
- return renderMarkdownToHtml(mdTree, options);
101
+ "markdown.markdownToHtml": {
102
+ callback: async (
103
+ _ctx,
104
+ text: string,
105
+ options: MarkdownRenderOptions = {},
106
+ ) => {
107
+ let mdTree = parse(markdownLanguageWithUserExtensions(client), text);
108
+ if (options.expand) {
109
+ mdTree = await expandMarkdownWithClient(client, mdTree);
110
+ }
111
+ if (!options.resolveTagHref) {
112
+ options.resolveTagHref = (tagName: string) => {
113
+ return (
114
+ client.config.get<string | null>(
115
+ ["tags", tagName, "tagPage"],
116
+ null,
117
+ ) ?? TagConstants.tagPrefix + tagName
118
+ );
119
+ };
120
+ }
121
+ return renderMarkdownToHtml(mdTree, options);
122
+ },
123
+ description: "Renders Markdown text to HTML.",
124
+ parameters: [
125
+ { name: "text", type: "string", description: "Markdown source." },
126
+ {
127
+ name: "options",
128
+ type: "table",
129
+ description: "HTML rendering options.",
130
+ optional: true,
131
+ },
132
+ ],
133
+ returns: [{ type: "string", description: "Rendered HTML." }],
134
+ examples: [{ code: 'local html = markdown.markdownToHtml("# Title")' }],
72
135
  },
73
- "markdown.objectsToTable": (
74
- _ctx,
75
- data: any[],
76
- options: {
77
- renderCell?: (val: any, key: string) => Promise<any> | any;
78
- } = {},
79
- ) => {
80
- return jsonToMDTable(data, options.renderCell || refCellTransformer);
136
+ // Re-bake every baked section (`<!--#lua EXPR -->` … `<!--/lua-->`) in
137
+ // `text` and return the updated markdown. Pure transform (no editor) — the
138
+ // text-level counterpart of the "Baked Sections: Update" command. `pageName`
139
+ // sets the `currentPage` context for the evaluated expressions.
140
+ "markdown.bakeSections": {
141
+ callback: (_ctx, text: string, pageName?: string): Promise<string> => {
142
+ return bakeSectionsInText(client, text, pageName);
143
+ },
144
+ description:
145
+ "Re-evaluates all baked Lua sections in Markdown text; sections that error or only render as HTML are left unchanged.",
146
+ parameters: [
147
+ {
148
+ name: "text",
149
+ type: "string",
150
+ description: "Markdown containing baked sections.",
151
+ },
152
+ {
153
+ name: "pageName",
154
+ type: "string",
155
+ description: "Page used as currentPage during evaluation.",
156
+ optional: true,
157
+ },
158
+ ],
159
+ returns: [
160
+ {
161
+ type: "string",
162
+ description: "Markdown with updated baked section bodies.",
163
+ },
164
+ ],
165
+ examples: [
166
+ {
167
+ code: 'local text = "Total: <!--#lua 1 + 2 -->\\nold\\n<!--/lua-->"\nprint(markdown.bakeSections(text))',
168
+ },
169
+ ],
170
+ },
171
+ "markdown.objectsToTable": {
172
+ callback: (
173
+ _ctx,
174
+ data: any[],
175
+ options: {
176
+ renderCell?: (val: any, key: string) => Promise<any> | any;
177
+ } = {},
178
+ ) => {
179
+ return jsonToMDTable(data, options.renderCell || refCellTransformer);
180
+ },
181
+ description: "Formats a list of objects as a Markdown table.",
182
+ parameters: [
183
+ { name: "data", type: "table", description: "Rows to render." },
184
+ {
185
+ name: "options",
186
+ type: "table",
187
+ description: "Optional renderCell callback.",
188
+ optional: true,
189
+ },
190
+ ],
191
+ returns: [{ type: "string", description: "Markdown table." }],
192
+ examples: [
193
+ {
194
+ code: 'local tableText = markdown.objectsToTable({{name = "Pete", age = 20}})',
195
+ },
196
+ ],
81
197
  },
82
198
  };
83
199
  }
@@ -11,34 +11,106 @@ export function mqSyscalls(mq: DataStoreMQ): SysCallMapping {
11
11
  /**
12
12
  * Define a Lua event listener
13
13
  */
14
- "mq.subscribe": (_ctx, def: MQListenerSpec) => {
15
- def.autoAck = def.autoAck !== false;
16
- // console.log("Registering Lua event listener: ", def.name);
17
- client.config.insert(["mqSubscriptions", def.queue], def);
14
+ "mq.subscribe": {
15
+ callback: (_ctx, def: MQListenerSpec) => {
16
+ def.autoAck = def.autoAck !== false;
17
+ client.config.insert(["mqSubscriptions", def.queue], def);
18
+ },
19
+ description: "Subscribes a Space Lua callback to a message queue.",
20
+ parameters: [
21
+ {
22
+ name: "spec",
23
+ type: "table",
24
+ description:
25
+ "Subscription with queue, optional batchSize and pollInterval, autoAck (default true), and a run(messages) callback; each message has queue, id, and body fields.",
26
+ },
27
+ ],
28
+ examples: [
29
+ {
30
+ code: 'mq.subscribe { queue = "tasks", batchSize = 1, run = function(messages) print(messages[1].body) end }',
31
+ },
32
+ ],
18
33
  },
19
- "mq.send": (_ctx, queue: string, body: any) => {
20
- return mq.send(queue, body);
34
+ "mq.send": {
35
+ callback: (_ctx, queue: string, body: any) => {
36
+ return mq.send(queue, body);
37
+ },
38
+ description: "Sends a message to a queue.",
39
+ parameters: [
40
+ { name: "queue", type: "string", description: "Queue name." },
41
+ { name: "body", description: "Message body." },
42
+ ],
43
+ examples: [{ code: 'mq.send("tasks", "my task")' }],
21
44
  },
22
- "mq.batchSend": (_ctx, queue: string, bodies: any[]) => {
23
- return mq.batchSend(queue, bodies);
45
+ "mq.batchSend": {
46
+ callback: (_ctx, queue: string, bodies: any[]) => {
47
+ return mq.batchSend(queue, bodies);
48
+ },
49
+ description: "Sends multiple messages to a queue in one operation.",
50
+ parameters: [
51
+ { name: "queue", type: "string", description: "Queue name." },
52
+ { name: "bodies", type: "table", description: "Message bodies." },
53
+ ],
24
54
  },
25
- "mq.ack": (_ctx, queue: string, id: string) => {
26
- return mq.ack(queue, id);
55
+ "mq.ack": {
56
+ callback: (_ctx, queue: string, id: string) => {
57
+ return mq.ack(queue, id);
58
+ },
59
+ description: "Acknowledges one queue message as processed.",
60
+ parameters: [
61
+ { name: "queue", type: "string", description: "Queue name." },
62
+ { name: "id", type: "string", description: "Message ID." },
63
+ ],
27
64
  },
28
- "mq.batchAck": (_ctx, queue: string, ids: string[]) => {
29
- return mq.batchAck(queue, ids);
65
+ "mq.batchAck": {
66
+ callback: (_ctx, queue: string, ids: string[]) => {
67
+ return mq.batchAck(queue, ids);
68
+ },
69
+ description: "Acknowledges multiple queue messages as processed.",
70
+ parameters: [
71
+ { name: "queue", type: "string", description: "Queue name." },
72
+ { name: "ids", type: "table", description: "Message IDs." },
73
+ ],
30
74
  },
31
- "mq.flushQueue": (_ctx, queue: string) => {
32
- return mq.flushQueue(queue);
75
+ "mq.flushQueue": {
76
+ callback: (_ctx, queue: string) => {
77
+ return mq.flushQueue(queue);
78
+ },
79
+ description: "Removes all messages from a queue.",
80
+ parameters: [
81
+ { name: "queue", type: "string", description: "Queue name." },
82
+ ],
33
83
  },
34
- "mq.flushAllQueues": () => {
35
- return mq.flushAllQueues();
84
+ "mq.flushAllQueues": {
85
+ callback: () => {
86
+ return mq.flushAllQueues();
87
+ },
88
+ description: "Removes all messages from every queue.",
36
89
  },
37
- "mq.getQueueStats": (_ctx, queue: string) => {
38
- return mq.getQueueStats(queue);
90
+ "mq.getQueueStats": {
91
+ callback: (_ctx, queue: string) => {
92
+ return mq.getQueueStats(queue);
93
+ },
94
+ description:
95
+ "Gets queued, processing, and dead-letter counts for a queue.",
96
+ parameters: [
97
+ {
98
+ name: "queue",
99
+ type: "string",
100
+ description: "Queue name.",
101
+ optional: true,
102
+ },
103
+ ],
104
+ returns: [{ type: "table", description: "Queue statistics." }],
39
105
  },
40
- "mq.awaitEmptyQueue": (_ctx, queue: string) => {
41
- return mq.awaitEmptyQueue(queue);
106
+ "mq.awaitEmptyQueue": {
107
+ callback: (_ctx, queue: string) => {
108
+ return mq.awaitEmptyQueue(queue);
109
+ },
110
+ description: "Waits until a queue has no pending or processing messages.",
111
+ parameters: [
112
+ { name: "queue", type: "string", description: "Queue name." },
113
+ ],
42
114
  },
43
115
  };
44
116
  }
@@ -0,0 +1,143 @@
1
+ import {
2
+ defineView,
3
+ focusPanel,
4
+ moveByRename,
5
+ openView,
6
+ pickView,
7
+ } from "../../navigator/navigator.ts";
8
+ import { newView } from "../../navigator/view_value.ts";
9
+ import type { SysCallMapping } from "../system.ts";
10
+
11
+ export function navigatorSyscalls(): SysCallMapping {
12
+ const viewSyscalls: SysCallMapping = {
13
+ "view.open": {
14
+ callback: (_ctx, name: string, opts?: any) => {
15
+ return openView(name, opts);
16
+ },
17
+ description: "Opens a navigator view by name.",
18
+ parameters: [
19
+ { name: "name", type: "string", description: "View name." },
20
+ {
21
+ name: "opts",
22
+ type: "table",
23
+ description:
24
+ "Optional segment, phrase, dropdown, focus and quiet flags.",
25
+ optional: true,
26
+ },
27
+ ],
28
+ returns: [
29
+ { type: "boolean", description: "Whether the view actually opened." },
30
+ ],
31
+ examples: [{ code: 'view.open("std.spaceTree")' }],
32
+ },
33
+ "view.focus": {
34
+ callback: (_ctx, slot?: string) => focusPanel(slot),
35
+ description:
36
+ "Returns focus to an open navigator panel's input, keeping its current selection.",
37
+ parameters: [
38
+ {
39
+ name: "slot",
40
+ type: "string",
41
+ description:
42
+ "Which panel: modal, lhs, rhs or bhs. Defaults to any open one.",
43
+ optional: true,
44
+ },
45
+ ],
46
+ returns: [
47
+ { type: "boolean", description: "Whether a panel was there to focus." },
48
+ ],
49
+ examples: [{ code: 'view.focus("rhs")' }],
50
+ },
51
+ "view.moveByRename": {
52
+ callback: (_ctx, obj: any, newName: string) => {
53
+ return moveByRename(obj, newName);
54
+ },
55
+ description:
56
+ "Renames the page, document or folder an object stands for -- the default `onMove` for space-backed views.",
57
+ parameters: [
58
+ { name: "obj", type: "table", description: "The row's object." },
59
+ { name: "newName", type: "string", description: "New name." },
60
+ ],
61
+ examples: [{ code: "onMove = view.moveByRename" }],
62
+ },
63
+ "lua:view.new": {
64
+ callback: (_ctx, spec: any) => newView(spec),
65
+ description:
66
+ "Creates a reusable navigator view value without registering or evaluating it.",
67
+ parameters: [
68
+ {
69
+ name: "spec",
70
+ type: "table",
71
+ description: "View content and behavior; see the Navigator API docs.",
72
+ },
73
+ ],
74
+ returns: [{ type: "table", description: "The reusable view value." }],
75
+ examples: [
76
+ {
77
+ code: "local projects = view.new { source = function() return {} end }",
78
+ },
79
+ ],
80
+ },
81
+ "lua:view.define": {
82
+ callback: (_ctx, spec: any) => {
83
+ return defineView(spec);
84
+ },
85
+ description:
86
+ "Registers a navigator view, and optionally a command that opens it. Rejects a bad spec at definition time.",
87
+ parameters: [
88
+ {
89
+ name: "spec",
90
+ type: "table",
91
+ description: "View definition; see the Navigator API docs.",
92
+ },
93
+ ],
94
+ examples: [
95
+ {
96
+ code: 'view.define {\n name = "myView",\n source = function() return {} end,\n onSelect = function(obj) editor.navigate(obj.ref) end,\n}',
97
+ },
98
+ ],
99
+ },
100
+ "lua:view.pick": {
101
+ callback: (_ctx, spec: any) => {
102
+ return pickView(spec);
103
+ },
104
+ description:
105
+ "Opens a one-shot picker over the supplied source and returns the object picked (or nil).",
106
+ parameters: [
107
+ {
108
+ name: "spec",
109
+ type: "table",
110
+ description:
111
+ "Picker definition; a view.define spec minus its name and chrome.",
112
+ },
113
+ ],
114
+ returns: [{ description: "The picked object, or nil." }],
115
+ examples: [
116
+ {
117
+ code: 'local picked = view.pick { source = function() return { { name = "One" } } end }',
118
+ },
119
+ ],
120
+ },
121
+ };
122
+
123
+ return {
124
+ ...viewSyscalls,
125
+ ...aliasNamespace(viewSyscalls, "view", "navigator"),
126
+ };
127
+ }
128
+
129
+ function aliasNamespace(
130
+ mapping: SysCallMapping,
131
+ from: string,
132
+ to: string,
133
+ ): SysCallMapping {
134
+ const aliased: SysCallMapping = {};
135
+ for (const [name, definition] of Object.entries(mapping)) {
136
+ const isLuaNative = name.startsWith("lua:");
137
+ const cleanName = isLuaNative ? name.slice("lua:".length) : name;
138
+ if (!cleanName.startsWith(`${from}.`)) continue;
139
+ const aliasedName = `${to}.${cleanName.slice(from.length + 1)}`;
140
+ aliased[isLuaNative ? `lua:${aliasedName}` : aliasedName] = definition;
141
+ }
142
+ return aliased;
143
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Pure schema-introspection helpers over the `["tags"]` config table.
3
+ *
4
+ * Returns raw JSON Schema objects; presentation-layer flattening (into typed
5
+ * property rows) happens in the `sb describe` CLI (describe.rs).
6
+ */
7
+
8
+ /**
9
+ * Returns a map of tag name → raw JSON Schema for every tag that defines a schema.
10
+ * Tags without a schema are omitted.
11
+ */
12
+ export function describeSchemas(
13
+ tags: Record<string, any>,
14
+ ): Record<string, unknown> {
15
+ const result: Record<string, unknown> = {};
16
+ for (const [name, def] of Object.entries(tags)) {
17
+ if (def?.schema != null) {
18
+ result[name] = def.schema;
19
+ }
20
+ }
21
+ return result;
22
+ }
23
+
24
+ /**
25
+ * Returns the raw JSON Schema for a single tag, or null if the tag is
26
+ * undefined or has no schema.
27
+ */
28
+ export function tagSchema(
29
+ tags: Record<string, any>,
30
+ tagName: string,
31
+ ): unknown | null {
32
+ return tags[tagName]?.schema ?? null;
33
+ }
@@ -0,0 +1,44 @@
1
+ import type { SysCallMapping } from "../system.ts";
2
+ import { rank, type RankOptions } from "../../../plug-api/lib/fuzzy.ts";
3
+
4
+ export function searchSyscalls(): SysCallMapping {
5
+ return {
6
+ "search.rank": {
7
+ callback: (
8
+ _ctx,
9
+ objects: Record<string, any>[],
10
+ phrase: string,
11
+ options?: {
12
+ fields?: Record<
13
+ string,
14
+ number | { weight: number; segments?: boolean }
15
+ >;
16
+ },
17
+ ) => rank(objects, phrase, options as RankOptions<any>),
18
+ description:
19
+ "Fuzzy-ranks objects against a phrase, best match first. The same ranker the navigator's own filtering uses.",
20
+ parameters: [
21
+ { name: "objects", type: "table", description: "Objects to rank." },
22
+ {
23
+ name: "phrase",
24
+ type: "string",
25
+ description:
26
+ "Phrase to match against. An empty phrase returns every object, in the order given.",
27
+ },
28
+ {
29
+ name: "options",
30
+ type: "table",
31
+ description:
32
+ "Ranking options. `fields` maps a field name to its weight, or to `{ weight, segments = true }` to also score the parts of a `/`-separated value.",
33
+ optional: true,
34
+ },
35
+ ],
36
+ returns: [
37
+ {
38
+ type: "table",
39
+ description: "The matching objects, best match first.",
40
+ },
41
+ ],
42
+ },
43
+ };
44
+ }