Major directive refactor (#195)

Fixes #188 #144 #76: major refactor of directive parsing, rendering, styling
This commit is contained in:
Zef Hemel
2022-12-14 20:04:20 +01:00
committed by GitHub
parent 79e1151ee6
commit aaebea5e54
44 changed files with 656 additions and 347 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
import { commandLinkRegex } from "../../common/parser.ts";
import { commandLinkRegex } from "../../common/markdown_parser/parser.ts";
import { ClickEvent } from "$sb/app_event.ts";
import { Decoration, syntaxTree } from "../deps.ts";
import { Editor } from "../editor.tsx";
+48 -33
View File
@@ -10,49 +10,64 @@ import {
export function directivePlugin() {
return decoratorStateField((state: EditorState) => {
const widgets: any[] = [];
const cursorPos = state.selection.main.head;
// TODO: This doesn't handle nested directives properly
let posOfLastOpen = { from: 0, to: 0 };
syntaxTree(state).iterate({
enter: ({ type, from, to }) => {
if (type.name !== "CommentBlock") {
enter: ({ type, from, to, node }) => {
const parent = node.parent;
if (!parent) {
return;
}
const text = state.sliceDoc(from, to);
if (/<!--\s*#/.exec(text)) {
// Open directive
posOfLastOpen = { from, to };
} else if (/<!--\s*\//.exec(text)) {
// Close directive
if (
(cursorPos > to || cursorPos < posOfLastOpen.from) &&
!isCursorInRange(state, [posOfLastOpen.from, to])
) {
const cursorInRange = isCursorInRange(state, [parent.from, parent.to]);
if (type.name === "DirectiveStart") {
if (cursorInRange) {
// Cursor outside this directive
widgets.push(
invisibleDecoration.range(
posOfLastOpen.from,
posOfLastOpen.to + 1,
),
);
widgets.push(
invisibleDecoration.range(from - 1, to),
Decoration.line({ class: "sb-directive-start" }).range(from),
);
} else {
widgets.push(invisibleDecoration.range(from, to));
widgets.push(
Decoration.line({
class: "sb-directive-start",
}).range(posOfLastOpen.from),
);
widgets.push(
Decoration.line({
class: "sb-directive-end",
}).range(from),
Decoration.line({ class: "sb-directive-start-outside" }).range(
state.doc.lineAt(to).from,
),
);
}
} else {
return;
return true;
}
if (type.name === "DirectiveEnd") {
// Cursor outside this directive
if (cursorInRange) {
widgets.push(
Decoration.line({ class: "sb-directive-end" }).range(from),
);
} else {
widgets.push(invisibleDecoration.range(from, to));
widgets.push(
Decoration.line({ class: "sb-directive-end-outside" }).range(
state.doc.lineAt(from - 1).from,
),
);
}
return true;
}
if (type.name === "DirectiveBody") {
const lines = state.sliceDoc(from, to).split("\n");
let pos = from;
for (const line of lines) {
if (pos !== to) {
widgets.push(
Decoration.line({
class: "sb-directive-body",
}).range(pos),
);
}
pos += line.length + 1;
}
}
},
});
+1
View File
@@ -5,6 +5,7 @@ const straightQuoteContexts = [
"FencedCode",
"InlineCode",
"FrontMatterCode",
"DirectiveStart",
];
// TODO: Add support for selection (put quotes around or create blockquote block?)
+1 -1
View File
@@ -13,7 +13,7 @@ import {
import { renderMarkdownToHtml } from "../../plugs/markdown/markdown_render.ts";
import { ParseTree } from "$sb/lib/tree.ts";
import { lezerToParseTree } from "../../common/parse_tree.ts";
import { lezerToParseTree } from "../../common/markdown_parser/parse_tree.ts";
import type { Editor } from "../editor.tsx";
class TableViewWidget extends WidgetType {
+1 -1
View File
@@ -1,4 +1,4 @@
import { pageLinkRegex } from "../../common/parser.ts";
import { pageLinkRegex } from "../../common/markdown_parser/parser.ts";
import { ClickEvent } from "../../plug-api/app_event.ts";
import { Decoration, syntaxTree } from "../deps.ts";
import { Editor } from "../editor.tsx";
+5 -2
View File
@@ -47,8 +47,11 @@ import {
import { SilverBulletHooks } from "../common/manifest.ts";
import { markdown } from "../common/deps.ts";
import { loadMarkdownExtensions, MDExt } from "../common/markdown_ext.ts";
import buildMarkdown from "../common/parser.ts";
import {
loadMarkdownExtensions,
MDExt,
} from "../common/markdown_parser/markdown_ext.ts";
import buildMarkdown from "../common/markdown_parser/parser.ts";
import { Space } from "../common/spaces/space.ts";
import { markdownSyscalls } from "../common/syscalls/markdown.ts";
import { FilterOption, PageMeta } from "../common/types.ts";
+4 -13
View File
@@ -1,11 +1,11 @@
import { HighlightStyle } from "../common/deps.ts";
import { tagHighlighter, tags as t } from "./deps.ts";
import * as ct from "../common/customtags.ts";
import { MDExt } from "../common/markdown_ext.ts";
import * as ct from "../common/markdown_parser/customtags.ts";
import { MDExt } from "../common/markdown_parser/markdown_ext.ts";
export default function highlightStyles(mdExtension: MDExt[]) {
tagHighlighter;
const hls = HighlightStyle.define([
return HighlightStyle.define([
{ tag: t.heading1, class: "sb-h1" },
{ tag: t.heading2, class: "sb-h2" },
{ tag: t.heading3, class: "sb-h3" },
@@ -44,20 +44,11 @@ export default function highlightStyles(mdExtension: MDExt[]) {
{ tag: t.comment, class: "sb-comment" },
{ tag: t.invalid, class: "sb-invalid" },
{ tag: t.processingInstruction, class: "sb-meta" },
// { tag: t.content, class: "tbl-content" },
{ tag: t.punctuation, class: "sb-punctuation" },
{ tag: ct.DirectiveTag, class: "sb-directive" },
{ tag: ct.HorizontalRuleTag, class: "sb-hr" },
...mdExtension.map((mdExt) => {
return { tag: mdExt.tag, ...mdExt.styles, class: mdExt.className };
}),
]);
const fn0 = hls.style;
// Hack: https://discuss.codemirror.net/t/highlighting-that-seems-ignored-in-cm6/4320/16
// @ts-ignore
hls.style = (tags) => {
// console.log("Tags", tags);
return fn0(tags || []);
};
return hls;
}
-21
View File
@@ -135,17 +135,6 @@
left: -12px;
}
.sb-directive-start::before {
content: "#";
color: gray;
border: 1px solid gray;
border-radius: 5px;
font-size: 62%;
padding: 2px;
position: relative;
left: -20px;
}
.sb-line-frontmatter-outside, .sb-line-code-outside {
display: none;
}
@@ -192,16 +181,6 @@
margin-left: -1ch;
}
.sb-directive-end::before {
content: "/";
border-radius: 5px;
color: gray;
border: 1px solid gray;
font-size: 62%;
padding: 2px;
position: relative;
left: -20px;
}
}
.cm-scroller {
+75 -16
View File
@@ -1,6 +1,8 @@
#sb-root {
--highlight-color: #464cfc;
--directive-color: #0000000f;
--ui-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--editor-font: "iA-Mono", "Menlo";
font-family: var(--ui-font);
}
@@ -28,7 +30,7 @@
}
.sb-notifications {
font-family: "iA-Mono";
font-family: var(--editor-font);
}
.sb-notifications > div {
@@ -108,7 +110,7 @@
/* Editor */
.cm-content {
font-family: "iA-Mono", "Menlo";
font-family: var(--editor-font);
}
.cm-selectionBackground {
@@ -225,7 +227,7 @@
}
.sb-command-button {
font-family: "iA-Mono";
font-family: var(--editor-font);
font-size: 1em;
}
@@ -299,20 +301,25 @@
line-height: inherit;
}
.sb-line-fenced-code .sb-keyword {
color: #830000;
.sb-keyword {
font-weight: bold;
}
.sb-line-fenced-code .sb-variableName {
color: #036d9b;
.sb-variableName {
color: #024866;
}
.sb-line-fenced-code .sb-typeName {
.sb-typeName {
color: #038138;
}
.sb-line-fenced-code .sb-string,
.sb-line-fenced-code .sb-string2 {
.sb-string,
.sb-string2,
.sb-number {
color: #440377;
}
.sb-string {
color: #440377;
}
@@ -368,6 +375,64 @@ sb-admonition-warning .sb-admonition-icon {
color: #676767;
}
// Directives
.sb-directive-body {
border-left: 1px solid var(--directive-color);
border-right: 1px solid var(--directive-color);
}
.cm-line.sb-directive-start, .cm-line.sb-directive-end {
color: #5b5b5b;
background-color: rgb(233, 233, 233, 50%);
padding: 3px;
}
.sb-directive-start {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-style: solid;
border-color: var(--directive-color);
border-width: 1px 1px 0 1px;
}
.sb-directive-end {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border-style: solid;
border-color: var(--directive-color);
border-width: 0 1px 1px 1px;
}
.sb-directive-start-outside {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-style: solid;
border-color: var(--directive-color);
border-left-width: 1px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 0;
padding-top: 5px !important;
}
.sb-directive-end-outside {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border-style: solid;
border-color: var(--directive-color);
border-left-width: 1px;
border-bottom-width: 1px;
border-right-width: 1px;
border-top-width: 0;
padding-bottom: 5px !important;
}
.sb-directive-end-outside.sb-directive-start-outside {
border-top-width: 1px;
border-bottom-width: 1px;
}
.sb-emphasis {
font-style: italic;
}
@@ -432,12 +497,6 @@ a.sb-wiki-link-page-missing, .sb-wiki-link-page-missing > .sb-wiki-link-page {
background-color: rgba(255, 255, 0, 0.5);
}
.sb-comment {
color: #989797;
font-size: 75%;
line-height: 75%;
}
html[data-theme="dark"] {
#sb-root {
background-color: #555;