Mostly working except yaml codeblocks
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
import { ChangeSpec, EditorSelection, StateCommand, Text } from "@codemirror/state";
|
||||
import {
|
||||
StateCommand,
|
||||
Text,
|
||||
EditorSelection,
|
||||
ChangeSpec,
|
||||
} from "@codemirror/state";
|
||||
import { syntaxTree } from "@codemirror/language";
|
||||
import { SyntaxNode, Tree } from "@lezer/common";
|
||||
import { markdownLanguage } from "./markdown";
|
||||
@@ -20,11 +25,8 @@ class Context {
|
||||
|
||||
blank(trailing: boolean = true) {
|
||||
let result = this.spaceBefore;
|
||||
if (this.node.name == "Blockquote") {
|
||||
result += ">";
|
||||
} else if (this.node.name == "Comment") {
|
||||
result += "%%";
|
||||
} else
|
||||
if (this.node.name == "Blockquote") result += ">";
|
||||
else
|
||||
for (
|
||||
let i = this.to - this.from - result.length - this.spaceAfter.length;
|
||||
i > 0;
|
||||
@@ -50,12 +52,7 @@ function getContext(node: SyntaxNode, line: string, doc: Text) {
|
||||
cur && cur.name != "Document";
|
||||
cur = cur.parent
|
||||
) {
|
||||
if (
|
||||
cur.name == "ListItem" ||
|
||||
cur.name == "Blockquote" ||
|
||||
cur.name == "Comment"
|
||||
)
|
||||
nodes.push(cur);
|
||||
if (cur.name == "ListItem" || cur.name == "Blockquote") nodes.push(cur);
|
||||
}
|
||||
let context = [],
|
||||
pos = 0;
|
||||
@@ -69,12 +66,6 @@ function getContext(node: SyntaxNode, line: string, doc: Text) {
|
||||
) {
|
||||
pos += match[0].length;
|
||||
context.push(new Context(node, start, pos, "", match[1], ">", null));
|
||||
} else if (
|
||||
node.name == "Comment" &&
|
||||
(match = /^[ \t]*%%( ?)/.exec(line.slice(pos)))
|
||||
) {
|
||||
pos += match[0].length;
|
||||
context.push(new Context(node, start, pos, "", match[1], "%%", null));
|
||||
} else if (
|
||||
node.name == "ListItem" &&
|
||||
node.parent!.name == "OrderedList" &&
|
||||
@@ -93,17 +84,21 @@ function getContext(node: SyntaxNode, line: string, doc: Text) {
|
||||
} else if (
|
||||
node.name == "ListItem" &&
|
||||
node.parent!.name == "BulletList" &&
|
||||
(match = /^([ \t]*)([-+*])([ \t]+)/.exec(nodeStart(node, doc)))
|
||||
(match = /^([ \t]*)([-+*])([ \t]{1,4}\[[ xX]\])?([ \t]+)/.exec(
|
||||
nodeStart(node, doc)
|
||||
))
|
||||
) {
|
||||
let after = match[3],
|
||||
let after = match[4],
|
||||
len = match[0].length;
|
||||
if (after.length > 4) {
|
||||
after = after.slice(0, after.length - 4);
|
||||
len -= 4;
|
||||
}
|
||||
let type = match[2];
|
||||
if (match[3]) type += match[3].replace(/[xX]/, " ");
|
||||
pos += len;
|
||||
context.push(
|
||||
new Context(node.parent!, start, pos, match[1], after, match[2], node)
|
||||
new Context(node.parent!, start, pos, match[1], after, type, node)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -229,19 +224,6 @@ export const insertNewlineContinueMarkup: StateCommand = ({
|
||||
}
|
||||
}
|
||||
|
||||
if (inner.node.name == "Comment" && emptyLine && line.from) {
|
||||
let prevLine = doc.lineAt(line.from - 1),
|
||||
commented = /%%\s*$/.exec(prevLine.text);
|
||||
// Two aligned empty quoted lines in a row
|
||||
if (commented && commented.index == inner.from) {
|
||||
let changes = state.changes([
|
||||
{ from: prevLine.from + commented.index, to: prevLine.to },
|
||||
{ from: line.from + inner.from, to: line.to },
|
||||
]);
|
||||
return { range: range.map(changes), changes };
|
||||
}
|
||||
}
|
||||
|
||||
let changes: ChangeSpec[] = [];
|
||||
if (inner.node.name == "OrderedList")
|
||||
renumberList(inner.item!, doc, changes);
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { Prec } from "@codemirror/state";
|
||||
import { KeyBinding, keymap } from "@codemirror/view";
|
||||
import { Language, LanguageDescription, LanguageSupport } from "@codemirror/language";
|
||||
import {
|
||||
Language,
|
||||
LanguageSupport,
|
||||
LanguageDescription,
|
||||
} from "@codemirror/language";
|
||||
import { MarkdownExtension, MarkdownParser, parseCode } from "@lezer/markdown";
|
||||
import { html } from "@codemirror/lang-html";
|
||||
import { commonmarkLanguage, getCodeParser, markdownLanguage, mkLang } from "./markdown";
|
||||
import { deleteMarkupBackward, insertNewlineContinueMarkup } from "./commands";
|
||||
|
||||
import {
|
||||
commonmarkLanguage,
|
||||
markdownLanguage,
|
||||
mkLang,
|
||||
getCodeParser,
|
||||
} from "./markdown";
|
||||
import { insertNewlineContinueMarkup, deleteMarkupBackward } from "./commands";
|
||||
export {
|
||||
commonmarkLanguage,
|
||||
markdownLanguage,
|
||||
@@ -30,11 +38,15 @@ export function markdown(
|
||||
/// When given, this language will be used by default to parse code
|
||||
/// blocks.
|
||||
defaultCodeLanguage?: Language | LanguageSupport;
|
||||
/// A collection of language descriptions to search through for a
|
||||
/// matching language (with
|
||||
/// [`LanguageDescription.matchLanguageName`](#language.LanguageDescription^matchLanguageName))
|
||||
/// when a fenced code block has an info string.
|
||||
codeLanguages?: readonly LanguageDescription[];
|
||||
/// A source of language support for highlighting fenced code
|
||||
/// blocks. When it is an array, the parser will use
|
||||
/// [`LanguageDescription.matchLanguageName`](#language.LanguageDescription^matchLanguageName)
|
||||
/// with the fenced code info to find a matching language. When it
|
||||
/// is a function, will be called with the info string and may
|
||||
/// return a language or `LanguageDescription` object.
|
||||
codeLanguages?:
|
||||
| readonly LanguageDescription[]
|
||||
| ((info: string) => Language | LanguageDescription | null);
|
||||
/// Set this to false to disable installation of the Markdown
|
||||
/// [keymap](#lang-markdown.markdownKeymap).
|
||||
addKeymap?: boolean;
|
||||
@@ -68,7 +80,7 @@ export function markdown(
|
||||
}
|
||||
let codeParser =
|
||||
codeLanguages || defaultCode
|
||||
? getCodeParser(codeLanguages || [], defaultCode)
|
||||
? getCodeParser(codeLanguages, defaultCode)
|
||||
: undefined;
|
||||
extensions.push(
|
||||
parseCode({ codeParser, htmlParser: htmlNoMatch.language.parser })
|
||||
|
||||
@@ -1,43 +1,25 @@
|
||||
import {
|
||||
Language,
|
||||
defineLanguageFacet,
|
||||
languageDataProp,
|
||||
foldNodeProp,
|
||||
indentNodeProp,
|
||||
Language,
|
||||
languageDataProp,
|
||||
LanguageDescription,
|
||||
ParseContext
|
||||
ParseContext,
|
||||
} from "@codemirror/language";
|
||||
import { styleTags, tags as t } from "@codemirror/highlight";
|
||||
import { Emoji, GFM, MarkdownParser, parser as baseParser, Subscript, Superscript } from "@lezer/markdown";
|
||||
import {
|
||||
parser as baseParser,
|
||||
MarkdownParser,
|
||||
GFM,
|
||||
Subscript,
|
||||
Superscript,
|
||||
Emoji,
|
||||
} 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) => ({
|
||||
@@ -55,51 +37,36 @@ export const commonmark = baseParser.configure({
|
||||
});
|
||||
|
||||
export function mkLang(parser: MarkdownParser) {
|
||||
return new Language(
|
||||
data,
|
||||
parser,
|
||||
parser.nodeSet.types.find((t) => t.name == "Document")!
|
||||
);
|
||||
return new Language(data, parser);
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}),
|
||||
],
|
||||
},
|
||||
]);
|
||||
const extended = commonmark.configure([GFM, Subscript, Superscript, Emoji]);
|
||||
|
||||
/// 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[],
|
||||
languages:
|
||||
| readonly LanguageDescription[]
|
||||
| ((info: string) => Language | LanguageDescription | null)
|
||||
| undefined,
|
||||
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());
|
||||
if (info && languages) {
|
||||
let found = null;
|
||||
if (typeof languages == "function") found = languages(info);
|
||||
else found = LanguageDescription.matchLanguageName(languages, info, true);
|
||||
if (found instanceof LanguageDescription)
|
||||
return found.support
|
||||
? found.support.language.parser
|
||||
: ParseContext.getSkippingParser(found.load());
|
||||
else if (found) return found.parser;
|
||||
}
|
||||
return defaultLanguage ? defaultLanguage.parser : null;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user