Refactor all the things
This commit is contained in:
parent
54d2deea15
commit
5ff1a8bae3
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,3 +13,4 @@ node_modules
|
|||||||
*.db
|
*.db
|
||||||
test_space
|
test_space
|
||||||
silverbullet
|
silverbullet
|
||||||
|
.silverbullet.db*
|
@ -1,4 +1,4 @@
|
|||||||
FROM lukechannings/deno:v1.36.1
|
FROM lukechannings/deno:v1.36.3
|
||||||
# The volume that will keep the space data
|
# The volume that will keep the space data
|
||||||
# Create a volume first:
|
# Create a volume first:
|
||||||
# docker volume create myspace
|
# docker volume create myspace
|
||||||
|
@ -38,7 +38,7 @@ export async function runPlug(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (indexFirst) {
|
if (indexFirst) {
|
||||||
await serverSystem.system.loadedPlugs.get("core")!.invoke(
|
await serverSystem.system.loadedPlugs.get("index")!.invoke(
|
||||||
"reindexSpace",
|
"reindexSpace",
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
@ -53,8 +53,8 @@ export async function runPlug(
|
|||||||
}
|
}
|
||||||
const result = await plug.invoke(funcName, args);
|
const result = await plug.invoke(funcName, args);
|
||||||
await serverSystem.close();
|
await serverSystem.close();
|
||||||
await serverSystem.kvStore?.delete();
|
serverSystem.denoKv.close();
|
||||||
// await Deno.remove(tempFile);
|
await Deno.remove(tempFile);
|
||||||
serverController.abort();
|
serverController.abort();
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
|
@ -95,7 +95,7 @@ To allow outside connections, pass -L 0.0.0.0 as a flag, and put a TLS terminato
|
|||||||
system = serverSystem.system;
|
system = serverSystem.system;
|
||||||
if (options.reindex) {
|
if (options.reindex) {
|
||||||
console.log("Reindexing space (requested via --reindex flag)");
|
console.log("Reindexing space (requested via --reindex flag)");
|
||||||
await serverSystem.system.loadedPlugs.get("core")!.invoke(
|
await serverSystem.system.loadedPlugs.get("index")!.invoke(
|
||||||
"reindexSpace",
|
"reindexSpace",
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { syscall } from "$sb/plugos-syscall/syscall.ts";
|
import { syscall } from "$sb/plugos-syscall/syscall.ts";
|
||||||
import { QueueStats } from "$sb/types.ts";
|
import { MQStats } from "$sb/types.ts";
|
||||||
|
|
||||||
export function send(queue: string, body: any) {
|
export function send(queue: string, body: any) {
|
||||||
return syscall("mq.send", queue, body);
|
return syscall("mq.send", queue, body);
|
||||||
@ -17,6 +17,6 @@ export function batchAck(queue: string, ids: string[]) {
|
|||||||
return syscall("mq.batchAck", queue, ids);
|
return syscall("mq.batchAck", queue, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getQueueStats(queue: string): Promise<QueueStats> {
|
export function getQueueStats(queue: string): Promise<MQStats> {
|
||||||
return syscall("mq.getQueueStats", queue);
|
return syscall("mq.getQueueStats", queue);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,11 @@
|
|||||||
import type { CommandDef } from "../../web/hooks/command.ts";
|
import type { CommandDef } from "../../web/hooks/command.ts";
|
||||||
import { syscall } from "./syscall.ts";
|
import { syscall } from "./syscall.ts";
|
||||||
|
|
||||||
export function invoke(
|
|
||||||
name: string,
|
|
||||||
...args: any[]
|
|
||||||
): Promise<any> {
|
|
||||||
return syscall("system.invoke", name, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @deprecated use invoke instead
|
|
||||||
export function invokeFunction(
|
export function invokeFunction(
|
||||||
env: string,
|
|
||||||
name: string,
|
name: string,
|
||||||
...args: any[]
|
...args: any[]
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
return syscall("system.invokeFunction", env, name, ...args);
|
return syscall("system.invokeFunction", name, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only available on the client
|
// Only available on the client
|
||||||
|
2
plug-api/syscalls.ts
Normal file
2
plug-api/syscalls.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "$sb/silverbullet-syscall/mod.ts";
|
||||||
|
export * from "$sb/plugos-syscall/mod.ts";
|
@ -1,16 +1,21 @@
|
|||||||
export type Message = {
|
export type MQMessage = {
|
||||||
id: string;
|
id: string;
|
||||||
queue: string;
|
queue: string;
|
||||||
body: any;
|
body: any;
|
||||||
retries?: number;
|
retries?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type QueueStats = {
|
export type MQStats = {
|
||||||
queued: number;
|
queued: number;
|
||||||
processing: number;
|
processing: number;
|
||||||
dlq: number;
|
dlq: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type MQSubscribeOptions = {
|
||||||
|
batchSize?: number;
|
||||||
|
pollInterval?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type FileMeta = {
|
export type FileMeta = {
|
||||||
name: string;
|
name: string;
|
||||||
lastModified: number;
|
lastModified: number;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Hook, Manifest } from "../types.ts";
|
import { Hook, Manifest } from "../types.ts";
|
||||||
import { System } from "../system.ts";
|
import { System } from "../system.ts";
|
||||||
import { DexieMQ } from "../lib/mq.dexie.ts";
|
|
||||||
import { fullQueueName } from "../lib/mq_util.ts";
|
import { fullQueueName } from "../lib/mq_util.ts";
|
||||||
import { Message } from "$sb/types.ts";
|
import { MQMessage } from "$sb/types.ts";
|
||||||
|
import { MessageQueue } from "../lib/mq.ts";
|
||||||
|
|
||||||
type MQSubscription = {
|
type MQSubscription = {
|
||||||
queue: string;
|
queue: string;
|
||||||
@ -17,7 +17,7 @@ export type MQHookT = {
|
|||||||
export class MQHook implements Hook<MQHookT> {
|
export class MQHook implements Hook<MQHookT> {
|
||||||
subscriptions: (() => void)[] = [];
|
subscriptions: (() => void)[] = [];
|
||||||
|
|
||||||
constructor(private system: System<MQHookT>, readonly mq: DexieMQ) {
|
constructor(private system: System<MQHookT>, readonly mq: MessageQueue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(system: System<MQHookT>): void {
|
apply(system: System<MQHookT>): void {
|
||||||
@ -64,7 +64,7 @@ export class MQHook implements Hook<MQHookT> {
|
|||||||
{
|
{
|
||||||
batchSize: subscriptionDef.batchSize,
|
batchSize: subscriptionDef.batchSize,
|
||||||
},
|
},
|
||||||
async (messages: Message[]) => {
|
async (messages: MQMessage[]) => {
|
||||||
try {
|
try {
|
||||||
await plug.invoke(name, [messages]);
|
await plug.invoke(name, [messages]);
|
||||||
if (subscriptionDef.autoAck) {
|
if (subscriptionDef.autoAck) {
|
||||||
|
@ -2,8 +2,8 @@ import { assertEquals } from "../../test_deps.ts";
|
|||||||
import { DenoKVStore } from "./kv_store.deno_kv.ts";
|
import { DenoKVStore } from "./kv_store.deno_kv.ts";
|
||||||
|
|
||||||
Deno.test("Test KV index", async () => {
|
Deno.test("Test KV index", async () => {
|
||||||
const kv = new DenoKVStore();
|
const denoKv = await Deno.openKv("test.db");
|
||||||
await kv.init("test.db");
|
const kv = new DenoKVStore(denoKv);
|
||||||
|
|
||||||
await kv.set("name", "Peter");
|
await kv.set("name", "Peter");
|
||||||
assertEquals(await kv.get("name"), "Peter");
|
assertEquals(await kv.get("name"), "Peter");
|
||||||
@ -52,5 +52,6 @@ Deno.test("Test KV index", async () => {
|
|||||||
await kv.deletePrefix("");
|
await kv.deletePrefix("");
|
||||||
assertEquals(await kv.queryPrefix(""), []);
|
assertEquals(await kv.queryPrefix(""), []);
|
||||||
|
|
||||||
await kv.delete();
|
denoKv.close();
|
||||||
|
await Deno.remove("test.db");
|
||||||
});
|
});
|
||||||
|
@ -5,23 +5,7 @@ import { KV, KVStore } from "./kv_store.ts";
|
|||||||
const kvBatchSize = 10;
|
const kvBatchSize = 10;
|
||||||
|
|
||||||
export class DenoKVStore implements KVStore {
|
export class DenoKVStore implements KVStore {
|
||||||
kv!: Deno.Kv;
|
constructor(private kv: Deno.Kv) {
|
||||||
path: string | undefined;
|
|
||||||
|
|
||||||
async init(path?: string) {
|
|
||||||
this.path = path;
|
|
||||||
this.kv = await Deno.openKv(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.kv.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
async delete() {
|
|
||||||
this.kv.close();
|
|
||||||
if (this.path) {
|
|
||||||
await Deno.remove(this.path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
del(key: string): Promise<void> {
|
del(key: string): Promise<void> {
|
||||||
|
20
plugos/lib/mq.deno_kv.test.ts
Normal file
20
plugos/lib/mq.deno_kv.test.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { sleep } from "../../common/async_util.ts";
|
||||||
|
import { DenoKvMQ } from "./mq.deno_kv.ts";
|
||||||
|
|
||||||
|
Deno.test("Deno MQ", async () => {
|
||||||
|
const denoKv = await Deno.openKv("test.db");
|
||||||
|
const mq = new DenoKvMQ(denoKv);
|
||||||
|
const unsub = mq.subscribe("test", {}, (messages) => {
|
||||||
|
console.log("Received on test", messages);
|
||||||
|
});
|
||||||
|
const unsub2 = mq.subscribe("test2", {}, (messages) => {
|
||||||
|
console.log("Received on test2", messages);
|
||||||
|
});
|
||||||
|
await mq.send("test", "Hello World");
|
||||||
|
await mq.batchSend("test2", ["Hello World 2", "Hello World 3"]);
|
||||||
|
|
||||||
|
// Let's avoid a panic here
|
||||||
|
await sleep(20);
|
||||||
|
denoKv.close();
|
||||||
|
await Deno.remove("test.db");
|
||||||
|
});
|
87
plugos/lib/mq.deno_kv.ts
Normal file
87
plugos/lib/mq.deno_kv.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/// <reference lib="deno.unstable" />
|
||||||
|
|
||||||
|
import {
|
||||||
|
MQMessage,
|
||||||
|
MQStats,
|
||||||
|
MQSubscribeOptions,
|
||||||
|
} from "../../plug-api/types.ts";
|
||||||
|
import { MessageQueue } from "./mq.ts";
|
||||||
|
|
||||||
|
type QueuedMessage = [string, MQMessage];
|
||||||
|
|
||||||
|
export class DenoKvMQ implements MessageQueue {
|
||||||
|
listeners: Map<string, Set<(messages: MQMessage[]) => void | Promise<void>>> =
|
||||||
|
new Map();
|
||||||
|
|
||||||
|
constructor(private kv: Deno.Kv) {
|
||||||
|
kv.listenQueue(async (message: unknown) => {
|
||||||
|
const [queue, body] = message as QueuedMessage;
|
||||||
|
const listeners = this.listeners.get(queue);
|
||||||
|
if (!listeners) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const listener of listeners) {
|
||||||
|
await Promise.resolve(listener([{ id: "_dummyid", queue, body }]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dummy implementation
|
||||||
|
getQueueStats(_queue: string): Promise<MQStats> {
|
||||||
|
return Promise.resolve({
|
||||||
|
queued: 0,
|
||||||
|
processing: 0,
|
||||||
|
dlq: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dummy implementation
|
||||||
|
getAllQueueStats(): Promise<Record<string, MQStats>> {
|
||||||
|
return Promise.resolve({});
|
||||||
|
}
|
||||||
|
|
||||||
|
async batchSend(queue: string, bodies: any[]): Promise<void> {
|
||||||
|
const results = await Promise.all(
|
||||||
|
bodies.map((body) => this.kv.enqueue([queue, body])),
|
||||||
|
);
|
||||||
|
for (const result of results) {
|
||||||
|
if (!result.ok) {
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async send(queue: string, body: any): Promise<void> {
|
||||||
|
const result = await this.kv.enqueue([queue, body]);
|
||||||
|
if (!result.ok) {
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subscribe(
|
||||||
|
queue: string,
|
||||||
|
_options: MQSubscribeOptions,
|
||||||
|
callback: (messages: MQMessage[]) => void | Promise<void>,
|
||||||
|
): () => void {
|
||||||
|
const listeners = this.listeners.get(queue);
|
||||||
|
if (!listeners) {
|
||||||
|
this.listeners.set(queue, new Set([callback]));
|
||||||
|
} else {
|
||||||
|
listeners.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const listeners = this.listeners.get(queue);
|
||||||
|
if (!listeners) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listeners.delete(callback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ack(_queue: string, _id: string): Promise<void> {
|
||||||
|
// Doesn't apply to this implementation
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
batchAck(_queue: string, _ids: string[]): Promise<void> {
|
||||||
|
// Doesn't apply to this implementation
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,14 @@
|
|||||||
import Dexie, { Table } from "dexie";
|
import Dexie, { Table } from "dexie";
|
||||||
import { Message, QueueStats } from "$sb/types.ts";
|
import { MQMessage, MQStats, MQSubscribeOptions } from "$sb/types.ts";
|
||||||
|
import { MessageQueue } from "./mq.ts";
|
||||||
|
|
||||||
export type ProcessingMessage = Message & {
|
export type ProcessingMessage = MQMessage & {
|
||||||
ts: number;
|
ts: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SubscribeOptions = {
|
export class DexieMQ implements MessageQueue {
|
||||||
batchSize?: number;
|
|
||||||
pollInterval?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class DexieMQ {
|
|
||||||
db: Dexie;
|
db: Dexie;
|
||||||
queued: Table<Message, [string, string]>;
|
queued: Table<MQMessage, [string, string]>;
|
||||||
processing: Table<ProcessingMessage, [string, string]>;
|
processing: Table<ProcessingMessage, [string, string]>;
|
||||||
dlq: Table<ProcessingMessage, [string, string]>;
|
dlq: Table<ProcessingMessage, [string, string]>;
|
||||||
|
|
||||||
@ -63,13 +59,15 @@ export class DexieMQ {
|
|||||||
return this.batchSend(queue, [body]);
|
return this.batchSend(queue, [body]);
|
||||||
}
|
}
|
||||||
|
|
||||||
poll(queue: string, maxItems: number): Promise<Message[]> {
|
poll(queue: string, maxItems: number): Promise<MQMessage[]> {
|
||||||
return this.db.transaction(
|
return this.db.transaction(
|
||||||
"rw",
|
"rw",
|
||||||
[this.queued, this.processing],
|
[this.queued, this.processing],
|
||||||
async (tx) => {
|
async (tx) => {
|
||||||
const messages =
|
const messages =
|
||||||
(await tx.table<Message, [string, string]>("queued").where({ queue })
|
(await tx.table<MQMessage, [string, string]>("queued").where({
|
||||||
|
queue,
|
||||||
|
})
|
||||||
.sortBy("id")).slice(0, maxItems);
|
.sortBy("id")).slice(0, maxItems);
|
||||||
const ids: [string, string][] = messages.map((m) => [queue, m.id]);
|
const ids: [string, string][] = messages.map((m) => [queue, m.id]);
|
||||||
await tx.table("queued").bulkDelete(ids);
|
await tx.table("queued").bulkDelete(ids);
|
||||||
@ -93,8 +91,8 @@ export class DexieMQ {
|
|||||||
*/
|
*/
|
||||||
subscribe(
|
subscribe(
|
||||||
queue: string,
|
queue: string,
|
||||||
options: SubscribeOptions,
|
options: MQSubscribeOptions,
|
||||||
callback: (messages: Message[]) => Promise<void> | void,
|
callback: (messages: MQMessage[]) => Promise<void> | void,
|
||||||
): () => void {
|
): () => void {
|
||||||
let running = true;
|
let running = true;
|
||||||
let timeout: number | undefined;
|
let timeout: number | undefined;
|
||||||
@ -219,7 +217,7 @@ export class DexieMQ {
|
|||||||
return this.dlq.clear();
|
return this.dlq.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
getQueueStats(queue: string): Promise<QueueStats> {
|
getQueueStats(queue: string): Promise<MQStats> {
|
||||||
return this.db.transaction(
|
return this.db.transaction(
|
||||||
"r",
|
"r",
|
||||||
[this.queued, this.processing, this.dlq],
|
[this.queued, this.processing, this.dlq],
|
||||||
@ -237,8 +235,8 @@ export class DexieMQ {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllQueueStats(): Promise<Record<string, QueueStats>> {
|
async getAllQueueStats(): Promise<Record<string, MQStats>> {
|
||||||
const allStatus: Record<string, QueueStats> = {};
|
const allStatus: Record<string, MQStats> = {};
|
||||||
await this.db.transaction(
|
await this.db.transaction(
|
||||||
"r",
|
"r",
|
||||||
[this.queued, this.processing, this.dlq],
|
[this.queued, this.processing, this.dlq],
|
||||||
|
16
plugos/lib/mq.ts
Normal file
16
plugos/lib/mq.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { MQMessage, MQStats, MQSubscribeOptions } from "$sb/types.ts";
|
||||||
|
|
||||||
|
export interface MessageQueue {
|
||||||
|
batchSend(queue: string, bodies: any[]): Promise<void>;
|
||||||
|
send(queue: string, body: any): Promise<void>;
|
||||||
|
subscribe(
|
||||||
|
queue: string,
|
||||||
|
options: MQSubscribeOptions,
|
||||||
|
callback: (messages: MQMessage[]) => Promise<void> | void,
|
||||||
|
): () => void;
|
||||||
|
ack(queue: string, id: string): Promise<void>;
|
||||||
|
batchAck(queue: string, ids: string[]): Promise<void>;
|
||||||
|
|
||||||
|
getQueueStats(queue: string): Promise<MQStats>;
|
||||||
|
getAllQueueStats(): Promise<Record<string, MQStats>>;
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import { SysCallMapping } from "../system.ts";
|
import { SysCallMapping } from "../system.ts";
|
||||||
import { DexieMQ } from "../lib/mq.dexie.ts";
|
|
||||||
import { fullQueueName } from "../lib/mq_util.ts";
|
import { fullQueueName } from "../lib/mq_util.ts";
|
||||||
|
import { MessageQueue } from "../lib/mq.ts";
|
||||||
|
|
||||||
export function mqSyscalls(
|
export function mqSyscalls(
|
||||||
mq: DexieMQ,
|
mq: MessageQueue,
|
||||||
): SysCallMapping {
|
): SysCallMapping {
|
||||||
return {
|
return {
|
||||||
"mq.send": (ctx, queue: string, body: any) => {
|
"mq.send": (ctx, queue: string, body: any) => {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
// TODO: Figure out how to keep this up-to-date automatically
|
// TODO: Figure out how to keep this up-to-date automatically
|
||||||
export const builtinPlugNames = [
|
export const builtinPlugNames = [
|
||||||
"core",
|
"editor",
|
||||||
|
"index",
|
||||||
|
"sync",
|
||||||
|
"template",
|
||||||
|
"plug-manager",
|
||||||
"directive",
|
"directive",
|
||||||
"emoji",
|
"emoji",
|
||||||
"markdown",
|
"markdown",
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
import { renderToText, replaceNodesMatching } from "$sb/lib/tree.ts";
|
|
||||||
import { parseMarkdown } from "$sb/silverbullet-syscall/markdown.ts";
|
|
||||||
import { FileMeta } from "$sb/types.ts";
|
|
||||||
|
|
||||||
export const cloudPrefix = "💭 ";
|
|
||||||
|
|
||||||
export async function readFileCloud(
|
|
||||||
name: string,
|
|
||||||
): Promise<{ data: Uint8Array; meta: FileMeta } | undefined> {
|
|
||||||
const originalUrl = name.substring(
|
|
||||||
cloudPrefix.length,
|
|
||||||
name.length - ".md".length,
|
|
||||||
);
|
|
||||||
let url = originalUrl;
|
|
||||||
if (!url.includes("/")) {
|
|
||||||
url += "/index";
|
|
||||||
}
|
|
||||||
if (!url.startsWith("127.0.0.1")) {
|
|
||||||
url = `https://${url}`;
|
|
||||||
} else {
|
|
||||||
url = `http://${url}`;
|
|
||||||
}
|
|
||||||
let text = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
const r = await fetch(`${encodeURI(url)}.md`);
|
|
||||||
text = await r.text();
|
|
||||||
if (!r.ok) {
|
|
||||||
text = `ERROR: ${text}`;
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
|
||||||
console.error("ERROR thrown", e.message);
|
|
||||||
text = `ERROR: ${e.message}`;
|
|
||||||
}
|
|
||||||
text = await translateLinksWithPrefix(
|
|
||||||
text,
|
|
||||||
`${cloudPrefix}${originalUrl.split("/")[0]}/`,
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
data: new TextEncoder().encode(text),
|
|
||||||
meta: {
|
|
||||||
name,
|
|
||||||
contentType: "text/markdown",
|
|
||||||
lastModified: 0,
|
|
||||||
size: text.length,
|
|
||||||
perm: "ro",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function writeFileCloud(
|
|
||||||
name: string,
|
|
||||||
): Promise<FileMeta> {
|
|
||||||
console.log("Writing cloud file", name);
|
|
||||||
return getFileMetaCloud(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function translateLinksWithPrefix(
|
|
||||||
text: string,
|
|
||||||
prefix: string,
|
|
||||||
): Promise<string> {
|
|
||||||
const tree = await parseMarkdown(text);
|
|
||||||
replaceNodesMatching(tree, (tree) => {
|
|
||||||
if (tree.type === "WikiLinkPage") {
|
|
||||||
// Add the prefix in the link text
|
|
||||||
if (!tree.children![0].text!.startsWith(cloudPrefix)) {
|
|
||||||
// Only for links that aren't already cloud links
|
|
||||||
tree.children![0].text = prefix + tree.children![0].text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
text = renderToText(tree);
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFileMetaCloud(name: string): Promise<FileMeta> {
|
|
||||||
return Promise.resolve({
|
|
||||||
name,
|
|
||||||
size: 0,
|
|
||||||
contentType: "text/markdown",
|
|
||||||
lastModified: 0,
|
|
||||||
perm: "ro",
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,515 +0,0 @@
|
|||||||
name: core
|
|
||||||
requiredPermissions:
|
|
||||||
- fetch
|
|
||||||
syntax:
|
|
||||||
Hashtag:
|
|
||||||
firstCharacters:
|
|
||||||
- "#"
|
|
||||||
regex: "#[^#\\d\\s\\[\\]]+\\w+"
|
|
||||||
className: sb-hashtag
|
|
||||||
NakedURL:
|
|
||||||
firstCharacters:
|
|
||||||
- "h"
|
|
||||||
regex: "https?:\\/\\/[-a-zA-Z0-9@:%._\\+~#=]{1,256}([-a-zA-Z0-9()@:%_\\+.~#?&=\\/]*)"
|
|
||||||
className: sb-naked-url
|
|
||||||
NamedAnchor:
|
|
||||||
firstCharacters:
|
|
||||||
- "$"
|
|
||||||
regex: "\\$[a-zA-Z\\.\\-\\/]+[\\w\\.\\-\\/]*"
|
|
||||||
className: sb-named-anchor
|
|
||||||
functions:
|
|
||||||
setEditorMode:
|
|
||||||
path: "./editor.ts:setEditorMode"
|
|
||||||
events:
|
|
||||||
- editor:init
|
|
||||||
toggleDarkMode:
|
|
||||||
path: "./editor.ts:toggleDarkMode"
|
|
||||||
command:
|
|
||||||
name: "Editor: Toggle Dark Mode"
|
|
||||||
centerCursor:
|
|
||||||
path: "./editor.ts:centerCursorCommand"
|
|
||||||
command:
|
|
||||||
name: "Editor: Center Cursor"
|
|
||||||
key: "Ctrl-Alt-l"
|
|
||||||
moveToPos:
|
|
||||||
path: "./editor.ts:moveToPosCommand"
|
|
||||||
command:
|
|
||||||
name: "Editor: Move Cursor to Position"
|
|
||||||
clearPageIndex:
|
|
||||||
path: "./page.ts:clearPageIndex"
|
|
||||||
env: server
|
|
||||||
events:
|
|
||||||
- page:saved
|
|
||||||
- page:deleted
|
|
||||||
pageQueryProvider:
|
|
||||||
path: ./page.ts:pageQueryProvider
|
|
||||||
events:
|
|
||||||
- query:page
|
|
||||||
parseIndexTextRepublish:
|
|
||||||
path: "./page.ts:parseIndexTextRepublish"
|
|
||||||
env: server
|
|
||||||
events:
|
|
||||||
- page:index_text
|
|
||||||
reindexSpaceCommand:
|
|
||||||
path: "./page.ts:reindexCommand"
|
|
||||||
command:
|
|
||||||
name: "Space: Reindex"
|
|
||||||
processIndexQueue:
|
|
||||||
path: ./page.ts:processIndexQueue
|
|
||||||
mqSubscriptions:
|
|
||||||
- queue: indexQueue
|
|
||||||
batchSize: 10
|
|
||||||
autoAck: true
|
|
||||||
reindexSpace:
|
|
||||||
path: "./page.ts:reindexSpace"
|
|
||||||
deletePage:
|
|
||||||
path: "./page.ts:deletePage"
|
|
||||||
command:
|
|
||||||
name: "Page: Delete"
|
|
||||||
copyPage:
|
|
||||||
path: "./page.ts:copyPage"
|
|
||||||
command:
|
|
||||||
name: "Page: Copy"
|
|
||||||
|
|
||||||
syncSpaceCommand:
|
|
||||||
path: "./sync.ts:syncSpaceCommand"
|
|
||||||
command:
|
|
||||||
name: "Sync: Now"
|
|
||||||
key: "Alt-Shift-s"
|
|
||||||
mac: "Cmd-Shift-s"
|
|
||||||
|
|
||||||
# Attachments
|
|
||||||
attachmentQueryProvider:
|
|
||||||
path: ./attachment.ts:attachmentQueryProvider
|
|
||||||
events:
|
|
||||||
- query:attachment
|
|
||||||
|
|
||||||
# Backlinks
|
|
||||||
indexLinks:
|
|
||||||
path: "./page_links.ts:indexLinks"
|
|
||||||
events:
|
|
||||||
- page:index
|
|
||||||
linkQueryProvider:
|
|
||||||
path: ./page_links.ts:linkQueryProvider
|
|
||||||
events:
|
|
||||||
- query:link
|
|
||||||
|
|
||||||
pageComplete:
|
|
||||||
path: "./page.ts:pageComplete"
|
|
||||||
events:
|
|
||||||
- editor:complete
|
|
||||||
|
|
||||||
attributeComplete:
|
|
||||||
path: "./attributes.ts:attributeComplete"
|
|
||||||
events:
|
|
||||||
- editor:complete
|
|
||||||
|
|
||||||
customAttributeCompleter:
|
|
||||||
path: ./attributes.ts:customAttributeCompleter
|
|
||||||
events:
|
|
||||||
- attribute:complete:page
|
|
||||||
- attribute:complete:task
|
|
||||||
- attribute:complete:item
|
|
||||||
- attribute:complete:*
|
|
||||||
|
|
||||||
builtinAttributeCompleter:
|
|
||||||
path: ./attributes.ts:builtinAttributeCompleter
|
|
||||||
events:
|
|
||||||
- attribute:complete:page
|
|
||||||
- attribute:complete:task
|
|
||||||
- attribute:complete:item
|
|
||||||
- attribute:complete:*
|
|
||||||
|
|
||||||
# Commands
|
|
||||||
commandComplete:
|
|
||||||
path: "./command.ts:commandComplete"
|
|
||||||
events:
|
|
||||||
- editor:complete
|
|
||||||
|
|
||||||
# Item indexing
|
|
||||||
indexItem:
|
|
||||||
path: "./item.ts:indexItems"
|
|
||||||
events:
|
|
||||||
- page:index
|
|
||||||
itemQueryProvider:
|
|
||||||
path: "./item.ts:queryProvider"
|
|
||||||
events:
|
|
||||||
- query:item
|
|
||||||
|
|
||||||
# Navigation
|
|
||||||
linkNavigate:
|
|
||||||
path: "./navigate.ts:linkNavigate"
|
|
||||||
command:
|
|
||||||
name: Navigate To page
|
|
||||||
key: Ctrl-Enter
|
|
||||||
mac: Cmd-Enter
|
|
||||||
clickNavigate:
|
|
||||||
path: "./navigate.ts:clickNavigate"
|
|
||||||
events:
|
|
||||||
- page:click
|
|
||||||
navigateHome:
|
|
||||||
path: "./navigate.ts:navigateCommand"
|
|
||||||
command:
|
|
||||||
name: "Navigate: Home"
|
|
||||||
key: "Alt-h"
|
|
||||||
page: ""
|
|
||||||
|
|
||||||
# Hashtags
|
|
||||||
indexTags:
|
|
||||||
path: "./tags.ts:indexTags"
|
|
||||||
events:
|
|
||||||
- page:index
|
|
||||||
tagComplete:
|
|
||||||
path: "./tags.ts:tagComplete"
|
|
||||||
events:
|
|
||||||
- editor:complete
|
|
||||||
tagProvider:
|
|
||||||
path: "./tags.ts:tagProvider"
|
|
||||||
events:
|
|
||||||
- query:tag
|
|
||||||
|
|
||||||
# Anchors
|
|
||||||
indexAnchors:
|
|
||||||
path: "./anchor.ts:indexAnchors"
|
|
||||||
events:
|
|
||||||
- page:index
|
|
||||||
anchorComplete:
|
|
||||||
path: "./anchor.ts:anchorComplete"
|
|
||||||
events:
|
|
||||||
- editor:complete
|
|
||||||
|
|
||||||
# Template commands
|
|
||||||
insertTemplateText:
|
|
||||||
path: "./template.ts:insertTemplateText"
|
|
||||||
applyLineReplace:
|
|
||||||
path: ./template.ts:applyLineReplace
|
|
||||||
insertFrontMatter:
|
|
||||||
redirect: insertTemplateText
|
|
||||||
slashCommand:
|
|
||||||
name: front-matter
|
|
||||||
description: Insert page front matter
|
|
||||||
value: |
|
|
||||||
---
|
|
||||||
|^|
|
|
||||||
---
|
|
||||||
makeH1:
|
|
||||||
redirect: applyLineReplace
|
|
||||||
slashCommand:
|
|
||||||
name: h1
|
|
||||||
description: Turn line into h1 header
|
|
||||||
match: "^#*\\s*"
|
|
||||||
replace: "# "
|
|
||||||
makeH2:
|
|
||||||
redirect: applyLineReplace
|
|
||||||
slashCommand:
|
|
||||||
name: h2
|
|
||||||
description: Turn line into h2 header
|
|
||||||
match: "^#*\\s*"
|
|
||||||
replace: "## "
|
|
||||||
makeH3:
|
|
||||||
redirect: applyLineReplace
|
|
||||||
slashCommand:
|
|
||||||
name: h3
|
|
||||||
description: Turn line into h3 header
|
|
||||||
match: "^#*\\s*"
|
|
||||||
replace: "### "
|
|
||||||
makeH4:
|
|
||||||
redirect: applyLineReplace
|
|
||||||
slashCommand:
|
|
||||||
name: h4
|
|
||||||
description: Turn line into h4 header
|
|
||||||
match: "^#*\\s*"
|
|
||||||
replace: "#### "
|
|
||||||
insertCodeBlock:
|
|
||||||
redirect: insertTemplateText
|
|
||||||
slashCommand:
|
|
||||||
name: code
|
|
||||||
description: Insert code block
|
|
||||||
value: |
|
|
||||||
```
|
|
||||||
|^|
|
|
||||||
```
|
|
||||||
|
|
||||||
newPage:
|
|
||||||
path: ./page.ts:newPageCommand
|
|
||||||
command:
|
|
||||||
name: "Page: New"
|
|
||||||
key: "Alt-Shift-n"
|
|
||||||
|
|
||||||
insertHRTemplate:
|
|
||||||
redirect: insertTemplateText
|
|
||||||
slashCommand:
|
|
||||||
name: hr
|
|
||||||
description: Insert a horizontal rule
|
|
||||||
value: "---"
|
|
||||||
insertTable:
|
|
||||||
redirect: insertTemplateText
|
|
||||||
slashCommand:
|
|
||||||
name: table
|
|
||||||
description: Insert a table
|
|
||||||
boost: -1 # Low boost because it's likely not very commonly used
|
|
||||||
value: |
|
|
||||||
| Header A | Header B |
|
|
||||||
|----------|----------|
|
|
||||||
| Cell A|^| | Cell B |
|
|
||||||
quickNoteCommand:
|
|
||||||
path: ./template.ts:quickNoteCommand
|
|
||||||
command:
|
|
||||||
name: "Quick Note"
|
|
||||||
key: "Alt-Shift-n"
|
|
||||||
priority: 1
|
|
||||||
dailyNoteCommand:
|
|
||||||
path: ./template.ts:dailyNoteCommand
|
|
||||||
command:
|
|
||||||
name: "Open Daily Note"
|
|
||||||
key: "Alt-Shift-d"
|
|
||||||
weeklyNoteCommand:
|
|
||||||
path: ./template.ts:weeklyNoteCommand
|
|
||||||
command:
|
|
||||||
name: "Open Weekly Note"
|
|
||||||
key: "Alt-Shift-w"
|
|
||||||
|
|
||||||
instantiateTemplateCommand:
|
|
||||||
path: ./template.ts:instantiateTemplateCommand
|
|
||||||
command:
|
|
||||||
name: "Template: Instantiate Page"
|
|
||||||
insertSnippet:
|
|
||||||
path: ./template.ts:insertSnippet
|
|
||||||
command:
|
|
||||||
name: "Template: Insert Snippet"
|
|
||||||
slashCommand:
|
|
||||||
name: snippet
|
|
||||||
description: Insert a snippet
|
|
||||||
applyPageTemplateCommand:
|
|
||||||
path: ./template.ts:applyPageTemplateCommand
|
|
||||||
slashCommand:
|
|
||||||
name: page-template
|
|
||||||
description: Apply a page template
|
|
||||||
insertTodayCommand:
|
|
||||||
path: "./template.ts:insertTemplateText"
|
|
||||||
slashCommand:
|
|
||||||
name: today
|
|
||||||
description: Insert today's date
|
|
||||||
value: "{{today}}"
|
|
||||||
insertTomorrowCommand:
|
|
||||||
path: "./template.ts:insertTemplateText"
|
|
||||||
slashCommand:
|
|
||||||
name: tomorrow
|
|
||||||
description: Insert tomorrow's date
|
|
||||||
value: "{{tomorrow}}"
|
|
||||||
|
|
||||||
# Text editing commands
|
|
||||||
quoteSelectionCommand:
|
|
||||||
path: ./text.ts:quoteSelection
|
|
||||||
command:
|
|
||||||
name: "Text: Quote Selection"
|
|
||||||
key: "Ctrl-Shift-."
|
|
||||||
mac: "Cmd-Shift-."
|
|
||||||
listifySelection:
|
|
||||||
path: ./text.ts:listifySelection
|
|
||||||
command:
|
|
||||||
name: "Text: Listify Selection"
|
|
||||||
key: "Ctrl-Shift-8"
|
|
||||||
mac: "Cmd-Shift-8"
|
|
||||||
numberListifySelection:
|
|
||||||
path: ./text.ts:numberListifySelection
|
|
||||||
command:
|
|
||||||
name: "Text: Number Listify Selection"
|
|
||||||
linkSelection:
|
|
||||||
path: ./text.ts:linkSelection
|
|
||||||
command:
|
|
||||||
name: "Text: Link Selection"
|
|
||||||
key: "Ctrl-Shift-k"
|
|
||||||
mac: "Cmd-Shift-k"
|
|
||||||
bold:
|
|
||||||
path: ./text.ts:wrapSelection
|
|
||||||
command:
|
|
||||||
name: "Text: Bold"
|
|
||||||
key: "Ctrl-b"
|
|
||||||
mac: "Cmd-b"
|
|
||||||
wrapper: "**"
|
|
||||||
italic:
|
|
||||||
path: ./text.ts:wrapSelection
|
|
||||||
command:
|
|
||||||
name: "Text: Italic"
|
|
||||||
key: "Ctrl-i"
|
|
||||||
mac: "Cmd-i"
|
|
||||||
wrapper: "_"
|
|
||||||
strikethrough:
|
|
||||||
path: ./text.ts:wrapSelection
|
|
||||||
command:
|
|
||||||
name: "Text: Strikethrough"
|
|
||||||
key: "Ctrl-Shift-s"
|
|
||||||
mac: "Cmd-Shift-s"
|
|
||||||
wrapper: "~~"
|
|
||||||
marker:
|
|
||||||
path: ./text.ts:wrapSelection
|
|
||||||
command:
|
|
||||||
name: "Text: Marker"
|
|
||||||
key: "Alt-m"
|
|
||||||
wrapper: "=="
|
|
||||||
|
|
||||||
# Refactoring Commands
|
|
||||||
extractToPageCommand:
|
|
||||||
path: ./refactor.ts:extractToPageCommand
|
|
||||||
command:
|
|
||||||
name: "Page: Extract"
|
|
||||||
renamePageCommand:
|
|
||||||
path: "./refactor.ts:renamePageCommand"
|
|
||||||
command:
|
|
||||||
name: "Page: Rename"
|
|
||||||
mac: Cmd-Alt-r
|
|
||||||
key: Ctrl-Alt-r
|
|
||||||
page: ""
|
|
||||||
renamePrefixCommand:
|
|
||||||
path: "./refactor.ts:renamePrefixCommand"
|
|
||||||
command:
|
|
||||||
name: "Page: Batch Rename Prefix"
|
|
||||||
|
|
||||||
# Plug manager
|
|
||||||
updatePlugsCommand:
|
|
||||||
path: ./plugmanager.ts:updatePlugsCommand
|
|
||||||
command:
|
|
||||||
name: "Plugs: Update"
|
|
||||||
key: "Ctrl-Shift-p"
|
|
||||||
mac: "Cmd-Shift-p"
|
|
||||||
getPlugHTTPS:
|
|
||||||
path: "./plugmanager.ts:getPlugHTTPS"
|
|
||||||
events:
|
|
||||||
- get-plug:https
|
|
||||||
getPlugGithub:
|
|
||||||
path: "./plugmanager.ts:getPlugGithub"
|
|
||||||
events:
|
|
||||||
- get-plug:github
|
|
||||||
getPlugGithubRelease:
|
|
||||||
path: "./plugmanager.ts:getPlugGithubRelease"
|
|
||||||
events:
|
|
||||||
- get-plug:ghr
|
|
||||||
addPlugCommand:
|
|
||||||
path: ./plugmanager.ts:addPlugCommand
|
|
||||||
command:
|
|
||||||
name: "Plugs: Add"
|
|
||||||
|
|
||||||
# Debug commands
|
|
||||||
parseCommand:
|
|
||||||
path: ./debug.ts:parsePageCommand
|
|
||||||
command:
|
|
||||||
name: "Debug: Parse Document"
|
|
||||||
|
|
||||||
reloadUICommand:
|
|
||||||
path: ./debug.ts:reloadUICommand
|
|
||||||
command:
|
|
||||||
name: "Debug: Reload UI"
|
|
||||||
|
|
||||||
resetClientCommand:
|
|
||||||
path: ./debug.ts:resetClientCommand
|
|
||||||
command:
|
|
||||||
name: "Debug: Reset Client"
|
|
||||||
|
|
||||||
versionCommand:
|
|
||||||
path: ./help.ts:versionCommand
|
|
||||||
command:
|
|
||||||
name: "Help: Version"
|
|
||||||
gettingStartedCommand:
|
|
||||||
path: ./help.ts:gettingStartedCommand
|
|
||||||
command:
|
|
||||||
name: "Help: Getting Started"
|
|
||||||
|
|
||||||
accountLogoutCommand:
|
|
||||||
path: ./account.ts:accountLogoutCommand
|
|
||||||
command:
|
|
||||||
name: "Account: Logout"
|
|
||||||
|
|
||||||
# Link unfurl infrastructure
|
|
||||||
unfurlLink:
|
|
||||||
path: ./link.ts:unfurlCommand
|
|
||||||
command:
|
|
||||||
name: "Link: Unfurl"
|
|
||||||
key: "Ctrl-Shift-u"
|
|
||||||
mac: "Cmd-Shift-u"
|
|
||||||
contexts:
|
|
||||||
- NakedURL
|
|
||||||
|
|
||||||
# Title-based link unfurl
|
|
||||||
titleUnfurlOptions:
|
|
||||||
path: ./link.ts:titleUnfurlOptions
|
|
||||||
events:
|
|
||||||
- unfurl:options
|
|
||||||
titleUnfurl:
|
|
||||||
path: ./link.ts:titleUnfurl
|
|
||||||
events:
|
|
||||||
- unfurl:title-unfurl
|
|
||||||
|
|
||||||
embedWidget:
|
|
||||||
path: ./embed.ts:embedWidget
|
|
||||||
codeWidget: embed
|
|
||||||
|
|
||||||
# Folding commands
|
|
||||||
foldCommand:
|
|
||||||
path: ./editor.ts:foldCommand
|
|
||||||
command:
|
|
||||||
name: "Fold: Fold"
|
|
||||||
mac: "Cmd-Alt-["
|
|
||||||
key: "Ctrl-Shift-["
|
|
||||||
unfoldCommand:
|
|
||||||
path: ./editor.ts:unfoldCommand
|
|
||||||
command:
|
|
||||||
name: "Fold: Unfold"
|
|
||||||
mac: "Cmd-Alt-]"
|
|
||||||
key: "Ctrl-Shift-]"
|
|
||||||
toggleFoldCommand:
|
|
||||||
path: ./editor.ts:toggleFoldCommand
|
|
||||||
command:
|
|
||||||
name: "Fold: Toggle Fold"
|
|
||||||
mac: "Cmd-Alt-f"
|
|
||||||
key: "Ctrl-Alt-f"
|
|
||||||
foldAllCommand:
|
|
||||||
path: ./editor.ts:foldAllCommand
|
|
||||||
command:
|
|
||||||
name: "Fold: Fold All"
|
|
||||||
key: "Ctrl-Alt-["
|
|
||||||
unfoldAllCommand:
|
|
||||||
path: ./editor.ts:unfoldAllCommand
|
|
||||||
command:
|
|
||||||
name: "Fold: Unfold All"
|
|
||||||
key: "Ctrl-Alt-]"
|
|
||||||
|
|
||||||
# Random stuff
|
|
||||||
statsCommand:
|
|
||||||
path: ./stats.ts:statsCommand
|
|
||||||
command:
|
|
||||||
name: "Stats: Show"
|
|
||||||
|
|
||||||
# Cloud pages
|
|
||||||
readPageCloud:
|
|
||||||
path: ./cloud.ts:readFileCloud
|
|
||||||
pageNamespace:
|
|
||||||
pattern: "💭 .+"
|
|
||||||
operation: readFile
|
|
||||||
writePageCloud:
|
|
||||||
path: ./cloud.ts:writeFileCloud
|
|
||||||
pageNamespace:
|
|
||||||
pattern: "💭 .+"
|
|
||||||
operation: writeFile
|
|
||||||
getPageMetaCloud:
|
|
||||||
path: ./cloud.ts:getFileMetaCloud
|
|
||||||
pageNamespace:
|
|
||||||
pattern: "💭 .+"
|
|
||||||
operation: getFileMeta
|
|
||||||
|
|
||||||
# Vim
|
|
||||||
toggleVimMode:
|
|
||||||
path: "./vim.ts:toggleVimMode"
|
|
||||||
command:
|
|
||||||
name: "Editor: Toggle Vim Mode"
|
|
||||||
loadVimRc:
|
|
||||||
path: "./vim.ts:loadVimRc"
|
|
||||||
command:
|
|
||||||
name: "Editor: Vim: Load VIMRC"
|
|
||||||
events:
|
|
||||||
- editor:modeswitch
|
|
||||||
|
|
||||||
brokenLinksCommand:
|
|
||||||
path: ./broken_links.ts:brokenLinksCommand
|
|
||||||
command:
|
|
||||||
name: "Broken Links: Show"
|
|
@ -1,4 +1,4 @@
|
|||||||
import { editor, markdown, space, sync } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, markdown, mq, space, sync } from "$sb/syscalls.ts";
|
||||||
import {
|
import {
|
||||||
ParseTree,
|
ParseTree,
|
||||||
removeParentPointers,
|
removeParentPointers,
|
||||||
@ -7,10 +7,9 @@ import {
|
|||||||
} from "$sb/lib/tree.ts";
|
} from "$sb/lib/tree.ts";
|
||||||
import { renderDirectives } from "./directives.ts";
|
import { renderDirectives } from "./directives.ts";
|
||||||
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||||
import { PageMeta } from "../../web/types.ts";
|
import type { PageMeta } from "../../web/types.ts";
|
||||||
import { isFederationPath } from "$sb/lib/resolve.ts";
|
import { isFederationPath } from "$sb/lib/resolve.ts";
|
||||||
import { mq } from "$sb/plugos-syscall/mod.ts";
|
import { MQMessage } from "$sb/types.ts";
|
||||||
import { Message } from "$sb/types.ts";
|
|
||||||
import { sleep } from "../../common/async_util.ts";
|
import { sleep } from "../../common/async_util.ts";
|
||||||
|
|
||||||
const directiveUpdateQueueName = "directiveUpdateQueue";
|
const directiveUpdateQueueName = "directiveUpdateQueue";
|
||||||
@ -92,7 +91,7 @@ export async function updateDirectivesInSpaceCommand() {
|
|||||||
await editor.flashNotification("Updating of all directives completed!");
|
await editor.flashNotification("Updating of all directives completed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function processUpdateQueue(messages: Message[]) {
|
export async function processUpdateQueue(messages: MQMessage[]) {
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
const pageName: string = message.body;
|
const pageName: string = message.body;
|
||||||
console.log("Updating directives in page", pageName);
|
console.log("Updating directives in page", pageName);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
import { events } from "$sb/syscalls.ts";
|
||||||
import { CompleteEvent } from "$sb/app_event.ts";
|
import { CompleteEvent } from "$sb/app_event.ts";
|
||||||
import { buildHandebarOptions } from "./util.ts";
|
import { buildHandebarOptions } from "./util.ts";
|
||||||
import type { PageMeta } from "../../web/types.ts";
|
import type { PageMeta } from "../../web/types.ts";
|
||||||
import {
|
import type {
|
||||||
AttributeCompleteEvent,
|
AttributeCompleteEvent,
|
||||||
AttributeCompletion,
|
AttributeCompletion,
|
||||||
} from "../core/attributes.ts";
|
} from "../index/attributes.ts";
|
||||||
|
|
||||||
export async function queryComplete(completeEvent: CompleteEvent) {
|
export async function queryComplete(completeEvent: CompleteEvent) {
|
||||||
const querySourceMatch = /#query\s+([\w\-_]*)$/.exec(
|
const querySourceMatch = /#query\s+([\w\-_]*)$/.exec(
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
// data:page@pos
|
// data:page@pos
|
||||||
|
|
||||||
import type { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
import type { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||||
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
import { index, YAML } from "$sb/syscalls.ts";
|
||||||
import { collectNodesOfType, findNodeOfType } from "$sb/lib/tree.ts";
|
import { collectNodesOfType, findNodeOfType } from "$sb/lib/tree.ts";
|
||||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||||
import { YAML } from "$sb/plugos-syscall/mod.ts";
|
|
||||||
|
|
||||||
export async function indexData({ name, tree }: IndexTreeEvent) {
|
export async function indexData({ name, tree }: IndexTreeEvent) {
|
||||||
const dataObjects: { key: string; value: any }[] = [];
|
const dataObjects: { key: string; value: any }[] = [];
|
||||||
|
@ -39,7 +39,7 @@ functions:
|
|||||||
|
|
||||||
# Templates
|
# Templates
|
||||||
insertQuery:
|
insertQuery:
|
||||||
redirect: core.insertTemplateText
|
redirect: template.insertTemplateText
|
||||||
slashCommand:
|
slashCommand:
|
||||||
name: query
|
name: query
|
||||||
description: Insert a query
|
description: Insert a query
|
||||||
@ -48,7 +48,7 @@ functions:
|
|||||||
|
|
||||||
<!-- /query -->
|
<!-- /query -->
|
||||||
insertInclude:
|
insertInclude:
|
||||||
redirect: core.insertTemplateText
|
redirect: template.insertTemplateText
|
||||||
slashCommand:
|
slashCommand:
|
||||||
name: include
|
name: include
|
||||||
description: Include another page
|
description: Include another page
|
||||||
@ -57,7 +57,7 @@ functions:
|
|||||||
|
|
||||||
<!-- /include -->
|
<!-- /include -->
|
||||||
insertUseTemplate:
|
insertUseTemplate:
|
||||||
redirect: core.insertTemplateText
|
redirect: template.insertTemplateText
|
||||||
slashCommand:
|
slashCommand:
|
||||||
name: use
|
name: use
|
||||||
description: Use a template
|
description: Use a template
|
||||||
@ -66,7 +66,7 @@ functions:
|
|||||||
|
|
||||||
<!-- /use -->
|
<!-- /use -->
|
||||||
insertUseVerboseTemplate:
|
insertUseVerboseTemplate:
|
||||||
redirect: core.insertTemplateText
|
redirect: template.insertTemplateText
|
||||||
slashCommand:
|
slashCommand:
|
||||||
name: use-verbose
|
name: use-verbose
|
||||||
description: Use a template (verbose mode)
|
description: Use a template (verbose mode)
|
||||||
@ -75,7 +75,7 @@ functions:
|
|||||||
|
|
||||||
<!-- /use-verbose -->
|
<!-- /use-verbose -->
|
||||||
insertEvalTemplate:
|
insertEvalTemplate:
|
||||||
redirect: core.insertTemplateText
|
redirect: template.insertTemplateText
|
||||||
slashCommand:
|
slashCommand:
|
||||||
name: eval
|
name: eval
|
||||||
description: Evaluate a JavaScript expression
|
description: Evaluate a JavaScript expression
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// This is some shocking stuff. My profession would kill me for this.
|
// This is some shocking stuff. My profession would kill me for this.
|
||||||
|
|
||||||
import { YAML } from "$sb/plugos-syscall/mod.ts";
|
import { YAML } from "$sb/syscalls.ts";
|
||||||
import { ParseTree } from "$sb/lib/tree.ts";
|
import { ParseTree } from "$sb/lib/tree.ts";
|
||||||
import { jsonToMDTable, renderTemplate } from "./util.ts";
|
import { jsonToMDTable, renderTemplate } from "./util.ts";
|
||||||
import { PageMeta } from "../../web/types.ts";
|
import type { PageMeta } from "../../web/types.ts";
|
||||||
import { replaceTemplateVars } from "../core/template.ts";
|
import { replaceTemplateVars } from "../template/template.ts";
|
||||||
|
|
||||||
// Enables plugName.functionName(arg1, arg2) syntax in JS expressions
|
// Enables plugName.functionName(arg1, arg2) syntax in JS expressions
|
||||||
function translateJs(js: string): string {
|
function translateJs(js: string): string {
|
||||||
@ -44,7 +44,7 @@ export async function evalDirectiveRenderer(
|
|||||||
const result = await (0, eval)(
|
const result = await (0, eval)(
|
||||||
`(async () => {
|
`(async () => {
|
||||||
function invokeFunction(name, ...args) {
|
function invokeFunction(name, ...args) {
|
||||||
return syscall("system.invoke", name, ...args);
|
return syscall("system.invokeFunction", name, ...args);
|
||||||
}
|
}
|
||||||
return ${replaceTemplateVars(translateJs(expression), pageMeta)};
|
return ${replaceTemplateVars(translateJs(expression), pageMeta)};
|
||||||
})()`,
|
})()`,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
import { events } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
import { replaceTemplateVars } from "../core/template.ts";
|
import { replaceTemplateVars } from "../template/template.ts";
|
||||||
import { renderTemplate } from "./util.ts";
|
import { renderTemplate } from "./util.ts";
|
||||||
import { parseQuery } from "./parser.ts";
|
import { parseQuery } from "./parser.ts";
|
||||||
import { jsonToMDTable } from "./util.ts";
|
import { jsonToMDTable } from "./util.ts";
|
||||||
import { ParseTree } from "$sb/lib/tree.ts";
|
import { ParseTree } from "$sb/lib/tree.ts";
|
||||||
import { PageMeta } from "../../web/types.ts";
|
import type { PageMeta } from "../../web/types.ts";
|
||||||
|
|
||||||
export async function queryDirectiveRenderer(
|
export async function queryDirectiveRenderer(
|
||||||
_directive: string,
|
_directive: string,
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
import { queryRegex } from "$sb/lib/query.ts";
|
import { queryRegex } from "$sb/lib/query.ts";
|
||||||
import {
|
import { ParseTree, renderToText } from "$sb/lib/tree.ts";
|
||||||
findNodeOfType,
|
import { markdown, space } from "$sb/syscalls.ts";
|
||||||
ParseTree,
|
|
||||||
renderToText,
|
|
||||||
traverseTree,
|
|
||||||
} from "$sb/lib/tree.ts";
|
|
||||||
import { markdown, space } from "$sb/silverbullet-syscall/mod.ts";
|
|
||||||
import Handlebars from "handlebars";
|
import Handlebars from "handlebars";
|
||||||
|
|
||||||
import { replaceTemplateVars } from "../core/template.ts";
|
import { replaceTemplateVars } from "../template/template.ts";
|
||||||
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||||
import { directiveRegex } from "./directives.ts";
|
import { directiveRegex } from "./directives.ts";
|
||||||
import { updateDirectives } from "./command.ts";
|
import { updateDirectives } from "./command.ts";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Handlebars from "handlebars";
|
import Handlebars from "handlebars";
|
||||||
|
|
||||||
import { space } from "$sb/silverbullet-syscall/mod.ts";
|
import { space } from "$sb/syscalls.ts";
|
||||||
import { PageMeta } from "../../web/types.ts";
|
import type { PageMeta } from "../../web/types.ts";
|
||||||
import { handlebarHelpers } from "./handlebar_helpers.ts";
|
import { handlebarHelpers } from "./handlebar_helpers.ts";
|
||||||
|
|
||||||
const maxWidth = 70;
|
const maxWidth = 70;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { editor } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
export async function accountLogoutCommand() {
|
export async function accountLogoutCommand() {
|
||||||
await editor.openUrl("/.client/logout.html", true);
|
await editor.openUrl("/.client/logout.html", true);
|
@ -1,9 +1,5 @@
|
|||||||
import { traverseTree } from "../../plug-api/lib/tree.ts";
|
import { traverseTree } from "../../plug-api/lib/tree.ts";
|
||||||
import {
|
import { editor, markdown, space } from "$sb/syscalls.ts";
|
||||||
editor,
|
|
||||||
markdown,
|
|
||||||
space,
|
|
||||||
} from "../../plug-api/silverbullet-syscall/mod.ts";
|
|
||||||
|
|
||||||
export async function brokenLinksCommand() {
|
export async function brokenLinksCommand() {
|
||||||
const pageName = "BROKEN LINKS";
|
const pageName = "BROKEN LINKS";
|
7
plugs/editor/client.ts
Normal file
7
plugs/editor/client.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { editor } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
|
export async function setThinClient(def: any) {
|
||||||
|
console.log("Setting thin client to", def.value);
|
||||||
|
await editor.setUiOption("thinClientMode", def.value);
|
||||||
|
await editor.reloadUI();
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { system } from "$sb/silverbullet-syscall/mod.ts";
|
import { system } from "$sb/syscalls.ts";
|
||||||
import { CompleteEvent } from "../../plug-api/app_event.ts";
|
import { CompleteEvent } from "$sb/app_event.ts";
|
||||||
|
|
||||||
export async function commandComplete(completeEvent: CompleteEvent) {
|
export async function commandComplete(completeEvent: CompleteEvent) {
|
||||||
const match = /\{\[([^\]]*)$/.exec(completeEvent.linePrefix);
|
const match = /\{\[([^\]]*)$/.exec(completeEvent.linePrefix);
|
@ -1,4 +1,4 @@
|
|||||||
import { debug, editor, markdown } from "$sb/silverbullet-syscall/mod.ts";
|
import { debug, editor, markdown } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
export async function parsePageCommand() {
|
export async function parsePageCommand() {
|
||||||
console.log(
|
console.log(
|
240
plugs/editor/editor.plug.yaml
Normal file
240
plugs/editor/editor.plug.yaml
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
name: editor
|
||||||
|
requiredPermissions:
|
||||||
|
- fetch
|
||||||
|
syntax:
|
||||||
|
NakedURL:
|
||||||
|
firstCharacters:
|
||||||
|
- "h"
|
||||||
|
regex: "https?:\\/\\/[-a-zA-Z0-9@:%._\\+~#=]{1,256}([-a-zA-Z0-9()@:%_\\+.~#?&=\\/]*)"
|
||||||
|
className: sb-naked-url
|
||||||
|
functions:
|
||||||
|
setEditorMode:
|
||||||
|
path: "./editor.ts:setEditorMode"
|
||||||
|
events:
|
||||||
|
- editor:init
|
||||||
|
toggleDarkMode:
|
||||||
|
path: "./editor.ts:toggleDarkMode"
|
||||||
|
command:
|
||||||
|
name: "Editor: Toggle Dark Mode"
|
||||||
|
|
||||||
|
# Page operations
|
||||||
|
deletePage:
|
||||||
|
path: "./page.ts:deletePage"
|
||||||
|
command:
|
||||||
|
name: "Page: Delete"
|
||||||
|
copyPage:
|
||||||
|
path: "./page.ts:copyPage"
|
||||||
|
command:
|
||||||
|
name: "Page: Copy"
|
||||||
|
newPage:
|
||||||
|
path: ./page.ts:newPageCommand
|
||||||
|
command:
|
||||||
|
name: "Page: New"
|
||||||
|
key: "Alt-Shift-n"
|
||||||
|
|
||||||
|
# Completion
|
||||||
|
pageComplete:
|
||||||
|
path: "./page.ts:pageComplete"
|
||||||
|
events:
|
||||||
|
- editor:complete
|
||||||
|
commandComplete:
|
||||||
|
path: "./command.ts:commandComplete"
|
||||||
|
events:
|
||||||
|
- editor:complete
|
||||||
|
|
||||||
|
# Navigation
|
||||||
|
linkNavigate:
|
||||||
|
path: "./navigate.ts:linkNavigate"
|
||||||
|
command:
|
||||||
|
name: Navigate To page
|
||||||
|
key: Ctrl-Enter
|
||||||
|
mac: Cmd-Enter
|
||||||
|
clickNavigate:
|
||||||
|
path: "./navigate.ts:clickNavigate"
|
||||||
|
events:
|
||||||
|
- page:click
|
||||||
|
navigateHome:
|
||||||
|
path: "./navigate.ts:navigateCommand"
|
||||||
|
command:
|
||||||
|
name: "Navigate: Home"
|
||||||
|
key: "Alt-h"
|
||||||
|
page: ""
|
||||||
|
|
||||||
|
# Text editing commands
|
||||||
|
quoteSelectionCommand:
|
||||||
|
path: ./text.ts:quoteSelection
|
||||||
|
command:
|
||||||
|
name: "Text: Quote Selection"
|
||||||
|
key: "Ctrl-Shift-."
|
||||||
|
mac: "Cmd-Shift-."
|
||||||
|
listifySelection:
|
||||||
|
path: ./text.ts:listifySelection
|
||||||
|
command:
|
||||||
|
name: "Text: Listify Selection"
|
||||||
|
key: "Ctrl-Shift-8"
|
||||||
|
mac: "Cmd-Shift-8"
|
||||||
|
numberListifySelection:
|
||||||
|
path: ./text.ts:numberListifySelection
|
||||||
|
command:
|
||||||
|
name: "Text: Number Listify Selection"
|
||||||
|
linkSelection:
|
||||||
|
path: ./text.ts:linkSelection
|
||||||
|
command:
|
||||||
|
name: "Text: Link Selection"
|
||||||
|
key: "Ctrl-Shift-k"
|
||||||
|
mac: "Cmd-Shift-k"
|
||||||
|
bold:
|
||||||
|
path: ./text.ts:wrapSelection
|
||||||
|
command:
|
||||||
|
name: "Text: Bold"
|
||||||
|
key: "Ctrl-b"
|
||||||
|
mac: "Cmd-b"
|
||||||
|
wrapper: "**"
|
||||||
|
italic:
|
||||||
|
path: ./text.ts:wrapSelection
|
||||||
|
command:
|
||||||
|
name: "Text: Italic"
|
||||||
|
key: "Ctrl-i"
|
||||||
|
mac: "Cmd-i"
|
||||||
|
wrapper: "_"
|
||||||
|
strikethrough:
|
||||||
|
path: ./text.ts:wrapSelection
|
||||||
|
command:
|
||||||
|
name: "Text: Strikethrough"
|
||||||
|
key: "Ctrl-Shift-s"
|
||||||
|
mac: "Cmd-Shift-s"
|
||||||
|
wrapper: "~~"
|
||||||
|
marker:
|
||||||
|
path: ./text.ts:wrapSelection
|
||||||
|
command:
|
||||||
|
name: "Text: Marker"
|
||||||
|
key: "Alt-m"
|
||||||
|
wrapper: "=="
|
||||||
|
centerCursor:
|
||||||
|
path: "./editor.ts:centerCursorCommand"
|
||||||
|
command:
|
||||||
|
name: "Editor: Center Cursor"
|
||||||
|
key: "Ctrl-Alt-l"
|
||||||
|
moveToPos:
|
||||||
|
path: "./editor.ts:moveToPosCommand"
|
||||||
|
command:
|
||||||
|
name: "Editor: Move Cursor to Position"
|
||||||
|
|
||||||
|
# Debug commands
|
||||||
|
parseCommand:
|
||||||
|
path: ./debug.ts:parsePageCommand
|
||||||
|
command:
|
||||||
|
name: "Debug: Parse Document"
|
||||||
|
|
||||||
|
# Link unfurl infrastructure
|
||||||
|
unfurlLink:
|
||||||
|
path: ./link.ts:unfurlCommand
|
||||||
|
command:
|
||||||
|
name: "Link: Unfurl"
|
||||||
|
key: "Ctrl-Shift-u"
|
||||||
|
mac: "Cmd-Shift-u"
|
||||||
|
contexts:
|
||||||
|
- NakedURL
|
||||||
|
|
||||||
|
# Title-based link unfurl
|
||||||
|
titleUnfurlOptions:
|
||||||
|
path: ./link.ts:titleUnfurlOptions
|
||||||
|
events:
|
||||||
|
- unfurl:options
|
||||||
|
titleUnfurl:
|
||||||
|
path: ./link.ts:titleUnfurl
|
||||||
|
events:
|
||||||
|
- unfurl:title-unfurl
|
||||||
|
|
||||||
|
embedWidget:
|
||||||
|
path: ./embed.ts:embedWidget
|
||||||
|
codeWidget: embed
|
||||||
|
|
||||||
|
# Folding commands
|
||||||
|
foldCommand:
|
||||||
|
path: ./editor.ts:foldCommand
|
||||||
|
command:
|
||||||
|
name: "Fold: Fold"
|
||||||
|
mac: "Cmd-Alt-["
|
||||||
|
key: "Ctrl-Shift-["
|
||||||
|
unfoldCommand:
|
||||||
|
path: ./editor.ts:unfoldCommand
|
||||||
|
command:
|
||||||
|
name: "Fold: Unfold"
|
||||||
|
mac: "Cmd-Alt-]"
|
||||||
|
key: "Ctrl-Shift-]"
|
||||||
|
toggleFoldCommand:
|
||||||
|
path: ./editor.ts:toggleFoldCommand
|
||||||
|
command:
|
||||||
|
name: "Fold: Toggle Fold"
|
||||||
|
mac: "Cmd-Alt-f"
|
||||||
|
key: "Ctrl-Alt-f"
|
||||||
|
foldAllCommand:
|
||||||
|
path: ./editor.ts:foldAllCommand
|
||||||
|
command:
|
||||||
|
name: "Fold: Fold All"
|
||||||
|
key: "Ctrl-Alt-["
|
||||||
|
unfoldAllCommand:
|
||||||
|
path: ./editor.ts:unfoldAllCommand
|
||||||
|
command:
|
||||||
|
name: "Fold: Unfold All"
|
||||||
|
key: "Ctrl-Alt-]"
|
||||||
|
|
||||||
|
# Vim
|
||||||
|
toggleVimMode:
|
||||||
|
path: "./vim.ts:toggleVimMode"
|
||||||
|
command:
|
||||||
|
name: "Editor: Toggle Vim Mode"
|
||||||
|
loadVimRc:
|
||||||
|
path: "./vim.ts:loadVimRc"
|
||||||
|
command:
|
||||||
|
name: "Editor: Vim: Load VIMRC"
|
||||||
|
events:
|
||||||
|
- editor:modeswitch
|
||||||
|
|
||||||
|
brokenLinksCommand:
|
||||||
|
path: ./broken_links.ts:brokenLinksCommand
|
||||||
|
command:
|
||||||
|
name: "Broken Links: Show"
|
||||||
|
|
||||||
|
# Client mode
|
||||||
|
enableThinClient:
|
||||||
|
path: ./client.ts:setThinClient
|
||||||
|
command:
|
||||||
|
name: "Client: Enable Thin Client"
|
||||||
|
value: true
|
||||||
|
disableThinClient:
|
||||||
|
path: ./client.ts:setThinClient
|
||||||
|
command:
|
||||||
|
name: "Client: Disable Thin Client"
|
||||||
|
value: false
|
||||||
|
|
||||||
|
# Random stuff
|
||||||
|
statsCommand:
|
||||||
|
path: ./stats.ts:statsCommand
|
||||||
|
command:
|
||||||
|
name: "Stats: Show"
|
||||||
|
reloadUICommand:
|
||||||
|
path: ./debug.ts:reloadUICommand
|
||||||
|
command:
|
||||||
|
name: "Debug: Reload UI"
|
||||||
|
|
||||||
|
resetClientCommand:
|
||||||
|
path: ./debug.ts:resetClientCommand
|
||||||
|
command:
|
||||||
|
name: "Debug: Reset Client"
|
||||||
|
|
||||||
|
versionCommand:
|
||||||
|
path: ./help.ts:versionCommand
|
||||||
|
command:
|
||||||
|
name: "Help: Version"
|
||||||
|
gettingStartedCommand:
|
||||||
|
path: ./help.ts:gettingStartedCommand
|
||||||
|
command:
|
||||||
|
name: "Help: Getting Started"
|
||||||
|
|
||||||
|
accountLogoutCommand:
|
||||||
|
path: ./account.ts:accountLogoutCommand
|
||||||
|
command:
|
||||||
|
name: "Account: Logout"
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
import { clientStore, editor } from "$sb/silverbullet-syscall/mod.ts";
|
import { clientStore, editor } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
// Run on "editor:init"
|
// Run on "editor:init"
|
||||||
export async function setEditorMode() {
|
export async function setEditorMode() {
|
@ -1,4 +1,4 @@
|
|||||||
import { YAML } from "$sb/plugos-syscall/mod.ts";
|
import { YAML } from "$sb/syscalls.ts";
|
||||||
import type { WidgetContent } from "$sb/app_event.ts";
|
import type { WidgetContent } from "$sb/app_event.ts";
|
||||||
|
|
||||||
type EmbedConfig = {
|
type EmbedConfig = {
|
@ -1,4 +1,4 @@
|
|||||||
import { editor } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor } from "$sb/syscalls.ts";
|
||||||
import { version } from "../../version.ts";
|
import { version } from "../../version.ts";
|
||||||
|
|
||||||
export async function versionCommand() {
|
export async function versionCommand() {
|
@ -1,6 +1,5 @@
|
|||||||
import { nodeAtPos } from "$sb/lib/tree.ts";
|
import { nodeAtPos } from "$sb/lib/tree.ts";
|
||||||
import { editor, markdown } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, events, markdown } from "$sb/syscalls.ts";
|
||||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
|
||||||
|
|
||||||
type UnfurlOption = {
|
type UnfurlOption = {
|
||||||
id: string;
|
id: string;
|
@ -1,5 +1,5 @@
|
|||||||
import type { ClickEvent } from "$sb/app_event.ts";
|
import type { ClickEvent } from "$sb/app_event.ts";
|
||||||
import { editor, markdown, system } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, markdown, system } from "$sb/syscalls.ts";
|
||||||
import {
|
import {
|
||||||
addParentPointers,
|
addParentPointers,
|
||||||
findNodeOfType,
|
findNodeOfType,
|
@ -1,33 +1,9 @@
|
|||||||
import type {
|
import type { CompleteEvent } from "$sb/app_event.ts";
|
||||||
CompleteEvent,
|
import { editor, space } from "$sb/syscalls.ts";
|
||||||
IndexEvent,
|
|
||||||
QueryProviderEvent,
|
|
||||||
} from "$sb/app_event.ts";
|
|
||||||
import {
|
|
||||||
editor,
|
|
||||||
index,
|
|
||||||
markdown,
|
|
||||||
space,
|
|
||||||
} from "$sb/silverbullet-syscall/mod.ts";
|
|
||||||
|
|
||||||
import { events, mq } from "$sb/plugos-syscall/mod.ts";
|
|
||||||
|
|
||||||
import { applyQuery } from "$sb/lib/query.ts";
|
|
||||||
import { invoke } from "$sb/silverbullet-syscall/system.ts";
|
|
||||||
import type { Message } from "$sb/types.ts";
|
|
||||||
import { sleep } from "../../common/async_util.ts";
|
|
||||||
import { cacheFileListing } from "../federation/federation.ts";
|
import { cacheFileListing } from "../federation/federation.ts";
|
||||||
import type { PageMeta } from "../../web/types.ts";
|
import type { PageMeta } from "../../web/types.ts";
|
||||||
|
|
||||||
// Key space:
|
|
||||||
// meta: => metaJson
|
|
||||||
|
|
||||||
export async function pageQueryProvider({
|
|
||||||
query,
|
|
||||||
}: QueryProviderEvent): Promise<any[]> {
|
|
||||||
return applyQuery(query, await space.listPages());
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deletePage() {
|
export async function deletePage() {
|
||||||
const pageName = await editor.getCurrentPage();
|
const pageName = await editor.getCurrentPage();
|
||||||
if (
|
if (
|
||||||
@ -85,12 +61,6 @@ export async function newPageCommand() {
|
|||||||
await editor.navigate(pageName);
|
await editor.navigate(pageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function reindexCommand() {
|
|
||||||
await editor.flashNotification("Performing full page reindex...");
|
|
||||||
await reindexSpace();
|
|
||||||
await editor.flashNotification("Done with page index!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Completion
|
// Completion
|
||||||
export async function pageComplete(completeEvent: CompleteEvent) {
|
export async function pageComplete(completeEvent: CompleteEvent) {
|
||||||
const match = /\[\[([^\]@:\{}]*)$/.exec(completeEvent.linePrefix);
|
const match = /\[\[([^\]@:\{}]*)$/.exec(completeEvent.linePrefix);
|
||||||
@ -130,51 +100,3 @@ export async function pageComplete(completeEvent: CompleteEvent) {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function reindexSpace() {
|
|
||||||
console.log("Clearing page index...");
|
|
||||||
await index.clearPageIndex();
|
|
||||||
// Executed this way to not have to embed the search plug code here
|
|
||||||
await invoke("search.clearIndex");
|
|
||||||
const pages = await space.listPages();
|
|
||||||
|
|
||||||
// Queue all page names to be indexed
|
|
||||||
await mq.batchSend("indexQueue", pages.map((page) => page.name));
|
|
||||||
|
|
||||||
// Now let's wait for the processing to finish
|
|
||||||
let queueStats = await mq.getQueueStats("indexQueue");
|
|
||||||
while (queueStats.queued > 0 || queueStats.processing > 0) {
|
|
||||||
sleep(1000);
|
|
||||||
queueStats = await mq.getQueueStats("indexQueue");
|
|
||||||
}
|
|
||||||
// And notify the user
|
|
||||||
console.log("Indexing completed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function processIndexQueue(messages: Message[]) {
|
|
||||||
for (const message of messages) {
|
|
||||||
const name: string = message.body;
|
|
||||||
console.log(`Indexing page ${name}`);
|
|
||||||
const text = await space.readPage(name);
|
|
||||||
// console.log("Going to parse markdown");
|
|
||||||
const parsed = await markdown.parseMarkdown(text);
|
|
||||||
// console.log("Dispatching ;age:index");
|
|
||||||
await events.dispatchEvent("page:index", {
|
|
||||||
name,
|
|
||||||
tree: parsed,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function clearPageIndex(page: string) {
|
|
||||||
// console.log("Clearing page index for page", page);
|
|
||||||
await index.clearPageIndexForPage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
|
|
||||||
console.log("Reindexing", name);
|
|
||||||
await events.dispatchEvent("page:index", {
|
|
||||||
name,
|
|
||||||
tree: await markdown.parseMarkdown(text),
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { editor, space } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, space } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
function countWords(str: string): number {
|
function countWords(str: string): number {
|
||||||
const matches = str.match(/[\w\d\'-]+/gi);
|
const matches = str.match(/[\w\d\'-]+/gi);
|
@ -1,4 +1,4 @@
|
|||||||
import { editor } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
export async function quoteSelection() {
|
export async function quoteSelection() {
|
||||||
let text = await editor.getText();
|
let text = await editor.getText();
|
@ -1,6 +1,5 @@
|
|||||||
import { readCodeBlockPage } from "../../plug-api/lib/yaml_page.ts";
|
import { readCodeBlockPage } from "$sb/lib/yaml_page.ts";
|
||||||
import { editor } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, store } from "$sb/syscalls.ts";
|
||||||
import { store } from "$sb/plugos-syscall/mod.ts";
|
|
||||||
|
|
||||||
export async function toggleVimMode() {
|
export async function toggleVimMode() {
|
||||||
let vimMode = await store.get("vimMode");
|
let vimMode = await store.get("vimMode");
|
@ -1,5 +1,5 @@
|
|||||||
import emojis from "./emoji.json" assert { type: "json" };
|
import emojis from "./emoji.json" assert { type: "json" };
|
||||||
import type { CompleteEvent } from "../../plug-api/app_event.ts";
|
import type { CompleteEvent } from "$sb/app_event.ts";
|
||||||
|
|
||||||
export function emojiCompleter({ linePrefix, pos }: CompleteEvent) {
|
export function emojiCompleter({ linePrefix, pos }: CompleteEvent) {
|
||||||
const match = /:([\w]+)$/.exec(linePrefix);
|
const match = /:([\w]+)$/.exec(linePrefix);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import "$sb/lib/fetch.ts";
|
import "$sb/lib/fetch.ts";
|
||||||
import { federatedPathToUrl } from "$sb/lib/resolve.ts";
|
import { federatedPathToUrl } from "$sb/lib/resolve.ts";
|
||||||
import { readFederationConfigs } from "./config.ts";
|
import { readFederationConfigs } from "./config.ts";
|
||||||
import { store } from "$sb/plugos-syscall/mod.ts";
|
import { store } from "$sb/syscalls.ts";
|
||||||
import { FileMeta } from "$sb/types.ts";
|
import type { FileMeta } from "$sb/types.ts";
|
||||||
|
|
||||||
async function responseToFileMeta(
|
async function responseToFileMeta(
|
||||||
r: Response,
|
r: Response,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
||||||
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
import { index } from "$sb/syscalls.ts";
|
||||||
import type { CompleteEvent, IndexTreeEvent } from "$sb/app_event.ts";
|
import type { CompleteEvent, IndexTreeEvent } from "$sb/app_event.ts";
|
||||||
import { removeQueries } from "$sb/lib/query.ts";
|
import { removeQueries } from "$sb/lib/query.ts";
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
import { QueryProviderEvent } from "$sb/app_event.ts";
|
import { QueryProviderEvent } from "$sb/app_event.ts";
|
||||||
import { applyQuery } from "$sb/lib/query.ts";
|
import { applyQuery } from "$sb/lib/query.ts";
|
||||||
import { space } from "$sb/silverbullet-syscall/mod.ts";
|
import { space } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
export async function attachmentQueryProvider({ query }: QueryProviderEvent) {
|
export async function attachmentQueryProvider({ query }: QueryProviderEvent) {
|
||||||
return applyQuery(query, await space.listAttachments());
|
return applyQuery(query, await space.listAttachments());
|
@ -1,6 +1,6 @@
|
|||||||
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
||||||
import type { CompleteEvent } from "$sb/app_event.ts";
|
import type { CompleteEvent } from "$sb/app_event.ts";
|
||||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
import { events } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
export type AttributeContext = "page" | "item" | "task";
|
export type AttributeContext = "page" | "item" | "task";
|
||||||
|
|
133
plugs/index/index.plug.yaml
Normal file
133
plugs/index/index.plug.yaml
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
name: index
|
||||||
|
syntax:
|
||||||
|
Hashtag:
|
||||||
|
firstCharacters:
|
||||||
|
- "#"
|
||||||
|
regex: "#[^#\\d\\s\\[\\]]+\\w+"
|
||||||
|
className: sb-hashtag
|
||||||
|
NamedAnchor:
|
||||||
|
firstCharacters:
|
||||||
|
- "$"
|
||||||
|
regex: "\\$[a-zA-Z\\.\\-\\/]+[\\w\\.\\-\\/]*"
|
||||||
|
className: sb-named-anchor
|
||||||
|
functions:
|
||||||
|
clearPageIndex:
|
||||||
|
path: "./page.ts:clearPageIndex"
|
||||||
|
env: server
|
||||||
|
events:
|
||||||
|
- page:saved
|
||||||
|
- page:deleted
|
||||||
|
pageQueryProvider:
|
||||||
|
path: ./page.ts:pageQueryProvider
|
||||||
|
events:
|
||||||
|
- query:page
|
||||||
|
parseIndexTextRepublish:
|
||||||
|
path: "./page.ts:parseIndexTextRepublish"
|
||||||
|
env: server
|
||||||
|
events:
|
||||||
|
- page:index_text
|
||||||
|
reindexSpaceCommand:
|
||||||
|
path: "./page.ts:reindexCommand"
|
||||||
|
command:
|
||||||
|
name: "Space: Reindex"
|
||||||
|
processIndexQueue:
|
||||||
|
path: ./page.ts:processIndexQueue
|
||||||
|
mqSubscriptions:
|
||||||
|
- queue: indexQueue
|
||||||
|
batchSize: 10
|
||||||
|
autoAck: true
|
||||||
|
reindexSpace:
|
||||||
|
path: "./page.ts:reindexSpace"
|
||||||
|
|
||||||
|
# Attachments
|
||||||
|
attachmentQueryProvider:
|
||||||
|
path: ./attachment.ts:attachmentQueryProvider
|
||||||
|
events:
|
||||||
|
- query:attachment
|
||||||
|
|
||||||
|
# Backlinks
|
||||||
|
indexLinks:
|
||||||
|
path: "./page_links.ts:indexLinks"
|
||||||
|
events:
|
||||||
|
- page:index
|
||||||
|
linkQueryProvider:
|
||||||
|
path: ./page_links.ts:linkQueryProvider
|
||||||
|
events:
|
||||||
|
- query:link
|
||||||
|
|
||||||
|
attributeComplete:
|
||||||
|
path: "./attributes.ts:attributeComplete"
|
||||||
|
events:
|
||||||
|
- editor:complete
|
||||||
|
|
||||||
|
customAttributeCompleter:
|
||||||
|
path: ./attributes.ts:customAttributeCompleter
|
||||||
|
events:
|
||||||
|
- attribute:complete:page
|
||||||
|
- attribute:complete:task
|
||||||
|
- attribute:complete:item
|
||||||
|
- attribute:complete:*
|
||||||
|
|
||||||
|
builtinAttributeCompleter:
|
||||||
|
path: ./attributes.ts:builtinAttributeCompleter
|
||||||
|
events:
|
||||||
|
- attribute:complete:page
|
||||||
|
- attribute:complete:task
|
||||||
|
- attribute:complete:item
|
||||||
|
- attribute:complete:*
|
||||||
|
|
||||||
|
# Item indexing
|
||||||
|
indexItem:
|
||||||
|
path: "./item.ts:indexItems"
|
||||||
|
events:
|
||||||
|
- page:index
|
||||||
|
itemQueryProvider:
|
||||||
|
path: "./item.ts:queryProvider"
|
||||||
|
events:
|
||||||
|
- query:item
|
||||||
|
|
||||||
|
# Anchors
|
||||||
|
indexAnchors:
|
||||||
|
path: "./anchor.ts:indexAnchors"
|
||||||
|
events:
|
||||||
|
- page:index
|
||||||
|
anchorComplete:
|
||||||
|
path: "./anchor.ts:anchorComplete"
|
||||||
|
events:
|
||||||
|
- editor:complete
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Hashtags
|
||||||
|
indexTags:
|
||||||
|
path: "./tags.ts:indexTags"
|
||||||
|
events:
|
||||||
|
- page:index
|
||||||
|
tagComplete:
|
||||||
|
path: "./tags.ts:tagComplete"
|
||||||
|
events:
|
||||||
|
- editor:complete
|
||||||
|
tagProvider:
|
||||||
|
path: "./tags.ts:tagProvider"
|
||||||
|
events:
|
||||||
|
- query:tag
|
||||||
|
|
||||||
|
renamePageCommand:
|
||||||
|
path: "./refactor.ts:renamePageCommand"
|
||||||
|
command:
|
||||||
|
name: "Page: Rename"
|
||||||
|
mac: Cmd-Alt-r
|
||||||
|
key: Ctrl-Alt-r
|
||||||
|
page: ""
|
||||||
|
renamePrefixCommand:
|
||||||
|
path: "./refactor.ts:renamePrefixCommand"
|
||||||
|
command:
|
||||||
|
name: "Page: Batch Rename Prefix"
|
||||||
|
|
||||||
|
# Refactoring Commands
|
||||||
|
extractToPageCommand:
|
||||||
|
path: ./refactor.ts:extractToPageCommand
|
||||||
|
command:
|
||||||
|
name: "Page: Extract"
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
import type { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
import type { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||||
|
|
||||||
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
import { index } from "$sb/syscalls.ts";
|
||||||
import { collectNodesOfType, ParseTree, renderToText } from "$sb/lib/tree.ts";
|
import { collectNodesOfType, ParseTree, renderToText } from "$sb/lib/tree.ts";
|
||||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
77
plugs/index/page.ts
Normal file
77
plugs/index/page.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import type { IndexEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||||
|
import {
|
||||||
|
editor,
|
||||||
|
events,
|
||||||
|
index,
|
||||||
|
markdown,
|
||||||
|
mq,
|
||||||
|
space,
|
||||||
|
system,
|
||||||
|
} from "$sb/syscalls.ts";
|
||||||
|
|
||||||
|
import { applyQuery } from "$sb/lib/query.ts";
|
||||||
|
import type { MQMessage } from "$sb/types.ts";
|
||||||
|
import { sleep } from "../../common/async_util.ts";
|
||||||
|
|
||||||
|
// Key space:
|
||||||
|
// meta: => metaJson
|
||||||
|
|
||||||
|
export async function pageQueryProvider({
|
||||||
|
query,
|
||||||
|
}: QueryProviderEvent): Promise<any[]> {
|
||||||
|
return applyQuery(query, await space.listPages());
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function reindexCommand() {
|
||||||
|
await editor.flashNotification("Performing full page reindex...");
|
||||||
|
await reindexSpace();
|
||||||
|
await editor.flashNotification("Done with page index!");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function reindexSpace() {
|
||||||
|
console.log("Clearing page index...");
|
||||||
|
await index.clearPageIndex();
|
||||||
|
// Executed this way to not have to embed the search plug code here
|
||||||
|
await system.invokeFunction("search.clearIndex");
|
||||||
|
const pages = await space.listPages();
|
||||||
|
|
||||||
|
// Queue all page names to be indexed
|
||||||
|
await mq.batchSend("indexQueue", pages.map((page) => page.name));
|
||||||
|
|
||||||
|
// Now let's wait for the processing to finish
|
||||||
|
let queueStats = await mq.getQueueStats("indexQueue");
|
||||||
|
while (queueStats.queued > 0 || queueStats.processing > 0) {
|
||||||
|
sleep(1000);
|
||||||
|
queueStats = await mq.getQueueStats("indexQueue");
|
||||||
|
}
|
||||||
|
// And notify the user
|
||||||
|
console.log("Indexing completed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function processIndexQueue(messages: MQMessage[]) {
|
||||||
|
for (const message of messages) {
|
||||||
|
const name: string = message.body;
|
||||||
|
console.log(`Indexing page ${name}`);
|
||||||
|
const text = await space.readPage(name);
|
||||||
|
// console.log("Going to parse markdown");
|
||||||
|
const parsed = await markdown.parseMarkdown(text);
|
||||||
|
// console.log("Dispatching ;age:index");
|
||||||
|
await events.dispatchEvent("page:index", {
|
||||||
|
name,
|
||||||
|
tree: parsed,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function clearPageIndex(page: string) {
|
||||||
|
// console.log("Clearing page index for page", page);
|
||||||
|
await index.clearPageIndexForPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
|
||||||
|
console.log("Reindexing", name);
|
||||||
|
await events.dispatchEvent("page:index", {
|
||||||
|
name,
|
||||||
|
tree: await markdown.parseMarkdown(text),
|
||||||
|
});
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
import { index } from "$sb/syscalls.ts";
|
||||||
import { findNodeOfType, traverseTree } from "$sb/lib/tree.ts";
|
import { findNodeOfType, traverseTree } from "$sb/lib/tree.ts";
|
||||||
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
@ -1,4 +1,4 @@
|
|||||||
import { editor, space } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, space } from "$sb/syscalls.ts";
|
||||||
import { validatePageName } from "$sb/lib/page.ts";
|
import { validatePageName } from "$sb/lib/page.ts";
|
||||||
import { getBackLinks } from "./page_links.ts";
|
import { getBackLinks } from "./page_links.ts";
|
||||||
|
|
@ -1,12 +1,12 @@
|
|||||||
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
||||||
import { index } from "$sb/silverbullet-syscall/mod.ts";
|
import { index } from "$sb/syscalls.ts";
|
||||||
import type {
|
import type {
|
||||||
CompleteEvent,
|
CompleteEvent,
|
||||||
IndexTreeEvent,
|
IndexTreeEvent,
|
||||||
QueryProviderEvent,
|
QueryProviderEvent,
|
||||||
} from "$sb/app_event.ts";
|
} from "$sb/app_event.ts";
|
||||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||||
import { extractFrontmatter } from "../../plug-api/lib/frontmatter.ts";
|
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||||
|
|
||||||
// Key space
|
// Key space
|
||||||
// tag:TAG => true (for completion)
|
// tag:TAG => true (for completion)
|
@ -1,7 +1,6 @@
|
|||||||
import { editor } from "$sb/silverbullet-syscall/mod.ts";
|
import { clientStore, editor } from "$sb/syscalls.ts";
|
||||||
import { readSettings } from "$sb/lib/settings_page.ts";
|
import { readSettings } from "$sb/lib/settings_page.ts";
|
||||||
import { updateMarkdownPreview } from "./preview.ts";
|
import { updateMarkdownPreview } from "./preview.ts";
|
||||||
import { clientStore } from "$sb/silverbullet-syscall/mod.ts";
|
|
||||||
|
|
||||||
export async function togglePreview() {
|
export async function togglePreview() {
|
||||||
const currentValue = !!(await clientStore.get("enableMarkdownPreview"));
|
const currentValue = !!(await clientStore.get("enableMarkdownPreview"));
|
||||||
|
@ -10,7 +10,7 @@ import { assertEquals } from "../../test_deps.ts";
|
|||||||
Deno.test("Markdown render", async () => {
|
Deno.test("Markdown render", async () => {
|
||||||
const system = new System<any>("server");
|
const system = new System<any>("server");
|
||||||
await system.load(
|
await system.load(
|
||||||
new URL("../../dist_plug_bundle/_plug/core.plug.js", import.meta.url),
|
new URL("../../dist_plug_bundle/_plug/editor.plug.js", import.meta.url),
|
||||||
createSandbox,
|
createSandbox,
|
||||||
);
|
);
|
||||||
await system.load(
|
await system.load(
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { clientStore, editor, system } from "$sb/silverbullet-syscall/mod.ts";
|
import { asset, clientStore, editor, markdown, system } from "$sb/syscalls.ts";
|
||||||
import { asset } from "$sb/plugos-syscall/mod.ts";
|
|
||||||
import { parseMarkdown } from "$sb/silverbullet-syscall/markdown.ts";
|
|
||||||
import { renderMarkdownToHtml } from "./markdown_render.ts";
|
import { renderMarkdownToHtml } from "./markdown_render.ts";
|
||||||
import { resolvePath } from "$sb/lib/resolve.ts";
|
import { resolvePath } from "$sb/lib/resolve.ts";
|
||||||
|
|
||||||
@ -10,7 +8,7 @@ export async function updateMarkdownPreview() {
|
|||||||
}
|
}
|
||||||
const currentPage = await editor.getCurrentPage();
|
const currentPage = await editor.getCurrentPage();
|
||||||
const text = await editor.getText();
|
const text = await editor.getText();
|
||||||
const mdTree = await parseMarkdown(text);
|
const mdTree = await markdown.parseMarkdown(text);
|
||||||
// const cleanMd = await cleanMarkdown(text);
|
// const cleanMd = await cleanMarkdown(text);
|
||||||
const css = await asset.readAsset("assets/styles.css");
|
const css = await asset.readAsset("assets/styles.css");
|
||||||
const js = await asset.readAsset("assets/handler.js");
|
const js = await asset.readAsset("assets/handler.js");
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
renderToText,
|
renderToText,
|
||||||
replaceNodesMatching,
|
replaceNodesMatching,
|
||||||
} from "$sb/lib/tree.ts";
|
} from "$sb/lib/tree.ts";
|
||||||
import { markdown } from "$sb/silverbullet-syscall/mod.ts";
|
import { markdown } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
export function encodePageUrl(name: string): string {
|
export function encodePageUrl(name: string): string {
|
||||||
return name;
|
return name;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { parseMarkdown } from "$sb/silverbullet-syscall/markdown.ts";
|
import { markdown } from "$sb/syscalls.ts";
|
||||||
import type { WidgetContent } from "$sb/app_event.ts";
|
import type { WidgetContent } from "$sb/app_event.ts";
|
||||||
import { renderMarkdownToHtml } from "./markdown_render.ts";
|
import { renderMarkdownToHtml } from "./markdown_render.ts";
|
||||||
|
|
||||||
export async function markdownWidget(
|
export async function markdownWidget(
|
||||||
bodyText: string,
|
bodyText: string,
|
||||||
): Promise<WidgetContent> {
|
): Promise<WidgetContent> {
|
||||||
const mdTree = await parseMarkdown(bodyText);
|
const mdTree = await markdown.parseMarkdown(bodyText);
|
||||||
|
|
||||||
const html = await renderMarkdownToHtml(mdTree, {
|
const html = renderMarkdownToHtml(mdTree, {
|
||||||
smartHardBreak: true,
|
smartHardBreak: true,
|
||||||
});
|
});
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
|
26
plugs/plug-manager/plug-manager.plug.yaml
Normal file
26
plugs/plug-manager/plug-manager.plug.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: plug-manager
|
||||||
|
requiredPermissions:
|
||||||
|
- fetch
|
||||||
|
functions:
|
||||||
|
updatePlugsCommand:
|
||||||
|
path: ./plugmanager.ts:updatePlugsCommand
|
||||||
|
command:
|
||||||
|
name: "Plugs: Update"
|
||||||
|
key: "Ctrl-Shift-p"
|
||||||
|
mac: "Cmd-Shift-p"
|
||||||
|
getPlugHTTPS:
|
||||||
|
path: "./plugmanager.ts:getPlugHTTPS"
|
||||||
|
events:
|
||||||
|
- get-plug:https
|
||||||
|
getPlugGithub:
|
||||||
|
path: "./plugmanager.ts:getPlugGithub"
|
||||||
|
events:
|
||||||
|
- get-plug:github
|
||||||
|
getPlugGithubRelease:
|
||||||
|
path: "./plugmanager.ts:getPlugGithubRelease"
|
||||||
|
events:
|
||||||
|
- get-plug:ghr
|
||||||
|
addPlugCommand:
|
||||||
|
path: ./plugmanager.ts:addPlugCommand
|
||||||
|
command:
|
||||||
|
name: "Plugs: Add"
|
@ -1,5 +1,4 @@
|
|||||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
import { editor, events, space, system } from "$sb/syscalls.ts";
|
||||||
import { editor, space, system } from "$sb/silverbullet-syscall/mod.ts";
|
|
||||||
import { readYamlPage } from "$sb/lib/yaml_page.ts";
|
import { readYamlPage } from "$sb/lib/yaml_page.ts";
|
||||||
import { builtinPlugNames } from "../builtin_plugs.ts";
|
import { builtinPlugNames } from "../builtin_plugs.ts";
|
||||||
|
|
@ -58,7 +58,7 @@ export class SimpleSearchEngine {
|
|||||||
const uniqueStemmedWords = [...new Set(stemmedWords)];
|
const uniqueStemmedWords = [...new Set(stemmedWords)];
|
||||||
const currentIdsArray = await this.index.get(uniqueStemmedWords);
|
const currentIdsArray = await this.index.get(uniqueStemmedWords);
|
||||||
|
|
||||||
stemmedWords.forEach((stemmedWord, i) => {
|
stemmedWords.forEach((stemmedWord) => {
|
||||||
const currentIds =
|
const currentIds =
|
||||||
currentIdsArray[uniqueStemmedWords.indexOf(stemmedWord)] || [];
|
currentIdsArray[uniqueStemmedWords.indexOf(stemmedWord)] || [];
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ functions:
|
|||||||
indexPage:
|
indexPage:
|
||||||
path: search.ts:indexPage
|
path: search.ts:indexPage
|
||||||
# Only enable in client for now
|
# Only enable in client for now
|
||||||
env: client
|
# env: client
|
||||||
events:
|
events:
|
||||||
- page:index
|
- page:index
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||||
import { renderToText } from "$sb/lib/tree.ts";
|
import { renderToText } from "$sb/lib/tree.ts";
|
||||||
import { store } from "$sb/plugos-syscall/mod.ts";
|
|
||||||
import { applyQuery } from "$sb/lib/query.ts";
|
import { applyQuery } from "$sb/lib/query.ts";
|
||||||
import { editor, index } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, index, store } from "$sb/syscalls.ts";
|
||||||
import { BatchKVStore, SimpleSearchEngine } from "./engine.ts";
|
import { BatchKVStore, SimpleSearchEngine } from "./engine.ts";
|
||||||
import { FileMeta } from "$sb/types.ts";
|
import { FileMeta } from "$sb/types.ts";
|
||||||
|
|
||||||
@ -26,10 +25,10 @@ class StoreKVStore implements BatchKVStore<string, string[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const engine = new SimpleSearchEngine(
|
const ftsKvStore = new StoreKVStore("fts:");
|
||||||
new StoreKVStore("fts:"),
|
const ftsRevKvStore = new StoreKVStore("fts_rev:");
|
||||||
new StoreKVStore("fts_rev:"),
|
|
||||||
);
|
const engine = new SimpleSearchEngine(ftsKvStore, ftsRevKvStore);
|
||||||
|
|
||||||
export async function indexPage({ name, tree }: IndexTreeEvent) {
|
export async function indexPage({ name, tree }: IndexTreeEvent) {
|
||||||
const text = renderToText(tree);
|
const text = renderToText(tree);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { events } from "$sb/plugos-syscall/mod.ts";
|
import { editor, events, markdown } from "$sb/syscalls.ts";
|
||||||
import { editor, markdown } from "$sb/silverbullet-syscall/mod.ts";
|
|
||||||
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||||
import { PublishEvent } from "$sb/app_event.ts";
|
import { PublishEvent } from "$sb/app_event.ts";
|
||||||
|
|
||||||
|
9
plugs/sync/sync.plug.yaml
Normal file
9
plugs/sync/sync.plug.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name: sync
|
||||||
|
functions:
|
||||||
|
syncSpaceCommand:
|
||||||
|
path: "./sync.ts:syncSpaceCommand"
|
||||||
|
command:
|
||||||
|
name: "Sync: Now"
|
||||||
|
key: "Alt-Shift-s"
|
||||||
|
mac: "Cmd-Shift-s"
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
import { editor, sync } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, sync } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
export async function syncSpaceCommand() {
|
export async function syncSpaceCommand() {
|
||||||
await editor.flashNotification("Syncing space...");
|
await editor.flashNotification("Syncing space...");
|
@ -4,13 +4,7 @@ import type {
|
|||||||
QueryProviderEvent,
|
QueryProviderEvent,
|
||||||
} from "$sb/app_event.ts";
|
} from "$sb/app_event.ts";
|
||||||
|
|
||||||
import {
|
import { editor, index, markdown, space, sync } from "$sb/syscalls.ts";
|
||||||
editor,
|
|
||||||
index,
|
|
||||||
markdown,
|
|
||||||
space,
|
|
||||||
sync,
|
|
||||||
} from "$sb/silverbullet-syscall/mod.ts";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addParentPointers,
|
addParentPointers,
|
||||||
@ -26,7 +20,7 @@ import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
|||||||
import { niceDate } from "$sb/lib/dates.ts";
|
import { niceDate } from "$sb/lib/dates.ts";
|
||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
||||||
import { rewritePageRefs } from "$sb/lib/resolve.ts";
|
import { rewritePageRefs } from "$sb/lib/resolve.ts";
|
||||||
import { indexAttributes } from "../core/attributes.ts";
|
import { indexAttributes } from "../index/attributes.ts";
|
||||||
|
|
||||||
export type Task = {
|
export type Task = {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -20,7 +20,7 @@ syntax:
|
|||||||
backgroundColor: "rgba(22,22,22,0.07)"
|
backgroundColor: "rgba(22,22,22,0.07)"
|
||||||
functions:
|
functions:
|
||||||
turnIntoTask:
|
turnIntoTask:
|
||||||
redirect: core.applyLineReplace
|
redirect: template.applyLineReplace
|
||||||
slashCommand:
|
slashCommand:
|
||||||
name: task
|
name: task
|
||||||
description: Turn into task
|
description: Turn into task
|
||||||
|
115
plugs/template/template.plug.yaml
Normal file
115
plugs/template/template.plug.yaml
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
name: template
|
||||||
|
functions:
|
||||||
|
# Template commands
|
||||||
|
insertTemplateText:
|
||||||
|
path: "./template.ts:insertTemplateText"
|
||||||
|
applyLineReplace:
|
||||||
|
path: ./template.ts:applyLineReplace
|
||||||
|
insertFrontMatter:
|
||||||
|
redirect: insertTemplateText
|
||||||
|
slashCommand:
|
||||||
|
name: front-matter
|
||||||
|
description: Insert page front matter
|
||||||
|
value: |
|
||||||
|
---
|
||||||
|
|^|
|
||||||
|
---
|
||||||
|
makeH1:
|
||||||
|
redirect: applyLineReplace
|
||||||
|
slashCommand:
|
||||||
|
name: h1
|
||||||
|
description: Turn line into h1 header
|
||||||
|
match: "^#*\\s*"
|
||||||
|
replace: "# "
|
||||||
|
makeH2:
|
||||||
|
redirect: applyLineReplace
|
||||||
|
slashCommand:
|
||||||
|
name: h2
|
||||||
|
description: Turn line into h2 header
|
||||||
|
match: "^#*\\s*"
|
||||||
|
replace: "## "
|
||||||
|
makeH3:
|
||||||
|
redirect: applyLineReplace
|
||||||
|
slashCommand:
|
||||||
|
name: h3
|
||||||
|
description: Turn line into h3 header
|
||||||
|
match: "^#*\\s*"
|
||||||
|
replace: "### "
|
||||||
|
makeH4:
|
||||||
|
redirect: applyLineReplace
|
||||||
|
slashCommand:
|
||||||
|
name: h4
|
||||||
|
description: Turn line into h4 header
|
||||||
|
match: "^#*\\s*"
|
||||||
|
replace: "#### "
|
||||||
|
insertCodeBlock:
|
||||||
|
redirect: insertTemplateText
|
||||||
|
slashCommand:
|
||||||
|
name: code
|
||||||
|
description: Insert code block
|
||||||
|
value: |
|
||||||
|
```
|
||||||
|
|^|
|
||||||
|
```
|
||||||
|
|
||||||
|
insertHRTemplate:
|
||||||
|
redirect: insertTemplateText
|
||||||
|
slashCommand:
|
||||||
|
name: hr
|
||||||
|
description: Insert a horizontal rule
|
||||||
|
value: "---"
|
||||||
|
insertTable:
|
||||||
|
redirect: insertTemplateText
|
||||||
|
slashCommand:
|
||||||
|
name: table
|
||||||
|
description: Insert a table
|
||||||
|
boost: -1 # Low boost because it's likely not very commonly used
|
||||||
|
value: |
|
||||||
|
| Header A | Header B |
|
||||||
|
|----------|----------|
|
||||||
|
| Cell A|^| | Cell B |
|
||||||
|
quickNoteCommand:
|
||||||
|
path: ./template.ts:quickNoteCommand
|
||||||
|
command:
|
||||||
|
name: "Quick Note"
|
||||||
|
key: "Alt-Shift-n"
|
||||||
|
priority: 1
|
||||||
|
dailyNoteCommand:
|
||||||
|
path: ./template.ts:dailyNoteCommand
|
||||||
|
command:
|
||||||
|
name: "Open Daily Note"
|
||||||
|
key: "Alt-Shift-d"
|
||||||
|
weeklyNoteCommand:
|
||||||
|
path: ./template.ts:weeklyNoteCommand
|
||||||
|
command:
|
||||||
|
name: "Open Weekly Note"
|
||||||
|
key: "Alt-Shift-w"
|
||||||
|
|
||||||
|
instantiateTemplateCommand:
|
||||||
|
path: ./template.ts:instantiateTemplateCommand
|
||||||
|
command:
|
||||||
|
name: "Template: Instantiate Page"
|
||||||
|
insertSnippet:
|
||||||
|
path: ./template.ts:insertSnippet
|
||||||
|
command:
|
||||||
|
name: "Template: Insert Snippet"
|
||||||
|
slashCommand:
|
||||||
|
name: snippet
|
||||||
|
description: Insert a snippet
|
||||||
|
applyPageTemplateCommand:
|
||||||
|
path: ./template.ts:applyPageTemplateCommand
|
||||||
|
slashCommand:
|
||||||
|
name: page-template
|
||||||
|
description: Apply a page template
|
||||||
|
insertTodayCommand:
|
||||||
|
path: "./template.ts:insertTemplateText"
|
||||||
|
slashCommand:
|
||||||
|
name: today
|
||||||
|
description: Insert today's date
|
||||||
|
value: "{{today}}"
|
||||||
|
insertTomorrowCommand:
|
||||||
|
path: "./template.ts:insertTemplateText"
|
||||||
|
slashCommand:
|
||||||
|
name: tomorrow
|
||||||
|
description: Insert tomorrow's date
|
||||||
|
value: "{{tomorrow}}"
|
@ -1,4 +1,4 @@
|
|||||||
import { editor, markdown, space } from "$sb/silverbullet-syscall/mod.ts";
|
import { editor, markdown, space } from "$sb/syscalls.ts";
|
||||||
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||||
import { renderToText } from "$sb/lib/tree.ts";
|
import { renderToText } from "$sb/lib/tree.ts";
|
||||||
import { niceDate } from "$sb/lib/dates.ts";
|
import { niceDate } from "$sb/lib/dates.ts";
|
@ -11,7 +11,6 @@ import { EndpointHook } from "../plugos/hooks/endpoint.ts";
|
|||||||
import { EventHook } from "../plugos/hooks/event.ts";
|
import { EventHook } from "../plugos/hooks/event.ts";
|
||||||
import { MQHook } from "../plugos/hooks/mq.ts";
|
import { MQHook } from "../plugos/hooks/mq.ts";
|
||||||
import { DenoKVStore } from "../plugos/lib/kv_store.deno_kv.ts";
|
import { DenoKVStore } from "../plugos/lib/kv_store.deno_kv.ts";
|
||||||
import { DexieMQ } from "../plugos/lib/mq.dexie.ts";
|
|
||||||
import assetSyscalls from "../plugos/syscalls/asset.ts";
|
import assetSyscalls from "../plugos/syscalls/asset.ts";
|
||||||
import { eventSyscalls } from "../plugos/syscalls/event.ts";
|
import { eventSyscalls } from "../plugos/syscalls/event.ts";
|
||||||
import { mqSyscalls } from "../plugos/syscalls/mq.dexie.ts";
|
import { mqSyscalls } from "../plugos/syscalls/mq.dexie.ts";
|
||||||
@ -19,16 +18,16 @@ import { storeSyscalls } from "../plugos/syscalls/store.ts";
|
|||||||
import { System } from "../plugos/system.ts";
|
import { System } from "../plugos/system.ts";
|
||||||
import { Space } from "../web/space.ts";
|
import { Space } from "../web/space.ts";
|
||||||
import { debugSyscalls } from "../web/syscalls/debug.ts";
|
import { debugSyscalls } from "../web/syscalls/debug.ts";
|
||||||
import { pageIndexSyscalls } from "../cli/syscalls/index.ts";
|
import { pageIndexSyscalls } from "./syscalls/index.ts";
|
||||||
import { markdownSyscalls } from "../web/syscalls/markdown.ts";
|
import { markdownSyscalls } from "../web/syscalls/markdown.ts";
|
||||||
import { spaceSyscalls } from "../cli/syscalls/space.ts";
|
import { spaceSyscalls } from "./syscalls/space.ts";
|
||||||
import { systemSyscalls } from "../web/syscalls/system.ts";
|
import { systemSyscalls } from "../web/syscalls/system.ts";
|
||||||
import { yamlSyscalls } from "../web/syscalls/yaml.ts";
|
import { yamlSyscalls } from "../web/syscalls/yaml.ts";
|
||||||
import { Application, path } from "./deps.ts";
|
import { Application, path } from "./deps.ts";
|
||||||
import { sandboxFetchSyscalls } from "../plugos/syscalls/fetch.ts";
|
import { sandboxFetchSyscalls } from "../plugos/syscalls/fetch.ts";
|
||||||
import { shellSyscalls } from "../plugos/syscalls/shell.deno.ts";
|
import { shellSyscalls } from "../plugos/syscalls/shell.deno.ts";
|
||||||
import { IDBKeyRange, indexedDB } from "https://esm.sh/fake-indexeddb@4.0.2";
|
|
||||||
import { SpacePrimitives } from "../common/spaces/space_primitives.ts";
|
import { SpacePrimitives } from "../common/spaces/space_primitives.ts";
|
||||||
|
import { DenoKvMQ } from "../plugos/lib/mq.deno_kv.ts";
|
||||||
|
|
||||||
const fileListInterval = 30 * 1000; // 30s
|
const fileListInterval = 30 * 1000; // 30s
|
||||||
|
|
||||||
@ -38,6 +37,7 @@ export class ServerSystem {
|
|||||||
private requeueInterval?: number;
|
private requeueInterval?: number;
|
||||||
kvStore?: DenoKVStore;
|
kvStore?: DenoKVStore;
|
||||||
listInterval?: number;
|
listInterval?: number;
|
||||||
|
denoKv!: Deno.Kv;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private baseSpacePrimitives: SpacePrimitives,
|
private baseSpacePrimitives: SpacePrimitives,
|
||||||
@ -56,19 +56,15 @@ export class ServerSystem {
|
|||||||
const cronHook = new CronHook(this.system);
|
const cronHook = new CronHook(this.system);
|
||||||
this.system.addHook(cronHook);
|
this.system.addHook(cronHook);
|
||||||
|
|
||||||
this.kvStore = new DenoKVStore();
|
this.denoKv = await Deno.openKv(this.dbPath);
|
||||||
await this.kvStore.init(this.dbPath);
|
|
||||||
|
this.kvStore = new DenoKVStore(this.denoKv);
|
||||||
|
|
||||||
// Endpoint hook
|
// Endpoint hook
|
||||||
this.system.addHook(new EndpointHook(this.app, "/_/"));
|
this.system.addHook(new EndpointHook(this.app, "/_/"));
|
||||||
|
|
||||||
// Use DexieMQ for this, in memory
|
// Use DexieMQ for this, in memory
|
||||||
const mq = new DexieMQ("mq", indexedDB, IDBKeyRange);
|
const mq = new DenoKvMQ(this.denoKv);
|
||||||
|
|
||||||
this.requeueInterval = setInterval(() => {
|
|
||||||
// Timeout after 5s, retries 3 times, otherwise drops the message (no DLQ)
|
|
||||||
mq.requeueTimeouts(5000, 3, true).catch(console.error);
|
|
||||||
}, 20000); // Look to requeue every 20s
|
|
||||||
|
|
||||||
const pageIndexCalls = pageIndexSyscalls(this.kvStore);
|
const pageIndexCalls = pageIndexSyscalls(this.kvStore);
|
||||||
|
|
||||||
@ -148,9 +144,7 @@ export class ServerSystem {
|
|||||||
const tempDir = await Deno.makeTempDir();
|
const tempDir = await Deno.makeTempDir();
|
||||||
try {
|
try {
|
||||||
for (const { name } of await this.spacePrimitives.fetchFileList()) {
|
for (const { name } of await this.spacePrimitives.fetchFileList()) {
|
||||||
if (
|
if (name.endsWith(".plug.js")) {
|
||||||
name.endsWith(".plug.js") // && !filePath.includes("search.plug.js")
|
|
||||||
) {
|
|
||||||
const plugPath = path.join(tempDir, name);
|
const plugPath = path.join(tempDir, name);
|
||||||
await Deno.mkdir(path.dirname(plugPath), { recursive: true });
|
await Deno.mkdir(path.dirname(plugPath), { recursive: true });
|
||||||
await Deno.writeFile(
|
await Deno.writeFile(
|
||||||
|
@ -4,8 +4,8 @@ import { pageIndexSyscalls } from "./index.ts";
|
|||||||
|
|
||||||
Deno.test("Test KV index", async () => {
|
Deno.test("Test KV index", async () => {
|
||||||
const ctx: any = {};
|
const ctx: any = {};
|
||||||
const kv = new DenoKVStore();
|
const denoKv = await Deno.openKv("test.db");
|
||||||
await kv.init("test.db");
|
const kv = new DenoKVStore(denoKv);
|
||||||
const calls = pageIndexSyscalls(kv);
|
const calls = pageIndexSyscalls(kv);
|
||||||
await calls["index.set"](ctx, "page", "test", "value");
|
await calls["index.set"](ctx, "page", "test", "value");
|
||||||
assertEquals(await calls["index.get"](ctx, "page", "test"), "value");
|
assertEquals(await calls["index.get"](ctx, "page", "test"), "value");
|
||||||
@ -33,5 +33,6 @@ Deno.test("Test KV index", async () => {
|
|||||||
await calls["index.clearPageIndex"](ctx);
|
await calls["index.clearPageIndex"](ctx);
|
||||||
results = await calls["index.queryPrefix"](ctx, "");
|
results = await calls["index.queryPrefix"](ctx, "");
|
||||||
assertEquals(results.length, 0);
|
assertEquals(results.length, 0);
|
||||||
await kv.delete();
|
denoKv.close();
|
||||||
|
await Deno.remove("test.db");
|
||||||
});
|
});
|
@ -1,7 +1,8 @@
|
|||||||
import { safeRun } from "../common/util.ts";
|
import { safeRun } from "../common/util.ts";
|
||||||
import { Client } from "./client.ts";
|
import { Client } from "./client.ts";
|
||||||
|
|
||||||
const thinClientMode = window.silverBulletConfig.thinClientMode === "on";
|
const thinClientMode = !!localStorage.getItem("thinClientMode");
|
||||||
|
|
||||||
safeRun(async () => {
|
safeRun(async () => {
|
||||||
console.log("Booting SilverBullet...");
|
console.log("Booting SilverBullet...");
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ declare global {
|
|||||||
// Injected via index.html
|
// Injected via index.html
|
||||||
silverBulletConfig: {
|
silverBulletConfig: {
|
||||||
spaceFolderPath: string;
|
spaceFolderPath: string;
|
||||||
thinClientMode: "on" | "off";
|
|
||||||
};
|
};
|
||||||
client: Client;
|
client: Client;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ import { MQHook } from "../plugos/hooks/mq.ts";
|
|||||||
import { mqSyscalls } from "../plugos/syscalls/mq.dexie.ts";
|
import { mqSyscalls } from "../plugos/syscalls/mq.dexie.ts";
|
||||||
import { indexProxySyscalls } from "./syscalls/index.proxy.ts";
|
import { indexProxySyscalls } from "./syscalls/index.proxy.ts";
|
||||||
import { storeProxySyscalls } from "./syscalls/store.proxy.ts";
|
import { storeProxySyscalls } from "./syscalls/store.proxy.ts";
|
||||||
|
import { mqProxySyscalls } from "./syscalls/mq.proxy.ts";
|
||||||
|
|
||||||
export class ClientSystem {
|
export class ClientSystem {
|
||||||
commandHook: CommandHook;
|
commandHook: CommandHook;
|
||||||
@ -82,7 +83,9 @@ export class ClientSystem {
|
|||||||
this.system.addHook(this.codeWidgetHook);
|
this.system.addHook(this.codeWidgetHook);
|
||||||
|
|
||||||
// MQ hook
|
// MQ hook
|
||||||
this.system.addHook(new MQHook(this.system, this.mq));
|
if (!this.thinClientMode) {
|
||||||
|
this.system.addHook(new MQHook(this.system, this.mq));
|
||||||
|
}
|
||||||
|
|
||||||
// Command hook
|
// Command hook
|
||||||
this.commandHook = new CommandHook();
|
this.commandHook = new CommandHook();
|
||||||
@ -120,17 +123,17 @@ export class ClientSystem {
|
|||||||
// console.log("New file list", files);
|
// console.log("New file list", files);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
this.eventHook.addLocalListener("file:changed", (file) => {
|
// this.eventHook.addLocalListener("file:changed", (file) => {
|
||||||
console.log("File changed", file);
|
// console.log("File changed", file);
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.eventHook.addLocalListener("file:created", (file) => {
|
// this.eventHook.addLocalListener("file:created", (file) => {
|
||||||
console.log("File created", file);
|
// console.log("File created", file);
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.eventHook.addLocalListener("file:deleted", (file) => {
|
// this.eventHook.addLocalListener("file:deleted", (file) => {
|
||||||
console.log("File deleted", file);
|
// console.log("File deleted", file);
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.registerSyscalls();
|
this.registerSyscalls();
|
||||||
}
|
}
|
||||||
@ -154,7 +157,7 @@ export class ClientSystem {
|
|||||||
markdownSyscalls(buildMarkdown(this.mdExtensions)),
|
markdownSyscalls(buildMarkdown(this.mdExtensions)),
|
||||||
assetSyscalls(this.system),
|
assetSyscalls(this.system),
|
||||||
yamlSyscalls(),
|
yamlSyscalls(),
|
||||||
mqSyscalls(this.mq),
|
this.thinClientMode ? mqProxySyscalls(this.client) : mqSyscalls(this.mq),
|
||||||
storeCalls,
|
storeCalls,
|
||||||
this.indexSyscalls,
|
this.indexSyscalls,
|
||||||
debugSyscalls(),
|
debugSyscalls(),
|
||||||
|
@ -195,7 +195,7 @@ export class MainUI {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("Now renaming page to...", newName);
|
console.log("Now renaming page to...", newName);
|
||||||
await editor.system.system.loadedPlugs.get("core")!.invoke(
|
await editor.system.system.loadedPlugs.get("index")!.invoke(
|
||||||
"renamePageCommand",
|
"renamePageCommand",
|
||||||
[{ page: newName }],
|
[{ page: newName }],
|
||||||
);
|
);
|
||||||
|
@ -34,14 +34,12 @@
|
|||||||
};
|
};
|
||||||
window.silverBulletConfig = {
|
window.silverBulletConfig = {
|
||||||
// These {{VARIABLES}} are replaced by http_server.ts
|
// These {{VARIABLES}} are replaced by http_server.ts
|
||||||
spaceFolderPath: "{{SPACE_PATH}}",
|
spaceFolderPath: "{{SPACE_PATH}}"
|
||||||
thinClientMode: "{{THIN_CLIENT_MODE}}",
|
|
||||||
};
|
};
|
||||||
// But in case these variables aren't replaced by the server, fall back fully static mode (no sync)
|
// But in case these variables aren't replaced by the server, fall back fully static mode (no sync)
|
||||||
if (window.silverBulletConfig.spaceFolderPath.includes("{{")) {
|
if (window.silverBulletConfig.spaceFolderPath.includes("{{")) {
|
||||||
window.silverBulletConfig = {
|
window.silverBulletConfig = {
|
||||||
spaceFolderPath: "",
|
spaceFolderPath: "",
|
||||||
thinClientMode: "off",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -171,9 +171,20 @@ export function editorSyscalls(editor: Client): SysCallMapping {
|
|||||||
return editor.confirm(message);
|
return editor.confirm(message);
|
||||||
},
|
},
|
||||||
"editor.getUiOption": (_ctx, key: string): any => {
|
"editor.getUiOption": (_ctx, key: string): any => {
|
||||||
|
if (key === "thinClientMode") {
|
||||||
|
return !!localStorage.getItem("thinClientMode");
|
||||||
|
}
|
||||||
return (editor.ui.viewState.uiOptions as any)[key];
|
return (editor.ui.viewState.uiOptions as any)[key];
|
||||||
},
|
},
|
||||||
"editor.setUiOption": (_ctx, key: string, value: any) => {
|
"editor.setUiOption": (_ctx, key: string, value: any) => {
|
||||||
|
if (key === "thinClientMode") {
|
||||||
|
if (value) {
|
||||||
|
localStorage.setItem("thinClientMode", "true");
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("thinClientMode");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
editor.ui.viewDispatch({
|
editor.ui.viewDispatch({
|
||||||
type: "set-ui-option",
|
type: "set-ui-option",
|
||||||
key,
|
key,
|
||||||
|
13
web/syscalls/mq.proxy.ts
Normal file
13
web/syscalls/mq.proxy.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { SysCallMapping } from "../../plugos/system.ts";
|
||||||
|
import { Client } from "../client.ts";
|
||||||
|
import { proxySyscalls } from "./util.ts";
|
||||||
|
|
||||||
|
export function mqProxySyscalls(client: Client): SysCallMapping {
|
||||||
|
return proxySyscalls(client, [
|
||||||
|
"mq.send",
|
||||||
|
"mq.batchSend",
|
||||||
|
"mq.ack",
|
||||||
|
"mq.batchAck",
|
||||||
|
"mq.getQueueStats",
|
||||||
|
]);
|
||||||
|
}
|
@ -10,16 +10,6 @@ export function systemSyscalls(
|
|||||||
): SysCallMapping {
|
): SysCallMapping {
|
||||||
const api: SysCallMapping = {
|
const api: SysCallMapping = {
|
||||||
"system.invokeFunction": (
|
"system.invokeFunction": (
|
||||||
ctx,
|
|
||||||
_env: string,
|
|
||||||
name: string,
|
|
||||||
...args: any[]
|
|
||||||
) => {
|
|
||||||
// For backwards compatibility
|
|
||||||
// TODO: Remove at some point
|
|
||||||
return api["system.invoke"](ctx, name, ...args);
|
|
||||||
},
|
|
||||||
"system.invoke": (
|
|
||||||
ctx,
|
ctx,
|
||||||
name: string,
|
name: string,
|
||||||
...args: any[]
|
...args: any[]
|
||||||
@ -28,6 +18,12 @@ export function systemSyscalls(
|
|||||||
throw Error("No plug associated with context");
|
throw Error("No plug associated with context");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name === "server" || name === "client") {
|
||||||
|
// Backwards compatibility mode (previously there was an 'env' argument)
|
||||||
|
name = args[0];
|
||||||
|
args = args.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
let plug: Plug<any> | undefined = ctx.plug;
|
let plug: Plug<any> | undefined = ctx.plug;
|
||||||
if (name.indexOf(".") !== -1) {
|
if (name.indexOf(".") !== -1) {
|
||||||
// plug name in the name
|
// plug name in the name
|
||||||
@ -44,7 +40,7 @@ export function systemSyscalls(
|
|||||||
}
|
}
|
||||||
if (functionDef.env && system.env && functionDef.env !== system.env) {
|
if (functionDef.env && system.env && functionDef.env !== system.env) {
|
||||||
// Proxy to another environment
|
// Proxy to another environment
|
||||||
return proxySyscall(editor.remoteSpacePrimitives, name, args);
|
return proxySyscall(ctx, editor.remoteSpacePrimitives, name, args);
|
||||||
}
|
}
|
||||||
return plug.invoke(name, args);
|
return plug.invoke(name, args);
|
||||||
},
|
},
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
|
import { plugCompileCommand } from "../../cmd/plug_compile.ts";
|
||||||
import { HttpSpacePrimitives } from "../../common/spaces/http_space_primitives.ts";
|
import { HttpSpacePrimitives } from "../../common/spaces/http_space_primitives.ts";
|
||||||
import { SysCallMapping } from "../../plugos/system.ts";
|
import { SyscallContext, SysCallMapping } from "../../plugos/system.ts";
|
||||||
import { SyscallResponse } from "../../server/rpc.ts";
|
import { SyscallResponse } from "../../server/rpc.ts";
|
||||||
import { Client } from "../client.ts";
|
import { Client } from "../client.ts";
|
||||||
|
|
||||||
export function proxySyscalls(client: Client, names: string[]): SysCallMapping {
|
export function proxySyscalls(client: Client, names: string[]): SysCallMapping {
|
||||||
const syscalls: SysCallMapping = {};
|
const syscalls: SysCallMapping = {};
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
syscalls[name] = (_ctx, ...args: any[]) => {
|
syscalls[name] = (ctx, ...args: any[]) => {
|
||||||
return proxySyscall(client.remoteSpacePrimitives, name, args);
|
return proxySyscall(ctx, client.remoteSpacePrimitives, name, args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return syscalls;
|
return syscalls;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function proxySyscall(
|
export async function proxySyscall(
|
||||||
|
ctx: SyscallContext,
|
||||||
httpSpacePrimitives: HttpSpacePrimitives,
|
httpSpacePrimitives: HttpSpacePrimitives,
|
||||||
name: string,
|
name: string,
|
||||||
args: any[],
|
args: any[],
|
||||||
@ -23,6 +25,7 @@ export async function proxySyscall(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
ctx: ctx.plug.name,
|
||||||
operation: "syscall",
|
operation: "syscall",
|
||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
|
@ -3,6 +3,12 @@ release.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Next
|
||||||
|
* Another heavy behind-the-scenes refactoring release, refactoring the large “core” plug into multiple smaller ones, documentation to be updated to reflect this.
|
||||||
|
* Removed [[Cloud Links]] support in favor of [[Federation]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 0.3.11
|
## 0.3.11
|
||||||
|
|
||||||
* Cookies set when using SilverBullet's built-in [[Authentication]] are now per domain + port, allowing you to run multiple instances of SB on a single host with different ports without the authentication interfering.
|
* Cookies set when using SilverBullet's built-in [[Authentication]] are now per domain + port, allowing you to run multiple instances of SB on a single host with different ports without the authentication interfering.
|
||||||
|
@ -1,5 +1 @@
|
|||||||
You can access the “markdown web” through SilverBullet directly. The idea of the the markdown web (we really need a better name) is simple: the Internet is a messy place — tracking everywhere, tons of banners and other stuff — let’s bring it back to the basics. How about Markdown?
|
Deprecated in favor of [[Federation]]
|
||||||
|
|
||||||
SilverBullet supports navigating this markdown web via cloud links, they’re simply wiki links that start with “💭 “. For instance: [[💭 silverbullet.md/SilverBullet]]. When you click one of these links, SilverBullet will simply pull in its content and present it to you in read-only mode (and do some clever internal link rewriting). What it does is simply fetch the link via HTTPs and postfix the url with `.md`, so [[💭 silverbullet.md/SilverBullet]] will fetch [this page](https://silverbullet.md/Silver%20Bullet.md). You can access all of the SilverBullet website this way, for instance here’s the [[💭 silverbullet.md/CHANGELOG]].
|
|
||||||
|
|
||||||
To publish your own content this way, simply create an `index.md` on your host (this will be fetched as the main page), and publish all the rest of your content as `.md` files alongside it. That’s all there’s to it.
|
|
@ -33,7 +33,7 @@ spaceIgnore: |
|
|||||||
plugOverrides:
|
plugOverrides:
|
||||||
core:
|
core:
|
||||||
# Matching this YAML structure:
|
# Matching this YAML structure:
|
||||||
# https://github.com/silverbulletmd/silverbullet/blob/main/plugs/core/core.plug.yaml
|
# https://github.com/silverbulletmd/silverbullet/blob/main/plugs/editor/editor.plug.yaml
|
||||||
# and overriding the "key" for centering the cursor
|
# and overriding the "key" for centering the cursor
|
||||||
functions.centerCursor.command.key: Ctrl-Alt-p
|
functions.centerCursor.command.key: Ctrl-Alt-p
|
||||||
# However, it's even possible to define custom slash commands this way without building a plug (/today-header in this case):
|
# However, it's even possible to define custom slash commands this way without building a plug (/today-header in this case):
|
||||||
|
@ -57,7 +57,7 @@ A simple example is multiplying numbers:
|
|||||||
|
|
||||||
However, you can also invoke arbitrary plug functions, e.g. the `titleUnfurlOptions` function in the `core` plug:
|
However, you can also invoke arbitrary plug functions, e.g. the `titleUnfurlOptions` function in the `core` plug:
|
||||||
|
|
||||||
<!-- #eval core.titleUnfurlOptions() -->
|
<!-- #eval editor.titleUnfurlOptions() -->
|
||||||
|id |name |
|
|id |name |
|
||||||
|------------|-------------|
|
|------------|-------------|
|
||||||
|title-unfurl|Extract title|
|
|title-unfurl|Extract title|
|
||||||
@ -65,7 +65,7 @@ However, you can also invoke arbitrary plug functions, e.g. the `titleUnfurlOpti
|
|||||||
|
|
||||||
Optionally, you can use a `render` clause to render the result as a template, similar to [[🔌 Directive/Query]]:
|
Optionally, you can use a `render` clause to render the result as a template, similar to [[🔌 Directive/Query]]:
|
||||||
|
|
||||||
<!-- #eval core.titleUnfurlOptions() render [[template/debug]] -->
|
<!-- #eval editor.titleUnfurlOptions() render [[template/debug]] -->
|
||||||
id: title-unfurl
|
id: title-unfurl
|
||||||
name: Extract title
|
name: Extract title
|
||||||
---
|
---
|
||||||
|
Loading…
Reference in New Issue
Block a user