diff --git a/lib/definitions.dart b/lib/definitions.dart
index 2f9942d..c696c9c 100644
--- a/lib/definitions.dart
+++ b/lib/definitions.dart
@@ -568,6 +568,18 @@ class Strong extends Inline {
}
+class Strikeout extends Inline {
+ Inlines contents;
+
+ Strikeout(this.contents);
+
+ String toString() => 'Strikeout $contents';
+
+ bool operator== (obj) => obj is Strikeout &&
+ _iterableEquality.equals(contents, obj.contents);
+}
+
+
abstract class Link extends Inline {
Inlines label;
Target target;
diff --git a/lib/html_writer.dart b/lib/html_writer.dart
index 0921e0a..c5d2105 100644
--- a/lib/html_writer.dart
+++ b/lib/html_writer.dart
@@ -179,6 +179,8 @@ class _HtmlBuilder extends StringBuffer {
writeEmph(inline, stripped: stripped);
} else if (inline is Strong) {
writeStrong(inline, stripped: stripped);
+ } else if (inline is Strikeout) {
+ writeStrikeout(inline, stripped: stripped);
} else if (inline is Link) {
writeLink(inline, stripped: stripped);
} else if (inline is Image) {
@@ -241,6 +243,17 @@ class _HtmlBuilder extends StringBuffer {
}
+ void writeStrikeout(Strikeout strikeout, {bool stripped: false}) {
+ if (!stripped) {
+ write('');
+ }
+ writeInlines(strikeout.contents, stripped: stripped);
+ if (!stripped) {
+ write('');
+ }
+ }
+
+
void writeSmartQuote(SmartQuote quote, {bool stripped: false}) {
// TODO different quotation styles
if (quote.open && quote.close) {
@@ -335,6 +348,7 @@ class HtmlWriter {
return builder.toString();
}
+ static HtmlWriter commonmark = new HtmlWriter(Options.commonmark);
static HtmlWriter strict = new HtmlWriter(Options.strict);
static HtmlWriter defaults = new HtmlWriter(Options.defaults);
}
diff --git a/lib/markdown_parser.dart b/lib/markdown_parser.dart
index 17e73b0..a77e0f9 100644
--- a/lib/markdown_parser.dart
+++ b/lib/markdown_parser.dart
@@ -68,7 +68,21 @@ class CommonMarkParser {
Map _references;
- CommonMarkParser(this._options, [this._references]);
+ String _inlineDelimiters;
+ String _strSpecialChars;
+
+ CommonMarkParser(this._options, [this._references]) {
+ _inlineDelimiters = "_*";
+ _strSpecialChars = " *_`![]&<\\";
+ if (_options.smartPunctuation) {
+ _inlineDelimiters += "'\"";
+ _strSpecialChars += "'\".-";
+ }
+ if (_options.strikeout) {
+ _inlineDelimiters += "~";
+ _strSpecialChars += "~";
+ }
+ }
Document parse(String s) {
// TODO separate preprocess option
@@ -519,8 +533,9 @@ class CommonMarkParser {
static RegExp _isSpace = new RegExp(r'^\s');
static RegExp _isPunctuation = new RegExp("^[\u{2000}-\u{206F}\u{2E00}-\u{2E7F}\\\\'!\"#\\\$%&\\(\\)\\*\\+,\\-\\.\\/:;<=>\\?@\\[\\]\\^_`\\{\\|\\}~]");
+
Parser get scanDelims => new Parser((String s, Position pos) {
- ParseResult testRes = oneOf(_options.smartPunctuation ? "*_'\"" : "*_").lookAhead.run(s, pos);
+ ParseResult testRes = oneOf(_inlineDelimiters).lookAhead.run(s, pos);
if (!testRes.isSuccess) {
return testRes;
}
@@ -544,6 +559,10 @@ class CommonMarkParser {
canOpen = canOpen && (!rightFlanking || _isPunctuation.hasMatch(charBefore));
canClose = canClose && (!leftFlanking || _isPunctuation.hasMatch(charAfter));
}
+ if (c == '~' && numDelims < 2) {
+ canOpen = false;
+ canClose = false;
+ }
return res.copy(value: [numDelims, canOpen, canClose, c]);
});
@@ -618,6 +637,17 @@ class CommonMarkParser {
inlines.add(inline);
count--;
}
+ } else if (char == "~") {
+ if (count & 1 == 1) {
+ inlines.add(new Str("~"));
+ count--;
+ }
+ while (count > 0) {
+ inline = new Strikeout(inlines);
+ inlines = new Inlines();
+ inlines.add(inline);
+ count -= 2;
+ }
} else {
if (count & 1 == 1) {
inline = new Emph(inlines);
@@ -930,7 +960,6 @@ class CommonMarkParser {
};
- String get _strSpecialChars => _options.smartPunctuation ? " *_`'\".-![]&<\\" : " *_`![]&<\\";
Parser get str => (noneOf(_strSpecialChars + "\n").many1 ^ (chars) => _transformString(chars.join())) |
(oneOf(_strSpecialChars) ^ (chars) => _transformString(chars)) |
(char("\n").notFollowedBy(spnl) ^ (_) => [new Str("\n")]);
@@ -1793,6 +1822,7 @@ class CommonMarkParser {
Parser get document => (block.manyUntil(eof) ^ (res) => new Document(processParsedBlocks(res))) % "document";
+ static CommonMarkParser commonmark = new CommonMarkParser(Options.commonmark);
static CommonMarkParser defaults = new CommonMarkParser(Options.defaults);
static CommonMarkParser strict = new CommonMarkParser(Options.strict);
}
diff --git a/lib/markdown_writer.dart b/lib/markdown_writer.dart
index dc671d0..1e1bb15 100644
--- a/lib/markdown_writer.dart
+++ b/lib/markdown_writer.dart
@@ -128,6 +128,10 @@ class _NotCheckedPart extends _InlinePart {
});
}
+ if (_options.strikeout) {
+ content = content.replaceAll(new RegExp("~~"), r"\~~");
+ }
+
if (!context.isHeader) {
content = content.replaceAllMapped(_notHeaderRegExp1, (Match m) => m.group(1) + r"\" + m.group(2));
content = content.replaceAllMapped(_notHeaderRegExp2, (Match m) => m.group(1) + r"\" + m.group(2));
@@ -301,6 +305,8 @@ class _InlineRenderer {
}
} else if (inline is SmartQuote) {
writeSmartQuote(inline, context: context);
+ } else if (inline is Strikeout) {
+ writeStrikeout(inline, context: context);
} else if (inline is RawInline) {
write(inline.contents);
} else {
@@ -364,6 +370,13 @@ class _InlineRenderer {
}
+ void writeStrikeout(Strikeout strikeout, {_EscapeContext context: _EscapeContext.empty}) {
+ write("~~");
+ writeInlines(strikeout.contents, context: context);
+ write("~~");
+ }
+
+
void writeLink(Link link) {
if (link is InlineLink) {
write('[');
@@ -708,6 +721,7 @@ class MarkdownWriter {
return builder.toString();
}
+ static const MarkdownWriter commonmark = const MarkdownWriter(Options.commonmark);
static const MarkdownWriter strict = const MarkdownWriter(Options.strict);
static const MarkdownWriter defaults = const MarkdownWriter(Options.defaults);
}
diff --git a/lib/options.dart b/lib/options.dart
index 14a7741..d120666 100644
--- a/lib/options.dart
+++ b/lib/options.dart
@@ -15,13 +15,17 @@ Target defaultLinkResolver(String normalizedReference, String reference) => null
class Options {
final bool smartPunctuation;
+ final bool strikeout;
final LinkResolver linkResolver;
const Options({
this.smartPunctuation: false,
+ this.strikeout: false,
this.linkResolver: defaultLinkResolver
});
- static const Options defaults = const Options(smartPunctuation: true);
+ static const Options commonmark = const Options(smartPunctuation: true);
+ static const Options defaults = const Options(smartPunctuation: true,
+ strikeout: true);
static const Options strict = const Options();
}
diff --git a/test/data/strikeout.txt b/test/data/strikeout.txt
new file mode 100644
index 0000000..97b9673
--- /dev/null
+++ b/test/data/strikeout.txt
@@ -0,0 +1,37 @@
+## Strikeout tests
+
+.
+~~Strikeout text~~
+.
+Strikeout text
+.
+
+.
+~~__Strikeout text__~~
+.
+Strikeout text
+.
+
+.
+Ins~~e~~ide w~~a~~ord
+.
+Inseide waord
+.
+
+.
+~\~No strikeout~~
+.
+~~No strikeout~~
+.
+
+.
+\~~No strikeout~~
+.
+~~No strikeout~~
+.
+
+.
+~No strikeout~
+.
+~No strikeout~
+.
diff --git a/test/data/test_data.dart b/test/data/test_data.dart
index 52c7ae0..21ec2bc 100644
--- a/test/data/test_data.dart
+++ b/test/data/test_data.dart
@@ -15,3 +15,6 @@ final Map markdownToMarkdown = _$markdownToMarkdownTests;
@EmbedTests('additionalMarkdownToHtml.txt')
final Map additionalMarkdownToHtml = _$additionalMarkdownToHtmlTests;
+
+@EmbedTests('strikeout.txt')
+final Map strikeout = _$strikeoutTests;
diff --git a/test/data/test_data.g.dart b/test/data/test_data.g.dart
index 31eefcf..5a0b91b 100644
--- a/test/data/test_data.g.dart
+++ b/test/data/test_data.g.dart
@@ -1,5 +1,5 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
-// 2015-08-10T12:56:10.881Z
+// 2015-08-10T14:52:17.270Z
part of md_proc.test.data.test_data;
@@ -4145,3 +4145,29 @@ bar
''',
};
+
+// **************************************************************************
+// Generator: EmbedTestsGenerator
+// Target: final Map strikeout
+// **************************************************************************
+
+final Map _$strikeoutTests = {
+ r'''~~Strikeout text~~
+''': r'''Strikeout text
+''',
+ r'''~~__Strikeout text__~~
+''': r'''Strikeout text
+''',
+ r'''Ins~~e~~ide w~~a~~ord
+''': r'''Inseide waord
+''',
+ r'''~\~No strikeout~~
+''': r'''~~No strikeout~~
+''',
+ r'''\~~No strikeout~~
+''': r'''~~No strikeout~~
+''',
+ r'''~No strikeout~
+''': r'''~No strikeout~
+''',
+};
diff --git a/test/library_test.dart b/test/library_test.dart
index 3bab148..821740e 100644
--- a/test/library_test.dart
+++ b/test/library_test.dart
@@ -22,6 +22,7 @@ void main() {
tests("Additional", additionalMarkdownToHtml, mdToHtmlTest(Options.strict));
// Additional tests
tests("SmartPunct", smartPunctuation, mdToHtmlTest(Options.defaults));
+ tests("Strikeout", strikeout, mdToHtmlTest(Options.defaults));
// Markdown to markdown tests
tests("md2md", markdownToMarkdown, mdToMdTest(Options.strict));
// Custom resolver
diff --git a/test/service.dart b/test/service.dart
index 08ef521..0e6343f 100644
--- a/test/service.dart
+++ b/test/service.dart
@@ -495,6 +495,20 @@ void serviceTests() {
});
});
+ t.group('Strikeout', () {
+ var strikeout = new Strikeout(new Inlines.from([new Str('Strikeout')]));
+ t.test('toString', () {
+ t.expect(strikeout.toString(), t.equals('Strikeout [Str "Strikeout"]'));
+ });
+ t.test('==', () {
+ t.expect(strikeout, t.equals(new Strikeout(new Inlines.from([new Str('Strikeout')]))));
+ });
+ t.test('!=', () {
+ t.expect(strikeout, t.isNot(t.equals(new Inlines.from([new Str('Emph')]))));
+ t.expect(strikeout, t.isNot(t.equals(null)));
+ });
+ });
+
t.group('InlineLink', () {
var link = new InlineLink(new Inlines.from([new Str('Dart')]), new Target('https://www.dartlang.org/', null));
t.test('toString', () {