-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
upgrade markdown package reference #2364
base: main
Are you sure you want to change the base?
Changes from 6 commits
6050484
9084683
fddd6dc
95ea5b2
7578b41
a5ae6c2
a1d18d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,9 +23,12 @@ MutableDocument deserializeMarkdownToDocument( | |
List<ElementToNodeConverter> customElementToNodeConverters = const [], | ||
bool encodeHtml = false, | ||
}) { | ||
final markdownLines = const LineSplitter().convert(markdown); | ||
final markdownLines = const LineSplitter().convert(markdown).map<md.Line>((String l) { | ||
return md.Line(l); | ||
}).toList(); | ||
|
||
final markdownDoc = md.Document( | ||
encodeHtml: encodeHtml, | ||
blockSyntaxes: [ | ||
...customBlockSyntax, | ||
if (syntax == MarkdownSyntax.superEditor) ...[ | ||
|
@@ -58,6 +61,14 @@ MutableDocument deserializeMarkdownToDocument( | |
); | ||
} | ||
|
||
// Add 1 hanging line for every 2 blank lines at the end, need this to preserve behavior pre markdown 7.2.1 | ||
final hangingEmptyLines = markdownLines.reversed.takeWhile((md.Line l) => l.isBlankLine); | ||
if(hangingEmptyLines.isNotEmpty && documentNodes.lastOrNull is ListItemNode) { | ||
for(var i = 0; i < hangingEmptyLines.length >> 1; i++) { | ||
documentNodes.add(ParagraphNode(id: Editor.createNodeId(), text: AttributedText())); | ||
} | ||
} | ||
|
||
return MutableDocument(nodes: documentNodes); | ||
} | ||
|
||
|
@@ -391,6 +402,7 @@ class _MarkdownToDocument implements md.NodeVisitor { | |
text, | ||
md.Document( | ||
inlineSyntaxes: [ | ||
SingleStrikethroughSyntax(), // this needs to be before md.StrikethroughSyntax to be recognized | ||
md.StrikethroughSyntax(), | ||
UnderlineSyntax(), | ||
if (syntax == MarkdownSyntax.superEditor) // | ||
|
@@ -519,24 +531,56 @@ abstract class ElementToNodeConverter { | |
DocumentNode? handleElement(md.Element element); | ||
} | ||
|
||
/// A Markdown [TagSyntax] that matches underline spans of text, which are represented in | ||
/// A Markdown [DelimiterSyntax] that matches underline spans of text, which are represented in | ||
/// Markdown with surrounding `¬` tags, e.g., "this is ¬underline¬ text". | ||
/// | ||
/// This [TagSyntax] produces `Element`s with a `u` tag. | ||
class UnderlineSyntax extends md.TagSyntax { | ||
UnderlineSyntax() : super('¬', requiresDelimiterRun: true, allowIntraWord: true); | ||
/// This [DelimiterSyntax] produces `Element`s with a `u` tag. | ||
class UnderlineSyntax extends md.DelimiterSyntax { | ||
|
||
/// According to the docs: | ||
/// | ||
/// https://pub.dev/documentation/markdown/latest/markdown/DelimiterSyntax-class.html | ||
/// | ||
/// The DelimiterSyntax constructor takes a nullable. However, the problem is there is a bug in the underlying dart | ||
/// library if you don't pass it. Due to these two lines, one sets it to const [] if not passed, then the next tries | ||
/// to sort. So we have to pass something at the moment or it blows up. | ||
/// | ||
/// https://github.com/dart-lang/markdown/blob/d53feae0760a4f0aae5ffdfb12d8e6acccf14b40/lib/src/inline_syntaxes/delimiter_syntax.dart#L67 | ||
/// https://github.com/dart-lang/markdown/blob/d53feae0760a4f0aae5ffdfb12d8e6acccf14b40/lib/src/inline_syntaxes/delimiter_syntax.dart#L319 | ||
static final _tags = [ md.DelimiterTag("u", 1) ]; | ||
|
||
UnderlineSyntax() : super('¬', requiresDelimiterRun: true, allowIntraWord: true, tags: _tags); | ||
|
||
@override | ||
md.Node? close( | ||
Iterable<md.Node>? close( | ||
md.InlineParser parser, | ||
md.Delimiter opener, | ||
md.Delimiter closer, { | ||
required List<md.Node> Function() getChildren, | ||
required String tag, | ||
}) { | ||
return md.Element('u', getChildren()); | ||
final element = md.Element('u', getChildren()); | ||
return [ element ]; | ||
} | ||
} | ||
|
||
/// A Markdown [DelimiterSyntax] that matches strikethrough spans of text, which are represented in | ||
/// Markdown with surrounding `~` tags, e.g., "this is ~strikethrough~ text". | ||
/// | ||
/// Markdown in library in 7.2.1 seems to not be matching single strikethroughs | ||
/// | ||
/// This [DelimiterSyntax] produces `Element`s with a `del` tag. | ||
class SingleStrikethroughSyntax extends md.DelimiterSyntax { | ||
SingleStrikethroughSyntax() | ||
: super( | ||
'~', | ||
requiresDelimiterRun: true, | ||
allowIntraWord: true, | ||
tags: [md.DelimiterTag('del', 1)], | ||
); | ||
} | ||
|
||
|
||
/// Parses a paragraph preceded by an alignment token. | ||
class _ParagraphWithAlignmentSyntax extends _EmptyLinePreservingParagraphSyntax { | ||
/// This pattern matches the text aligment notation. | ||
|
@@ -548,7 +592,7 @@ class _ParagraphWithAlignmentSyntax extends _EmptyLinePreservingParagraphSyntax | |
|
||
@override | ||
bool canParse(md.BlockParser parser) { | ||
if (!_alignmentNotationPattern.hasMatch(parser.current)) { | ||
if (!_alignmentNotationPattern.hasMatch(parser.current.content)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this a pre-existing error on our part? Should we have been accessing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Markdown lib changed from String to Line which has a content member, so this just redirects to where the string is now. |
||
return false; | ||
} | ||
|
||
|
@@ -564,7 +608,7 @@ class _ParagraphWithAlignmentSyntax extends _EmptyLinePreservingParagraphSyntax | |
/// We found a paragraph alignment token, but the block after the alignment token isn't a paragraph. | ||
/// Therefore, the paragraph alignment token is actually regular content. This parser doesn't need to | ||
/// take any action. | ||
if (_standardNonParagraphBlockSyntaxes.any((syntax) => syntax.pattern.hasMatch(nextLine))) { | ||
if (_standardNonParagraphBlockSyntaxes.any((syntax) => syntax.pattern.hasMatch(nextLine.content))) { | ||
return false; | ||
} | ||
|
||
|
@@ -575,7 +619,7 @@ class _ParagraphWithAlignmentSyntax extends _EmptyLinePreservingParagraphSyntax | |
|
||
@override | ||
md.Node? parse(md.BlockParser parser) { | ||
final match = _alignmentNotationPattern.firstMatch(parser.current); | ||
final match = _alignmentNotationPattern.firstMatch(parser.current.content); | ||
|
||
// We've parsed the alignment token on the current line. We know a paragraph starts on the | ||
// next line. Move the parser to the next line so that we can parse the paragraph. | ||
|
@@ -630,13 +674,13 @@ class _EmptyLinePreservingParagraphSyntax extends md.BlockSyntax { | |
return false; | ||
} | ||
|
||
if (parser.current.isEmpty) { | ||
if (parser.current.content.isEmpty) { | ||
// We consider this input to be a separator between blocks because | ||
// it started with an empty line. We want to parse this input. | ||
return true; | ||
} | ||
|
||
if (_isAtParagraphEnd(parser, ignoreEmptyBlocks: _endsWithHardLineBreak(parser.current))) { | ||
if (_isAtParagraphEnd(parser, ignoreEmptyBlocks: _endsWithHardLineBreak(parser.current.content))) { | ||
// Another parser wants to parse this input. Let the other parser run. | ||
return false; | ||
} | ||
|
@@ -648,12 +692,12 @@ class _EmptyLinePreservingParagraphSyntax extends md.BlockSyntax { | |
@override | ||
md.Node? parse(md.BlockParser parser) { | ||
final childLines = <String>[]; | ||
final startsWithEmptyLine = parser.current.isEmpty; | ||
final startsWithEmptyLine = parser.current.content.isEmpty; | ||
|
||
// A hard line break causes the next line to be treated | ||
// as part of the same paragraph, except if the next line is | ||
// the beginning of another block element. | ||
bool hasHardLineBreak = _endsWithHardLineBreak(parser.current); | ||
bool hasHardLineBreak = _endsWithHardLineBreak(parser.current.content); | ||
|
||
if (startsWithEmptyLine) { | ||
// The parser started at an empty line. | ||
|
@@ -669,7 +713,7 @@ class _EmptyLinePreservingParagraphSyntax extends md.BlockSyntax { | |
return null; | ||
} | ||
|
||
if (!_blankLinePattern.hasMatch(parser.current)) { | ||
if (!_blankLinePattern.hasMatch(parser.current.content)) { | ||
// We found an empty line, but the following line isn't blank. | ||
// As there is no hard line break, the first line is consumed | ||
// as a separator between blocks. | ||
|
@@ -682,7 +726,7 @@ class _EmptyLinePreservingParagraphSyntax extends md.BlockSyntax { | |
childLines.add(''); | ||
|
||
// Check for a hard line break, so we consume the next line if we found one. | ||
hasHardLineBreak = _endsWithHardLineBreak(parser.current); | ||
hasHardLineBreak = _endsWithHardLineBreak(parser.current.content); | ||
parser.advance(); | ||
} | ||
|
||
|
@@ -691,9 +735,9 @@ class _EmptyLinePreservingParagraphSyntax extends md.BlockSyntax { | |
// ends with a hard line break. | ||
while (!_isAtParagraphEnd(parser, ignoreEmptyBlocks: hasHardLineBreak)) { | ||
final currentLine = parser.current; | ||
childLines.add(currentLine); | ||
childLines.add(currentLine.content); | ||
|
||
hasHardLineBreak = _endsWithHardLineBreak(currentLine); | ||
hasHardLineBreak = _endsWithHardLineBreak(currentLine.content); | ||
|
||
parser.advance(); | ||
} | ||
|
@@ -777,7 +821,7 @@ class _TaskSyntax extends md.BlockSyntax { | |
|
||
@override | ||
md.Node? parse(md.BlockParser parser) { | ||
final match = pattern.firstMatch(parser.current); | ||
final match = pattern.firstMatch(parser.current.content); | ||
if (match == null) { | ||
return null; | ||
} | ||
|
@@ -795,10 +839,10 @@ class _TaskSyntax extends md.BlockSyntax { | |
// - find a blank line OR | ||
// - find the start of another block element (including another task) | ||
while (!parser.isDone && | ||
!_blankLinePattern.hasMatch(parser.current) && | ||
!_standardNonParagraphBlockSyntaxes.any((syntax) => syntax.pattern.hasMatch(parser.current))) { | ||
!_blankLinePattern.hasMatch(parser.current.content) && | ||
!_standardNonParagraphBlockSyntaxes.any((syntax) => syntax.pattern.hasMatch(parser.current.content))) { | ||
buffer.write('\n'); | ||
buffer.write(parser.current); | ||
buffer.write(parser.current.content); | ||
|
||
parser.advance(); | ||
} | ||
|
@@ -832,7 +876,7 @@ class _HeaderWithAlignmentSyntax extends md.BlockSyntax { | |
|
||
@override | ||
bool canParse(md.BlockParser parser) { | ||
if (!_alignmentNotationPattern.hasMatch(parser.current)) { | ||
if (!_alignmentNotationPattern.hasMatch(parser.current.content)) { | ||
return false; | ||
} | ||
|
||
|
@@ -846,7 +890,7 @@ class _HeaderWithAlignmentSyntax extends md.BlockSyntax { | |
} | ||
|
||
// Only parse if the next line is header. | ||
if (!_headerSyntax.pattern.hasMatch(nextLine)) { | ||
if (!_headerSyntax.pattern.hasMatch(nextLine.content)) { | ||
return false; | ||
} | ||
|
||
|
@@ -855,7 +899,7 @@ class _HeaderWithAlignmentSyntax extends md.BlockSyntax { | |
|
||
@override | ||
md.Node? parse(md.BlockParser parser) { | ||
final match = _alignmentNotationPattern.firstMatch(parser.current); | ||
final match = _alignmentNotationPattern.firstMatch(parser.current.content); | ||
|
||
// We've parsed the alignment token on the current line. We know a header starts on the | ||
// next line. Move the parser to the next line so that we can parse the header. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this be a bit more readable if we use
hangingEmptyLines.length ~/ 2
instead ofhangingEmptyLines.length >> 1
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't catch that for loop, but yeah, @jezell let's not use bit shifting unless we absolutely have to. If you wanna divide by two, let's use the standard operators for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jezell can you push an update with this change?