Expose syscalls in space script via globals (no more syscall calls)
parent
6b69449d05
commit
e29352556b
|
@ -3,6 +3,7 @@ import type { ParseTree } from "../plug-api/lib/tree.ts";
|
||||||
import type { ScriptObject } from "../plugs/index/script.ts";
|
import type { ScriptObject } from "../plugs/index/script.ts";
|
||||||
import type { AppCommand, CommandDef } from "$lib/command.ts";
|
import type { AppCommand, CommandDef } from "$lib/command.ts";
|
||||||
import { Intl, Temporal, toTemporalInstant } from "@js-temporal/polyfill";
|
import { Intl, Temporal, toTemporalInstant } from "@js-temporal/polyfill";
|
||||||
|
import * as syscalls from "@silverbulletmd/silverbullet/syscalls";
|
||||||
|
|
||||||
// @ts-ignore: Temporal polyfill
|
// @ts-ignore: Temporal polyfill
|
||||||
Date.prototype.toTemporalInstant = toTemporalInstant;
|
Date.prototype.toTemporalInstant = toTemporalInstant;
|
||||||
|
@ -95,15 +96,23 @@ export class ScriptEnvironment {
|
||||||
// Internal API
|
// Internal API
|
||||||
evalScript(script: string, system: System<any>) {
|
evalScript(script: string, system: System<any>) {
|
||||||
try {
|
try {
|
||||||
|
const syscallArgs = [];
|
||||||
|
const syscallValues = [];
|
||||||
|
for (const [tl, value] of Object.entries(syscalls)) {
|
||||||
|
syscallArgs.push(tl);
|
||||||
|
syscallValues.push(value);
|
||||||
|
}
|
||||||
const fn = Function(
|
const fn = Function(
|
||||||
"silverbullet",
|
"silverbullet",
|
||||||
"syscall",
|
"syscall",
|
||||||
|
...syscallArgs,
|
||||||
script,
|
script,
|
||||||
);
|
);
|
||||||
fn.call(
|
fn.call(
|
||||||
{},
|
{},
|
||||||
this,
|
this,
|
||||||
(name: string, ...args: any[]) => system.syscall({}, name, args),
|
(name: string, ...args: any[]) => system.syscall({}, name, args),
|
||||||
|
...syscallValues,
|
||||||
);
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -113,6 +122,10 @@ export class ScriptEnvironment {
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadFromSystem(system: System<any>) {
|
async loadFromSystem(system: System<any>) {
|
||||||
|
// Install global syscall function on globalThis
|
||||||
|
(globalThis as any).syscall = (name: string, ...args: any[]) =>
|
||||||
|
system.syscall({}, name, args);
|
||||||
|
|
||||||
if (!system.loadedPlugs.has("index")) {
|
if (!system.loadedPlugs.has("index")) {
|
||||||
console.warn("Index plug not found, skipping loading space scripts");
|
console.warn("Index plug not found, skipping loading space scripts");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -11,4 +11,7 @@ if (typeof self === "undefined") {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const syscall = (globalThis as any).syscall;
|
// Late binding syscall
|
||||||
|
export function syscall(name: string, ...args: any[]) {
|
||||||
|
return (globalThis as any).syscall(name, ...args);
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ Depending on where code is run (client or server), a slightly different JavaScri
|
||||||
* `silverbullet.registerCommand(def, callback)`: registers a custom command (see [[#Custom commands]]).
|
* `silverbullet.registerCommand(def, callback)`: registers a custom command (see [[#Custom commands]]).
|
||||||
* `silverbullet.registerEventListener`: registers an event listener (see [[#Custom event listeners]]).
|
* `silverbullet.registerEventListener`: registers an event listener (see [[#Custom event listeners]]).
|
||||||
* `silverbullet.registerAttributeExtractor(def, callback)`: registers a custom attribute extractor.
|
* `silverbullet.registerAttributeExtractor(def, callback)`: registers a custom attribute extractor.
|
||||||
* `syscall(name, args...)`: invoke a syscall (see [[#Syscalls]]).
|
* Various SilverBullet syscalls, see [[#Syscalls]]
|
||||||
|
|
||||||
Many standard JavaScript APIs are available, such as:
|
Many standard JavaScript APIs are available, such as:
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ Even though a [[Functions#readPage(name)]] function already exist, you could imp
|
||||||
|
|
||||||
```space-script
|
```space-script
|
||||||
silverbullet.registerFunction({name: "myReadPage"}, async (name) => {
|
silverbullet.registerFunction({name: "myReadPage"}, async (name) => {
|
||||||
const pageContent = await syscall("space.readPage", name);
|
const pageContent = await space.readPage(name);
|
||||||
return pageContent;
|
return pageContent;
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
@ -79,7 +79,7 @@ Here is an example of defining a custom command using space script:
|
||||||
|
|
||||||
```space-script
|
```space-script
|
||||||
silverbullet.registerCommand({name: "My First Command"}, async () => {
|
silverbullet.registerCommand({name: "My First Command"}, async () => {
|
||||||
await syscall("editor.flashNotification", "Hello there!");
|
await editor.flashNotification("Hello there!");
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ silverbullet.registerEventListener({name: "task:stateChange"}, async (event) =>
|
||||||
const {from, to, newState} = event.data;
|
const {from, to, newState} = event.data;
|
||||||
if(newState !== " ") {
|
if(newState !== " ") {
|
||||||
// Now dispatch an editor change to add the completion date at the end of the task
|
// Now dispatch an editor change to add the completion date at the end of the task
|
||||||
await syscall("editor.dispatch", {
|
await editor.dispatch({
|
||||||
changes: {
|
changes: {
|
||||||
from: to, // insert at the end of the task
|
from: to, // insert at the end of the task
|
||||||
insert: " ✅ " + Temporal.Now.plainDateISO().toString(),
|
insert: " ✅ " + Temporal.Now.plainDateISO().toString(),
|
||||||
|
@ -204,7 +204,7 @@ Note that indexing happens on every page save. You have to run {[Space: Reindex]
|
||||||
## Example
|
## Example
|
||||||
Let’s say you want to use the syntax `✅ 2024-02-27` in a task to signify when that task was completed and strip it from the task name. Here’s an example:
|
Let’s say you want to use the syntax `✅ 2024-02-27` in a task to signify when that task was completed and strip it from the task name. Here’s an example:
|
||||||
|
|
||||||
* [x] I’ve done this ✅ 2024-02-27
|
* [x] I’ve done this ✅ 2024-08-07
|
||||||
|
|
||||||
The following attribute extractor will accomplish this:
|
The following attribute extractor will accomplish this:
|
||||||
|
|
||||||
|
@ -236,16 +236,6 @@ Result:
|
||||||
# Syscalls
|
# Syscalls
|
||||||
The primary way to interact with the SilverBullet environment is using “syscalls”. Syscalls expose SilverBullet functionality largely available both on the client and server in a safe way.
|
The primary way to interact with the SilverBullet environment is using “syscalls”. Syscalls expose SilverBullet functionality largely available both on the client and server in a safe way.
|
||||||
|
|
||||||
In your space script, a syscall is invoked via `syscall(name, arg1, arg2)` and usually returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) with the result.
|
In your space script, all syscalls are exposed via the global environment, and all return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) with the result.
|
||||||
|
|
||||||
Here are all available syscalls:
|
[A full list of syscall are documented here](https://jsr.io/@silverbulletmd/silverbullet/doc/syscalls/~)
|
||||||
|
|
||||||
```template
|
|
||||||
{{#each @module in {syscall select replace(name, /\.\w+$/, "") as name}}}
|
|
||||||
## {{@module.name}}
|
|
||||||
{{#each {syscall where @module.name = replace(name, /\.\w+$/, "")}}}
|
|
||||||
* `{{name}}`
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
{{/each}}
|
|
||||||
```
|
|
Loading…
Reference in New Issue