106 lines
3.0 KiB
TypeScript
106 lines
3.0 KiB
TypeScript
import {
|
|
defineLanguageFacet,
|
|
foldNodeProp,
|
|
indentNodeProp,
|
|
Language,
|
|
languageDataProp,
|
|
LanguageDescription,
|
|
ParseContext
|
|
} from "@codemirror/language";
|
|
import { styleTags, tags as t } from "@codemirror/highlight";
|
|
import { Emoji, GFM, MarkdownParser, parser as baseParser, Subscript, Superscript } from "@lezer/markdown";
|
|
|
|
const data = defineLanguageFacet({ block: { open: "<!--", close: "-->" } });
|
|
|
|
export const commonmark = baseParser.configure({
|
|
props: [
|
|
styleTags({
|
|
"Blockquote/...": t.quote,
|
|
HorizontalRule: t.contentSeparator,
|
|
"ATXHeading1/... SetextHeading1/...": t.heading1,
|
|
"ATXHeading2/... SetextHeading2/...": t.heading2,
|
|
"ATXHeading3/...": t.heading3,
|
|
"ATXHeading4/...": t.heading4,
|
|
"ATXHeading5/...": t.heading5,
|
|
"ATXHeading6/...": t.heading6,
|
|
"Comment CommentBlock": t.comment,
|
|
Escape: t.escape,
|
|
Entity: t.character,
|
|
"Emphasis/...": t.emphasis,
|
|
"StrongEmphasis/...": t.strong,
|
|
"Link/... Image/...": t.link,
|
|
"OrderedList/... BulletList/...": t.list,
|
|
"InlineCode CodeText": t.monospace,
|
|
URL: t.url,
|
|
"HeaderMark HardBreak QuoteMark ListMark LinkMark EmphasisMark CodeMark":
|
|
t.processingInstruction,
|
|
"CodeInfo LinkLabel": t.labelName,
|
|
LinkTitle: t.string,
|
|
Paragraph: t.content,
|
|
}),
|
|
foldNodeProp.add((type) => {
|
|
if (!type.is("Block") || type.is("Document")) return undefined;
|
|
return (tree, state) => ({
|
|
from: state.doc.lineAt(tree.from).to,
|
|
to: tree.to,
|
|
});
|
|
}),
|
|
indentNodeProp.add({
|
|
Document: () => null,
|
|
}),
|
|
languageDataProp.add({
|
|
Document: data,
|
|
}),
|
|
],
|
|
});
|
|
|
|
export function mkLang(parser: MarkdownParser) {
|
|
return new Language(
|
|
data,
|
|
parser,
|
|
parser.nodeSet.types.find((t) => t.name == "Document")!
|
|
);
|
|
}
|
|
|
|
/// Language support for strict CommonMark.
|
|
export const commonmarkLanguage = mkLang(commonmark);
|
|
|
|
const extended = commonmark.configure([
|
|
GFM,
|
|
Subscript,
|
|
Superscript,
|
|
Emoji,
|
|
{
|
|
props: [
|
|
styleTags({
|
|
"TableDelimiter SubscriptMark SuperscriptMark StrikethroughMark":
|
|
t.processingInstruction,
|
|
"TableHeader/...": t.heading,
|
|
"Strikethrough/...": t.strikethrough,
|
|
TaskMarker: t.atom,
|
|
Task: t.list,
|
|
Emoji: t.character,
|
|
"Subscript Superscript": t.special(t.content),
|
|
TableCell: t.content,
|
|
}),
|
|
],
|
|
},
|
|
]);
|
|
|
|
/// Language support for [GFM](https://github.github.com/gfm/) plus
|
|
/// subscript, superscript, and emoji syntax.
|
|
export const markdownLanguage = mkLang(extended);
|
|
|
|
export function getCodeParser(
|
|
languages: readonly LanguageDescription[],
|
|
defaultLanguage?: Language
|
|
) {
|
|
return (info: string) => {
|
|
let found =
|
|
info && LanguageDescription.matchLanguageName(languages, info, true);
|
|
if (!found) return defaultLanguage ? defaultLanguage.parser : null;
|
|
if (found.support) return found.support.language.parser;
|
|
return ParseContext.getSkippingParser(found.load());
|
|
};
|
|
}
|