1
0

Refactor all the things

This commit is contained in:
Zef Hemel 2023-08-28 17:12:15 +02:00
parent 54d2deea15
commit 5ff1a8bae3
87 changed files with 930 additions and 896 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ node_modules
*.db
test_space
silverbullet
.silverbullet.db*

View File

@ -1,4 +1,4 @@
FROM lukechannings/deno:v1.36.1
FROM lukechannings/deno:v1.36.3
# The volume that will keep the space data
# Create a volume first:
# docker volume create myspace

View File

@ -38,7 +38,7 @@ export async function runPlug(
});
if (indexFirst) {
await serverSystem.system.loadedPlugs.get("core")!.invoke(
await serverSystem.system.loadedPlugs.get("index")!.invoke(
"reindexSpace",
[],
);
@ -53,8 +53,8 @@ export async function runPlug(
}
const result = await plug.invoke(funcName, args);
await serverSystem.close();
await serverSystem.kvStore?.delete();
// await Deno.remove(tempFile);
serverSystem.denoKv.close();
await Deno.remove(tempFile);
serverController.abort();
return result;
} else {

View File

@ -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;
if (options.reindex) {
console.log("Reindexing space (requested via --reindex flag)");
await serverSystem.system.loadedPlugs.get("core")!.invoke(
await serverSystem.system.loadedPlugs.get("index")!.invoke(
"reindexSpace",
[],
);

View File

@ -1,5 +1,5 @@
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) {
return syscall("mq.send", queue, body);
@ -17,6 +17,6 @@ export function batchAck(queue: string, ids: string[]) {
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);
}

View File

@ -1,20 +1,11 @@
import type { CommandDef } from "../../web/hooks/command.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(
env: string,
name: string,
...args: any[]
): Promise<any> {
return syscall("system.invokeFunction", env, name, ...args);
return syscall("system.invokeFunction", name, ...args);
}
// Only available on the client

2
plug-api/syscalls.ts Normal file
View File

@ -0,0 +1,2 @@
export * from "$sb/silverbullet-syscall/mod.ts";
export * from "$sb/plugos-syscall/mod.ts";

View File

@ -1,16 +1,21 @@
export type Message = {
export type MQMessage = {
id: string;
queue: string;
body: any;
retries?: number;
};
export type QueueStats = {
export type MQStats = {
queued: number;
processing: number;
dlq: number;
};
export type MQSubscribeOptions = {
batchSize?: number;
pollInterval?: number;
};
export type FileMeta = {
name: string;
lastModified: number;

View File

@ -1,8 +1,8 @@
import { Hook, Manifest } from "../types.ts";
import { System } from "../system.ts";
import { DexieMQ } from "../lib/mq.dexie.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 = {
queue: string;
@ -17,7 +17,7 @@ export type MQHookT = {
export class MQHook implements Hook<MQHookT> {
subscriptions: (() => void)[] = [];
constructor(private system: System<MQHookT>, readonly mq: DexieMQ) {
constructor(private system: System<MQHookT>, readonly mq: MessageQueue) {
}
apply(system: System<MQHookT>): void {
@ -64,7 +64,7 @@ export class MQHook implements Hook<MQHookT> {
{
batchSize: subscriptionDef.batchSize,
},
async (messages: Message[]) => {
async (messages: MQMessage[]) => {
try {
await plug.invoke(name, [messages]);
if (subscriptionDef.autoAck) {

View File

@ -2,8 +2,8 @@ import { assertEquals } from "../../test_deps.ts";
import { DenoKVStore } from "./kv_store.deno_kv.ts";
Deno.test("Test KV index", async () => {
const kv = new DenoKVStore();
await kv.init("test.db");
const denoKv = await Deno.openKv("test.db");
const kv = new DenoKVStore(denoKv);
await kv.set("name", "Peter");
assertEquals(await kv.get("name"), "Peter");
@ -52,5 +52,6 @@ Deno.test("Test KV index", async () => {
await kv.deletePrefix("");
assertEquals(await kv.queryPrefix(""), []);
await kv.delete();
denoKv.close();
await Deno.remove("test.db");
});

View File

@ -5,23 +5,7 @@ import { KV, KVStore } from "./kv_store.ts";
const kvBatchSize = 10;
export class DenoKVStore implements KVStore {
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);
}
constructor(private kv: Deno.Kv) {
}
del(key: string): Promise<void> {

View 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
View 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();
}
}

View File

@ -1,18 +1,14 @@
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;
};
export type SubscribeOptions = {
batchSize?: number;
pollInterval?: number;
};
export class DexieMQ {
export class DexieMQ implements MessageQueue {
db: Dexie;
queued: Table<Message, [string, string]>;
queued: Table<MQMessage, [string, string]>;
processing: Table<ProcessingMessage, [string, string]>;
dlq: Table<ProcessingMessage, [string, string]>;
@ -63,13 +59,15 @@ export class DexieMQ {
return this.batchSend(queue, [body]);
}
poll(queue: string, maxItems: number): Promise<Message[]> {
poll(queue: string, maxItems: number): Promise<MQMessage[]> {
return this.db.transaction(
"rw",
[this.queued, this.processing],
async (tx) => {
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);
const ids: [string, string][] = messages.map((m) => [queue, m.id]);
await tx.table("queued").bulkDelete(ids);
@ -93,8 +91,8 @@ export class DexieMQ {
*/
subscribe(
queue: string,
options: SubscribeOptions,
callback: (messages: Message[]) => Promise<void> | void,
options: MQSubscribeOptions,
callback: (messages: MQMessage[]) => Promise<void> | void,
): () => void {
let running = true;
let timeout: number | undefined;
@ -219,7 +217,7 @@ export class DexieMQ {
return this.dlq.clear();
}
getQueueStats(queue: string): Promise<QueueStats> {
getQueueStats(queue: string): Promise<MQStats> {
return this.db.transaction(
"r",
[this.queued, this.processing, this.dlq],
@ -237,8 +235,8 @@ export class DexieMQ {
);
}
async getAllQueueStats(): Promise<Record<string, QueueStats>> {
const allStatus: Record<string, QueueStats> = {};
async getAllQueueStats(): Promise<Record<string, MQStats>> {
const allStatus: Record<string, MQStats> = {};
await this.db.transaction(
"r",
[this.queued, this.processing, this.dlq],

16
plugos/lib/mq.ts Normal file
View 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>>;
}

View File

@ -1,9 +1,9 @@
import { SysCallMapping } from "../system.ts";
import { DexieMQ } from "../lib/mq.dexie.ts";
import { fullQueueName } from "../lib/mq_util.ts";
import { MessageQueue } from "../lib/mq.ts";
export function mqSyscalls(
mq: DexieMQ,
mq: MessageQueue,
): SysCallMapping {
return {
"mq.send": (ctx, queue: string, body: any) => {

View File

@ -1,6 +1,10 @@
// TODO: Figure out how to keep this up-to-date automatically
export const builtinPlugNames = [
"core",
"editor",
"index",
"sync",
"template",
"plug-manager",
"directive",
"emoji",
"markdown",

View File

@ -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",
});
}

View File

@ -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"

View File

@ -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 {
ParseTree,
removeParentPointers,
@ -7,10 +7,9 @@ import {
} from "$sb/lib/tree.ts";
import { renderDirectives } from "./directives.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 { mq } from "$sb/plugos-syscall/mod.ts";
import { Message } from "$sb/types.ts";
import { MQMessage } from "$sb/types.ts";
import { sleep } from "../../common/async_util.ts";
const directiveUpdateQueueName = "directiveUpdateQueue";
@ -92,7 +91,7 @@ export async function updateDirectivesInSpaceCommand() {
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) {
const pageName: string = message.body;
console.log("Updating directives in page", pageName);

View File

@ -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 { buildHandebarOptions } from "./util.ts";
import type { PageMeta } from "../../web/types.ts";
import {
import type {
AttributeCompleteEvent,
AttributeCompletion,
} from "../core/attributes.ts";
} from "../index/attributes.ts";
export async function queryComplete(completeEvent: CompleteEvent) {
const querySourceMatch = /#query\s+([\w\-_]*)$/.exec(

View File

@ -2,10 +2,9 @@
// data:page@pos
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 { applyQuery, removeQueries } from "$sb/lib/query.ts";
import { YAML } from "$sb/plugos-syscall/mod.ts";
export async function indexData({ name, tree }: IndexTreeEvent) {
const dataObjects: { key: string; value: any }[] = [];

View File

@ -39,7 +39,7 @@ functions:
# Templates
insertQuery:
redirect: core.insertTemplateText
redirect: template.insertTemplateText
slashCommand:
name: query
description: Insert a query
@ -48,7 +48,7 @@ functions:
<!-- /query -->
insertInclude:
redirect: core.insertTemplateText
redirect: template.insertTemplateText
slashCommand:
name: include
description: Include another page
@ -57,7 +57,7 @@ functions:
<!-- /include -->
insertUseTemplate:
redirect: core.insertTemplateText
redirect: template.insertTemplateText
slashCommand:
name: use
description: Use a template
@ -66,7 +66,7 @@ functions:
<!-- /use -->
insertUseVerboseTemplate:
redirect: core.insertTemplateText
redirect: template.insertTemplateText
slashCommand:
name: use-verbose
description: Use a template (verbose mode)
@ -75,7 +75,7 @@ functions:
<!-- /use-verbose -->
insertEvalTemplate:
redirect: core.insertTemplateText
redirect: template.insertTemplateText
slashCommand:
name: eval
description: Evaluate a JavaScript expression

View File

@ -1,10 +1,10 @@
// 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 { jsonToMDTable, renderTemplate } from "./util.ts";
import { PageMeta } from "../../web/types.ts";
import { replaceTemplateVars } from "../core/template.ts";
import type { PageMeta } from "../../web/types.ts";
import { replaceTemplateVars } from "../template/template.ts";
// Enables plugName.functionName(arg1, arg2) syntax in JS expressions
function translateJs(js: string): string {
@ -44,7 +44,7 @@ export async function evalDirectiveRenderer(
const result = await (0, eval)(
`(async () => {
function invokeFunction(name, ...args) {
return syscall("system.invoke", name, ...args);
return syscall("system.invokeFunction", name, ...args);
}
return ${replaceTemplateVars(translateJs(expression), pageMeta)};
})()`,

View File

@ -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 { parseQuery } from "./parser.ts";
import { jsonToMDTable } from "./util.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(
_directive: string,

View File

@ -1,14 +1,9 @@
import { queryRegex } from "$sb/lib/query.ts";
import {
findNodeOfType,
ParseTree,
renderToText,
traverseTree,
} from "$sb/lib/tree.ts";
import { markdown, space } from "$sb/silverbullet-syscall/mod.ts";
import { ParseTree, renderToText } from "$sb/lib/tree.ts";
import { markdown, space } from "$sb/syscalls.ts";
import Handlebars from "handlebars";
import { replaceTemplateVars } from "../core/template.ts";
import { replaceTemplateVars } from "../template/template.ts";
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
import { directiveRegex } from "./directives.ts";
import { updateDirectives } from "./command.ts";

View File

@ -1,7 +1,7 @@
import Handlebars from "handlebars";
import { space } from "$sb/silverbullet-syscall/mod.ts";
import { PageMeta } from "../../web/types.ts";
import { space } from "$sb/syscalls.ts";
import type { PageMeta } from "../../web/types.ts";
import { handlebarHelpers } from "./handlebar_helpers.ts";
const maxWidth = 70;

View File

@ -1,4 +1,4 @@
import { editor } from "$sb/silverbullet-syscall/mod.ts";
import { editor } from "$sb/syscalls.ts";
export async function accountLogoutCommand() {
await editor.openUrl("/.client/logout.html", true);

View File

@ -1,9 +1,5 @@
import { traverseTree } from "../../plug-api/lib/tree.ts";
import {
editor,
markdown,
space,
} from "../../plug-api/silverbullet-syscall/mod.ts";
import { editor, markdown, space } from "$sb/syscalls.ts";
export async function brokenLinksCommand() {
const pageName = "BROKEN LINKS";

7
plugs/editor/client.ts Normal file
View 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();
}

View File

@ -1,5 +1,5 @@
import { system } from "$sb/silverbullet-syscall/mod.ts";
import { CompleteEvent } from "../../plug-api/app_event.ts";
import { system } from "$sb/syscalls.ts";
import { CompleteEvent } from "$sb/app_event.ts";
export async function commandComplete(completeEvent: CompleteEvent) {
const match = /\{\[([^\]]*)$/.exec(completeEvent.linePrefix);

View File

@ -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() {
console.log(

View 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"

View File

@ -1,4 +1,4 @@
import { clientStore, editor } from "$sb/silverbullet-syscall/mod.ts";
import { clientStore, editor } from "$sb/syscalls.ts";
// Run on "editor:init"
export async function setEditorMode() {

View File

@ -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";
type EmbedConfig = {

View File

@ -1,4 +1,4 @@
import { editor } from "$sb/silverbullet-syscall/mod.ts";
import { editor } from "$sb/syscalls.ts";
import { version } from "../../version.ts";
export async function versionCommand() {

View File

@ -1,6 +1,5 @@
import { nodeAtPos } from "$sb/lib/tree.ts";
import { editor, markdown } from "$sb/silverbullet-syscall/mod.ts";
import { events } from "$sb/plugos-syscall/mod.ts";
import { editor, events, markdown } from "$sb/syscalls.ts";
type UnfurlOption = {
id: string;

View File

@ -1,5 +1,5 @@
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 {
addParentPointers,
findNodeOfType,

View File

@ -1,33 +1,9 @@
import type {
CompleteEvent,
IndexEvent,
QueryProviderEvent,
} from "$sb/app_event.ts";
import {
editor,
index,
markdown,
space,
} from "$sb/silverbullet-syscall/mod.ts";
import type { CompleteEvent } from "$sb/app_event.ts";
import { editor, space } from "$sb/syscalls.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 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() {
const pageName = await editor.getCurrentPage();
if (
@ -85,12 +61,6 @@ export async function newPageCommand() {
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
export async function pageComplete(completeEvent: CompleteEvent) {
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),
});
}

View File

@ -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 {
const matches = str.match(/[\w\d\'-]+/gi);

View File

@ -1,4 +1,4 @@
import { editor } from "$sb/silverbullet-syscall/mod.ts";
import { editor } from "$sb/syscalls.ts";
export async function quoteSelection() {
let text = await editor.getText();

View File

@ -1,6 +1,5 @@
import { readCodeBlockPage } from "../../plug-api/lib/yaml_page.ts";
import { editor } from "$sb/silverbullet-syscall/mod.ts";
import { store } from "$sb/plugos-syscall/mod.ts";
import { readCodeBlockPage } from "$sb/lib/yaml_page.ts";
import { editor, store } from "$sb/syscalls.ts";
export async function toggleVimMode() {
let vimMode = await store.get("vimMode");

View File

@ -1,5 +1,5 @@
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) {
const match = /:([\w]+)$/.exec(linePrefix);

View File

@ -1,8 +1,8 @@
import "$sb/lib/fetch.ts";
import { federatedPathToUrl } from "$sb/lib/resolve.ts";
import { readFederationConfigs } from "./config.ts";
import { store } from "$sb/plugos-syscall/mod.ts";
import { FileMeta } from "$sb/types.ts";
import { store } from "$sb/syscalls.ts";
import type { FileMeta } from "$sb/types.ts";
async function responseToFileMeta(
r: Response,

View File

@ -1,5 +1,5 @@
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 { removeQueries } from "$sb/lib/query.ts";

View File

@ -1,6 +1,6 @@
import { QueryProviderEvent } from "$sb/app_event.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) {
return applyQuery(query, await space.listAttachments());

View File

@ -1,6 +1,6 @@
import { index } from "$sb/silverbullet-syscall/mod.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";

133
plugs/index/index.plug.yaml Normal file
View 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"

View File

@ -1,6 +1,6 @@
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 { applyQuery, removeQueries } from "$sb/lib/query.ts";
import { extractAttributes } from "$sb/lib/attribute.ts";

77
plugs/index/page.ts Normal file
View 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),
});
}

View File

@ -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 { extractFrontmatter } from "$sb/lib/frontmatter.ts";
import { extractAttributes } from "$sb/lib/attribute.ts";

View File

@ -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 { getBackLinks } from "./page_links.ts";

View File

@ -1,12 +1,12 @@
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,
QueryProviderEvent,
} from "$sb/app_event.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
// tag:TAG => true (for completion)

View File

@ -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 { updateMarkdownPreview } from "./preview.ts";
import { clientStore } from "$sb/silverbullet-syscall/mod.ts";
export async function togglePreview() {
const currentValue = !!(await clientStore.get("enableMarkdownPreview"));

View File

@ -10,7 +10,7 @@ import { assertEquals } from "../../test_deps.ts";
Deno.test("Markdown render", async () => {
const system = new System<any>("server");
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,
);
await system.load(

View File

@ -1,6 +1,4 @@
import { clientStore, editor, system } from "$sb/silverbullet-syscall/mod.ts";
import { asset } from "$sb/plugos-syscall/mod.ts";
import { parseMarkdown } from "$sb/silverbullet-syscall/markdown.ts";
import { asset, clientStore, editor, markdown, system } from "$sb/syscalls.ts";
import { renderMarkdownToHtml } from "./markdown_render.ts";
import { resolvePath } from "$sb/lib/resolve.ts";
@ -10,7 +8,7 @@ export async function updateMarkdownPreview() {
}
const currentPage = await editor.getCurrentPage();
const text = await editor.getText();
const mdTree = await parseMarkdown(text);
const mdTree = await markdown.parseMarkdown(text);
// const cleanMd = await cleanMarkdown(text);
const css = await asset.readAsset("assets/styles.css");
const js = await asset.readAsset("assets/handler.js");

View File

@ -3,7 +3,7 @@ import {
renderToText,
replaceNodesMatching,
} 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 {
return name;

View File

@ -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 { renderMarkdownToHtml } from "./markdown_render.ts";
export async function markdownWidget(
bodyText: string,
): Promise<WidgetContent> {
const mdTree = await parseMarkdown(bodyText);
const mdTree = await markdown.parseMarkdown(bodyText);
const html = await renderMarkdownToHtml(mdTree, {
const html = renderMarkdownToHtml(mdTree, {
smartHardBreak: true,
});
return Promise.resolve({

View 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"

View File

@ -1,5 +1,4 @@
import { events } from "$sb/plugos-syscall/mod.ts";
import { editor, space, system } from "$sb/silverbullet-syscall/mod.ts";
import { editor, events, space, system } from "$sb/syscalls.ts";
import { readYamlPage } from "$sb/lib/yaml_page.ts";
import { builtinPlugNames } from "../builtin_plugs.ts";

View File

@ -58,7 +58,7 @@ export class SimpleSearchEngine {
const uniqueStemmedWords = [...new Set(stemmedWords)];
const currentIdsArray = await this.index.get(uniqueStemmedWords);
stemmedWords.forEach((stemmedWord, i) => {
stemmedWords.forEach((stemmedWord) => {
const currentIds =
currentIdsArray[uniqueStemmedWords.indexOf(stemmedWord)] || [];

View File

@ -3,7 +3,7 @@ functions:
indexPage:
path: search.ts:indexPage
# Only enable in client for now
env: client
# env: client
events:
- page:index

View File

@ -1,8 +1,7 @@
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
import { renderToText } from "$sb/lib/tree.ts";
import { store } from "$sb/plugos-syscall/mod.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 { FileMeta } from "$sb/types.ts";
@ -26,10 +25,10 @@ class StoreKVStore implements BatchKVStore<string, string[]> {
}
}
const engine = new SimpleSearchEngine(
new StoreKVStore("fts:"),
new StoreKVStore("fts_rev:"),
);
const ftsKvStore = new StoreKVStore("fts:");
const ftsRevKvStore = new StoreKVStore("fts_rev:");
const engine = new SimpleSearchEngine(ftsKvStore, ftsRevKvStore);
export async function indexPage({ name, tree }: IndexTreeEvent) {
const text = renderToText(tree);

View File

@ -1,5 +1,4 @@
import { events } from "$sb/plugos-syscall/mod.ts";
import { editor, markdown } from "$sb/silverbullet-syscall/mod.ts";
import { editor, events, markdown } from "$sb/syscalls.ts";
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
import { PublishEvent } from "$sb/app_event.ts";

View 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"

View File

@ -1,4 +1,4 @@
import { editor, sync } from "$sb/silverbullet-syscall/mod.ts";
import { editor, sync } from "$sb/syscalls.ts";
export async function syncSpaceCommand() {
await editor.flashNotification("Syncing space...");

View File

@ -4,13 +4,7 @@ import type {
QueryProviderEvent,
} from "$sb/app_event.ts";
import {
editor,
index,
markdown,
space,
sync,
} from "$sb/silverbullet-syscall/mod.ts";
import { editor, index, markdown, space, sync } from "$sb/syscalls.ts";
import {
addParentPointers,
@ -26,7 +20,7 @@ import { applyQuery, removeQueries } from "$sb/lib/query.ts";
import { niceDate } from "$sb/lib/dates.ts";
import { extractAttributes } from "$sb/lib/attribute.ts";
import { rewritePageRefs } from "$sb/lib/resolve.ts";
import { indexAttributes } from "../core/attributes.ts";
import { indexAttributes } from "../index/attributes.ts";
export type Task = {
name: string;

View File

@ -20,7 +20,7 @@ syntax:
backgroundColor: "rgba(22,22,22,0.07)"
functions:
turnIntoTask:
redirect: core.applyLineReplace
redirect: template.applyLineReplace
slashCommand:
name: task
description: Turn into task

View 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}}"

View File

@ -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 { renderToText } from "$sb/lib/tree.ts";
import { niceDate } from "$sb/lib/dates.ts";

View File

@ -11,7 +11,6 @@ import { EndpointHook } from "../plugos/hooks/endpoint.ts";
import { EventHook } from "../plugos/hooks/event.ts";
import { MQHook } from "../plugos/hooks/mq.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 { eventSyscalls } from "../plugos/syscalls/event.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 { Space } from "../web/space.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 { spaceSyscalls } from "../cli/syscalls/space.ts";
import { spaceSyscalls } from "./syscalls/space.ts";
import { systemSyscalls } from "../web/syscalls/system.ts";
import { yamlSyscalls } from "../web/syscalls/yaml.ts";
import { Application, path } from "./deps.ts";
import { sandboxFetchSyscalls } from "../plugos/syscalls/fetch.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 { DenoKvMQ } from "../plugos/lib/mq.deno_kv.ts";
const fileListInterval = 30 * 1000; // 30s
@ -38,6 +37,7 @@ export class ServerSystem {
private requeueInterval?: number;
kvStore?: DenoKVStore;
listInterval?: number;
denoKv!: Deno.Kv;
constructor(
private baseSpacePrimitives: SpacePrimitives,
@ -56,19 +56,15 @@ export class ServerSystem {
const cronHook = new CronHook(this.system);
this.system.addHook(cronHook);
this.kvStore = new DenoKVStore();
await this.kvStore.init(this.dbPath);
this.denoKv = await Deno.openKv(this.dbPath);
this.kvStore = new DenoKVStore(this.denoKv);
// Endpoint hook
this.system.addHook(new EndpointHook(this.app, "/_/"));
// Use DexieMQ for this, in memory
const mq = new DexieMQ("mq", indexedDB, IDBKeyRange);
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 mq = new DenoKvMQ(this.denoKv);
const pageIndexCalls = pageIndexSyscalls(this.kvStore);
@ -148,9 +144,7 @@ export class ServerSystem {
const tempDir = await Deno.makeTempDir();
try {
for (const { name } of await this.spacePrimitives.fetchFileList()) {
if (
name.endsWith(".plug.js") // && !filePath.includes("search.plug.js")
) {
if (name.endsWith(".plug.js")) {
const plugPath = path.join(tempDir, name);
await Deno.mkdir(path.dirname(plugPath), { recursive: true });
await Deno.writeFile(

View File

@ -4,8 +4,8 @@ import { pageIndexSyscalls } from "./index.ts";
Deno.test("Test KV index", async () => {
const ctx: any = {};
const kv = new DenoKVStore();
await kv.init("test.db");
const denoKv = await Deno.openKv("test.db");
const kv = new DenoKVStore(denoKv);
const calls = pageIndexSyscalls(kv);
await calls["index.set"](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);
results = await calls["index.queryPrefix"](ctx, "");
assertEquals(results.length, 0);
await kv.delete();
denoKv.close();
await Deno.remove("test.db");
});

View File

@ -1,7 +1,8 @@
import { safeRun } from "../common/util.ts";
import { Client } from "./client.ts";
const thinClientMode = window.silverBulletConfig.thinClientMode === "on";
const thinClientMode = !!localStorage.getItem("thinClientMode");
safeRun(async () => {
console.log("Booting SilverBullet...");

View File

@ -47,7 +47,6 @@ declare global {
// Injected via index.html
silverBulletConfig: {
spaceFolderPath: string;
thinClientMode: "on" | "off";
};
client: Client;
}

View File

@ -35,6 +35,7 @@ import { MQHook } from "../plugos/hooks/mq.ts";
import { mqSyscalls } from "../plugos/syscalls/mq.dexie.ts";
import { indexProxySyscalls } from "./syscalls/index.proxy.ts";
import { storeProxySyscalls } from "./syscalls/store.proxy.ts";
import { mqProxySyscalls } from "./syscalls/mq.proxy.ts";
export class ClientSystem {
commandHook: CommandHook;
@ -82,7 +83,9 @@ export class ClientSystem {
this.system.addHook(this.codeWidgetHook);
// 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
this.commandHook = new CommandHook();
@ -120,17 +123,17 @@ export class ClientSystem {
// console.log("New file list", files);
// });
this.eventHook.addLocalListener("file:changed", (file) => {
console.log("File changed", file);
});
// this.eventHook.addLocalListener("file:changed", (file) => {
// console.log("File changed", file);
// });
this.eventHook.addLocalListener("file:created", (file) => {
console.log("File created", file);
});
// this.eventHook.addLocalListener("file:created", (file) => {
// console.log("File created", file);
// });
this.eventHook.addLocalListener("file:deleted", (file) => {
console.log("File deleted", file);
});
// this.eventHook.addLocalListener("file:deleted", (file) => {
// console.log("File deleted", file);
// });
this.registerSyscalls();
}
@ -154,7 +157,7 @@ export class ClientSystem {
markdownSyscalls(buildMarkdown(this.mdExtensions)),
assetSyscalls(this.system),
yamlSyscalls(),
mqSyscalls(this.mq),
this.thinClientMode ? mqProxySyscalls(this.client) : mqSyscalls(this.mq),
storeCalls,
this.indexSyscalls,
debugSyscalls(),

View File

@ -195,7 +195,7 @@ export class MainUI {
return;
}
console.log("Now renaming page to...", newName);
await editor.system.system.loadedPlugs.get("core")!.invoke(
await editor.system.system.loadedPlugs.get("index")!.invoke(
"renamePageCommand",
[{ page: newName }],
);

View File

@ -34,14 +34,12 @@
};
window.silverBulletConfig = {
// These {{VARIABLES}} are replaced by http_server.ts
spaceFolderPath: "{{SPACE_PATH}}",
thinClientMode: "{{THIN_CLIENT_MODE}}",
spaceFolderPath: "{{SPACE_PATH}}"
};
// But in case these variables aren't replaced by the server, fall back fully static mode (no sync)
if (window.silverBulletConfig.spaceFolderPath.includes("{{")) {
window.silverBulletConfig = {
spaceFolderPath: "",
thinClientMode: "off",
};
}
</script>

View File

@ -171,9 +171,20 @@ export function editorSyscalls(editor: Client): SysCallMapping {
return editor.confirm(message);
},
"editor.getUiOption": (_ctx, key: string): any => {
if (key === "thinClientMode") {
return !!localStorage.getItem("thinClientMode");
}
return (editor.ui.viewState.uiOptions as any)[key];
},
"editor.setUiOption": (_ctx, key: string, value: any) => {
if (key === "thinClientMode") {
if (value) {
localStorage.setItem("thinClientMode", "true");
} else {
localStorage.removeItem("thinClientMode");
}
return;
}
editor.ui.viewDispatch({
type: "set-ui-option",
key,

13
web/syscalls/mq.proxy.ts Normal file
View 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",
]);
}

View File

@ -10,16 +10,6 @@ export function systemSyscalls(
): SysCallMapping {
const api: SysCallMapping = {
"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,
name: string,
...args: any[]
@ -28,6 +18,12 @@ export function systemSyscalls(
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;
if (name.indexOf(".") !== -1) {
// plug name in the name
@ -44,7 +40,7 @@ export function systemSyscalls(
}
if (functionDef.env && system.env && functionDef.env !== system.env) {
// Proxy to another environment
return proxySyscall(editor.remoteSpacePrimitives, name, args);
return proxySyscall(ctx, editor.remoteSpacePrimitives, name, args);
}
return plug.invoke(name, args);
},

View File

@ -1,19 +1,21 @@
import { plugCompileCommand } from "../../cmd/plug_compile.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 { Client } from "../client.ts";
export function proxySyscalls(client: Client, names: string[]): SysCallMapping {
const syscalls: SysCallMapping = {};
for (const name of names) {
syscalls[name] = (_ctx, ...args: any[]) => {
return proxySyscall(client.remoteSpacePrimitives, name, args);
syscalls[name] = (ctx, ...args: any[]) => {
return proxySyscall(ctx, client.remoteSpacePrimitives, name, args);
};
}
return syscalls;
}
export async function proxySyscall(
ctx: SyscallContext,
httpSpacePrimitives: HttpSpacePrimitives,
name: string,
args: any[],
@ -23,6 +25,7 @@ export async function proxySyscall(
{
method: "POST",
body: JSON.stringify({
ctx: ctx.plug.name,
operation: "syscall",
name,
args,

View File

@ -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
* 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.

View File

@ -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  lets bring it back to the basics. How about Markdown?
SilverBullet supports navigating this markdown web via cloud links, theyre 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 heres 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. Thats all theres to it.
Deprecated in favor of [[Federation]]

View File

@ -33,7 +33,7 @@ spaceIgnore: |
plugOverrides:
core:
# 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
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):

View File

@ -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:
<!-- #eval core.titleUnfurlOptions() -->
<!-- #eval editor.titleUnfurlOptions() -->
|id |name |
|------------|-------------|
|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]]:
<!-- #eval core.titleUnfurlOptions() render [[template/debug]] -->
<!-- #eval editor.titleUnfurlOptions() render [[template/debug]] -->
id: title-unfurl
name: Extract title
---