Skip to content

Commit

Permalink
Add transclusion to widget types
Browse files Browse the repository at this point in the history
  • Loading branch information
onespaceman committed Aug 8, 2024
1 parent 506d5cc commit 41277ce
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 23 deletions.
14 changes: 5 additions & 9 deletions plugs/query/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type { CodeWidgetContent } from "../../plug-api/types.ts";
import { jsonToMDTable } from "../template/util.ts";
import { renderQuery } from "./api.ts";
import type { ChangeSpec } from "@codemirror/state";
import { nodeAtPos } from "$sb/lib/tree.ts";
import { findNodeMatching, nodeAtPos } from "$sb/lib/tree.ts";

export async function widget(
bodyText: string,
Expand Down Expand Up @@ -90,21 +90,19 @@ export async function editButton(bodyText: string) {
export async function bakeButton(bodyText: string) {
try {
const text = await editor.getText();

const pos = text.indexOf(bodyText);
const tree = await markdown.parseMarkdown(text);
addParentPointers(tree);

const textNode = nodeAtPos(tree, pos);
// Need to find it in page to make the replacement, see editButton for comment about finding by content
const textNode = findNodeMatching(tree, (n) => n.text === bodyText) ||
nodeAtPos(tree, text.indexOf(bodyText));
if (!textNode) {
throw new Error(`Could not find node to bake`);
}
const blockNode = findParentMatching(
textNode,
(n) => n.type === "FencedCode" || n.type === "Image",
);

if (!blockNode) {
removeParentPointers(textNode);
console.error("baked node", textNode);
Expand Down Expand Up @@ -147,17 +145,15 @@ async function changeForBake(
const lang = nodeToReplace.type === "FencedCode"
? renderToText(findNodeOfType(nodeToReplace, "CodeInfo") ?? undefined)
: nodeToReplace.type === "Image"
? "template"
? "transclusion"
: undefined;

let body: string | undefined = undefined;
if (nodeToReplace.type === "FencedCode") {
body = renderToText(findNodeOfType(nodeToReplace, "CodeText") ?? undefined);
} else if (nodeToReplace.type === "Image") {
const text = renderToText(nodeToReplace).slice(1);
body = `{{${text}}}`;
body = renderToText(nodeToReplace);
}
console.log(lang, body);

if (!lang || body === undefined) {
return null;
Expand Down
8 changes: 8 additions & 0 deletions plugs/template/template.plug.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ functions:
codeWidget: template
renderMode: markdown

transclusionWidget:
path: widget.ts:transclusionWidget
codeWidget: transclusion
renderMode: markdown

navigateButton:
path: widget.ts:navigateButton

# API invoked when a new page is created
newPage:
path: page.ts:newPage
Expand Down
60 changes: 60 additions & 0 deletions plugs/template/widget.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
editor,
markdown,
space,
system,
Expand All @@ -9,11 +10,14 @@ import type { CodeWidgetContent, PageMeta } from "../../plug-api/types.ts";
import { renderTemplate } from "./plug_api.ts";
import { renderToText } from "@silverbulletmd/silverbullet/lib/tree";
import {
isFederationPath,
resolvePath,
rewritePageRefs,
rewritePageRefsInString,
} from "@silverbulletmd/silverbullet/lib/resolve";
import { queryParsed } from "../query/api.ts";
import { parseQuery } from "../../plug-api/lib/parse_query.ts";
import { parsePageRef } from "@silverbulletmd/silverbullet/lib/page_ref";

type TemplateWidgetConfig = {
// Pull the template from a page
Expand Down Expand Up @@ -182,6 +186,56 @@ export async function templateWidget(
};
}
}

export async function transclusionWidget(
bodyText: string,
pageName: string,
): Promise<CodeWidgetContent> {
const config = await system.getSpaceConfig();
const pageMeta: PageMeta = await loadPageObject(pageName);
let url: string | undefined = undefined;
let match: RegExpExecArray | null;
if ((match = /!?\[([^\]]*)\]\((.+)\)/g.exec(bodyText))) {
[/* fullMatch */, /* alias */ , url] = match;
} else if (
(match = /(!?\[\[)([^\]\|]+)(?:\|([^\]]+))?(\]\])/g.exec(bodyText))
) {
[/* fullMatch */, /* firstMark */ , url /* alias */] = match;
if (!isFederationPath(url)) {
url = "/" + url;
}
}

try {
if (!url) {
throw new Error("Could not parse link");
}
url = resolvePath(pageName, url, true);

const templateText =
`{{rewriteRefsAndFederationLinks([[${url}]], "${url}")}}`;

const { text: rendered } = await renderTemplate(
templateText,
pageMeta,
{ page: pageMeta, config },
);

return {
markdown: rendered,
buttons: [
{
description: "Bake result",
svg:
`<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-align-left"><line x1="17" y1="10" x2="3" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="17" y1="18" x2="3" y2="18"></line></svg>`,
invokeFunction: ["query.bakeButton", bodyText],
},
{
description: "Open Page",
svg:
`<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`,
invokeFunction: ["template.navigateButton", url],
},
{
description: "Reload",
svg:
Expand All @@ -196,3 +250,9 @@ export async function templateWidget(
};
}
}

// Navigate to page in a transclusion widget
export async function navigateButton(url: string) {
const pageRef = parsePageRef(url);
await editor.navigate(pageRef, false, false);
}
31 changes: 17 additions & 14 deletions web/cm_plugins/inline_content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,7 @@ export function inlineContentPlugin(client: Client) {
}

const text = state.sliceDoc(node.from, node.to);
let [url, alias]: (string | null)[] = [null, null];
let dim: ContentDimensions | undefined;
let [url, alias]: (string | undefined)[] = [undefined, undefined];
let match: RegExpExecArray | null;
if ((match = /!?\[([^\]]*)\]\((.+)\)/g.exec(text))) {
[/* fullMatch */, alias, url] = match;
Expand All @@ -172,10 +171,12 @@ export function inlineContentPlugin(client: Client) {
if (!isFederationPath(url)) {
url = "/" + url;
}
} else {
}
if (!url) {
return;
}

let dim: ContentDimensions | undefined;
if (alias) {
const { alias: parsedAlias, dim: parsedDim } = parseAlias(alias);
if (parsedAlias) {
Expand All @@ -187,36 +188,33 @@ export function inlineContentPlugin(client: Client) {
}

if (isLocalPath(url)) {
url = resolvePath(client.currentPage, decodeURI(url), true);
url = resolvePath(
client.currentPage,
decodeURI(url),
true,
);
const pageRef = parsePageRef(url);
if (
isFederationPath(pageRef.page) ||
client.clientSystem.allKnownFiles.has(pageRef.page + ".md")
) {
// This is a page reference, let's inline the content
const codeWidgetCallback = client.clientSystem.codeWidgetHook
.codeWidgetCallbacks.get("template");
.codeWidgetCallbacks.get("transclusion");

if (!codeWidgetCallback) {
return;
}

widgets.push(
Decoration.line({
class: "sb-fenced-code-iframe",
}).range(node.to),
);

widgets.push(
Decoration.widget({
widget: new MarkdownWidget(
node.from,
client,
`widget:${client.currentPage}:${text}`,
`{{rewriteRefsAndFederationLinks([[${url}]], "${url}")}}`,
text,
codeWidgetCallback,
"sb-markdown-widget sb-markdown-widget-inline",
text,
),
block: true,
}).range(node.to + 1),
Expand All @@ -227,7 +225,12 @@ export function inlineContentPlugin(client: Client) {

widgets.push(
Decoration.widget({
widget: new InlineContentWidget(url, alias, dim, client),
widget: new InlineContentWidget(
url,
alias,
dim,
client,
),
block: true,
}).range(node.to + 1),
);
Expand Down

0 comments on commit 41277ce

Please sign in to comment.