Compare commits

...

251 Commits

Author SHA1 Message Date
Alexandre Mutel
3ef1d735d5 Bump to 0.20.0 2020-04-18 18:31:44 +02:00
Alexandre Mutel
47c6c49f5c Merge pull request #417 from KrisVandermotten/StringBuilderCache
Cleanup StringBuilderCache
2020-04-18 18:21:39 +02:00
Kris Vandermotten
a19f78342f merged from master 2020-04-18 18:17:40 +02:00
Alexandre Mutel
edb4c6c3cb Merge pull request #422 from KrisVandermotten/ListBlockParser
Cleanup ListBlockParser
2020-04-18 17:58:49 +02:00
Alexandre Mutel
4b6d7c78f5 Merge pull request #421 from KrisVandermotten/ParagraphBlockParser
Cleanup ParagraphBlockParser
2020-04-18 17:57:51 +02:00
Alexandre Mutel
0386cfd617 Merge pull request #418 from KrisVandermotten/CodeInlineParser
Optimized away the expensive StringBuilder.Remove(0, 1) in CodeInlineParser
2020-04-18 17:55:53 +02:00
Alexandre Mutel
5c52a7249d Merge pull request #416 from MihaZupan/new
Random improvements
2020-04-18 17:54:22 +02:00
Kris Vandermotten
14fb550704 Merge branch 'master' into StringBuilderCache 2020-04-18 14:21:48 +02:00
Kris Vandermotten
741d09a4e8 Merge branch 'master' into CodeInlineParser 2020-04-18 14:21:09 +02:00
Kris Vandermotten
34d9fa2bcc Merge branch 'master' into ParagraphBlockParser 2020-04-18 14:20:24 +02:00
Kris Vandermotten
8ee50a265d Merge branch 'master' into ListBlockParser 2020-04-18 14:19:46 +02:00
MihaZupan
eb002db3c7 Cross-target netstandard2.1 2020-04-18 14:14:57 +02:00
MihaZupan
a15203a061 Don't count non-ascii chars into maxChar limit in CharacterMap 2020-04-18 14:10:01 +02:00
MihaZupan
b0a2f19ed7 Optimize CharacterMap further 2020-04-18 14:10:00 +02:00
MihaZupan
a9d78e04a1 Cross-target Core 3.1 2020-04-18 14:10:00 +02:00
MihaZupan
a8b6e2c2e4 Remove allocation in EntityHelper.DecodeEntity 2020-04-18 14:10:00 +02:00
MihaZupan
665f5f5e51 Cache string representations of numbers 0-26 2020-04-18 14:10:00 +02:00
MihaZupan
86a72c3582 Avoid delegate allocation in LinkInlineParser.MarkParentAsInactive 2020-04-18 14:10:00 +02:00
MihaZupan
784b999d6c Improve CodeGen by using ThrowHelper everywhere 2020-04-18 14:10:00 +02:00
MihaZupan
be3a893d3d Use foreach where appropriate 2020-04-18 14:10:00 +02:00
MihaZupan
2679c84788 Remove .Net Foundation license header 2020-04-18 14:10:00 +02:00
MihaZupan
3d005d6444 Avoid allocations in EntityHelper 2020-04-18 14:09:59 +02:00
MihaZupan
09593ff3da Remove unused Helper 2020-04-18 14:09:59 +02:00
MihaZupan
f0269fc61f Remove ArrayHelper 2020-04-18 14:09:59 +02:00
MihaZupan
2d97628cfd Optimize StringSlice helpers 2020-04-18 14:09:59 +02:00
MihaZupan
ee97d32ef0 Remove MethodImplOptionPortable compat helper 2020-04-18 14:09:59 +02:00
MihaZupan
9ca5cdcb31 Remove substring allocation in RomanToArabic 2020-04-18 14:09:59 +02:00
MihaZupan
5f453fbe92 Remove ExcludeFromCodeCoverage compat for net35 2020-04-18 14:09:59 +02:00
MihaZupan
8300a9cca2 Add System.Memory package for netstandard2.0 2020-04-18 14:09:59 +02:00
MihaZupan
f7d763230d Unseal MarkdownParserContext 2020-04-18 14:09:58 +02:00
MihaZupan
cce1b99edc Drop net35 and net40 targets 2020-04-18 14:07:48 +02:00
Alexandre Mutel
2dca2119fa Run coveralls.net upload only on push 2020-04-18 09:13:32 +02:00
Alexandre Mutel
faf0a20816 Fix coverlet and coverall.net upload 2020-04-18 09:02:02 +02:00
Alexandre Mutel
68196c1ce6 Fix specs 2020-04-18 08:48:49 +02:00
Kris Vandermotten
fdf125d05d Cleanup ListBlockParser 2020-04-16 20:09:00 +02:00
Kris Vandermotten
46133715ab Cleanup ParagraphBlockParser 2020-04-16 20:03:40 +02:00
Kris Vandermotten
4151ac2287 Optimized away the expensive StringBuilder.Remove(0, 1) in CodeInlineParser 2020-04-13 16:24:35 +02:00
Kris Vandermotten
305f722899 Cleanup StringBuilderCache 2020-04-13 16:02:04 +02:00
Alexandre Mutel
abc8aa25b7 Merge pull request #411 from WeihanLi/patch-1
make dotnet framework ReferenceAssemblies Private
2020-03-23 20:49:37 +01:00
Alexandre Mutel
e6bb83ecdf Merge pull request #410 from KrisVandermotten/RendererBase
Optimized RendererBase
2020-03-23 20:48:54 +01:00
Weihan Li
e6ea8ad274 make dotnet framework ReferenceAssemblies Private 2020-03-19 13:33:18 +08:00
Kris Vandermotten
1f3cf5962f Optimized RendererBase 2020-03-09 15:32:29 +01:00
Alexandre Mutel
83b3427805 Fix Microsoft.SourceLink.GitHub 2020-03-08 10:45:00 +01:00
Alexandre Mutel
3ff3f1ccb9 Bump to 0.18.3 2020-03-08 10:33:57 +01:00
Alexandre Mutel
5d91f0e26f Fix NuGet symbol packages 2020-03-08 10:33:13 +01:00
Alexandre Mutel
9af462e412 Bump to 0.18.2 2020-03-08 10:15:30 +01:00
Alexandre Mutel
e1ba52da20 Merge pull request #406 from FranklinWhale/patch-1
Make output of HtmlTableRenderer XML wellformed
2020-03-08 10:09:29 +01:00
Alexandre Mutel
70ee97d5c7 Merge pull request #404 from webmaster442/master
Fixes issue #303
2020-03-08 10:09:03 +01:00
Alexandre Mutel
da916a1700 Merge pull request #402 from KrisVandermotten/HeadingRendererBugFix
Fixed a bug in HeadingRenderer
2020-03-08 10:08:47 +01:00
Franklin Tse
5548246703 Update TestPlayParser.cs 2020-03-06 19:00:37 +08:00
Franklin Tse
097fc5c4e0 Update GridTableSpecs.md 2020-03-06 18:55:00 +08:00
Franklin Tse
168ad39ff6 Make output of HtmlTableRenderer XML wellformed 2020-03-06 18:49:22 +08:00
Alexandre Mutel
54e065aabe Merge pull request #405 from bbodenmiller/patch-1
Github -> GitHub
2020-03-06 08:56:56 +01:00
Ben Bodenmiller
98d58797d9 Github -> GitHub 2020-03-05 23:55:39 -08:00
Ruzsinszki Gábor
2f0dd2a6a7 Fixes issue #303 2020-03-03 11:10:17 +01:00
Kris Vandermotten
247209870e Fixed a bug in HeadingRenderer 2020-03-01 14:44:41 +01:00
Alexandre Mutel
ef5b958267 Merge pull request #399 from KrisVandermotten/StringLineGroup
Some optimizations in StringLineGroup
2020-02-18 21:01:55 +01:00
Kris Vandermotten
7d61df2c0c Some optimizations in StringLineGroup 2020-02-15 10:34:24 +01:00
Alexandre Mutel
51f9da1974 Merge pull request #396 from KrisVandermotten/CharacterMapBitVector128
Use BitVector128 in CharacterMap<T>
2020-02-06 06:56:32 +01:00
Kris Vandermotten
9321628b9c Use uint instead of ulong 2020-02-05 22:38:21 +01:00
Kris Vandermotten
525e2c7fb8 Use BitVector128 in CharacterMap<T> 2020-02-04 22:45:42 +01:00
Alexandre Mutel
1f9b70636f Merge pull request #394 from KrisVandermotten/charactermap
Use HashSet<T> instead of Dictionary<TKey, TValue> in CharacterMap<T>
2020-01-31 18:43:24 +01:00
Kris Vandermotten
d4f43f826f Use HashSet<T> instead of Dictionary<TKey, TValue> in CharacterMap<T> 2020-01-31 18:35:28 +01:00
Alexandre Mutel
62788b1101 Merge pull request #393 from MihaZupan/line-reader
Optimize LineReader.ReadLine
2020-01-31 08:01:42 +01:00
MihaZupan
c3c4d37b82 Optimize LineReader.ReadLine 2020-01-30 21:14:06 +01:00
Alexandre Mutel
333bf04274 Update ci.yml, fix publish 2020-01-29 08:14:26 +01:00
Alexandre Mutel
dab4b7176d Merge pull request #392 from RudeySH/patch-1
Add Bootstrap and YAML to exclusion list in readme
2020-01-27 19:00:14 +01:00
Rudey
25ec56e1be Change frontmatter to Front Matter 2020-01-27 18:50:25 +01:00
Rudey
3455fd12da Add Bootstrap and YAML to exclusion list in readme
Both the Bootstrap and YAML frontmatter aren't included in `UseAdvancedExtensions`, but the readme didn't specify that.
2020-01-27 18:30:53 +01:00
Alexandre Mutel
ae5d47a0ed Merge pull request #391 from MihaZupan/remove-uap-remains
Remove UAP specific code
2020-01-27 08:36:14 +01:00
MihaZupan
1ff721d512 Remove UAP specific code 2020-01-26 23:04:57 +01:00
Alexandre Mutel
2c130504e2 Merge pull request #389 from MihaZupan/code-coverage
Improve code coverage
2020-01-26 22:01:06 +01:00
Alexandre Mutel
6405b16692 Migrate to GitHub Actions 2020-01-26 19:42:23 +01:00
Alexandre Mutel
2e1912a23d Update projects to compile with dotnet build/test, remove uap10.0 2020-01-26 19:35:21 +01:00
MihaZupan
71c680388c Make ExcludeFromCodeCoverage compatibility stub internal 2020-01-22 02:27:50 +01:00
MihaZupan
3f50b3fd0b Add LinkHelper.UrilizeAsGfm tests 2020-01-22 02:18:24 +01:00
MihaZupan
99b250b4c9 Add ContainerBlock tests 2020-01-22 02:06:42 +01:00
MihaZupan
655bf13df0 Exclude CompactPrefixTree from code coverage 2020-01-22 01:43:12 +01:00
MihaZupan
d2c89a3a06 Add tests for core Markdown apis 2020-01-22 01:42:23 +01:00
MihaZupan
754d11fd44 Fix test execution inside VS Enterprise Live Unit Testing 2020-01-21 21:44:29 +01:00
MihaZupan
1252e49ba4 Add more custom emoji tests 2020-01-21 18:36:36 +01:00
MihaZupan
d18487ae53 Fix StringLineGroupIterator.PeekChar for cross-line peeks 2020-01-21 18:16:13 +01:00
MihaZupan
f401d5082e Add SmartyPants tests 2020-01-21 17:35:58 +01:00
Alexandre Mutel
dd6418d108 Bump to 0.18.1 2020-01-21 08:30:32 +01:00
Alexandre Mutel
7875e4bce9 Merge pull request #387 from MihaZupan/descendants-api
Add missing Descendants<T> api
2020-01-21 08:24:13 +01:00
Alexandre Mutel
2e1b1a1fdc Merge pull request #386 from mlaily/emoji-customization
Emojis and smileys customization
2020-01-21 08:23:48 +01:00
MihaZupan
fa2b157c1a Improve some CharHelper methods 2020-01-21 01:31:44 +01:00
MihaZupan
e4e6406546 Add missing Descendants<T> overload 2020-01-21 01:03:47 +01:00
Melvyn Laïly
1cff10270a Set the default emoji dictionaries capacity in their ctor 2020-01-16 09:12:05 +01:00
Melvyn Laïly
87023184cb Clarify emoji terminology (emoji "shortcode") 2020-01-16 09:12:04 +01:00
Melvyn Laïly
aecdf2192e Improve the emoji extension (code review remarks) 2020-01-16 09:12:04 +01:00
Melvyn Laïly
0a36382126 Update changelog 2020-01-16 09:12:04 +01:00
Melvyn Laïly
0057b368ec Add unit tests for custom emojis and smileys 2020-01-16 09:11:04 +01:00
Melvyn Laïly
3033284096 Re-allow emojis and smileys customization
(this feature was broken in #308)
2020-01-16 09:11:03 +01:00
Alexandre Mutel
9b1b791b18 Merge pull request #341 from OpportunityLiu/master
Add customizable media link; handle protocol-less media
2020-01-15 13:27:06 +01:00
Opportunity
2b7d205701 Merge branch 'master' into master 2020-01-15 19:35:17 +08:00
Opportunity
89b28659b1 Update src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs
Co-Authored-By: Alexandre Mutel <alexandre_mutel@live.com>
2020-01-15 19:32:37 +08:00
Alexandre Mutel
446b1bcc0d Bump to 0.18.0 2019-10-24 21:08:11 +02:00
Alexandre Mutel
ec7a4a6902 Create FUNDING.yml 2019-10-24 07:10:27 +02:00
Alexandre Mutel
07a77142f4 Merge pull request #377 from MihaZupan/allocation-reductions
10% time and 50% memory improvement
2019-10-15 23:06:31 +02:00
MihaZupan
3606f234b8 Update changelog 2019-10-15 15:09:34 +02:00
MihaZupan
616eed62bd Use try/finally instead of goto release in AutoLinkParser 2019-10-15 15:07:45 +02:00
MihaZupan
99f55e9ddc Resolve merge conflict 2019-10-15 14:58:03 +02:00
Alexandre Mutel
f8ab1cccc5 Merge pull request #375 from MihaZupan/balanced-link-brackets
Balanced link brackets
2019-10-15 13:46:31 +02:00
MihaZupan
f24067cd16 Update AppVeyor build image 2019-10-14 19:11:28 +02:00
MihaZupan
9af96ba2b4 Minor CharHelper optimizations 2019-10-14 19:03:15 +02:00
MihaZupan
c99f7dd96a Mark some struct methods as readonly 2019-10-14 18:39:40 +02:00
MihaZupan
bf28cbd33f Optimize ContainerBlock this[] accessor 2019-10-14 18:32:24 +02:00
MihaZupan
2040e23545 Correctly return IsEmpty for ICharIterator.TrimStart 2019-10-14 18:31:51 +02:00
MihaZupan
2761e36b6b Optimize StringSlice primitives 2019-10-14 18:28:32 +02:00
MihaZupan
891334134c Mark Readonly structs as Readonly 2019-10-14 13:38:21 +02:00
MihaZupan
0987fab6f2 Seal internal types 2019-10-14 13:33:24 +02:00
MihaZupan
ed5eea5e27 Cache List<char> in AutoLinkParser 2019-10-14 13:26:09 +02:00
MihaZupan
f73cbe4e76 Resize LineOffsets to sufficient Capacity before adding items 2019-10-14 13:11:07 +02:00
MihaZupan
aefad219cf Cache StringLine[]s in StringLineGroup with a custom ArrayPool 2019-10-14 13:04:27 +02:00
MihaZupan
76c3e88c58 Estimate LineCount from text Length to minimize List resizes 2019-10-14 12:58:03 +02:00
MihaZupan
afe4308e91 Cache HtmlRenderer on Pipeline for ToHtml(string, Pipeline) 2019-10-13 18:03:13 +02:00
MihaZupan
606556b692 Use Write(Span) on NetCore 2019-10-13 15:44:36 +02:00
MihaZupan
253be5c362 Cache HtmlRenderers in AutoIdentifier Extension 2019-10-13 15:17:33 +02:00
MihaZupan
33037d1034 Update changelog 2019-10-08 17:29:49 +02:00
MihaZupan
f16ee828db Fix link text balanced bracket matching 2019-10-08 17:27:50 +02:00
MihaZupan
a76305f39b Add tests for balanced brackets in link text
For issue #371
2019-10-08 17:26:16 +02:00
MihaZupan
f52a41e167 Cleanup LinkInline parsing code
No functional changes, readability only
Switch with a single case => if statement
Pattern matching, inline out variable declarations ...
2019-10-08 16:22:53 +02:00
Opportunity
4d172bf905 Merge branch 'master' into master 2019-10-01 21:31:02 +08:00
Opportunity
890b2cda2a Update MediaLinkExtension.cs 2019-09-30 21:09:44 +08:00
Alexandre Mutel
c818670919 Merge pull request #360 from MihaZupan/smarty-pants
Fix SmartyPants quote matching
2019-09-25 22:15:36 +02:00
Alexandre Mutel
a78a0b7016 Merge pull request #361 from MihaZupan/generic-attributes
Fix GenericAttributes matching of single-char values
2019-09-25 22:15:22 +02:00
Miha Zupan
6a0c9aeb47 Fix GenericAttributes matching of single-char values 2019-08-01 16:14:51 +02:00
Miha Zupan
b1cfcf2431 Add GenericAttributes test for #182 2019-08-01 16:13:37 +02:00
Miha Zupan
b411522a23 Increase EnsureSpecsAreUpToDate time leeway to 3min 2019-08-01 16:12:44 +02:00
Miha Zupan
1d2977d47b Fix SmartyPants quote matching 2019-08-01 15:28:20 +02:00
Miha Zupan
ee8c87c357 Add SmartyPants tests for #183 2019-08-01 15:26:04 +02:00
Alexandre Mutel
25959174d5 Merge pull request #357 from MihaZupan/master
Ignore backticks in GFM AutoLinks
2019-07-17 09:25:33 +02:00
Miha Zupan
033ddaf6a8 Ignore backticks in GFM AutoLinks 2019-07-16 10:21:52 +02:00
Alexandre Mutel
f3f7584c39 Bump to 0.17.1 2019-07-04 22:21:31 +02:00
Alexandre Mutel
d00ca4acc1 Add coverage badge to readme.readme.md 2019-07-03 09:00:45 +02:00
Alexandre Mutel
d9663ef2e6 Try to upload to coveralls.io 2019-07-03 08:39:34 +02:00
Alexandre Mutel
3106a49d02 Merge pull request #352 from MihaZupan/master
Add code coverage
2019-07-03 08:30:49 +02:00
Miha Zupan
a47a6890e7 Remove coverage report from source control 2019-07-02 15:53:32 +02:00
Miha Zupan
7d21f8b003 Add test code coverage 2019-06-29 21:04:55 +02:00
Miha Zupan
15f6205adc Ensure line ending diffs don't trigger spec regeneration 2019-06-29 19:28:45 +02:00
Miha Zupan
e6dd2cf3d4 Cleanup build configuration 2019-06-27 12:36:19 +02:00
Alexandre Mutel
ea6592b773 Merge pull request #346 from kelvindules/update-emoji-dictionary
Update Emoji Dictionary
2019-06-07 14:43:30 +02:00
Kelvin Dules
5cd20efe3e Removed duplicates 2019-06-06 20:19:41 -03:00
Kelvin Dules
31c7ba5862 Update Emoji Dictionary 2019-06-06 19:29:32 -03:00
Alexandre Mutel
0272840a62 Add Markdig.Signed project. Move Markdig.Benchmarks to new csproj 2019-05-25 22:46:27 +02:00
OpportunityLiu
8886b48634 add tests 2019-05-16 15:58:02 +08:00
OpportunityLiu
64cd8ec262 customize iframe class of each provider 2019-05-15 10:48:12 +08:00
OpportunityLiu
a1e19912a9 update changelog 2019-05-14 17:32:09 +08:00
OpportunityLiu
ca51967fb1 fix #135 2019-05-14 17:31:03 +08:00
OpportunityLiu
bb3a4f372c add change log 2019-05-14 16:07:14 +08:00
OpportunityLiu
1d6a464c5d add unit test 2019-05-14 15:59:05 +08:00
OpportunityLiu
0fe5c17a93 Add customizable media link 2019-05-14 15:30:15 +08:00
Alexandre Mutel
f879d55b4a Merge pull request #340 from MihaZupan/master
Fix regression from #315
2019-05-13 10:46:59 +02:00
Miha Zupan
6d3a3584ac Fix regression from #315 2019-05-12 11:28:04 +02:00
Alexandre Mutel
ea13b33f1a Allow to tag with version without v prefix 2019-05-11 17:22:14 +02:00
Alexandre Mutel
9b2ec2e2e5 Bump to 0.17.0 2019-05-10 18:25:10 +02:00
Alexandre Mutel
d8dffc28b4 Merge pull request #336 from FranklinWhale/youtube-enhancements
Enhancements for YouTube Links
2019-05-10 18:20:38 +02:00
Alexandre Mutel
0735042599 Merge pull request #334 from OpportunityLiu/master
fix code inline normalize
2019-05-10 18:18:03 +02:00
Franklin Tse
d1f99cdb69 Add test cases and URL escaping 2019-04-30 03:00:35 +08:00
Franklin Tse
d0a2ae2b50 Code formatting change 2019-04-30 01:46:54 +08:00
OpportunityLiu
dd4d1b349f lf as line ending 2019-04-29 16:57:33 +08:00
OpportunityLiu
e33281b8ae optimize 2019-04-29 16:39:55 +08:00
Franklin Tse
50d42560da Use null-conditional operator 2019-04-29 15:11:32 +08:00
Franklin Tse
a1e96d717b Correct lambda 2019-04-29 15:08:48 +08:00
Franklin Tse
56278657fd Fixes #335 2019-04-29 14:58:06 +08:00
OpportunityLiu
b7202084d2 fix code inline normalize 2019-04-29 10:49:37 +08:00
Alexandre Mutel
88052168d0 Merge pull request #304 from nschonni/patch-1
typo: dib -> div
2019-04-23 11:52:41 +02:00
Alexandre Mutel
27cb88773a Merge pull request #331 from nschonni/typos
typo roundup
2019-04-23 11:52:00 +02:00
Nick Schonning
fe3d5b0ccf typo: occuring -> occurring 2019-04-15 02:05:17 -04:00
Nick Schonning
86759e44e1 typo: jsut -> just 2019-04-15 02:02:30 -04:00
Nick Schonning
dd60990d3d typo: Sibliing -> Sibling 2019-04-15 02:01:46 -04:00
Nick Schonning
a3a9496c6f typo: inlnie -> inline 2019-04-15 02:01:16 -04:00
Nick Schonning
d09013ba14 typo: childrens -> children 2019-04-15 02:00:47 -04:00
Nick Schonning
9499660f83 typo: columWidth -> columnWidth 2019-04-15 02:00:25 -04:00
Nick Schonning
df24ab9846 typo: succesfull -> successful 2019-04-15 01:59:18 -04:00
Nick Schonning
40a8cd09b6 typo: proessed -> processed 2019-04-15 01:58:43 -04:00
Nick Schonning
b556f06d31 typo: balanaced -> balanced 2019-04-15 01:58:25 -04:00
Nick Schonning
54e61d3b91 typo: succsesfull -> successful 2019-04-15 01:57:18 -04:00
Nick Schonning
221afcc4d3 typo: curent -> current 2019-04-15 01:56:43 -04:00
Nick Schonning
f1fc64af42 typo: arround -> around 2019-04-15 01:55:52 -04:00
Nick Schonning
b39614f10c typo: ommitted -> omitted 2019-04-15 01:54:44 -04:00
Nick Schonning
5bda352f7a typo: backstick -> backtick 2019-04-15 01:54:08 -04:00
Nick Schonning
4f08094de0 typo: accross -> across 2019-04-15 01:51:25 -04:00
Nick Schonning
13a733a061 typo: Abreviation -> Abbreviation 2019-04-15 01:51:09 -04:00
Nick Schonning
d010a4f21e typo: occured -> occurred 2019-04-15 01:45:25 -04:00
Nick Schonning
a353c59e26 typo: Repressents -> Represents 2019-04-15 01:42:55 -04:00
Nick Schonning
01c8aedced typo: dicard -> discard 2019-04-15 01:40:58 -04:00
Nick Schonning
01d8842ac1 typo: sucessfull -> successful 2019-04-15 01:40:35 -04:00
Nick Schonning
69a2261562 typo: perfoming -> performing 2019-04-15 01:40:03 -04:00
Nick Schonning
09905db72a typo: Sligthly -> Slightly 2019-04-15 01:39:34 -04:00
Nick Schonning
754409c8fa typo: minumun -> minimum 2019-04-15 01:39:10 -04:00
Nick Schonning
cd67a3049a typo: porcess -> process 2019-04-15 01:38:35 -04:00
Nick Schonning
277aef341a typo: occurence -> occurrence 2019-04-15 01:38:03 -04:00
Nick Schonning
9a5ef61bd1 typo: implemts -> implements 2019-04-15 01:37:37 -04:00
Nick Schonning
ed6c59dd07 typo: blcok -> block 2019-04-15 01:37:08 -04:00
Nick Schonning
4deeac538a typo: openning -> opening 2019-04-15 01:36:31 -04:00
Nick Schonning
b05161d20e typo: continous -> continuous 2019-04-15 01:36:11 -04:00
Nick Schonning
d02adf1bf3 typo: elemeent -> element 2019-04-15 01:35:39 -04:00
Nick Schonning
f767b649e6 typo: mulitple -> multiple 2019-04-15 01:33:54 -04:00
Nick Schonning
bdec15d943 typo: capitalised -> capitalized
US spelling since that is normal in .Net
2019-04-15 01:30:36 -04:00
Nick Schonning
fe4ac6643a typo: preceeded -> preceded 2019-04-15 01:29:12 -04:00
Nick Schonning
eb72bc6d4f typo: onre -> one 2019-04-15 01:28:03 -04:00
Nick Schonning
f484366612 typo: hypen -> hyphen 2019-04-15 01:27:32 -04:00
Nick Schonning
bb5e45b939 typo: Nuitrion -> Nutrition 2019-04-15 01:25:52 -04:00
Nick Schonning
2b41e47170 typo: outputing -> outputting 2019-04-15 01:23:59 -04:00
Nick Schonning
3c16852219 typo: ponctuation -> punctuation 2019-04-15 01:21:33 -04:00
Nick Schonning
744417c7a2 typo: dib -> div 2019-04-15 01:07:01 -04:00
Alexandre Mutel
4039e11e08 Merge pull request #327 from MihaZupan/pr327
CommonMark 0.29, DisableHeadings extension, AutoLinkOptions
2019-04-12 17:59:01 +02:00
Miha Zupan
3c73a2d05a Apply CommonMark spec patch 2019-04-12 17:28:35 +02:00
Miha Zupan
1ef247b093 Update readme and changelog 2019-04-11 16:56:11 +02:00
Miha Zupan
d45d8873f5 [CM 0.29] Use new ListItem indendation rules 2019-04-11 16:53:18 +02:00
Miha Zupan
396a03567c Update code comments for Link- and CharHelper 2019-04-11 14:54:40 +02:00
Miha Zupan
6a98e204a5 [CM 0.29] Remove 'meta' from recognised html tags 2019-04-11 11:01:48 +02:00
Miha Zupan
210a6612c7 [CM 0.29] Apply new entity length limits 2019-04-11 11:01:37 +02:00
Miha Zupan
27c35b3b09 [CM 0.29] Correctly handle empty setex headings under a LinkReferenceDefinition 2019-04-10 23:19:40 +02:00
Miha Zupan
ac1db841d5 [CM 0.29] Permit empty urls and spaces for angle-bracket links 2019-04-10 23:18:06 +02:00
Miha Zupan
09f29615c1 [CM 0.29] Use new rule for EmphasisDelimiter matching 2019-04-10 23:07:21 +02:00
Miha Zupan
05e5a3f2bb [CM 0.29] Use new infostring rules for tilde FencedBlocks 2019-04-10 23:06:09 +02:00
Miha Zupan
6d238de69e [CM 0.29] Use new space-trimming rules for CodeInline 2019-04-10 23:02:50 +02:00
Miha Zupan
5b88dbb90a Use StringBuilderCache in JiraLink parser 2019-04-10 23:00:14 +02:00
Miha Zupan
fbd822cef7 Update CommonMark spec to 0.29 2019-04-10 22:59:23 +02:00
Miha Zupan
0e22a120f1 Use a '.generated' suffix for generated test code files 2019-04-05 18:18:26 +02:00
Alexandre Mutel
590f3d0b1b Merge pull request #326 from manuel-guilbault/master
Set ContainerBlock.Count to zero upon Clear() calls.
2019-04-05 09:01:47 -07:00
Miha Zupan
23766d84fa Rename UseHttpsForWWWLinks option 2019-04-05 16:59:51 +02:00
Miha Zupan
14e9e618a2 Update changelog 2019-04-05 16:48:11 +02:00
Miha Zupan
f523cb243b Add UseHttpsPrefixForWWWLinks option to AutoLinks 2019-04-05 16:45:09 +02:00
Miha Zupan
1064818b49 Add OpenInNewWindow option to AutoLinks 2019-04-05 16:37:15 +02:00
Miha Zupan
befd1ca846 Add 'DisableHeadings' extension 2019-04-05 16:07:15 +02:00
Miha Zupan
65c671d014 Bump target UWP version 2019-04-03 22:27:01 +02:00
Manuel Guilbault
25bc0b8bf6 Set Count to zero upon Clear() calls. 2019-04-01 15:27:17 +02:00
Miha Zupan
343a2a17e1 Add sample Normalize/PlainText spec files 2019-03-17 13:00:11 +01:00
Miha Zupan
5100ed0b68 Update changelog 2019-03-17 11:58:48 +01:00
Miha Zupan
95dd2c148c Add Spec files for Normalize and PlainText renderers 2019-03-17 11:39:47 +01:00
Alexandre Mutel
354db6b306 Merge pull request #319 from MihaZupan/allow-unicode-domain-names
Allow unicode domain names
2019-03-11 18:30:01 +01:00
Miha Zupan
50313a36dc Update changelog 2019-03-11 18:19:04 +01:00
Miha Zupan
77d5dcb6dd Drop support for netstandard1.1 and legacy PCL 2019-03-11 16:35:14 +01:00
Miha Zupan
1c88fb65c8 Use IDNA encoding for domain names containing non-ascii chars 2019-03-11 15:36:03 +01:00
Miha Zupan
db9660d090 Allow non-ascii characters in domain names 2019-03-11 15:35:55 +01:00
Miha Zupan
39ab066e2d Exclude nuget.props from source control 2019-03-11 15:35:44 +01:00
Miha Zupan
47f395dad7 Add unicode domain name test for LinkReferenceDefinitions 2019-03-09 20:16:01 +01:00
Miha Zupan
04e195cdb2 Add tests for unicode in domain names 2019-03-09 19:59:23 +01:00
Miha Zupan
3b3872ffe3 Use a universal time format for spec timestamps 2019-03-09 19:59:00 +01:00
Alexandre Mutel
c7cda0df45 Merge pull request #318 from OpportunityLiu/master
fix #242: HtmlCustomContainerRenderer does not honour EnableHtmlForBlock == false
2019-03-08 10:12:49 +01:00
OpportunityLiu
7651e75bfa fix #242 2019-03-08 16:59:47 +08:00
Alexandre Mutel
ea99cd6115 Merge pull request #315 from OpportunityLiu/patch-1
Fix ToPlainText with htmlentity
2019-03-07 10:14:40 +01:00
Opportunity
3af4f33b5d Update TestPlainText.cs 2019-03-07 16:39:03 +08:00
Opportunity
41e8d5e5fc Update LiteralInlineRenderer.cs 2019-03-07 16:37:43 +08:00
Opportunity
5a73c2bf2b Update HtmlEntityInlineRenderer.cs 2019-03-07 16:37:11 +08:00
Opportunity
f542fd0a88 Update LiteralInlineRenderer.cs 2019-03-07 16:36:29 +08:00
Opportunity
5a6300823c Update HtmlEntityInlineRenderer.cs 2019-03-07 16:33:43 +08:00
196 changed files with 9886 additions and 7079 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [xoofx]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

61
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: ci
env:
PROJECT_NAME: Markdig
on:
push:
paths-ignore:
- 'doc/**'
- 'img/**'
- 'changelog.md'
- 'readme.md'
pull_request:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.0.100
- name: Build (Release)
run: dotnet build src -c Release
- name: SpecFileGen
run: dotnet src/SpecFileGen/bin/Release/netcoreapp2.1/SpecFileGen.dll
- name: Test (Release)
run: dotnet test src -c Release
- name: Build & Test (Debug)
run: dotnet test src -c Debug
- name: Coverlet
run: dotnet test src -c Release -f netcoreapp2.1 /p:Include=\"[${{env.PROJECT_NAME}}]*\" /p:CollectCoverage=true /p:CoverletOutputFormat=lcov
- name: Coveralls Upload
uses: coverallsapp/github-action@v1.0.1
if: github.event_name == 'push'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: src/${{env.PROJECT_NAME}}.Tests/coverage.netcoreapp2.1.info
- name: Pack
run: dotnet pack src -c Release
- name: Publish
if: github.event_name == 'push'
run: |
if ( "${{github.ref}}" -match "^refs/tags/[0-9]+\.[0-9]+\.[0-9]+$" ) {
dotnet nuget push src\${{env.PROJECT_NAME}}\bin\Release\*.nupkg -s nuget.org -k ${{secrets.NUGET_TOKEN}}
dotnet nuget push src\${{env.PROJECT_NAME}}.Signed\bin\Release\*.nupkg -s nuget.org -k ${{secrets.NUGET_TOKEN}}
} else {
echo "publish is only enabled by tagging with a release tag"
}

2
.gitignore vendored
View File

@@ -6,6 +6,8 @@
*.user
*.userosscache
*.sln.docstates
*.nuget.props
*.nuget.targets
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

View File

@@ -1,48 +0,0 @@
version: 10.0.{build}
image: Visual Studio 2017
configuration: Release
install:
- ps: >-
cd src
nuget restore Markdig.sln
$env:MARKDIG_BUILD_NUMBER = ([int]$env:APPVEYOR_BUILD_NUMBER).ToString("000")
$env:MARKDIG_VERSION_SUFFIX = ""
$env:appveyor_nuget_push = 'false'
if(-Not $env:APPVEYOR_PULL_REQUEST_NUMBER) {
if($env:appveyor_repo_tag -eq 'True') {
if($env:appveyor_repo_tag_name -match '^v[0-9]') {
$env:appveyor_nuget_push = 'true'
$env:MARKDIG_VERSION_SUFFIX = ""
}
if($env:appveyor_repo_tag_name -eq 'latest') {
$env:appveyor_nuget_push = 'true'
$env:MARKDIG_VERSION_SUFFIX = "pre$env:MARKDIG_BUILD_NUMBER"
}
}
}
build:
project: src/Markdig.sln
verbosity: minimal
after_build:
- dotnet run --project SpecFileGen/SpecFileGen.csproj -c Release
before_package:
- cmd: >-
msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release Markdig/Markdig.csproj
msbuild /t:Clean Markdig/Markdig.csproj
msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release;SignAssembly=true Markdig/Markdig.csproj
artifacts:
- path: src\Markdig\Bin\Release\*.nupkg
name: Markdig Nugets
deploy:
- provider: NuGet
api_key:
secure: 7cthHh+wYWZjhqxaxR6QObRaRnstvFkQOY7MkxIsC5kpQEBlKZXuinf0IybbYxJt
on:
appveyor_nuget_push: true

View File

@@ -1,5 +1,51 @@
# Changelog
## 0.20.0 (18 Apr 2020)
- Markdig is now compatible only with `NETStandard 2.0`, `NETStandard 2.1`, `NETCoreApp 2.1` and `NETCoreApp 3.1`.
- Many performance improvements from [PR #416](https://github.com/lunet-io/markdig/pull/416)
[PR #417](https://github.com/lunet-io/markdig/pull/417)
[PR #418](https://github.com/lunet-io/markdig/pull/418)
[PR #421](https://github.com/lunet-io/markdig/pull/421)
[PR #422](https://github.com/lunet-io/markdig/pull/422)
[PR #410](https://github.com/lunet-io/markdig/pull/410)
## 0.18.3 (8 Mar 2020)
- Publish NuGet Symbol packages
## 0.18.2 (8 Mar 2020)
- Optimize LineReader.ReadLine in [PR #393](https://github.com/lunet-io/markdig/pull/393)
- Use HashSet<T> instead of Dictionary<TKey, TValue> in CharacterMap<T> in [PR #394](https://github.com/lunet-io/markdig/pull/394)
- Use BitVector128 in CharacterMap<T> in [PR #396](https://github.com/lunet-io/markdig/pull/396)
- Optimizations in StringLineGroup in [PR #399](https://github.com/lunet-io/markdig/pull/399)
- Fixed a bug in HeadingRenderer in [PR #402](https://github.com/lunet-io/markdig/pull/402)
- Fixes issue #303 in [PR #404](https://github.com/lunet-io/markdig/pull/404)
- Make output of HtmlTableRenderer XML wellformed in [PR #406](https://github.com/lunet-io/markdig/pull/406)
## 0.18.1 (21 Jan 2020)
- Re-allow emojis and smileys customization, that was broken in [PR #308](https://github.com/lunet-io/markdig/pull/308) ([PR #386](https://github.com/lunet-io/markdig/pull/386))
- Add `IHostProvider` for medialink customization (#337), support protocol-less url (#135) ([(PR #341)](https://github.com/lunet-io/markdig/pull/341))
- Add missing Descendants<T> overload ([(PR #387)](https://github.com/lunet-io/markdig/pull/387))
## 0.18.0 (24 Oct 2019)
- Ignore backslashes in GFM AutoLinks ([(PR #357)](https://github.com/lunet-io/markdig/pull/357))
- Fix SmartyPants quote matching ([(PR #360)](https://github.com/lunet-io/markdig/pull/360))
- Fix generic attributes with values of length 1 ([(PR #361)](https://github.com/lunet-io/markdig/pull/361))
- Fix link text balanced bracket matching ([(PR #375)](https://github.com/lunet-io/markdig/pull/375))
- Improve overall performance and substantially reduce allocations ([(PR #377)](https://github.com/lunet-io/markdig/pull/377))
## 0.17.1 (04 July 2019)
- Fix regression when escaping HTML characters ([(PR #340)](https://github.com/lunet-io/markdig/pull/340))
- Update Emoji Dictionary ([(PR #346)](https://github.com/lunet-io/markdig/pull/346))
## 0.17.0 (10 May 2019)
- Update to latest CommonMark specs 0.29 ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
- Add `AutoLinkOptions` with `OpenInNewWindow`, `UseHttpsForWWWLinks` ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
- Add `DisableHeadings` extension method to `MarkdownPipelineBuilder` ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
- Drop support for netstandard1.1 and Portable Class Libraries ([(PR #319)](https://github.com/lunet-io/markdig/pull/319))
- Allow non-ASCII characters in url domain names ([(PR #319)](https://github.com/lunet-io/markdig/pull/319))
- Add better support for youtu.be link ([(PR #336)](https://github.com/lunet-io/markdig/pull/336))
- Fix backsticks in Markdown.Normalize ([(PR #334)](https://github.com/lunet-io/markdig/pull/334))
## 0.16.0 (25 Feb 2019)
- Improve performance of emoji-abbreviation parser ([(PR #305)](https://github.com/lunet-io/markdig/pull/305))
- Change output for math extension to use a rendering more compatible with existing Math JS libraries ([(PR #311)](https://github.com/lunet-io/markdig/pull/311))
@@ -25,7 +71,7 @@
- Ensuring line breaks when renderer does not have html enabled ([(PR #270)](https://github.com/lunet-io/markdig/pull/270))
## 0.15.4 (07 Oct 2018)
- Add autolink domain GFM validation ([(PR #239)](https://github.com/lunet-io/markdig/pull/253))
- Add autolink domain GFM validation ([(PR #253)](https://github.com/lunet-io/markdig/pull/253))
## 0.15.3 (15 Sep 2018)
- Add support for RTL ([(PR #239)](https://github.com/lunet-io/markdig/pull/239))
@@ -132,7 +178,7 @@
## 0.8.3
- fix NullReferenceException with Gridtables extension when a single `+` is entered on a line
## 0.8.2
- fix potential cast exception with Abreviation extension and empty literals
- fix potential cast exception with Abbreviation extension and empty literals
## 0.8.1
- new extension to disable URI escaping for non-US-ASCII characters to workaround a bug in Edge/IE
- Fix an issue with abbreviations with left/right multiple non-punctuation/space characters

View File

@@ -1,4 +1,4 @@
# Markdig [![Build status](https://ci.appveyor.com/api/projects/status/hk391x8jcskxt1u8?svg=true)](https://ci.appveyor.com/project/xoofx/markdig) [![NuGet](https://img.shields.io/nuget/v/Markdig.svg)](https://www.nuget.org/packages/Markdig/) [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRGHXBTP442JL)
# Markdig [![Build Status](https://github.com/lunet-io/markdig/workflows/ci/badge.svg?branch=master)](https://github.com/lunet-io/markdig/actions) [![Coverage Status](https://coveralls.io/repos/github/lunet-io/markdig/badge.svg?branch=master)](https://coveralls.io/github/lunet-io/markdig?branch=master) [![NuGet](https://img.shields.io/nuget/v/Markdig.svg)](https://www.nuget.org/packages/Markdig/) [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRGHXBTP442JL)
<img align="right" width="160px" height="160px" src="img/markdig.png">
@@ -14,14 +14,14 @@ You can **try Markdig online** and compare it to other implementations on [babel
- **Abstract Syntax Tree** with precise source code location for syntax tree, useful when building a Markdown editor.
- Checkout [MarkdownEditor for Visual Studio](https://visualstudiogallery.msdn.microsoft.com/eaab33c3-437b-4918-8354-872dfe5d1bfe) powered by Markdig!
- Converter to **HTML**
- Passing more than **600+ tests** from the latest [CommonMark specs (0.28)](http://spec.commonmark.org/)
- Passing more than **600+ tests** from the latest [CommonMark specs (0.29)](http://spec.commonmark.org/)
- Includes all the core elements of CommonMark:
- including **GFM fenced code blocks**.
- **Extensible** architecture
- Even the core Markdown/CommonMark parsing is pluggable, so it allows to disable builtin Markdown/Commonmark parsing (e.g [Disable HTML parsing](https://github.com/lunet-io/markdig/blob/7964bd0160d4c18e4155127a4c863d61ebd8944a/src/Markdig/MarkdownExtensions.cs#L306)) or change behaviour (e.g change matching `#` of a headers with `@`)
- Built-in with **20+ extensions**, including:
- 2 kind of tables:
- [**Pipe tables**](src/Markdig.Tests/Specs/PipeTableSpecs.md) (inspired from Github tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
- [**Pipe tables**](src/Markdig.Tests/Specs/PipeTableSpecs.md) (inspired from GitHub tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
- [**Grid tables**](src/Markdig.Tests/Specs/GridTableSpecs.md) (inspired from [Pandoc - Grid Tables](http://pandoc.org/README.html#extension-grid_tables))
- [**Extra emphasis**](src/Markdig.Tests/Specs/EmphasisExtraSpecs.md) (inspired from [Pandoc - Emphasis](http://pandoc.org/README.html#strikeout) and [Markdown-it](https://markdown-it.github.io/))
- strike through `~~`,
@@ -48,9 +48,11 @@ You can **try Markdig online** and compare it to other implementations on [babel
- [**SmartyPants**](src/Markdig.Tests/Specs/SmartyPantsSpecs.md) (inspired from [Daring Fireball - SmartyPants](https://daringfireball.net/projects/smartypants/))
- [**Bootstrap**](src/Markdig.Tests/Specs/BootstrapSpecs.md) class (to output bootstrap class)
- [**Diagrams**](src/Markdig.Tests/Specs/DiagramsSpecs.md) extension whenever a fenced code block contains a special keyword, it will be converted to a div block with the content as-is (currently, supports [`mermaid`](https://knsv.github.io/mermaid/) and [`nomnoml`](https://github.com/skanaar/nomnoml) diagrams)
- [**YAML frontmatter**](src/Markdig.Tests/Specs/YamlSpecs.md) to parse without evaluating the frontmatter and to discard it from the HTML output (typically used for previewing without the frontmatter in MarkdownEditor)
- [**YAML Front Matter**](src/Markdig.Tests/Specs/YamlSpecs.md) to parse without evaluating the front matter and to discard it from the HTML output (typically used for previewing without the front matter in MarkdownEditor)
- [**JIRA links**](src/Markdig.Tests/Specs/JiraLinks.md) to automatically generate links for JIRA project references (Thanks to @clarkd: https://github.com/clarkd/MarkdigJiraLinker)
- Compatible with .NET 3.5, 4.0+ and .NET Core (`netstandard1.1+`)
- Starting with Markdig version `0.20.0+`, Markdig is compatible only with `NETStandard 2.0`, `NETStandard 2.1`, `NETCoreApp 2.1` and `NETCoreApp 3.1`.
If you are looking for support for an old .NET Framework 3.5 or 4.0, you can download Markdig `0.18.3`.
### Third Party Extensions
@@ -84,7 +86,7 @@ var result = Markdown.ToHtml("This is a text with some *emphasis*");
Console.WriteLine(result); // prints: <p>This is a text with some <em>emphasis</em></p>
```
In order to activate most of all advanced extensions (except Emoji, SoftLine as HardLine, JiraLinks and SmartyPants)
In order to activate most of all advanced extensions (except Emoji, SoftLine as HardLine, Bootstrap, YAML Front Matter, JiraLinks and SmartyPants)
```csharp
// Configure the pipeline with all advanced extensions active

View File

@@ -1,43 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6A19F040-BC7C-4283-873A-177B5324F1ED}</ProjectGuid>
<TargetFrameworks>net471</TargetFrameworks>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Markdig.Benchmarks</RootNamespace>
<AssemblyName>Markdig.Benchmarks</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<CopyNuGetImplementations>true</CopyNuGetImplementations>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>true</Prefer32Bit>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<None Remove="spec.md" />
</ItemGroup>
<ItemGroup>
<Reference Include="CommonMarkNew, Version=0.1.0.0, Culture=neutral, PublicKeyToken=001ef8810438905d, processorArchitecture=MSIL">
<HintPath>lib\CommonMarkNew.dll</HintPath>
@@ -45,31 +15,12 @@
<Aliases>newcmark</Aliases>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Build" />
<Reference Include="Microsoft.Build.Framework" />
<Reference Include="Microsoft.Build.Utilities.v4.0" />
<Reference Include="MoonShine">
<HintPath>lib\MoonShine.dll</HintPath>
</Reference>
<Reference Include="MarkdownDeep">
<HintPath>lib\MarkdownDeep.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommonMarkLib.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestMatchPerf.cs" />
<Compile Include="TestStringPerf.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="cmark.dll">
@@ -83,21 +34,16 @@
<Content Include="spec.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="app.config" />
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Reference Include="Markdig">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Markdig\Bin\$(Configuration)\net40\Markdig.dll</HintPath>
</Reference>
<PackageReference Include="BenchmarkDotNet" Version="0.10.6" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.10.6" />
<PackageReference Include="CommonMark.NET" Version="0.15.1" />
<PackageReference Include="MarkdownSharp" Version="1.13.0.0" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="0.8.31-beta" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="1.0.41.0" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Testamina.Markdig.Benchmarks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Testamina.Markdig.Benchmarks")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6a19f040-bc7c-4283-873a-177b5324f1ed")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,8 +0,0 @@
{
"profiles": {
"CLASSIC": {
"executablePath": "Testamina.Markdig.Benchmarks.dll",
"workingDirectory": "..\\..\\artifacts\\bin\\Testamina.Markdig.Benchmarks\\Debug\\net45"
}
}
}

View File

@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>

View File

@@ -1,29 +0,0 @@
{
"runtimes": {
"win-x86": {},
"win-x64": {}
},
"frameworks": {
"net46": {
"compilationOptions": {
"define": [
"CLASSIC"
]
},
"frameworkAssemblies": {
"Microsoft.Build": "4.0.0.0",
"Microsoft.Build.Framework": "4.0.0.0",
"Microsoft.Build.Utilities.v4.0": "4.0.0.0",
"System.Management": "4.0.0.0"
}
}
},
"dependencies": {
"BenchmarkDotNet": "0.10.6",
"BenchmarkDotNet.Diagnostics.Windows": "0.10.6",
"CommonMark.NET": "0.15.1",
"MarkdownSharp": "1.13.0.0",
"Microsoft.Diagnostics.Runtime": "0.8.31-beta",
"Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.41.0"
}
}

View File

@@ -5397,7 +5397,7 @@ foo
## Entity and numeric character references
All valid HTML entity references and numeric character
references, except those occuring in code blocks and code spans,
references, except those occurring in code blocks and code spans,
are recognized as such and treated as equivalent to the
corresponding Unicode characters. Conforming CommonMark parsers
need not store information about whether a particular character

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>Markdig.Signed</PackageId>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Markdig\**\*.cs" Exclude="..\Markdig\obj\**;..\Markdig\bin\**">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
<Import Project="..\Markdig\Markdig.targets" />
</Project>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
</configuration>

View File

@@ -1,154 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A0C5CB5F-5568-40AB-B945-D6D2664D51B0}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Markdig.Tests</RootNamespace>
<AssemblyName>Markdig.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<OutputType>Library</OutputType>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Specs\AbbreviationSpecs.cs" />
<Compile Include="Specs\AutoIdentifierSpecs.cs" />
<Compile Include="Specs\AutoLinks.cs" />
<Compile Include="Specs\BootstrapSpecs.cs" />
<Compile Include="Specs\CommonMark.cs" />
<Compile Include="Specs\CustomContainerSpecs.cs" />
<Compile Include="Specs\DefinitionListSpecs.cs" />
<Compile Include="Specs\DiagramsSpecs.cs" />
<Compile Include="Specs\EmojiSpecs.cs" />
<Compile Include="Specs\EmphasisExtraSpecs.cs" />
<Compile Include="Specs\FigureFooterAndCiteSpecs.cs" />
<Compile Include="Specs\FootnotesSpecs.cs" />
<Compile Include="Specs\GenericAttributesSpecs.cs" />
<Compile Include="Specs\GlobalizationSpecs.cs" />
<Compile Include="Specs\GridTableSpecs.cs" />
<Compile Include="Specs\HardlineBreakSpecs.cs" />
<Compile Include="Specs\JiraLinks.cs" />
<Compile Include="Specs\ListExtraSpecs.cs" />
<Compile Include="Specs\MathSpecs.cs" />
<Compile Include="Specs\MediaSpecs.cs" />
<Compile Include="Specs\NoHtmlSpecs.cs" />
<Compile Include="Specs\PipeTableSpecs.cs" />
<Compile Include="Specs\SmartyPantsSpecs.cs" />
<Compile Include="Specs\TaskListSpecs.cs" />
<Compile Include="Specs\YamlSpecs.cs" />
<Compile Include="TestEmphasisExtended.cs" />
<Compile Include="TestEmphasisPlus.cs" />
<Compile Include="TestEmphasisExtraOptions.cs" />
<Compile Include="TestDescendantsOrder.cs" />
<Compile Include="TestConfigureNewLine.cs" />
<Compile Include="TestHtmlAttributes.cs" />
<Compile Include="TestHtmlHelper.cs" />
<Compile Include="TestLineReader.cs" />
<Compile Include="TestLinkHelper.cs" />
<Compile Include="TestNormalize.cs" />
<Compile Include="TestOrderedList.cs" />
<Compile Include="TestPlainText.cs" />
<Compile Include="TestPragmaLines.cs" />
<Compile Include="TestLinkRewriter.cs" />
<Compile Include="TestRelativeUrlReplacement.cs" />
<Compile Include="TestSourcePosition.cs" />
<Compile Include="TestStringSliceList.cs" />
<Compile Include="TestPlayParser.cs" />
<Compile Include="TextAssert.cs" />
<Compile Include="TestParser.cs" />
<ProjectReference Include="..\Markdig\Markdig.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<Content Include="ArgumentOutOfRangeException.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="hang.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="project.json" />
<None Include="Specs\CommonMark.md" />
<None Include="Specs\GlobalizationSpecs.md" />
<None Include="Specs\JiraLinks.md" />
<None Include="Specs\AutoLinks.md" />
<None Include="Specs\AutoIdentifierSpecs.md" />
<None Include="Specs\AbbreviationSpecs.md" />
<None Include="Specs\FigureFooterAndCiteSpecs.md" />
<None Include="Specs\ListExtraSpecs.md" />
<None Include="Specs\GenericAttributesSpecs.md" />
<None Include="Specs\CustomContainerSpecs.md" />
<None Include="Specs\DefinitionListSpecs.md" />
<None Include="Specs\EmojiSpecs.md" />
<None Include="Specs\FootnotesSpecs.md" />
<None Include="Specs\GridTableSpecs.md" />
<None Include="Specs\HardlineBreakSpecs.md" />
<None Include="Specs\BootstrapSpecs.md" />
<None Include="Specs\DiagramsSpecs.md" />
<None Include="Specs\NoHtmlSpecs.md" />
<None Include="Specs\readme.md" />
<None Include="Specs\YamlSpecs.md" />
<None Include="Specs\TaskListSpecs.md" />
<None Include="Specs\SmartyPantsSpecs.md" />
<None Include="Specs\MediaSpecs.md" />
<None Include="Specs\MathSpecs.md" />
<None Include="Specs\PipeTableSpecs.md" />
<None Include="Specs\EmphasisExtraSpecs.md" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj">
<Project>{8a58a7e2-627c-4f41-933f-5ac92adfab48}</Project>
<Name>Markdig</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,241 @@
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Markdig.Extensions.AutoLinks;
using NUnit.Framework;
namespace Markdig.Tests
{
public class MiscTests
{
[TestCase("link [foo [bar]]")] // https://spec.commonmark.org/0.29/#example-508
[TestCase("link [foo][bar]")]
[TestCase("link [][foo][bar][]")]
[TestCase("link [][foo][bar][[]]")]
[TestCase("link [foo] [bar]")]
[TestCase("link [[foo] [] [bar] [[abc]def]]")]
[TestCase("[]")]
[TestCase("[ ]")]
[TestCase("[bar][]")]
[TestCase("[bar][ foo]")]
[TestCase("[bar][foo ][]")]
[TestCase("[bar][fo[ ]o ][][]")]
[TestCase("[a]b[c[d[e]f]g]h")]
[TestCase("a[b[c[d]e]f[g]h]i foo [j]k[l[m]n]o")]
[TestCase("a[b[c[d]e]f[g]h]i[] [][foo][bar][] foo [j]k[l[m]n]o")]
[TestCase("a[b[c[d]e]f[g]h]i foo [j]k[l[m]n]o[][]")]
public void LinkTextMayContainBalancedBrackets(string linkText)
{
string markdown = $"[{linkText}](/uri)";
string expected = $@"<p><a href=""/uri"">{linkText}</a></p>";
TestParser.TestSpec(markdown, expected);
// Make the link text unbalanced
foreach (var bracketIndex in linkText
.Select((c, i) => new Tuple<char, int>(c, i))
.Where(t => t.Item1 == '[' || t.Item1 == ']')
.Select(t => t.Item2))
{
string brokenLinkText = linkText.Remove(bracketIndex, 1);
markdown = $"[{brokenLinkText}](/uri)";
expected = $@"<p><a href=""/uri"">{brokenLinkText}</a></p>";
string actual = Markdown.ToHtml(markdown);
Assert.AreNotEqual(expected, actual);
}
}
[Test]
public void IsIssue356Corrected()
{
string input = @"https://foo.bar/path/\#m4mv5W0GYKZpGvfA.97";
string expected = @"<p><a href=""https://foo.bar/path/%5C#m4mv5W0GYKZpGvfA.97"">https://foo.bar/path/\#m4mv5W0GYKZpGvfA.97</a></p>";
TestParser.TestSpec($"<{input}>", expected);
TestParser.TestSpec(input, expected, "autolinks|advanced");
}
[Test]
public void TestAltTextIsCorrectlyEscaped()
{
TestParser.TestSpec(
@"![This is image alt text with quotation ' and double quotation ""hello"" world](girl.png)",
@"<p><img src=""girl.png"" alt=""This is image alt text with quotation ' and double quotation &quot;hello&quot; world"" /></p>");
}
[Test]
public void TestChangelogPRLinksMatchDescription()
{
string solutionFolder = Path.GetFullPath(Path.Combine(TestParser.TestsDirectory, "../.."));
string changelogPath = Path.Combine(solutionFolder, "changelog.md");
string changelog = File.ReadAllText(changelogPath);
var matches = Regex.Matches(changelog, @"\(\[\(PR #(\d+)\)\]\(.*?pull\/(\d+)\)\)");
Assert.Greater(matches.Count, 0);
foreach (Match match in matches)
{
Assert.True(int.TryParse(match.Groups[1].Value, out int textNr));
Assert.True(int.TryParse(match.Groups[2].Value, out int linkNr));
Assert.AreEqual(textNr, linkNr);
}
}
[Test]
public void TestFixHang()
{
var input = File.ReadAllText(Path.Combine(TestParser.TestsDirectory, "hang.md"));
_ = Markdown.ToHtml(input);
}
[Test]
public void TestInvalidHtmlEntity()
{
var input = "9&ddr;&*&ddr;&de<64><65>__";
TestParser.TestSpec(input, "<p>9&amp;ddr;&amp;*&amp;ddr;&amp;de<64><65>__</p>");
}
[Test]
public void TestInvalidCharacterHandling()
{
var input = File.ReadAllText(Path.Combine(TestParser.TestsDirectory, "ArgumentOutOfRangeException.md"));
_ = Markdown.ToHtml(input);
}
[Test]
public void TestInvalidCodeEscape()
{
var input = "```**Header** ";
_ = Markdown.ToHtml(input);
}
[Test]
public void TestEmphasisAndHtmlEntity()
{
var markdownText = "*Unlimited-Fun&#174;*&#174;";
TestParser.TestSpec(markdownText, "<p><em>Unlimited-Fun®</em>®</p>");
}
[Test]
public void TestThematicInsideCodeBlockInsideList()
{
var input = @"1. In the :
```
Id DisplayName Description
-- ----------- -----------
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
```";
TestParser.TestSpec(input, @"<ol>
<li><p>In the :</p>
<pre><code>Id DisplayName Description
-- ----------- -----------
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
</code></pre></li>
</ol>");
}
[Test]
public void VisualizeMathExpressions()
{
string math = @"Math expressions
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
$$\frac{n!}{k!(n-k)!} = \binom{n}{k}$$
$$
\frac{n!}{k!(n-k)!} = \binom{n}{k}
$$
<div class=""math"">
\begin{align}
\sqrt{37} & = \sqrt{\frac{73^2-1}{12^2}} \\
& = \sqrt{\frac{73^2}{12^2}\cdot\frac{73^2-1}{73^2}} \\
& = \sqrt{\frac{73^2}{12^2}}\sqrt{\frac{73^2-1}{73^2}} \\
& = \frac{73}{12}\sqrt{1 - \frac{1}{73^2}} \\
& \approx \frac{73}{12}\left(1 - \frac{1}{2\cdot73^2}\right)
\end{align}
</div>
";
Console.WriteLine("Math Expressions:\n");
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
}
[Test]
public void InlineMathExpression()
{
string math = @"Math expressions
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
";
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
Assert.IsTrue(html.Contains("<p><span class=\"math\">\\("), "Leading bracket missing");
Assert.IsTrue(html.Contains("\\)</span></p>"), "Trailing bracket missing");
}
[Test]
public void BlockMathExpression()
{
string math = @"Math expressions
$$
\frac{n!}{k!(n-k)!} = \binom{n}{k}
$$
";
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
Assert.IsTrue(html.Contains("<div class=\"math\">\n\\["), "Leading bracket missing");
Assert.IsTrue(html.Contains("\\]</div>"), "Trailing bracket missing");
}
[Test]
public void CanDisableParsingHeadings()
{
var noHeadingsPipeline = new MarkdownPipelineBuilder().DisableHeadings().Build();
TestParser.TestSpec("Foo\n===", "<h1>Foo</h1>");
TestParser.TestSpec("Foo\n===", "<p>Foo\n===</p>", noHeadingsPipeline);
TestParser.TestSpec("# Heading 1", "<h1>Heading 1</h1>");
TestParser.TestSpec("# Heading 1", "<p># Heading 1</p>", noHeadingsPipeline);
// Does not also disable link reference definitions
TestParser.TestSpec("[Foo]\n\n[Foo]: bar", "<p><a href=\"bar\">Foo</a></p>");
TestParser.TestSpec("[Foo]\n\n[Foo]: bar", "<p><a href=\"bar\">Foo</a></p>", noHeadingsPipeline);
}
[Test]
public void CanOpenAutoLinksInNewWindow()
{
var pipeline = new MarkdownPipelineBuilder().UseAutoLinks().Build();
var newWindowPipeline = new MarkdownPipelineBuilder().UseAutoLinks(new AutoLinkOptions() { OpenInNewWindow = true }).Build();
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\">www.foo.bar</a></p>", pipeline);
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\" target=\"blank\">www.foo.bar</a></p>", newWindowPipeline);
}
[Test]
public void CanUseHttpsPrefixForWWWAutoLinks()
{
var pipeline = new MarkdownPipelineBuilder().UseAutoLinks().Build();
var httpsPipeline = new MarkdownPipelineBuilder().UseAutoLinks(new AutoLinkOptions() { UseHttpsForWWWLinks = true }).Build();
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\">www.foo.bar</a></p>", pipeline);
TestParser.TestSpec("www.foo.bar", "<p><a href=\"https://www.foo.bar\">www.foo.bar</a></p>", httpsPipeline);
}
}
}

View File

@@ -0,0 +1,93 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Headings
// --------------------------------
using System;
using NUnit.Framework;
namespace Markdig.Tests.Specs.Normalize.Headings
{
[TestFixture]
public class TestHeadings
{
// # Headings
[Test]
public void Headings_Example001()
{
// Example 1
// Section: Headings
//
// The following Markdown:
// # Heading 1
//
// ## Heading 2
//
// ### Heading 3
//
// #### Heading 4
//
// ##### Heading 5
//
// ###### Heading 6
//
// Should be rendered as:
// # Heading 1
//
// ## Heading 2
//
// ### Heading 3
//
// #### Heading 4
//
// ##### Heading 5
//
// ###### Heading 6
Console.WriteLine("Example 1\nSection Headings\n");
TestNormalize.TestSpec("# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "");
}
[Test]
public void Headings_Example002()
{
// Example 2
// Section: Headings
//
// The following Markdown:
// ###### Heading
//
// Text after two newlines
//
// Should be rendered as:
// ###### Heading
//
// Text after two newlines
Console.WriteLine("Example 2\nSection Headings\n");
TestNormalize.TestSpec("###### Heading\n\nText after two newlines", "###### Heading\n\nText after two newlines", "");
}
[Test]
public void Headings_Example003()
{
// Example 3
// Section: Headings
//
// The following Markdown:
// Heading
// =======
//
// Text after two newlines
//
// Should be rendered as:
// # Heading
//
// Text after two newlines
Console.WriteLine("Example 3\nSection Headings\n");
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines", "# Heading\n\nText after two newlines", "");
}
}
}

View File

@@ -0,0 +1,48 @@
# Headings
```````````````````````````````` example
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
.
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
````````````````````````````````
```````````````````````````````` example
###### Heading
Text after two newlines
.
###### Heading
Text after two newlines
````````````````````````````````
```````````````````````````````` example
Heading
=======
Text after two newlines
.
# Heading
Text after two newlines
````````````````````````````````

View File

@@ -0,0 +1,35 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Sample
// --------------------------------
using System;
using NUnit.Framework;
namespace Markdig.Tests.Specs.PlainText.Sample
{
[TestFixture]
public class TestSamplePlainTextSpec
{
// # Sample plain text spec
//
// Emphasis and anchors are stripped. A newline is ensured.
[Test]
public void SamplePlainTextSpec_Example001()
{
// Example 1
// Section: Sample plain text spec
//
// The following Markdown:
// *Hello*, [world](http://example.com)!
//
// Should be rendered as:
// Hello, world!
//
Console.WriteLine("Example 1\nSection Sample plain text spec\n");
TestPlainText.TestSpec("*Hello*, [world](http://example.com)!", "Hello, world!\n", "");
}
}
}

View File

@@ -0,0 +1,10 @@
# Sample plain text spec
Emphasis and anchors are stripped. A newline is ensured.
```````````````````````````````` example
*Hello*, [world](http://example.com)!
.
Hello, world!
````````````````````````````````

View File

@@ -1,14 +0,0 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
namespace Markdig.Tests
{
public class Program
{
public static void Main()
{
new TestPlayParser().TestSimple();
}
}
}

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Textamin.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Textamin.Tests")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a0c5cb5f-5568-40ab-b945-d6d2664d51b0")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,4 +1,4 @@
// Generated: 6. 02. 2019 16:15:54
// Generated: 2019-05-15 02:46:55
// --------------------------------
// Abbreviations

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Auto Identifiers

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Auto Links
@@ -446,4 +446,113 @@ namespace Markdig.Tests.Specs.AutoLinks
TestParser.TestSpec("https://github.com?\n\nhttps://github.com?a\n\nhttps://github.com#a\n\nhttps://github.com:\n\nhttps://github.com:443", "<p><a href=\"https://github.com\">https://github.com</a>?</p>\n<p><a href=\"https://github.com?a\">https://github.com?a</a></p>\n<p><a href=\"https://github.com#a\">https://github.com#a</a></p>\n<p><a href=\"https://github.com\">https://github.com</a>:</p>\n<p><a href=\"https://github.com:443\">https://github.com:443</a></p>", "autolinks|advanced");
}
}
[TestFixture]
public class TestExtensionsAutoLinksUnicodeSupport
{
// ### Unicode support
//
// Links with unicode characters in the path / query / fragment are matched and url encoded
[Test]
public void ExtensionsAutoLinksUnicodeSupport_Example021()
{
// Example 21
// Section: Extensions / AutoLinks / Unicode support
//
// The following Markdown:
// http://abc.net/☃
//
// http://abc.net?☃
//
// http://abc.net#☃
//
// http://abc.net/foo#☃
//
// Should be rendered as:
// <p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
// <p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
Console.WriteLine("Example 21\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("http://abc.net/☃\n\nhttp://abc.net?☃\n\nhttp://abc.net#☃\n\nhttp://abc.net/foo#☃", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
}
// Unicode characters in the FQDN are matched and IDNA encoded
[Test]
public void ExtensionsAutoLinksUnicodeSupport_Example022()
{
// Example 22
// Section: Extensions / AutoLinks / Unicode support
//
// The following Markdown:
// http://☃.net?☃
//
// Should be rendered as:
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
Console.WriteLine("Example 22\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("http://☃.net?☃", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
}
// Same goes for regular autolinks
[Test]
public void ExtensionsAutoLinksUnicodeSupport_Example023()
{
// Example 23
// Section: Extensions / AutoLinks / Unicode support
//
// The following Markdown:
// <http://abc.net/☃>
//
// <http://abc.net?☃>
//
// <http://abc.net#☃>
//
// <http://abc.net/foo#☃>
//
// Should be rendered as:
// <p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
// <p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
Console.WriteLine("Example 23\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("<http://abc.net/☃>\n\n<http://abc.net?☃>\n\n<http://abc.net#☃>\n\n<http://abc.net/foo#☃>", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
}
[Test]
public void ExtensionsAutoLinksUnicodeSupport_Example024()
{
// Example 24
// Section: Extensions / AutoLinks / Unicode support
//
// The following Markdown:
// <http://☃.net?☃>
//
// Should be rendered as:
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
Console.WriteLine("Example 24\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("<http://☃.net?☃>", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
}
// It also complies with CommonMark's vision of priority.
// This will therefore be seen as an autolink and not as code inline.
[Test]
public void ExtensionsAutoLinksUnicodeSupport_Example025()
{
// Example 25
// Section: Extensions / AutoLinks / Unicode support
//
// The following Markdown:
// <http://foö.bar.`baz>`
//
// Should be rendered as:
// <p><a href="http://xn--fo-gka.bar.%60baz">http://foö.bar.`baz</a>`</p>
Console.WriteLine("Example 25\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("<http://foö.bar.`baz>`", "<p><a href=\"http://xn--fo-gka.bar.%60baz\">http://foö.bar.`baz</a>`</p>", "autolinks|advanced");
}
}
}

View File

@@ -239,4 +239,63 @@ https://github.com:443
<p><a href="https://github.com#a">https://github.com#a</a></p>
<p><a href="https://github.com">https://github.com</a>:</p>
<p><a href="https://github.com:443">https://github.com:443</a></p>
````````````````````````````````
### Unicode support
Links with unicode characters in the path / query / fragment are matched and url encoded
```````````````````````````````` example
http://abc.net/☃
http://abc.net?☃
http://abc.net#☃
http://abc.net/foo#☃
.
<p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
<p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
<p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
<p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
````````````````````````````````
Unicode characters in the FQDN are matched and IDNA encoded
```````````````````````````````` example
http://☃.net?☃
.
<p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
````````````````````````````````
Same goes for regular autolinks
```````````````````````````````` example
<http://abc.net/☃>
<http://abc.net?☃>
<http://abc.net#☃>
<http://abc.net/foo#☃>
.
<p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
<p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
<p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
<p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
````````````````````````````````
```````````````````````````````` example
<http://☃.net?☃>
.
<p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
````````````````````````````````
It also complies with CommonMark's vision of priority.
This will therefore be seen as an autolink and not as code inline.
```````````````````````````````` example
<http://foö.bar.`baz>`
.
<p><a href="http://xn--fo-gka.bar.%60baz">http://foö.bar.`baz</a>`</p>
````````````````````````````````

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-15 05:23:49
// --------------------------------
// Bootstrap
@@ -14,7 +14,7 @@ namespace Markdig.Tests.Specs.Bootstrap
{
// # Extensions
//
// Adds support for outputing bootstrap ready tags:
// Adds support for outputting bootstrap ready tags:
//
// ## Bootstrap
//

View File

@@ -1,6 +1,6 @@
# Extensions
Adds support for outputing bootstrap ready tags:
Adds support for outputting bootstrap ready tags:
## Bootstrap

View File

@@ -1,8 +1,8 @@
---
title: CommonMark Spec
author: John MacFarlane
version: 0.28
date: '2017-08-01'
version: 0.29
date: '2019-04-06'
license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)'
...
@@ -248,7 +248,7 @@ satisfactory replacement for a spec.
Because there is no unambiguous spec, implementations have diverged
considerably. As a result, users are often surprised to find that
a document that renders one way on one system (say, a github wiki)
a document that renders one way on one system (say, a GitHub wiki)
renders differently on another (say, converting to docbook using
pandoc). To make matters worse, because nothing in Markdown counts
as a "syntax error," the divergence often isn't discovered right away.
@@ -328,8 +328,10 @@ that is not a [whitespace character].
An [ASCII punctuation character](@)
is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`,
`*`, `+`, `,`, `-`, `.`, `/`, `:`, `;`, `<`, `=`, `>`, `?`, `@`,
`[`, `\`, `]`, `^`, `_`, `` ` ``, `{`, `|`, `}`, or `~`.
`*`, `+`, `,`, `-`, `.`, `/` (U+00212F),
`:`, `;`, `<`, `=`, `>`, `?`, `@` (U+003A0040),
`[`, `\`, `]`, `^`, `_`, `` ` `` (U+005B0060),
`{`, `|`, `}`, or `~` (U+007B007E).
A [punctuation character](@) is an [ASCII
punctuation character] or anything in
@@ -514,8 +516,8 @@ one block element does not affect the inline parsing of any other.
## Container blocks and leaf blocks
We can divide blocks into two types:
[container block](@)s,
which can contain other blocks, and [leaf block](@)s,
[container blocks](@),
which can contain other blocks, and [leaf blocks](@),
which cannot.
# Leaf blocks
@@ -527,7 +529,7 @@ Markdown document.
A line consisting of 0-3 spaces of indentation, followed by a sequence
of three or more matching `-`, `_`, or `*` characters, each followed
optionally by any number of spaces, forms a
optionally by any number of spaces or tabs, forms a
[thematic break](@).
```````````````````````````````` example
@@ -825,7 +827,7 @@ Contents are parsed as inlines:
````````````````````````````````
Leading and trailing blanks are ignored in parsing inline content:
Leading and trailing [whitespace] is ignored in parsing inline content:
```````````````````````````````` example
# foo
@@ -1024,6 +1026,20 @@ baz*
baz</em></h1>
````````````````````````````````
The contents are the result of parsing the headings's raw
content as inlines. The heading's raw content is formed by
concatenating the lines and removing initial and final
[whitespace].
```````````````````````````````` example
Foo *bar
baz*→
====
.
<h1>Foo <em>bar
baz</em></h1>
````````````````````````````````
The underlining can be any length:
@@ -1584,8 +1600,8 @@ begins with a code fence, indented no more than three spaces.
The line with the opening code fence may optionally contain some text
following the code fence; this is trimmed of leading and trailing
spaces and called the [info string](@).
The [info string] may not contain any backtick
whitespace and called the [info string](@). If the [info string] comes
after a backtick fence, it may not contain any backtick
characters. (The reason for this restriction is that otherwise
some inline code would be incorrectly interpreted as the
beginning of a fenced code block.)
@@ -1870,7 +1886,7 @@ Code fences (opening and closing) cannot contain internal spaces:
``` ```
aaa
.
<p><code></code>
<p><code> </code>
aaa</p>
````````````````````````````````
@@ -1922,9 +1938,11 @@ bar
An [info string] can be provided after the opening code fence.
Opening and closing spaces will be stripped, and the first word, prefixed
with `language-`, is used as the value for the `class` attribute of the
`code` element within the enclosing `pre` element.
Although this spec doesn't mandate any particular treatment of
the info string, the first word is typically used to specify
the language of the code block. In HTML output, the language is
normally indicated by adding a class to the `code` element consisting
of `language-` followed by the language name.
```````````````````````````````` example
```ruby
@@ -1973,6 +1991,18 @@ foo</p>
````````````````````````````````
[Info strings] for tilde code blocks can contain backticks and tildes:
```````````````````````````````` example
~~~ aa ``` ~~~
foo
~~~
.
<pre><code class="language-aa">foo
</code></pre>
````````````````````````````````
Closing code fences cannot have [info strings]:
```````````````````````````````` example
@@ -1991,14 +2021,15 @@ Closing code fences cannot have [info strings]:
An [HTML block](@) is a group of lines that is treated
as raw HTML (and will not be escaped in HTML output).
There are seven kinds of [HTML block], which can be defined
by their start and end conditions. The block begins with a line that
meets a [start condition](@) (after up to three spaces
optional indentation). It ends with the first subsequent line that
meets a matching [end condition](@), or the last line of
the document or other [container block]), if no line is encountered that meets the
[end condition]. If the first line meets both the [start condition]
and the [end condition], the block will contain just that line.
There are seven kinds of [HTML block], which can be defined by their
start and end conditions. The block begins with a line that meets a
[start condition](@) (after up to three spaces optional indentation).
It ends with the first subsequent line that meets a matching [end
condition](@), or the last line of the document, or the last line of
the [container block](#container-blocks) containing the current HTML
block, if no line is encountered that meets the [end condition]. If
the first line meets both the [start condition] and the [end
condition], the block will contain just that line.
1. **Start condition:** line begins with the string `<script`,
`<pre`, or `<style` (case-insensitive), followed by whitespace,
@@ -2029,7 +2060,7 @@ followed by one of the strings (case-insensitive) `address`,
`footer`, `form`, `frame`, `frameset`,
`h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hr`,
`html`, `iframe`, `legend`, `li`, `link`, `main`, `menu`, `menuitem`,
`meta`, `nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
`nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
`section`, `source`, `summary`, `table`, `tbody`, `td`,
`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
by [whitespace], the end of the line, the string `>`, or
@@ -2037,16 +2068,17 @@ the string `/>`.\
**End condition:** line is followed by a [blank line].
7. **Start condition:** line begins with a complete [open tag]
or [closing tag] (with any [tag name] other than `script`,
`style`, or `pre`) followed only by [whitespace]
or the end of the line.\
(with any [tag name] other than `script`,
`style`, or `pre`) or a complete [closing tag],
followed only by [whitespace] or the end of the line.\
**End condition:** line is followed by a [blank line].
HTML blocks continue until they are closed by their appropriate
[end condition], or the last line of the document or other [container block].
This means any HTML **within an HTML block** that might otherwise be recognised
as a start condition will be ignored by the parser and passed through as-is,
without changing the parser's state.
[end condition], or the last line of the document or other [container
block](#container-blocks). This means any HTML **within an HTML
block** that might otherwise be recognised as a start condition will
be ignored by the parser and passed through as-is, without changing
the parser's state.
For instance, `<pre>` within a HTML block started by `<table>` will not affect
the parser state; as the HTML block was started in by start condition 6, it
@@ -2069,7 +2101,7 @@ _world_.
</td></tr></table>
````````````````````````````````
In this case, the HTML block is terminated by the newline — the `**hello**`
In this case, the HTML block is terminated by the newline — the `**Hello**`
text remains verbatim — and regular parsing resumes, with a paragraph,
emphasised `world` and inline and block HTML following.
@@ -2612,7 +2644,8 @@ bar
However, a following blank line is needed, except at the end of
a document, and except for blocks of types 1--5, above:
a document, and except for blocks of types 1--5, [above][HTML
block]:
```````````````````````````````` example
<div>
@@ -2758,8 +2791,8 @@ an indented code block:
Fortunately, blank lines are usually not necessary and can be
deleted. The exception is inside `<pre>` tags, but as described
above, raw HTML blocks starting with `<pre>` *can* contain blank
lines.
[above][HTML blocks], raw HTML blocks starting with `<pre>`
*can* contain blank lines.
## Link reference definitions
@@ -2811,7 +2844,7 @@ them.
```````````````````````````````` example
[Foo bar]:
<my%20url>
<my url>
'title'
[Foo bar]
@@ -2877,6 +2910,29 @@ The link destination may not be omitted:
<p>[foo]</p>
````````````````````````````````
However, an empty link destination may be specified using
angle brackets:
```````````````````````````````` example
[foo]: <>
[foo]
.
<p><a href="">foo</a></p>
````````````````````````````````
The title must be separated from the link destination by
whitespace:
```````````````````````````````` example
[foo]: <bar>(baz)
[foo]
.
<p>[foo]: <bar>(baz)</p>
<p>[foo]</p>
````````````````````````````````
Both title and destination can contain backslash escapes
and literal backslashes:
@@ -3034,6 +3090,25 @@ and thematic breaks, and it need not be followed by a blank line.
</blockquote>
````````````````````````````````
```````````````````````````````` example
[foo]: /url
bar
===
[foo]
.
<h1>bar</h1>
<p><a href="/url">foo</a></p>
````````````````````````````````
```````````````````````````````` example
[foo]: /url
===
[foo]
.
<p>===
<a href="/url">foo</a></p>
````````````````````````````````
Several [link reference definitions]
can occur one after another, without intervening blank lines.
@@ -3070,6 +3145,17 @@ are defined:
````````````````````````````````
Whether something is a [link reference definition] is
independent of whether the link reference it defines is
used in the document. Thus, for example, the following
document contains just a link reference definition, and
no visible content:
```````````````````````````````` example
[foo]: /url
.
````````````````````````````````
## Paragraphs
@@ -3207,7 +3293,7 @@ aaa
# Container blocks
A [container block] is a block that has other
A [container block](#container-blocks) is a block that has other
blocks as its contents. There are two basic kinds of container blocks:
[block quotes] and [list items].
[Lists] are meta-containers for [list items].
@@ -3669,9 +3755,8 @@ in some browsers.)
The following rules define [list items]:
1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of
blocks *Bs* starting with a [non-whitespace character] and not separated
from each other by more than one blank line, and *M* is a list
marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result
blocks *Bs* starting with a [non-whitespace character], and *M* is a
list marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result
of prepending *M* and the following spaces to the first line of
*Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a
list item with *Bs* as its contents. The type of the list item
@@ -3981,8 +4066,7 @@ A start number may not be negative:
2. **Item starting with indented code.** If a sequence of lines *Ls*
constitute a sequence of blocks *Bs* starting with an indented code
block and not separated from each other by more than one blank line,
and *M* is a list marker of width *W* followed by
block, and *M* is a list marker of width *W* followed by
one space, then the result of prepending *M* and the following
space to the first line of *Ls*, and indenting subsequent lines of
*Ls* by *W + 1* spaces, is a list item with *Bs* as its contents.
@@ -4458,9 +4542,10 @@ continued here.</p>
6. **That's all.** Nothing that is not counted as a list item by rules
#1--5 counts as a [list item](#list-items).
The rules for sublists follow from the general rules above. A sublist
must be indented the same number of spaces a paragraph would need to be
in order to be included in the list item.
The rules for sublists follow from the general rules
[above][List items]. A sublist must be indented the same number
of spaces a paragraph would need to be in order to be included
in the list item.
So, in this case we need two spaces indent:
@@ -5049,11 +5134,9 @@ item:
- b
- c
- d
- e
- f
- g
- h
- i
- e
- f
- g
.
<ul>
<li>a</li>
@@ -5063,12 +5146,54 @@ item:
<li>e</li>
<li>f</li>
<li>g</li>
<li>h</li>
<li>i</li>
</ul>
````````````````````````````````
```````````````````````````````` example
1. a
2. b
3. c
.
<ol>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
</li>
<li>
<p>c</p>
</li>
</ol>
````````````````````````````````
Note, however, that list items may not be indented more than
three spaces. Here `- e` is treated as a paragraph continuation
line, because it is indented more than three spaces:
```````````````````````````````` example
- a
- b
- c
- d
- e
.
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d
- e</li>
</ul>
````````````````````````````````
And here, `3. c` is treated as in indented code block,
because it is indented four spaces and preceded by a
blank line.
```````````````````````````````` example
1. a
@@ -5083,10 +5208,9 @@ item:
<li>
<p>b</p>
</li>
<li>
<p>c</p>
</li>
</ol>
<pre><code>3. c
</code></pre>
````````````````````````````````
@@ -5378,10 +5502,10 @@ Thus, for example, in
<p><code>hi</code>lo`</p>
````````````````````````````````
`hi` is parsed as code, leaving the backtick at the end as a literal
backtick.
## Backslash escapes
Any ASCII punctuation character may be backslash-escaped:
@@ -5415,6 +5539,7 @@ not have their usual Markdown meanings:
\* not a list
\# not a heading
\[foo]: /url "not a reference"
\&ouml; not a character entity
.
<p>*not emphasized*
&lt;br/&gt; not a tag
@@ -5423,7 +5548,8 @@ not have their usual Markdown meanings:
1. not a list
* not a list
# not a heading
[foo]: /url &quot;not a reference&quot;</p>
[foo]: /url &quot;not a reference&quot;
&amp;ouml; not a character entity</p>
````````````````````````````````
@@ -5521,13 +5647,23 @@ foo
## Entity and numeric character references
All valid HTML entity references and numeric character
references, except those occuring in code blocks and code spans,
are recognized as such and treated as equivalent to the
corresponding Unicode characters. Conforming CommonMark parsers
need not store information about whether a particular character
was represented in the source using a Unicode character or
an entity reference.
Valid HTML entity references and numeric character references
can be used in place of the corresponding Unicode character,
with the following exceptions:
- Entity and character references are not recognized in code
blocks and code spans.
- Entity and character references cannot stand in place of
special characters that define structural elements in
CommonMark. For example, although `&#42;` can be used
in place of a literal `*` character, `&#42;` cannot replace
`*` in emphasis delimiters, bullet list markers, or thematic
breaks.
Conforming CommonMark parsers need not store information about
whether a particular character was represented in the source
using a Unicode character or an entity reference.
[Entity references](@) consist of `&` + any of the valid
HTML5 entity names + `;`. The
@@ -5548,22 +5684,22 @@ references and their corresponding code points.
[Decimal numeric character
references](@)
consist of `&#` + a string of 1--8 arabic digits + `;`. A
consist of `&#` + a string of 1--7 arabic digits + `;`. A
numeric character reference is parsed as the corresponding
Unicode character. Invalid Unicode code points will be replaced by
the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons,
the code point `U+0000` will also be replaced by `U+FFFD`.
```````````````````````````````` example
&#35; &#1234; &#992; &#98765432; &#0;
&#35; &#1234; &#992; &#0;
.
<p># Ӓ Ϡ <20> <20></p>
<p># Ӓ Ϡ <20></p>
````````````````````````````````
[Hexadecimal numeric character
references](@) consist of `&#` +
either `X` or `x` + a string of 1-8 hexadecimal digits + `;`.
either `X` or `x` + a string of 1-6 hexadecimal digits + `;`.
They too are parsed as the corresponding Unicode character (this
time specified with a hexadecimal numeral instead of decimal).
@@ -5578,9 +5714,13 @@ Here are some nonentities:
```````````````````````````````` example
&nbsp &x; &#; &#x;
&#87654321;
&#abcdef0;
&ThisIsNotDefined; &hi?;
.
<p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
&amp;#87654321;
&amp;#abcdef0;
&amp;ThisIsNotDefined; &amp;hi?;</p>
````````````````````````````````
@@ -5661,6 +5801,51 @@ text in code spans and code blocks:
````````````````````````````````
Entity and numeric character references cannot be used
in place of symbols indicating structure in CommonMark
documents.
```````````````````````````````` example
&#42;foo&#42;
*foo*
.
<p>*foo*
<em>foo</em></p>
````````````````````````````````
```````````````````````````````` example
&#42; foo
* foo
.
<p>* foo</p>
<ul>
<li>foo</li>
</ul>
````````````````````````````````
```````````````````````````````` example
foo&#10;&#10;bar
.
<p>foo
bar</p>
````````````````````````````````
```````````````````````````````` example
&#9;foo
.
<p>→foo</p>
````````````````````````````````
```````````````````````````````` example
[a](url &quot;tit&quot;)
.
<p>[a](url &quot;tit&quot;)</p>
````````````````````````````````
## Code spans
A [backtick string](@)
@@ -5669,9 +5854,16 @@ preceded nor followed by a backtick.
A [code span](@) begins with a backtick string and ends with
a backtick string of equal length. The contents of the code span are
the characters between the two backtick strings, with leading and
trailing spaces and [line endings] removed, and
[whitespace] collapsed to single spaces.
the characters between the two backtick strings, normalized in the
following ways:
- First, [line endings] are converted to [spaces].
- If the resulting string both begins *and* ends with a [space]
character, but does not consist entirely of [space]
characters, a single [space] character is removed from the
front and back. This allows you to include code that begins
or ends with backtick characters, which must be separated by
whitespace from the opening or closing backtick strings.
This is a simple code span:
@@ -5683,10 +5875,11 @@ This is a simple code span:
Here two backticks are used, because the code contains a backtick.
This example also illustrates stripping of leading and trailing spaces:
This example also illustrates stripping of a single leading and
trailing space:
```````````````````````````````` example
`` foo ` bar ``
`` foo ` bar ``
.
<p><code>foo ` bar</code></p>
````````````````````````````````
@@ -5701,57 +5894,78 @@ spaces:
<p><code>``</code></p>
````````````````````````````````
Note that only *one* space is stripped:
```````````````````````````````` example
` `` `
.
<p><code> `` </code></p>
````````````````````````````````
The stripping only happens if the space is on both
sides of the string:
```````````````````````````````` example
` a`
.
<p><code> a</code></p>
````````````````````````````````
Only [spaces], and not [unicode whitespace] in general, are
stripped in this way:
```````````````````````````````` example
` b `
.
<p><code> b </code></p>
````````````````````````````````
No stripping occurs if the code span contains only spaces:
```````````````````````````````` example
` `
` `
.
<p><code> </code>
<code> </code></p>
````````````````````````````````
[Line endings] are treated like spaces:
```````````````````````````````` example
``
foo
bar
baz
``
.
<p><code>foo</code></p>
<p><code>foo bar baz</code></p>
````````````````````````````````
Interior spaces and [line endings] are collapsed into
single spaces, just as they would be by a browser:
```````````````````````````````` example
`foo bar
baz`
``
foo
``
.
<p><code>foo bar baz</code></p>
<p><code>foo </code></p>
````````````````````````````````
Not all [Unicode whitespace] (for instance, non-breaking space) is
collapsed, however:
Interior spaces are not collapsed:
```````````````````````````````` example
`a  b`
`foo bar
baz`
.
<p><code>a  b</code></p>
<p><code>foo bar baz</code></p>
````````````````````````````````
Note that browsers will typically collapse consecutive spaces
when rendering `<code>` elements, so it is recommended that
the following CSS be used:
Q: Why not just leave the spaces, since browsers will collapse them
anyway? A: Because we might be targeting a non-HTML format, and we
shouldn't rely on HTML-specific rendering assumptions.
(Existing implementations differ in their treatment of internal
spaces and [line endings]. Some, including `Markdown.pl` and
`showdown`, convert an internal [line ending] into a
`<br />` tag. But this makes things difficult for those who like to
hard-wrap their paragraphs, since a line break in the midst of a code
span will cause an unintended line break in the output. Others just
leave internal spaces as they are, which is fine if only HTML is being
targeted.)
```````````````````````````````` example
`foo `` bar`
.
<p><code>foo `` bar</code></p>
````````````````````````````````
code{white-space: pre-wrap;}
Note that backslash escapes do not work in code spans. All backslashes
@@ -5768,6 +5982,19 @@ Backslash escapes are never needed, because one can always choose a
string of *n* backtick characters as delimiters, where the code does
not contain any strings of exactly *n* backtick characters.
```````````````````````````````` example
``foo`bar``
.
<p><code>foo`bar</code></p>
````````````````````````````````
```````````````````````````````` example
` foo `` bar `
.
<p><code>foo `` bar</code></p>
````````````````````````````````
Code span backticks have higher precedence than any other inline
constructs except HTML tags and autolinks. Thus, for example, this is
not parsed as emphasized text, since the second `*` is part of a code
@@ -5905,15 +6132,17 @@ of one or more `_` characters that is not preceded or followed by
a non-backslash-escaped `_` character.
A [left-flanking delimiter run](@) is
a [delimiter run] that is (a) not followed by [Unicode whitespace],
and (b) not followed by a [punctuation character], or
a [delimiter run] that is (1) not followed by [Unicode whitespace],
and either (2a) not followed by a [punctuation character], or
(2b) followed by a [punctuation character] and
preceded by [Unicode whitespace] or a [punctuation character].
For purposes of this definition, the beginning and the end of
the line count as Unicode whitespace.
A [right-flanking delimiter run](@) is
a [delimiter run] that is (a) not preceded by [Unicode whitespace],
and (b) not preceded by a [punctuation character], or
a [delimiter run] that is (1) not preceded by [Unicode whitespace],
and either (2a) not preceded by a [punctuation character], or
(2b) preceded by a [punctuation character] and
followed by [Unicode whitespace] or a [punctuation character].
For purposes of this definition, the beginning and the end of
the line count as Unicode whitespace.
@@ -6005,7 +6234,8 @@ The following rules define emphasis and strong emphasis:
[delimiter runs]. If one of the delimiters can both
open and close emphasis, then the sum of the lengths of the
delimiter runs containing the opening and closing delimiters
must not be a multiple of 3.
must not be a multiple of 3 unless both lengths are
multiples of 3.
10. Strong emphasis begins with a delimiter that
[can open strong emphasis] and ends with a delimiter that
@@ -6015,7 +6245,8 @@ The following rules define emphasis and strong emphasis:
[delimiter runs]. If one of the delimiters can both open
and close strong emphasis, then the sum of the lengths of
the delimiter runs containing the opening and closing
delimiters must not be a multiple of 3.
delimiters must not be a multiple of 3 unless both lengths
are multiples of 3.
11. A literal `*` character cannot occur at the beginning or end of
`*`-delimited emphasis or `**`-delimited strong emphasis, unless it
@@ -6634,7 +6865,19 @@ is precluded by the condition that a delimiter that
can both open and close (like the `*` after `foo`)
cannot form emphasis if the sum of the lengths of
the delimiter runs containing the opening and
closing delimiters is a multiple of 3.
closing delimiters is a multiple of 3 unless
both lengths are multiples of 3.
For the same reason, we don't get two consecutive
emphasis sections in this example:
```````````````````````````````` example
*foo**bar*
.
<p><em>foo**bar</em></p>
````````````````````````````````
The same condition ensures that the following
cases are all strong emphasis nested inside
@@ -6663,6 +6906,23 @@ omitted:
````````````````````````````````
When the lengths of the interior closing and opening
delimiter runs are *both* multiples of 3, though,
they can match to create emphasis:
```````````````````````````````` example
foo***bar***baz
.
<p>foo<em><strong>bar</strong></em>baz</p>
````````````````````````````````
```````````````````````````````` example
foo******bar*********baz
.
<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
````````````````````````````````
Indefinite levels of nesting are possible:
```````````````````````````````` example
@@ -7198,15 +7458,16 @@ following rules apply:
A [link destination](@) consists of either
- a sequence of zero or more characters between an opening `<` and a
closing `>` that contains no spaces, line breaks, or unescaped
closing `>` that contains no line breaks or unescaped
`<` or `>` characters, or
- a nonempty sequence of characters that does not include
ASCII space or control characters, and includes parentheses
only if (a) they are backslash-escaped or (b) they are part of
a balanced pair of unescaped parentheses. (Implementations
may impose limits on parentheses nesting to avoid performance
issues, but at least three levels of nesting should be supported.)
- a nonempty sequence of characters that does not start with
`<`, does not include ASCII space or control characters, and
includes parentheses only if (a) they are backslash-escaped or
(b) they are part of a balanced pair of unescaped parentheses.
(Implementations may impose limits on parentheses nesting to
avoid performance issues, but at least three levels of nesting
should be supported.)
A [link title](@) consists of either
@@ -7219,7 +7480,8 @@ A [link title](@) consists of either
backslash-escaped, or
- a sequence of zero or more characters between matching parentheses
(`(...)`), including a `)` character only if it is backslash-escaped.
(`(...)`), including a `(` or `)` character only if it is
backslash-escaped.
Although [link titles] may span multiple lines, they may not contain
a [blank line].
@@ -7269,9 +7531,8 @@ Both the title and the destination may be omitted:
<p><a href="">link</a></p>
````````````````````````````````
The destination cannot contain spaces or line breaks,
even if enclosed in pointy brackets:
The destination can only contain spaces if it is
enclosed in pointy brackets:
```````````````````````````````` example
[link](/my uri)
@@ -7279,13 +7540,14 @@ even if enclosed in pointy brackets:
<p>[link](/my uri)</p>
````````````````````````````````
```````````````````````````````` example
[link](</my uri>)
.
<p>[link](&lt;/my uri&gt;)</p>
<p><a href="/my%20uri">link</a></p>
````````````````````````````````
The destination cannot contain line breaks,
even if enclosed in pointy brackets:
```````````````````````````````` example
[link](foo
@@ -7295,7 +7557,6 @@ bar)
bar)</p>
````````````````````````````````
```````````````````````````````` example
[link](<foo
bar>)
@@ -7304,6 +7565,36 @@ bar>)
bar>)</p>
````````````````````````````````
The destination can contain `)` if it is enclosed
in pointy brackets:
```````````````````````````````` example
[a](<b)c>)
.
<p><a href="b)c">a</a></p>
````````````````````````````````
Pointy brackets that enclose links must be unescaped:
```````````````````````````````` example
[link](<foo\>)
.
<p>[link](&lt;foo&gt;)</p>
````````````````````````````````
These are not links, because the opening pointy bracket
is not matched properly:
```````````````````````````````` example
[a](<b)c
[a](<b)c>
[a](<b>c)
.
<p>[a](&lt;b)c
[a](&lt;b)c&gt;
[a](<b>c)</p>
````````````````````````````````
Parentheses inside the link destination may be escaped:
```````````````````````````````` example
@@ -8411,7 +8702,7 @@ If you want a link after a literal `!`, backslash-escape the
as the link label.
A [URI autolink](@) consists of `<`, followed by an
[absolute URI] not containing `<`, followed by `>`. It is parsed as
[absolute URI] followed by `>`. It is parsed as
a link to the URI, with the URI as the link's label.
An [absolute URI](@),
@@ -8624,7 +8915,7 @@ a [single-quoted attribute value], or a [double-quoted attribute value].
An [unquoted attribute value](@)
is a nonempty string of characters not
including spaces, `"`, `'`, `=`, `<`, `>`, or `` ` ``.
including [whitespace], `"`, `'`, `=`, `<`, `>`, or `` ` ``.
A [single-quoted attribute value](@)
consists of `'`, zero or more
@@ -8745,9 +9036,13 @@ Illegal [whitespace]:
```````````````````````````````` example
< a><
foo><bar/ >
<foo bar=baz
bim!bop />
.
<p>&lt; a&gt;&lt;
foo&gt;&lt;bar/ &gt;</p>
foo&gt;&lt;bar/ &gt;
&lt;foo bar=baz
bim!bop /&gt;</p>
````````````````````````````````
@@ -8944,10 +9239,10 @@ bar</em></p>
Line breaks do not occur inside code spans
```````````````````````````````` example
`code
`code
span`
.
<p><code>code span</code></p>
<p><code>code span</code></p>
````````````````````````````````
@@ -9365,7 +9660,8 @@ just above `stack_bottom` (or the first element if `stack_bottom`
is NULL).
We keep track of the `openers_bottom` for each delimiter
type (`*`, `_`). Initialize this to `stack_bottom`.
type (`*`, `_`) and each length of the closing delimiter run
(modulo 3). Initialize this to `stack_bottom`.
Then we repeat the following until we run out of potential
closers:
@@ -9397,7 +9693,7 @@ closers:
of the delimiter stack. If the closing node is removed, reset
`current_position` to the next element in the stack.
- If none in found:
- If none is found:
+ Set `openers_bottom` to the element before `current_position`.
(We know that there are no openers for this kind of closer up to and

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Custom Containers

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-15 05:06:35
// --------------------------------
// Definition Lists
@@ -18,7 +18,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
//
// ## Definition lists
//
// A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</dib>` block.
// A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
[Test]
public void ExtensionsDefinitionLists_Example001()
{

View File

@@ -4,7 +4,7 @@ This section describes the different extensions supported:
## Definition lists
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</dib>` block.
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
```````````````````````````````` example
@@ -129,4 +129,4 @@ Definition lists can be nested inside list items
<dd>Second Definition</dd>
</dl></li>
</ol>
````````````````````````````````
````````````````````````````````

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Diagrams

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2020-01-13 21:08:58
// --------------------------------
// Emoji
@@ -18,7 +18,7 @@ namespace Markdig.Tests.Specs.Emoji
//
// ## Emoji
//
// Emoji and smiley can be converted to their respective unicode characters:
// Emoji shortcodes and smileys can be converted to their respective unicode characters:
[Test]
public void ExtensionsEmoji_Example001()
{
@@ -52,7 +52,7 @@ namespace Markdig.Tests.Specs.Emoji
TestParser.TestSpec("These are not:) an emoji with a:) x:angry:x", "<p>These are not:) an emoji with a:) x:angry:x</p>", "emojis|advanced+emojis");
}
// Emoji can be followed by close ponctuation (or any other characters):
// Emojis can be followed by close punctuation (or any other characters):
[Test]
public void ExtensionsEmoji_Example003()
{
@@ -69,7 +69,7 @@ namespace Markdig.Tests.Specs.Emoji
TestParser.TestSpec("We all need :), it makes us :muscle:. (and :ok_hand:).", "<p>We all need 😃, it makes us 💪. (and 👌).</p>", "emojis|advanced+emojis");
}
// Sentences can end with Emoji:
// Sentences can end with emojis:
[Test]
public void ExtensionsEmoji_Example004()
{

View File

@@ -4,7 +4,7 @@ This section describes the different extensions supported:
## Emoji
Emoji and smiley can be converted to their respective unicode characters:
Emoji shortcodes and smileys can be converted to their respective unicode characters:
```````````````````````````````` example
This is a test with a :) and a :angry: smiley
@@ -20,7 +20,7 @@ These are not:) an emoji with a:) x:angry:x
<p>These are not:) an emoji with a:) x:angry:x</p>
````````````````````````````````
Emoji can be followed by close ponctuation (or any other characters):
Emojis can be followed by close punctuation (or any other characters):
```````````````````````````````` example
We all need :), it makes us :muscle:. (and :ok_hand:).
@@ -28,7 +28,7 @@ We all need :), it makes us :muscle:. (and :ok_hand:).
<p>We all need 😃, it makes us 💪. (and 👌).</p>
````````````````````````````````
Sentences can end with Emoji:
Sentences can end with emojis:
```````````````````````````````` example
This is a sentence :ok_hand:

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Emphasis Extra

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:42:25
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Figures, Footers and Cites

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-15 05:33:49
// --------------------------------
// Footnotes
@@ -84,7 +84,7 @@ namespace Markdig.Tests.Specs.Footnotes
TestParser.TestSpec("Here is a footnote reference,[^1] and another.[^longnote]\n\nThis is another reference to [^1]\n\n[^1]: Here is the footnote.\n\nAnd another reference to [^longnote]\n\n[^longnote]: Here's one with multiple blocks.\n\n Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.\n\n > This is a block quote\n > Inside a footnote\n\n { some.code }\n\n The whole paragraph can be indented, or just the first\n line. In this way, multi-paragraph footnotes work like\n multi-paragraph list items.\n\nThis paragraph won't be part of the note, because it\nisn't indented.", "<p>Here is a footnote reference,<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a> and another.<a id=\"fnref:3\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This is another reference to <a id=\"fnref:2\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></p>\n<p>And another reference to <a id=\"fnref:4\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This paragraph won't be part of the note, because it\nisn't indented.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a><a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p>\n</li>\n<li id=\"fn:2\">\n<p>Here's one with multiple blocks.</p>\n<p>Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.</p>\n<blockquote>\n<p>This is a block quote\nInside a footnote</p>\n</blockquote>\n<pre><code>{ some.code }\n</code></pre>\n<p>The whole paragraph can be indented, or just the first\nline. In this way, multi-paragraph footnotes work like\nmulti-paragraph list items.<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a><a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</a></p>\n</li>\n</ol>\n</div>", "footnotes|advanced");
}
// Check with mulitple consecutive footnotes:
// Check with multiple consecutive footnotes:
[Test]
public void ExtensionsFootnotes_Example002()
{

View File

@@ -61,7 +61,7 @@ multi-paragraph list items.<a href="#fnref:3" class="footnote-back-ref">&#8617;<
</div>
````````````````````````````````
Check with mulitple consecutive footnotes:
Check with multiple consecutive footnotes:
```````````````````````````````` example
Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 15:02:43
// Generated: 2019-08-01 13:57:17
// --------------------------------
// Generic Attributes
@@ -79,5 +79,28 @@ namespace Markdig.Tests.Specs.GenericAttributes
Console.WriteLine("Example 2\nSection Extensions / Generic Attributes\n");
TestParser.TestSpec("{#fenced-id .fenced-class}\n~~~\nThis is a fenced with attached attributes\n~~~ ", "<pre><code id=\"fenced-id\" class=\"fenced-class\">This is a fenced with attached attributes\n</code></pre>", "attributes|advanced");
}
// Attribute values can be one character long
[Test]
public void ExtensionsGenericAttributes_Example003()
{
// Example 3
// Section: Extensions / Generic Attributes
//
// The following Markdown:
// [Foo](url){data-x=1}
//
// [Foo](url){data-x='1'}
//
// [Foo](url){data-x=11}
//
// Should be rendered as:
// <p><a href="url" data-x="1">Foo</a></p>
// <p><a href="url" data-x="1">Foo</a></p>
// <p><a href="url" data-x="11">Foo</a></p>
Console.WriteLine("Example 3\nSection Extensions / Generic Attributes\n");
TestParser.TestSpec("[Foo](url){data-x=1}\n\n[Foo](url){data-x='1'}\n\n[Foo](url){data-x=11}", "<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"11\">Foo</a></p>", "attributes|advanced");
}
}
}

View File

@@ -47,3 +47,17 @@ This is a fenced with attached attributes
<pre><code id="fenced-id" class="fenced-class">This is a fenced with attached attributes
</code></pre>
````````````````````````````````
Attribute values can be one character long
```````````````````````````````` example
[Foo](url){data-x=1}
[Foo](url){data-x='1'}
[Foo](url){data-x=11}
.
<p><a href="url" data-x="1">Foo</a></p>
<p><a href="url" data-x="1">Foo</a></p>
<p><a href="url" data-x="11">Foo</a></p>
````````````````````````````````

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-15 05:25:26
// --------------------------------
// Globalization
@@ -173,7 +173,7 @@ namespace Markdig.Tests.Specs.Globalization
// Section: Extensions / Globalization
//
// The following Markdown:
// Nuitrion |Apple | Oranges
// Nutrition |Apple | Oranges
// --|-- | --
// Calories|52|47
// Sugar|10g|9g
@@ -187,7 +187,7 @@ namespace Markdig.Tests.Specs.Globalization
// <table>
// <thead>
// <tr>
// <th>Nuitrion</th>
// <th>Nutrition</th>
// <th>Apple</th>
// <th>Oranges</th>
// </tr>
@@ -228,7 +228,7 @@ namespace Markdig.Tests.Specs.Globalization
// </table>
Console.WriteLine("Example 3\nSection Extensions / Globalization\n");
TestParser.TestSpec("Nuitrion |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "<table>\n<thead>\n<tr>\n<th>Nuitrion</th>\n<th>Apple</th>\n<th>Oranges</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Calories</td>\n<td>52</td>\n<td>47</td>\n</tr>\n<tr>\n<td>Sugar</td>\n<td>10g</td>\n<td>9g</td>\n</tr>\n</tbody>\n</table>\n<table dir=\"rtl\" align=\"right\">\n<thead>\n<tr>\n<th>پێکهاتە</th>\n<th>سێو</th>\n<th>پڕتەقاڵ</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>کالۆری</td>\n<td>٥٢</td>\n<td>٤٧</td>\n</tr>\n<tr>\n<td>شەکر</td>\n<td>١٠گ</td>\n<td>٩گ</td>\n</tr>\n</tbody>\n</table>", "globalization+advanced+emojis");
TestParser.TestSpec("Nutrition |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "<table>\n<thead>\n<tr>\n<th>Nutrition</th>\n<th>Apple</th>\n<th>Oranges</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Calories</td>\n<td>52</td>\n<td>47</td>\n</tr>\n<tr>\n<td>Sugar</td>\n<td>10g</td>\n<td>9g</td>\n</tr>\n</tbody>\n</table>\n<table dir=\"rtl\" align=\"right\">\n<thead>\n<tr>\n<th>پێکهاتە</th>\n<th>سێو</th>\n<th>پڕتەقاڵ</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>کالۆری</td>\n<td>٥٢</td>\n<td>٤٧</td>\n</tr>\n<tr>\n<td>شەکر</td>\n<td>١٠گ</td>\n<td>٩گ</td>\n</tr>\n</tbody>\n</table>", "globalization+advanced+emojis");
}
}
}

View File

@@ -134,7 +134,7 @@ Lists:
Tables:
```````````````````````````````` example
Nuitrion |Apple | Oranges
Nutrition |Apple | Oranges
--|-- | --
Calories|52|47
Sugar|10g|9g
@@ -147,7 +147,7 @@ Sugar|10g|9g
<table>
<thead>
<tr>
<th>Nuitrion</th>
<th>Nutrition</th>
<th>Apple</th>
<th>Oranges</th>
</tr>

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2020-04-18 06:41:26
// --------------------------------
// Grid Tables
@@ -62,8 +62,8 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:50%">
// <col style="width:50%">
// <col style="width:50%" />
// <col style="width:50%" />
// <tbody>
// <tr>
// <td>This is</td>
@@ -73,7 +73,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 1\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+\n| This is | a table |", "<table>\n<col style=\"width:50%\">\n<col style=\"width:50%\">\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+\n| This is | a table |", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
}
// The following is not a valid row separator
@@ -112,9 +112,9 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <tbody>
// <tr>
// <td>Col1
@@ -135,7 +135,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 3\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+---------+\n| Col1 | Col2 | Col3 |\n| Col1a | Col2a | Col3a |\n| Col1b | Col3b |\n| Col1c |", "<table>\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<tbody>\n<tr>\n<td>Col1\nCol1a</td>\n<td>Col2\nCol2a</td>\n<td>Col3\nCol3a</td>\n</tr>\n<tr>\n<td colspan=\"2\">Col1b</td>\n<td>Col3b</td>\n</tr>\n<tr>\n<td colspan=\"3\">Col1c</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+---------+\n| Col1 | Col2 | Col3 |\n| Col1a | Col2a | Col3a |\n| Col1b | Col3b |\n| Col1c |", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>Col1\nCol1a</td>\n<td>Col2\nCol2a</td>\n<td>Col3\nCol3a</td>\n</tr>\n<tr>\n<td colspan=\"2\">Col1b</td>\n<td>Col3b</td>\n</tr>\n<tr>\n<td colspan=\"3\">Col1c</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
}
// A row header is separated using `+========+` instead of `+---------+`:
@@ -152,8 +152,8 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:50%">
// <col style="width:50%">
// <col style="width:50%" />
// <col style="width:50%" />
// <thead>
// <tr>
// <th>This is</th>
@@ -163,7 +163,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 4\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+\n| This is | a table |\n+=========+=========+", "<table>\n<col style=\"width:50%\">\n<col style=\"width:50%\">\n<thead>\n<tr>\n<th>This is</th>\n<th>a table</th>\n</tr>\n</thead>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+\n| This is | a table |\n+=========+=========+", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<thead>\n<tr>\n<th>This is</th>\n<th>a table</th>\n</tr>\n</thead>\n</table>", "gridtables|advanced");
}
// The last column separator `|` may be omitted:
@@ -179,8 +179,8 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:50%">
// <col style="width:50%">
// <col style="width:50%" />
// <col style="width:50%" />
// <tbody>
// <tr>
// <td>This is</td>
@@ -190,7 +190,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 5\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+\n| This is | a table with a longer text in the second column", "<table>\n<col style=\"width:50%\">\n<col style=\"width:50%\">\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table with a longer text in the second column</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+\n| This is | a table with a longer text in the second column", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table with a longer text in the second column</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
}
// The respective width of the columns are calculated from the ratio between the total size of the first table row without counting the `+`: `+----+--------+----+` would be divided between:
@@ -215,9 +215,9 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:25%">
// <col style="width:50%">
// <col style="width:25%">
// <col style="width:25%" />
// <col style="width:50%" />
// <col style="width:25%" />
// <tbody>
// <tr>
// <td>A</td>
@@ -228,7 +228,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 6\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+----+--------+----+\n| A | B C D | E |\n+----+--------+----+", "<table>\n<col style=\"width:25%\">\n<col style=\"width:50%\">\n<col style=\"width:25%\">\n<tbody>\n<tr>\n<td>A</td>\n<td>B C D</td>\n<td>E</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+----+--------+----+\n| A | B C D | E |\n+----+--------+----+", "<table>\n<col style=\"width:25%\" />\n<col style=\"width:50%\" />\n<col style=\"width:25%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td>B C D</td>\n<td>E</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
}
// Alignment might be specified on the first row using the character `:`:
@@ -245,9 +245,9 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <tbody>
// <tr>
// <td>A</td>
@@ -258,7 +258,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 7\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+-----+:---:+-----+\n| A | B | C |\n+-----+-----+-----+", "<table>\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<tbody>\n<tr>\n<td>A</td>\n<td style=\"text-align: center;\">B</td>\n<td>C</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+-----+:---:+-----+\n| A | B | C |\n+-----+-----+-----+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td style=\"text-align: center;\">B</td>\n<td>C</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
}
// A grid table may have cells spanning both columns and rows:
@@ -279,9 +279,9 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <tbody>
// <tr>
// <td colspan="2">AAAAA</td>
@@ -302,7 +302,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 8\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+---+---+ B +\n| D | E | B |\n+ D +---+---+\n| D | CCCCC |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<tbody>\n<tr>\n<td colspan=\"2\">AAAAA</td>\n<td rowspan=\"2\">B\nB\nB</td>\n</tr>\n<tr>\n<td rowspan=\"2\">D\nD\nD</td>\n<td>E</td>\n</tr>\n<tr>\n<td colspan=\"2\">CCCCC</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+---+---+ B +\n| D | E | B |\n+ D +---+---+\n| D | CCCCC |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\">AAAAA</td>\n<td rowspan=\"2\">B\nB\nB</td>\n</tr>\n<tr>\n<td rowspan=\"2\">D\nD\nD</td>\n<td>E</td>\n</tr>\n<tr>\n<td colspan=\"2\">CCCCC</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
}
// A grid table may have cells with both colspan and rowspan:
@@ -323,9 +323,9 @@ namespace Markdig.Tests.Specs.GridTables
//
// Should be rendered as:
// <table>
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%">
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <col style="width:33.33%" />
// <tbody>
// <tr>
// <td colspan="2" rowspan="2">AAAAA
@@ -345,7 +345,7 @@ namespace Markdig.Tests.Specs.GridTables
// </table>
Console.WriteLine("Example 9\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ AAAAA +---+\n| AAAAA | C |\n+---+---+---+\n| D | E | F |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<col style=\"width:33.33%\">\n<tbody>\n<tr>\n<td colspan=\"2\" rowspan=\"2\">AAAAA\nAAAAA\nAAAAA</td>\n<td>B</td>\n</tr>\n<tr>\n<td>C</td>\n</tr>\n<tr>\n<td>D</td>\n<td>E</td>\n<td>F</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ AAAAA +---+\n| AAAAA | C |\n+---+---+---+\n| D | E | F |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\" rowspan=\"2\">AAAAA\nAAAAA\nAAAAA</td>\n<td>B</td>\n</tr>\n<tr>\n<td>C</td>\n</tr>\n<tr>\n<td>D</td>\n<td>E</td>\n<td>F</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
}
// A grid table may not have irregularly shaped cells:

View File

@@ -42,8 +42,8 @@ The following is a valid row separator
| This is | a table |
.
<table>
<col style="width:50%">
<col style="width:50%">
<col style="width:50%" />
<col style="width:50%" />
<tbody>
<tr>
<td>This is</td>
@@ -74,9 +74,9 @@ A regular row can continue a previous regular row when column separator `|` are
| Col1c |
.
<table>
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%" />
<col style="width:33.33%" />
<col style="width:33.33%" />
<tbody>
<tr>
<td>Col1
@@ -105,8 +105,8 @@ A row header is separated using `+========+` instead of `+---------+`:
+=========+=========+
.
<table>
<col style="width:50%">
<col style="width:50%">
<col style="width:50%" />
<col style="width:50%" />
<thead>
<tr>
<th>This is</th>
@@ -123,8 +123,8 @@ The last column separator `|` may be omitted:
| This is | a table with a longer text in the second column
.
<table>
<col style="width:50%">
<col style="width:50%">
<col style="width:50%" />
<col style="width:50%" />
<tbody>
<tr>
<td>This is</td>
@@ -150,9 +150,9 @@ So the width would be 4/16 = 25%, 8/16 = 50%, 4/16 = 25%
+----+--------+----+
.
<table>
<col style="width:25%">
<col style="width:50%">
<col style="width:25%">
<col style="width:25%" />
<col style="width:50%" />
<col style="width:25%" />
<tbody>
<tr>
<td>A</td>
@@ -172,9 +172,9 @@ Alignment might be specified on the first row using the character `:`:
+-----+-----+-----+
.
<table>
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%" />
<col style="width:33.33%" />
<col style="width:33.33%" />
<tbody>
<tr>
<td>A</td>
@@ -197,9 +197,9 @@ Alignment might be specified on the first row using the character `:`:
+---+---+---+
.
<table>
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%" />
<col style="width:33.33%" />
<col style="width:33.33%" />
<tbody>
<tr>
<td colspan="2">AAAAA</td>
@@ -232,9 +232,9 @@ A grid table may have cells with both colspan and rowspan:
+---+---+---+
.
<table>
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%">
<col style="width:33.33%" />
<col style="width:33.33%" />
<col style="width:33.33%" />
<tbody>
<tr>
<td colspan="2" rowspan="2">AAAAA

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Hardline Breaks

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:22:45
// Generated: 2019-04-15 05:30:00
// --------------------------------
// Jira Links
@@ -14,7 +14,7 @@ namespace Markdig.Tests.Specs.JiraLinks
{
// ## Jira Links
//
// The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
// The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
//
// ```
// var pipeline = new MarkdownPipelineBuilder()
@@ -24,10 +24,10 @@ namespace Markdig.Tests.Specs.JiraLinks
//
// The rules for detecting a link are:
//
// - The project key must be composed of onre or more capitalised ASCII letter `[A-Z]+`
// - A single hypen `-` must separate the project key and issue number.
// - The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
// - A single hyphen `-` must separate the project key and issue number.
// - The issue number is composed of 1 or more digits `[0, 9]+`
// - The reference must be preceeded by either `(` or whitespace or EOF.
// - The reference must be preceded by either `(` or whitespace or EOF.
// - The reference must be followed by either `)` or whitespace or EOF.
//
// The following are valid examples:

View File

@@ -1,6 +1,6 @@
## Jira Links
The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
```
var pipeline = new MarkdownPipelineBuilder()
@@ -10,10 +10,10 @@ var pipeline = new MarkdownPipelineBuilder()
The rules for detecting a link are:
- The project key must be composed of onre or more capitalised ASCII letter `[A-Z]+`
- A single hypen `-` must separate the project key and issue number.
- The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
- A single hyphen `-` must separate the project key and issue number.
- The issue number is composed of 1 or more digits `[0, 9]+`
- The reference must be preceeded by either `(` or whitespace or EOF.
- The reference must be preceded by either `(` or whitespace or EOF.
- The reference must be followed by either `)` or whitespace or EOF.
The following are valid examples:

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// List Extras

View File

@@ -1,4 +1,4 @@
// Generated: 2/22/2019 8:27:26 PM
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Math

View File

@@ -1,50 +0,0 @@
// Generated: 21. 01. 2019 14:26:34
// --------------------------------
// Media
// --------------------------------
using System;
using NUnit.Framework;
namespace Markdig.Tests.Specs.Media
{
[TestFixture]
public class TestExtensionsMediaLinks
{
// # Extensions
//
// Adds support for media links:
//
// ## Media links
//
// Allows to embed audio/video links to popular website:
[Test]
public void ExtensionsMediaLinks_Example001()
{
// Example 1
// Section: Extensions / Media links
//
// The following Markdown:
// ![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)
//
// ![Video2](https://vimeo.com/8607834)
//
// ![Video3](https://sample.com/video.mp4)
//
// ![Audio4](https://music.yandex.ru/album/411845/track/4402274)
//
// ![Video5](https://ok.ru/video/26870090463)
//
// Should be rendered as:
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
// <p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
// <p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" width="500" height="281" frameborder="0"></iframe></p>
// <p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
Console.WriteLine("Example 1\nSection Extensions / Media links\n");
TestParser.TestSpec("![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![Video2](https://vimeo.com/8607834)\n\n![Video3](https://sample.com/video.mp4)\n\n![Audio4](https://music.yandex.ru/album/411845/track/4402274)\n\n![Video5](https://ok.ru/video/26870090463)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks");
}
}
}

View File

@@ -0,0 +1,65 @@
// Generated: 2019-05-15 02:46:20
// --------------------------------
// Media
// --------------------------------
using System;
using NUnit.Framework;
namespace Markdig.Tests.Specs.Media
{
[TestFixture]
public class TestExtensionsMediaLinks
{
// # Extensions
//
// Adds support for media links:
//
// ## Media links
//
// Allows to embed audio/video links to popular website:
[Test]
public void ExtensionsMediaLinks_Example001()
{
// Example 1
// Section: Extensions / Media links
//
// The following Markdown:
// ![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)
//
// ![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)
//
// ![youtu.be](https://youtu.be/mswPy5bt3TQ)
//
// ![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)
//
// ![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)
//
// ![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)
//
// ![vimeo](https://vimeo.com/8607834)
//
// ![static mp4](https://sample.com/video.mp4)
//
// ![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)
//
// ![ok.ru](https://ok.ru/video/26870090463)
//
// Should be rendered as:
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" class="vimeo" frameborder="0" allowfullscreen=""></iframe></p>
// <p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
// <p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" width="500" height="281" class="yandex" frameborder="0"></iframe></p>
// <p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" class="odnoklassniki" frameborder="0" allowfullscreen=""></iframe></p>
Console.WriteLine("Example 1\nSection Extensions / Media links\n");
TestParser.TestSpec("![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)\n\n![youtu.be](https://youtu.be/mswPy5bt3TQ)\n\n![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)\n\n![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)\n \n![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)\n\n![vimeo](https://vimeo.com/8607834)\n\n![static mp4](https://sample.com/video.mp4)\n\n![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)\n\n![ok.ru](https://ok.ru/video/26870090463)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" width=\"500\" height=\"281\" class=\"vimeo\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" width=\"500\" height=\"281\" class=\"yandex\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" class=\"odnoklassniki\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks");
}
}
}

View File

@@ -7,19 +7,34 @@ Adds support for media links:
Allows to embed audio/video links to popular website:
```````````````````````````````` example
![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)
![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)
![Video2](https://vimeo.com/8607834)
![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)
![Video3](https://sample.com/video.mp4)
![youtu.be](https://youtu.be/mswPy5bt3TQ)
![Audio4](https://music.yandex.ru/album/411845/track/4402274)
![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)
![Video5](https://ok.ru/video/26870090463)
![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)
![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)
![vimeo](https://vimeo.com/8607834)
![static mp4](https://sample.com/video.mp4)
![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)
![ok.ru](https://ok.ru/video/26870090463)
.
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" class="vimeo" frameborder="0" allowfullscreen=""></iframe></p>
<p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
<p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" width="500" height="281" frameborder="0"></iframe></p>
<p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" width="500" height="281" class="yandex" frameborder="0"></iframe></p>
<p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" class="odnoklassniki" frameborder="0" allowfullscreen=""></iframe></p>
````````````````````````````````

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// No Html

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-15 05:54:35
// --------------------------------
// Pipe Tables
@@ -21,7 +21,7 @@ namespace Markdig.Tests.Specs.PipeTables
// A pipe table is detected when:
//
// **Rule #1**
// - Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backstick \`) or a HTML inline.
// - Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
// - The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
// - starting by optional spaces
// - followed by an optional `:` to specify left align
@@ -347,7 +347,7 @@ namespace Markdig.Tests.Specs.PipeTables
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
}
// Or may be ommitted on one side:
// Or may be omitted on one side:
[Test]
public void ExtensionsPipeTable_Example011()
{
@@ -629,7 +629,7 @@ namespace Markdig.Tests.Specs.PipeTables
// **Rule #7**
//
// A backstick/code delimiter has a higher precedence than a column delimiter `|`:
// A backtick/code delimiter has a higher precedence than a column delimiter `|`:
[Test]
public void ExtensionsPipeTable_Example019()
{

View File

@@ -7,7 +7,7 @@ This section describes the different extensions supported:
A pipe table is detected when:
**Rule #1**
- Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backstick \`) or a HTML inline.
- Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
- The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
- starting by optional spaces
- followed by an optional `:` to specify left align
@@ -243,7 +243,7 @@ A pipe may be present at both the beginning/ending of each line:
</table>
````````````````````````````````
Or may be ommitted on one side:
Or may be omitted on one side:
```````````````````````````````` example
a|b|
@@ -454,7 +454,7 @@ A column delimiter has a higher priority than emphasis delimiter
**Rule #7**
A backstick/code delimiter has a higher precedence than a column delimiter `|`:
A backtick/code delimiter has a higher precedence than a column delimiter `|`:
```````````````````````````````` example
a | b `

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-08-01 12:33:23
// --------------------------------
// Smarty Pants
@@ -140,13 +140,13 @@ namespace Markdig.Tests.Specs.SmartyPants
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
// This is a 'text <<with' a another text>>
// This is 'a "text 'with" a another text'
//
// Should be rendered as:
// <p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>
// <p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>
Console.WriteLine("Example 8\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a 'text <<with' a another text>>", "<p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is 'a \"text 'with\" a another text'", "<p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>", "pipetables+smartypants|advanced+smartypants");
}
[Test]
@@ -156,20 +156,36 @@ namespace Markdig.Tests.Specs.SmartyPants
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
// This is a 'text <<with' a another text>>
//
// Should be rendered as:
// <p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>
Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a 'text <<with' a another text>>", "<p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>", "pipetables+smartypants|advanced+smartypants");
}
[Test]
public void ExtensionsSmartyPantsQuotes_Example010()
{
// Example 10
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
// This is a <<text 'with>> a another text'
//
// Should be rendered as:
// <p>This is a &laquo;text 'with&raquo; a another text'</p>
Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n");
Console.WriteLine("Example 10\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a <<text 'with>> a another text'", "<p>This is a &laquo;text 'with&raquo; a another text'</p>", "pipetables+smartypants|advanced+smartypants");
}
// Quotes requires to have the same rules than emphasis `_` regarding left/right frankling rules:
[Test]
public void ExtensionsSmartyPantsQuotes_Example010()
public void ExtensionsSmartyPantsQuotes_Example011()
{
// Example 10
// Example 11
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
@@ -178,24 +194,8 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>It's not quotes'</p>
Console.WriteLine("Example 10\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("It's not quotes'", "<p>It's not quotes'</p>", "pipetables+smartypants|advanced+smartypants");
}
[Test]
public void ExtensionsSmartyPantsQuotes_Example011()
{
// Example 11
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
// They are ' not matching quotes '
//
// Should be rendered as:
// <p>They are ' not matching quotes '</p>
Console.WriteLine("Example 11\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("They are ' not matching quotes '", "<p>They are ' not matching quotes '</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("It's not quotes'", "<p>It's not quotes'</p>", "pipetables+smartypants|advanced+smartypants");
}
[Test]
@@ -205,20 +205,36 @@ namespace Markdig.Tests.Specs.SmartyPants
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
// They are ' not matching quotes '
//
// Should be rendered as:
// <p>They are ' not matching quotes '</p>
Console.WriteLine("Example 12\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("They are ' not matching quotes '", "<p>They are ' not matching quotes '</p>", "pipetables+smartypants|advanced+smartypants");
}
[Test]
public void ExtensionsSmartyPantsQuotes_Example013()
{
// Example 13
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
// They are' not matching 'quotes
//
// Should be rendered as:
// <p>They are' not matching 'quotes</p>
Console.WriteLine("Example 12\nSection Extensions / SmartyPants Quotes\n");
Console.WriteLine("Example 13\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("They are' not matching 'quotes", "<p>They are' not matching 'quotes</p>", "pipetables+smartypants|advanced+smartypants");
}
// An emphasis starting inside left/right quotes will span over the right quote:
[Test]
public void ExtensionsSmartyPantsQuotes_Example013()
public void ExtensionsSmartyPantsQuotes_Example014()
{
// Example 13
// Example 14
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
@@ -227,9 +243,26 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is &ldquo;a <em>text&rdquo; with an emphasis</em></p>
Console.WriteLine("Example 13\nSection Extensions / SmartyPants Quotes\n");
Console.WriteLine("Example 14\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is \"a *text\" with an emphasis*", "<p>This is &ldquo;a <em>text&rdquo; with an emphasis</em></p>", "pipetables+smartypants|advanced+smartypants");
}
// Multiple sets of quotes can be used
[Test]
public void ExtensionsSmartyPantsQuotes_Example015()
{
// Example 15
// Section: Extensions / SmartyPants Quotes
//
// The following Markdown:
// "aaa" "bbb" "ccc" "ddd"
//
// Should be rendered as:
// <p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>
Console.WriteLine("Example 15\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("\"aaa\" \"bbb\" \"ccc\" \"ddd\"", "<p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>", "pipetables+smartypants|advanced+smartypants");
}
}
[TestFixture]
@@ -237,9 +270,9 @@ namespace Markdig.Tests.Specs.SmartyPants
{
// ## SmartyPants Separators
[Test]
public void ExtensionsSmartyPantsSeparators_Example014()
public void ExtensionsSmartyPantsSeparators_Example016()
{
// Example 14
// Example 16
// Section: Extensions / SmartyPants Separators
//
// The following Markdown:
@@ -248,14 +281,14 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &ndash; text</p>
Console.WriteLine("Example 14\nSection Extensions / SmartyPants Separators\n");
Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a -- text", "<p>This is a &ndash; text</p>", "pipetables+smartypants|advanced+smartypants");
}
[Test]
public void ExtensionsSmartyPantsSeparators_Example015()
public void ExtensionsSmartyPantsSeparators_Example017()
{
// Example 15
// Example 17
// Section: Extensions / SmartyPants Separators
//
// The following Markdown:
@@ -264,14 +297,14 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &mdash; text</p>
Console.WriteLine("Example 15\nSection Extensions / SmartyPants Separators\n");
Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a --- text", "<p>This is a &mdash; text</p>", "pipetables+smartypants|advanced+smartypants");
}
[Test]
public void ExtensionsSmartyPantsSeparators_Example016()
public void ExtensionsSmartyPantsSeparators_Example018()
{
// Example 16
// Example 18
// Section: Extensions / SmartyPants Separators
//
// The following Markdown:
@@ -280,15 +313,15 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a en ellipsis&hellip;</p>
Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n");
Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a en ellipsis...", "<p>This is a en ellipsis&hellip;</p>", "pipetables+smartypants|advanced+smartypants");
}
// Check that a smartypants are not breaking pipetable parsing:
[Test]
public void ExtensionsSmartyPantsSeparators_Example017()
public void ExtensionsSmartyPantsSeparators_Example019()
{
// Example 17
// Example 19
// Section: Extensions / SmartyPants Separators
//
// The following Markdown:
@@ -312,15 +345,15 @@ namespace Markdig.Tests.Specs.SmartyPants
// </tbody>
// </table>
Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n");
Console.WriteLine("Example 19\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("a | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables+smartypants|advanced+smartypants");
}
// Check quotes and dash:
[Test]
public void ExtensionsSmartyPantsSeparators_Example018()
public void ExtensionsSmartyPantsSeparators_Example020()
{
// Example 18
// Example 20
// Section: Extensions / SmartyPants Separators
//
// The following Markdown:
@@ -329,7 +362,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>A &ldquo;quote&rdquo; with a &mdash;</p>
Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n");
Console.WriteLine("Example 20\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("A \"quote\" with a ---", "<p>A &ldquo;quote&rdquo; with a &mdash;</p>", "pipetables+smartypants|advanced+smartypants");
}
}

View File

@@ -52,6 +52,12 @@ This is a "text 'with" a another text'
<p>This is a &ldquo;text 'with&rdquo; a another text'</p>
````````````````````````````````
```````````````````````````````` example
This is 'a "text 'with" a another text'
.
<p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>
````````````````````````````````
```````````````````````````````` example
This is a 'text <<with' a another text>>
.
@@ -91,6 +97,14 @@ This is "a *text" with an emphasis*
<p>This is &ldquo;a <em>text&rdquo; with an emphasis</em></p>
````````````````````````````````
Multiple sets of quotes can be used
```````````````````````````````` example
"aaa" "bbb" "ccc" "ddd"
.
<p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>
````````````````````````````````
## SmartyPants Separators
```````````````````````````````` example

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Task Lists

View File

@@ -1,4 +1,4 @@
// Generated: 21. 01. 2019 14:26:34
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Yaml

View File

@@ -0,0 +1,70 @@
using System;
using Markdig.Syntax;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestContainerBlocks
{
private class MockContainerBlock : ContainerBlock
{
public MockContainerBlock()
: base(null)
{
}
}
[Test]
public void CanBeCleared()
{
ContainerBlock container = new MockContainerBlock();
Assert.AreEqual(0, container.Count);
Assert.Null(container.LastChild);
var paragraph = new ParagraphBlock();
Assert.Null(paragraph.Parent);
container.Add(paragraph);
Assert.AreEqual(1, container.Count);
Assert.AreSame(container, paragraph.Parent);
Assert.AreSame(paragraph, container.LastChild);
container.Clear();
Assert.AreEqual(0, container.Count);
Assert.Null(container.LastChild);
Assert.Null(paragraph.Parent);
}
[Test]
public void CanBeInsertedInto()
{
ContainerBlock container = new MockContainerBlock();
var one = new ParagraphBlock();
container.Insert(0, one);
Assert.AreEqual(1, container.Count);
Assert.AreSame(container[0], one);
var two = new ParagraphBlock();
container.Insert(1, two);
Assert.AreEqual(2, container.Count);
Assert.AreSame(container[0], one);
Assert.AreSame(container[1], two);
var three = new ParagraphBlock();
container.Insert(0, three);
Assert.AreEqual(3, container.Count);
Assert.AreSame(container[0], three);
Assert.AreSame(container[1], one);
Assert.AreSame(container[2], two);
Assert.Throws<ArgumentNullException>(() => container.Insert(0, null));
Assert.Throws<ArgumentOutOfRangeException>(() => container.Insert(4, new ParagraphBlock()));
Assert.Throws<ArgumentOutOfRangeException>(() => container.Insert(-1, new ParagraphBlock()));
Assert.Throws<ArgumentException>(() => container.Insert(0, one)); // one already has a parent
}
}
}

View File

@@ -0,0 +1,129 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Markdig.Extensions.Emoji;
using NUnit.Framework;
namespace Markdig.Tests
{
[TestFixture]
public class TestCustomEmojis
{
[Test]
[TestCase(":smiley:", "<p>♥</p>\n")]
[TestCase(":confused:", "<p>:confused:</p>\n")] // default emoji does not work
[TestCase(":/", "<p>:/</p>\n")] // default smiley does not work
public void TestCustomEmoji(string input, string expected)
{
var emojiToUnicode = new Dictionary<string, string>();
var smileyToEmoji = new Dictionary<string, string>();
emojiToUnicode[":smiley:"] = "♥";
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
var pipeline = new MarkdownPipelineBuilder()
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
.Build();
var actual = Markdown.ToHtml(input, pipeline);
Assert.AreEqual(expected, actual);
}
[Test]
[TestCase(":testheart:", "<p>♥</p>\n")]
[TestCase("hello", "<p>♥</p>\n")]
[TestCase(":confused:", "<p>:confused:</p>\n")] // default emoji does not work
[TestCase(":/", "<p>:/</p>\n")] // default smiley does not work
public void TestCustomSmiley(string input, string expected)
{
var emojiToUnicode = new Dictionary<string, string>();
var smileyToEmoji = new Dictionary<string, string>();
emojiToUnicode[":testheart:"] = "♥";
smileyToEmoji["hello"] = ":testheart:";
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
var pipeline = new MarkdownPipelineBuilder()
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
.Build();
var actual = Markdown.ToHtml(input, pipeline);
Assert.AreEqual(expected, actual);
}
[Test]
[TestCase(":smiley:", "<p>♥</p>\n")]
[TestCase(":)", "<p>♥</p>\n")]
[TestCase(":confused:", "<p>😕</p>\n")] // default emoji still works
[TestCase(":/", "<p>😕</p>\n")] // default smiley still works
public void TestOverrideDefaultWithCustomEmoji(string input, string expected)
{
var emojiToUnicode = EmojiMapping.GetDefaultEmojiShortcodeToUnicode();
var smileyToEmoji = EmojiMapping.GetDefaultSmileyToEmojiShortcode();
emojiToUnicode[":smiley:"] = "♥";
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
var pipeline = new MarkdownPipelineBuilder()
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
.Build();
var actual = Markdown.ToHtml(input, pipeline);
Assert.AreEqual(expected, actual);
}
[Test]
[TestCase(":testheart:", "<p>♥</p>\n")]
[TestCase("hello", "<p>♥</p>\n")]
[TestCase(":confused:", "<p>😕</p>\n")] // default emoji still works
[TestCase(":/", "<p>😕</p>\n")] // default smiley still works
public void TestOverrideDefaultWithCustomSmiley(string input, string expected)
{
var emojiToUnicode = EmojiMapping.GetDefaultEmojiShortcodeToUnicode();
var smileyToEmoji = EmojiMapping.GetDefaultSmileyToEmojiShortcode();
emojiToUnicode[":testheart:"] = "♥";
smileyToEmoji["hello"] = ":testheart:";
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
var pipeline = new MarkdownPipelineBuilder()
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
.Build();
var actual = Markdown.ToHtml(input, pipeline);
Assert.AreEqual(expected, actual);
}
[Test]
public void TestCustomEmojiValidation()
{
var emojiToUnicode = new Dictionary<string, string>();
var smileyToEmoji = new Dictionary<string, string>();
Assert.Throws<ArgumentNullException>(() => new EmojiMapping(null, smileyToEmoji));
Assert.Throws<ArgumentNullException>(() => new EmojiMapping(emojiToUnicode, null));
emojiToUnicode.Add("null-value", null);
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
emojiToUnicode.Clear();
smileyToEmoji.Add("null-value", null);
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
smileyToEmoji.Clear();
smileyToEmoji.Add("foo", "something-that-does-not-exist-in-emojiToUnicode");
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
smileyToEmoji.Clear();
emojiToUnicode.Add("a", "aaa");
emojiToUnicode.Add("b", "bbb");
emojiToUnicode.Add("c", "ccc");
smileyToEmoji.Add("a", "c"); // "a" already exists in emojiToUnicode
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
}
}
}

View File

@@ -1,6 +1,7 @@
using NUnit.Framework;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using System;
using System.Linq;
using System.Collections.Generic;
@@ -12,24 +13,91 @@ namespace Markdig.Tests
[Test]
public void TestSchemas()
{
foreach (var markdown in TestParser.SpecsMarkdown)
foreach (var syntaxTree in TestParser.SpecsSyntaxTrees)
{
AssertSameDescendantsOrder(markdown);
AssertIEnumerablesAreEqual(
Descendants_Legacy(syntaxTree),
syntaxTree.Descendants());
AssertIEnumerablesAreEqual(
syntaxTree.Descendants().OfType<ParagraphBlock>(),
syntaxTree.Descendants<ParagraphBlock>());
AssertIEnumerablesAreEqual(
syntaxTree.Descendants().OfType<ParagraphBlock>(),
(syntaxTree as ContainerBlock).Descendants<ParagraphBlock>());
AssertIEnumerablesAreEqual(
syntaxTree.Descendants().OfType<LiteralInline>(),
syntaxTree.Descendants<LiteralInline>());
foreach (LiteralInline literalInline in syntaxTree.Descendants<LiteralInline>())
{
Assert.AreSame(Array.Empty<ListBlock>(), literalInline.Descendants<ListBlock>());
Assert.AreSame(Array.Empty<ParagraphBlock>(), literalInline.Descendants<ParagraphBlock>());
Assert.AreSame(Array.Empty<ContainerInline>(), literalInline.Descendants<ContainerInline>());
}
foreach (ContainerInline containerInline in syntaxTree.Descendants<ContainerInline>())
{
AssertIEnumerablesAreEqual(
containerInline.FindDescendants<LiteralInline>(),
containerInline.Descendants<LiteralInline>());
AssertIEnumerablesAreEqual(
containerInline.FindDescendants<LiteralInline>(),
(containerInline as MarkdownObject).Descendants<LiteralInline>());
if (containerInline.FirstChild is null)
{
Assert.AreSame(Array.Empty<LiteralInline>(), containerInline.Descendants<LiteralInline>());
Assert.AreSame(Array.Empty<LiteralInline>(), containerInline.FindDescendants<LiteralInline>());
Assert.AreSame(Array.Empty<LiteralInline>(), (containerInline as MarkdownObject).Descendants<LiteralInline>());
}
Assert.AreSame(Array.Empty<ListBlock>(), containerInline.Descendants<ListBlock>());
Assert.AreSame(Array.Empty<ParagraphBlock>(), containerInline.Descendants<ParagraphBlock>());
}
foreach (ParagraphBlock paragraphBlock in syntaxTree.Descendants<ParagraphBlock>())
{
AssertIEnumerablesAreEqual(
(paragraphBlock as MarkdownObject).Descendants<LiteralInline>(),
paragraphBlock.Descendants<LiteralInline>());
Assert.AreSame(Array.Empty<ParagraphBlock>(), paragraphBlock.Descendants<ParagraphBlock>());
}
foreach (ContainerBlock containerBlock in syntaxTree.Descendants<ContainerBlock>())
{
AssertIEnumerablesAreEqual(
containerBlock.Descendants<LiteralInline>(),
(containerBlock as MarkdownObject).Descendants<LiteralInline>());
AssertIEnumerablesAreEqual(
containerBlock.Descendants<ParagraphBlock>(),
(containerBlock as MarkdownObject).Descendants<ParagraphBlock>());
if (containerBlock.Count == 0)
{
Assert.AreSame(Array.Empty<LiteralInline>(), containerBlock.Descendants<LiteralInline>());
Assert.AreSame(Array.Empty<LiteralInline>(), (containerBlock as Block).Descendants<LiteralInline>());
Assert.AreSame(Array.Empty<LiteralInline>(), (containerBlock as MarkdownObject).Descendants<LiteralInline>());
}
}
}
}
private void AssertSameDescendantsOrder(string markdown)
private static void AssertIEnumerablesAreEqual<T>(IEnumerable<T> first, IEnumerable<T> second)
{
var syntaxTree = Markdown.Parse(markdown, new MarkdownPipelineBuilder().UseAdvancedExtensions().Build());
var firstList = new List<T>(first);
var secondList = new List<T>(second);
var descendants_legacy = Descendants_Legacy(syntaxTree).ToList();
var descendants_new = syntaxTree.Descendants().ToList();
Assert.AreEqual(firstList.Count, secondList.Count);
Assert.AreEqual(descendants_legacy.Count, descendants_new.Count);
for (int i = 0; i < descendants_legacy.Count; i++)
for (int i = 0; i < firstList.Count; i++)
{
Assert.AreSame(descendants_legacy[i], descendants_new[i]);
Assert.AreSame(firstList[i], secondList[i]);
}
}

View File

@@ -0,0 +1,48 @@
using NUnit.Framework;
namespace Markdig.Tests
{
[TestFixture]
public class TestExceptionNotThrown
{
[Test]
public void DoesNotThrowIndexOutOfRangeException1()
{
Assert.DoesNotThrow(() =>
{
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
Markdown.ToHtml("+-\n|\n+", pipeline);
});
}
[Test]
public void DoesNotThrowIndexOutOfRangeException2()
{
Assert.DoesNotThrow(() =>
{
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
Markdown.ToHtml("+--\n|\n+0", pipeline);
});
}
[Test]
public void DoesNotThrowIndexOutOfRangeException3()
{
Assert.DoesNotThrow(() =>
{
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
Markdown.ToHtml("+-\n|\n+\n0", pipeline);
});
}
[Test]
public void DoesNotThrowIndexOutOfRangeException4()
{
Assert.DoesNotThrow(() =>
{
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
Markdown.ToHtml("+-\n|\n+0", pipeline);
});
}
}
}

View File

@@ -1,9 +1,8 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using NUnit.Framework;
using Markdig.Helpers;
using Markdig.Syntax;
namespace Markdig.Tests
{
@@ -15,8 +14,7 @@ namespace Markdig.Tests
{
var inputTag = "<a>";
var text = new StringSlice(inputTag);
string outputTag;
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
Assert.AreEqual(inputTag, outputTag);
}
@@ -25,8 +23,7 @@ namespace Markdig.Tests
{
var inputTag = "<a href='http://google.com'>";
var text = new StringSlice(inputTag);
string outputTag;
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
Assert.AreEqual(inputTag, outputTag);
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
@@ -18,60 +18,60 @@ namespace Markdig.Tests
public void TestEmpty()
{
var lineReader = new LineReader("");
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestLinesOnlyLf()
{
var lineReader = new LineReader("\n\n\n");
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.AreEqual(1, lineReader.SourcePosition);
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.AreEqual(2, lineReader.SourcePosition);
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestLinesOnlyCr()
{
var lineReader = new LineReader("\r\r\r");
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.AreEqual(1, lineReader.SourcePosition);
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.AreEqual(2, lineReader.SourcePosition);
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestLinesOnlyCrLf()
{
var lineReader = new LineReader("\r\n\r\n\r\n");
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.AreEqual(2, lineReader.SourcePosition);
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.AreEqual(4, lineReader.SourcePosition);
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestNoEndOfLine()
{
var lineReader = new LineReader("123");
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.AreEqual("123", lineReader.ReadLine().ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestLf()
{
var lineReader = new LineReader("123\n");
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
Assert.AreEqual("123", lineReader.ReadLine().ToString());
Assert.AreEqual(4, lineReader.SourcePosition);
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
@@ -79,29 +79,29 @@ namespace Markdig.Tests
{
// When limited == true, we limit the internal buffer exactly after the first new line char '\n'
var lineReader = new LineReader("123\n456");
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
Assert.AreEqual("123", lineReader.ReadLine().ToString());
Assert.AreEqual(4, lineReader.SourcePosition);
Assert.AreEqual("456", lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.AreEqual("456", lineReader.ReadLine().ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestCr()
{
var lineReader = new LineReader("123\r");
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
Assert.AreEqual("123", lineReader.ReadLine().ToString());
Assert.AreEqual(4, lineReader.SourcePosition);
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestCr2()
{
var lineReader = new LineReader("123\r456");
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
Assert.AreEqual("123", lineReader.ReadLine().ToString());
Assert.AreEqual(4, lineReader.SourcePosition);
Assert.AreEqual("456", lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.AreEqual("456", lineReader.ReadLine().ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
@@ -110,19 +110,19 @@ namespace Markdig.Tests
// When limited == true, we limit the internal buffer exactly after the first new line char '\r'
// and we check that we don't get a new line for `\n`
var lineReader = new LineReader("123\r\n");
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
Assert.AreEqual("123", lineReader.ReadLine().ToString());
Assert.AreEqual(5, lineReader.SourcePosition);
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine().Text);
}
[Test]
public void TestCrLf2()
{
var lineReader = new LineReader("123\r\n456");
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
Assert.AreEqual("123", lineReader.ReadLine().ToString());
Assert.AreEqual(5, lineReader.SourcePosition);
Assert.AreEqual("456", lineReader.ReadLine()?.ToString());
Assert.Null(lineReader.ReadLine()?.ToString());
Assert.AreEqual("456", lineReader.ReadLine().ToString());
Assert.Null(lineReader.ReadLine().Text);
}
}
}

View File

@@ -322,6 +322,16 @@ namespace Markdig.Tests
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, false));
}
[TestCase("Header identifiers in HTML", "header-identifiers-in-html")]
[TestCase("* Dogs*?--in *my* house?", "-dogs--in-my-house")]
[TestCase("[HTML], [S5], or [RTF]?", "html-s5-or-rtf")]
[TestCase("3. Applications", "3-applications")]
[TestCase("33", "33")]
public void TestUrilizeGfm(string input, string expectedResult)
{
Assert.AreEqual(expectedResult, LinkHelper.UrilizeAsGfm(input));
}
[TestCase("abc", "abc")]
[TestCase("a-c", "a-c")]
[TestCase("a c", "a-c")]
@@ -409,5 +419,11 @@ namespace Markdig.Tests
{
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, false));
}
[Test]
public void TestUnicodeInDomainNameOfLinkReferenceDefinition()
{
TestParser.TestSpec("[Foo]\n\n[Foo]: http://ünicode.com", "<p><a href=\"http://xn--nicode-2ya.com\">Foo</a></p>");
}
}
}

View File

@@ -0,0 +1,148 @@
using Markdig.Renderers;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using NUnit.Framework;
using System.IO;
namespace Markdig.Tests
{
public class TestMarkdigCoreApi
{
[Test]
public void TestToHtml()
{
string html = Markdown.ToHtml("This is a text with some *emphasis*");
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
html = Markdown.ToHtml("This is a text with a https://link.tld/");
Assert.AreNotEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
}
[Test]
public void TestToHtmlWithPipeline()
{
var pipeline = new MarkdownPipelineBuilder()
.Build();
string html = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
html = Markdown.ToHtml("This is a text with a https://link.tld/", pipeline);
Assert.AreNotEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.Build();
html = Markdown.ToHtml("This is a text with a https://link.tld/", pipeline);
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
}
[Test]
public void TestToHtmlWithWriter()
{
StringWriter writer = new StringWriter();
_ = Markdown.ToHtml("This is a text with some *emphasis*", writer);
string html = writer.ToString();
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
writer = new StringWriter();
var pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.Build();
_ = Markdown.ToHtml("This is a text with a https://link.tld/", writer, pipeline);
html = writer.ToString();
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
}
[Test]
public void TestConvert()
{
StringWriter writer = new StringWriter();
HtmlRenderer renderer = new HtmlRenderer(writer);
_ = Markdown.Convert("This is a text with some *emphasis*", renderer);
string html = writer.ToString();
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
writer = new StringWriter();
renderer = new HtmlRenderer(writer);
var pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.Build();
_ = Markdown.Convert("This is a text with a https://link.tld/", renderer, pipeline);
html = writer.ToString();
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
}
[Test]
public void TestParse()
{
const string markdown = "This is a text with some *emphasis*";
var pipeline = new MarkdownPipelineBuilder()
.UsePreciseSourceLocation()
.Build();
MarkdownDocument document = Markdown.Parse(markdown, pipeline);
Assert.AreEqual(1, document.LineCount);
Assert.AreEqual(markdown.Length, document.Span.Length);
Assert.AreEqual(1, document.LineStartIndexes.Count);
Assert.AreEqual(0, document.LineStartIndexes[0]);
Assert.AreEqual(1, document.Count);
ParagraphBlock paragraph = document[0] as ParagraphBlock;
Assert.NotNull(paragraph);
Assert.AreEqual(markdown.Length, paragraph.Span.Length);
LiteralInline literal = paragraph.Inline.FirstChild as LiteralInline;
Assert.NotNull(literal);
Assert.AreEqual("This is a text with some ", literal.ToString());
EmphasisInline emphasis = literal.NextSibling as EmphasisInline;
Assert.NotNull(emphasis);
Assert.AreEqual("*emphasis*".Length, emphasis.Span.Length);
LiteralInline emphasisLiteral = emphasis.FirstChild as LiteralInline;
Assert.NotNull(emphasisLiteral);
Assert.AreEqual("emphasis", emphasisLiteral.ToString());
Assert.Null(emphasisLiteral.NextSibling);
Assert.Null(emphasis.NextSibling);
}
[Test]
public void TestNormalize()
{
string normalized = Markdown.Normalize("Heading\n=======");
Assert.AreEqual("# Heading", normalized);
}
public void TestNormalizeWithWriter()
{
StringWriter writer = new StringWriter();
_ = Markdown.Normalize("Heading\n=======", writer);
string normalized = writer.ToString();
Assert.AreEqual("# Heading", normalized);
}
[Test]
public void TestToPlainText()
{
string plainText = Markdown.ToPlainText("*Hello*, [world](http://example.com)!");
Assert.AreEqual("Hello, world!\n", plainText);
}
[Test]
public void TestToPlainTextWithWriter()
{
StringWriter writer = new StringWriter();
_ = Markdown.ToPlainText("*Hello*, [world](http://example.com)!", writer);
string plainText = writer.ToString();
Assert.AreEqual("Hello, world!\n", plainText);
}
}
}

View File

@@ -0,0 +1,87 @@
using Markdig.Extensions.MediaLinks;
using NUnit.Framework;
using System;
using System.Text.RegularExpressions;
namespace Markdig.Tests
{
[TestFixture]
public class TestMediaLinks
{
private MarkdownPipeline GetPipeline(MediaOptions options = null)
{
return new MarkdownPipelineBuilder()
.UseMediaLinks(options)
.Build();
}
[Test]
[TestCase("![static mp4](https://sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n")]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)", "<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" width=\"500\" height=\"281\" class=\"yandex\" frameborder=\"0\"></iframe></p>\n")]
[TestCase("![vimeo](https://vimeo.com/8607834)", "<p><iframe src=\"https://player.vimeo.com/video/8607834\" width=\"500\" height=\"281\" class=\"vimeo\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![ok.ru](https://ok.ru/video/26870090463)", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" class=\"odnoklassniki\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![ok.ru](//ok.ru/video/26870090463)", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" class=\"odnoklassniki\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
public void TestBuiltInHosts(string markdown, string expected)
{
string html = Markdown.ToHtml(markdown, GetPipeline());
Assert.AreEqual(html, expected);
}
private class TestHostProvider : IHostProvider
{
public string Class { get; } = "regex";
public bool AllowFullScreen { get; }
public bool TryHandle(Uri mediaUri, bool isSchemaRelative, out string iframeUrl)
{
iframeUrl = null;
var uri = isSchemaRelative ? "//" + mediaUri.GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Scheme, UriFormat.UriEscaped) : mediaUri.ToString();
if (!matcher.IsMatch(uri))
return false;
iframeUrl = matcher.Replace(uri, replacement);
return true;
}
private Regex matcher;
private string replacement;
public TestHostProvider(string provider, string replace)
{
matcher = new Regex(provider);
replacement = replace;
}
}
[Test]
[TestCase("![p1](https://sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4\" width=\"500\" height=\"281\" class=\"regex\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1")]
[TestCase("![p1](//sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4\" width=\"500\" height=\"281\" class=\"regex\" frameborder=\"0\"></iframe></p>\n", @"^//sample.com/(.+)$", @"https://example.com/$1")]
[TestCase("![p1](https://sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4?token=aaabbb\" width=\"500\" height=\"281\" class=\"regex\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1?token=aaabbb")]
public void TestCustomHostProvider(string markdown, string expected, string provider, string replace)
{
string html = Markdown.ToHtml(markdown, GetPipeline(new MediaOptions
{
Hosts =
{
new TestHostProvider(provider, replace),
}
}));
Assert.AreEqual(html, expected);
}
[Test]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n", "")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "")]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\" class=\"k\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n", "k")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"k youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "k")]
public void TestCustomClass(string markdown, string expected, string klass)
{
string html = Markdown.ToHtml(markdown, GetPipeline(new MediaOptions
{
Class = klass,
}));
Assert.AreEqual(html, expected);
}
}
}

View File

@@ -271,8 +271,14 @@ asdf
[Test]
public void CodeInline()
{
AssertNormalizeNoTrim("This has a ` ` in it");
AssertNormalizeNoTrim("This has a `HelloWorld()` in it");
AssertNormalizeNoTrim(@"This has a ``Hello`World()`` in it");
AssertNormalizeNoTrim(@"This has a ``` Hello`World() ``` in it", @"This has a ``Hello`World()`` in it");
AssertNormalizeNoTrim(@"This has a ``Hello`World()` `` in it");
AssertNormalizeNoTrim(@"This has a ```` ``Hello```World()` ```` in it");
AssertNormalizeNoTrim(@"This has a `` `Hello`World()`` in it");
AssertNormalizeNoTrim(@"This has a ``` ``Hello`World()` ``` in it");
}
[Test]
@@ -409,8 +415,6 @@ This is a last line";
AssertNormalizeNoTrim("[ ] This is not a task list");
}
[Test]
public void JiraLinks()
{
@@ -453,16 +457,24 @@ This is a last line";
Assert.AreEqual(expected, actual);
}
public void AssertNormalizeNoTrim(string input, string expected = null, NormalizeOptions options = null)
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null)
{
foreach (var pipeline in TestParser.GetPipeline(extensions))
{
AssertNormalize(inputText, expectedOutputText, trim: false, pipeline: pipeline.Value);
}
}
public static void AssertNormalizeNoTrim(string input, string expected = null, NormalizeOptions options = null)
=> AssertNormalize(input, expected, false, options);
public void AssertNormalize(string input, string expected = null, bool trim = true, NormalizeOptions options = null)
public static void AssertNormalize(string input, string expected = null, bool trim = true, NormalizeOptions options = null, MarkdownPipeline pipeline = null)
{
expected = expected ?? input;
input = NormText(input, trim);
expected = NormText(expected, trim);
var pipeline = new MarkdownPipelineBuilder()
pipeline = pipeline ?? new MarkdownPipelineBuilder()
.UseAutoLinks()
.UseJiraLinks(new Extensions.JiraLinks.JiraLinkOptions("https://jira.example.com"))
.UseTaskLists()
@@ -471,16 +483,7 @@ This is a last line";
var result = Markdown.Normalize(input, options, pipeline: pipeline);
result = NormText(result, trim);
Console.WriteLine("```````````````````Source");
Console.WriteLine(TestParser.DisplaySpaceAndTabs(input));
Console.WriteLine("```````````````````Result");
Console.WriteLine(TestParser.DisplaySpaceAndTabs(result));
Console.WriteLine("```````````````````Expected");
Console.WriteLine(TestParser.DisplaySpaceAndTabs(expected));
Console.WriteLine("```````````````````");
Console.WriteLine();
TextAssert.AreEqual(expected, result);
TestParser.PrintAssertExpected(input, result, expected);
}
private static string NormText(string text, bool trim)

View File

@@ -8,66 +8,13 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Markdig.Extensions.JiraLinks;
using Markdig.Syntax;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestParser
{
[Test]
public void TestFixHang()
{
var input = File.ReadAllText(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "hang.md"));
var html = Markdown.ToHtml(input);
}
[Test]
public void TestInvalidHtmlEntity()
{
var input = "9&ddr;&*&ddr;&de<64><65>__";
TestSpec(input, "<p>9&amp;ddr;&amp;*&amp;ddr;&amp;de<64><65>__</p>");
}
[Test]
public void TestInvalidCharacterHandling()
{
var input = File.ReadAllText(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "ArgumentOutOfRangeException.md"));
var html = Markdown.ToHtml(input);
}
[Test]
public void TestInvalidCodeEscape()
{
var input = "```**Header** ";
var html = Markdown.ToHtml(input);
}
[Test]
public void TestEmphasisAndHtmlEntity()
{
var markdownText = "*Unlimited-Fun&#174;*&#174;";
TestSpec(markdownText, "<p><em>Unlimited-Fun®</em>®</p>");
}
[Test]
public void TestThematicInsideCodeBlockInsideList()
{
var input = @"1. In the :
```
Id DisplayName Description
-- ----------- -----------
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
```";
TestSpec(input, @"<ol>
<li><p>In the :</p>
<pre><code>Id DisplayName Description
-- ----------- -----------
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
</code></pre></li>
</ol>");
}
[Test]
public void EnsureSpecsAreUpToDate()
{
@@ -77,7 +24,7 @@ namespace Markdig.Tests
foreach (var specFilePath in SpecsFilePaths)
{
string testFilePath = Path.ChangeExtension(specFilePath, ".cs");
string testFilePath = Path.ChangeExtension(specFilePath, ".generated.cs");
Assert.True(File.Exists(testFilePath),
"A new specification file has been added. Add the spec to the list in SpecFileGen and regenerate the tests.");
@@ -87,9 +34,9 @@ namespace Markdig.Tests
// If file creation times aren't preserved by git, add some leeway
// If specs have come from git, assume that they were regenerated since CI would fail otherwise
testTime = testTime.AddSeconds(2);
testTime = testTime.AddMinutes(3);
// This might not catch a changed spec every time, but should most of the time. Otherwise CI will catch it
// This might not catch a changed spec every time, but should at least sometimes. Otherwise CI will catch it
// This could also trigger, if a user has modified the spec file but reverted the change - can't think of a good workaround
Assert.Less(specTime, testTime,
@@ -98,104 +45,41 @@ namespace Markdig.Tests
}
}
[Test]
public void VisualizeMathExpressions()
{
string math = @"Math expressions
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
$$\frac{n!}{k!(n-k)!} = \binom{n}{k}$$
$$
\frac{n!}{k!(n-k)!} = \binom{n}{k}
$$
<div class=""math"">
\begin{align}
\sqrt{37} & = \sqrt{\frac{73^2-1}{12^2}} \\
& = \sqrt{\frac{73^2}{12^2}\cdot\frac{73^2-1}{73^2}} \\
& = \sqrt{\frac{73^2}{12^2}}\sqrt{\frac{73^2-1}{73^2}} \\
& = \frac{73}{12}\sqrt{1 - \frac{1}{73^2}} \\
& \approx \frac{73}{12}\left(1 - \frac{1}{2\cdot73^2}\right)
\end{align}
</div>
";
Console.WriteLine("Math Expressions:\n");
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
}
[Test]
public void InlineMathExpression()
{
string math = @"Math expressions
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
";
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
Assert.IsTrue(html.Contains("<p><span class=\"math\">\\("),"Leading bracket missing");
Assert.IsTrue(html.Contains("\\)</span></p>"), "Trailing bracket missing");
}
[Test]
public void BlockMathExpression()
{
string math = @"Math expressions
$$
\frac{n!}{k!(n-k)!} = \binom{n}{k}
$$
";
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
Assert.IsTrue(html.Contains("<div class=\"math\">\n\\["), "Leading bracket missing");
Assert.IsTrue(html.Contains("\\]</div>"), "Trailing bracket missing");
}
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null)
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null, bool plainText = false)
{
foreach (var pipeline in GetPipeline(extensions))
{
Console.WriteLine($"Pipeline configured with extensions: {pipeline.Key}");
TestSpec(inputText, expectedOutputText, pipeline.Value);
TestSpec(inputText, expectedOutputText, pipeline.Value, plainText);
}
}
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline)
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline, bool plainText = false)
{
// Uncomment this line to get more debug information for process inlines.
//pipeline.DebugLog = Console.Out;
var result = Markdown.ToHtml(inputText, pipeline);
var result = plainText ? Markdown.ToPlainText(inputText, pipeline) : Markdown.ToHtml(inputText, pipeline);
result = Compact(result);
expectedOutputText = Compact(expectedOutputText);
PrintAssertExpected(inputText, result, expectedOutputText);
}
public static void PrintAssertExpected(string source, string result, string expected)
{
Console.WriteLine("```````````````````Source");
Console.WriteLine(DisplaySpaceAndTabs(inputText));
Console.WriteLine(DisplaySpaceAndTabs(source));
Console.WriteLine("```````````````````Result");
Console.WriteLine(DisplaySpaceAndTabs(result));
Console.WriteLine("```````````````````Expected");
Console.WriteLine(DisplaySpaceAndTabs(expectedOutputText));
Console.WriteLine(DisplaySpaceAndTabs(expected));
Console.WriteLine("```````````````````");
Console.WriteLine();
TextAssert.AreEqual(expectedOutputText, result);
TextAssert.AreEqual(expected, result);
}
private static IEnumerable<KeyValuePair<string, MarkdownPipeline>> GetPipeline(string extensionsGroupText)
public static IEnumerable<KeyValuePair<string, MarkdownPipeline>> GetPipeline(string extensionsGroupText)
{
// For the standard case, we make sure that both the CommmonMark core and Extra/Advanced are CommonMark compliant!
if (string.IsNullOrEmpty(extensionsGroupText))
@@ -257,6 +141,9 @@ $$
public static readonly bool IsContinuousIntegration = Environment.GetEnvironmentVariable("CI") != null;
public static readonly string TestsDirectory =
Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "../../.."));
/// <summary>
/// Contains absolute paths to specification markdown files (order is the same as in <see cref="SpecsMarkdown"/>)
/// </summary>
@@ -265,20 +152,38 @@ $$
/// Contains the markdown source for specification files (order is the same as in <see cref="SpecsFilePaths"/>)
/// </summary>
public static readonly string[] SpecsMarkdown;
/// <summary>
/// Contains the markdown syntax tree for specification files (order is the same as in <see cref="SpecsFilePaths"/>)
/// </summary>
public static readonly MarkdownDocument[] SpecsSyntaxTrees;
static TestParser()
{
string assemblyDir = Path.GetDirectoryName(typeof(TestParser).Assembly.Location);
string specsDir = Path.GetFullPath(Path.Combine(assemblyDir, "../../Specs"));
const string RunningInsideVisualStudioPath = "\\src\\.vs\\markdig\\";
int index = TestsDirectory.IndexOf(RunningInsideVisualStudioPath);
if (index != -1)
{
TestsDirectory = TestsDirectory.Substring(0, index) + "\\src\\Markdig.Tests";
}
SpecsFilePaths = Directory.GetFiles(specsDir)
.Where(file => file.EndsWith(".md", StringComparison.Ordinal) && !file.Contains("readme"))
SpecsFilePaths = Directory.GetDirectories(TestsDirectory)
.Where(dir => dir.EndsWith("Specs"))
.SelectMany(dir => Directory.GetFiles(dir)
.Where(file => file.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
.Where(file => file.IndexOf("readme", StringComparison.OrdinalIgnoreCase) == -1))
.ToArray();
SpecsMarkdown = new string[SpecsFilePaths.Length];
SpecsSyntaxTrees = new MarkdownDocument[SpecsFilePaths.Length];
var pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.Build();
for (int i = 0; i < SpecsFilePaths.Length; i++)
{
SpecsMarkdown[i] = File.ReadAllText(SpecsFilePaths[i]);
string markdown = SpecsMarkdown[i] = File.ReadAllText(SpecsFilePaths[i]);
SpecsSyntaxTrees[i] = Markdown.Parse(markdown, pipeline);
}
}
}

View File

@@ -5,15 +5,6 @@ namespace Markdig.Tests
[TestFixture]
public class TestPlainText
{
[Test]
public void TestPlain()
{
var markdownText = "*Hello*, [world](http://example.com)!";
var expected = "Hello, world!\n";
var actual = Markdown.ToPlainText(markdownText);
Assert.AreEqual(expected, actual);
}
[Test]
[TestCase(/* markdownText: */ "foo bar", /* expected: */ "foo bar\n")]
[TestCase(/* markdownText: */ "foo\nbar", /* expected: */ "foo\nbar\n")]
@@ -28,11 +19,25 @@ namespace Markdig.Tests
[TestCase(/* markdownText: */ "`foo\nbar`", /* expected: */ "foo bar\n")] // new line within codespan is treated as whitespace (Example317)
[TestCase(/* markdownText: */ "```\nfoo bar\n```", /* expected: */ "foo bar\n")]
[TestCase(/* markdownText: */ "- foo\n- bar\n- baz", /* expected: */ "foo\nbar\nbaz\n")]
[TestCase(/* markdownText: */ "- foo<baz", /* expected: */ "foo<baz\n")]
[TestCase(/* markdownText: */ "- foo&lt;baz", /* expected: */ "foo<baz\n")]
public void TestPlainEnsureNewLine(string markdownText, string expected)
{
var actual = Markdown.ToPlainText(markdownText);
Assert.AreEqual(expected, actual);
}
[Test]
[TestCase(/* markdownText: */ ":::\nfoo\n:::", /* expected: */ "foo\n", /*extensions*/ "customcontainers|advanced")]
[TestCase(/* markdownText: */ ":::bar\nfoo\n:::", /* expected: */ "foo\n", /*extensions*/ "customcontainers+attributes|advanced")]
public void TestPlainWithExtensions(string markdownText, string expected, string extensions)
{
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
}
public static void TestSpec(string markdownText, string expected, string extensions)
{
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
}
}
}

View File

@@ -1,5 +1,5 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
using System.Linq;
@@ -19,7 +19,7 @@ namespace Markdig.Tests
var link = doc.Descendants<ParagraphBlock>().SelectMany(x => x.Inline.Descendants<LinkInline>()).FirstOrDefault(l => l.IsImage);
Assert.AreEqual("/yoyo", link?.Url);
}
[Test]
public void TestListBug2()
{
@@ -53,11 +53,11 @@ Later in a text we are using HTML and it becomes an abbr tag HTML
[Test]
public void TestEmptyLiteral()
{
var text = @"> *some text*
var text = @"> *some text*
> some other text";
var doc = Markdown.Parse(text);
Assert.True(doc.Descendants().OfType<LiteralInline>().All(x => !x.Content.IsEmpty),
Assert.True(doc.Descendants<LiteralInline>().All(x => !x.Content.IsEmpty),
"There should not have any empty literals");
}
@@ -195,8 +195,8 @@ Paragraph
";
var expected = @"<table class=""table"">
<col style=""width:50%"">
<col style=""width:50%"">
<col style=""width:50%"" />
<col style=""width:50%"" />
<thead>
<tr>
<th>a</th>
@@ -219,7 +219,7 @@ Paragraph
{
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
// Reuse the same pipeline
// Reuse the same pipeline
var result1 = Markdown.ToHtml("This is a \"\"citation\"\"", pipeline);
var result2 = Markdown.ToHtml("This is a \"\"citation\"\"", pipeline);
@@ -269,7 +269,7 @@ Paragraph
//| Yes |
//| ``` |
//+===================================+======================================+
//| This is a second line |
//| This is a second line |
//+-----------------------------------+--------------------------------------+
//:::spoiler {#yessss}

View File

@@ -0,0 +1,36 @@
using Markdig.Extensions.SmartyPants;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestSmartyPants
{
[Test]
public void MappingCanBeReconfigured()
{
SmartyPantOptions options = new SmartyPantOptions();
options.Mapping[SmartyPantType.LeftAngleQuote] = "foo";
options.Mapping[SmartyPantType.RightAngleQuote] = "bar";
var pipeline = new MarkdownPipelineBuilder()
.UseSmartyPants(options)
.Build();
TestParser.TestSpec("<<test>>", "<p>footestbar</p>", pipeline);
}
[Test]
public void MappingCanBeReconfigured_HandlesRemovedMappings()
{
SmartyPantOptions options = new SmartyPantOptions();
options.Mapping.Remove(SmartyPantType.LeftAngleQuote);
options.Mapping.Remove(SmartyPantType.RightAngleQuote);
var pipeline = new MarkdownPipelineBuilder()
.UseSmartyPants(options)
.Build();
TestParser.TestSpec("<<test>>", "<p>&laquo;test&raquo;</p>", pipeline);
}
}
}

View File

@@ -6,8 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Markdig.Extensions.Footnotes;
using Markdig.Helpers;
using Markdig.Extensions.Footnotes;
using Markdig.Renderers.Html;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
@@ -147,7 +146,7 @@ literal ( 0, 6) 6-7
public void TestFootnoteLinkReferenceDefinition()
{
// 01 2 345678
var footnote = Markdown.Parse("0\n\n [^1]:", new MarkdownPipelineBuilder().UsePreciseSourceLocation().UseFootnotes().Build()).Descendants().OfType<FootnoteLinkReferenceDefinition>().FirstOrDefault();
var footnote = Markdown.Parse("0\n\n [^1]:", new MarkdownPipelineBuilder().UsePreciseSourceLocation().UseFootnotes().Build()).Descendants<FootnoteLinkReferenceDefinition>().FirstOrDefault();
Assert.NotNull(footnote);
Assert.AreEqual(2, footnote.Line);
@@ -160,7 +159,7 @@ literal ( 0, 6) 6-7
{
// 0 1
// 0123456789012345
var link = Markdown.Parse("[234]: /56 'yo' ", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants().OfType<LinkReferenceDefinition>().FirstOrDefault();
var link = Markdown.Parse("[234]: /56 'yo' ", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<LinkReferenceDefinition>().FirstOrDefault();
Assert.NotNull(link);
Assert.AreEqual(0, link.Line);
@@ -175,7 +174,7 @@ literal ( 0, 6) 6-7
{
// 0 1
// 01 2 34567890123456789
var link = Markdown.Parse("0\n\n [234]: /56 'yo' ", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants().OfType<LinkReferenceDefinition>().FirstOrDefault();
var link = Markdown.Parse("0\n\n [234]: /56 'yo' ", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<LinkReferenceDefinition>().FirstOrDefault();
Assert.NotNull(link);
Assert.AreEqual(2, link.Line);
@@ -213,7 +212,7 @@ literal ( 0, 4) 4-5
{
// 0 1
// 01 2 3456789012345
var link = Markdown.Parse("0\n\n01 [234](/56)", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants().OfType<LinkInline>().FirstOrDefault();
var link = Markdown.Parse("0\n\n01 [234](/56)", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<LinkInline>().FirstOrDefault();
Assert.NotNull(link);
Assert.AreEqual(new SourceSpan(7, 9), link.LabelSpan);
@@ -226,7 +225,7 @@ literal ( 0, 4) 4-5
{
// 0 1
// 01 2 34567890123456789
var link = Markdown.Parse("0\n\n01 [234](/56 'yo')", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants().OfType<LinkInline>().FirstOrDefault();
var link = Markdown.Parse("0\n\n01 [234](/56 'yo')", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<LinkInline>().FirstOrDefault();
Assert.NotNull(link);
Assert.AreEqual(new SourceSpan(7, 9), link.LabelSpan);
@@ -240,7 +239,7 @@ literal ( 0, 4) 4-5
{
// 0 1
// 01 2 3456789012345
var link = Markdown.Parse("0\n\n01![234](/56)", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants().OfType<LinkInline>().FirstOrDefault();
var link = Markdown.Parse("0\n\n01![234](/56)", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<LinkInline>().FirstOrDefault();
Assert.NotNull(link);
Assert.AreEqual(new SourceSpan(5, 15), link.Span);
@@ -408,7 +407,7 @@ literal ( 1, 2) 6-6
6. Bar
987123. FooBar";
test = test.Replace("\r\n", "\n");
var list = Markdown.Parse(test, new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants().OfType<ListBlock>().FirstOrDefault();
var list = Markdown.Parse(test, new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<ListBlock>().FirstOrDefault();
Assert.NotNull(list);
Assert.AreEqual(1, list.Line);

View File

@@ -1,8 +1,9 @@
using NUnit.Framework;
using NUnit.Framework;
using System.Collections.Generic;
using System.Text;
using Markdig.Helpers;
using Markdig.Syntax;
using System;
namespace Markdig.Tests
{
@@ -27,6 +28,8 @@ namespace Markdig.Tests
var chars = ToString(text.ToCharIterator());
TextAssert.AreEqual("ABC\nE\nF", chars.ToString());
TextAssert.AreEqual("ABC\nE\nF", text.ToString());
}
[Test]
@@ -81,8 +84,18 @@ namespace Markdig.Tests
public void TestSkipWhitespaces()
{
var text = new StringLineGroup(" ABC").ToCharIterator();
Assert.True(text.TrimStart());
Assert.False(text.TrimStart());
Assert.AreEqual('A', text.CurrentChar);
text = new StringLineGroup(" ").ToCharIterator();
Assert.True(text.TrimStart());
Assert.AreEqual('\0', text.CurrentChar);
var slice = new StringSlice(" ABC");
Assert.False(slice.TrimStart());
slice = new StringSlice(" ");
Assert.True(slice.TrimStart());
}
[Test]
@@ -116,5 +129,31 @@ namespace Markdig.Tests
var result = ToString(text);
TextAssert.AreEqual("ABC \n DEF ", result);
}
[Test]
public void TestStringLineGroupIteratorPeekChar()
{
var iterator = new StringLineGroup(4)
{
new StringSlice("ABC"),
new StringSlice("E"),
new StringSlice("F")
}.ToCharIterator();
Assert.AreEqual('A', iterator.CurrentChar);
Assert.AreEqual('A', iterator.PeekChar(0));
Assert.AreEqual('B', iterator.PeekChar());
Assert.AreEqual('B', iterator.PeekChar(1));
Assert.AreEqual('C', iterator.PeekChar(2));
Assert.AreEqual('\n', iterator.PeekChar(3));
Assert.AreEqual('E', iterator.PeekChar(4));
Assert.AreEqual('\n', iterator.PeekChar(5));
Assert.AreEqual('F', iterator.PeekChar(6));
Assert.AreEqual('\0', iterator.PeekChar(7)); // There is no \n appended to the last line
Assert.AreEqual('\0', iterator.PeekChar(8));
Assert.AreEqual('\0', iterator.PeekChar(100));
Assert.Throws<ArgumentOutOfRangeException>(() => iterator.PeekChar(-1));
}
}
}

View File

@@ -1,24 +0,0 @@
{
"runtimes": {
"win": {}
},
"frameworks": {
"net451": {
"compilationOptions": {
"define": [
"CLASSIC"
]
},
"frameworkAssemblies": {
"Microsoft.Build": "4.0.0.0",
"Microsoft.Build.Framework": "4.0.0.0",
"Microsoft.Build.Utilities.v4.0": "4.0.0.0",
"System.Management": "4.0.0.0"
}
}
},
"dependencies": {
"NUnit": "3.2.0",
"NUnit3TestAdapter": "3.9.0"
}
}

View File

@@ -9,6 +9,7 @@
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
<ApplicationInsightsResourceId>/subscriptions/b6745039-70e7-4641-994b-5457cb220e2a/resourcegroups/Default-ApplicationInsights-EastUS/providers/microsoft.insights/components/Markdig.WebApp</ApplicationInsightsResourceId>
<ApplicationInsightsAnnotationResourceId>/subscriptions/b6745039-70e7-4641-994b-5457cb220e2a/resourcegroups/Default-ApplicationInsights-EastUS/providers/microsoft.insights/components/Markdig.WebApp</ApplicationInsightsAnnotationResourceId>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
@@ -22,16 +23,16 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.12.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="2.2.1" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -43,8 +43,8 @@ namespace Markdig.WebApp
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
//loggerFactory.AddConsole(Configuration.GetSection("Logging"));
//loggerFactory.AddDebug();
app.UseMvc();
}

View File

@@ -1,9 +0,0 @@
<Project>
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-*" PrivateAssets="All"/>
</ItemGroup>
</Project>

View File

@@ -1,8 +1,9 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
using System.Collections.Generic;
using Markdig.Helpers;
using Markdig.Syntax;
namespace Markdig.Extensions.Abbreviations
@@ -21,9 +22,9 @@ namespace Markdig.Extensions.Abbreviations
public static void AddAbbreviation(this MarkdownDocument document, string label, Abbreviation abbr)
{
if (document == null) throw new ArgumentNullException(nameof(document));
if (label == null) throw new ArgumentNullException(nameof(label));
if (abbr == null) throw new ArgumentNullException(nameof(abbr));
if (document == null) ThrowHelper.ArgumentNullException(nameof(document));
if (label == null) ThrowHelper.ArgumentNullException_label();
if (abbr == null) ThrowHelper.ArgumentNullException(nameof(abbr));
var map = document.GetAbbreviations();
if (map == null)

View File

@@ -1,6 +1,7 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
using System.Collections.Generic;
using Markdig.Helpers;
using Markdig.Parsers;
@@ -115,7 +116,7 @@ namespace Markdig.Extensions.Abbreviations
ValidAbbreviationStart:;
if (prefixTree.TryMatchLongest(text, i, content.End - i + 1, out KeyValuePair<string, Abbreviation> abbreviationMatch))
if (prefixTree.TryMatchLongest(text.AsSpan(i, content.End - i + 1), out KeyValuePair<string, Abbreviation> abbreviationMatch))
{
var match = abbreviationMatch.Key;
if (!IsValidAbbreviationEnding(match, content, i))

View File

@@ -1,5 +1,5 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
@@ -22,6 +22,7 @@ namespace Markdig.Extensions.AutoIdentifiers
{
private const string AutoIdentifierKey = "AutoIdentifier";
private readonly AutoIdentifierOptions options;
private readonly StripRendererCache rendererCache = new StripRendererCache();
/// <summary>
/// Initializes a new instance of the <see cref="AutoIdentifierExtension"/> class.
@@ -111,12 +112,12 @@ namespace Markdig.Extensions.AutoIdentifiers
doc.SetLinkReferenceDefinition(keyPair.Key, keyPair.Value);
}
}
// Once we are done, we don't need to keep the intermediate dictionary arround
// Once we are done, we don't need to keep the intermediate dictionary around
doc.RemoveData(this);
}
/// <summary>
/// Callback when there is a reference to found to a heading.
/// Callback when there is a reference to found to a heading.
/// Note that reference are only working if they are declared after.
/// </summary>
private Inline CreateLinkInlineForHeading(InlineProcessor inlineState, LinkReferenceDefinition linkRef, Inline child)
@@ -159,17 +160,11 @@ namespace Markdig.Extensions.AutoIdentifiers
}
// Use internally a HtmlRenderer to strip links from a heading
var headingWriter = new StringWriter();
var stripRenderer = new HtmlRenderer(headingWriter)
{
// Set to false both to avoid having any HTML tags in the output
EnableHtmlForInline = false,
EnableHtmlEscape = false
};
var stripRenderer = rendererCache.Get();
stripRenderer.Render(headingBlock.Inline);
var headingText = headingWriter.ToString();
headingWriter.GetStringBuilder().Length = 0;
var headingText = stripRenderer.Writer.ToString();
rendererCache.Release(stripRenderer);
// Urilize the link
headingText = (options & AutoIdentifierOptions.GitHub) != 0
@@ -195,5 +190,25 @@ namespace Markdig.Extensions.AutoIdentifiers
attributes.Id = headingId;
}
private sealed class StripRendererCache : ObjectCache<HtmlRenderer>
{
protected override HtmlRenderer NewInstance()
{
var headingWriter = new StringWriter();
var stripRenderer = new HtmlRenderer(headingWriter)
{
// Set to false both to avoid having any HTML tags in the output
EnableHtmlForInline = false,
EnableHtmlEscape = false
};
return stripRenderer;
}
protected override void Reset(HtmlRenderer instance)
{
instance.Reset();
}
}
}
}

View File

@@ -11,14 +11,14 @@ namespace Markdig.Extensions.AutoLinks
/// <summary>
/// Extension to automatically create <see cref="LinkInline"/> when a link url http: or mailto: is found.
/// </summary>
/// <seealso cref="Markdig.IMarkdownExtension" />
/// <seealso cref="IMarkdownExtension" />
public class AutoLinkExtension : IMarkdownExtension
{
public readonly string ValidPreviousCharacters;
public readonly AutoLinkOptions Options;
public AutoLinkExtension(string validPreviousCharacters = AutoLinkParser.DefaultValidPreviousCharacters)
public AutoLinkExtension(AutoLinkOptions options)
{
ValidPreviousCharacters = validPreviousCharacters;
Options = options ?? new AutoLinkOptions();
}
public void Setup(MarkdownPipelineBuilder pipeline)
@@ -26,14 +26,13 @@ namespace Markdig.Extensions.AutoLinks
if (!pipeline.InlineParsers.Contains<AutoLinkParser>())
{
// Insert the parser before any other parsers
pipeline.InlineParsers.Insert(0, new AutoLinkParser(ValidPreviousCharacters));
pipeline.InlineParsers.Insert(0, new AutoLinkParser(Options));
}
}
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
var normalizeRenderer = renderer as NormalizeRenderer;
if (normalizeRenderer != null && !normalizeRenderer.ObjectRenderers.Contains<NormalizeAutoLinkRenderer>())
if (renderer is NormalizeRenderer normalizeRenderer && !normalizeRenderer.ObjectRenderers.Contains<NormalizeAutoLinkRenderer>())
{
normalizeRenderer.ObjectRenderers.InsertBefore<LinkInlineRenderer>(new NormalizeAutoLinkRenderer());
}

View File

@@ -0,0 +1,22 @@
namespace Markdig.Extensions.AutoLinks
{
public class AutoLinkOptions
{
public AutoLinkOptions()
{
ValidPreviousCharacters = "*_~(";
}
public string ValidPreviousCharacters { get; set; }
/// <summary>
/// Should the link open in a new window when clicked (false by default)
/// </summary>
public bool OpenInNewWindow { get; set; }
/// <summary>
/// Should a www link be prefixed with https:// instead of http:// (false by default)
/// </summary>
public bool UseHttpsForWWWLinks { get; set; }
}
}

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Renderers.Html;
using Markdig.Syntax.Inlines;
namespace Markdig.Extensions.AutoLinks
@@ -13,188 +14,196 @@ namespace Markdig.Extensions.AutoLinks
/// <summary>
/// The inline parser used to for autolinks.
/// </summary>
/// <seealso cref="Markdig.Parsers.InlineParser" />
/// <seealso cref="InlineParser" />
public class AutoLinkParser : InlineParser
{
/// <summary>
/// Initializes a new instance of the <see cref="AutoLinkParser"/> class.
/// </summary>
public AutoLinkParser(string validPreviousCharacters = DefaultValidPreviousCharacters)
public AutoLinkParser(AutoLinkOptions options)
{
Options = options ?? throw new ArgumentNullException(nameof(options));
OpeningCharacters = new char[]
{
'h', // for http:// and https://
'f', // for ftp://
'm', // for mailto:
'w', // for www.
};
ValidPreviousCharacters = validPreviousCharacters;
}
// All such recognized autolinks can only come at the beginning of a line, after whitespace, or any of the delimiting characters *, _, ~, and (.
public readonly string ValidPreviousCharacters;
public const string DefaultValidPreviousCharacters = "*_~(";
};
_listOfCharCache = new ListOfCharCache();
}
public readonly AutoLinkOptions Options;
private readonly ListOfCharCache _listOfCharCache;
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
// Previous char must be a whitespace or a punctuation
var previousChar = slice.PeekCharExtra(-1);
if (!previousChar.IsWhiteSpaceOrZero() && ValidPreviousCharacters.IndexOf(previousChar) == -1)
if (!previousChar.IsWhiteSpaceOrZero() && Options.ValidPreviousCharacters.IndexOf(previousChar) == -1)
{
return false;
}
List<char> pendingEmphasis;
// Check that an autolink is possible in the current context
if (!IsAutoLinkValidInCurrentContext(processor, out pendingEmphasis))
{
return false;
}
var startPosition = slice.Start;
int domainOffset = 0;
var c = slice.CurrentChar;
// Precheck URL
switch (c)
{
case 'h':
if (slice.MatchLowercase("ttp://", 1))
{
domainOffset = 7; // http://
}
else if (slice.MatchLowercase("ttps://", 1))
{
domainOffset = 8; // https://
}
else return false;
break;
case 'f':
if (!slice.MatchLowercase("tp://", 1))
{
return false;
}
domainOffset = 6; // ftp://
break;
case 'm':
if (!slice.MatchLowercase("ailto:", 1))
{
return false;
}
break;
case 'w':
if (!slice.MatchLowercase("ww.", 1)) // We won't match http:/www. or /www.xxx
{
return false;
}
domainOffset = 4; // www.
break;
}
// Parse URL
string link;
if (!LinkHelper.TryParseUrl(ref slice, out link, true))
{
return false;
}
// If we have any pending emphasis, remove any pending emphasis characters from the end of the link
if (pendingEmphasis != null)
{
for (int i = link.Length - 1; i >= 0; i--)
{
if (pendingEmphasis.Contains(link[i]))
{
slice.Start--;
}
else
{
if (i < link.Length - 1)
{
link = link.Substring(0, i + 1);
}
break;
}
}
}
// Post-check URL
switch (c)
{
case 'h':
if (string.Equals(link, "http://", StringComparison.OrdinalIgnoreCase) ||
string.Equals(link, "https://", StringComparison.OrdinalIgnoreCase))
{
return false;
}
break;
case 'f':
if (string.Equals(link, "ftp://", StringComparison.OrdinalIgnoreCase))
{
return false;
}
break;
case 'm':
int atIndex = link.IndexOf('@');
if (atIndex == -1 ||
atIndex == 7) // mailto:@ - no email part
{
return false;
}
domainOffset = atIndex + 1;
break;
}
if (!LinkHelper.IsValidDomain(link, domainOffset))
List<char> pendingEmphasis = _listOfCharCache.Get();
try
{
return false;
// Check that an autolink is possible in the current context
if (!IsAutoLinkValidInCurrentContext(processor, pendingEmphasis))
{
return false;
}
var startPosition = slice.Start;
int domainOffset = 0;
var c = slice.CurrentChar;
// Precheck URL
switch (c)
{
case 'h':
if (slice.MatchLowercase("ttp://", 1))
{
domainOffset = 7; // http://
}
else if (slice.MatchLowercase("ttps://", 1))
{
domainOffset = 8; // https://
}
else return false;
break;
case 'f':
if (!slice.MatchLowercase("tp://", 1))
{
return false;
}
domainOffset = 6; // ftp://
break;
case 'm':
if (!slice.MatchLowercase("ailto:", 1))
{
return false;
}
break;
case 'w':
if (!slice.MatchLowercase("ww.", 1)) // We won't match http:/www. or /www.xxx
{
return false;
}
domainOffset = 4; // www.
break;
}
// Parse URL
if (!LinkHelper.TryParseUrl(ref slice, out string link, true))
{
return false;
}
// If we have any pending emphasis, remove any pending emphasis characters from the end of the link
if (pendingEmphasis.Count > 0)
{
for (int i = link.Length - 1; i >= 0; i--)
{
if (pendingEmphasis.Contains(link[i]))
{
slice.Start--;
}
else
{
if (i < link.Length - 1)
{
link = link.Substring(0, i + 1);
}
break;
}
}
}
// Post-check URL
switch (c)
{
case 'h':
if (string.Equals(link, "http://", StringComparison.OrdinalIgnoreCase) ||
string.Equals(link, "https://", StringComparison.OrdinalIgnoreCase))
{
return false;
}
break;
case 'f':
if (string.Equals(link, "ftp://", StringComparison.OrdinalIgnoreCase))
{
return false;
}
break;
case 'm':
int atIndex = link.IndexOf('@');
if (atIndex == -1 ||
atIndex == 7) // mailto:@ - no email part
{
return false;
}
domainOffset = atIndex + 1;
break;
}
if (!LinkHelper.IsValidDomain(link, domainOffset))
{
return false;
}
var inline = new LinkInline()
{
Span =
{
Start = processor.GetSourcePosition(startPosition, out int line, out int column),
},
Line = line,
Column = column,
Url = c == 'w' ? ((Options.UseHttpsForWWWLinks ? "https://" : "http://") + link) : link,
IsClosed = true,
IsAutoLink = true,
};
var skipFromBeginning = c == 'm' ? 7 : 0; // For mailto: skip "mailto:" for content
inline.Span.End = inline.Span.Start + link.Length - 1;
inline.UrlSpan = inline.Span;
inline.AppendChild(new LiteralInline()
{
Span = inline.Span,
Line = line,
Column = column,
Content = new StringSlice(slice.Text, startPosition + skipFromBeginning, startPosition + link.Length - 1),
IsClosed = true
});
processor.Inline = inline;
if (Options.OpenInNewWindow)
{
inline.GetAttributes().AddPropertyIfNotExist("target", "blank");
}
return true;
}
finally
{
_listOfCharCache.Release(pendingEmphasis);
}
int line;
int column;
var inline = new LinkInline()
{
Span =
{
Start = processor.GetSourcePosition(startPosition, out line, out column),
},
Line = line,
Column = column,
Url = c == 'w' ? "http://" + link : link,
IsClosed = true,
IsAutoLink = true,
};
var skipFromBeginning = c == 'm' ? 7 : 0; // For mailto: skip "mailto:" for content
inline.Span.End = inline.Span.Start + link.Length - 1;
inline.UrlSpan = inline.Span;
inline.AppendChild(new LiteralInline()
{
Span = inline.Span,
Line = line,
Column = column,
Content = new StringSlice(slice.Text, startPosition + skipFromBeginning, startPosition + link.Length - 1),
IsClosed = true
});
processor.Inline = inline;
return true;
}
private bool IsAutoLinkValidInCurrentContext(InlineProcessor processor, out List<char> pendingEmphasis)
private bool IsAutoLinkValidInCurrentContext(InlineProcessor processor, List<char> pendingEmphasis)
{
pendingEmphasis = null;
// Case where there is a pending HtmlInline <a>
var currentInline = processor.Inline;
while (currentInline != null)
{
var htmlInline = currentInline as HtmlInline;
if (htmlInline != null)
if (currentInline is HtmlInline htmlInline)
{
// If we have a </a> we don't expect nested <a>
if (htmlInline.Tag.StartsWith("</a", StringComparison.OrdinalIgnoreCase))
@@ -209,7 +218,7 @@ namespace Markdig.Extensions.AutoLinks
}
}
// Check previous sibling and parents in the tree
// Check previous sibling and parents in the tree
currentInline = currentInline.PreviousSibling ?? currentInline.Parent;
}
@@ -219,8 +228,7 @@ namespace Markdig.Extensions.AutoLinks
int countBrackets = 0;
while (currentInline != null)
{
var linkDelimiterInline = currentInline as LinkDelimiterInline;
if (linkDelimiterInline != null && linkDelimiterInline.IsActive)
if (currentInline is LinkDelimiterInline linkDelimiterInline && linkDelimiterInline.IsActive)
{
if (linkDelimiterInline.Type == DelimiterType.Open)
{
@@ -234,14 +242,8 @@ namespace Markdig.Extensions.AutoLinks
else
{
// Record all pending characters for emphasis
var emphasisDelimiter = currentInline as EmphasisDelimiterInline;
if (emphasisDelimiter != null)
if (currentInline is EmphasisDelimiterInline emphasisDelimiter)
{
if (pendingEmphasis == null)
{
// Not optimized for GC, but we don't expect this case much
pendingEmphasis = new List<char>();
}
if (!pendingEmphasis.Contains(emphasisDelimiter.DelimiterChar))
{
pendingEmphasis.Add(emphasisDelimiter.DelimiterChar);
@@ -252,6 +254,14 @@ namespace Markdig.Extensions.AutoLinks
}
return countBrackets <= 0;
}
private sealed class ListOfCharCache : DefaultObjectCache<List<char>>
{
protected override void Reset(List<char> instance)
{
instance.Clear();
}
}
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
@@ -51,8 +51,7 @@ namespace Markdig.Extensions.Bootstrap
}
else if (node is Inline)
{
var link = node as LinkInline;
if (link != null && link.IsImage)
if (node is LinkInline link && link.IsImage)
{
link.GetAttributes().AddClass("img-fluid");
}

View File

@@ -15,10 +15,16 @@ namespace Markdig.Extensions.CustomContainers
protected override void Write(HtmlRenderer renderer, CustomContainer obj)
{
renderer.EnsureLine();
renderer.Write("<div").WriteAttributes(obj).Write(">");
if (renderer.EnableHtmlForBlock)
{
renderer.Write("<div").WriteAttributes(obj).Write(">");
}
// We don't escape a CustomContainer
renderer.WriteChildren(obj);
renderer.WriteLine("</div>");
if (renderer.EnableHtmlForBlock)
{
renderer.WriteLine("</div>");
}
}
}
}

View File

@@ -7,24 +7,24 @@ using Markdig.Renderers;
namespace Markdig.Extensions.Emoji
{
/// <summary>
/// Extension to allow emoji and smiley replacement.
/// Extension to allow emoji shortcodes and smileys replacement.
/// </summary>
/// <seealso cref="Markdig.IMarkdownExtension" />
public class EmojiExtension : IMarkdownExtension
{
public EmojiExtension(bool enableSmiley = true)
{
EnableSmiley = enableSmiley;
public EmojiExtension(EmojiMapping emojiMapping)
{
EmojiMapping = emojiMapping;
}
public bool EnableSmiley { get; set; }
public EmojiMapping EmojiMapping { get; }
public void Setup(MarkdownPipelineBuilder pipeline)
{
if (!pipeline.InlineParsers.Contains<EmojiParser>())
{
// Insert the parser before any other parsers
pipeline.InlineParsers.Insert(0, new EmojiParser(EnableSmiley));
pipeline.InlineParsers.Insert(0, new EmojiParser(EmojiMapping));
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
@@ -8,7 +8,7 @@ using Markdig.Syntax.Inlines;
namespace Markdig.Extensions.Emoji
{
/// <summary>
/// An emoji inline
/// An emoji inline.
/// </summary>
/// <seealso cref="Markdig.Syntax.Inlines.Inline" />
public class EmojiInline : LiteralInline
@@ -32,7 +32,7 @@ namespace Markdig.Extensions.Emoji
}
/// <summary>
/// Gets or sets the original match string (either an emoji or a text smiley)
/// Gets or sets the original match string (either an emoji shortcode or a text smiley)
/// </summary>
public string Match { get; set; }
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using Markdig.Parsers;
@@ -8,7 +8,7 @@ using Markdig.Syntax;
namespace Markdig.Extensions.Footers
{
/// <summary>
/// A block elemeent for a footer.
/// A block element for a footer.
/// </summary>
/// <seealso cref="Markdig.Syntax.ContainerBlock" />
public class FooterBlock : ContainerBlock

View File

@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
@@ -16,7 +16,7 @@ namespace Markdig.Extensions.GenericAttributes
/// Extension that allows to attach HTML attributes to the previous <see cref="Inline"/> or current <see cref="Block"/>.
/// This extension should be enabled last after enabling other extensions.
/// </summary>
/// <seealso cref="Markdig.IMarkdownExtension" />
/// <seealso cref="IMarkdownExtension" />
public class GenericAttributesExtension : IMarkdownExtension
{
public void Setup(MarkdownPipelineBuilder pipeline)
@@ -29,8 +29,7 @@ namespace Markdig.Extensions.GenericAttributes
// Plug into all IAttributesParseable
foreach (var parser in pipeline.BlockParsers)
{
var attributesParseable = parser as IAttributesParseable;
if (attributesParseable != null)
if (parser is IAttributesParseable attributesParseable)
{
attributesParseable.TryParseAttributes = TryProcessAttributesForHeading;
}
@@ -53,8 +52,7 @@ namespace Markdig.Extensions.GenericAttributes
var copy = line;
copy.Start = indexOfAttributes;
var startOfAttributes = copy.Start;
HtmlAttributes attributes;
if (GenericAttributesParser.TryParse(ref copy, out attributes))
if (GenericAttributesParser.TryParse(ref copy, out HtmlAttributes attributes))
{
var htmlAttributes = block.GetAttributes();
attributes.CopyTo(htmlAttributes);

View File

@@ -1,5 +1,5 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System.Collections.Generic;
@@ -14,7 +14,7 @@ namespace Markdig.Extensions.GenericAttributes
/// <summary>
/// An inline parser used to parse a HTML attributes that can be attached to the previous <see cref="Inline"/> or current <see cref="Block"/>.
/// </summary>
/// <seealso cref="Markdig.Parsers.InlineParser" />
/// <seealso cref="InlineParser" />
public class GenericAttributesParser : InlineParser
{
/// <summary>
@@ -27,13 +27,12 @@ namespace Markdig.Extensions.GenericAttributes
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
HtmlAttributes attributes;
var startPosition = slice.Start;
if (TryParse(ref slice, out attributes))
if (TryParse(ref slice, out HtmlAttributes attributes))
{
var inline = processor.Inline;
// If the curent object to attach is either a literal or delimiter
// If the current object to attach is either a literal or delimiter
// try to find a suitable parent, otherwise attach the html attributes to the block
if (inline is LiteralInline)
{
@@ -50,8 +49,10 @@ namespace Markdig.Extensions.GenericAttributes
// If the current block is a Paragraph, but only the HtmlAttributes is used,
// Try to attach the attributes to the following block
var paragraph = objectToAttach as ParagraphBlock;
if (paragraph != null && paragraph.Inline.FirstChild == null && processor.Inline == null && slice.IsEmptyOrWhitespace())
if (objectToAttach is ParagraphBlock paragraph &&
paragraph.Inline.FirstChild == null &&
processor.Inline == null &&
slice.IsEmptyOrWhitespace())
{
var parent = paragraph.Parent;
var indexOfParagraph = parent.IndexOf(paragraph);
@@ -67,9 +68,7 @@ namespace Markdig.Extensions.GenericAttributes
attributes.CopyTo(currentHtmlAttributes, true, false);
// Update the position of the attributes
int line;
int column;
currentHtmlAttributes.Span.Start = processor.GetSourcePosition(startPosition, out line, out column);
currentHtmlAttributes.Span.Start = processor.GetSourcePosition(startPosition, out int line, out int column);
currentHtmlAttributes.Line = line;
currentHtmlAttributes.Column = column;
currentHtmlAttributes.Span.End = currentHtmlAttributes.Span.Start + slice.Start - startPosition - 1;
@@ -86,7 +85,7 @@ namespace Markdig.Extensions.GenericAttributes
/// </summary>
/// <param name="slice">The slice to parse.</param>
/// <param name="attributes">The output attributes or null if not found or invalid</param>
/// <returns><c>true</c> if parsing the HTML attributes was succsesfull</returns>
/// <returns><c>true</c> if parsing the HTML attributes was successful</returns>
public static bool TryParse(ref StringSlice slice, out HtmlAttributes attributes)
{
attributes = null;
@@ -173,7 +172,7 @@ namespace Markdig.Extensions.GenericAttributes
line.TrimStart();
c = line.CurrentChar;
// Handle boolean properties that are not followed by =
// Handle boolean properties that are not followed by =
if ((hasSpace && (c == '.' || c == '#' || IsStartAttributeName(c))) || c == '}')
{
if (properties == null)
@@ -184,7 +183,7 @@ namespace Markdig.Extensions.GenericAttributes
properties.Add(new KeyValuePair<string, string>(name, null));
continue;
}
// Else we expect a regular property
if (line.CurrentChar != '=')
{
@@ -223,6 +222,7 @@ namespace Markdig.Extensions.GenericAttributes
{
// Parse until we match a space or a special html character
startValue = line.Start;
bool valid = false;
while (true)
{
if (c == '\0')
@@ -234,9 +234,10 @@ namespace Markdig.Extensions.GenericAttributes
break;
}
c = line.NextChar();
valid = true;
}
endValue = line.Start - 1;
if (endValue == startValue)
if (!valid)
{
break;
}
@@ -264,7 +265,7 @@ namespace Markdig.Extensions.GenericAttributes
Properties = properties
};
// Assign back the current processor of the line to
// Assign back the current processor of the line to
slice = line;
}
return isValid;

View File

@@ -38,7 +38,7 @@ namespace Markdig.Extensions.Globalization
var attributes = node.GetAttributes();
attributes.AddPropertyIfNotExist("dir", "rtl");
if (node is Table table)
if (node is Table)
{
attributes.AddPropertyIfNotExist("align", "right");
}
@@ -71,19 +71,16 @@ namespace Markdig.Extensions.Globalization
}
else if (item is LiteralInline literal)
{
return StartsWithRtlCharacter(literal.ToString());
return StartsWithRtlCharacter(literal.Content);
}
foreach (var descendant in item.Descendants())
foreach (var paragraph in item.Descendants<ParagraphBlock>())
{
if (descendant is ParagraphBlock p)
foreach (var inline in paragraph.Inline)
{
foreach (var i in p.Inline)
if (inline is LiteralInline literal)
{
if (i is LiteralInline l)
{
return StartsWithRtlCharacter(l.ToString());
}
return StartsWithRtlCharacter(literal.Content);
}
}
}
@@ -91,9 +88,9 @@ namespace Markdig.Extensions.Globalization
return false;
}
private bool StartsWithRtlCharacter(string text)
private bool StartsWithRtlCharacter(StringSlice slice)
{
foreach (var c in CharHelper.ToUtf32(text))
foreach (var c in CharHelper.ToUtf32(slice))
{
if (CharHelper.IsRightToLeft(c))
return true;

View File

@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
@@ -92,7 +92,7 @@ namespace Markdig.Extensions.JiraLinks
jiraLink.Span.End = jiraLink.Span.Start + (endIssue - startKey);
// Builds the Url
var builder = new StringBuilder();
var builder = StringBuilderCache.Local();
builder.Append(_baseUrl).Append('/').Append(jiraLink.ProjectKey).Append('-').Append(jiraLink.Issue);
jiraLink.Url = builder.ToString();

View File

@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
@@ -45,16 +45,16 @@ namespace Markdig.Extensions.ListExtras
if ((isRomanLow || isRomanUp) && (pendingBulletType == '\0' || pendingBulletType == 'i' || pendingBulletType == 'I'))
{
int startChar = state.Start;
int endChar = 0;
// With a roman, we can have multiple characters
// Note that we don't validate roman numbers
while (isRomanLow ? CharHelper.IsRomanLetterLowerPartial(c) : CharHelper.IsRomanLetterUpperPartial(c))
do
{
endChar = state.Start;
c = state.NextChar();
}
while (isRomanLow ? CharHelper.IsRomanLetterLowerPartial(c) : CharHelper.IsRomanLetterUpperPartial(c));
result.OrderedStart = CharHelper.RomanToArabic(state.Line.Text.Substring(startChar, endChar - startChar + 1)).ToString();
int orderValue = CharHelper.RomanToArabic(state.Line.Text.AsSpan(startChar, state.Start - startChar));
result.OrderedStart = CharHelper.SmallNumberToString(orderValue);
result.BulletType = isRomanLow ? 'i' : 'I';
result.DefaultOrderedStart = isRomanLow ? "i" : "I";
}
@@ -62,7 +62,7 @@ namespace Markdig.Extensions.ListExtras
{
// otherwise we expect a regular alpha lettered list with a single character.
var isUpper = c.IsAlphaUpper();
result.OrderedStart = (Char.ToUpperInvariant(c) - 64).ToString();
result.OrderedStart = CharHelper.SmallNumberToString((c | 0x20) - 'a' + 1);
result.BulletType = isUpper ? 'A' : 'a';
result.DefaultOrderedStart = isUpper ? "A" : "a";
state.NextChar();

Some files were not shown because too many files have changed in this diff Show More