mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-03-23 23:58:13 +00:00
not really working but it will
This commit is contained in:
@@ -36,6 +36,53 @@ const highlightStyle = HighlightStyle.define([
|
||||
// …
|
||||
]);
|
||||
|
||||
/*custom tokens */
|
||||
import { Decoration, ViewPlugin, WidgetType } from "@codemirror/view";
|
||||
import { tokenizeCustomMarkdown, customTags } from "./customMarkdownGrammar.js";
|
||||
|
||||
const customHighlightStyle = HighlightStyle.define([
|
||||
{ tag: tags.heading1, color: "#000", fontWeight: "700" },
|
||||
{ tag: tags.keyword, color: "#07a" }, // example for your markdown headings
|
||||
{ tag: customTags.pageLine, color: "#f0a" },
|
||||
{ tag: customTags.snippetBreak, class: "cm-snippet-break", color: "#0af" },
|
||||
{ tag: customTags.inlineBlock, class: "cm-inline-block", backgroundColor: "#fffae6" },
|
||||
{ tag: customTags.emoji, class: "cm-emoji", color: "#fa0" },
|
||||
{ tag: customTags.superscript, class: "cm-superscript", verticalAlign: "super", fontSize: "0.8em" },
|
||||
{ tag: customTags.subscript, class: "cm-subscript", verticalAlign: "sub", fontSize: "0.8em" },
|
||||
{ tag: customTags.definitionTerm, class: "cm-dt", fontWeight: "bold", color: "#0a0" },
|
||||
{ tag: customTags.definitionDesc, class: "cm-dd", color: "#070" },
|
||||
]);
|
||||
|
||||
const customHighlightPlugin = ViewPlugin.fromClass(
|
||||
class {
|
||||
constructor(view) {
|
||||
this.decorations = this.buildDecorations(view);
|
||||
}
|
||||
update(update) {
|
||||
if (update.docChanged) {
|
||||
this.decorations = this.buildDecorations(update.view);
|
||||
}
|
||||
}
|
||||
buildDecorations(view) {
|
||||
const widgets = [];
|
||||
const tokens = tokenizeCustomMarkdown(view.state.doc.toString());
|
||||
|
||||
// sort by line number
|
||||
tokens.sort((a, b) => a.line - b.line);
|
||||
|
||||
tokens.forEach((tok) => {
|
||||
const line = view.state.doc.line(tok.line + 1); // CM lines are 1-based
|
||||
widgets.push(Decoration.line({ class: `cm-${tok.type}` }).range(line.from));
|
||||
});
|
||||
|
||||
return Decoration.set(widgets);
|
||||
}
|
||||
},
|
||||
{
|
||||
decorations: (v) => v.decorations,
|
||||
},
|
||||
);
|
||||
|
||||
const CodeEditor = forwardRef(
|
||||
(
|
||||
{
|
||||
@@ -116,6 +163,8 @@ const CodeEditor = forwardRef(
|
||||
lineNumbers(),
|
||||
themeExtension,
|
||||
syntaxHighlighting(highlightStyle),
|
||||
customHighlightPlugin,
|
||||
syntaxHighlighting(customHighlightStyle),
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
95
client/components/codeEditor/customMarkdownGrammar.js
Normal file
95
client/components/codeEditor/customMarkdownGrammar.js
Normal file
@@ -0,0 +1,95 @@
|
||||
// customMarkdownGrammar.js
|
||||
|
||||
// --- Custom tags with CM6-compatible class names ---
|
||||
export const customTags = {
|
||||
pageLine: "pageLine", // .cm-pageLine
|
||||
snippetLine: "snippetLine", // .cm-snippetLine
|
||||
columnSplit: "columnSplit", // .cm-columnSplit
|
||||
snippetBreak: "snippetBreak", // .cm-snippetBreak
|
||||
inlineBlock: "inline-block", // .cm-inline-block
|
||||
block: "block", // .cm-block
|
||||
emoji: "emoji", // .cm-emoji
|
||||
superscript: "superscript", // .cm-superscript
|
||||
subscript: "subscript", // .cm-subscript
|
||||
definitionTerm: "dt-highlight", // .cm-dt-highlight
|
||||
definitionDesc: "dd-highlight", // .cm-dd-highlight
|
||||
injection: "injection", // .cm-injection
|
||||
};
|
||||
|
||||
// --- Tokenizer function ---
|
||||
export function tokenizeCustomMarkdown(text) {
|
||||
const tokens = [];
|
||||
const lines = text.split("\n");
|
||||
|
||||
// Track multi-line blocks
|
||||
let inBlock = false;
|
||||
let blockStart = 0;
|
||||
|
||||
lines.forEach((lineText, lineNumber) => {
|
||||
// --- Page / snippet lines ---
|
||||
if (/\\page/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.pageLine });
|
||||
if (/\\snippet/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.snippetLine });
|
||||
if (/^\\column(?:break)?$/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.columnSplit });
|
||||
if (/\\snippet/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.snippetBreak });
|
||||
|
||||
// --- Emoji ---
|
||||
if (/:\w+?:/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.emoji });
|
||||
|
||||
// --- Superscript / Subscript ---
|
||||
if (/\^\^/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.subscript });
|
||||
if (/\^/.test(lineText)) tokens.push({ line: lineNumber, type: customTags.superscript });
|
||||
|
||||
// --- Definition lists ---
|
||||
if (/::/.test(lineText)) {
|
||||
tokens.push({ line: lineNumber, type: customTags.definitionDesc });
|
||||
tokens.push({ line: lineNumber, type: customTags.definitionTerm });
|
||||
}
|
||||
|
||||
// Track ranges already marked for injections
|
||||
const injectionRanges = [];
|
||||
|
||||
if (line.includes("{") && line.includes("}")) {
|
||||
const regex = /{[^{}]*}/gm;
|
||||
let match;
|
||||
while ((match = regex.exec(line)) != null) {
|
||||
codeMirror?.markText(
|
||||
{ line: lineNumber, ch: match.index },
|
||||
{ line: lineNumber, ch: match.index + match[0].length },
|
||||
{ className: "injection" },
|
||||
);
|
||||
injectionRanges.push([match.index, match.index + match[0].length]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now mark inline blocks, but skip overlapping injection ranges
|
||||
if (line.includes("{{") && line.includes("}}")) {
|
||||
const regex = /{{[^{}]*}}/gm;
|
||||
let match;
|
||||
while ((match = regex.exec(line)) != null) {
|
||||
const start = match.index,
|
||||
end = match.index + match[0].length;
|
||||
const overlaps = injectionRanges.some(([iStart, iEnd]) => start < iEnd && end > iStart);
|
||||
if (!overlaps) {
|
||||
codeMirror?.markText(
|
||||
{ line: lineNumber, ch: start },
|
||||
{ line: lineNumber, ch: end },
|
||||
{ className: "inline-block" },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Multi-line blocks `{{…}}` --- only start/end lines
|
||||
if (lineText.trimLeft().startsWith("{{") && !lineText.trimLeft().endsWith("}}")) {
|
||||
inBlock = true;
|
||||
blockStart = lineNumber;
|
||||
tokens.push({ line: lineNumber, type: customTags.block });
|
||||
}
|
||||
if (lineText.trimLeft().startsWith("}}") && inBlock) {
|
||||
tokens.push({ line: lineNumber, type: customTags.block });
|
||||
inBlock = false;
|
||||
}
|
||||
});
|
||||
|
||||
return tokens;
|
||||
}
|
||||
Reference in New Issue
Block a user