-
Notifications
You must be signed in to change notification settings - Fork 204
Implement AlertBlockSyntax
using BlockquoteSyntax
#585
Conversation
As I understand the alert-block syntax, it is an extension on the orignal blockquote support in markdown. Basically, it's a blockquote that is rendered differently. That means that if alert-block syntax isn't supported a markdown parser will render it as a blockquote. This provides a nice graceful fallback. It also means that if you're implementing it, you really should implement it the same way you implement blockquote parsing.
Currently, running crash-test on this, though that won't reveal if we have bugs. Just that it doesn't crash 🤣 |
Pull Request Test Coverage Report for Build 8007970317Details
💛 - Coveralls |
No crashes scanning all markdown files in the latest version for all packages on pub.dev
|
return pattern.hasMatch(parser.current.content) && | ||
parser.lines.any((line) => _contentLineRegExp.hasMatch(line.content)); |
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 can't make sense of this.
I suspect that parser.lines
is the full text document.
So we're asking if both of the following are true:
- (i) current line matches:
^\s{0,3}>\s{0,3}\\?\[!(note|tip|important|caution|warning)\\?\]\s*$
, and, - (ii) some line in the current document matches:
>?\s?(.*)*
.
If (i) is true, then I think (ii) is always trivially true.
I suspect this is here because there has to be a line on the form:
> [!note]
and it has to be followed by a line > ...
or a paragraph continuation.
But the implementation makes no sense, and it doesn't account for the paragraph continuation if it did.
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 suspect that parser.lines is the full text document.
Hmm, that might explain https://github.com/dart-lang/markdown/issues/579 - parsing times being quadratic.
continue; | ||
} | ||
|
||
final lastLine = childLines.last; |
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.
childLines
can be empty at this point.
final match = strippedContent.isEmpty | ||
? null | ||
: _contentLineRegExp.firstMatch(strippedContent); |
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.
This makes it unable to distinguish between an empty line and a line containing only >
, but these are very different at result in different behavior.
); | ||
|
||
if (isBlockquote) { | ||
return Element('blockquote', children); |
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.
This is ugly, but I don't see a better way, unless we make BlockquoteSyntax
do everything.
I suppose we could in theory make BlockquoteSyntax
check if AlertBlockSyntax
is enabled by doing:`
final isAlertSyntaxEnabled = parser.document.blockSyntaxes.any(
(s) => s is AlertBlockSyntax,
);
If we could give AlertBlockSyntax
a factory singleton constructor we could do:
final isAlertSyntaxEnabled = parser.document.blockSyntaxes.contains(
const AlertBlockSyntax(),
);
If inside BlockquoteSyntax
we had isAlertSyntaxEnabled
then it could implement both. Ofcourse this would mean that enabling AlertBlockSyntax
wouldn't work without enabling BlockquoteSyntax
.
I'm not sure why we should ever allow such configuration, we surely don't intent to test it, but that's how the package is structured.
The point with implementing alert-syntax inside BlockquoteSyntax
is that alert-syntax is really a post-processing step for blockquote. But I don't really see how package:markdown
has the facilities to post-processing.
// Until we've parse all the child lines, we can't actually know if this is | ||
// a blockquote containing `[!note]` or if this is an alert-block. | ||
// | ||
// This is because `> [!note]` is not a valid alert-block! |
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.
Can you explain why this is not a valid alert block? because it is empty?
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 don't know, that's how it behaves on github :D
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.
But is it the emptiness that makes it invalid, or some other property?
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.
Example of the empty case
-----------
> [!note]
-----------
[!note]
Example of the non-empty case
-----------
> [!note]
> Hello world
-----------
Note
Hello world
Conclusion
If we have > [!note]
it's not a special block. But if it's:
- Followed by text that wants to belong to the previous paragraph, then it is. OR
- Followed by lines like
> ...
indicating that whatever is there belongs inside the blockquote, then it also is special.
Otherwise, it's not special, just a normal blockquote.
Notice that > foo\nbar
is the same as > foo\n> bar
, the line that follows is considered to be a paragraph continuation of the previous line, so the blockquote continues.
So yes, as far as I can see, it's emptiness that decides it. Even if you have > [!note]\n>
it'll still not be rendered as a special alert-block.
I've just landed #593 as a fix for the crash, but I think this PR is probably going in a direction that would be good in the long term, so I'd like to keep it open. I'll try to review more tomorrow. I looked at it today, and the only think I don't like is the same thing you don't like @jonasfj haha, which you elaborate on above. I think there should be a way to "nicely" sit this syntax into the GFM extension, "on top" of the blockquote syntax.
Haha this is really true. It's a weird concept, to have a plugable parser like this, based on an "ordering" of syntaxes, where we ask each in an order, "Can you parse this line? No? And you?" It's inherently flawed. |
It's completely orthogonal, maybe it deserves a controversial proposal, where we can shoot down the idea :D Filed dart-lang/tools#1352 |
Closing as the dart-lang/markdown repository is merged into the dart-lang/tools monorepo. Please re-open this PR there! |
A proposed fix for dart-lang/tools#1349
As I understand the alert-block syntax, it is an extension on the original blockquote support in markdown. Basically, it's a blockquote that is rendered differently.
That means that if alert-block syntax isn't supported a markdown parser will render it as a blockquote. This provides a nice graceful fallback. It also means that if you're implementing it, you really should implement it the same way you implement blockquote parsing.
This is an attempt at implementing
AlertBlockSyntax
using the same parsing logic asBlockquoteSyntax
.This is not pretty. Ideally, whether to support alert-syntax should be a boolean option passed to
BlockquoteSyntax
. Because an alert-syntax is a blockquote with extra bling. But that's not how this package is structured 🤣In fact, it can probably be argued that trying to make a markdown parser that consists of composeable objects is extremely sketchy. Especially, when we let consumers of the package implement their own syntaxes and inject them into the whole mix. It's very hard to determine how this whole thing works (and what combinations of syntaxes will work). It would probably have been safer to pass in all the option as boolean configuration options that enable/disable a particular syntaxes in a single large parser.