Extracted syscall packages

pull/3/head
Zef Hemel 2022-04-01 17:07:08 +02:00
parent 7f647758c2
commit 3aafa63073
34 changed files with 411 additions and 124 deletions

View File

@ -1,5 +1,6 @@
export type PageMeta = { export type PageMeta = {
name: string; name: string;
lastModified: number; lastModified: number;
version?: number; lastOpened?: number;
created?: boolean;
}; };

View File

@ -0,0 +1,93 @@
import { syscall } from "./syscall";
export function getCurrentPage(): Promise<string> {
return syscall("editor.getCurrentPage");
}
export function getText(): Promise<string> {
return syscall("editor.getText");
}
export function getCursor(): Promise<number> {
return syscall("editor.getCursor");
}
export function save(): Promise<void> {
return syscall("editor.save");
}
export function navigate(name: string, pos?: number): Promise<void> {
return syscall("editor.navigate", name, pos);
}
export function reloadPage(): Promise<void> {
return syscall("editor.reloadPage");
}
export function openUrl(url: string): Promise<void> {
return syscall("editor.openUrl", url);
}
export function flashNotification(message: string): Promise<void> {
return syscall("editor.flashNotification", message);
}
export function showRhs(html: string): Promise<void> {
return syscall("editor.showRhs", html);
}
export function insertAtPos(text: string, pos: number): Promise<void> {
return syscall("editor.insertAtPos", text, pos);
}
export function replaceRange(
from: number,
to: number,
text: string
): Promise<void> {
return syscall("editor.replaceRange", from, to, text);
}
export function moveCursor(pos: number): Promise<void> {
return syscall("editor.moveCursor", pos);
}
export function insertAtCursor(text: string): Promise<void> {
return syscall("editor.insertAtCursor", text);
}
export type SyntaxNode = {
name: string;
text: string;
from: number;
to: number;
};
export function getSyntaxNodeUnderCursor(): Promise<SyntaxNode> {
return syscall("editor.getSyntaxNodeUnderCursor");
}
export function getLineUnderCursor(): Promise<string> {
return syscall("editor.getLineUnderCursor");
}
export function matchBefore(
re: string
): Promise<{ from: number; to: number; text: string } | null> {
return syscall("editor.matchBefore", re);
}
export function getSyntaxNodeAtPos(pos: number): Promise<SyntaxNode> {
return syscall("editor.getSyntaxNodeAtPos", pos);
}
export function dispatch(change: any): Promise<void> {
return syscall("editor.dispatch", change);
}
export function prompt(
message: string,
defaultValue = ""
): Promise<string | undefined> {
return syscall("editor.prompt", message, defaultValue);
}

View File

@ -0,0 +1,54 @@
import { syscall } from "./syscall";
export type KV = {
key: string;
value: any;
};
export async function set(
page: string,
key: string,
value: any
): Promise<void> {
return syscall("index.set", page, key, value);
}
export async function batchSet(page: string, kvs: KV[]): Promise<void> {
return syscall("index.batchSet", page, kvs);
}
export async function get(page: string, key: string): Promise<any> {
return syscall("index.get", page, key);
}
export async function del(page: string, key: string): Promise<void> {
return syscall("index.delete", page, key);
}
export async function scanPrefixForPage(
page: string,
prefix: string
): Promise<{ key: string; page: string; value: any }[]> {
return syscall("index.scanPrefixForPage", page, prefix);
}
export async function scanPrefixGlobal(
prefix: string
): Promise<{ key: string; page: string; value: any }[]> {
return syscall("index.scanPrefixGlobal", prefix);
}
export async function clearPageIndexForPage(page: string): Promise<void> {
return syscall("index.clearPageIndexForPage", page);
}
export async function deletePrefixForPage(
page: string,
prefix: string
): Promise<void> {
return syscall("index.deletePrefixForPage", page, prefix);
}
export async function clearPageIndex(): Promise<void> {
return syscall("index.clearPageIndex");
}

View File

@ -0,0 +1,4 @@
{
"name": "plugos-silverbullet-syscall",
"version": "1.0.0"
}

View File

@ -0,0 +1,20 @@
import { syscall } from "./syscall";
import { PageMeta } from "../common/types";
export async function listPages(): Promise<PageMeta[]> {
return syscall("space.listPages");
}
export async function readPage(
name: string
): Promise<{ text: string; meta: PageMeta }> {
return syscall("space.readPage", name);
}
export async function writePage(name: string, text: string): Promise<PageMeta> {
return syscall("space.writePage", name, text);
}
export async function deletePage(name: string): Promise<PageMeta> {
return syscall("space.deletePage", name);
}

View File

