Template syntax refactor

pull/66/head
Zef Hemel 2022-08-09 15:37:47 +02:00
parent 1bbfbe19e2
commit 7f6e608460
18 changed files with 152 additions and 112 deletions

View File

@ -187,18 +187,35 @@ functions:
path: "./template.ts:insertTemplateText"
slashCommand:
name: include
description: Include another page
value: |
<!-- #include "|^|" -->
<!-- #include [[|^|]] -->
<!-- /include -->
insertInlineTemplate:
insertInjectTemplate:
path: "./template.ts:insertTemplateText"
slashCommand:
name: inline-template
name: inject
description: Inject template
value: |
<!-- #template "|^|" {} -->
<!-- #inject [[|^|]] {} -->
<!-- /template -->
<!-- /inject -->
insertInjectCleanTemplate:
path: "./template.ts:insertTemplateText"
slashCommand:
name: inject-clean
description: Inject template clean
value: |
<!-- #inject-clean [[|^|]] {} -->
<!-- /inject-clean -->
insertHRTemplate:
path: "./template.ts:insertTemplateText"
slashCommand:
name: hr
description: Insert a horizontal rule
value: "---"
quickNoteCommand:
path: ./template.ts:quickNoteCommand
command:

View File

@ -48,6 +48,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
console.log("Now indexing", name);
let pageMeta = extractMeta(tree);
if (Object.keys(pageMeta).length > 0) {
console.log("Extracted page meta data", pageMeta);
await set(name, "meta:", pageMeta);
}
@ -88,14 +89,12 @@ export async function linkQueryProvider({
query,
pageName,
}: QueryProviderEvent): Promise<any[]> {
let uniqueLinks = new Set<string>();
for (let { value: name } of await queryPrefix(`pl:${pageName}:`)) {
uniqueLinks.add(name);
let links: any[] = [];
for (let { value: name, key } of await queryPrefix(`pl:${pageName}:`)) {
const [, , pos] = key.split(":"); // Key: pl:page:pos
links.push({ name, pos });
}
return applyQuery(
query,
[...uniqueLinks].map((l) => ({ name: l }))
);
return applyQuery(query, links);
}
export async function deletePage() {

View File

@ -46,9 +46,12 @@ export async function instantiateTemplateCommand() {
);
let parseTree = await parseMarkdown(text);
let additionalPageMeta = extractMeta(parseTree, ["PAGENAME"]);
let additionalPageMeta = extractMeta(parseTree, [
"$name",
"$disableDirectives",
]);
let pageName = await prompt("Name of new page", additionalPageMeta.PAGENAME);
let pageName = await prompt("Name of new page", additionalPageMeta.$name);
if (!pageName) {
return;
}

View File

@ -18,37 +18,4 @@ export async function queryComplete() {
})),
};
}
prefix = await matchBefore('render "[^"]*');
if (prefix) {
let allPages = await listPages();
return {
from: prefix.from + 'render "'.length,
options: allPages.map((pageMeta) => ({
label: pageMeta.name,
})),
};
}
prefix = await matchBefore('#template "[^"]*');
if (prefix) {
let allPages = await listPages();
return {
from: prefix.from + '#template "'.length,
options: allPages.map((pageMeta) => ({
label: pageMeta.name,
})),
};
}
prefix = await matchBefore('#include "[^"]*');
if (prefix) {
let allPages = await listPages();
return {
from: prefix.from + '#include "'.length,
options: allPages.map((pageMeta) => ({
label: pageMeta.name,
})),
};
}
}

View File

