Import latest markdown library from dartdoc
diff --git a/pkgs/markdown/lib/markdown.dart b/pkgs/markdown/lib/markdown.dart index 0bcc777..01de970 100644 --- a/pkgs/markdown/lib/markdown.dart +++ b/pkgs/markdown/lib/markdown.dart
@@ -5,19 +5,18 @@ /// Parses text in a markdown-like format and renders to HTML. library markdown; -import 'src/classify/dart.dart'; - // TODO(rnystrom): Use "package:" URL (#4968). part 'src/markdown/ast.dart'; part 'src/markdown/block_parser.dart'; part 'src/markdown/html_renderer.dart'; part 'src/markdown/inline_parser.dart'; -typedef String ClassifierFunction(String syntax, String source); +typedef Node Resolver(String name); /// Converts the given string of markdown to HTML. -String markdownToHtml(String markdown, [ClassifierFunction classifier]) { - final document = new Document(classifier); +String markdownToHtml(String markdown, {inlineSyntaxes, linkResolver}) { + final document = new Document(inlineSyntaxes: inlineSyntaxes, + linkResolver: linkResolver); // Replace windows line endings with unix line endings, and split. final lines = markdown.replaceAll('\r\n','\n').split('\n'); @@ -33,26 +32,15 @@ .replaceAll('>', '>'); } -var _implicitLinkResolver; - -Node setImplicitLinkResolver(Node resolver(String text)) { - _implicitLinkResolver = resolver; -} - /// Maintains the context needed to parse a markdown document. class Document { final Map<String, Link> refLinks; - final ClassifierFunction classifier; - - Document(this.classifier) + List<InlineSyntax> inlineSyntaxes; + Resolver linkResolver; + + Document({this.inlineSyntaxes, this.linkResolver}) : refLinks = <String, Link>{}; - - String classify(String syntax, String source) { - if (syntax == 'dart') return classifyDart(source); - if (classifier == null) return source; - return classifier(syntax, source); - } - + parseRefLinks(List<String> lines) { // This is a hideous regex. It matches: // [id]: http:foo.com "some title"
diff --git a/pkgs/markdown/lib/src/markdown/block_parser.dart b/pkgs/markdown/lib/src/markdown/block_parser.dart index b59c795..42b9353 100644 --- a/pkgs/markdown/lib/src/markdown/block_parser.dart +++ b/pkgs/markdown/lib/src/markdown/block_parser.dart
@@ -20,7 +20,7 @@ final _RE_INDENT = new RegExp(r'^(?: |\t)(.*)$'); /// GitHub style triple quoted code block. -final _RE_CODE = new RegExp(r'^```(\w*)$'); +final _RE_CODE = new RegExp(r'^```(.*)$'); /// Three or more hyphens, asterisks or underscores by themselves. Note that /// a line like `----` is valid as both HR and SETEXT. In case of a tie, @@ -238,9 +238,9 @@ childLines.add(''); // Escape the code. - final escaped = childLines.join('n');//classifySource(); + final escaped = escapeHtml(childLines.join('\n')); - return new Element.text('pre', escaped); + return new Element('pre', [new Element.text('code', escaped)]); } } @@ -274,9 +274,9 @@ childLines.add(''); // Escape the code. - final escaped = parser.document.classify(syntax, childLines.join('\n').trim()); + final escaped = escapeHtml(childLines.join('\n')); - return new Element.text('pre', escaped); + return new Element('pre', [new Element.text('code', escaped)]); } } @@ -315,7 +315,7 @@ parser.advance(); } - return new Text(Strings.join(childLines, '\n')); + return new Text(childLines.join('\n')); } } @@ -497,8 +497,7 @@ parser.advance(); } - final contents = parser.document.parseInline( - Strings.join(childLines, '\n')); + final contents = parser.document.parseInline(childLines.join('\n')); return new Element('p', contents); } }
diff --git a/pkgs/markdown/lib/src/markdown/html_renderer.dart b/pkgs/markdown/lib/src/markdown/html_renderer.dart index 1695e96..5494394 100644 --- a/pkgs/markdown/lib/src/markdown/html_renderer.dart +++ b/pkgs/markdown/lib/src/markdown/html_renderer.dart
@@ -24,17 +24,17 @@ } void visitText(Text text) { - buffer.add(text.text); + buffer.write(text.text); } bool visitElementBefore(Element element) { // Hackish. Separate block-level elements with newlines. if (!buffer.isEmpty && _BLOCK_TAGS.firstMatch(element.tag) != null) { - buffer.add('\n'); + buffer.write('\n'); } - buffer.add('<${element.tag}'); + buffer.write('<${element.tag}'); // Sort the keys so that we generate stable output. // TODO(rnystrom): This assumes keys returns a fresh mutable @@ -42,20 +42,20 @@ final attributeNames = element.attributes.keys.toList(); attributeNames.sort((a, b) => a.compareTo(b)); for (final name in attributeNames) { - buffer.add(' $name="${element.attributes[name]}"'); + buffer.write(' $name="${element.attributes[name]}"'); } if (element.isEmpty) { // Empty element like <hr/>. - buffer.add(' />'); + buffer.write(' />'); return false; } else { - buffer.add('>'); + buffer.write('>'); return true; } } void visitElementAfter(Element element) { - buffer.add('</${element.tag}>'); + buffer.write('</${element.tag}>'); } }
diff --git a/pkgs/markdown/lib/src/markdown/inline_parser.dart b/pkgs/markdown/lib/src/markdown/inline_parser.dart index af42e3e..d3ec7ae 100644 --- a/pkgs/markdown/lib/src/markdown/inline_parser.dart +++ b/pkgs/markdown/lib/src/markdown/inline_parser.dart
@@ -7,56 +7,51 @@ /// Maintains the internal state needed to parse inline span elements in /// markdown. class InlineParser { - static List<InlineSyntax> get syntaxes { - // Lazy initialize. - if (_syntaxes == null) { - _syntaxes = <InlineSyntax>[ - // This first regexp matches plain text to accelerate parsing. It must - // be written so that it does not match any prefix of any following - // syntax. Most markdown is plain text, so it is faster to match one - // regexp per 'word' rather than fail to match all the following regexps - // at each non-syntax character position. It is much more important - // that the regexp is fast than complete (for example, adding grouping - // is likely to slow the regexp down enough to negate its benefit). - // Since it is purely for optimization, it can be removed for debugging. - new TextSyntax(r'\s*[A-Za-z0-9]+'), + static List<InlineSyntax> defaultSyntaxes = <InlineSyntax>[ + // This first regexp matches plain text to accelerate parsing. It must + // be written so that it does not match any prefix of any following + // syntax. Most markdown is plain text, so it is faster to match one + // regexp per 'word' rather than fail to match all the following regexps + // at each non-syntax character position. It is much more important + // that the regexp is fast than complete (for example, adding grouping + // is likely to slow the regexp down enough to negate its benefit). + // Since it is purely for optimization, it can be removed for debugging. - // The real syntaxes. + // TODO(amouravski): this regex will glom up any custom syntaxes unless + // they're at the beginning. + new TextSyntax(r'\s*[A-Za-z0-9]+'), - new AutolinkSyntax(), - new LinkSyntax(), - // "*" surrounded by spaces is left alone. - new TextSyntax(r' \* '), - // "_" surrounded by spaces is left alone. - new TextSyntax(r' _ '), - // Leave already-encoded HTML entities alone. Ensures we don't turn - // "&" into "&amp;" - new TextSyntax(r'&[#a-zA-Z0-9]*;'), - // Encode "&". - new TextSyntax(r'&', sub: '&'), - // Encode "<". (Why not encode ">" too? Gruber is toying with us.) - new TextSyntax(r'<', sub: '<'), - // Parse "**strong**" tags. - new TagSyntax(r'\*\*', tag: 'strong'), - // Parse "__strong__" tags. - new TagSyntax(r'__', tag: 'strong'), - // Parse "*emphasis*" tags. - new TagSyntax(r'\*', tag: 'em'), - // Parse "_emphasis_" tags. - // TODO(rnystrom): Underscores in the middle of a word should not be - // parsed as emphasis like_in_this. - new TagSyntax(r'_', tag: 'em'), - // Parse inline code within double backticks: "``code``". - new CodeSyntax(r'``\s?((?:.|\n)*?)\s?``'), - // Parse inline code within backticks: "`code`". - new CodeSyntax(r'`([^`]*)`') - ]; - } + // The real syntaxes. - return _syntaxes; - } - - static List<InlineSyntax> _syntaxes; + new AutolinkSyntax(), + new LinkSyntax(), + // "*" surrounded by spaces is left alone. + new TextSyntax(r' \* '), + // "_" surrounded by spaces is left alone. + new TextSyntax(r' _ '), + // Leave already-encoded HTML entities alone. Ensures we don't turn + // "&" into "&amp;" + new TextSyntax(r'&[#a-zA-Z0-9]*;'), + // Encode "&". + new TextSyntax(r'&', sub: '&'), + // Encode "<". (Why not encode ">" too? Gruber is toying with us.) + new TextSyntax(r'<', sub: '<'), + // Parse "**strong**" tags. + new TagSyntax(r'\*\*', tag: 'strong'), + // Parse "__strong__" tags. + new TagSyntax(r'__', tag: 'strong'), + // Parse "*emphasis*" tags. + new TagSyntax(r'\*', tag: 'em'), + // Parse "_emphasis_" tags. + // TODO(rnystrom): Underscores in the middle of a word should not be + // parsed as emphasis like_in_this. + new TagSyntax(r'_', tag: 'em'), + // Parse inline code within double backticks: "``code``". + new CodeSyntax(r'``\s?((?:.|\n)*?)\s?``'), + // Parse inline code within backticks: "`code`". + new CodeSyntax(r'`([^`]*)`') + // We will add the LinkSyntax once we know about the specific link resolver. + ]; /// The string of markdown being parsed. final String source; @@ -64,6 +59,8 @@ /// The markdown document this parser is parsing. final Document document; + List<InlineSyntax> syntaxes; + /// The current read position. int pos = 0; @@ -73,7 +70,18 @@ final List<TagState> _stack; InlineParser(this.source, this.document) - : _stack = <TagState>[]; + : _stack = <TagState>[] { + /// User specified syntaxes will be the first syntaxes to be evaluated. + if (document.inlineSyntaxes != null) { + syntaxes = []; + syntaxes.addAll(document.inlineSyntaxes); + syntaxes.addAll(defaultSyntaxes); + } else { + syntaxes = defaultSyntaxes; + } + // Custom link resolver goes after the generic text syntax. + syntaxes.insert(1, new LinkSyntax(linkResolver: document.linkResolver)); + } List<Node> parse() { // Make a fake top tag to hold the results. @@ -236,6 +244,8 @@ /// Matches inline links like `[blah] [id]` and `[blah] (url)`. class LinkSyntax extends TagSyntax { + Resolver linkResolver; + /// The regex for the end of a link needs to handle both reference style and /// inline styles as well as optional titles for inline links. To make that /// a bit more palatable, this breaks it into pieces. @@ -253,7 +263,7 @@ // 4: Contains the title, if present, for an inline link. } - LinkSyntax() + LinkSyntax({this.linkResolver}) : super(r'\[', end: linkPattern); bool onMatchEnd(InlineParser parser, Match match, TagState state) { @@ -263,10 +273,10 @@ // If we didn't match refLink or inlineLink, then it means there was // nothing after the first square bracket, so it isn't a normal markdown // link at all. Instead, we allow users of the library to specify a special - // resolver function ([setImplicitLinkResolver]) that may choose to handle + // resolver function ([linkResolver]) that may choose to handle // this. Otherwise, it's just treated as plain text. if ((match[1] == null) || (match[1] == '')) { - if (_implicitLinkResolver == null) return false; + if (linkResolver == null) return false; // Only allow implicit links if the content is just text. // TODO(rnystrom): Do we want to relax this? @@ -276,7 +286,7 @@ Text link = state.children[0]; // See if we have a resolver that will generate a link for us. - final node = _implicitLinkResolver(link.text); + final node = linkResolver(link.text); if (node == null) return false; parser.addNode(node); @@ -376,9 +386,8 @@ int index = parser._stack.indexOf(this); // Remove the unmatched children. - final unmatchedTags = parser._stack.getRange(index + 1, - parser._stack.length - index - 1); - parser._stack.removeRange(index + 1, parser._stack.length - index - 1); + final unmatchedTags = parser._stack.sublist(index + 1); + parser._stack.removeRange(index + 1, parser._stack.length); // Flatten them out onto this tag. for (final unmatched in unmatchedTags) {