Massive restructure of plugin API
This commit is contained in:
+10
-17
@@ -1,44 +1,37 @@
|
||||
import { collectNodesOfType } from "../../common/tree.ts";
|
||||
import {
|
||||
batchSet,
|
||||
queryPrefix,
|
||||
} from "../../syscall/silverbullet-syscall/index.ts";
|
||||
import {
|
||||
getCurrentPage,
|
||||
matchBefore,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import type { IndexTreeEvent } from "../../web/app_event.ts";
|
||||
import { removeQueries } from "../query/util.ts";
|
||||
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
||||
import { editor, index } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import type { IndexTreeEvent } from "$sb/app_event.ts";
|
||||
import { removeQueries } from "$sb/lib/query.ts";
|
||||
|
||||
// Key space
|
||||
// a:pageName:anchorName => pos
|
||||
|
||||
export async function indexAnchors({ name: pageName, tree }: IndexTreeEvent) {
|
||||
removeQueries(tree);
|
||||
let anchors: { key: string; value: string }[] = [];
|
||||
const anchors: { key: string; value: string }[] = [];
|
||||
|
||||
collectNodesOfType(tree, "NamedAnchor").forEach((n) => {
|
||||
let aName = n.children![0].text!;
|
||||
const aName = n.children![0].text!;
|
||||
anchors.push({
|
||||
key: `a:${pageName}:${aName}`,
|
||||
value: "" + n.from,
|
||||
});
|
||||
});
|
||||
console.log("Found", anchors.length, "anchors(s)");
|
||||
await batchSet(pageName, anchors);
|
||||
await index.batchSet(pageName, anchors);
|
||||
}
|
||||
|
||||
export async function anchorComplete() {
|
||||
let prefix = await matchBefore("\\[\\[[^\\]@:]*@[\\w\\.\\-\\/]*");
|
||||
const prefix = await editor.matchBefore("\\[\\[[^\\]@:]*@[\\w\\.\\-\\/]*");
|
||||
if (!prefix) {
|
||||
return null;
|
||||
}
|
||||
const [pageRefPrefix, anchorRef] = prefix.text.split("@");
|
||||
let pageRef = pageRefPrefix.substring(2);
|
||||
if (!pageRef) {
|
||||
pageRef = await getCurrentPage();
|
||||
pageRef = await editor.getCurrentPage();
|
||||
}
|
||||
let allAnchors = await queryPrefix(`a:${pageRef}:@${anchorRef}`);
|
||||
const allAnchors = await index.queryPrefix(`a:${pageRef}:@${anchorRef}`);
|
||||
return {
|
||||
from: prefix.from + pageRefPrefix.length + 1,
|
||||
options: allAnchors.map((a) => ({
|
||||
|
||||
+6
-6
@@ -2,9 +2,9 @@ import type {
|
||||
FileData,
|
||||
FileEncoding,
|
||||
} from "../../common/spaces/space_primitives.ts";
|
||||
import { renderToText, replaceNodesMatching } from "../../common/tree.ts";
|
||||
import { renderToText, replaceNodesMatching } from "$sb/lib/tree.ts";
|
||||
import type { FileMeta } from "../../common/types.ts";
|
||||
import { parseMarkdown } from "../../syscall/silverbullet-syscall/markdown.ts";
|
||||
import { parseMarkdown } from "$sb/silverbullet-syscall/markdown.ts";
|
||||
|
||||
const pagePrefix = "💭 ";
|
||||
|
||||
@@ -55,7 +55,7 @@ async function translateLinksWithPrefix(
|
||||
text: string,
|
||||
prefix: string,
|
||||
): Promise<string> {
|
||||
let tree = await parseMarkdown(text);
|
||||
const tree = await parseMarkdown(text);
|
||||
replaceNodesMatching(tree, (tree) => {
|
||||
if (tree.type === "WikiLinkPage") {
|
||||
// Add the prefix in the link text
|
||||
@@ -67,12 +67,12 @@ async function translateLinksWithPrefix(
|
||||
return text;
|
||||
}
|
||||
|
||||
export async function getFileMetaCloud(name: string): Promise<FileMeta> {
|
||||
return {
|
||||
export function getFileMetaCloud(name: string): Promise<FileMeta> {
|
||||
return Promise.resolve({
|
||||
name,
|
||||
size: 0,
|
||||
contentType: "text/markdown",
|
||||
lastModified: 0,
|
||||
perm: "ro",
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { matchBefore } from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { listCommands } from "../../syscall/silverbullet-syscall/system.ts";
|
||||
import { editor, system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
export async function commandComplete() {
|
||||
let prefix = await matchBefore("\\{\\[[^\\]]*");
|
||||
const prefix = await editor.matchBefore("\\{\\[[^\\]]*");
|
||||
if (!prefix) {
|
||||
return null;
|
||||
}
|
||||
let allCommands = await listCommands();
|
||||
const allCommands = await system.listCommands();
|
||||
|
||||
return {
|
||||
from: prefix.from + 2,
|
||||
|
||||
@@ -139,11 +139,11 @@ functions:
|
||||
|
||||
# Full text search
|
||||
# searchIndex:
|
||||
# path: ./search.ts:index
|
||||
# path: ./search.ts:pageIndex
|
||||
# events:
|
||||
# - page:index
|
||||
# searchUnindex:
|
||||
# path: "./search.ts:unindex"
|
||||
# path: "./search.ts:pageUnindex"
|
||||
# env: server
|
||||
# events:
|
||||
# - page:deleted
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
export function niceDate(d: Date): string {
|
||||
function pad(n: number) {
|
||||
let s = String(n);
|
||||
if (s.length === 1) {
|
||||
s = "0" + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
return d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate());
|
||||
}
|
||||
+14
-12
@@ -1,24 +1,26 @@
|
||||
import { getLogs } from "../../syscall/plugos-syscall/sandbox.ts";
|
||||
import { sandbox } from "$sb/plugos-syscall/mod.ts";
|
||||
import {
|
||||
getText,
|
||||
hidePanel,
|
||||
showPanel,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { parseMarkdown } from "../../syscall/silverbullet-syscall/markdown.ts";
|
||||
import { getServerLogs } from "../../syscall/silverbullet-syscall/sandbox.ts";
|
||||
editor,
|
||||
markdown,
|
||||
sandbox as serverSandbox,
|
||||
} from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
export async function parsePageCommand() {
|
||||
console.log(
|
||||
"AST",
|
||||
JSON.stringify(await parseMarkdown(await getText()), null, 2),
|
||||
JSON.stringify(
|
||||
await markdown.parseMarkdown(await editor.getText()),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export async function showLogsCommand() {
|
||||
let clientLogs = await getLogs();
|
||||
let serverLogs = await getServerLogs();
|
||||
const clientLogs = await sandbox.getLogs();
|
||||
const serverLogs = await serverSandbox.getServerLogs();
|
||||
|
||||
await showPanel(
|
||||
await editor.showPanel(
|
||||
"bhs",
|
||||
1,
|
||||
`
|
||||
@@ -83,5 +85,5 @@ export async function showLogsCommand() {
|
||||
}
|
||||
|
||||
export async function hideBhsCommand() {
|
||||
await hidePanel("bhs");
|
||||
await editor.hidePanel("bhs");
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import * as clientStore from "../../syscall/silverbullet-syscall/clientStore.ts";
|
||||
import { enableReadOnlyMode } from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { clientStore, editor } from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
export async function editorLoad() {
|
||||
let readOnlyMode = await clientStore.get("readOnlyMode");
|
||||
const readOnlyMode = await clientStore.get("readOnlyMode");
|
||||
if (readOnlyMode) {
|
||||
await enableReadOnlyMode(true);
|
||||
await editor.enableReadOnlyMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
export async function toggleReadOnlyMode() {
|
||||
let readOnlyMode = await clientStore.get("readOnlyMode");
|
||||
readOnlyMode = !readOnlyMode;
|
||||
await enableReadOnlyMode(readOnlyMode);
|
||||
await editor.enableReadOnlyMode(readOnlyMode);
|
||||
await clientStore.set("readOnlyMode", readOnlyMode);
|
||||
}
|
||||
|
||||
+14
-22
@@ -1,16 +1,8 @@
|
||||
import type { IndexTreeEvent } from "../../web/app_event.ts";
|
||||
import type { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||
|
||||
import {
|
||||
batchSet,
|
||||
queryPrefix,
|
||||
} from "../../syscall/silverbullet-syscall/index.ts";
|
||||
import {
|
||||
collectNodesOfType,
|
||||
ParseTree,
|
||||
renderToText,
|
||||
} from "../../common/tree.ts";
|
||||
import { removeQueries } from "../query/util.ts";
|
||||
import { applyQuery, QueryProviderEvent } from "../query/engine.ts";
|
||||
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { collectNodesOfType, ParseTree, renderToText } from "$sb/lib/tree.ts";
|
||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||
|
||||
export type Item = {
|
||||
name: string;
|
||||
@@ -22,12 +14,12 @@ export type Item = {
|
||||
};
|
||||
|
||||
export async function indexItems({ name, tree }: IndexTreeEvent) {
|
||||
let items: { key: string; value: Item }[] = [];
|
||||
const items: { key: string; value: Item }[] = [];
|
||||
removeQueries(tree);
|
||||
|
||||
console.log("Indexing items", name);
|
||||
|
||||
let coll = collectNodesOfType(tree, "ListItem");
|
||||
const coll = collectNodesOfType(tree, "ListItem");
|
||||
|
||||
coll.forEach((n) => {
|
||||
if (!n.children) {
|
||||
@@ -38,9 +30,9 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
let textNodes: ParseTree[] = [];
|
||||
const textNodes: ParseTree[] = [];
|
||||
let nested: string | undefined;
|
||||
for (let child of n.children!.slice(1)) {
|
||||
for (const child of n.children!.slice(1)) {
|
||||
if (child.type === "OrderedList" || child.type === "BulletList") {
|
||||
nested = renderToText(child);
|
||||
break;
|
||||
@@ -48,8 +40,8 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
|
||||
textNodes.push(child);
|
||||
}
|
||||
|
||||
let itemText = textNodes.map(renderToText).join("").trim();
|
||||
let item: Item = {
|
||||
const itemText = textNodes.map(renderToText).join("").trim();
|
||||
const item: Item = {
|
||||
name: itemText,
|
||||
};
|
||||
if (nested) {
|
||||
@@ -68,15 +60,15 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
|
||||
});
|
||||
});
|
||||
console.log("Found", items.length, "item(s)");
|
||||
await batchSet(name, items);
|
||||
await index.batchSet(name, items);
|
||||
}
|
||||
|
||||
export async function queryProvider({
|
||||
query,
|
||||
}: QueryProviderEvent): Promise<any[]> {
|
||||
let allItems: Item[] = [];
|
||||
for (let { key, page, value } of await queryPrefix("it:")) {
|
||||
let [, pos] = key.split(":");
|
||||
const allItems: Item[] = [];
|
||||
for (const { key, page, value } of await index.queryPrefix("it:")) {
|
||||
const [, pos] = key.split(":");
|
||||
allItems.push({
|
||||
...value,
|
||||
page: page,
|
||||
|
||||
+22
-26
@@ -1,14 +1,6 @@
|
||||
import { nodeAtPos } from "../../common/tree.ts";
|
||||
import {
|
||||
filterBox,
|
||||
flashNotification,
|
||||
getCursor,
|
||||
getText,
|
||||
replaceRange,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { parseMarkdown } from "../../syscall/silverbullet-syscall/markdown.ts";
|
||||
import { dispatch as dispatchEvent } from "../../syscall/plugos-syscall/event.ts";
|
||||
import { invokeFunction } from "../../syscall/silverbullet-syscall/system.ts";
|
||||
import { nodeAtPos } from "$sb/lib/tree.ts";
|
||||
import { editor, markdown, system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
||||
|
||||
type UnfurlOption = {
|
||||
id: string;
|
||||
@@ -16,16 +8,16 @@ type UnfurlOption = {
|
||||
};
|
||||
|
||||
export async function unfurlCommand() {
|
||||
let mdTree = await parseMarkdown(await getText());
|
||||
let nakedUrlNode = nodeAtPos(mdTree, await getCursor());
|
||||
let url = nakedUrlNode!.children![0].text!;
|
||||
const mdTree = await markdown.parseMarkdown(await editor.getText());
|
||||
const nakedUrlNode = nodeAtPos(mdTree, await editor.getCursor());
|
||||
const url = nakedUrlNode!.children![0].text!;
|
||||
console.log("Got URL to unfurl", url);
|
||||
let optionResponses = await dispatchEvent("unfurl:options", url);
|
||||
let options: UnfurlOption[] = [];
|
||||
for (let resp of optionResponses) {
|
||||
const optionResponses = await events.dispatchEvent("unfurl:options", url);
|
||||
const options: UnfurlOption[] = [];
|
||||
for (const resp of optionResponses) {
|
||||
options.push(...resp);
|
||||
}
|
||||
let selectedUnfurl: any = await filterBox(
|
||||
const selectedUnfurl: any = await editor.filterBox(
|
||||
"Unfurl",
|
||||
options,
|
||||
"Select the unfurl strategy of your choice",
|
||||
@@ -34,19 +26,23 @@ export async function unfurlCommand() {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let replacement = await invokeFunction(
|
||||
const replacement = await system.invokeFunction(
|
||||
"server",
|
||||
"unfurlExec",
|
||||
selectedUnfurl.id,
|
||||
url,
|
||||
);
|
||||
await replaceRange(nakedUrlNode?.from!, nakedUrlNode?.to!, replacement);
|
||||
await editor.replaceRange(
|
||||
nakedUrlNode?.from!,
|
||||
nakedUrlNode?.to!,
|
||||
replacement,
|
||||
);
|
||||
} catch (e: any) {
|
||||
await flashNotification(e.message, "error");
|
||||
await editor.flashNotification(e.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
export async function titleUnfurlOptions(url: string): Promise<UnfurlOption[]> {
|
||||
export function titleUnfurlOptions(): UnfurlOption[] {
|
||||
return [
|
||||
{
|
||||
id: "title-unfurl",
|
||||
@@ -57,7 +53,7 @@ export async function titleUnfurlOptions(url: string): Promise<UnfurlOption[]> {
|
||||
|
||||
// Run on the server because plugs will likely rely on fetch for this
|
||||
export async function unfurlExec(id: string, url: string): Promise<string> {
|
||||
let replacement = await dispatchEvent(`unfurl:${id}`, url);
|
||||
const replacement = await events.dispatchEvent(`unfurl:${id}`, url);
|
||||
if (replacement.length === 0) {
|
||||
throw new Error("Unfurl failed");
|
||||
} else {
|
||||
@@ -68,13 +64,13 @@ export async function unfurlExec(id: string, url: string): Promise<string> {
|
||||
const titleRegex = /<title[^>]*>\s*([^<]+)\s*<\/title\s*>/i;
|
||||
|
||||
export async function titleUnfurl(url: string): Promise<string> {
|
||||
let response = await fetch(url);
|
||||
const response = await fetch(url);
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
console.error("Unfurl failed", await response.text());
|
||||
throw new Error(`Failed to fetch: ${await response.statusText}`);
|
||||
}
|
||||
let body = await response.text();
|
||||
let match = titleRegex.exec(body);
|
||||
const body = await response.text();
|
||||
const match = titleRegex.exec(body);
|
||||
if (match) {
|
||||
return `[${match[1]}](${url})`;
|
||||
} else {
|
||||
|
||||
+13
-22
@@ -1,15 +1,6 @@
|
||||
import type { ClickEvent } from "../../web/app_event.ts";
|
||||
import {
|
||||
flashNotification,
|
||||
getCurrentPage,
|
||||
getCursor,
|
||||
getText,
|
||||
navigate as navigateTo,
|
||||
openUrl,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { parseMarkdown } from "../../syscall/silverbullet-syscall/markdown.ts";
|
||||
import { nodeAtPos, ParseTree } from "../../common/tree.ts";
|
||||
import { invokeCommand } from "../../syscall/silverbullet-syscall/system.ts";
|
||||
import type { ClickEvent } from "$sb/app_event.ts";
|
||||
import { editor, markdown, system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { nodeAtPos, ParseTree } from "$sb/lib/tree.ts";
|
||||
|
||||
// Checks if the URL contains a protocol, if so keeps it, otherwise assumes an attachment
|
||||
function patchUrl(url: string): string {
|
||||
@@ -35,21 +26,21 @@ async function actionClickOrActionEnter(mdTree: ParseTree | null) {
|
||||
}
|
||||
}
|
||||
if (!pageLink) {
|
||||
pageLink = await getCurrentPage();
|
||||
pageLink = await editor.getCurrentPage();
|
||||
}
|
||||
await navigateTo(pageLink, pos);
|
||||
await editor.navigate(pageLink, pos);
|
||||
break;
|
||||
}
|
||||
case "URL":
|
||||
case "NakedURL":
|
||||
await openUrl(patchUrl(mdTree.children![0].text!));
|
||||
await editor.openUrl(patchUrl(mdTree.children![0].text!));
|
||||
break;
|
||||
case "Link": {
|
||||
const url = patchUrl(mdTree.children![4].children![0].text!);
|
||||
if (url.length <= 1) {
|
||||
return flashNotification("Empty link, ignoring", "error");
|
||||
return editor.flashNotification("Empty link, ignoring", "error");
|
||||
}
|
||||
await openUrl(url);
|
||||
await editor.openUrl(url);
|
||||
break;
|
||||
}
|
||||
case "CommandLink": {
|
||||
@@ -57,15 +48,15 @@ async function actionClickOrActionEnter(mdTree: ParseTree | null) {
|
||||
.children![0].text!.substring(2, mdTree.children![0].text!.length - 2)
|
||||
.trim();
|
||||
console.log("Got command link", command);
|
||||
await invokeCommand(command);
|
||||
await system.invokeCommand(command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function linkNavigate() {
|
||||
const mdTree = await parseMarkdown(await getText());
|
||||
const newNode = nodeAtPos(mdTree, await getCursor());
|
||||
const mdTree = await markdown.parseMarkdown(await editor.getText());
|
||||
const newNode = nodeAtPos(mdTree, await editor.getCursor());
|
||||
await actionClickOrActionEnter(newNode);
|
||||
}
|
||||
|
||||
@@ -74,11 +65,11 @@ export async function clickNavigate(event: ClickEvent) {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
return;
|
||||
}
|
||||
const mdTree = await parseMarkdown(await getText());
|
||||
const mdTree = await markdown.parseMarkdown(await editor.getText());
|
||||
const newNode = nodeAtPos(mdTree, event.pos);
|
||||
await actionClickOrActionEnter(newNode);
|
||||
}
|
||||
|
||||
export async function navigateCommand(cmdDef: any) {
|
||||
await navigateTo(cmdDef.page);
|
||||
await editor.navigate(cmdDef.page);
|
||||
}
|
||||
|
||||
+65
-76
@@ -1,39 +1,26 @@
|
||||
import type { IndexEvent, IndexTreeEvent } from "../../web/app_event.ts";
|
||||
import type {
|
||||
IndexEvent,
|
||||
IndexTreeEvent,
|
||||
QueryProviderEvent,
|
||||
} from "$sb/app_event.ts";
|
||||
import {
|
||||
batchSet,
|
||||
clearPageIndex as clearPageIndexSyscall,
|
||||
clearPageIndexForPage,
|
||||
queryPrefix,
|
||||
set,
|
||||
} from "../../syscall/silverbullet-syscall/index.ts";
|
||||
editor,
|
||||
index,
|
||||
markdown,
|
||||
space,
|
||||
system,
|
||||
} from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
import {
|
||||
flashNotification,
|
||||
getCurrentPage,
|
||||
getCursor,
|
||||
getText,
|
||||
matchBefore,
|
||||
navigate,
|
||||
prompt,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { events, store } from "$sb/plugos-syscall/mod.ts";
|
||||
|
||||
import { dispatch } from "../../syscall/plugos-syscall/event.ts";
|
||||
import {
|
||||
deletePage as deletePageSyscall,
|
||||
listPages,
|
||||
readPage,
|
||||
writePage,
|
||||
} from "../../syscall/silverbullet-syscall/space.ts";
|
||||
import { invokeFunction } from "../../syscall/silverbullet-syscall/system.ts";
|
||||
import { parseMarkdown } from "../../syscall/silverbullet-syscall/markdown.ts";
|
||||
import {
|
||||
addParentPointers,
|
||||
collectNodesMatching,
|
||||
ParseTree,
|
||||
renderToText,
|
||||
replaceNodesMatching,
|
||||
} from "../../common/tree.ts";
|
||||
import { applyQuery, QueryProviderEvent } from "../query/engine.ts";
|
||||
} from "$sb/lib/tree.ts";
|
||||
import { applyQuery } from "$sb/lib/query.ts";
|
||||
import { extractMeta } from "../query/data.ts";
|
||||
|
||||
// Key space:
|
||||
@@ -41,19 +28,19 @@ import { extractMeta } from "../query/data.ts";
|
||||
// meta => metaJson
|
||||
|
||||
export async function indexLinks({ name, tree }: IndexTreeEvent) {
|
||||
let backLinks: { key: string; value: string }[] = [];
|
||||
const backLinks: { key: string; value: string }[] = [];
|
||||
// [[Style Links]]
|
||||
console.log("Now indexing", name);
|
||||
let pageMeta = extractMeta(tree);
|
||||
const pageMeta = extractMeta(tree);
|
||||
if (Object.keys(pageMeta).length > 0) {
|
||||
console.log("Extracted page meta data", pageMeta);
|
||||
// Don't index meta data starting with $
|
||||
for (let key in pageMeta) {
|
||||
for (const key in pageMeta) {
|
||||
if (key.startsWith("$")) {
|
||||
delete pageMeta[key];
|
||||
}
|
||||
}
|
||||
await set(name, "meta:", pageMeta);
|
||||
await index.set(name, "meta:", pageMeta);
|
||||
}
|
||||
|
||||
collectNodesMatching(tree, (n) => n.type === "WikiLinkPage").forEach((n) => {
|
||||
@@ -67,18 +54,18 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
|
||||
});
|
||||
});
|
||||
console.log("Found", backLinks.length, "wiki link(s)");
|
||||
await batchSet(name, backLinks);
|
||||
await index.batchSet(name, backLinks);
|
||||
}
|
||||
|
||||
export async function pageQueryProvider({
|
||||
query,
|
||||
}: QueryProviderEvent): Promise<any[]> {
|
||||
let allPages = await listPages();
|
||||
let allPageMap: Map<string, any> = new Map(
|
||||
let allPages = await space.listPages();
|
||||
const allPageMap: Map<string, any> = new Map(
|
||||
allPages.map((pm) => [pm.name, pm]),
|
||||
);
|
||||
for (let { page, value } of await queryPrefix("meta:")) {
|
||||
let p = allPageMap.get(page);
|
||||
for (const { page, value } of await index.queryPrefix("meta:")) {
|
||||
const p = allPageMap.get(page);
|
||||
if (p) {
|
||||
for (let [k, v] of Object.entries(value)) {
|
||||
p[k] = v;
|
||||
@@ -93,8 +80,10 @@ export async function linkQueryProvider({
|
||||
query,
|
||||
pageName,
|
||||
}: QueryProviderEvent): Promise<any[]> {
|
||||
let links: any[] = [];
|
||||
for (let { value: name, key } of await queryPrefix(`pl:${pageName}:`)) {
|
||||
const links: any[] = [];
|
||||
for (
|
||||
const { value: name, key } of await index.queryPrefix(`pl:${pageName}:`)
|
||||
) {
|
||||
const [, , pos] = key.split(":"); // Key: pl:page:pos
|
||||
links.push({ name, pos });
|
||||
}
|
||||
@@ -102,18 +91,18 @@ export async function linkQueryProvider({
|
||||
}
|
||||
|
||||
export async function deletePage() {
|
||||
let pageName = await getCurrentPage();
|
||||
const pageName = await editor.getCurrentPage();
|
||||
console.log("Navigating to index page");
|
||||
await navigate("");
|
||||
await editor.navigate("");
|
||||
console.log("Deleting page from space");
|
||||
await deletePageSyscall(pageName);
|
||||
await space.deletePage(pageName);
|
||||
}
|
||||
|
||||
export async function renamePage() {
|
||||
const oldName = await getCurrentPage();
|
||||
const cursor = await getCursor();
|
||||
const oldName = await editor.getCurrentPage();
|
||||
const cursor = await editor.getCursor();
|
||||
console.log("Old name is", oldName);
|
||||
const newName = await prompt(`Rename ${oldName} to:`, oldName);
|
||||
const newName = await editor.prompt(`Rename ${oldName} to:`, oldName);
|
||||
if (!newName) {
|
||||
return;
|
||||
}
|
||||
@@ -123,45 +112,45 @@ export async function renamePage() {
|
||||
}
|
||||
console.log("New name", newName);
|
||||
|
||||
let pagesToUpdate = await getBackLinks(oldName);
|
||||
const pagesToUpdate = await getBackLinks(oldName);
|
||||
console.log("All pages containing backlinks", pagesToUpdate);
|
||||
|
||||
let text = await getText();
|
||||
const text = await editor.getText();
|
||||
console.log("Writing new page to space");
|
||||
await writePage(newName, text);
|
||||
await space.writePage(newName, text);
|
||||
console.log("Navigating to new page");
|
||||
await navigate(newName, cursor, true);
|
||||
await editor.navigate(newName, cursor, true);
|
||||
console.log("Deleting page from space");
|
||||
await deletePageSyscall(oldName);
|
||||
await space.deletePage(oldName);
|
||||
|
||||
let pageToUpdateSet = new Set<string>();
|
||||
for (let pageToUpdate of pagesToUpdate) {
|
||||
const pageToUpdateSet = new Set<string>();
|
||||
for (const pageToUpdate of pagesToUpdate) {
|
||||
pageToUpdateSet.add(pageToUpdate.page);
|
||||
}
|
||||
|
||||
for (let pageToUpdate of pageToUpdateSet) {
|
||||
for (const pageToUpdate of pageToUpdateSet) {
|
||||
if (pageToUpdate === oldName) {
|
||||
continue;
|
||||
}
|
||||
console.log("Now going to update links in", pageToUpdate);
|
||||
let { text } = await readPage(pageToUpdate);
|
||||
const text = await space.readPage(pageToUpdate);
|
||||
// console.log("Received text", text);
|
||||
if (!text) {
|
||||
// Page likely does not exist, but at least we can skip it
|
||||
continue;
|
||||
}
|
||||
let mdTree = await parseMarkdown(text);
|
||||
const mdTree = await markdown.parseMarkdown(text);
|
||||
addParentPointers(mdTree);
|
||||
replaceNodesMatching(mdTree, (n): ParseTree | undefined | null => {
|
||||
if (n.type === "WikiLinkPage") {
|
||||
let pageName = n.children![0].text!;
|
||||
const pageName = n.children![0].text!;
|
||||
if (pageName === oldName) {
|
||||
n.children![0].text = newName;
|
||||
return n;
|
||||
}
|
||||
// page name with @pos position
|
||||
if (pageName.startsWith(`${oldName}@`)) {
|
||||
let [, pos] = pageName.split("@");
|
||||
const [, pos] = pageName.split("@");
|
||||
n.children![0].text = `${newName}@${pos}`;
|
||||
return n;
|
||||
}
|
||||
@@ -169,10 +158,10 @@ export async function renamePage() {
|
||||
return;
|
||||
});
|
||||
// let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);
|
||||
let newText = renderToText(mdTree);
|
||||
const newText = renderToText(mdTree);
|
||||
if (text !== newText) {
|
||||
console.log("Changes made, saving...");
|
||||
await writePage(pageToUpdate, newText);
|
||||
await space.writePage(pageToUpdate, newText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,10 +172,10 @@ type BackLink = {
|
||||
};
|
||||
|
||||
async function getBackLinks(pageName: string): Promise<BackLink[]> {
|
||||
let allBackLinks = await queryPrefix(`pl:${pageName}:`);
|
||||
let pagesToUpdate: BackLink[] = [];
|
||||
for (let { key, value } of allBackLinks) {
|
||||
let keyParts = key.split(":");
|
||||
const allBackLinks = await index.queryPrefix(`pl:${pageName}:`);
|
||||
const pagesToUpdate: BackLink[] = [];
|
||||
for (const { key, value } of allBackLinks) {
|
||||
const keyParts = key.split(":");
|
||||
pagesToUpdate.push({
|
||||
page: value,
|
||||
pos: +keyParts[keyParts.length - 1],
|
||||
@@ -196,18 +185,18 @@ async function getBackLinks(pageName: string): Promise<BackLink[]> {
|
||||
}
|
||||
|
||||
export async function reindexCommand() {
|
||||
await flashNotification("Reindexing...");
|
||||
await invokeFunction("server", "reindexSpace");
|
||||
await flashNotification("Reindexing done");
|
||||
await editor.flashNotification("Reindexing...");
|
||||
await system.invokeFunction("server", "reindexSpace");
|
||||
await editor.flashNotification("Reindexing done");
|
||||
}
|
||||
|
||||
// Completion
|
||||
export async function pageComplete() {
|
||||
let prefix = await matchBefore("\\[\\[[^\\]@:]*");
|
||||
const prefix = await editor.matchBefore("\\[\\[[^\\]@:]*");
|
||||
if (!prefix) {
|
||||
return null;
|
||||
}
|
||||
let allPages = await listPages();
|
||||
const allPages = await space.listPages();
|
||||
return {
|
||||
from: prefix.from + 2,
|
||||
options: allPages.map((pageMeta) => ({
|
||||
@@ -220,14 +209,14 @@ export async function pageComplete() {
|
||||
// Server functions
|
||||
export async function reindexSpace() {
|
||||
console.log("Clearing page index...");
|
||||
await clearPageIndexSyscall();
|
||||
await index.clearPageIndex();
|
||||
console.log("Listing all pages");
|
||||
let pages = await listPages();
|
||||
for (let { name } of pages) {
|
||||
const pages = await space.listPages();
|
||||
for (const { name } of pages) {
|
||||
console.log("Indexing", name);
|
||||
const { text } = await readPage(name);
|
||||
let parsed = await parseMarkdown(text);
|
||||
await dispatch("page:index", {
|
||||
const text = await space.readPage(name);
|
||||
const parsed = await markdown.parseMarkdown(text);
|
||||
await events.dispatchEvent("page:index", {
|
||||
name,
|
||||
tree: parsed,
|
||||
});
|
||||
@@ -237,12 +226,12 @@ export async function reindexSpace() {
|
||||
|
||||
export async function clearPageIndex(page: string) {
|
||||
console.log("Clearing page index for page", page);
|
||||
await clearPageIndexForPage(page);
|
||||
await index.clearPageIndexForPage(page);
|
||||
}
|
||||
|
||||
export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
|
||||
await dispatch("page:index", {
|
||||
await events.dispatchEvent("page:index", {
|
||||
name,
|
||||
tree: await parseMarkdown(text),
|
||||
tree: await markdown.parseMarkdown(text),
|
||||
});
|
||||
}
|
||||
|
||||
+28
-39
@@ -1,30 +1,18 @@
|
||||
import { dispatch } from "../../syscall/plugos-syscall/event.ts";
|
||||
import { Manifest } from "../../common/manifest.ts";
|
||||
import {
|
||||
flashNotification,
|
||||
save,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import {
|
||||
deleteAttachment,
|
||||
listPlugs,
|
||||
writeAttachment,
|
||||
} from "../../syscall/silverbullet-syscall/space.ts";
|
||||
import {
|
||||
invokeFunction,
|
||||
reloadPlugs,
|
||||
} from "../../syscall/silverbullet-syscall/system.ts";
|
||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
||||
import type { Manifest } from "../../common/manifest.ts";
|
||||
import { editor, space, system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
import { readYamlPage } from "../lib/yaml_page.ts";
|
||||
import { readYamlPage } from "$sb/lib/yaml_page.ts";
|
||||
|
||||
export async function updatePlugsCommand() {
|
||||
await save();
|
||||
flashNotification("Updating plugs...");
|
||||
await editor.save();
|
||||
await editor.flashNotification("Updating plugs...");
|
||||
try {
|
||||
await invokeFunction("server", "updatePlugs");
|
||||
flashNotification("And... done!");
|
||||
await reloadPlugs();
|
||||
await system.invokeFunction("server", "updatePlugs");
|
||||
await editor.flashNotification("And... done!");
|
||||
system.reloadPlugs();
|
||||
} catch (e: any) {
|
||||
flashNotification("Error updating plugs: " + e.message, "error");
|
||||
editor.flashNotification("Error updating plugs: " + e.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,18 +30,21 @@ export async function updatePlugs() {
|
||||
throw new Error(`Error processing PLUGS: ${e.message}`);
|
||||
}
|
||||
console.log("Plug YAML", plugList);
|
||||
let allPlugNames: string[] = [];
|
||||
for (let plugUri of plugList) {
|
||||
let [protocol, ...rest] = plugUri.split(":");
|
||||
let manifests = await dispatch(`get-plug:${protocol}`, rest.join(":"));
|
||||
const allPlugNames: string[] = [];
|
||||
for (const plugUri of plugList) {
|
||||
const [protocol, ...rest] = plugUri.split(":");
|
||||
const manifests = await events.dispatchEvent(
|
||||
`get-plug:${protocol}`,
|
||||
rest.join(":"),
|
||||
);
|
||||
if (manifests.length === 0) {
|
||||
console.error("Could not resolve plug", plugUri);
|
||||
}
|
||||
// console.log("Got manifests", plugUri, protocol, manifests);
|
||||
let manifest = manifests[0];
|
||||
const manifest = manifests[0];
|
||||
allPlugNames.push(manifest.name);
|
||||
// console.log("Writing", `_plug/${manifest.name}`);
|
||||
await writeAttachment(
|
||||
await space.writeAttachment(
|
||||
`_plug/${manifest.name}.plug.json`,
|
||||
"string",
|
||||
JSON.stringify(manifest),
|
||||
@@ -61,34 +52,32 @@ export async function updatePlugs() {
|
||||
}
|
||||
|
||||
// And delete extra ones
|
||||
for (let existingPlug of await listPlugs()) {
|
||||
let plugName = existingPlug.substring(
|
||||
for (const existingPlug of await space.listPlugs()) {
|
||||
const plugName = existingPlug.substring(
|
||||
"_plug/".length,
|
||||
existingPlug.length - ".plug.json".length,
|
||||
);
|
||||
console.log("Considering", plugName);
|
||||
if (!allPlugNames.includes(plugName)) {
|
||||
console.log("Removing plug", plugName);
|
||||
await deleteAttachment(existingPlug);
|
||||
await space.deleteAttachment(existingPlug);
|
||||
}
|
||||
}
|
||||
await reloadPlugs();
|
||||
await system.reloadPlugs();
|
||||
}
|
||||
|
||||
export async function getPlugHTTPS(url: string): Promise<Manifest> {
|
||||
let fullUrl = `https:${url}`;
|
||||
const fullUrl = `https:${url}`;
|
||||
console.log("Now fetching plug manifest from", fullUrl);
|
||||
let req = await fetch(fullUrl);
|
||||
const req = await fetch(fullUrl);
|
||||
if (req.status !== 200) {
|
||||
throw new Error(`Could not fetch plug manifest from ${fullUrl}`);
|
||||
}
|
||||
let json = await req.json();
|
||||
|
||||
return json;
|
||||
return req.json();
|
||||
}
|
||||
|
||||
export async function getPlugGithub(identifier: string): Promise<Manifest> {
|
||||
let [owner, repo, path] = identifier.split("/");
|
||||
export function getPlugGithub(identifier: string): Promise<Manifest> {
|
||||
const [owner, repo, path] = identifier.split("/");
|
||||
let [repoClean, branch] = repo.split("@");
|
||||
if (!branch) {
|
||||
branch = "main"; // or "master"?
|
||||
|
||||
+21
-27
@@ -1,42 +1,36 @@
|
||||
import {
|
||||
fullTextDelete,
|
||||
fullTextIndex,
|
||||
fullTextSearch,
|
||||
} from "../../syscall/plugos-syscall/fulltext.ts";
|
||||
import { renderToText } from "../../common/tree.ts";
|
||||
import { PageMeta } from "../../common/types.ts";
|
||||
import { queryPrefix } from "../../syscall/silverbullet-syscall/index.ts";
|
||||
import { navigate, prompt } from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { IndexTreeEvent } from "../../web/app_event.ts";
|
||||
import { applyQuery, QueryProviderEvent } from "../query/engine.ts";
|
||||
import { removeQueries } from "../query/util.ts";
|
||||
import { fulltext } from "$sb/plugos-syscall/mod.ts";
|
||||
import { renderToText } from "$sb/lib/tree.ts";
|
||||
import type { PageMeta } from "../../common/types.ts";
|
||||
import { editor, index } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||
|
||||
const searchPrefix = "🔍 ";
|
||||
|
||||
export async function index(data: IndexTreeEvent) {
|
||||
export async function pageIndex(data: IndexTreeEvent) {
|
||||
removeQueries(data.tree);
|
||||
let cleanText = renderToText(data.tree);
|
||||
await fullTextIndex(data.name, cleanText);
|
||||
const cleanText = renderToText(data.tree);
|
||||
await fulltext.fullTextIndex(data.name, cleanText);
|
||||
}
|
||||
|
||||
export async function unindex(pageName: string) {
|
||||
await fullTextDelete(pageName);
|
||||
export async function pageUnindex(pageName: string) {
|
||||
await fulltext.fullTextDelete(pageName);
|
||||
}
|
||||
|
||||
export async function queryProvider({
|
||||
query,
|
||||
}: QueryProviderEvent): Promise<any[]> {
|
||||
let phraseFilter = query.filter.find((f) => f.prop === "phrase");
|
||||
const phraseFilter = query.filter.find((f) => f.prop === "phrase");
|
||||
if (!phraseFilter) {
|
||||
throw Error("No 'phrase' filter specified, this is mandatory");
|
||||
}
|
||||
let results = await fullTextSearch(phraseFilter.value, 100);
|
||||
let results = await fulltext.fullTextSearch(phraseFilter.value, 100);
|
||||
|
||||
let allPageMap: Map<string, any> = new Map(
|
||||
const allPageMap: Map<string, any> = new Map(
|
||||
results.map((r: any) => [r.name, r]),
|
||||
);
|
||||
for (let { page, value } of await queryPrefix("meta:")) {
|
||||
let p = allPageMap.get(page);
|
||||
for (const { page, value } of await index.queryPrefix("meta:")) {
|
||||
const p = allPageMap.get(page);
|
||||
if (p) {
|
||||
for (let [k, v] of Object.entries(value)) {
|
||||
p[k] = v;
|
||||
@@ -52,17 +46,17 @@ export async function queryProvider({
|
||||
}
|
||||
|
||||
export async function searchCommand() {
|
||||
let phrase = await prompt("Search for: ");
|
||||
const phrase = await prompt("Search for: ");
|
||||
if (phrase) {
|
||||
await navigate(`${searchPrefix}${phrase}`);
|
||||
await editor.navigate(`${searchPrefix}${phrase}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function readPageSearch(
|
||||
name: string,
|
||||
): Promise<{ text: string; meta: PageMeta }> {
|
||||
let phrase = name.substring(searchPrefix.length);
|
||||
let results = await fullTextSearch(phrase, 100);
|
||||
const phrase = name.substring(searchPrefix.length);
|
||||
const results = await fulltext.fullTextSearch(phrase, 100);
|
||||
const text = `# Search results for "${phrase}"\n${
|
||||
results
|
||||
.map((r: any) => `* [[${r.name}]] (score: ${r.rank})`)
|
||||
@@ -79,7 +73,7 @@ export async function readPageSearch(
|
||||
};
|
||||
}
|
||||
|
||||
export async function getPageMetaSearch(name: string): Promise<PageMeta> {
|
||||
export function getPageMetaSearch(name: string): PageMeta {
|
||||
return {
|
||||
name,
|
||||
lastModified: 0,
|
||||
|
||||
+4
-8
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
flashNotification,
|
||||
getText,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { listPages } from "../../syscall/silverbullet-syscall/space.ts";
|
||||
import { editor, space } from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
function countWords(str: string): number {
|
||||
const matches = str.match(/[\w\d\'-]+/gi);
|
||||
@@ -15,11 +11,11 @@ function readingTime(wordCount: number): number {
|
||||
}
|
||||
|
||||
export async function statsCommand() {
|
||||
const text = await getText();
|
||||
const allPages = await listPages();
|
||||
const text = await editor.getText();
|
||||
const allPages = await space.listPages();
|
||||
const wordCount = countWords(text);
|
||||
const time = readingTime(wordCount);
|
||||
await flashNotification(
|
||||
await editor.flashNotification(
|
||||
`${wordCount} words; ${time} minutes read; ${allPages.length} total pages in space.`,
|
||||
);
|
||||
}
|
||||
|
||||
+10
-15
@@ -1,35 +1,30 @@
|
||||
import { collectNodesOfType } from "../../common/tree.ts";
|
||||
import {
|
||||
batchSet,
|
||||
queryPrefix,
|
||||
} from "../../syscall/silverbullet-syscall/index.ts";
|
||||
import { matchBefore } from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import type { IndexTreeEvent } from "../../web/app_event.ts";
|
||||
import { applyQuery, QueryProviderEvent } from "../query/engine.ts";
|
||||
import { removeQueries } from "../query/util.ts";
|
||||
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
||||
import { editor, index } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import type { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||
|
||||
// Key space
|
||||
// tag:TAG => true (for completion)
|
||||
|
||||
export async function indexTags({ name, tree }: IndexTreeEvent) {
|
||||
removeQueries(tree);
|
||||
let allTags = new Set<string>();
|
||||
const allTags = new Set<string>();
|
||||
collectNodesOfType(tree, "Hashtag").forEach((n) => {
|
||||
allTags.add(n.children![0].text!);
|
||||
});
|
||||
batchSet(
|
||||
await index.batchSet(
|
||||
name,
|
||||
[...allTags].map((t) => ({ key: `tag:${t}`, value: t })),
|
||||
);
|
||||
}
|
||||
|
||||
export async function tagComplete() {
|
||||
let prefix = await matchBefore("#[^#\\s]+");
|
||||
const prefix = await editor.matchBefore("#[^#\\s]+");
|
||||
// console.log("Running tag complete", prefix);
|
||||
if (!prefix) {
|
||||
return null;
|
||||
}
|
||||
let allTags = await queryPrefix(`tag:${prefix.text}`);
|
||||
const allTags = await index.queryPrefix(`tag:${prefix.text}`);
|
||||
return {
|
||||
from: prefix.from,
|
||||
options: allTags.map((tag) => ({
|
||||
@@ -45,8 +40,8 @@ type Tag = {
|
||||
};
|
||||
|
||||
export async function tagProvider({ query }: QueryProviderEvent) {
|
||||
let allTags = new Map<string, number>();
|
||||
for (let { value } of await queryPrefix("tag:")) {
|
||||
const allTags = new Map<string, number>();
|
||||
for (const { value } of await index.queryPrefix("tag:")) {
|
||||
let currentFreq = allTags.get(value);
|
||||
if (!currentFreq) {
|
||||
currentFreq = 0;
|
||||
|
||||
+51
-59
@@ -1,31 +1,16 @@
|
||||
import {
|
||||
getPageMeta,
|
||||
listPages,
|
||||
readPage,
|
||||
writePage,
|
||||
} from "$sb/silverbullet-syscall/space.ts";
|
||||
import {
|
||||
filterBox,
|
||||
getCurrentPage,
|
||||
getCursor,
|
||||
insertAtCursor,
|
||||
moveCursor,
|
||||
navigate,
|
||||
prompt,
|
||||
} from "../../syscall/silverbullet-syscall/editor.ts";
|
||||
import { parseMarkdown } from "../../syscall/silverbullet-syscall/markdown.ts";
|
||||
import { editor, markdown, space } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { extractMeta } from "../query/data.ts";
|
||||
import { renderToText } from "../../common/tree.ts";
|
||||
import { niceDate } from "./dates.ts";
|
||||
import { readSettings } from "../lib/settings_page.ts";
|
||||
import { renderToText } from "$sb/lib/tree.ts";
|
||||
import { niceDate } from "$sb/lib/dates.ts";
|
||||
import { readSettings } from "$sb/lib/settings_page.ts";
|
||||
|
||||
export async function instantiateTemplateCommand() {
|
||||
const allPages = await listPages();
|
||||
const allPages = await space.listPages();
|
||||
const { pageTemplatePrefix } = await readSettings({
|
||||
pageTemplatePrefix: "template/page/",
|
||||
});
|
||||
|
||||
const selectedTemplate = await filterBox(
|
||||
const selectedTemplate = await editor.filterBox(
|
||||
"Template",
|
||||
allPages
|
||||
.filter((pageMeta) => pageMeta.name.startsWith(pageTemplatePrefix))
|
||||
@@ -41,40 +26,43 @@ export async function instantiateTemplateCommand() {
|
||||
}
|
||||
console.log("Selected template", selectedTemplate);
|
||||
|
||||
const { text } = await readPage(
|
||||
const text = await space.readPage(
|
||||
`${pageTemplatePrefix}${selectedTemplate.name}`,
|
||||
);
|
||||
|
||||
const parseTree = await parseMarkdown(text);
|
||||
const parseTree = await markdown.parseMarkdown(text);
|
||||
const additionalPageMeta = extractMeta(parseTree, [
|
||||
"$name",
|
||||
"$disableDirectives",
|
||||
]);
|
||||
|
||||
const pageName = await prompt("Name of new page", additionalPageMeta.$name);
|
||||
const pageName = await editor.prompt(
|
||||
"Name of new page",
|
||||
additionalPageMeta.$name,
|
||||
);
|
||||
if (!pageName) {
|
||||
return;
|
||||
}
|
||||
const pageText = replaceTemplateVars(renderToText(parseTree), pageName);
|
||||
await writePage(pageName, pageText);
|
||||
await navigate(pageName);
|
||||
await space.writePage(pageName, pageText);
|
||||
await editor.navigate(pageName);
|
||||
}
|
||||
|
||||
export async function insertSnippet() {
|
||||
let allPages = await listPages();
|
||||
let { snippetPrefix } = await readSettings({
|
||||
const allPages = await space.listPages();
|
||||
const { snippetPrefix } = await readSettings({
|
||||
snippetPrefix: "snippet/",
|
||||
});
|
||||
let cursorPos = await getCursor();
|
||||
let page = await getCurrentPage();
|
||||
let allSnippets = allPages
|
||||
const cursorPos = await editor.getCursor();
|
||||
const page = await editor.getCurrentPage();
|
||||
const allSnippets = allPages
|
||||
.filter((pageMeta) => pageMeta.name.startsWith(snippetPrefix))
|
||||
.map((pageMeta) => ({
|
||||
...pageMeta,
|
||||
name: pageMeta.name.slice(snippetPrefix.length),
|
||||
}));
|
||||
|
||||
let selectedSnippet = await filterBox(
|
||||
const selectedSnippet = await editor.filterBox(
|
||||
"Snippet",
|
||||
allSnippets,
|
||||
`Select the snippet to insert (listing any page starting with <tt>${snippetPrefix}</tt>)`,
|
||||
@@ -83,15 +71,15 @@ export async function insertSnippet() {
|
||||
if (!selectedSnippet) {
|
||||
return;
|
||||
}
|
||||
let { text } = await readPage(`${snippetPrefix}${selectedSnippet.name}`);
|
||||
|
||||
const text = await space.readPage(`${snippetPrefix}${selectedSnippet.name}`);
|
||||
let templateText = replaceTemplateVars(text, page);
|
||||
let carretPos = templateText.indexOf("|^|");
|
||||
const carretPos = templateText.indexOf("|^|");
|
||||
templateText = templateText.replace("|^|", "");
|
||||
templateText = replaceTemplateVars(templateText, page);
|
||||
await insertAtCursor(templateText);
|
||||
await editor.insertAtCursor(templateText);
|
||||
if (carretPos !== -1) {
|
||||
await moveCursor(cursorPos + carretPos);
|
||||
await editor.moveCursor(cursorPos + carretPos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,18 +89,22 @@ export function replaceTemplateVars(s: string, pageName: string): string {
|
||||
switch (v) {
|
||||
case "today":
|
||||
return niceDate(new Date());
|
||||
case "tomorrow":
|
||||
let tomorrow = new Date();
|
||||
case "tomorrow": {
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
return niceDate(tomorrow);
|
||||
case "yesterday":
|
||||
let yesterday = new Date();
|
||||
}
|
||||
|
||||
case "yesterday": {
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
return niceDate(yesterday);
|
||||
case "lastWeek":
|
||||
let lastWeek = new Date();
|
||||
}
|
||||
case "lastWeek": {
|
||||
const lastWeek = new Date();
|
||||
lastWeek.setDate(lastWeek.getDate() - 7);
|
||||
return niceDate(lastWeek);
|
||||
}
|
||||
case "page":
|
||||
return pageName;
|
||||
}
|
||||
@@ -121,55 +113,55 @@ export function replaceTemplateVars(s: string, pageName: string): string {
|
||||
}
|
||||
|
||||
export async function quickNoteCommand() {
|
||||
let { quickNotePrefix } = await readSettings({
|
||||
const { quickNotePrefix } = await readSettings({
|
||||
quickNotePrefix: "📥 ",
|
||||
});
|
||||
let isoDate = new Date().toISOString();
|
||||
const isoDate = new Date().toISOString();
|
||||
let [date, time] = isoDate.split("T");
|
||||
time = time.split(".")[0];
|
||||
let pageName = `${quickNotePrefix}${date} ${time}`;
|
||||
await navigate(pageName);
|
||||
const pageName = `${quickNotePrefix}${date} ${time}`;
|
||||
await editor.navigate(pageName);
|
||||
}
|
||||
|
||||
export async function dailyNoteCommand() {
|
||||
let { dailyNoteTemplate, dailyNotePrefix } = await readSettings({
|
||||
const { dailyNoteTemplate, dailyNotePrefix } = await readSettings({
|
||||
dailyNoteTemplate: "template/page/Daily Note",
|
||||
dailyNotePrefix: "📅 ",
|
||||
});
|
||||
let dailyNoteTemplateText = "";
|
||||
try {
|
||||
let { text } = await readPage(dailyNoteTemplate);
|
||||
const text = await space.readPage(dailyNoteTemplate);
|
||||
dailyNoteTemplateText = text;
|
||||
} catch {
|
||||
console.warn(`No daily note template found at ${dailyNoteTemplate}`);
|
||||
}
|
||||
let date = niceDate(new Date());
|
||||
let pageName = `${dailyNotePrefix}${date}`;
|
||||
const date = niceDate(new Date());
|
||||
const pageName = `${dailyNotePrefix}${date}`;
|
||||
if (dailyNoteTemplateText) {
|
||||
try {
|
||||
await getPageMeta(pageName);
|
||||
await space.getPageMeta(pageName);
|
||||
} catch {
|
||||
// Doesn't exist, let's create
|
||||
await writePage(
|
||||
await space.writePage(
|
||||
pageName,
|
||||
replaceTemplateVars(dailyNoteTemplateText, pageName),
|
||||
);
|
||||
}
|
||||
await navigate(pageName);
|
||||
await editor.navigate(pageName);
|
||||
} else {
|
||||
await navigate(pageName);
|
||||
await editor.navigate(pageName);
|
||||
}
|
||||
}
|
||||
|
||||
export async function insertTemplateText(cmdDef: any) {
|
||||
let cursorPos = await getCursor();
|
||||
let page = await getCurrentPage();
|
||||
const cursorPos = await editor.getCursor();
|
||||
const page = await editor.getCurrentPage();
|
||||
let templateText: string = cmdDef.value;
|
||||
let carretPos = templateText.indexOf("|^|");
|
||||
const carretPos = templateText.indexOf("|^|");
|
||||
templateText = templateText.replace("|^|", "");
|
||||
templateText = replaceTemplateVars(templateText, page);
|
||||
await insertAtCursor(templateText);
|
||||
await editor.insertAtCursor(templateText);
|
||||
if (carretPos !== -1) {
|
||||
await moveCursor(cursorPos + carretPos);
|
||||
await editor.moveCursor(cursorPos + carretPos);
|
||||
}
|
||||
}
|
||||
|
||||
+24
-31
@@ -1,15 +1,8 @@
|
||||
import {
|
||||
getSelection,
|
||||
getText,
|
||||
insertAtCursor,
|
||||
moveCursor,
|
||||
replaceRange,
|
||||
setSelection,
|
||||
} from "$sb/silverbullet-syscall/editor.ts";
|
||||
import { editor } from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
export async function quoteSelection() {
|
||||
let text = await getText();
|
||||
const selection = await getSelection();
|
||||
let text = await editor.getText();
|
||||
const selection = await editor.getSelection();
|
||||
let from = selection.from;
|
||||
while (from >= 0 && text[from] !== "\n") {
|
||||
from--;
|
||||
@@ -23,12 +16,12 @@ export async function quoteSelection() {
|
||||
text = text.slice(from, selection.to);
|
||||
text = `> ${text.replaceAll("\n", "\n> ")}`;
|
||||
}
|
||||
await replaceRange(from, selection.to, text);
|
||||
await editor.replaceRange(from, selection.to, text);
|
||||
}
|
||||
|
||||
export async function listifySelection() {
|
||||
let text = await getText();
|
||||
const selection = await getSelection();
|
||||
let text = await editor.getText();
|
||||
const selection = await editor.getSelection();
|
||||
let from = selection.from;
|
||||
while (from >= 0 && text[from] !== "\n") {
|
||||
from--;
|
||||
@@ -36,12 +29,12 @@ export async function listifySelection() {
|
||||
from++;
|
||||
text = text.slice(from, selection.to);
|
||||
text = `* ${text.replaceAll(/\n(?!\n)/g, "\n* ")}`;
|
||||
await replaceRange(from, selection.to, text);
|
||||
await editor.replaceRange(from, selection.to, text);
|
||||
}
|
||||
|
||||
export async function numberListifySelection() {
|
||||
let text = await getText();
|
||||
const selection = await getSelection();
|
||||
let text = await editor.getText();
|
||||
const selection = await editor.getSelection();
|
||||
let from = selection.from;
|
||||
while (from >= 0 && text[from] !== "\n") {
|
||||
from--;
|
||||
@@ -55,12 +48,12 @@ export async function numberListifySelection() {
|
||||
return `\n${counter}. `;
|
||||
})
|
||||
}`;
|
||||
await replaceRange(from, selection.to, text);
|
||||
await editor.replaceRange(from, selection.to, text);
|
||||
}
|
||||
|
||||
export async function linkSelection() {
|
||||
const text = await getText();
|
||||
const selection = await getSelection();
|
||||
const text = await editor.getText();
|
||||
const selection = await editor.getSelection();
|
||||
const textSelection = text.slice(selection.from, selection.to);
|
||||
let linkedText = `[]()`;
|
||||
let pos = 1;
|
||||
@@ -73,8 +66,8 @@ export async function linkSelection() {
|
||||
pos = linkedText.length - 1;
|
||||
}
|
||||
}
|
||||
await replaceRange(selection.from, selection.to, linkedText);
|
||||
await moveCursor(selection.from + pos);
|
||||
await editor.replaceRange(selection.from, selection.to, linkedText);
|
||||
await editor.moveCursor(selection.from + pos);
|
||||
}
|
||||
|
||||
export function wrapSelection(cmdDef: any) {
|
||||
@@ -82,17 +75,17 @@ export function wrapSelection(cmdDef: any) {
|
||||
}
|
||||
|
||||
async function insertMarker(marker: string) {
|
||||
let text = await getText();
|
||||
const selection = await getSelection();
|
||||
const text = await editor.getText();
|
||||
const selection = await editor.getSelection();
|
||||
if (selection.from === selection.to) {
|
||||
// empty selection
|
||||
if (markerAt(selection.from)) {
|
||||
// Already there, skipping ahead
|
||||
await moveCursor(selection.from + marker.length);
|
||||
await editor.moveCursor(selection.from + marker.length);
|
||||
} else {
|
||||
// Not there, inserting
|
||||
await insertAtCursor(marker + marker);
|
||||
await moveCursor(selection.from + marker.length);
|
||||
await editor.insertAtCursor(marker + marker);
|
||||
await editor.moveCursor(selection.from + marker.length);
|
||||
}
|
||||
} else {
|
||||
let from = selection.from;
|
||||
@@ -107,28 +100,28 @@ async function insertMarker(marker: string) {
|
||||
|
||||
if (!hasMarker) {
|
||||
// Adding
|
||||
await replaceRange(
|
||||
await editor.replaceRange(
|
||||
selection.from,
|
||||
selection.to,
|
||||
marker + text.slice(selection.from, selection.to) + marker,
|
||||
);
|
||||
await setSelection(
|
||||
await editor.setSelection(
|
||||
selection.from + marker.length,
|
||||
selection.to + marker.length,
|
||||
);
|
||||
} else {
|
||||
// Removing
|
||||
await replaceRange(
|
||||
await editor.replaceRange(
|
||||
from,
|
||||
to,
|
||||
text.substring(from + marker.length, to - marker.length),
|
||||
);
|
||||
await setSelection(from, to - marker.length * 2);
|
||||
await editor.setSelection(from, to - marker.length * 2);
|
||||
}
|
||||
}
|
||||
|
||||
function markerAt(pos: number) {
|
||||
for (var i = 0; i < marker.length; i++) {
|
||||
for (let i = 0; i < marker.length; i++) {
|
||||
if (text[pos + i] !== marker[i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user