Fixes #8: SETTINGS page to keep all settings

website
Zef Hemel 2022-07-15 11:17:02 +02:00
parent a8274d225c
commit a69289f1ab
6 changed files with 103 additions and 27 deletions

View File

@ -107,6 +107,15 @@ export function findNodeOfType(
return collectNodesMatching(tree, (n) => n.type === nodeType)[0]; return collectNodesMatching(tree, (n) => n.type === nodeType)[0];
} }
export function traverseTree(
tree: ParseTree,
// Return value = should stop traversal?
matchFn: (tree: ParseTree) => boolean
): void {
// Do a collect, but ignore the result
collectNodesMatching(tree, matchFn);
}
// Finds non-text node at position // Finds non-text node at position
export function nodeAtPos(tree: ParseTree, pos: number): ParseTree | null { export function nodeAtPos(tree: ParseTree, pos: number): ParseTree | null {
if (pos < tree.from! || pos > tree.to!) { if (pos < tree.from! || pos > tree.to!) {

View File

@ -12,11 +12,8 @@ import { set as storeSet } from "@plugos/plugos-syscall/store";
import { import {
flashNotification, flashNotification,
getCurrentPage, getCurrentPage,
getCursor,
getText, getText,
insertAtCursor,
matchBefore, matchBefore,
moveCursor,
navigate, navigate,
prompt, prompt,
} from "@silverbulletmd/plugos-silverbullet-syscall/editor"; } from "@silverbulletmd/plugos-silverbullet-syscall/editor";

View File

@ -1,22 +1,20 @@
import { dispatch } from "@plugos/plugos-syscall/event"; import { dispatch } from "@plugos/plugos-syscall/event";
import { Manifest } from "@silverbulletmd/common/manifest"; import { Manifest } from "@silverbulletmd/common/manifest";
import { findNodeOfType } from "@silverbulletmd/common/tree";
import { import {
flashNotification, flashNotification,
save, save,
} from "@silverbulletmd/plugos-silverbullet-syscall/editor"; } from "@silverbulletmd/plugos-silverbullet-syscall/editor";
import { parseMarkdown } from "@silverbulletmd/plugos-silverbullet-syscall/markdown";
import { import {
deletePage, deletePage,
listPages, listPages,
readPage,
writePage, writePage,
} from "@silverbulletmd/plugos-silverbullet-syscall/space"; } from "@silverbulletmd/plugos-silverbullet-syscall/space";
import { import {
invokeFunction, invokeFunction,
reloadPlugs, reloadPlugs,
} from "@silverbulletmd/plugos-silverbullet-syscall/system"; } from "@silverbulletmd/plugos-silverbullet-syscall/system";
import YAML from "yaml";
import { readYamlPage } from "../lib/yaml_page";
async function listPlugs(): Promise<string[]> { async function listPlugs(): Promise<string[]> {
let unfilteredPages = await listPages(true); let unfilteredPages = await listPages(true);
@ -28,23 +26,22 @@ async function listPlugs(): Promise<string[]> {
export async function updatePlugsCommand() { export async function updatePlugsCommand() {
await save(); await save();
flashNotification("Updating plugs..."); flashNotification("Updating plugs...");
await invokeFunction("server", "updatePlugs"); try {
flashNotification("And... done!"); await invokeFunction("server", "updatePlugs");
await reloadPlugs(); flashNotification("And... done!");
await reloadPlugs();
} catch (e: any) {
flashNotification("Error updating plugs: " + e.message, "error");
}
} }
export async function updatePlugs() { export async function updatePlugs() {
let { text: plugPageText } = await readPage("PLUGS"); let plugList: string[] = [];
try {
let tree = await parseMarkdown(plugPageText); plugList = await readYamlPage("PLUGS");
} catch (e: any) {
let codeTextNode = findNodeOfType(tree, "CodeText"); throw new Error(`Error processing PLUGS: ${e.message}`);
if (!codeTextNode) {
console.error("Could not find yaml block in PLUGS");
return;
} }
let plugYaml = codeTextNode.children![0].text;
let plugList = YAML.parse(plugYaml!);
console.log("Plug YAML", plugList); console.log("Plug YAML", plugList);
let allPlugNames: string[] = []; let allPlugNames: string[] = [];
for (let plugUri of plugList) { for (let plugUri of plugList) {

View File

@ -16,12 +16,14 @@ import { parseMarkdown } from "@silverbulletmd/plugos-silverbullet-syscall/markd
import { extractMeta } from "../query/data"; import { extractMeta } from "../query/data";
import { renderToText } from "@silverbulletmd/common/tree"; import { renderToText } from "@silverbulletmd/common/tree";
import { niceDate } from "./dates"; import { niceDate } from "./dates";
import { readSettings } from "../lib/settings_page";
const pageTemplatePrefix = `template/page/`;
const snippetPrefix = `snippet/`;
export async function instantiateTemplateCommand() { export async function instantiateTemplateCommand() {
let allPages = await listPages(); let allPages = await listPages();
let { pageTemplatePrefix } = await readSettings({
pageTemplatePrefix: "template/page/",
});
let allPageTemplates = allPages.filter((pageMeta) => let allPageTemplates = allPages.filter((pageMeta) =>
pageMeta.name.startsWith(pageTemplatePrefix) pageMeta.name.startsWith(pageTemplatePrefix)
); );
@ -54,11 +56,17 @@ export async function instantiateTemplateCommand() {
export async function insertSnippet() { export async function insertSnippet() {
let allPages = await listPages(); let allPages = await listPages();
let { snippetPrefix } = await readSettings({
snippetPrefix: "snippet/",
});
let cursorPos = await getCursor(); let cursorPos = await getCursor();
let page = await getCurrentPage(); let page = await getCurrentPage();
let allSnippets = allPages.filter((pageMeta) => let allSnippets = allPages
pageMeta.name.startsWith(snippetPrefix) .filter((pageMeta) => pageMeta.name.startsWith(snippetPrefix))
); .map((pageMeta) => ({
...pageMeta,
name: pageMeta.name.slice(snippetPrefix.length),
}));
let selectedSnippet = await filterBox( let selectedSnippet = await filterBox(
"Snippet", "Snippet",
@ -69,7 +77,7 @@ export async function insertSnippet() {
if (!selectedSnippet) { if (!selectedSnippet) {
return; return;
} }
let { text } = await readPage(selectedSnippet.name); let { text } = await readPage(`${snippetPrefix}${selectedSnippet.name}`);
let templateText = replaceTemplateVars(text, page); let templateText = replaceTemplateVars(text, page);
let carretPos = templateText.indexOf("|^|"); let carretPos = templateText.indexOf("|^|");

View File

@ -0,0 +1,23 @@
import { readYamlPage } from "./yaml_page";
export async function readSettings<T extends object>(settings: T): Promise<T> {
try {
let allSettings = (await readYamlPage("SETTINGS", ["yaml"])) || {};
// TODO: I'm sure there's a better way to type this than "any"
let collectedSettings: any = {};
for (let [key, defaultVal] of Object.entries(settings)) {
if (allSettings[key]) {
collectedSettings[key] = allSettings[key];
} else {
collectedSettings[key] = defaultVal;
}
}
return collectedSettings as T;
} catch (e: any) {
if (e.message === "Page not found") {
// No settings yet, return default values for all
return settings;
}
throw e;
}
}

View File

@ -0,0 +1,42 @@
import { findNodeOfType, traverseTree } from "@silverbulletmd/common/tree";
import { parseMarkdown } from "@silverbulletmd/plugos-silverbullet-syscall/markdown";
import { readPage } from "@silverbulletmd/plugos-silverbullet-syscall/space";
import YAML from "yaml";
export async function readYamlPage(
pageName: string,
allowedLanguages = ["yaml"]
): Promise<any> {
const { text } = await readPage(pageName);
let tree = await parseMarkdown(text);
let data: any = {};
traverseTree(tree, (t): boolean => {
// Find a fenced code block
if (t.type !== "FencedCode") {
return false;
}
let codeInfoNode = findNodeOfType(t, "CodeInfo");
if (!codeInfoNode) {
return false;
}
if (!allowedLanguages.includes(codeInfoNode.children![0].text!)) {
return false;
}
let codeTextNode = findNodeOfType(t, "CodeText");
if (!codeTextNode) {
// Honestly, this shouldn't happen
return false;
}
let codeText = codeTextNode.children![0].text!;
try {
data = YAML.parse(codeText);
} catch (e: any) {
console.error("YAML Page parser error", e);
throw new Error(`YAML Error: ${e.message}`);
}
return true;
});
return data;
}