@ -0,0 +1,8 @@
import { syscall } from "./syscall";
export async function invokeFunctionOnServer(
name: string,
...args: any[]
): Promise<any> {
return syscall("system.invokeFunctionOnServer", name, ...args);
}

5
plugos-syscall/event.ts Normal file
View File

@ -0,0 +1,5 @@
import { syscall } from "./syscall";
export async function dispatch(eventName: string, data: any): Promise<void> {
return syscall("event.dispatch", eventName, data);
}

12
plugos-syscall/fetch.ts Normal file
View File

@ -0,0 +1,12 @@
import { syscall } from "./syscall";
export async function json(url: RequestInfo, init: RequestInit): Promise<any> {
return syscall("fetch.json", url, init);
}
export async function text(
url: RequestInfo,
init: RequestInit
): Promise<string> {
return syscall("fetch.text", url, init);
}

View File

@ -0,0 +1,4 @@
{
"name": "plugos-syscall",
"version": "1.0.0"
}

8
plugos-syscall/shell.ts Normal file
View File

@ -0,0 +1,8 @@
import { syscall } from "./syscall";
export async function run(
cmd: string,
args: string[]
): Promise<{ stdout: string; stderr: string }> {
return syscall("shell.run", cmd, args);
}

40
plugos-syscall/store.ts Normal file
View File

@ -0,0 +1,40 @@
import { syscall } from "./syscall";
export type KV = {
key: string;
value: any;
};
export async function set(key: string, value: any): Promise<void> {
return syscall("store.set", key, value);
}
export async function batchSet(kvs: KV[]): Promise<void> {
return syscall("store.batchSet", kvs);
}
export async function get(key: string): Promise<any> {
return syscall("store.get", key);
}
export async function del(key: string): Promise<void> {
return syscall("store.delete", key);
}
export async function batchDel(keys: string[]): Promise<void> {
return syscall("store.batchDelete", keys);
}
export async function queryPrefix(
prefix: string
): Promise<{ key: string; value: any }[]> {
return syscall("store.scanPrefix", prefix);
}
export async function deletePrefix(prefix: string): Promise<void> {
return syscall("store.deletePrefix", prefix);
}
export async function deleteAll(): Promise<void> {
return syscall("store.deleteAll");
}

View File

@ -0,0 +1,5 @@
declare global {
function syscall(name: string, ...args: any[]): Promise<any>;
}
export const syscall = self.syscall;

View File

@ -1,7 +1,6 @@
import { syscall } from "../lib/syscall"; import { insertAtCursor } from "plugos-silverbullet-syscall/editor";
export async function insertToday() { export async function insertToday() {
console.log("Inserting date!");
let niceDate = new Date().toISOString().split("T")[0]; let niceDate = new Date().toISOString().split("T")[0];
await syscall("editor.insertAtCursor", niceDate); await insertAtCursor(niceDate);
} }

View File

@ -1,6 +1,7 @@
import { IndexEvent } from "../../webapp/app_event"; import { IndexEvent } from "../../webapp/app_event";
import { whiteOutQueries } from "./materialized_queries"; import { whiteOutQueries } from "./materialized_queries";
import { syscall } from "../lib/syscall";
import { batchSet } from "plugos-silverbullet-syscall/index";
type Item = { type Item = {
item: string; item: string;
@ -35,5 +36,5 @@ export async function indexItems({ name, text }: IndexEvent) {
}); });
} }
console.log("Found", items.length, "item(s)"); console.log("Found", items.length, "item(s)");
await syscall("index.batchSet", name, items); await batchSet(name, items);
} }

View File

