Fix plugs and plug updating
This commit is contained in:
@@ -3,6 +3,19 @@
|
||||
This defines the [JSON schema](https://json-schema.org/) for built-in settings.
|
||||
|
||||
```space-lua
|
||||
config.define("plugs", {
|
||||
description = "List of plugs to enable",
|
||||
oneOf = {
|
||||
{
|
||||
type = "array",
|
||||
items = { type = "string" }
|
||||
},
|
||||
{ -- only as a fallback for an empty table in Lua
|
||||
type = "object",
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
config.define("autoCloseBrackets", {
|
||||
description = "List of brackets to auto close",
|
||||
type = "string",
|
||||
|
||||
@@ -36,23 +36,10 @@ This is where you configure SilverBullet to your liking. See [[^Library/Std/Conf
|
||||
|
||||
\`\`\`space-lua
|
||||
config.set {
|
||||
actionButtons = {
|
||||
{
|
||||
icon = "home",
|
||||
command = "Navigate: Home",
|
||||
description = "Go to the index page"
|
||||
},
|
||||
{
|
||||
icon = "book",
|
||||
command = "Navigate: Page Picker",
|
||||
description = "Open page"
|
||||
},
|
||||
{
|
||||
icon = "terminal",
|
||||
command = "Open Command Palette",
|
||||
description = "Run command"
|
||||
}
|
||||
},
|
||||
plugs = {
|
||||
-- Add your plugs here (https://silverbullet.md/Plugs)
|
||||
-- Then run the \`Plugs: Update\` command to update them
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
`;
|
||||
|
||||
@@ -28,6 +28,22 @@ export function systemSyscalls(
|
||||
}
|
||||
return plug.invoke(functionName, args);
|
||||
},
|
||||
"system.invokeFunctionOnServer": (
|
||||
ctx,
|
||||
fullName: string, // plug.function
|
||||
...args: any[]
|
||||
) => {
|
||||
console.warn(
|
||||
"Calling deprecated system.invokeFunctionOnServer, use system.invokeFunction instead",
|
||||
);
|
||||
return api["system.invokeFunction"](ctx, fullName, ...args);
|
||||
},
|
||||
"system.serverSyscall": (_ctx, name: string, ...args: any[]) => {
|
||||
console.warn(
|
||||
"Calling deprecated system.serverSyscall, use syscall instead",
|
||||
);
|
||||
return client.clientSystem.localSyscall(name, args);
|
||||
},
|
||||
"system.invokeCommand": (_ctx, name: string, args?: string[]) => {
|
||||
if (!client) {
|
||||
throw new Error("Not supported");
|
||||
@@ -69,6 +85,10 @@ export function systemSyscalls(
|
||||
}
|
||||
return client.loadPlugs();
|
||||
},
|
||||
"system.reloadConfig": (): Record<string, any> => {
|
||||
console.warn("system.reloadConfig is deprecated, it's now a no-op");
|
||||
return client.config.values;
|
||||
},
|
||||
"system.loadSpaceScripts": async () => {
|
||||
await client.clientSystem.loadSpaceScripts();
|
||||
},
|
||||
@@ -79,7 +99,16 @@ export function systemSyscalls(
|
||||
await client.loadCustomStyles();
|
||||
},
|
||||
// DEPRECATED
|
||||
"system.getEnv": () => {
|
||||
console.warn(
|
||||
"system.getEnv is deprecated, you can assume the env to always be the client",
|
||||
);
|
||||
return null;
|
||||
},
|
||||
"system.getSpaceConfig": (_ctx, key, defaultValue?) => {
|
||||
console.warn(
|
||||
"system.getSpaceConfig is deprecated, use system.getConfig instead",
|
||||
);
|
||||
return client.config.get(key, defaultValue);
|
||||
},
|
||||
"system.getMode": () => {
|
||||
|
||||
@@ -21,8 +21,3 @@ functions:
|
||||
path: "./plugmanager.ts:getPlugGithubRelease"
|
||||
events:
|
||||
- get-plug:ghr
|
||||
addPlugCommand:
|
||||
path: ./plugmanager.ts:addPlugCommand
|
||||
command:
|
||||
name: "Plugs: Add"
|
||||
requireMode: rw
|
||||
|
||||
@@ -1,33 +1,24 @@
|
||||
import {
|
||||
editor,
|
||||
events,
|
||||
language,
|
||||
markdown,
|
||||
space,
|
||||
system,
|
||||
} from "@silverbulletmd/silverbullet/syscalls";
|
||||
import { readYamlPage } from "@silverbulletmd/silverbullet/lib/yaml_page";
|
||||
import { builtinPlugNames } from "../builtin_plugs.ts";
|
||||
import {
|
||||
findNodeMatching,
|
||||
traverseTree,
|
||||
} from "@silverbulletmd/silverbullet/lib/tree";
|
||||
import {
|
||||
addParentPointers,
|
||||
findNodeOfType,
|
||||
} from "@silverbulletmd/silverbullet/lib/tree";
|
||||
import { assert } from "@std/assert/assert";
|
||||
|
||||
const plugsPage = "PLUGS";
|
||||
const plugsPrelude =
|
||||
"#meta\n\nThis file lists all plugs added with the {[Plugs: Add]} command. Run the {[Plugs: Update]} command to update all Plugs defined anywhere using Space Config.\n\n";
|
||||
|
||||
export async function updatePlugsCommand() {
|
||||
// Save the current file (could be a config page)
|
||||
await editor.save();
|
||||
// Reload the config and commands
|
||||
await editor.reloadConfigAndCommands();
|
||||
await editor.flashNotification("Updating plugs...");
|
||||
try {
|
||||
const plugList: string[] = [];
|
||||
const configPlugs: any[] = await system.getConfig("plugs", []);
|
||||
let configPlugs: any[] = await system.getConfig("plugs", []);
|
||||
if (Object.keys(configPlugs).length === 0) {
|
||||
// Handle case of empty Lua table
|
||||
configPlugs = [];
|
||||
}
|
||||
if (!Array.isArray(configPlugs)) {
|
||||
throw new Error("Expected 'plugs' in Space Config to be an array");
|
||||
}
|
||||
@@ -40,37 +31,6 @@ export async function updatePlugsCommand() {
|
||||
);
|
||||
}
|
||||
plugList.push(...stringPlugs);
|
||||
if (await space.fileExists("PLUGS.md")) {
|
||||
// This is not primary mode of managing plugs anymore, only here for backwards compatibility.
|
||||
try {
|
||||
const pagePlugs: any[] = await readYamlPage("PLUGS");
|
||||
if (Array.isArray(pagePlugs)) {
|
||||
// It's possible that the user is using it for something else, but if it has yaml with an array, assume it's plugs
|
||||
const pageStringPlugs = pagePlugs.filter((plug) =>
|
||||
typeof plug === "string"
|
||||
);
|
||||
if (pageStringPlugs.length !== pagePlugs.length) {
|
||||
throw new Error(
|
||||
`${
|
||||
pagePlugs.length - pageStringPlugs.length
|
||||
} plugs from PLUG page were not in a yaml list format`,
|
||||
);
|
||||
}
|
||||
plugList.push(...pageStringPlugs);
|
||||
if (pageStringPlugs.length > 0) {
|
||||
editor.flashNotification(
|
||||
`${pageStringPlugs.length} plugs in PLUGS page can be moved to Space Config for better editor support`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
editor.flashNotification(
|
||||
`Error processing PLUGS page: ${e.message}`,
|
||||
"error",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// De-duplicate URIs, this is safe because by definition they point to the same plug
|
||||
plugList.forEach((uri, index) => {
|
||||
@@ -129,13 +89,15 @@ export async function updatePlugsCommand() {
|
||||
// console.log("Got manifests", plugUri, protocol, manifests);
|
||||
const workerCode = manifests[0] as string;
|
||||
allCustomPlugNames.push(plugName);
|
||||
// console.log("Writing", `_plug/${plugName}.plug.js`, workerCode);
|
||||
console.log("Writing", `_plug/${plugName}.plug.js`);
|
||||
await space.writeDocument(
|
||||
`_plug/${plugName}.plug.js`,
|
||||
new TextEncoder().encode(workerCode),
|
||||
);
|
||||
}
|
||||
|
||||
console.log("This part is done");
|
||||
|
||||
const allPlugNames = [...builtinPlugNames, ...allCustomPlugNames];
|
||||
// And delete extra ones
|
||||
for (const { name: existingPlug } of await space.listPlugs()) {
|
||||
@@ -144,135 +106,19 @@ export async function updatePlugsCommand() {
|
||||
existingPlug.length - ".plug.js".length,
|
||||
);
|
||||
if (!allPlugNames.includes(plugName)) {
|
||||
console.log("Deleting", existingPlug);
|
||||
await space.deleteDocument(existingPlug);
|
||||
}
|
||||
}
|
||||
await editor.flashNotification("And... done!");
|
||||
await editor.flashNotification(
|
||||
"All done!",
|
||||
);
|
||||
system.reloadPlugs();
|
||||
} catch (e: any) {
|
||||
editor.flashNotification("Error updating plugs: " + e.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
export async function addPlugCommand(_cmdDef: any, uriSuggestion: string = "") {
|
||||
let uri = await editor.prompt("Plug URI:", uriSuggestion);
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
// Support people copy & pasting the YAML version
|
||||
if (uri.startsWith("-")) {
|
||||
uri = uri.replace(/^\-\s*/, "");
|
||||
}
|
||||
|
||||
let plugPageContent = plugsPrelude;
|
||||
if (await space.fileExists(plugsPage + ".md")) {
|
||||
plugPageContent = await space.readPage(plugsPage);
|
||||
} else {
|
||||
await space.writePage(plugsPage, plugPageContent);
|
||||
}
|
||||
await editor.navigate({ kind: "page", page: plugsPage });
|
||||
// Here we are on the PLUGS page, if it didn't exist before it's filled with prelude
|
||||
const changeList = await insertIntoPlugPage(uri, plugPageContent);
|
||||
for (const { from, to, text } of changeList) {
|
||||
editor.replaceRange(from, to, text);
|
||||
}
|
||||
await editor.flashNotification("Plug added!");
|
||||
system.reloadPlugs();
|
||||
}
|
||||
|
||||
/** Add the plug to the end of the plugs list in Space Config inside the PLUGS page content
|
||||
* Returns an array for `editor.replaceRange` syscalls.
|
||||
*
|
||||
* Rewrites the `yaml` block to `space-config` if present
|
||||
* Appends the `space-config` block if needed.
|
||||
* Appends the `plugs` key on root level if needed.
|
||||
*
|
||||
* It's exported only to allow testing.
|
||||
* There are a bunch of asserts to please the type checker that will fail with a malformed page.
|
||||
*/
|
||||
export async function insertIntoPlugPage(
|
||||
uri: string,
|
||||
pageContent: string,
|
||||
): Promise<{ from: number; to: number; text: string }[]> {
|
||||
const edits: { from: number; to: number; text: string }[] = [];
|
||||
|
||||
const tree = await markdown.parseMarkdown(pageContent);
|
||||
addParentPointers(tree);
|
||||
|
||||
const yamlInfo = findNodeMatching(tree, (n) => {
|
||||
return n.type === "CodeInfo" &&
|
||||
n.children !== undefined &&
|
||||
n.children.length === 1 &&
|
||||
n.children[0].text === "yaml";
|
||||
});
|
||||
const configInfo = findNodeMatching(tree, (n) => {
|
||||
return n.type === "CodeInfo" &&
|
||||
n.children !== undefined &&
|
||||
n.children.length === 1 &&
|
||||
n.children[0].text === "space-config";
|
||||
});
|
||||
|
||||
if (yamlInfo) {
|
||||
// replace YAML with Space Config, add plugs: line at the start, and the new URI at the end
|
||||
assert(yamlInfo.from && yamlInfo.to);
|
||||
edits.push({ from: yamlInfo.from, to: yamlInfo.to, text: "space-config" });
|
||||
|
||||
assert(yamlInfo.parent);
|
||||
const yamlText = findNodeOfType(yamlInfo.parent, "CodeText");
|
||||
assert(yamlText && yamlText.from && yamlText.to);
|
||||
edits.push({ from: yamlText.from, to: yamlText.from, text: "plugs:\n" });
|
||||
edits.push({ from: yamlText.to, to: yamlText.to, text: `\n- ${uri}` });
|
||||
} else if (configInfo) {
|
||||
// Append the required parts into the Space Config block, using lezer's (upstream) parser
|
||||
assert(configInfo.parent);
|
||||
const configText = findNodeOfType(configInfo.parent, "CodeText");
|
||||
assert(configText && configText.from && configText.to);
|
||||
assert(configText.children?.length === 1 && configText.children[0].text);
|
||||
|
||||
const config = configText.children[0].text;
|
||||
const configTree = await language.parseLanguage("yaml", config);
|
||||
traverseTree(configTree, (n) => {
|
||||
if (n.type === "atom") {
|
||||
if (n.children![0].text === "plugs") {
|
||||
edits.push({
|
||||
from: configText.from! + n.to! + 1,
|
||||
to: configText.from! + n.to! + 1,
|
||||
text: `\n- ${uri}`,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (edits.length === 0) {
|
||||
// No plugs in this block
|
||||
edits.push({
|
||||
from: configText.to,
|
||||
to: configText.to,
|
||||
text: `\nplugs:\n- ${uri}`,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Just add the whole block if there's nothing
|
||||
const configBlock = `\`\`\`space-config
|
||||
plugs:
|
||||
- ${uri}
|
||||
\`\`\``;
|
||||
edits.push({
|
||||
from: pageContent.length,
|
||||
to: pageContent.length,
|
||||
// Start on an empty line
|
||||
text: (pageContent.endsWith("\n") || pageContent === "")
|
||||
? configBlock
|
||||
: ("\n" + configBlock),
|
||||
});
|
||||
}
|
||||
|
||||
// Sort edits from end to start, so they don't affect each other's positions
|
||||
edits.sort((a, b) => b.from - a.from);
|
||||
return edits;
|
||||
}
|
||||
|
||||
export async function getPlugHTTPS(url: string): Promise<string> {
|
||||
const fullUrl = `https:${url}`;
|
||||
console.log("Now fetching plug code from", fullUrl);
|
||||
|
||||
Reference in New Issue
Block a user