Template syntax refactor
parent
1bbfbe19e2
commit
7f6e608460
|
@ -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:
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: [],
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -18,4 +18,5 @@ export const
|
|||
Order = 16,
|
||||
LimitClause = 17,
|
||||
SelectClause = 18,
|
||||
RenderClause = 19
|
||||
RenderClause = 19,
|
||||
PageRef = 20
|
||||
|
|
|
@ -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!);
|
||||
}
|
||||
|
||||
|
|
|
@ -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+ }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -37,7 +37,7 @@ What type of extensions, you ask? Let us demonstrate this in a very meta way: by
|
|||
|
||||
Here’s 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))
|
||||
|
|
|
@ -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 doesn’t apply.
|
||||
Snippet templates do not support the `$name` page meta, because it doesn’t 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.
|
||||
|
||||
|
|
|
@ -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 -->
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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]] -->
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue