Major directive refactor (#195)
Fixes #188 #144 #76: major refactor of directive parsing, rendering, styling
This commit is contained in:
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ const straightQuoteContexts = [
|
||||
"FencedCode",
|
||||
"InlineCode",
|
||||
"FrontMatterCode",
|
||||
"DirectiveStart",
|
||||
];
|
||||
|
||||
// TODO: Add support for selection (put quotes around or create blockquote block?)
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user