@ -62,6 +62,12 @@ test("Test parser", () => {
],
});
expect(parseQuery(`something render [[template/table]]`)).toStrictEqual({
table: "something",
filter: [],
render: "template/table",
});
expect(parseQuery(`something render "template/table"`)).toStrictEqual({
table: "something",
filter: [],

View File

@ -27,6 +27,9 @@ export function valueNodeToVal(valNode: ParseTree): any {
case "String":
let stringVal = valNode.children![0].text!;
return stringVal.substring(1, stringVal.length - 1);
case "PageRef":
let pageRefVal = valNode.children![0].text!;
return pageRefVal.substring(2, pageRefVal.length - 2);
case "List":
return collectNodesOfType(valNode, "Value").map((t) =>
valueNodeToVal(t.children![0])

View File

@ -17,7 +17,8 @@ import { jsonToMDTable, queryRegex } from "./util";
import { dispatch } from "@plugos/plugos-syscall/event";
import { replaceAsync } from "../lib/util";
import { parseMarkdown } from "@silverbulletmd/plugos-silverbullet-syscall/markdown";
import { nodeAtPos } from "@silverbulletmd/common/tree";
import { nodeAtPos, renderToText } from "@silverbulletmd/common/tree";
import { extractMeta } from "./data";
export async function updateMaterializedQueriesCommand() {
const currentPage = await getCurrentPage();
@ -34,7 +35,7 @@ export async function updateMaterializedQueriesCommand() {
}
export const templateInstRegex =
/(<!--\s*#(template|include)\s+"([^"]+)"(.+?)-->)(.+?)(<!--\s*\/\2\s*-->)/gs;
/(<!--\s*#(inject|inject-clean|include)\s+\[\[([^\]]+)\]\](.*?)-->)(.+?)(<!--\s*\/\2\s*-->)/gs;
async function updateTemplateInstantiations(
text: string,
@ -66,8 +67,11 @@ async function updateTemplateInstantiations(
templateText = (await readPage(template)).text;
}
let newBody = templateText;
// if it's a template (note a literal "include")
if (type === "template") {
// if it's a template injection (not a literal "include")
if (type == "inject" || type === "inject-clean") {
let tree = await parseMarkdown(templateText);
extractMeta(tree, ["$disableDirectives"]);
templateText = renderToText(tree);
let templateFn = Handlebars.compile(
replaceTemplateVars(templateText, pageName),
{ noEscape: true }
@ -79,6 +83,29 @@ async function updateTemplateInstantiations(
);
}
async function cleanTemplateInstantiations(text: string): Promise<string> {
return replaceAsync(
text,
templateInstRegex,
async (fullMatch, startInst, type, template, args, body, endInst) => {
if (type === "inject-clean") {
body = body.replaceAll(
queryRegex,
(
fullMatch: string,
startQuery: string,
query: string,
body: string
) => {
return body.trim();
}
);
}
return `${startInst}${body}${endInst}`;
}
);
}
// Called from client, running on server
export async function updateMaterializedQueriesOnPage(
pageName: string
@ -96,6 +123,12 @@ export async function updateMaterializedQueriesOnPage(
}
let newText = await updateTemplateInstantiations(text, pageName);
let tree = await parseMarkdown(newText);
let metaData = extractMeta(tree, ["$disableDirectives"]);
if (metaData.$disableDirectives) {
console.log("Directives disabled, skipping");
return false;
}
newText = renderToText(tree);
newText = await replaceAsync(
newText,
@ -106,7 +139,6 @@ export async function updateMaterializedQueriesOnPage(
// If not a comment block, it's likely a code block, ignore
return fullMatch;
}
// console.log("Text slice", newText.substring(index, index + 100));
let parsedQuery = parseQuery(replaceTemplateVars(query, pageName));
@ -132,6 +164,7 @@ export async function updateMaterializedQueriesOnPage(
}
}
);
newText = await cleanTemplateInstantiations(newText);
if (text !== newText) {
await writePage(pageName, newText);
return true;

View File

@ -2,14 +2,14 @@
import {LRParser} from "@lezer/lr"
export const parser = LRParser.deserialize({
version: 14,
states: "&fOVQPOOOmQQO'#C^QOQPOOOtQPO'#C`OyQQO'#CkO!OQPO'#CmO!TQPO'#CnO!YQPO'#CoOOQO'#Cp'#CpO!_QQO,58xO!fQQO'#CcO#TQQO'#CaOOQO'#Ca'#CaOOQO,58z,58zO#lQPO,59VOOQO,59X,59XO#qQQO'#D`OOQO,59Y,59YOOQO,59Z,59ZOOQO-E6n-E6nO$YQQO,58}OtQPO,58|O$qQQO1G.qO%]QPO'#CrO%bQQO,59zOOQO'#Cg'#CgOOQO'#Ci'#CiO$YQQO'#CjOOQO'#Cd'#CdOOQO1G.i1G.iOOQO1G.h1G.hOOQO'#Cl'#ClOOQO7+$]7+$]OOQO,59^,59^OOQO-E6p-E6pO%yQPO'#C|O&RQPO,59UO$YQQO'#CqO&WQPO,59hOOQO1G.p1G.pOOQO,59],59]OOQO-E6o-E6o",
stateData: "&`~OiOS~ORPO~OjRO|SO!QTO!RUO!TVO~OgQX~P[ORYO~O}^O~OX_O~OR`O~OYbO~OgQa~P[OkdOsdOtdOudOvdOwdOxdOydOzdO~O{eOgTXjTX|TX!QTX!RTX!TTX~ORfO~OqgOg!SXj!SX|!SX!Q!SX!R!SX!T!SX~OXlOYlO[lOliOmiOnjOokO~O!OoO!PoOg_ij_i|_i!Q_i!R_i!T_i~ORqO~OqgOg!Saj!Sa|!Sa!Q!Sa!R!Sa!T!Sa~OquOrpX~OrwO~OquOrpa~O",
goto: "#d!TPP!UP!X!]!`!c!iPP!rP!r!r!X!w!X!X!X!z#Q#WPPPPPPPPP#^PPPPPPPPPPPPPPPPP#aRQOTWPXR]RR[RQZRRneQmdQskRxuVldkuRpfQXPRcXQvsRyvQh`RrhRtkRaU",
nodeNames: "⚠ Program Query Name WhereClause LogicalExpr AndExpr FilterExpr Value Number String Bool Regex Null List OrderClause Order LimitClause SelectClause RenderClause",
maxTerm: 51,
states: "&fOVQPOOOmQQO'#C^QOQPOOOtQPO'#C`OyQQO'#CkO!OQPO'#CmO!TQPO'#CnO!YQPO'#CoOOQO'#Cq'#CqO!bQQO,58xO!iQQO'#CcO#WQQO'#CaOOQO'#Ca'#CaOOQO,58z,58zO#oQPO,59VOOQO,59X,59XO#tQQO'#DaOOQO,59Y,59YOOQO,59Z,59ZOOQO-E6o-E6oO$]QQO,58}OtQPO,58|O$tQQO1G.qO%`QPO'#CsO%eQQO,59{OOQO'#Cg'#CgOOQO'#Ci'#CiO$]QQO'#CjOOQO'#Cd'#CdOOQO1G.i1G.iOOQO1G.h1G.hOOQO'#Cl'#ClOOQO7+$]7+$]OOQO,59_,59_OOQO-E6q-E6qO%|QPO'#C}O&UQPO,59UO$]QQO'#CrO&ZQPO,59iOOQO1G.p1G.pOOQO,59^,59^OOQO-E6p-E6p",
stateData: "&c~OjOS~ORPO~OkRO}SO!RTO!SUO!UVO~OhQX~P[ORYO~O!O^O~OX_O~OR`O~OYbOdbO~OhQa~P[OldOtdOudOvdOwdOxdOydOzdO{dO~O|eOhTXkTX}TX!RTX!STX!UTX~ORfO~OrgOh!TXk!TX}!TX!R!TX!S!TX!U!TX~OXlOYlO[lOmiOniOojOpkO~O!PoO!QoOh_ik_i}_i!R_i!S_i!U_i~ORqO~OrgOh!Tak!Ta}!Ta!R!Ta!S!Ta!U!Ta~OruOsqX~OswO~OruOsqa~O",
goto: "#e!UPP!VP!Y!^!a!d!jPP!sP!s!s!Y!x!Y!Y!YP!{#R#XPPPPPPPPP#_PPPPPPPPPPPPPPPPP#bRQOTWPXR]RR[RQZRRneQmdQskRxuVldkuRpfQXPRcXQvsRyvQh`RrhRtkRaU",
nodeNames: "⚠ Program Query Name WhereClause LogicalExpr AndExpr FilterExpr Value Number String Bool Regex Null List OrderClause Order LimitClause SelectClause RenderClause PageRef",
maxTerm: 52,
skippedNodes: [0],
repeatNodeCount: 3,
tokenData: "Ap~R}X^$Opq$Oqr$srs%W|}%r}!O%w!P!Q&Y!Q!['P!^!_'X!_!`'f!`!a's!c!}%w!}#O(Q#P#Q(V#R#S%w#T#U([#U#V*q#V#W%w#W#X+m#X#Y%w#Y#Z-i#Z#]%w#]#^/y#^#`%w#`#a0u#a#b%w#b#c3Y#c#d5U#d#f%w#f#g7i#g#h:e#h#i=a#i#k%w#k#l?]#l#o%w#y#z$O$f$g$O#BY#BZ$O$IS$I_$O$Ip$Iq%W$Iq$Ir%W$I|$JO$O$JT$JU$O$KV$KW$O&FU&FV$O~$TYi~X^$Opq$O#y#z$O$f$g$O#BY#BZ$O$IS$I_$O$I|$JO$O$JT$JU$O$KV$KW$O&FU&FV$O~$vP!_!`$y~%OPu~#r#s%R~%WOy~~%ZUOr%Wrs%ms$Ip%W$Ip$Iq%m$Iq$Ir%m$Ir~%W~%rOY~~%wOq~P%|SRP}!O%w!c!}%w#R#S%w#T#o%w~&_V[~OY&YZ]&Y^!P&Y!P!Q&t!Q#O&Y#O#P&y#P~&Y~&yO[~~&|PO~&Y~'UPX~!Q!['P~'^Pk~!_!`'a~'fOs~~'kPt~#r#s'n~'sOx~~'xPw~!_!`'{~(QOv~~(VOo~~([Or~R(aWRP}!O%w!c!}%w#R#S%w#T#b%w#b#c(y#c#g%w#g#h)u#h#o%wR)OURP}!O%w!c!}%w#R#S%w#T#W%w#W#X)b#X#o%wR)iS{QRP}!O%w!c!}%w#R#S%w#T#o%wR)zURP}!O%w!c!}%w#R#S%w#T#V%w#V#W*^#W#o%wR*eS!PQRP}!O%w!c!}%w#R#S%w#T#o%wR*vURP}!O%w!c!}%w#R#S%w#T#m%w#m#n+Y#n#o%wR+aS}QRP}!O%w!c!}%w#R#S%w#T#o%wR+rURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y,U#Y#o%wR,ZURP}!O%w!c!}%w#R#S%w#T#g%w#g#h,m#h#o%wR,rURP}!O%w!c!}%w#R#S%w#T#V%w#V#W-U#W#o%wR-]S!OQRP}!O%w!c!}%w#R#S%w#T#o%wR-nTRP}!O%w!c!}%w#R#S%w#T#U-}#U#o%wR.SURP}!O%w!c!}%w#R#S%w#T#`%w#`#a.f#a#o%wR.kURP}!O%w!c!}%w#R#S%w#T#g%w#g#h.}#h#o%wR/SURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y/f#Y#o%wR/mSmQRP}!O%w!c!}%w#R#S%w#T#o%wR0OURP}!O%w!c!}%w#R#S%w#T#b%w#b#c0b#c#o%wR0iSzQRP}!O%w!c!}%w#R#S%w#T#o%wR0zURP}!O%w!c!}%w#R#S%w#T#]%w#]#^1^#^#o%wR1cURP}!O%w!c!}%w#R#S%w#T#a%w#a#b1u#b#o%wR1zURP}!O%w!c!}%w#R#S%w#T#]%w#]#^2^#^#o%wR2cURP}!O%w!c!}%w#R#S%w#T#h%w#h#i2u#i#o%wR2|S!QQRP}!O%w!c!}%w#R#S%w#T#o%wR3_URP}!O%w!c!}%w#R#S%w#T#i%w#i#j3q#j#o%wR3vURP}!O%w!c!}%w#R#S%w#T#`%w#`#a4Y#a#o%wR4_URP}!O%w!c!}%w#R#S%w#T#`%w#`#a4q#a#o%wR4xSnQRP}!O%w!c!}%w#R#S%w#T#o%wR5ZURP}!O%w!c!}%w#R#S%w#T#f%w#f#g5m#g#o%wR5rURP}!O%w!c!}%w#R#S%w#T#W%w#W#X6U#X#o%wR6ZURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y6m#Y#o%wR6rURP}!O%w!c!}%w#R#S%w#T#f%w#f#g7U#g#o%wR7]S|QRP}!O%w!c!}%w#R#S%w#T#o%wR7nURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y8Q#Y#o%wR8VURP}!O%w!c!}%w#R#S%w#T#b%w#b#c8i#c#o%wR8nURP}!O%w!c!}%w#R#S%w#T#W%w#W#X9Q#X#o%wR9VURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y9i#Y#o%wR9nURP}!O%w!c!}%w#R#S%w#T#f%w#f#g:Q#g#o%wR:XS!TQRP}!O%w!c!}%w#R#S%w#T#o%wR:jURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y:|#Y#o%wR;RURP}!O%w!c!}%w#R#S%w#T#`%w#`#a;e#a#o%wR;jURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y;|#Y#o%wR<RURP}!O%w!c!}%w#R#S%w#T#V%w#V#W<e#W#o%wR<jURP}!O%w!c!}%w#R#S%w#T#h%w#h#i<|#i#o%wR=TS!RQRP}!O%w!c!}%w#R#S%w#T#o%wR=fURP}!O%w!c!}%w#R#S%w#T#f%w#f#g=x#g#o%wR=}URP}!O%w!c!}%w#R#S%w#T#i%w#i#j>a#j#o%wR>fURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y>x#Y#o%wR?PSlQRP}!O%w!c!}%w#R#S%w#T#o%wR?bURP}!O%w!c!}%w#R#S%w#T#[%w#[#]?t#]#o%wR?yURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y@]#Y#o%wR@bURP}!O%w!c!}%w#R#S%w#T#f%w#f#g@t#g#o%wR@yURP}!O%w!c!}%w#R#S%w#T#X%w#X#YA]#Y#o%wRAdSjQRP}!O%w!c!}%w#R#S%w#T#o%w",
tokenData: "B[~R}X^$Opq$Oqr$srs%W|}%r}!O%w!P!Q&Y!Q!['P!^!_'X!_!`'f!`!a's!c!}%w!}#O(Q#P#Q(q#R#S%w#T#U(v#U#V+]#V#W%w#W#X,X#X#Y%w#Y#Z.T#Z#]%w#]#^0e#^#`%w#`#a1a#a#b%w#b#c3t#c#d5p#d#f%w#f#g8T#g#h;P#h#i={#i#k%w#k#l?w#l#o%w#y#z$O$f$g$O#BY#BZ$O$IS$I_$O$Ip$Iq%W$Iq$Ir%W$I|$JO$O$JT$JU$O$KV$KW$O&FU&FV$O~$TYj~X^$Opq$O#y#z$O$f$g$O#BY#BZ$O$IS$I_$O$I|$JO$O$JT$JU$O$KV$KW$O&FU&FV$O~$vP!_!`$y~%OPv~#r#s%R~%WOz~~%ZUOr%Wrs%ms$Ip%W$Ip$Iq%m$Iq$Ir%m$Ir~%W~%rOY~~%wOr~P%|SRP}!O%w!c!}%w#R#S%w#T#o%w~&_V[~OY&YZ]&Y^!P&Y!P!Q&t!Q#O&Y#O#P&y#P~&Y~&yO[~~&|PO~&Y~'UPX~!Q!['P~'^Pl~!_!`'a~'fOt~~'kPu~#r#s'n~'sOy~~'xPx~!_!`'{~(QOw~R(VPpQ!}#O(YP(]RO#P(Y#P#Q(f#Q~(YP(iP#P#Q(lP(qOdP~(vOs~R({WRP}!O%w!c!}%w#R#S%w#T#b%w#b#c)e#c#g%w#g#h*a#h#o%wR)jURP}!O%w!c!}%w#R#S%w#T#W%w#W#X)|#X#o%wR*TS|QRP}!O%w!c!}%w#R#S%w#T#o%wR*fURP}!O%w!c!}%w#R#S%w#T#V%w#V#W*x#W#o%wR+PS!QQRP}!O%w!c!}%w#R#S%w#T#o%wR+bURP}!O%w!c!}%w#R#S%w#T#m%w#m#n+t#n#o%wR+{S!OQRP}!O%w!c!}%w#R#S%w#T#o%wR,^URP}!O%w!c!}%w#R#S%w#T#X%w#X#Y,p#Y#o%wR,uURP}!O%w!c!}%w#R#S%w#T#g%w#g#h-X#h#o%wR-^URP}!O%w!c!}%w#R#S%w#T#V%w#V#W-p#W#o%wR-wS!PQRP}!O%w!c!}%w#R#S%w#T#o%wR.YTRP}!O%w!c!}%w#R#S%w#T#U.i#U#o%wR.nURP}!O%w!c!}%w#R#S%w#T#`%w#`#a/Q#a#o%wR/VURP}!O%w!c!}%w#R#S%w#T#g%w#g#h/i#h#o%wR/nURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y0Q#Y#o%wR0XSnQRP}!O%w!c!}%w#R#S%w#T#o%wR0jURP}!O%w!c!}%w#R#S%w#T#b%w#b#c0|#c#o%wR1TS{QRP}!O%w!c!}%w#R#S%w#T#o%wR1fURP}!O%w!c!}%w#R#S%w#T#]%w#]#^1x#^#o%wR1}URP}!O%w!c!}%w#R#S%w#T#a%w#a#b2a#b#o%wR2fURP}!O%w!c!}%w#R#S%w#T#]%w#]#^2x#^#o%wR2}URP}!O%w!c!}%w#R#S%w#T#h%w#h#i3a#i#o%wR3hS!RQRP}!O%w!c!}%w#R#S%w#T#o%wR3yURP}!O%w!c!}%w#R#S%w#T#i%w#i#j4]#j#o%wR4bURP}!O%w!c!}%w#R#S%w#T#`%w#`#a4t#a#o%wR4yURP}!O%w!c!}%w#R#S%w#T#`%w#`#a5]#a#o%wR5dSoQRP}!O%w!c!}%w#R#S%w#T#o%wR5uURP}!O%w!c!}%w#R#S%w#T#f%w#f#g6X#g#o%wR6^URP}!O%w!c!}%w#R#S%w#T#W%w#W#X6p#X#o%wR6uURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y7X#Y#o%wR7^URP}!O%w!c!}%w#R#S%w#T#f%w#f#g7p#g#o%wR7wS}QRP}!O%w!c!}%w#R#S%w#T#o%wR8YURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y8l#Y#o%wR8qURP}!O%w!c!}%w#R#S%w#T#b%w#b#c9T#c#o%wR9YURP}!O%w!c!}%w#R#S%w#T#W%w#W#X9l#X#o%wR9qURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y:T#Y#o%wR:YURP}!O%w!c!}%w#R#S%w#T#f%w#f#g:l#g#o%wR:sS!UQRP}!O%w!c!}%w#R#S%w#T#o%wR;UURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y;h#Y#o%wR;mURP}!O%w!c!}%w#R#S%w#T#`%w#`#a<P#a#o%wR<UURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y<h#Y#o%wR<mURP}!O%w!c!}%w#R#S%w#T#V%w#V#W=P#W#o%wR=UURP}!O%w!c!}%w#R#S%w#T#h%w#h#i=h#i#o%wR=oS!SQRP}!O%w!c!}%w#R#S%w#T#o%wR>QURP}!O%w!c!}%w#R#S%w#T#f%w#f#g>d#g#o%wR>iURP}!O%w!c!}%w#R#S%w#T#i%w#i#j>{#j#o%wR?QURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y?d#Y#o%wR?kSmQRP}!O%w!c!}%w#R#S%w#T#o%wR?|URP}!O%w!c!}%w#R#S%w#T#[%w#[#]@`#]#o%wR@eURP}!O%w!c!}%w#R#S%w#T#X%w#X#Y@w#Y#o%wR@|URP}!O%w!c!}%w#R#S%w#T#f%w#f#gA`#g#o%wRAeURP}!O%w!c!}%w#R#S%w#T#X%w#X#YAw#Y#o%wRBOSkQRP}!O%w!c!}%w#R#S%w#T#o%w",
tokenizers: [0, 1],
topRules: {"Program":[0,1]},
tokenPrec: 0

View File

@ -18,4 +18,5 @@ export const
Order = 16,
LimitClause = 17,
SelectClause = 18,
RenderClause = 19
RenderClause = 19,
PageRef = 20

View File

@ -84,7 +84,10 @@ export function parseQuery(query: string): ParsedQuery {
let renderNode = findNodeOfType(queryNode, "RenderClause");
if (renderNode) {
let renderNameNode = findNodeOfType(renderNode, "String");
let renderNameNode = findNodeOfType(renderNode, "PageRef");
if (!renderNameNode) {
renderNameNode = findNodeOfType(renderNode, "String");
}
parsedQuery.render = valueNodeToVal(renderNameNode!);
}

View File

@ -12,7 +12,7 @@ WhereClause { "where" LogicalExpr }
OrderClause { "order" "by" Name Order? }
LimitClause { "limit" Number }
SelectClause { "select" commaSep<Name> }
RenderClause { "render" String }
RenderClause { "render" (PageRef | String) }
Order {
"desc" | "asc"
@ -56,6 +56,9 @@ Null {
String {
("\"" | "“" | "”") ![\"”“]* ("\"" | "“" | "”")
}
PageRef {
"[" "[" ![\]]* "]" "]"
}
Regex { "/" ( ![/\\\n\r] | "\\" _ )* "/"? }
Number { std.digit+ }

View File

@ -8,15 +8,9 @@ import {
export const queryRegex =
/(<!--\s*#query\s+(.+?)-->)(.+?)(<!--\s*\/query\s*-->)/gs;
export const queryStartRegex = /<!--\s*#query\s+(.+?)-->/s;
export const directiveStartRegex = /<!--\s*#([\w\-]+)\s+(.+?)-->/s;
export const queryEndRegex = /<!--\s*\/query\s*-->/s;
// export function whiteOutQueries(text: string): string {
// return text.replaceAll(queryRegex, (match) =>
// new Array(match.length + 1).join(" ")
// );
// }
export const directiveEndRegex = /<!--\s*\/([\w\-]+)\s*-->/s;
export function removeQueries(pt: ParseTree) {
addParentPointers(pt);
@ -25,9 +19,11 @@ export function removeQueries(pt: ParseTree) {
return false;
}
let text = t.children![0].text!;
if (!queryStartRegex.exec(text)) {
let match = directiveStartRegex.exec(text);
if (!match) {
return false;
}
let directiveType = match[1];
let parentChildren = t.parent!.children!;
let index = parentChildren.indexOf(t);
let nodesToReplace: ParseTree[] = [];
@ -35,7 +31,8 @@ export function removeQueries(pt: ParseTree) {
let n = parentChildren[i];
if (n.type === "CommentBlock") {
let text = n.children![0].text!;
if (queryEndRegex.exec(text)) {
let match = directiveEndRegex.exec(text);
if (match && match[1] === directiveType) {
break;
}
}

View File

@ -1,10 +1,18 @@
An attempt at documenting of the changes/new features introduced in each (pre) release.
## 0.0.31
* Update to the query language: the `render` clause now uses page reference syntax `[[page]]`. For example `render [[template/task]]` rather than `render "template/task"`. The old syntax still works, but is deprecated, completion for the old syntax has been removed.
* Updates to templates:
* For the `Template: Instantiate Page` command, the page meta value `PAGENAME` is now used to configure the page name (was `name` before). Also if `PAGENAME` is the only page meta defined, it will remove the page meta entirely when instantiating.
* For the `Template: Instantiate Page` command, the page meta value `$name` is now used to configure the page name (was `name` before). Also if `$name` is the only page meta defined, it will remove the page meta entirely when instantiating.
* You can now configure a daily note prefix with `dailyNotePrefix` in `SETTINGS` and create a template for your daily note under `template/page/Daily Note` (configurable via the `dailyNoteTemplate` setting).
* You can now a quick note prefix with `quickNotePrefix` in `SETTINGS`.
* Directives (e.g. `#query`, `#import`, `#inject`) changes:
* Renamed `#template` directive to `#inject`
* New `#inject-clean` directive will clean all the embedded queries and templates in its scope
* All directives now use the page reference syntax `[[page name]]` instead of `"page name"`, this includes `#inject` and `#inject-clean` as well as `#import`.
* The `link` query provider now also returns the `pos` of a link (in addition to the `page`)
* New `$disableDirectives` page meta data attribute can be used to disable directives processing in a page (useful for templates)
* Added a new `/hr` slash command to insert a horizontal rule (`---`) useful for mobile devices (where these are harder to type)
## 0.0.30
* Slash commands now only trigger after a non-word character to avoid "false positives" like "hello/world".

View File

@ -37,7 +37,7 @@ What type of extensions, you ask? Let us demonstrate this in a very meta way: by
Heres a list of (non-built in) plugs documented in this space (note the `#query` ... `/query` notation used):
<!-- #query page where type = "plug" order by name render "template/plug" -->
<!-- #query page where type = "plug" order by name render [[template/plug]] -->
* [[🔌 Backlinks]] by **Guillermo Vayá** ([repo](https://github.com/Willyfrog/silverbullet-backlinks))
* [[🔌 Ghost]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-ghost))
* [[🔌 Git]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-github))

View File

@ -16,14 +16,14 @@ Page templates, by default, are looked for in the `template/page/` prefix. So cr
Page template have one “magic” type of page meta data that is used during instantiation:
* `PAGENAME` is used as a default value for a new page based on this template
* `$name` is used as a default value for a new page based on this template
In addition, any standard template placeholders are available (see below)
For instance:
```meta
PAGENAME: "📕 "
$name: "📕 "
```
# {{page}}
@ -45,7 +45,7 @@ Will prompt you to pick a page name (defaulting to “📕 “), and then create
### Snippets
Snippets are similar to page templates, except you insert them into an existing page with the `/snippet` slash command. The default prefix is `snippet/` which is configurable via the `snippetPrefix` setting in `SETTINGS`.
Snippet templates do not support the `PAGENAME` page meta, because it doesnt apply.
Snippet templates do not support the `$name` page meta, because it doesnt apply.
However, snippets do support the special `|^|` placeholder for placing the cursor caret after injecting the snippet. If you leave it out, the cursor will simply be placed at the end, but if you like to insert the cursor elsewhere, that position can be set with the `|^|` placeholder.

View File

@ -4,7 +4,7 @@ uri: github:silverbulletmd/silverbullet-github/github.plug.json
repo: https://github.com/silverbulletmd/silverbullet-github
author: Zef Hemel
```
<!-- #include "https://raw.githubusercontent.com/silverbulletmd/silverbullet-github/main/README.md" -->
<!-- #include [[https://raw.githubusercontent.com/silverbulletmd/silverbullet-github/main/README.md]] -->
# SilverBullet plug for Github
Provides Github events, notifications and pull requests as query sources using SB's query mechanism
@ -44,7 +44,7 @@ Example uses:
<!-- /query -->
## Recent PRs
<!-- #query gh-pull where repo = "silverbulletmd/silverbullet" and user_login = "zefhemel" limit 3 render "template/gh-pull" -->
<!-- #query gh-pull where repo = "silverbulletmd/silverbullet" and user_login = "zefhemel" limit 3 render [[template/gh-pull]] -->
<!-- /query -->

View File

@ -3,7 +3,7 @@ Silver Bullet at its core is bare bones in terms of functionality, most of its p
Plugs are an extension mechanism (implemented using a library called `plugos` that runs plug code on the server in a sandboxed v8 node.js process, and in the browser using web workers). Plugs can hook into SB in various ways: plugs can extend the Markdown parser and its syntax, define new commands and keybindings, respond to various events triggered either on the server or client side, as well as run recurring and background tasks. Plugs can even define their own extension mechanisms through custom events. Each plug runs in its own sandboxed environment and communicates with SB via _syscalls_ that expose a vast range of functionality. Plugs can be loaded, unloaded and updated without having to restart SB itself.
## Directory
<!-- #query page where type = "plug" order by name render "template/plug" -->
<!-- #query page where type = "plug" order by name render [[template/plug]] -->
* [[🔌 Backlinks]] by **Guillermo Vayá** ([repo](https://github.com/Willyfrog/silverbullet-backlinks))
* [[🔌 Ghost]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-ghost))
* [[🔌 Git]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-github))

View File

@ -64,10 +64,10 @@ city: Berlin
country: Germany
```
<!-- #query data where age > 20 and country = "Italy" -->
|name|age|city |country|page |pos |
|----|--|-----|-----|---------------|----|
|John|50|Milan|Italy|🔌 Query |2198|
|Jane|53|Rome |Italy|🔌 Query |2244|
|name|age|city |country|page |pos |
|----|--|-----|-----|--------|----|
|John|50|Milan|Italy|🔌 Query|2277|
|Jane|53|Rome |Italy|🔌 Query|2323|
<!-- /query -->
#### 4.2 Plugs data sources
@ -89,18 +89,18 @@ For the sake of simplicity, we will use `page` data source and limit the results
**Result:** Look at the data. This is more than we need. The query even gives us template pages. Lets try to limit it in the next step.
<!-- #query page limit 10 -->
|name |lastModified |perm|tags |type|uri |repo |author |
|name |lastModified |perm|tags |type|uri |repo |author |
|--|--|--|--|--|--|--|--|
|index |1659178324000|rw|undefined|undefined|undefined |undefined |undefined |
|Mattermost Plugin|1659108035000|rw|undefined|undefined|undefined |undefined |undefined |
|PLUGS |1659108634000|rw|undefined|undefined|undefined |undefined |undefined |
|Test Data Query |1659179547000|rw|undefined|undefined|undefined |undefined |undefined |
|template/plug |1659108035000|rw|undefined|undefined|undefined |undefined |undefined |
|template/tasks |1659108035000|rw|#each|undefined|undefined |undefined |undefined |
|💡 Inspiration |1659108035000|rw|undefined|undefined|undefined |undefined |undefined |
|🔌 Backlinks |1659108035000|rw|undefined|plug|ghr:Willyfrog/silverbullet-backlinks |https://github.com/Willyfrog/silverbullet-backlinks |Guillermo Vayá|
|🔌 Ghost |1659108035000|rw|undefined|plug|github:silverbulletmd/silverbullet-ghost/ghost.plug.json |https://github.com/silverbulletmd/silverbullet-ghost |Zef Hemel |
|🔌 Git |1659108035000|rw|undefined|plug|github:silverbulletmd/silverbullet-github/github.plug.json|https://github.com/silverbulletmd/silverbullet-github|Zef Hemel |
|SETTINGS |1659437160849|rw|undefined|undefined|undefined |undefined |undefined |
|Silver Bullet |1660051168973|rw|undefined|undefined|undefined |undefined |undefined |
|CHANGELOG |1660050383951|rw|undefined|undefined|undefined |undefined |undefined |
|Mattermost Plugin|1658755340866|rw|undefined|undefined|undefined |undefined |undefined |
|PLUGS |1659437423367|rw|undefined|undefined|undefined |undefined |undefined |
|index |1659440751554|rw|undefined|undefined|undefined |undefined |undefined |
|template/plug |1658751100952|rw|undefined|undefined|undefined |undefined |undefined |
|template/tasks |1657890041936|rw|#each|undefined|undefined |undefined |undefined |
|💡 Inspiration |1658133917441|rw|undefined|undefined|undefined |undefined |undefined |
|🔌 Backlinks |1658760465195|rw|undefined|plug|ghr:Willyfrog/silverbullet-backlinks|https://github.com/Willyfrog/silverbullet-backlinks|Guillermo Vayá|
<!-- /query -->
#### 5.2 Simple query with a condition
@ -109,13 +109,13 @@ For the sake of simplicity, we will use `page` data source and limit the results
**Result:** Okay, this what we wanted but there are also information such as perm, type and lastModified that we don't need.
<!-- #query page where type = "plug" order by lastModified desc limit 5 -->
|name |lastModified |perm|type|uri |repo |author |
|name |lastModified |perm|type|uri |repo |author |
|--|--|--|--|--|--|--|
|🔌 Query |1659194185345|rw|plug|core:query |https://github.com/silverbulletmd/silverbullet |Silver Bullet Authors|
|🔌 Mattermost|1659111156000|rw|plug|github:silverbulletmd/silverbullet-mattermost/mattermost.plug.json|https://github.com/silverbulletmd/silverbullet-mattermost|Zef Hemel |
|🔌 Backlinks |1659108035000|rw|plug|ghr:Willyfrog/silverbullet-backlinks |https://github.com/Willyfrog/silverbullet-backlinks |Guillermo Vayá |
|🔌 Ghost |1659108035000|rw|plug|github:silverbulletmd/silverbullet-ghost/ghost.plug.json |https://github.com/silverbulletmd/silverbullet-ghost |Zef Hemel |
|🔌 Git |1659108035000|rw|plug|github:silverbulletmd/silverbullet-github/github.plug.json |https://github.com/silverbulletmd/silverbullet-github |Zef Hemel |
|🔌 Query |1660051209241|rw|plug|core:query |https://github.com/silverbulletmd/silverbullet |Silver Bullet Authors|
|🔌 Github|1660050280511|rw|plug|github:silverbulletmd/silverbullet-github/github.plug.json|https://github.com/silverbulletmd/silverbullet-github|Zef Hemel |
|🔌 Mount |1658760601369|rw|plug|github:silverbulletmd/silverbullet-mount/mount.plug.json |https://github.com/silverbulletmd/silverbullet-mount |Zef Hemel |
|🔌 Git |1658760545612|rw|plug|github:silverbulletmd/silverbullet-github/github.plug.json|https://github.com/silverbulletmd/silverbullet-github|Zef Hemel |
|🔌 Ghost |1658760515320|rw|plug|github:silverbulletmd/silverbullet-ghost/ghost.plug.json |https://github.com/silverbulletmd/silverbullet-ghost |Zef Hemel |
<!-- /query -->
@ -125,13 +125,13 @@ For the sake of simplicity, we will use `page` data source and limit the results
**Result:** Okay, this is much better. However, I believe this needs a touch from a visual perspective.
<!-- #query page select name author repo uri where type = "plug" order by lastModified desc limit 5 -->
|name |author |repo |
|name |author |repo |
|--|--|--|
|🔌 Query |Silver Bullet Authors|https://github.com/silverbulletmd/silverbullet |
|🔌 Mattermost|Zef Hemel |https://github.com/silverbulletmd/silverbullet-mattermost|
|🔌 Backlinks |Guillermo Vayá |https://github.com/Willyfrog/silverbullet-backlinks |
|🔌 Ghost |Zef Hemel |https://github.com/silverbulletmd/silverbullet-ghost |
|🔌 Git |Zef Hemel |https://github.com/silverbulletmd/silverbullet-github |
|🔌 Query |Silver Bullet Authors|https://github.com/silverbulletmd/silverbullet |
|🔌 Github|Zef Hemel |https://github.com/silverbulletmd/silverbullet-github|
|🔌 Mount |Zef Hemel |https://github.com/silverbulletmd/silverbullet-mount |
|🔌 Git |Zef Hemel |https://github.com/silverbulletmd/silverbullet-github|
|🔌 Ghost |Zef Hemel |https://github.com/silverbulletmd/silverbullet-ghost |
<!-- /query -->
#### 5.4 Display the data in a format defined by a template
@ -140,21 +140,21 @@ For the sake of simplicity, we will use `page` data source and limit the results
**Result:** Here you go. This is the result we would like to achieve 🎉. Did you see how I used `render` and `template/plug` in a query? 🚀
<!-- #query page select name author repo uri where type = "plug" order by lastModified desc limit 5 render "template/plug" -->
<!-- #query page select name author repo uri where type = "plug" order by lastModified desc limit 5 render [[template/plug]] -->
* [[🔌 Query]] by **Silver Bullet Authors** ([repo](https://github.com/silverbulletmd/silverbullet))
* [[🔌 Mattermost]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-mattermost))
* [[🔌 Backlinks]] by **Guillermo Vayá** ([repo](https://github.com/Willyfrog/silverbullet-backlinks))
* [[🔌 Ghost]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-ghost))
* [[🔌 Github]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-github))
* [[🔌 Mount]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-mount))
* [[🔌 Git]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-github))
* [[🔌 Ghost]] by **Zef Hemel** ([repo](https://github.com/silverbulletmd/silverbullet-ghost))
<!-- /query -->
PS: You don't need select only certain fields to use templates. Templates are smart enough to get only the information needed to render the data.
Therefore, following queries are same in terms of end result when using the templates.
```yaml
<!-- #query page select name author repo uri where type = "plug" order by lastModified desc limit 5 render "template/plug" -->
<!-- #query page select name author repo uri where type = "plug" order by lastModified desc limit 5 render [[template/plug]] -->
```
```yaml
<!-- #query page where type = "plug" order by lastModified desc limit 5 render "template/plug" -->
<!-- #query page where type = "plug" order by lastModified desc limit 5 render [[template/plug]] -->
```