Index: lib/src/inline_parser.dart |
diff --git a/lib/src/inline_parser.dart b/lib/src/inline_parser.dart |
index c9cf98a94aed9b7e96e7f808b38bdb25ecb811fb..5c11d7f50084fc38e0c3fe686c6b0881e3cbcb8f 100644 |
--- a/lib/src/inline_parser.dart |
+++ b/lib/src/inline_parser.dart |
@@ -2,7 +2,7 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
-library markdown.inline_parser; |
+library markdown.src.inline_parser; |
import 'ast.dart'; |
import 'document.dart'; |
@@ -26,7 +26,6 @@ class InlineParser { |
new TextSyntax(r'\s*[A-Za-z0-9]+'), |
// The real syntaxes. |
- |
new AutolinkSyntax(), |
new LinkSyntax(), |
new ImageLinkSyntax(), |
@@ -75,13 +74,15 @@ class InlineParser { |
final List<TagState> _stack; |
InlineParser(this.source, this.document) : _stack = <TagState>[] { |
- /// User specified syntaxes will be the first syntaxes to be evaluated. |
+ // User specified syntaxes are the first syntaxes to be evaluated. |
if (document.inlineSyntaxes != null) { |
syntaxes.addAll(document.inlineSyntaxes); |
} |
+ |
syntaxes.addAll(_defaultSyntaxes); |
+ |
// Custom link resolvers goes after the generic text syntax. |
- syntaxes.insertAll(1, <InlineSyntax>[ |
+ syntaxes.insertAll(1, [ |
new LinkSyntax(linkResolver: document.linkResolver), |
new ImageLinkSyntax(linkResolver: document.imageLinkResolver) |
]); |
@@ -92,25 +93,28 @@ class InlineParser { |
_stack.add(new TagState(0, 0, null)); |
while (!isDone) { |
- bool matched = false; |
+ var matched = false; |
// See if any of the current tags on the stack match. We don't allow tags |
- // of the same kind to nest, so this takes priority over other possible // matches. |
- for (int i = _stack.length - 1; i > 0; i--) { |
+ // of the same kind to nest, so this takes priority over other possible |
+ // matches. |
+ for (var i = _stack.length - 1; i > 0; i--) { |
if (_stack[i].tryMatch(this)) { |
matched = true; |
break; |
} |
} |
+ |
if (matched) continue; |
// See if the current text matches any defined markdown syntax. |
- for (final syntax in syntaxes) { |
+ for (var syntax in syntaxes) { |
if (syntax.tryMatch(this)) { |
matched = true; |
break; |
} |
} |
+ |
if (matched) continue; |
// If we got here, it's just text. |
@@ -127,17 +131,16 @@ class InlineParser { |
} |
void writeTextRange(int start, int end) { |
- if (end > start) { |
- final text = source.substring(start, end); |
- final nodes = _stack.last.children; |
- |
- // If the previous node is text too, just append. |
- if ((nodes.length > 0) && (nodes.last is Text)) { |
- final newNode = new Text('${nodes.last.text}$text'); |
- nodes[nodes.length - 1] = newNode; |
- } else { |
- nodes.add(new Text(text)); |
- } |
+ if (end <= start) return; |
+ |
+ var text = source.substring(start, end); |
+ var nodes = _stack.last.children; |
+ |
+ // If the previous node is text too, just append. |
+ if (nodes.length > 0 && nodes.last is Text) { |
+ nodes[nodes.length - 1] = new Text('${nodes.last.text}$text'); |
+ } else { |
+ nodes.add(new Text(text)); |
} |
} |
@@ -147,6 +150,7 @@ class InlineParser { |
// TODO(rnystrom): Only need this because RegExp doesn't let you start |
// searching from a given offset. |
+ @deprecated |
String get currentSource => source.substring(pos, source.length); |
bool get isDone => pos == source.length; |
@@ -168,16 +172,15 @@ abstract class InlineSyntax { |
InlineSyntax(String pattern) : pattern = new RegExp(pattern, multiLine: true); |
bool tryMatch(InlineParser parser) { |
- final startMatch = pattern.firstMatch(parser.currentSource); |
- if ((startMatch != null) && (startMatch.start == 0)) { |
+ var startMatch = pattern.matchAsPrefix(parser.source, parser.pos); |
+ if (startMatch != null) { |
// Write any existing plain text up to this point. |
parser.writeText(); |
- if (onMatch(parser, startMatch)) { |
- parser.consume(startMatch[0].length); |
- } |
+ if (onMatch(parser, startMatch)) parser.consume(startMatch[0].length); |
return true; |
} |
+ |
return false; |
} |
@@ -187,6 +190,7 @@ abstract class InlineSyntax { |
/// Matches stuff that should just be passed through as straight text. |
class TextSyntax extends InlineSyntax { |
final String substitute; |
+ |
TextSyntax(String pattern, {String sub}) |
: super(pattern), |
substitute = sub; |
@@ -210,10 +214,9 @@ class AutolinkSyntax extends InlineSyntax { |
// TODO(rnystrom): Make case insensitive. |
bool onMatch(InlineParser parser, Match match) { |
- final url = match[1]; |
- |
- final anchor = new Element.text('a', escapeHtml(url)) |
- ..attributes['href'] = url; |
+ var url = match[1]; |
+ var anchor = new Element.text('a', escapeHtml(url)); |
+ anchor.attributes['href'] = url; |
parser.addNode(anchor); |
return true; |
@@ -226,15 +229,13 @@ class TagSyntax extends InlineSyntax { |
final RegExp endPattern; |
final String tag; |
- TagSyntax(String pattern, {String tag, String end}) |
+ TagSyntax(String pattern, {this.tag, String end}) |
: super(pattern), |
- endPattern = new RegExp((end != null) ? end : pattern, multiLine: true), |
- tag = tag; |
- // TODO(rnystrom): Doing this.field doesn't seem to work with named args. |
+ endPattern = new RegExp((end != null) ? end : pattern, multiLine: true); |
bool onMatch(InlineParser parser, Match match) { |
- parser._stack.add( |
- new TagState(parser.pos, parser.pos + match[0].length, this)); |
+ parser._stack |
+ .add(new TagState(parser.pos, parser.pos + match[0].length, this)); |
return true; |
} |
@@ -255,9 +256,9 @@ class LinkSyntax extends TagSyntax { |
/// inline styles as well as optional titles for inline links. To make that |
/// a bit more palatable, this breaks it into pieces. |
static get linkPattern { |
- final refLink = r'\s?\[([^\]]*)\]'; // "[id]" reflink id. |
- final title = r'(?:[ ]*"([^"]+)"|)'; // Optional title in quotes. |
- final inlineLink = '\\s?\\(([^ )]+)$title\\)'; // "(url "title")" link. |
+ var refLink = r'\s?\[([^\]]*)\]'; // "[id]" reflink id. |
+ var title = r'(?:[ ]*"([^"]+)"|)'; // Optional title in quotes. |
+ var inlineLink = '\\s?\\(([^ )]+)$title\\)'; // "(url "title")" link. |
return '\](?:($refLink|$inlineLink)|)'; |
// The groups matched by this are: |
@@ -277,7 +278,7 @@ class LinkSyntax extends TagSyntax { |
// link at all. Instead, we allow users of the library to specify a special |
// resolver function ([linkResolver]) that may choose to handle |
// this. Otherwise, it's just treated as plain text. |
- if (isNullOrEmpty(match[1])) { |
+ if (match[1] == null) { |
if (linkResolver == null) return null; |
// Treat the contents as unparsed text even if they happen to match. This |
@@ -289,20 +290,20 @@ class LinkSyntax extends TagSyntax { |
resolved = true; |
return linkResolver(textToResolve); |
} else { |
- Link link = getLink(parser, match, state); |
+ var link = getLink(parser, match, state); |
if (link == null) return null; |
- final Element node = new Element('a', state.children) |
- ..attributes["href"] = escapeHtml(link.url) |
- ..attributes['title'] = escapeHtml(link.title); |
+ var node = new Element('a', state.children); |
+ |
+ node.attributes["href"] = escapeHtml(link.url); |
+ if (link.title != null) node.attributes['title'] = escapeHtml(link.title); |
- cleanMap(node.attributes); |
return node; |
} |
} |
Link getLink(InlineParser parser, Match match, TagState state) { |
- if ((match[3] != null) && (match[3] != '')) { |
+ if (match[3] != null && match[3] != '') { |
// Inline link like [foo](url). |
var url = match[3]; |
var title = match[4]; |
@@ -316,10 +317,12 @@ class LinkSyntax extends TagSyntax { |
} else { |
var id; |
// Reference link like [foo] [bar]. |
- if (match[2] == '') |
- // The id is empty ("[]") so infer it from the contents. |
- id = parser.source.substring(state.startPos + 1, parser.pos); |
- else id = match[2]; |
+ if (match[2] == '') { |
+ // The id is empty ("[]") so infer it from the contents. |
+ id = parser.source.substring(state.startPos + 1, parser.pos); |
+ } else { |
+ id = match[2]; |
+ } |
// References are case-insensitive. |
id = id.toLowerCase(); |
@@ -328,8 +331,9 @@ class LinkSyntax extends TagSyntax { |
} |
bool onMatchEnd(InlineParser parser, Match match, TagState state) { |
- Node node = createNode(parser, match, state); |
+ var node = createNode(parser, match, state); |
if (node == null) return false; |
+ |
parser.addNode(node); |
return true; |
} |
@@ -339,21 +343,24 @@ class LinkSyntax extends TagSyntax { |
/// `![alternate text][url reference]`. |
class ImageLinkSyntax extends LinkSyntax { |
final Resolver linkResolver; |
+ |
ImageLinkSyntax({this.linkResolver}) : super(pattern: r'!\['); |
Node createNode(InlineParser parser, Match match, TagState state) { |
var node = super.createNode(parser, match, state); |
+ |
if (resolved) return node; |
if (node == null) return null; |
- final Element imageElement = new Element.withTag("img") |
- ..attributes["src"] = node.attributes["href"] |
- ..attributes["title"] = node.attributes["title"] |
- ..attributes["alt"] = node.children |
- .map((e) => isNullOrEmpty(e) || e is! Text ? '' : e.text) |
- .join(' '); |
+ var imageElement = new Element.withTag("img"); |
+ imageElement.attributes["src"] = node.attributes["href"]; |
+ |
+ if (node.attributes.containsKey("title")) { |
+ imageElement.attributes["title"] = node.attributes["title"]; |
+ } |
- cleanMap(imageElement.attributes); |
+ var alt = node.children.map((e) => e is! Text ? '' : e.text).join(" "); |
+ if (alt != "") imageElement.attributes["alt"] = alt; |
node.children |
..clear() |
@@ -393,8 +400,8 @@ class TagState { |
/// Attempts to close this tag by matching the current text against its end |
/// pattern. |
bool tryMatch(InlineParser parser) { |
- Match endMatch = syntax.endPattern.firstMatch(parser.currentSource); |
- if ((endMatch != null) && (endMatch.start == 0)) { |
+ var endMatch = syntax.endPattern.matchAsPrefix(parser.source, parser.pos); |
+ if (endMatch != null) { |
// Close the tag. |
close(parser, endMatch); |
return true; |
@@ -411,14 +418,14 @@ class TagState { |
// means they are mismatched. Mismatched tags are treated as plain text in |
// markdown. So for each tag above this one, we write its start tag as text |
// and then adds its children to this one's children. |
- int index = parser._stack.indexOf(this); |
+ var index = parser._stack.indexOf(this); |
// Remove the unmatched children. |
- final unmatchedTags = parser._stack.sublist(index + 1); |
+ var 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) { |
+ for (var unmatched in unmatchedTags) { |
// Write the start tag as text. |
parser.writeTextRange(unmatched.startPos, unmatched.endPos); |