Migrated to pacel and removed deno
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"commands": {
|
||||
"Navigate To page": {
|
||||
"invoke": "linkNavigate",
|
||||
"key": "Ctrl-Enter",
|
||||
"mac": "Cmd-Enter"
|
||||
},
|
||||
"Insert Current Date": {
|
||||
"invoke": "insertToday",
|
||||
"slashCommand": "/today"
|
||||
},
|
||||
"Toggle : Heading 1": {
|
||||
"invoke": "toggle_h1",
|
||||
"mac": "Cmd-1",
|
||||
"key": "Ctrl-1"
|
||||
},
|
||||
"Toggle : Heading 2": {
|
||||
"invoke": "toggle_h2",
|
||||
"mac": "Cmd-2",
|
||||
"key": "Ctrl-2"
|
||||
},
|
||||
"Page: Delete": {
|
||||
"invoke": "deletePage"
|
||||
},
|
||||
"Page: Rename": {
|
||||
"invoke": "renamePage"
|
||||
},
|
||||
"Pages: Reindex": {
|
||||
"invoke": "reindexPages"
|
||||
},
|
||||
"Pages: Back Links": {
|
||||
"invoke": "showBackLinks"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"page:click": ["taskToggle", "clickNavigate"],
|
||||
"editor:complete": ["pageComplete"],
|
||||
"page:index": ["indexLinks"]
|
||||
},
|
||||
"functions": {
|
||||
"indexLinks": {
|
||||
"path": "./page.ts:indexLinks"
|
||||
},
|
||||
"deletePage": {
|
||||
"path": "./page.ts:deletePage"
|
||||
},
|
||||
"showBackLinks": {
|
||||
"path": "./page.ts:showBackLinks"
|
||||
},
|
||||
"renamePage": {
|
||||
"path": "./page.ts:renamePage"
|
||||
},
|
||||
"reindexPages": {
|
||||
"path": "./page.ts:reindex"
|
||||
},
|
||||
"pageComplete": {
|
||||
"path": "./navigate.ts:pageComplete"
|
||||
},
|
||||
"linkNavigate": {
|
||||
"path": "./navigate.ts:linkNavigate"
|
||||
},
|
||||
"clickNavigate": {
|
||||
"path": "./navigate.ts:clickNavigate"
|
||||
},
|
||||
"taskToggle": {
|
||||
"path": "./task.ts:taskToggle"
|
||||
},
|
||||
"insertToday": {
|
||||
"path": "./dates.ts:insertToday"
|
||||
},
|
||||
"toggle_h1": {
|
||||
"path": "./markup.ts:toggleH1"
|
||||
},
|
||||
"toggle_h2": {
|
||||
"path": "./markup.ts:toggleH2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { syscall } from "./lib/syscall.ts";
|
||||
|
||||
export async function insertToday() {
|
||||
let niceDate = new Date().toISOString().split("T")[0];
|
||||
await syscall("editor.insertAtCursor", niceDate);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import {syscall} from "./syscall.ts";
|
||||
|
||||
export async function put(key: string, value: any) {
|
||||
return await syscall("db.put", key, value);
|
||||
}
|
||||
|
||||
export async function get(key: string) {
|
||||
return await syscall("db.get", key);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export function syscall(name: string, ...args: any[]): any {
|
||||
let reqId = Math.floor(Math.random() * 1000000);
|
||||
// console.log("Syscall", name, reqId);
|
||||
return new Promise((resolve, reject) => {
|
||||
self.dispatchEvent(
|
||||
new CustomEvent("syscall", {
|
||||
detail: {
|
||||
id: reqId,
|
||||
name: name,
|
||||
args: args,
|
||||
callback: resolve,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { syscall } from "./lib/syscall.ts";
|
||||
|
||||
export async function toggleH1() {
|
||||
await togglePrefix("# ");
|
||||
}
|
||||
|
||||
export async function toggleH2() {
|
||||
await togglePrefix("## ");
|
||||
}
|
||||
|
||||
function lookBack(s: string, pos: number, backString: string): boolean {
|
||||
return s.substring(pos - backString.length, pos) === backString;
|
||||
}
|
||||
|
||||
async function togglePrefix(prefix: string) {
|
||||
let text = (await syscall("editor.getText")) as string;
|
||||
let pos = (await syscall("editor.getCursor")) as number;
|
||||
if (text[pos] === "\n") {
|
||||
pos--;
|
||||
}
|
||||
while (pos > 0 && text[pos] !== "\n") {
|
||||
if (lookBack(text, pos, prefix)) {
|
||||
// Already has this prefix, let's flip it
|
||||
await syscall("editor.replaceRange", pos - prefix.length, pos, "");
|
||||
return;
|
||||
}
|
||||
pos--;
|
||||
}
|
||||
if (pos) {
|
||||
pos++;
|
||||
}
|
||||
await syscall("editor.insertAtPos", prefix, pos);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { ClickEvent } from "../../webapp/src/app_event.ts";
|
||||
import { syscall } from "./lib/syscall.ts";
|
||||
|
||||
async function navigate(syntaxNode: any) {
|
||||
if (!syntaxNode) {
|
||||
return;
|
||||
}
|
||||
console.log("Attempting to navigate based on syntax node", syntaxNode);
|
||||
switch (syntaxNode.name) {
|
||||
case "WikiLinkPage":
|
||||
await syscall("editor.navigate", syntaxNode.text);
|
||||
break;
|
||||
case "URL":
|
||||
await syscall("editor.openUrl", syntaxNode.text);
|
||||
break;
|
||||
case "Link":
|
||||
// Markdown link: [bla](URLHERE) needs extraction
|
||||
let match = /\[[^\\]+\]\(([^\)]+)\)/.exec(syntaxNode.text);
|
||||
if (match) {
|
||||
await syscall("editor.openUrl", match[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function linkNavigate() {
|
||||
navigate(await syscall("editor.getSyntaxNodeUnderCursor"));
|
||||
}
|
||||
|
||||
export async function clickNavigate(event: ClickEvent) {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
let syntaxNode = await syscall("editor.getSyntaxNodeAtPos", event.pos);
|
||||
navigate(syntaxNode);
|
||||
}
|
||||
}
|
||||
|
||||
export async function pageComplete() {
|
||||
let prefix = await syscall("editor.matchBefore", "\\[\\[[\\w\\s]*");
|
||||
if (!prefix) {
|
||||
return null;
|
||||
}
|
||||
let allPages = await syscall("space.listPages");
|
||||
return {
|
||||
from: prefix.from + 2,
|
||||
options: allPages.map((pageMeta: any) => ({
|
||||
label: pageMeta.name,
|
||||
type: "page",
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import { IndexEvent } from "../../webapp/src/app_event";
|
||||
import { pageLinkRegex } from "../../webapp/src/constant";
|
||||
import { syscall } from "./lib/syscall";
|
||||
|
||||
const wikilinkRegex = new RegExp(pageLinkRegex, "g");
|
||||
|
||||
export async function indexLinks({ name, text }: IndexEvent) {
|
||||
let backLinks: { key: string; value: string }[] = [];
|
||||
for (let match of text.matchAll(wikilinkRegex)) {
|
||||
let toPage = match[1];
|
||||
let pos = match.index!;
|
||||
backLinks.push({
|
||||
key: `pl:${toPage}:${pos}`,
|
||||
value: name,
|
||||
});
|
||||
}
|
||||
console.log("Found", backLinks.length, "wiki link(s)");
|
||||
await syscall("indexer.batchSet", name, backLinks);
|
||||
}
|
||||
|
||||
export async function deletePage() {
|
||||
let pageMeta = await syscall("editor.getCurrentPage");
|
||||
console.log("Navigating to start page");
|
||||
await syscall("editor.navigate", "start");
|
||||
console.log("Deleting page from space");
|
||||
await syscall("space.deletePage", pageMeta.name);
|
||||
console.log("Reloading page list");
|
||||
await syscall("space.reloadPageList");
|
||||
}
|
||||
|
||||
export async function renamePage() {
|
||||
const pageMeta = await syscall("editor.getCurrentPage");
|
||||
const oldName = pageMeta.name;
|
||||
console.log("Old name is", oldName);
|
||||
const newName = await syscall(
|
||||
"editor.prompt",
|
||||
`Rename ${oldName} to:`,
|
||||
oldName
|
||||
);
|
||||
if (!newName) {
|
||||
return;
|
||||
}
|
||||
console.log("New name", newName);
|
||||
|
||||
let pagesToUpdate = await getBackLinks(oldName);
|
||||
console.log("All pages containing backlinks", pagesToUpdate);
|
||||
|
||||
let text = await syscall("editor.getText");
|
||||
console.log("Writing new page to space");
|
||||
await syscall("space.writePage", newName, text);
|
||||
console.log("Deleting page from space");
|
||||
await syscall("space.deletePage", oldName);
|
||||
console.log("Reloading page list");
|
||||
await syscall("space.reloadPageList");
|
||||
console.log("Navigating to new page");
|
||||
await syscall("editor.navigate", newName);
|
||||
|
||||
let pageToUpdateSet = new Set<string>();
|
||||
for (let pageToUpdate of pagesToUpdate) {
|
||||
pageToUpdateSet.add(pageToUpdate.page);
|
||||
}
|
||||
|
||||
for (let pageToUpdate of pageToUpdateSet) {
|
||||
console.log("Now going to update links in", pageToUpdate);
|
||||
let { text } = await syscall("space.readPage", pageToUpdate);
|
||||
if (!text) {
|
||||
// Page likely does not exist, but at least we can skip it
|
||||
continue;
|
||||
}
|
||||
let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);
|
||||
if (text !== newText) {
|
||||
console.log("Changes made, saving...");
|
||||
await syscall("space.writePage", pageToUpdate, newText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type BackLink = {
|
||||
page: string;
|
||||
pos: number;
|
||||
};
|
||||
|
||||
async function getBackLinks(pageName: string): Promise<BackLink[]> {
|
||||
let allBackLinks = await syscall(
|
||||
"indexer.scanPrefixGlobal",
|
||||
`pl:${pageName}:`
|
||||
);
|
||||
let pagesToUpdate: BackLink[] = [];
|
||||
for (let { key, value } of allBackLinks) {
|
||||
let keyParts = key.split(":");
|
||||
pagesToUpdate.push({
|
||||
page: value,
|
||||
pos: +keyParts[keyParts.length - 1],
|
||||
});
|
||||
}
|
||||
return pagesToUpdate;
|
||||
}
|
||||
|
||||
export async function showBackLinks() {
|
||||
const pageMeta = await syscall("editor.getCurrentPage");
|
||||
let backLinks = await getBackLinks(pageMeta.name);
|
||||
|
||||
console.log("Backlinks", backLinks);
|
||||
}
|
||||
|
||||
export async function reindex() {
|
||||
await syscall("space.reindex");
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ClickEvent } from "../../webapp/src/app_event.ts";
|
||||
import { syscall } from "./lib/syscall.ts";
|
||||
|
||||
export async function taskToggle(event: ClickEvent) {
|
||||
let syntaxNode = await syscall("editor.getSyntaxNodeAtPos", event.pos);
|
||||
if (syntaxNode && syntaxNode.name === "TaskMarker") {
|
||||
if (syntaxNode.text === "[x]" || syntaxNode.text === "[X]") {
|
||||
await syscall("editor.dispatch", {
|
||||
changes: {
|
||||
from: syntaxNode.from,
|
||||
to: syntaxNode.to,
|
||||
insert: "[ ]",
|
||||
},
|
||||
selection: {
|
||||
anchor: event.pos,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await syscall("editor.dispatch", {
|
||||
changes: {
|
||||
from: syntaxNode.from,
|
||||
to: syntaxNode.to,
|
||||
insert: "[x]",
|
||||
},
|
||||
selection: {
|
||||
anchor: event.pos,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function welcome() {
|
||||
console.log("Hello world!");
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
function countWords(str: string): number {
|
||||
var matches = str.match(/[\w\d\'\'-]+/gi);
|
||||
return matches ? matches.length : 0;
|
||||
}
|
||||
|
||||
function readingTime(wordCount: number): number {
|
||||
// 225 is average word reading speed for adults
|
||||
return Math.ceil(wordCount / 225);
|
||||
}
|
||||
|
||||
import { syscall } from "./lib/syscall.ts";
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "plugbox",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"source": "src/bundle.ts",
|
||||
"main": "dist/bundle.js",
|
||||
"scripts": {
|
||||
"build": "parcel build",
|
||||
"core": "node dist/bundle.js --debug core/core.plugin.json ../webapp/src/generated/core.plugin.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"esbuild": "^0.14.24",
|
||||
"typescript": ">=3.0.0",
|
||||
"vm2": "^3.9.9",
|
||||
"yargs": "^17.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/yargs": "^17.0.9",
|
||||
"parcel": "^2.3.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import esbuild from "esbuild";
|
||||
import { readFile, unlink, writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import { Manifest } from "../../webapp/src/plugins/types";
|
||||
|
||||
async function compile(filePath: string, sourceMap: string) {
|
||||
let tempFile = "out.js";
|
||||
let js = await esbuild.build({
|
||||
entryPoints: [filePath],
|
||||
bundle: true,
|
||||
format: "iife",
|
||||
globalName: "mod",
|
||||
platform: "neutral",
|
||||
sourcemap: sourceMap ? "inline" : false,
|
||||
minify: true,
|
||||
outfile: tempFile,
|
||||
});
|
||||
|
||||
let jsCode = (await readFile(tempFile)).toString();
|
||||
jsCode = jsCode.replace(/^var mod ?= ?/, "");
|
||||
await unlink(tempFile);
|
||||
return jsCode;
|
||||
}
|
||||
|
||||
async function bundle(manifestPath, sourceMaps) {
|
||||
const rootPath = path.dirname(manifestPath);
|
||||
const manifest = JSON.parse(
|
||||
(await readFile(manifestPath)).toString()
|
||||
) as Manifest;
|
||||
|
||||
for (let [name, def] of Object.entries(manifest.functions)) {
|
||||
let jsFunctionName = def.functionName,
|
||||
filePath = path.join(rootPath, def.path);
|
||||
if (filePath.indexOf(":") !== -1) {
|
||||
[filePath, jsFunctionName] = filePath.split(":");
|
||||
} else if (!jsFunctionName) {
|
||||
jsFunctionName = "default";
|
||||
}
|
||||
|
||||
def.code = await compile(filePath, sourceMaps);
|
||||
def.path = filePath;
|
||||
def.functionName = jsFunctionName;
|
||||
}
|
||||
return manifest;
|
||||
}
|
||||
async function run() {
|
||||
let args = await yargs(hideBin(process.argv))
|
||||
.option("debug", {
|
||||
type: "boolean",
|
||||
})
|
||||
.parse();
|
||||
|
||||
let generatedManifest = await bundle(args._[0], !!args.debug);
|
||||
writeFile(args._[1] as string, JSON.stringify(generatedManifest, null, 2));
|
||||
}
|
||||
|
||||
run().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
+1768
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user