1
0

Changed all indexes to use (pre) parsed trees.

This commit is contained in:
Zef Hemel 2022-04-20 10:56:43 +02:00
parent c7176b00fa
commit dbdfc9d631
26 changed files with 264 additions and 167 deletions

View File

@ -45,9 +45,9 @@ export class EventedSpacePrimitives implements SpacePrimitives {
this.eventHook this.eventHook
.dispatchEvent("page:saved", pageName) .dispatchEvent("page:saved", pageName)
.then(() => { .then(() => {
return this.eventHook.dispatchEvent("page:index", { return this.eventHook.dispatchEvent("page:index_text", {
name: pageName, name: pageName,
text: text, text,
}); });
}) })
.catch((e) => { .catch((e) => {

View File

@ -13,6 +13,10 @@ export function addParentPointers(tree: ParseTree) {
return; return;
} }
for (let child of tree.children) { for (let child of tree.children) {
if (child.parent) {
// Already added parent pointers before
return;
}
child.parent = tree; child.parent = tree;
addParentPointers(child); addParentPointers(child);
} }

View File

@ -6,13 +6,18 @@ export async function dispatch(
timeout?: number timeout?: number
): Promise<any[]> { ): Promise<any[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let timeOut = setTimeout(() => { let timeouter: any = -1;
console.log("Timeout!"); if (timeout) {
reject("timeout"); timeouter = setTimeout(() => {
}, timeout); console.log("Timeout!");
reject("timeout");
}, timeout);
}
syscall("event.dispatch", eventName, data) syscall("event.dispatch", eventName, data)
.then((r) => { .then((r) => {
clearTimeout(timeOut); if (timeouter !== -1) {
clearTimeout(timeouter);
}
resolve(r); resolve(r);
}) })
.catch(reject); .catch(reject);

View File

@ -29,6 +29,10 @@ functions:
path: ./page.ts:pageQueryProvider path: ./page.ts:pageQueryProvider
events: events:
- query:page - query:page
parseIndexTextRepublish:
path: "./page.ts:parseIndexTextRepublish"
events:
- page:index_text
indexLinks: indexLinks:
path: "./page.ts:indexLinks" path: "./page.ts:indexLinks"
events: events:

View File

@ -1,30 +1,9 @@
import { insertAtCursor } from "plugos-silverbullet-syscall/editor"; import { insertAtCursor } from "plugos-silverbullet-syscall/editor";
import { IndexEvent } from "../../webapp/app_event";
import { batchSet } from "plugos-silverbullet-syscall";
import { whiteOutQueries } from "../query/util";
const dateMatchRegex = /(\d{4}\-\d{2}\-\d{2})/g; const dateMatchRegex = /(\d{4}\-\d{2}\-\d{2})/g;
// Index key space:
// d:[date]:page@pos
export async function indexDates({ name, text }: IndexEvent) {
let dates: { key: string; value: boolean }[] = [];
text = whiteOutQueries(text);
console.log("Now date indexing", name);
for (let match of text.matchAll(dateMatchRegex)) {
// console.log("Date match", match[0]);
dates.push({
key: `d:${match[0]}:${name}@${match.index}`,
value: true,
});
}
console.log("Found", dates.length, "dates");
await batchSet(name, dates);
}
export function niceDate(d: Date): string { export function niceDate(d: Date): string {
return new Date().toISOString().split("T")[0]; return d.toISOString().split("T")[0];
} }
export async function insertToday() { export async function insertToday() {

View File

@ -1,9 +1,8 @@
import { IndexEvent } from "../../webapp/app_event"; import { IndexTreeEvent } from "../../webapp/app_event";
import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall/index"; import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall/index";
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
import { collectNodesOfType, ParseTree, renderToText } from "../../common/tree"; import { collectNodesOfType, ParseTree, renderToText } from "../../common/tree";
import { whiteOutQueries } from "../query/util"; import { removeQueries } from "../query/util";
import { applyQuery, QueryProviderEvent } from "../query/engine"; import { applyQuery, QueryProviderEvent } from "../query/engine";
export type Item = { export type Item = {
@ -14,14 +13,13 @@ export type Item = {
pos?: number; pos?: number;
}; };
export async function indexItems({ name, text }: IndexEvent) { export async function indexItems({ name, tree }: IndexTreeEvent) {
let items: { key: string; value: Item }[] = []; let items: { key: string; value: Item }[] = [];
text = whiteOutQueries(text); removeQueries(tree);
console.log("Indexing items", name); console.log("Indexing items", name);
let mdTree = await parseMarkdown(text);
let coll = collectNodesOfType(mdTree, "ListItem"); let coll = collectNodesOfType(tree, "ListItem");
coll.forEach((n) => { coll.forEach((n) => {
if (!n.children) { if (!n.children) {

View File

@ -1,4 +1,4 @@
import { IndexEvent } from "../../webapp/app_event"; import { IndexEvent, IndexTreeEvent } from "../../webapp/app_event";
import { import {
batchSet, batchSet,
clearPageIndex as clearPageIndexSyscall, clearPageIndex as clearPageIndexSyscall,
@ -28,23 +28,20 @@ import {
import { applyQuery, QueryProviderEvent } from "../query/engine"; import { applyQuery, QueryProviderEvent } from "../query/engine";
import { PageMeta } from "../../common/types"; import { PageMeta } from "../../common/types";
export async function indexLinks({ name, text }: IndexEvent) { export async function indexLinks({ name, tree }: IndexTreeEvent) {
let backLinks: { key: string; value: string }[] = []; let backLinks: { key: string; value: string }[] = [];
// [[Style Links]] // [[Style Links]]
console.log("Now indexing", name); console.log("Now indexing", name);
let mdTree = await parseMarkdown(text); collectNodesMatching(tree, (n) => n.type === "WikiLinkPage").forEach((n) => {
collectNodesMatching(mdTree, (n) => n.type === "WikiLinkPage").forEach( let toPage = n.children![0].text!;
(n) => { if (toPage.includes("@")) {
let toPage = n.children![0].text!; toPage = toPage.split("@")[0];
if (toPage.includes("@")) {
toPage = toPage.split("@")[0];
}
backLinks.push({
key: `pl:${toPage}:${n.from}`,
value: name,
});
} }
); backLinks.push({
key: `pl:${toPage}:${n.from}`,
value: name,
});
});
console.log("Found", backLinks.length, "wiki link(s)"); console.log("Found", backLinks.length, "wiki link(s)");
await batchSet(name, backLinks); await batchSet(name, backLinks);
} }
@ -193,10 +190,11 @@ export async function reindexSpace() {
let pages = await listPages(); let pages = await listPages();
for (let { name } of pages) { for (let { name } of pages) {
console.log("Indexing", name); console.log("Indexing", name);
const pageObj = await readPage(name); const { text } = await readPage(name);
let parsed = await parseMarkdown(text);
await dispatch("page:index", { await dispatch("page:index", {
name, name,
text: pageObj.text, tree: parsed,
}); });
} }
} }
@ -206,6 +204,13 @@ export async function clearPageIndex(page: string) {
await clearPageIndexForPage(page); await clearPageIndexForPage(page);
} }
export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
await dispatch("page:index", {
name,
tree: await parseMarkdown(text),
});
}
export async function parseServerPageCommand() { export async function parseServerPageCommand() {
console.log(await invokeFunction("server", "parsePage", await getText())); console.log(await invokeFunction("server", "parsePage", await getText()));
} }

View File

@ -4,7 +4,6 @@ import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
import { extractMeta } from "../query/data"; import { extractMeta } from "../query/data";
import { renderToText } from "../../common/tree"; import { renderToText } from "../../common/tree";
import { niceDate } from "./dates"; import { niceDate } from "./dates";
import { dispatch } from "plugos-syscall/event";
import { invokeFunction } from "plugos-silverbullet-syscall/system"; import { invokeFunction } from "plugos-silverbullet-syscall/system";
const pageTemplatePrefix = `template/page/`; const pageTemplatePrefix = `template/page/`;
@ -60,17 +59,17 @@ export async function replaceTemplateVarsCommand() {
export function replaceTemplateVars(s: string, pageName: string): string { export function replaceTemplateVars(s: string, pageName: string): string {
return s.replaceAll(/\{\{([^\}]+)\}\}/g, (match, v) => { return s.replaceAll(/\{\{([^\}]+)\}\}/g, (match, v) => {
if (v === "today") { switch (v) {
return niceDate(new Date()); case "today":
} return niceDate(new Date());
if (v.startsWith("placeholder:")) { case "yesterday":
// Dispatch event, to be replaced in the file async later let yesterday = new Date();
dispatch(v, { yesterday.setDate(yesterday.getDate() - 1);
pageName: pageName, return niceDate(yesterday);
placeholder: v, case "lastWeek":
}).catch((e) => { let lastWeek = new Date();
console.error("Failed to dispatch placeholder event", e); lastWeek.setDate(lastWeek.getDate() - 7);
}); return niceDate(lastWeek);
} }
return match; return match;
}); });

View File

@ -15,6 +15,24 @@ body {
padding-right: 20px; padding-right: 20px;
} }
table {
width: 100%;
border-spacing: 0;
}
thead tr {
background-color: #333;
color: #eee;
}
th, td {
padding: 8px;
}
tbody tr:nth-of-type(even) {
background-color: #f3f3f3;
}
a[href] { a[href] {
text-decoration: none; text-decoration: none;
} }

View File

@ -1,11 +1,12 @@
import { readPage } from "plugos-silverbullet-syscall/space"; import { readPage } from "plugos-silverbullet-syscall/space";
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown"; import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
import { extractMeta } from "../query/data"; import { extractMeta } from "../query/data";
import { UserProfile } from "@hmhealey/types/lib/users";
import { json } from "plugos-syscall/fetch"; import { json } from "plugos-syscall/fetch";
import { Post } from "@hmhealey/types/lib/posts"; import type { UserProfile } from "@mattermost/types/lib/users";
import { Channel } from "@hmhealey/types/lib/channels"; import type { Post } from "@mattermost/types/lib/posts";
import { Team } from "@hmhealey/types/lib/teams"; import type { Channel } from "@mattermost/types/lib/channels";
import type { Team } from "@mattermost/types/lib/teams";
import { niceDate } from "../core/dates";
type MattermostConfig = { type MattermostConfig = {
url: string; url: string;
@ -19,6 +20,13 @@ async function getConfig(): Promise<MattermostConfig> {
return pageMeta as MattermostConfig; return pageMeta as MattermostConfig;
} }
type AugmentedPost = Post & {
// Dates we can use to filter
createdAt: string;
updatedAt: string;
editedAt: string;
};
export class MattermostClient { export class MattermostClient {
userCache = new Map<string, UserProfile>(); userCache = new Map<string, UserProfile>();
channelCache = new Map<string, Channel>(); channelCache = new Map<string, Channel>();
@ -77,7 +85,10 @@ export class MattermostClient {
return team!; return team!;
} }
async getFlaggedPosts(userId: string, perPage: number = 10): Promise<Post[]> { async getFlaggedPosts(
userId: string,
perPage: number = 10
): Promise<AugmentedPost[]> {
let postCollection = await json( let postCollection = await json(
`${this.url}/api/v4/users/${userId}/posts/flagged?per_page=${perPage}`, `${this.url}/api/v4/users/${userId}/posts/flagged?per_page=${perPage}`,
{ {
@ -86,10 +97,24 @@ export class MattermostClient {
}, },
} }
); );
let posts: Post[] = []; let posts: AugmentedPost[] = [];
for (let order of postCollection.order) { for (let order of postCollection.order) {
posts.push(postCollection.posts[order]); let post = postCollection.posts[order];
augmentPost(post);
posts.push(post);
} }
return posts; return posts;
} }
} }
function augmentPost(post: AugmentedPost) {
if (post.create_at) {
post.createdAt = niceDate(new Date(post.create_at));
}
if (post.update_at) {
post.updatedAt = niceDate(new Date(post.update_at));
}
if (post.edit_at) {
post.editedAt = niceDate(new Date(post.edit_at));
}
}

View File

@ -20,17 +20,16 @@ export async function savedPostsQueryProvider({
let savedPostsMd = []; let savedPostsMd = [];
savedPosts = applyQuery(query, savedPosts); savedPosts = applyQuery(query, savedPosts);
for (let savedPost of savedPosts) { for (let savedPost of savedPosts) {
// savedPost.
let channel = await client.getChannel(savedPost.channel_id); let channel = await client.getChannel(savedPost.channel_id);
let team = await client.getTeam(channel.team_id); let team = await client.getTeam(channel.team_id);
savedPostsMd.push( savedPostsMd.push(
`@${ `@${(await client.getUser(savedPost.user_id)).username} [${
(await client.getUser(savedPost.user_id)).username savedPost.createdAt
} [link](${mattermostDesktopUrlForPost( }](${mattermostDesktopUrlForPost(
client.url, client.url,
team.name, team.name,
savedPost.id savedPost.id
)}):\n> ${savedPost.message.replaceAll(/\n/g, "\n> ")}` )}):\n> ${savedPost.message.substring(0, 1000).replaceAll(/\n/g, "\n> ")}`
); );
} }
return savedPostsMd.join("\n\n"); return savedPostsMd.join("\n\n");

View File

@ -8,10 +8,10 @@
"name": "plugs", "name": "plugs",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@hmhealey/types": "^6.6.0-4",
"@jest/globals": "^27.5.1", "@jest/globals": "^27.5.1",
"@lezer/generator": "^0.15.4", "@lezer/generator": "^0.15.4",
"@lezer/lr": "^0.15.8", "@lezer/lr": "^0.15.8",
"@mattermost/types": "^6.7.0-0",
"@types/yaml": "^1.9.7", "@types/yaml": "^1.9.7",
"plugos-silverbullet-syscall": "file:../plugos-silverbullet-syscall", "plugos-silverbullet-syscall": "file:../plugos-silverbullet-syscall",
"plugos-syscall": "file:../plugos-syscall", "plugos-syscall": "file:../plugos-syscall",
@ -120,19 +120,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/@hmhealey/types": {
"version": "6.6.0-4",
"resolved": "https://registry.npmjs.org/@hmhealey/types/-/types-6.6.0-4.tgz",
"integrity": "sha512-71IxVaXhrUesmLnvQQh4RtUqqhmVL+ejci4qo4R6rTWTdY77BniRtBx269uAz34wzTlAgITysN8x7MBTdt/XBg==",
"peerDependencies": {
"typescript": "^4.3"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@jest/environment": { "node_modules/@jest/environment": {
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz",
@ -216,6 +203,19 @@
"@lezer/common": "^0.15.0" "@lezer/common": "^0.15.0"
} }
}, },
"node_modules/@mattermost/types": {
"version": "6.7.0-0",
"resolved": "https://registry.npmjs.org/@mattermost/types/-/types-6.7.0-0.tgz",
"integrity": "sha512-mT8wJwWEp20KPo9D12y7bW7EdUHO7VhUHxr3gH8nPGapWooGcl0Ra0H3u1iCjPpqPWvp7LiodcneU0IysunYKQ==",
"peerDependencies": {
"typescript": "^4.3"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@sinonjs/commons": { "node_modules/@sinonjs/commons": {
"version": "1.8.3", "version": "1.8.3",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
@ -697,12 +697,6 @@
} }
} }
}, },
"@hmhealey/types": {
"version": "6.6.0-4",
"resolved": "https://registry.npmjs.org/@hmhealey/types/-/types-6.6.0-4.tgz",
"integrity": "sha512-71IxVaXhrUesmLnvQQh4RtUqqhmVL+ejci4qo4R6rTWTdY77BniRtBx269uAz34wzTlAgITysN8x7MBTdt/XBg==",
"requires": {}
},
"@jest/environment": { "@jest/environment": {
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz",
@ -771,6 +765,12 @@
"@lezer/common": "^0.15.0" "@lezer/common": "^0.15.0"
} }
}, },
"@mattermost/types": {
"version": "6.7.0-0",
"resolved": "https://registry.npmjs.org/@mattermost/types/-/types-6.7.0-0.tgz",
"integrity": "sha512-mT8wJwWEp20KPo9D12y7bW7EdUHO7VhUHxr3gH8nPGapWooGcl0Ra0H3u1iCjPpqPWvp7LiodcneU0IysunYKQ==",
"requires": {}
},
"@sinonjs/commons": { "@sinonjs/commons": {
"version": "1.8.3", "version": "1.8.3",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",

View File

@ -5,7 +5,7 @@
"generate": "lezer-generator query/query.grammar -o query/parse-query.js" "generate": "lezer-generator query/query.grammar -o query/parse-query.js"
}, },
"dependencies": { "dependencies": {
"@hmhealey/types": "^6.6.0-4", "@mattermost/types": "^6.7.0-0",
"@jest/globals": "^27.5.1", "@jest/globals": "^27.5.1",
"@lezer/generator": "^0.15.4", "@lezer/generator": "^0.15.4",
"@lezer/lr": "^0.15.8", "@lezer/lr": "^0.15.8",

View File

@ -1,23 +1,17 @@
// Index key space: // Index key space:
// data:page@pos // data:page@pos
import { IndexEvent } from "../../webapp/app_event"; import { IndexTreeEvent } from "../../webapp/app_event";
import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall"; import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall";
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
import { collectNodesOfType, findNodeOfType, ParseTree, replaceNodesMatching } from "../../common/tree"; import { collectNodesOfType, findNodeOfType, ParseTree, replaceNodesMatching } from "../../common/tree";
import YAML, { parse as parseYaml, parseAllDocuments } from "yaml"; import YAML, { parse as parseYaml, parseAllDocuments } from "yaml";
import { whiteOutQueries } from "./util";
import type { QueryProviderEvent } from "./engine"; import type { QueryProviderEvent } from "./engine";
import { applyQuery } from "./engine"; import { applyQuery } from "./engine";
export async function indexData({ name, text }: IndexEvent) { export async function indexData({ name, tree }: IndexTreeEvent) {
text = whiteOutQueries(text);
// console.log("Now data indexing", name);
let mdTree = await parseMarkdown(text);
let dataObjects: { key: string; value: Object }[] = []; let dataObjects: { key: string; value: Object }[] = [];
collectNodesOfType(mdTree, "FencedCode").forEach((t) => { collectNodesOfType(tree, "FencedCode").forEach((t) => {
let codeInfoNode = findNodeOfType(t, "CodeInfo"); let codeInfoNode = findNodeOfType(t, "CodeInfo");
if (!codeInfoNode) { if (!codeInfoNode) {
return; return;

View File

@ -1,30 +1,18 @@
import { flashNotification, getCurrentPage, reloadPage, save } from "plugos-silverbullet-syscall/editor"; import { flashNotification, getCurrentPage, getText, reloadPage, save } from "plugos-silverbullet-syscall/editor";
import { readPage, writePage } from "plugos-silverbullet-syscall/space"; import { readPage, writePage } from "plugos-silverbullet-syscall/space";
import { invokeFunction } from "plugos-silverbullet-syscall/system"; import { invokeFunction } from "plugos-silverbullet-syscall/system";
import { parseQuery } from "./engine"; import { parseQuery } from "./engine";
import { replaceTemplateVars } from "../core/template"; import { replaceTemplateVars } from "../core/template";
import { queryRegex } from "./util"; import { queryRegex, removeQueries } from "./util";
import { dispatch } from "plugos-syscall/event"; import { dispatch } from "plugos-syscall/event";
import { replaceAsync } from "../lib/util";
async function replaceAsync( import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
str: string,
regex: RegExp,
asyncFn: (match: string, ...args: any[]) => Promise<string>
) {
const promises: Promise<string>[] = [];
str.replace(regex, (match: string, ...args: any[]): string => {
const promise = asyncFn(match, ...args);
promises.push(promise);
return "";
});
const data = await Promise.all(promises);
return str.replace(regex, () => data.shift()!);
}
export async function updateMaterializedQueriesCommand() { export async function updateMaterializedQueriesCommand() {
const currentPage = await getCurrentPage(); const currentPage = await getCurrentPage();
await save(); await save();
await flashNotification("Updating materialized queries...");
await invokeFunction( await invokeFunction(
"server", "server",
"updateMaterializedQueriesOnPage", "updateMaterializedQueriesOnPage",
@ -34,6 +22,12 @@ export async function updateMaterializedQueriesCommand() {
await flashNotification("Updated materialized queries"); await flashNotification("Updated materialized queries");
} }
export async function whiteOutQueriesCommand() {
const text = await getText();
const parsed = await parseMarkdown(text);
console.log(removeQueries(parsed));
}
// Called from client, running on server // Called from client, running on server
export async function updateMaterializedQueriesOnPage(pageName: string) { export async function updateMaterializedQueriesOnPage(pageName: string) {
let { text } = await readPage(pageName); let { text } = await readPage(pageName);
@ -49,7 +43,7 @@ export async function updateMaterializedQueriesOnPage(pageName: string) {
let results = await dispatch( let results = await dispatch(
`query:${parsedQuery.table}`, `query:${parsedQuery.table}`,
{ query: parsedQuery, pageName: pageName }, { query: parsedQuery, pageName: pageName },
5000 10 * 1000
); );
if (results.length === 0) { if (results.length === 0) {
return `${startQuery}\n${endQuery}`; return `${startQuery}\n${endQuery}`;

View File

@ -3,15 +3,19 @@ import { LRParser } from "@lezer/lr";
export const parser = LRParser.deserialize({ export const parser = LRParser.deserialize({
version: 13, version: 13,
states: "$[OVQPOOO[QQO'#C^QOQPOOOjQPO'#C`OoQQO'#CjOtQPO'#ClOOQO'#Cm'#CmOyQQO,58xO!XQPO'#CcO!sQQO'#CaOOQO'#Ca'#CaOOQO,58z,58zO#UQPO,59UOOQO,59W,59WOOQO-E6k-E6kO#ZQQO,58}OjQPO,58|O#oQQO1G.pOOQO'#Cg'#CgOOQO'#Ci'#CiOOQO'#Cd'#CdOOQO1G.i1G.iOOQO1G.h1G.hOOQO'#Ck'#CkOOQO7+$[7+$[", states:
stateData: "$T~OdOS~ORPO~OeROrSOvTObQX~ORWO~Os[O~OX]O~OeROrSOvTObQa~Of_Oj_Ok_Ol_Om_On_Oo_Op_O~Oq`ObTXeTXrTXvTX~ORaO~OXdOYdO[dOgbOhbOicO~OtgOugOb^ie^ir^iv^i~O", "$[OVQPOOO[QQO'#C^QOQPOOOjQPO'#C`OoQQO'#CjOtQPO'#ClOOQO'#Cm'#CmOyQQO,58xO!XQPO'#CcO!sQQO'#CaOOQO'#Ca'#CaOOQO,58z,58zO#UQPO,59UOOQO,59W,59WOOQO-E6k-E6kO#ZQQO,58}OjQPO,58|O#oQQO1G.pOOQO'#Cg'#CgOOQO'#Ci'#CiOOQO'#Cd'#CdOOQO1G.i1G.iOOQO1G.h1G.hOOQO'#Ck'#CkOOQO7+$[7+$[",
stateData:
"$T~OdOS~ORPO~OeROrSOvTObQX~ORWO~Os[O~OX]O~OeROrSOvTObQa~Of_Oj_Ok_Ol_Om_On_Oo_Op_O~Oq`ObTXeTXrTXvTX~ORaO~OXdOYdO[dOgbOhbOicO~OtgOugOb^ie^ir^iv^i~O",
goto: "!VbPPcPfjmpvPPyPyf|f!PRQOTUPVRZRRYRQXRRf`Re_Rd_RhaQVPR^V", goto: "!VbPPcPfjmpvPPyPyf|f!PRQOTUPVRZRRYRQXRRf`Re_Rd_RhaQVPR^V",
nodeNames: "⚠ Program Query Name WhereClause LogicalExpr AndExpr FilterExpr Value Number String Bool Regex Null OrderClause Order LimitClause", nodeNames:
"⚠ Program Query Name WhereClause LogicalExpr AndExpr FilterExpr Value Number String Bool Regex Null OrderClause Order LimitClause",
maxTerm: 38, maxTerm: 38,
skippedNodes: [0], skippedNodes: [0],
repeatNodeCount: 1, repeatNodeCount: 1,
tokenData: ":W~RvX^#ipq#iqr$^rs$q}!O%]!P!Q%n!Q![&e!^!_&m!_!`&z!`!a'X!c!}%]#R#S%]#T#U'f#U#V){#V#W%]#W#X*w#X#Y%]#Y#Z,s#Z#`%]#`#a/T#a#b%]#b#c1h#c#d3d#d#h%]#h#i5w#i#k%]#k#l7s#l#o%]#y#z#i$f$g#i#BY#BZ#i$IS$I_#i$Ip$Iq$q$Iq$Ir$q$I|$JO#i$JT$JU#i$KV$KW#i&FU&FV#i~#nYd~X^#ipq#i#y#z#i$f$g#i#BY#BZ#i$IS$I_#i$I|$JO#i$JT$JU#i$KV$KW#i&FU&FV#i~$aP!_!`$d~$iPl~#r#s$l~$qOp~~$tUOr$qrs%Ws$Ip$q$Ip$Iq%W$Iq$Ir%W$Ir~$q~%]OY~P%bSRP}!O%]!c!}%]#R#S%]#T#o%]~%sV[~OY%nZ]%n^!P%n!P!Q&Y!Q#O%n#O#P&_#P~%n~&_O[~~&bPO~%n~&jPX~!Q![&e~&rPf~!_!`&u~&zOj~~'PPk~#r#s'S~'XOo~~'^Pn~!_!`'a~'fOm~R'kWRP}!O%]!c!}%]#R#S%]#T#b%]#b#c(T#c#g%]#g#h)P#h#o%]R(YURP}!O%]!c!}%]#R#S%]#T#W%]#W#X(l#X#o%]R(sSqQRP}!O%]!c!}%]#R#S%]#T#o%]R)UURP}!O%]!c!}%]#R#S%]#T#V%]#V#W)h#W#o%]R)oSuQRP}!O%]!c!}%]#R#S%]#T#o%]R*QURP}!O%]!c!}%]#R#S%]#T#m%]#m#n*d#n#o%]R*kSsQRP}!O%]!c!}%]#R#S%]#T#o%]R*|URP}!O%]!c!}%]#R#S%]#T#X%]#X#Y+`#Y#o%]R+eURP}!O%]!c!}%]#R#S%]#T#g%]#g#h+w#h#o%]R+|URP}!O%]!c!}%]#R#S%]#T#V%]#V#W,`#W#o%]R,gStQRP}!O%]!c!}%]#R#S%]#T#o%]R,xTRP}!O%]!c!}%]#R#S%]#T#U-X#U#o%]R-^URP}!O%]!c!}%]#R#S%]#T#`%]#`#a-p#a#o%]R-uURP}!O%]!c!}%]#R#S%]#T#g%]#g#h.X#h#o%]R.^URP}!O%]!c!}%]#R#S%]#T#X%]#X#Y.p#Y#o%]R.wShQRP}!O%]!c!}%]#R#S%]#T#o%]R/YURP}!O%]!c!}%]#R#S%]#T#]%]#]#^/l#^#o%]R/qURP}!O%]!c!}%]#R#S%]#T#a%]#a#b0T#b#o%]R0YURP}!O%]!c!}%]#R#S%]#T#]%]#]#^0l#^#o%]R0qURP}!O%]!c!}%]#R#S%]#T#h%]#h#i1T#i#o%]R1[SvQRP}!O%]!c!}%]#R#S%]#T#o%]R1mURP}!O%]!c!}%]#R#S%]#T#i%]#i#j2P#j#o%]R2UURP}!O%]!c!}%]#R#S%]#T#`%]#`#a2h#a#o%]R2mURP}!O%]!c!}%]#R#S%]#T#`%]#`#a3P#a#o%]R3WSiQRP}!O%]!c!}%]#R#S%]#T#o%]R3iURP}!O%]!c!}%]#R#S%]#T#f%]#f#g3{#g#o%]R4QURP}!O%]!c!}%]#R#S%]#T#W%]#W#X4d#X#o%]R4iURP}!O%]!c!}%]#R#S%]#T#X%]#X#Y4{#Y#o%]R5QURP}!O%]!c!}%]#R#S%]#T#f%]#f#g5d#g#o%]R5kSrQRP}!O%]!c!}%]#R#S%]#T#o%]R5|URP}!O%]!c!}%]#R#S%]#T#f%]#f#g6`#g#o%]R6eURP}!O%]!c!}%]#R#S%]#T#i%]#i#j6w#j#o%]R6|URP}!O%]!c!}%]#R#S%]#T#X%]#X#Y7`#Y#o%]R7gSgQRP}!O%]!c!}%]#R#S%]#T#o%]R7xURP}!O%]!c!}%]#R#S%]#T#[%]#[#]8[#]#o%]R8aURP}!O%]!c!}%]#R#S%]#T#X%]#X#Y8s#Y#o%]R8xURP}!O%]!c!}%]#R#S%]#T#f%]#f#g9[#g#o%]R9aURP}!O%]!c!}%]#R#S%]#T#X%]#X#Y9s#Y#o%]R9zSeQRP}!O%]!c!}%]#R#S%]#T#o%]", tokenData:
":W~RvX^#ipq#iqr$^rs$q}!O%]!P!Q%n!Q![&e!^!_&m!_!`&z!`!a'X!c!}%]#R#S%]#T#U'f#U#V){#V#W%]#W#X*w#X#Y%]#Y#Z,s#Z#`%]#`#a/T#a#b%]#b#c1h#c#d3d#d#h%]#h#i5w#i#k%]#k#l7s#l#o%]#y#z#i$f$g#i#BY#BZ#i$IS$I_#i$Ip$Iq$q$Iq$Ir$q$I|$JO#i$JT$JU#i$KV$KW#i&FU&FV#i~#nYd~X^#ipq#i#y#z#i$f$g#i#BY#BZ#i$IS$I_#i$I|$JO#i$JT$JU#i$KV$KW#i&FU&FV#i~$aP!_!`$d~$iPl~#r#s$l~$qOp~~$tUOr$qrs%Ws$Ip$q$Ip$Iq%W$Iq$Ir%W$Ir~$q~%]OY~P%bSRP}!O%]!c!}%]#R#S%]#T#o%]~%sV[~OY%nZ]%n^!P%n!P!Q&Y!Q#O%n#O#P&_#P~%n~&_O[~~&bPO~%n~&jPX~!Q![&e~&rPf~!_!`&u~&zOj~~'PPk~#r#s'S~'XOo~~'^Pn~!_!`'a~'fOm~R'kWRP}!O%]!c!}%]#R#S%]#T#b%]#b#c(T#c#g%]#g#h)P#h#o%]R(YURP}!O%]!c!}%]#R#S%]#T#W%]#W#X(l#X#o%]R(sSqQRP}!O%]!c!}%]#R#S%]#T#o%]R)UURP}!O%]!c!}%]#R#S%]#T#V%]#V#W)h#W#o%]R)oSuQRP}!O%]!c!}%]#R#S%]#T#o%]R*QURP}!O%]!c!}%]#R#S%]#T#m%]#m#n*d#n#o%]R*kSsQRP}!O%]!c!}%]#R#S%]#T#o%]R*|URP}!O%]!c!}%]#R#S%]#T#X%]#X#Y+`#Y#o%]R+eURP}!O%]!c!}%]#R#S%]#T#g%]#g#h+w#h#o%]R+|URP}!O%]!c!}%]#R#S%]#T#V%]#V#W,`#W#o%]R,gStQRP}!O%]!c!}%]#R#S%]#T#o%]R,xTRP}!O%]!c!}%]#R#S%]#T#U-X#U#o%]R-^URP}!O%]!c!}%]#R#S%]#T#`%]#`#a-p#a#o%]R-uURP}!O%]!c!}%]#R#S%]#T#g%]#g#h.X#h#o%]R.^URP}!O%]!c!}%]#R#S%]#T#X%]#X#Y.p#Y#o%]R.wShQRP}!O%]!c!}%]#R#S%]#T#o%]R/YURP}!O%]!c!}%]#R#S%]#T#]%]#]#^/l#^#o%]R/qURP}!O%]!c!}%]#R#S%]#T#a%]#a#b0T#b#o%]R0YURP}!O%]!c!}%]#R#S%]#T#]%]#]#^0l#^#o%]R0qURP}!O%]!c!}%]#R#S%]#T#h%]#h#i1T#i#o%]R1[SvQRP}!O%]!c!}%]#R#S%]#T#o%]R1mURP}!O%]!c!}%]#R#S%]#T#i%]#i#j2P#j#o%]R2UURP}!O%]!c!}%]#R#S%]#T#`%]#`#a2h#a#o%]R2mURP}!O%]!c!}%]#R#S%]#T#`%]#`#a3P#a#o%]R3WSiQRP}!O%]!c!}%]#R#S%]#T#o%]R3iURP}!O%]!c!}%]#R#S%]#T#f%]#f#g3{#g#o%]R4QURP}!O%]!c!}%]#R#S%]#T#W%]#W#X4d#X#o%]R4iURP}!O%]!c!}%]#R#S%]#T#X%]#X#Y4{#Y#o%]R5QURP}!O%]!c!}%]#R#S%]#T#f%]#f#g5d#g#o%]R5kSrQRP}!O%]!c!}%]#R#S%]#T#o%]R5|URP}!O%]!c!}%]#R#S%]#T#f%]#f#g6`#g#o%]R6eURP}!O%]!c!}%]#R#S%]#T#i%]#i#j6w#j#o%]R6|URP}!O%]!c!}%]#R#S%]#T#X%]#X#Y7`#Y#o%]R7gSgQRP}!O%]!c!}%]#R#S%]#T#o%]R7xURP}!O%]!c!}%]#R#S%]#T#[%]#[#]8[#]#o%]R8aURP}!O%]!c!}%]#R#S%]#T#X%]#X#Y8s#Y#o%]R8xURP}!O%]!c!}%]#R#S%]#T#f%]#f#g9[#g#o%]R9aURP}!O%]!c!}%]#R#S%]#T#X%]#X#Y9s#Y#o%]R9zSeQRP}!O%]!c!}%]#R#S%]#T#o%]",
tokenizers: [0, 1], tokenizers: [0, 1],
topRules: {"Program":[0,1]}, topRules: { Program: [0, 1] },
tokenPrec: 0 tokenPrec: 0,
}) });

View File

@ -6,6 +6,10 @@ functions:
command: command:
name: "Materialized Queries: Update" name: "Materialized Queries: Update"
key: "Alt-q" key: "Alt-q"
whiteOutQueriesCommand:
path: ./materialized_queries.ts:whiteOutQueriesCommand
command:
name: "Debug: Whiteout Queries"
indexData: indexData:
path: ./data.ts:indexData path: ./data.ts:indexData
events: events:

View File

@ -1,8 +1,45 @@
import { addParentPointers, collectNodesMatching, ParseTree, renderToText } from "../../common/tree";
export const queryRegex = export const queryRegex =
/(<!--\s*#query\s+(.+?)-->)(.+?)(<!--\s*#end\s*-->)/gs; /(<!--\s*#query\s+(.+?)-->)(.+?)(<!--\s*#end\s*-->)/gs;
export function whiteOutQueries(text: string): string { export const queryStartRegex = /<!--\s*#query\s+(.+?)-->/s;
return text.replaceAll(queryRegex, (match) =>
new Array(match.length + 1).join(" ") export const queryEndRegex = /<!--\s*#end\s*-->/s;
);
// export function whiteOutQueries(text: string): string {
// return text.replaceAll(queryRegex, (match) =>
// new Array(match.length + 1).join(" ")
// );
// }
export function removeQueries(pt: ParseTree) {
addParentPointers(pt);
collectNodesMatching(pt, (t) => {
if (t.type !== "CommentBlock") {
return false;
}
let text = t.children![0].text!;
if (!queryStartRegex.exec(text)) {
return false;
}
let parentChildren = t.parent!.children!;
let index = parentChildren.indexOf(t);
let nodesToReplace: ParseTree[] = [];
for (let i = index + 1; i < parentChildren.length; i++) {
let n = parentChildren[i];
if (n.type === "CommentBlock") {
let text = n.children![0].text!;
if (queryEndRegex.exec(text)) {
break;
}
}
nodesToReplace.push(n);
}
let renderedText = nodesToReplace.map(renderToText).join("");
parentChildren.splice(index + 1, nodesToReplace.length, {
text: new Array(renderedText.length + 1).join(" "),
});
return true;
});
} }

View File

@ -1,4 +1,4 @@
import type { ClickEvent, IndexEvent } from "../../webapp/app_event"; import type { ClickEvent, IndexTreeEvent } from "../../webapp/app_event";
import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall/index"; import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall/index";
import { readPage, writePage } from "plugos-silverbullet-syscall/space"; import { readPage, writePage } from "plugos-silverbullet-syscall/space";
@ -11,7 +11,7 @@ import {
nodeAtPos, nodeAtPos,
renderToText renderToText
} from "../../common/tree"; } from "../../common/tree";
import { whiteOutQueries } from "../query/util"; import { removeQueries } from "../query/util";
import { applyQuery, QueryProviderEvent } from "../query/engine"; import { applyQuery, QueryProviderEvent } from "../query/engine";
export type Task = { export type Task = {
@ -24,13 +24,11 @@ export type Task = {
page?: string; page?: string;
}; };
export async function indexTasks({ name, text }: IndexEvent) { export async function indexTasks({ name, tree }: IndexTreeEvent) {
// console.log("Indexing tasks"); // console.log("Indexing tasks");
let tasks: { key: string; value: Task }[] = []; let tasks: { key: string; value: Task }[] = [];
text = whiteOutQueries(text); removeQueries(tree);
let mdTree = await parseMarkdown(text); collectNodesOfType(tree, "Task").forEach((n) => {
addParentPointers(mdTree);
collectNodesOfType(mdTree, "Task").forEach((n) => {
let task = n.children!.slice(1).map(renderToText).join("").trim(); let task = n.children!.slice(1).map(renderToText).join("").trim();
let complete = n.children![0].children![0].text! !== "[ ]"; let complete = n.children![0].children![0].text! !== "[ ]";
let value: Task = { let value: Task = {

View File

@ -23,11 +23,6 @@
"chalk" "^2.0.0" "chalk" "^2.0.0"
"js-tokens" "^4.0.0" "js-tokens" "^4.0.0"
"@hmhealey/types@^6.6.0-4":
"integrity" "sha512-71IxVaXhrUesmLnvQQh4RtUqqhmVL+ejci4qo4R6rTWTdY77BniRtBx269uAz34wzTlAgITysN8x7MBTdt/XBg=="
"resolved" "https://registry.npmjs.org/@hmhealey/types/-/types-6.6.0-4.tgz"
"version" "6.6.0-4"
"@jest/environment@^27.5.1": "@jest/environment@^27.5.1":
"integrity" "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==" "integrity" "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA=="
"resolved" "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz" "resolved" "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz"
@ -90,6 +85,11 @@
dependencies: dependencies:
"@lezer/common" "^0.15.0" "@lezer/common" "^0.15.0"
"@mattermost/types@^6.7.0-0":
"integrity" "sha512-mT8wJwWEp20KPo9D12y7bW7EdUHO7VhUHxr3gH8nPGapWooGcl0Ra0H3u1iCjPpqPWvp7LiodcneU0IysunYKQ=="
"resolved" "https://registry.npmjs.org/@mattermost/types/-/types-6.7.0-0.tgz"
"version" "6.7.0-0"
"@sinonjs/commons@^1.7.0": "@sinonjs/commons@^1.7.0":
"integrity" "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==" "integrity" "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ=="
"resolved" "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz" "resolved" "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz"

View File

@ -1,3 +1,5 @@
import type { ParseTree } from "../common/tree";
export type AppEvent = "page:click" | "page:complete"; export type AppEvent = "page:click" | "page:complete";
export type ClickEvent = { export type ClickEvent = {
@ -12,3 +14,8 @@ export type IndexEvent = {
name: string; name: string;
text: string; text: string;
}; };
export type IndexTreeEvent = {
name: string;
tree: ParseTree;
};

View File

@ -300,7 +300,6 @@ export class Editor {
closeBrackets(), closeBrackets(),
autocompletion({ autocompletion({
override: [ override: [
// this.completerHook.plugCompleter.bind(this.completerHook),
this.completer.bind(this), this.completer.bind(this),
this.slashCommandHook.slashCommandCompleter.bind( this.slashCommandHook.slashCommandCompleter.bind(
this.slashCommandHook this.slashCommandHook
@ -320,6 +319,7 @@ export class Editor {
{ selector: "Comment", class: "line-comment" }, { selector: "Comment", class: "line-comment" },
{ selector: "BulletList", class: "line-ul" }, { selector: "BulletList", class: "line-ul" },
{ selector: "OrderedList", class: "line-ol" }, { selector: "OrderedList", class: "line-ol" },
{ selector: "TableHeader", class: "line-tbl-header" },
]), ]),
keymap.of([ keymap.of([
...smartQuoteKeymap, ...smartQuoteKeymap,
@ -433,6 +433,9 @@ export class Editor {
editorView.setState( editorView.setState(
this.createEditorState(this.currentPage, editorView.state.sliceDoc()) this.createEditorState(this.currentPage, editorView.state.sliceDoc())
); );
if (editorView.contentDOM) {
editorView.contentDOM.spellcheck = true;
}
} }
} }
@ -503,6 +506,9 @@ export class Editor {
let editorState = this.createEditorState(pageName, doc.text); let editorState = this.createEditorState(pageName, doc.text);
let pageState = this.openPages.get(pageName); let pageState = this.openPages.get(pageName);
editorView.setState(editorState); editorView.setState(editorState);
if (editorView.contentDOM) {
editorView.contentDOM.spellcheck = true;
}
if (!pageState) { if (!pageState) {
pageState = new PageState(0, editorState.selection); pageState = new PageState(0, editorState.selection);
this.openPages.set(pageName, pageState!); this.openPages.set(pageName, pageState!);

View File

@ -5,17 +5,10 @@ import {
Language, Language,
languageDataProp, languageDataProp,
LanguageDescription, LanguageDescription,
ParseContext, ParseContext
} from "@codemirror/language"; } from "@codemirror/language";
import { styleTags, tags as t } from "@codemirror/highlight"; import { styleTags, tags as t } from "@codemirror/highlight";
import { import { Emoji, GFM, MarkdownParser, parser as baseParser, Subscript, Superscript } from "@lezer/markdown";
Emoji,
GFM,
MarkdownParser,
parser as baseParser,
Subscript,
Superscript,
} from "@lezer/markdown";
const data = defineLanguageFacet({ block: { open: "<!--", close: "-->" } }); const data = defineLanguageFacet({ block: { open: "<!--", close: "-->" } });
@ -37,8 +30,6 @@ export const commonmark = baseParser.configure({
"StrongEmphasis/...": t.strong, "StrongEmphasis/...": t.strong,
"Link/... Image/...": t.link, "Link/... Image/...": t.link,
"OrderedList/... BulletList/...": t.list, "OrderedList/... BulletList/...": t.list,
// "CodeBlock/... FencedCode/...": t.blockComment,
"InlineCode CodeText": t.monospace, "InlineCode CodeText": t.monospace,
URL: t.url, URL: t.url,
"HeaderMark HardBreak QuoteMark ListMark LinkMark EmphasisMark CodeMark": "HeaderMark HardBreak QuoteMark ListMark LinkMark EmphasisMark CodeMark":

View File

@ -1,5 +1,5 @@
import { styleTags } from "@codemirror/highlight"; import { styleTags, tags as t } from "@codemirror/highlight";
import { BlockContext, LeafBlock, LeafBlockParser, MarkdownConfig, parseCode, TaskList } from "@lezer/markdown"; import { BlockContext, LeafBlock, LeafBlockParser, MarkdownConfig, parseCode, Table, TaskList } from "@lezer/markdown";
import { commonmark, getCodeParser, mkLang } from "./markdown/markdown"; import { commonmark, getCodeParser, mkLang } from "./markdown/markdown";
import * as ct from "./customtags"; import * as ct from "./customtags";
import { Language, LanguageDescription, LanguageSupport } from "@codemirror/language"; import { Language, LanguageDescription, LanguageSupport } from "@codemirror/language";
@ -73,6 +73,7 @@ export default function buildMarkdown(mdExtensions: MDExt[]): Language {
WikiLink, WikiLink,
TaskList, TaskList,
Comment, Comment,
Table,
...mdExtensions.map(mdExtensionSyntaxConfig), ...mdExtensions.map(mdExtensionSyntaxConfig),
parseCode({ parseCode({
codeParser: getCodeParser([ codeParser: getCodeParser([
@ -96,6 +97,10 @@ export default function buildMarkdown(mdExtensions: MDExt[]): Language {
Task: ct.TaskTag, Task: ct.TaskTag,
TaskMarker: ct.TaskMarkerTag, TaskMarker: ct.TaskMarkerTag,
Comment: ct.CommentTag, Comment: ct.CommentTag,
"TableDelimiter SubscriptMark SuperscriptMark StrikethroughMark":
t.processingInstruction,
"TableHeader/...": t.heading,
TableCell: t.content,
}), }),
...mdExtensions.map((mdExt) => ...mdExtensions.map((mdExt) =>
styleTags(mdExtensionStyleTags(mdExt)) styleTags(mdExtensionStyleTags(mdExt))

View File

@ -36,6 +36,8 @@ export default function highlightStyles(mdExtension: MDExt[]) {
{ tag: t.variableName, class: "variableName" }, { tag: t.variableName, class: "variableName" },
{ tag: t.comment, class: "comment" }, { tag: t.comment, class: "comment" },
{ tag: t.invalid, class: "invalid" }, { tag: t.invalid, class: "invalid" },
{ tag: t.processingInstruction, class: "meta" },
// { tag: t.content, class: "tbl-content" },
{ tag: t.punctuation, class: "punctuation" }, { tag: t.punctuation, class: "punctuation" },
...mdExtension.map((mdExt) => { ...mdExtension.map((mdExt) => {
return { tag: mdExt.tag, ...mdExt.styles }; return { tag: mdExt.tag, ...mdExt.styles };

View File

@ -58,12 +58,35 @@
} }
.line-code { .line-code {
background-color: #efefef; background-color: rgba(72, 72, 72, 0.1);
margin-left: 30px;
.code {
background-color: transparent;
}
}
.line-tbl-header {
font-weight: bold;
.meta {
font-weight: normal;
}
}
.struct {
color: darkred;
}
.code {
background-color: rgba(72, 72, 72, 0.1);
} }
.line-fenced-code { .line-fenced-code {
background-color: rgba(72, 72, 72, 0.1); background-color: rgba(72, 72, 72, 0.1);
.code {
background-color: transparent;
}
} }
.meta { .meta {
@ -117,10 +140,6 @@
.code {
background-color: #efefef;
}
// Indentation of follow-up lines // Indentation of follow-up lines
@mixin lineOverflow($baseIndent) { @mixin lineOverflow($baseIndent) {
text-indent: -1 * ($baseIndent + 2ch); text-indent: -1 * ($baseIndent + 2ch);