diff --git a/plug-api/lib/resolve.ts b/plug-api/lib/resolve.ts index d89096a..e1b1205 100644 --- a/plug-api/lib/resolve.ts +++ b/plug-api/lib/resolve.ts @@ -30,14 +30,14 @@ export function isFederationPath(path: string) { return path.startsWith("!"); } -export function rewritePageRefs(tree: ParseTree, templatePath: string) { +export function rewritePageRefs(tree: ParseTree, containerPageName: string) { traverseTree(tree, (n): boolean => { if (n.type === "DirectiveStart") { const pageRef = findNodeOfType(n, "PageRef")!; if (pageRef) { const pageRefName = pageRef.children![0].text!.slice(2, -2); pageRef.children![0].text = `[[${ - resolvePath(templatePath, pageRefName) + resolvePath(containerPageName, pageRefName) }]]`; } const directiveText = n.children![0].text; @@ -48,7 +48,7 @@ export function rewritePageRefs(tree: ParseTree, templatePath: string) { const pageRefName = match[1]; n.children![0].text = directiveText.replace( match[0], - `[[${resolvePath(templatePath, pageRefName)}]]`, + `[[${resolvePath(containerPageName, pageRefName)}]]`, ); } } @@ -56,7 +56,10 @@ export function rewritePageRefs(tree: ParseTree, templatePath: string) { return true; } if (n.type === "WikiLinkPage") { - n.children![0].text = resolvePath(templatePath, n.children![0].text!); + n.children![0].text = resolvePath( + containerPageName, + n.children![0].text!, + ); return true; } diff --git a/plugs/core/item.ts b/plugs/core/item.ts index 79313a3..1d130a4 100644 --- a/plugs/core/item.ts +++ b/plugs/core/item.ts @@ -4,6 +4,7 @@ import { index } from "$sb/silverbullet-syscall/mod.ts"; import { collectNodesOfType, ParseTree, renderToText } from "$sb/lib/tree.ts"; import { applyQuery, removeQueries } from "$sb/lib/query.ts"; import { extractAttributes } from "$sb/lib/attribute.ts"; +import { rewritePageRefs } from "$sb/lib/resolve.ts"; export type Item = { name: string; @@ -38,6 +39,7 @@ export async function indexItems({ name, tree }: IndexTreeEvent) { const textNodes: ParseTree[] = []; let nested: string | undefined; for (const child of n.children!.slice(1)) { + rewritePageRefs(child, name); if (child.type === "OrderedList" || child.type === "BulletList") { nested = renderToText(child); break; @@ -67,7 +69,7 @@ export async function indexItems({ name, tree }: IndexTreeEvent) { value: item, }); } - // console.log("Found", items.length, "item(s)"); + // console.log("Found", items, "item(s)"); await index.batchSet(name, items); } diff --git a/plugs/core/page.ts b/plugs/core/page.ts index 022ad8b..4c4990d 100644 --- a/plugs/core/page.ts +++ b/plugs/core/page.ts @@ -14,7 +14,6 @@ import { events } from "$sb/plugos-syscall/mod.ts"; import { applyQuery } from "$sb/lib/query.ts"; import { invokeFunction } from "$sb/silverbullet-syscall/system.ts"; -import { backlinkPrefix } from "./page_links.ts"; // Key space: // meta: => metaJson diff --git a/plugs/core/page_links.ts b/plugs/core/page_links.ts index bce6f41..d665a35 100644 --- a/plugs/core/page_links.ts +++ b/plugs/core/page_links.ts @@ -4,6 +4,7 @@ import { extractFrontmatter } from "$sb/lib/frontmatter.ts"; import { extractAttributes } from "$sb/lib/attribute.ts"; import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts"; import { applyQuery } from "$sb/lib/query.ts"; +import { resolvePath } from "$sb/lib/resolve.ts"; // Key space: // l:toPage:pos => {name: pageName, inDirective: true, asTemplate: true} @@ -46,7 +47,10 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) { directiveDepth++; const pageRef = findNodeOfType(n, "PageRef")!; if (pageRef) { - const pageRefName = pageRef.children![0].text!.slice(2, -2); + const pageRefName = resolvePath( + name, + pageRef.children![0].text!.slice(2, -2), + ); backLinks.push({ key: `${backlinkPrefix}${pageRefName}:${pageRef.from! + 2}`, value: { name, asTemplate: true }, @@ -57,7 +61,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) { if (directiveText) { const match = /\[\[(.+)\]\]/.exec(directiveText); if (match) { - const pageRefName = match[1]; + const pageRefName = resolvePath(name, match[1]); backLinks.push({ key: `${backlinkPrefix}${pageRefName}:${ n.from! + match.index! + 2 @@ -77,7 +81,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) { if (n.type === "WikiLink") { const wikiLinkPage = findNodeOfType(n, "WikiLinkPage")!; const wikiLinkAlias = findNodeOfType(n, "WikiLinkAlias"); - let toPage = wikiLinkPage.children![0].text!; + let toPage = resolvePath(name, wikiLinkPage.children![0].text!); if (toPage.includes("@")) { toPage = toPage.split("@")[0]; } @@ -96,7 +100,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) { } return false; }); - // console.log("Found", backLinks.length, "page link(s)"); + // console.log("Found", backLinks, "page link(s)"); await index.batchSet(name, backLinks); } diff --git a/plugs/tasks/task.ts b/plugs/tasks/task.ts index c37851d..fbe9eaf 100644 --- a/plugs/tasks/task.ts +++ b/plugs/tasks/task.ts @@ -24,6 +24,7 @@ import { 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"; export type Task = { name: string; @@ -54,6 +55,8 @@ export async function indexTasks({ name, tree }: IndexTreeEvent) { done: complete, }; + rewritePageRefs(n, name); + replaceNodesMatching(n, (tree) => { if (tree.type === "DeadlineDate") { task.deadline = getDeadline(tree); @@ -91,7 +94,7 @@ export async function indexTasks({ name, tree }: IndexTreeEvent) { return true; }); - // console.log("Found", tasks.length, "task(s)"); + // console.log("Found", tasks, "task(s)"); await index.batchSet(name, tasks); } diff --git a/website/Federation.md b/website/Federation.md new file mode 100644 index 0000000..cfef7c0 --- /dev/null +++ b/website/Federation.md @@ -0,0 +1,28 @@ +Federation enables _browsing_, and _synchronizing_ (parts of) spaces outside of the user’s space into your SilverBullet client. + +This enables a few things: + +* Linking and browsing publicly hosted SilverBullet spaces (or website adhering to its [[API]]). For instance the [[!silverbullet.md/CHANGELOG|SilverBullet CHANGELOG]] without leaving the comfort of your own SilverBullet client. +* Reusing content from externally hosted sources, such as: + * _Templates_, e.g. by federating with `silverbullet.md/template` will give you access to the example templates hosted there without manually copying and pasting them, and automatically pull in the latest version. So you can for instance use `render [[!silverbullet.md/template/page]]` to use the [[template/page]] template. + * _Data_: such as tasks, item, data hosted elsewhere that you want to query from your own space. + +**Note:** Federation does not support authentication yet, so all federated spaces need to be unauthenticated and will be _read only_. + +## Browsing +Browsing other publicly hosted spaces is as simple as navigating to a page starting with `!` such as [[!silverbullet.md/CHANGELOG]]. + +## Federating +To synchronize federated content into your client, you need to list these URIs in your [[SETTINGS]] under the `federate` key. For instance: + +```yaml +federate: +- uri: silverbullet.md/template +``` + +This will synchronize all content under `!silverbullet.md` with a `template` prefix (so all templates hosted there) locally. + +Currently content can only be synchronized in read-only mode, so you can not edit the synchronized files. This will likely change in the future. + +## Hosting +Tooling to make hosting public spaces is still work in progress. \ No newline at end of file