@ -1,8 +1,8 @@
import { syscall } from "../lib/syscall";
import mdParser from "../../webapp/parser"; import mdParser from "../../webapp/parser";
import { getText } from "plugos-silverbullet-syscall/editor";
export async function renderMD() { export async function renderMD() {
let text = await syscall("editor.getText"); let text = await getText();
let tree = mdParser.parser.parse(text); let tree = mdParser.parser.parse(text);
let slicesToRemove: [number, number][] = []; let slicesToRemove: [number, number][] = [];

View File

@ -1,4 +1,9 @@
import { syscall } from "../lib/syscall"; import {
getCursor,
getText,
insertAtPos,
replaceRange,
} from "plugos-silverbullet-syscall/editor";
export async function toggleH1() { export async function toggleH1() {
await togglePrefix("# "); await togglePrefix("# ");
@ -13,15 +18,15 @@ function lookBack(s: string, pos: number, backString: string): boolean {
} }
async function togglePrefix(prefix: string) { async function togglePrefix(prefix: string) {
let text = (await syscall("editor.getText")) as string; let text = await getText();
let pos = (await syscall("editor.getCursor")) as number; let pos = await getCursor();
if (text[pos] === "\n") { if (text[pos] === "\n") {
pos--; pos--;
} }
while (pos > 0 && text[pos] !== "\n") { while (pos > 0 && text[pos] !== "\n") {
if (lookBack(text, pos, prefix)) { if (lookBack(text, pos, prefix)) {
// Already has this prefix, let's flip it // Already has this prefix, let's flip it
await syscall("editor.replaceRange", pos - prefix.length, pos, ""); await replaceRange(pos - prefix.length, pos, "");
return; return;
} }
pos--; pos--;
@ -29,5 +34,5 @@ async function togglePrefix(prefix: string) {
if (pos) { if (pos) {
pos++; pos++;
} }
await syscall("editor.insertAtPos", prefix, pos); await insertAtPos(prefix, pos);
} }

View File

@ -1,7 +1,16 @@
import { syscall } from "../lib/syscall"; import {
flashNotification,
getCurrentPage,
reloadPage,
save,
} from "plugos-silverbullet-syscall/editor";
import { readPage, writePage } from "plugos-silverbullet-syscall/space";
import { invokeFunctionOnServer } from "plugos-silverbullet-syscall/system";
import { scanPrefixGlobal } from "plugos-silverbullet-syscall";
export const queryRegex = export const queryRegex =
/(<!--\s*#query\s+(?<table>\w+)\s*(filter\s+["'](?<filter>[^"']+)["'])?\s*(group by\s+(?<groupBy>\w+))?\s*-->)(.+?)(<!--\s*#end\s*-->)/gs; /(<!--\s*#query\s+(?<table>\w+)\s*(filter\s+["'](?<filter>[^"']+)["'])?\s*-->)(.+?)(<!--\s*#end\s*-->)/gs;
export function whiteOutQueries(text: string): string { export function whiteOutQueries(text: string): string {
return text.replaceAll(queryRegex, (match) => return text.replaceAll(queryRegex, (match) =>
@ -25,18 +34,16 @@ async function replaceAsync(
} }
export async function updateMaterializedQueriesCommand() { export async function updateMaterializedQueriesCommand() {
await syscall( const currentPage = await getCurrentPage();
"system.invokeFunctionOnServer", await save();
"updateMaterializedQueriesOnPage", await invokeFunctionOnServer("updateMaterializedQueriesOnPage", currentPage);
await syscall("editor.getCurrentPage") await reloadPage();
); await flashNotification("Updated materialized queries");
await syscall("editor.reloadPage");
await syscall("editor.flashNotification", "Updated materialized queries");
} }
// Called from client, running on server // Called from client, running on server
export async function updateMaterializedQueriesOnPage(pageName: string) { export async function updateMaterializedQueriesOnPage(pageName: string) {
let { text } = await syscall("space.readPage", pageName); let { text } = await readPage(pageName);
text = await replaceAsync(text, queryRegex, async (match, ...args) => { text = await replaceAsync(text, queryRegex, async (match, ...args) => {
let { table, filter, groupBy } = args[args.length - 1]; let { table, filter, groupBy } = args[args.length - 1];
const startQuery = args[0]; const startQuery = args[0];
@ -48,23 +55,20 @@ export async function updateMaterializedQueriesOnPage(pageName: string) {
key, key,
page, page,
value: { task, complete, children }, value: { task, complete, children },
} of await syscall("index.scanPrefixGlobal", "task:")) { } of await scanPrefixGlobal("task:")) {
let [, pos] = key.split(":"); let [, pos] = key.split(":");
if (!filter || (filter && task.includes(filter))) { if (!filter || (filter && task.includes(filter))) {
results.push( results.push(
`* [${complete ? "x" : " "}] [[${page}@${pos}]] ${task}` `* [${complete ? "x" : " "}] [[${page}@${pos}]] ${task}` +
(children ? "\n" + children.join("\n") : "")
); );
if (children) {
results.push(children.join("\n"));
}
} }
} }
return `${startQuery}\n${results.join("\n")}\n${endQuery}`; return `${startQuery}\n${results.sort().join("\n")}\n${endQuery}`;
case "link": case "link":
let uniqueLinks = new Set<string>(); let uniqueLinks = new Set<string>();
for (let {key, page, value: name} of await syscall( for (let { key, page, value: name } of await scanPrefixGlobal(
"index.scanPrefixGlobal", `pl:${pageName}:`
`pl:${pageName}:`
)) { )) {
let [, pos] = key.split(":"); let [, pos] = key.split(":");
if (!filter || (filter && name.includes(filter))) { if (!filter || (filter && name.includes(filter))) {
@ -80,20 +84,20 @@ export async function updateMaterializedQueriesOnPage(pageName: string) {
key, key,
page, page,
value: { item, children }, value: { item, children },
}; of await syscall("index.scanPrefixGlobal", "it:")) { } of await scanPrefixGlobal("it:")) {
let [, pos] = key.split(":"); let [, pos] = key.split(":");
if (!filter || (filter && item.includes(filter))) { if (!filter || (filter && item.includes(filter))) {
results.push(`* [[${page}@${pos}]] ${item}`); results.push(
if (children) { `* [[${page}@${pos}]] ${item}` +
results.push(children.join("\n")); (children ? "\n" + children.join("\n") : "")
} );
} }
} }
return `${startQuery}\n${results.join("\n")}\n${endQuery}`; return `${startQuery}\n${results.sort().join("\n")}\n${endQuery}`;
default: default:
return match; return match;
} }
}); });
// console.log("New text", text); // console.log("New text", text);
await syscall("space.writePage", pageName, text); await writePage(pageName, text);
} }

View File

@ -1,6 +1,11 @@
import { ClickEvent } from "../../webapp/app_event"; import { ClickEvent } from "../../webapp/app_event";
import { syscall } from "../lib/syscall";
import { updateMaterializedQueriesCommand } from "./materialized_queries"; import { updateMaterializedQueriesCommand } from "./materialized_queries";
import {
getSyntaxNodeAtPos,
getSyntaxNodeUnderCursor,
navigate as navigateTo,
openUrl,
} from "plugos-silverbullet-syscall/editor";
const materializedQueryPrefix = /<!--\s*#query\s+/; const materializedQueryPrefix = /<!--\s*#query\s+/;
@ -16,10 +21,10 @@ async function navigate(syntaxNode: any) {
if (pageLink.includes("@")) { if (pageLink.includes("@")) {
[pageLink, pos] = syntaxNode.text.split("@"); [pageLink, pos] = syntaxNode.text.split("@");
} }
await syscall("editor.navigate", pageLink, +pos); await navigateTo(pageLink, +pos);
break; break;
case "URL": case "URL":
await syscall("editor.openUrl", syntaxNode.text); await openUrl(syntaxNode.text);
break; break;
case "CommentBlock": case "CommentBlock":
if (syntaxNode.text.match(materializedQueryPrefix)) { if (syntaxNode.text.match(materializedQueryPrefix)) {
@ -30,19 +35,19 @@ async function navigate(syntaxNode: any) {
// Markdown link: [bla](URLHERE) needs extraction // Markdown link: [bla](URLHERE) needs extraction
let match = /\[[^\\]+\]\(([^\)]+)\)/.exec(syntaxNode.text); let match = /\[[^\\]+\]\(([^\)]+)\)/.exec(syntaxNode.text);
if (match) { if (match) {
await syscall("editor.openUrl", match[1]); await openUrl(match[1]);
} }
break; break;
} }
} }
export async function linkNavigate() { export async function linkNavigate() {
await navigate(await syscall("editor.getSyntaxNodeUnderCursor")); await navigate(await getSyntaxNodeUnderCursor());
} }
export async function clickNavigate(event: ClickEvent) { export async function clickNavigate(event: ClickEvent) {
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
let syntaxNode = await syscall("editor.getSyntaxNodeAtPos", event.pos); let syntaxNode = await getSyntaxNodeAtPos(event.pos);
await navigate(syntaxNode); await navigate(syntaxNode);
} }
} }

View File

@ -1,6 +1,27 @@
import { IndexEvent } from "../../webapp/app_event"; import { IndexEvent } from "../../webapp/app_event";
import { pageLinkRegex } from "../../webapp/constant"; import { pageLinkRegex } from "../../webapp/constant";
import { syscall } from "../lib/syscall"; import {
batchSet,
clearPageIndex as clearPageIndexSyscall,
clearPageIndexForPage,
scanPrefixGlobal,
} from "plugos-silverbullet-syscall/index";
import {
flashNotification,
getCurrentPage,
getText,
matchBefore,
navigate,
} from "plugos-silverbullet-syscall/editor";
import { dispatch } from "plugos-syscall/event";
import {
deletePage as deletePageSyscall,
listPages,
readPage,
writePage,
} from "plugos-silverbullet-syscall/space";
import { invokeFunctionOnServer } from "plugos-silverbullet-syscall/system";
const wikilinkRegex = new RegExp(pageLinkRegex, "g"); const wikilinkRegex = new RegExp(pageLinkRegex, "g");
@ -20,25 +41,21 @@ export async function indexLinks({ name, text }: IndexEvent) {
}); });
} }
console.log("Found", backLinks.length, "wiki link(s)"); console.log("Found", backLinks.length, "wiki link(s)");
await syscall("index.batchSet", name, backLinks); await batchSet(name, backLinks);
} }
export async function deletePage() { export async function deletePage() {
let pageName = await syscall("editor.getCurrentPage"); let pageName = await getCurrentPage();
console.log("Navigating to start page"); console.log("Navigating to start page");
await syscall("editor.navigate", "start"); await navigate("start");
console.log("Deleting page from space"); console.log("Deleting page from space");
await syscall("space.deletePage", pageName); await deletePageSyscall(pageName);
} }
export async function renamePage() { export async function renamePage() {
const oldName = await syscall("editor.getCurrentPage"); const oldName = await getCurrentPage();
console.log("Old name is", oldName); console.log("Old name is", oldName);
const newName = await syscall( const newName = await prompt(`Rename ${oldName} to:`, oldName);
"editor.prompt",
`Rename ${oldName} to:`,
oldName
);
if (!newName) { if (!newName) {
return; return;
} }
@ -47,13 +64,13 @@ export async function renamePage() {
let pagesToUpdate = await getBackLinks(oldName); let pagesToUpdate = await getBackLinks(oldName);
console.log("All pages containing backlinks", pagesToUpdate); console.log("All pages containing backlinks", pagesToUpdate);
let text = await syscall("editor.getText"); let text = await getText();
console.log("Writing new page to space"); console.log("Writing new page to space");
await syscall("space.writePage", newName, text); await writePage(newName, text);
console.log("Navigating to new page"); console.log("Navigating to new page");
await syscall("editor.navigate", newName); await navigate(newName);
console.log("Deleting page from space"); console.log("Deleting page from space");
await syscall("space.deletePage", oldName); await deletePageSyscall(oldName);
let pageToUpdateSet = new Set<string>(); let pageToUpdateSet = new Set<string>();
for (let pageToUpdate of pagesToUpdate) { for (let pageToUpdate of pagesToUpdate) {
@ -62,7 +79,7 @@ export async function renamePage() {
for (let pageToUpdate of pageToUpdateSet) { for (let pageToUpdate of pageToUpdateSet) {
console.log("Now going to update links in", pageToUpdate); console.log("Now going to update links in", pageToUpdate);
let { text } = await syscall("space.readPage", pageToUpdate); let { text } = await readPage(pageToUpdate);
console.log("Received text", text); console.log("Received text", text);
if (!text) { if (!text) {
// Page likely does not exist, but at least we can skip it // Page likely does not exist, but at least we can skip it
@ -71,7 +88,7 @@ export async function renamePage() {
let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`); let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);
if (text !== newText) { if (text !== newText) {
console.log("Changes made, saving..."); console.log("Changes made, saving...");
await syscall("space.writePage", pageToUpdate, newText); await writePage(pageToUpdate, newText);
} }
} }
} }
@ -82,7 +99,7 @@ type BackLink = {
}; };
async function getBackLinks(pageName: string): Promise<BackLink[]> { async function getBackLinks(pageName: string): Promise<BackLink[]> {
let allBackLinks = await syscall("index.scanPrefixGlobal", `pl:${pageName}:`); let allBackLinks = await scanPrefixGlobal(`pl:${pageName}:`);
let pagesToUpdate: BackLink[] = []; let pagesToUpdate: BackLink[] = [];
for (let { key, value } of allBackLinks) { for (let { key, value } of allBackLinks) {
let keyParts = key.split(":"); let keyParts = key.split(":");
@ -95,28 +112,28 @@ async function getBackLinks(pageName: string): Promise<BackLink[]> {
} }
export async function showBackLinks() { export async function showBackLinks() {
const pageName = await syscall("editor.getCurrentPage"); const pageName = await getCurrentPage();
let backLinks = await getBackLinks(pageName); let backLinks = await getBackLinks(pageName);
console.log("Backlinks", backLinks); console.log("Backlinks", backLinks);
} }
export async function reindexCommand() { export async function reindexCommand() {
await syscall("editor.flashNotification", "Reindexing..."); await flashNotification("Reindexing...");
await syscall("system.invokeFunctionOnServer", "reindexSpace"); await invokeFunctionOnServer("reindexSpace");
await syscall("editor.flashNotification", "Reindexing done"); await flashNotification("Reindexing done");
} }
// Completion // Completion
export async function pageComplete() { export async function pageComplete() {
let prefix = await syscall("editor.matchBefore", "\\[\\[[\\w\\s]*"); let prefix = await matchBefore("\\[\\[[\\w\\s]*");
if (!prefix) { if (!prefix) {
return null; return null;
} }
let allPages = await syscall("space.listPages"); let allPages = await listPages();
return { return {
from: prefix.from + 2, from: prefix.from + 2,
options: allPages.map((pageMeta: any) => ({ options: allPages.map((pageMeta) => ({
label: pageMeta.name, label: pageMeta.name,
type: "page", type: "page",
})), })),
@ -126,13 +143,13 @@ export async function pageComplete() {
// Server functions // Server functions
export async function reindexSpace() { export async function reindexSpace() {
console.log("Clearing page index..."); console.log("Clearing page index...");
await syscall("index.clearPageIndex"); await clearPageIndexSyscall();
console.log("Listing all pages"); console.log("Listing all pages");
let pages = await syscall("space.listPages"); let pages = await listPages();
for (let { name } of pages) { for (let { name } of pages) {
console.log("Indexing", name); console.log("Indexing", name);
const pageObj = await syscall("space.readPage", name); const pageObj = await readPage(name);
await syscall("event.dispatch", "page:index", { await dispatch("page:index", {
name, name,
text: pageObj.text, text: pageObj.text,
}); });
@ -141,5 +158,5 @@ export async function reindexSpace() {
export async function clearPageIndex(page: string) { export async function clearPageIndex(page: string) {
console.log("Clearing page index for page", page); console.log("Clearing page index for page", page);
await syscall("index.clearPageIndexForPage", page); await clearPageIndexForPage(page);
} }

View File

@ -1,5 +1,3 @@
import { syscall } from "../lib/syscall";
function countWords(str: string): number { function countWords(str: string): number {
const matches = str.match(/[\w\d\'-]+/gi); const matches = str.match(/[\w\d\'-]+/gi);
return matches ? matches.length : 0; return matches ? matches.length : 0;
@ -9,12 +7,3 @@ function readingTime(wordCount: number): number {
// 225 is average word reading speed for adults // 225 is average word reading speed for adults
return Math.ceil(wordCount / 225); return Math.ceil(wordCount / 225);
} }
export async function wordCount({ text }: { text: string }) {
let sysCallText = (await syscall("editor.getText")) as string;
const count = countWords(sysCallText);
console.log("Word count", count);
let syntaxNode = await syscall("editor.getSyntaxNodeUnderCursor");
console.log("Syntax node", syntaxNode);
return count;
}

View File

@ -1,3 +1,4 @@
build: build:
curl https://unicode.org/Public/emoji/14.0/emoji-test.txt > emoji-data.txt curl https://unicode.org/Public/emoji/14.0/emoji-test.txt > emoji-data.txt
node build.js node build.js
rm emoji-data.txt

View File

@ -1,11 +1,11 @@
// @ts-ignore // @ts-ignore
import emojis from "./emoji.json"; import emojis from "./emoji.json";
import { syscall } from "../lib/syscall"; import { matchBefore } from "plugos-silverbullet-syscall/editor";
const emojiMatcher = /\(([^\)]+)\)\s+(.+)$/; const emojiMatcher = /\(([^\)]+)\)\s+(.+)$/;
export async function emojiCompleter() { export async function emojiCompleter() {
let prefix = await syscall("editor.matchBefore", ":[\\w\\s]*"); let prefix = await matchBefore(":[\\w\\s]*");
if (!prefix) { if (!prefix) {
return null; return null;
} }

View File

@ -1,4 +1,6 @@
import { syscall } from "../lib/syscall"; import { run } from "plugos-syscall/shell";
import { flashNotification, prompt } from "plugos-silverbullet-syscall/editor";
import { invokeFunctionOnServer } from "plugos-silverbullet-syscall/system";
export async function commit(message?: string) { export async function commit(message?: string) {
if (!message) { if (!message) {
@ -8,9 +10,9 @@ export async function commit(message?: string) {
"Snapshotting the current space to git with commit message", "Snapshotting the current space to git with commit message",
message message
); );
await syscall("shell.run", "git", ["add", "./*.md"]); await run("git", ["add", "./*.md"]);
try { try {
await syscall("shell.run", "git", ["commit", "-a", "-m", message]); await run("git", ["commit", "-a", "-m", message]);
} catch (e) { } catch (e) {
// We can ignore, this happens when there's no changes to commit // We can ignore, this happens when there's no changes to commit
} }
@ -18,26 +20,26 @@ export async function commit(message?: string) {
} }
export async function snapshotCommand() { export async function snapshotCommand() {
let revName = await syscall("editor.prompt", `Revision name:`); let revName = await prompt(`Revision name:`);
if (!revName) { if (!revName) {
revName = "Snapshot"; revName = "Snapshot";
} }
console.log("Revision name", revName); console.log("Revision name", revName);
await syscall("system.invokeFunctionOnServer", "commit", revName); await invokeFunctionOnServer("commit", revName);
} }
export async function syncCommand() { export async function syncCommand() {
await syscall("editor.flashNotification", "Syncing with git"); await flashNotification("Syncing with git");
await syscall("system.invokeFunctionOnServer", "sync"); await invokeFunctionOnServer("sync");
await syscall("editor.flashNotification", "Git sync complete!"); await flashNotification("Git sync complete!");
} }
export async function sync() { export async function sync() {
console.log("Going to sync with git"); console.log("Going to sync with git");
await commit(); await commit();
console.log("Then pulling from remote"); console.log("Then pulling from remote");
await syscall("shell.run", "git", ["pull"]); await run("git", ["pull"]);
console.log("And then pushing to remote"); console.log("And then pushing to remote");
await syscall("shell.run", "git", ["push"]); await run("git", ["push"]);
console.log("Done!"); console.log("Done!");
} }

View File

@ -1,5 +1,5 @@
import MarkdownIt from "markdown-it"; import MarkdownIt from "markdown-it";
import { syscall } from "../lib/syscall"; import { getText, showRhs } from "plugos-silverbullet-syscall/editor";
var taskLists = require("markdown-it-task-lists"); var taskLists = require("markdown-it-task-lists");
@ -10,7 +10,7 @@ const md = new MarkdownIt({
}).use(taskLists); }).use(taskLists);
export async function renderMarkdown() { export async function renderMarkdown() {
let text = await syscall("editor.getText"); let text = await getText();
let html = md.render(text); let html = md.render(text);
await syscall("editor.showRhs", `<html><body>${html}</body></html>`); await showRhs(`<html><body>${html}</body></html>`);
} }

8
plugs/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "plugs",
"version": "1.0.0",
"dependencies": {
"plugos-silverbullet-syscall": "file:../plugos-silverbullet-syscall",
"plugos-syscall": "file:../plugos-syscall"
}
}

View File

@ -1,8 +1,14 @@
import type { ClickEvent } from "../../webapp/app_event"; import type { ClickEvent } from "../../webapp/app_event";
import { IndexEvent } from "../../webapp/app_event"; import { IndexEvent } from "../../webapp/app_event";
import { syscall } from "../lib/syscall";
import { whiteOutQueries } from "../core/materialized_queries"; import { whiteOutQueries } from "../core/materialized_queries";
import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall/index";
import { readPage, writePage } from "plugos-silverbullet-syscall/space";
import {
dispatch,
getLineUnderCursor,
getSyntaxNodeAtPos,
} from "plugos-silverbullet-syscall/editor";
const allTasksPageName = "ALL TASKS"; const allTasksPageName = "ALL TASKS";
const taskRe = /[\-\*]\s*\[([ Xx])\]\s*(.*)/g; const taskRe = /[\-\*]\s*\[([ Xx])\]\s*(.*)/g;
@ -45,11 +51,11 @@ export async function indexTasks({ name, text }: IndexEvent) {
}); });
} }
console.log("Found", tasks.length, "task(s)"); console.log("Found", tasks.length, "task(s)");
await syscall("index.batchSet", name, tasks); await batchSet(name, tasks);
} }
export async function updateTaskPage() { export async function updateTaskPage() {
let allTasks = await syscall("index.scanPrefixGlobal", "task:"); let allTasks = await scanPrefixGlobal("task:");
let pageTasks = new Map<string, Task[]>(); let pageTasks = new Map<string, Task[]>();
for (let { for (let {
key, key,
@ -61,7 +67,7 @@ export async function updateTaskPage() {
} }
let [, pos] = key.split(":"); let [, pos] = key.split(":");
let tasks = pageTasks.get(page) || []; let tasks = pageTasks.get(page) || [];
tasks.push({ task, complete, pos }); tasks.push({ task, complete, pos: +pos });
pageTasks.set(page, tasks); pageTasks.set(page, tasks);
} }
@ -78,17 +84,17 @@ export async function updateTaskPage() {
} }
let taskMd = mdPieces.join("\n"); let taskMd = mdPieces.join("\n");
await syscall("space.writePage", allTasksPageName, taskMd); await writePage(allTasksPageName, taskMd);
} }
export async function taskToggle(event: ClickEvent) { export async function taskToggle(event: ClickEvent) {
let syntaxNode = await syscall("editor.getSyntaxNodeAtPos", event.pos); let syntaxNode = await getSyntaxNodeAtPos(event.pos);
if (syntaxNode && syntaxNode.name === "TaskMarker") { if (syntaxNode && syntaxNode.name === "TaskMarker") {
let changeTo = "[x]"; let changeTo = "[x]";
if (syntaxNode.text === "[x]" || syntaxNode.text === "[X]") { if (syntaxNode.text === "[x]" || syntaxNode.text === "[X]") {
changeTo = "[ ]"; changeTo = "[ ]";
} }
await syscall("editor.dispatch", { await dispatch({
changes: { changes: {
from: syntaxNode.from, from: syntaxNode.from,
to: syntaxNode.to, to: syntaxNode.to,
@ -100,12 +106,12 @@ export async function taskToggle(event: ClickEvent) {
}); });
if (event.page === allTasksPageName) { if (event.page === allTasksPageName) {
// Propagate back to the page in question // Propagate back to the page in question
let line = (await syscall("editor.getLineUnderCursor")) as string; let line = await getLineUnderCursor();
let match = line.match(extractPageLink); let match = line.match(extractPageLink);
if (match) { if (match) {
let [, page, posS] = match; let [, page, posS] = match;
let pos = +posS; let pos = +posS;
let pageData = await syscall("space.readPage", page); let pageData = await readPage(page);
let text = pageData.text; let text = pageData.text;
// Apply the toggle // Apply the toggle
@ -113,7 +119,7 @@ export async function taskToggle(event: ClickEvent) {
text.substring(0, pos) + text.substring(0, pos) +
text.substring(pos).replace(/^([\-\*]\s*)\[[ xX]\]/, "$1" + changeTo); text.substring(pos).replace(/^([\-\*]\s*)\[[ xX]\]/, "$1" + changeTo);
await syscall("space.writePage", page, text); await writePage(page, text);
} }
} }
} }

View File

@ -1,6 +1,6 @@
import { mkdir, readdir, readFile, stat, unlink, writeFile } from "fs/promises"; import { mkdir, readdir, readFile, stat, unlink, writeFile } from "fs/promises";
import * as path from "path"; import * as path from "path";
import { PageMeta } from "./types"; import { PageMeta } from "../common/types";
import { EventHook } from "../plugos/hooks/event"; import { EventHook } from "../plugos/hooks/event";
export interface Storage { export interface Storage {

View File

@ -1,4 +1,4 @@
import { PageMeta } from "../types"; import { PageMeta } from "../../common/types";
import { SysCallMapping } from "../../plugos/system"; import { SysCallMapping } from "../../plugos/system";
import { Storage } from "../disk_storage"; import { Storage } from "../disk_storage";

View File

@ -1,6 +1,6 @@
import { PageMeta } from "../types";
import { FilterList, Option } from "./filter"; import { FilterList, Option } from "./filter";
import { faFileLines } from "@fortawesome/free-solid-svg-icons"; import { faFileLines } from "@fortawesome/free-solid-svg-icons";
import { PageMeta } from "../../common/types";
export function PageNavigator({ export function PageNavigator({
allPages, allPages,

View File

@ -1,8 +1,8 @@
import { PageMeta } from "./types";
import { EventEmitter } from "../common/event"; import { EventEmitter } from "../common/event";
import { Manifest } from "../common/manifest"; import { Manifest } from "../common/manifest";
import { safeRun } from "./util"; import { safeRun } from "./util";
import { Plug } from "../plugos/plug"; import { Plug } from "../plugos/plug";
import { PageMeta } from "../common/types";
export type SpaceEvents = { export type SpaceEvents = {
pageCreated: (meta: PageMeta) => void; pageCreated: (meta: PageMeta) => void;

View File

@ -36,6 +36,9 @@ export default (editor: Editor): SysCallMapping => ({
getCursor: (): number => { getCursor: (): number => {
return editor.editorView!.state.selection.main.from; return editor.editorView!.state.selection.main.from;
}, },
save: async () => {
return editor.save(true);
},
navigate: async (ctx, name: string, pos: number) => { navigate: async (ctx, name: string, pos: number) => {
await editor.navigate(name, pos); await editor.navigate(name, pos);
}, },

View File

@ -1,6 +1,6 @@
import { Editor } from "../editor"; import { Editor } from "../editor";
import { PageMeta } from "../types";
import { SysCallMapping } from "../../plugos/system"; import { SysCallMapping } from "../../plugos/system";
import { PageMeta } from "../../common/types";
export default (editor: Editor): SysCallMapping => ({ export default (editor: Editor): SysCallMapping => ({
listPages: async (): Promise<PageMeta[]> => { listPages: async (): Promise<PageMeta[]> => {

View File

@ -1,12 +1,5 @@
import { AppCommand } from "./hooks/command"; import { AppCommand } from "./hooks/command";
import { PageMeta } from "../common/types";
export type PageMeta = {
name: string;
lastModified: number;
version?: number;
lastOpened?: number;
created?: boolean;
};
export const slashCommandRegexp = /\/[\w\-]*/; export const slashCommandRegexp = /\/[\w\-]*/;