commonmarker 0.23.10 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1049 -0
  3. data/Cargo.toml +6 -0
  4. data/README.md +144 -203
  5. data/ext/commonmarker/Cargo.toml +13 -0
  6. data/ext/commonmarker/extconf.rb +3 -6
  7. data/ext/commonmarker/src/lib.rs +153 -0
  8. data/ext/commonmarker/src/options.rs +140 -0
  9. data/ext/commonmarker/src/plugins/syntax_highlighting.rs +74 -0
  10. data/ext/commonmarker/src/plugins.rs +3 -0
  11. data/ext/commonmarker/src/utils.rs +8 -0
  12. data/lib/commonmarker/config.rb +84 -40
  13. data/lib/commonmarker/constants.rb +7 -0
  14. data/lib/commonmarker/extension.rb +14 -0
  15. data/lib/commonmarker/renderer.rb +1 -127
  16. data/lib/commonmarker/utils.rb +22 -0
  17. data/lib/commonmarker/version.rb +2 -2
  18. data/lib/commonmarker.rb +14 -29
  19. metadata +36 -188
  20. data/Rakefile +0 -109
  21. data/bin/commonmarker +0 -118
  22. data/commonmarker.gemspec +0 -38
  23. data/ext/commonmarker/arena.c +0 -104
  24. data/ext/commonmarker/autolink.c +0 -508
  25. data/ext/commonmarker/autolink.h +0 -8
  26. data/ext/commonmarker/blocks.c +0 -1622
  27. data/ext/commonmarker/buffer.c +0 -278
  28. data/ext/commonmarker/buffer.h +0 -116
  29. data/ext/commonmarker/case_fold_switch.inc +0 -4327
  30. data/ext/commonmarker/chunk.h +0 -135
  31. data/ext/commonmarker/cmark-gfm-core-extensions.h +0 -54
  32. data/ext/commonmarker/cmark-gfm-extension_api.h +0 -737
  33. data/ext/commonmarker/cmark-gfm-extensions_export.h +0 -42
  34. data/ext/commonmarker/cmark-gfm.h +0 -833
  35. data/ext/commonmarker/cmark-gfm_export.h +0 -42
  36. data/ext/commonmarker/cmark-gfm_version.h +0 -7
  37. data/ext/commonmarker/cmark.c +0 -55
  38. data/ext/commonmarker/cmark_ctype.c +0 -44
  39. data/ext/commonmarker/cmark_ctype.h +0 -33
  40. data/ext/commonmarker/commonmark.c +0 -514
  41. data/ext/commonmarker/commonmarker.c +0 -1308
  42. data/ext/commonmarker/commonmarker.h +0 -16
  43. data/ext/commonmarker/config.h +0 -76
  44. data/ext/commonmarker/core-extensions.c +0 -27
  45. data/ext/commonmarker/entities.inc +0 -2138
  46. data/ext/commonmarker/ext_scanners.c +0 -879
  47. data/ext/commonmarker/ext_scanners.h +0 -24
  48. data/ext/commonmarker/footnotes.c +0 -63
  49. data/ext/commonmarker/footnotes.h +0 -27
  50. data/ext/commonmarker/houdini.h +0 -57
  51. data/ext/commonmarker/houdini_href_e.c +0 -100
  52. data/ext/commonmarker/houdini_html_e.c +0 -66
  53. data/ext/commonmarker/houdini_html_u.c +0 -149
  54. data/ext/commonmarker/html.c +0 -502
  55. data/ext/commonmarker/html.h +0 -27
  56. data/ext/commonmarker/inlines.c +0 -1788
  57. data/ext/commonmarker/inlines.h +0 -29
  58. data/ext/commonmarker/iterator.c +0 -159
  59. data/ext/commonmarker/iterator.h +0 -26
  60. data/ext/commonmarker/latex.c +0 -468
  61. data/ext/commonmarker/linked_list.c +0 -37
  62. data/ext/commonmarker/man.c +0 -274
  63. data/ext/commonmarker/map.c +0 -129
  64. data/ext/commonmarker/map.h +0 -44
  65. data/ext/commonmarker/node.c +0 -1045
  66. data/ext/commonmarker/node.h +0 -167
  67. data/ext/commonmarker/parser.h +0 -59
  68. data/ext/commonmarker/plaintext.c +0 -218
  69. data/ext/commonmarker/plugin.c +0 -36
  70. data/ext/commonmarker/plugin.h +0 -34
  71. data/ext/commonmarker/references.c +0 -43
  72. data/ext/commonmarker/references.h +0 -26
  73. data/ext/commonmarker/registry.c +0 -63
  74. data/ext/commonmarker/registry.h +0 -24
  75. data/ext/commonmarker/render.c +0 -213
  76. data/ext/commonmarker/render.h +0 -62
  77. data/ext/commonmarker/scanners.c +0 -14056
  78. data/ext/commonmarker/scanners.h +0 -70
  79. data/ext/commonmarker/scanners.re +0 -341
  80. data/ext/commonmarker/strikethrough.c +0 -167
  81. data/ext/commonmarker/strikethrough.h +0 -9
  82. data/ext/commonmarker/syntax_extension.c +0 -149
  83. data/ext/commonmarker/syntax_extension.h +0 -34
  84. data/ext/commonmarker/table.c +0 -917
  85. data/ext/commonmarker/table.h +0 -12
  86. data/ext/commonmarker/tagfilter.c +0 -60
  87. data/ext/commonmarker/tagfilter.h +0 -8
  88. data/ext/commonmarker/tasklist.c +0 -156
  89. data/ext/commonmarker/tasklist.h +0 -8
  90. data/ext/commonmarker/utf8.c +0 -317
  91. data/ext/commonmarker/utf8.h +0 -35
  92. data/ext/commonmarker/xml.c +0 -182
  93. data/lib/commonmarker/node/inspect.rb +0 -47
  94. data/lib/commonmarker/node.rb +0 -83
  95. data/lib/commonmarker/renderer/html_renderer.rb +0 -256
data/Cargo.toml ADDED
@@ -0,0 +1,6 @@
1
+ # This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is
2
+ # a Rust project. Your extensions depedencies should be added to the Cargo.toml
3
+ # in the ext/ directory.
4
+
5
+ [workspace]
6
+ members = ["ext/commonmarker"]
data/README.md CHANGED
@@ -1,11 +1,13 @@
1
- # CommonMarker
1
+ # Commonmarker
2
2
 
3
- ![Build Status](https://github.com/gjtorikian/commonmarker/workflows/CI/badge.svg) [![Gem Version](https://badge.fury.io/rb/commonmarker.svg)](http://badge.fury.io/rb/commonmarker)
3
+ > **Note**
4
+ > This README refers to the behavior in the new 1.0.0.pre gem.
4
5
 
5
- Ruby wrapper for [libcmark-gfm](https://github.com/github/cmark),
6
- GitHub's fork of the reference parser for CommonMark. It passes all of the C tests, and is therefore spec-complete. It also includes extensions to the CommonMark spec as documented in the [GitHub Flavored Markdown spec](http://github.github.com/gfm/), such as support for tables, strikethroughs, and autolinking.
6
+ Ruby wrapper for Rust's [comrak](https://github.com/kivikakk/comrak) crate.
7
7
 
8
- For more information on available extensions, see [the documentation below](#extensions).
8
+ It passes all of the CommonMark test suite, and is therefore spec-complete. It also includes extensions to the CommonMark spec as documented in the [GitHub Flavored Markdown spec](http://github.github.com/gfm/), such as support for tables, strikethroughs, and autolinking.
9
+
10
+ For more information on available extensions, see [the documentation below](#extension-options).
9
11
 
10
12
  ## Installation
11
13
 
@@ -25,234 +27,168 @@ Or install it yourself as:
25
27
 
26
28
  ### Converting to HTML
27
29
 
28
- Call `render_html` on a string to convert it to HTML:
29
-
30
- ``` ruby
31
- require 'commonmarker'
32
- CommonMarker.render_html('Hi *there*', :DEFAULT)
33
- # <p>Hi <em>there</em></p>\n
34
- ```
35
-
36
- The second argument is optional--[see below](#options) for more information.
37
-
38
- ### Generating a document
30
+ Call `to_html` on a string to convert it to HTML:
39
31
 
40
- You can also parse a string to receive a `Document` node. You can then print that node to HTML, iterate over the children, and other fun node stuff. For example:
41
-
42
- ``` ruby
32
+ ```ruby
43
33
  require 'commonmarker'
44
-
45
- doc = CommonMarker.render_doc('*Hello* world', :DEFAULT)
46
- puts(doc.to_html) # <p>Hi <em>there</em></p>\n
47
-
48
- doc.walk do |node|
49
- puts node.type # [:document, :paragraph, :text, :emph, :text]
50
- end
34
+ Commonmarker.to_html('"Hi *there*"', options: {
35
+ parse: { smart: true }
36
+ })
37
+ # <p>“Hi <em>there</em>”</p>\n
51
38
  ```
52
39
 
53
40
  The second argument is optional--[see below](#options) for more information.
54
41
 
55
- #### Example: walking the AST
56
-
57
- You can use `walk` or `each` to iterate over nodes:
58
-
59
- - `walk` will iterate on a node and recursively iterate on a node's children.
60
- - `each` will iterate on a node and its children, but no further.
42
+ ## Options and plugins
61
43
 
62
- ``` ruby
63
- require 'commonmarker'
64
-
65
- # parse the files specified on the command line
66
- doc = CommonMarker.render_doc("# The site\n\n [GitHub](https://www.github.com)")
44
+ ### Options
67
45
 
68
- # Walk tree and print out URLs for links
69
- doc.walk do |node|
70
- if node.type == :link
71
- printf("URL = %s\n", node.url)
72
- end
73
- end
74
-
75
- # Capitalize all regular text in headers
76
- doc.walk do |node|
77
- if node.type == :header
78
- node.each do |subnode|
79
- if subnode.type == :text
80
- subnode.string_content = subnode.string_content.upcase
81
- end
82
- end
83
- end
84
- end
85
-
86
- # Transform links to regular text
87
- doc.walk do |node|
88
- if node.type == :link
89
- node.insert_before(node.first_child)
90
- node.delete
91
- end
92
- end
93
- ```
94
-
95
- ### Creating a custom renderer
96
-
97
- You can also derive a class from CommonMarker's `HtmlRenderer` class. This produces slower output, but is far more customizable. For example:
98
-
99
- ``` ruby
100
- class MyHtmlRenderer < CommonMarker::HtmlRenderer
101
- def initialize
102
- super
103
- @headerid = 1
104
- end
105
-
106
- def header(node)
107
- block do
108
- out("<h", node.header_level, " id=\"", @headerid, "\">",
109
- :children, "</h", node.header_level, ">")
110
- @headerid += 1
111
- end
112
- end
113
- end
46
+ Commonmarker accepts the same parse, render, and extensions options that comrak does, as a hash dictionary with symbol keys:
114
47
 
115
- myrenderer = MyHtmlRenderer.new
116
- puts myrenderer.render(doc)
117
-
118
- # Print any warnings to STDERR
119
- renderer.warnings.each do |w|
120
- STDERR.write("#{w}\n")
121
- end
48
+ ```ruby
49
+ Commonmarker.to_html('"Hi *there*"', options:{
50
+ parse: { smart: true },
51
+ render: { hardbreaks: false}
52
+ })
122
53
  ```
123
54
 
124
- ## Options
125
-
126
- CommonMarker accepts the same options that CMark does, as symbols. Note that there is a distinction in CMark for "parse" options and "render" options, which are represented in the tables below.
55
+ Note that there is a distinction in comrak for "parse" options and "render" options, which are represented in the tables below.
127
56
 
128
57
  ### Parse options
129
58
 
130
- | Name | Description
131
- | ----------------------------- | -----------
132
- | `:DEFAULT` | The default parsing system.
133
- | `:SOURCEPOS` | Include source position in nodes
134
- | `:UNSAFE` | Allow raw/custom HTML and unsafe links.
135
- | `:VALIDATE_UTF8` | Replace illegal sequences with the replacement character `U+FFFD`.
136
- | `:SMART` | Use smart punctuation (curly quotes, etc.).
137
- | `:LIBERAL_HTML_TAG` | Support liberal parsing of inline HTML tags.
138
- | `:FOOTNOTES` | Parse footnotes.
139
- | `:STRIKETHROUGH_DOUBLE_TILDE` | Parse strikethroughs by double tildes (compatibility with [redcarpet](https://github.com/vmg/redcarpet))
59
+ | Name | Description | Default |
60
+ | --------------------- | ------------------------------------------------------------------------------------ | ------- |
61
+ | `smart` | Punctuation (quotes, full-stops and hyphens) are converted into 'smart' punctuation. | `false` |
62
+ | `default_info_string` | The default info string for fenced code blocks. | `""` |
140
63
 
141
64
  ### Render options
142
65
 
143
- | Name | Description |
144
- | ------------------ | ----------- |
145
- | `:DEFAULT` | The default rendering system. |
146
- | `:SOURCEPOS` | Include source position in rendered HTML. |
147
- | `:HARDBREAKS` | Treat `\n` as hardbreaks (by adding `<br/>`). |
148
- | `:UNSAFE` | Allow raw/custom HTML and unsafe links. |
149
- | `:NOBREAKS` | Translate `\n` in the source to a single whitespace. |
150
- | `:VALIDATE_UTF8` | Replace illegal sequences with the replacement character `U+FFFD`. |
151
- | `:SMART` | Use smart punctuation (curly quotes, etc.). |
152
- | `:GITHUB_PRE_LANG` | Use GitHub-style `<pre lang>` for fenced code blocks. |
153
- | `:LIBERAL_HTML_TAG` | Support liberal parsing of inline HTML tags. |
154
- | `:FOOTNOTES` | Render footnotes. |
155
- | `:STRIKETHROUGH_DOUBLE_TILDE` | Parse strikethroughs by double tildes (compatibility with [redcarpet](https://github.com/vmg/redcarpet)) |
156
- | `:TABLE_PREFER_STYLE_ATTRIBUTES` | Use `style` insted of `align` for table cells. |
157
- | `:FULL_INFO_STRING` | Include full info strings of code blocks in separate attribute. |
158
-
159
- ### Passing options
160
-
161
- To apply a single option, pass it in as a symbol argument:
162
-
163
- ``` ruby
164
- CommonMarker.render_doc("\"Hello,\" said the spider.", :SMART)
165
- # <p>“Hello,” said the spider.</p>\n
166
- ```
66
+ | Name | Description | Default |
67
+ | ----------------- | ------------------------------------------------------------------------------------------------------ | ------- |
68
+ | `hardbreaks` | [Soft line breaks](http://spec.commonmark.org/0.27/#soft-line-breaks) translate into hard line breaks. | `true` |
69
+ | `github_pre_lang` | GitHub-style `<pre lang="xyz">` is used for fenced code blocks with info tags. | `true` |
70
+ | `width` | The wrap column when outputting CommonMark. | `80` |
71
+ | `unsafe` | Allow rendering of raw HTML and potentially dangerous links. | `false` |
72
+ | `escape` | Escape raw HTML instead of clobbering it. | `false` |
167
73
 
168
- To have multiple options applied, pass in an array of symbols:
74
+ As well, there are several extensions which you can toggle in the same manner:
169
75
 
170
- ``` ruby
171
- CommonMarker.render_html("\"'Shelob' is my name.\"", [:HARDBREAKS, :SOURCEPOS])
76
+ ```ruby
77
+ Commonmarker.to_html('"Hi *there*"', options: {
78
+ extension: { footnotes: true, description_lists: true },
79
+ render: { hardbreaks: false}
80
+ })
172
81
  ```
173
82
 
174
- For more information on these options, see [the CMark documentation](https://git.io/v7nh1).
175
-
176
- ## Extensions
177
-
178
- Both `render_html` and `render_doc` take an optional third argument defining the extensions you want enabled as your CommonMark document is being processed. The documentation for these extensions are [defined in this spec](https://github.github.com/gfm/), and the rationale is provided [in this blog post](https://githubengineering.com/a-formal-spec-for-github-markdown/).
83
+ ### Extension options
84
+
85
+ | Name | Description | Default |
86
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------- | ------- |
87
+ | `strikethrough` | Enables the [strikethrough extension](https://github.github.com/gfm/#strikethrough-extension-) from the GFM spec. | `true` |
88
+ | `tagfilter` | Enables the [tagfilter extension](https://github.github.com/gfm/#disallowed-raw-html-extension-) from the GFM spec. | `true` |
89
+ | `table` | Enables the [table extension](https://github.github.com/gfm/#tables-extension-) from the GFM spec. | `true` |
90
+ | `autolink` | Enables the [autolink extension](https://github.github.com/gfm/#autolinks-extension-) from the GFM spec. | `true` |
91
+ | `tasklist` | Enables the [task list extension](https://github.github.com/gfm/#task-list-items-extension-) from the GFM spec. | `true` |
92
+ | `superscript` | Enables the superscript Comrak extension. | `false` |
93
+ | `header_ids` | Enables the header IDs Comrak extension. from the GFM spec. | `""` |
94
+ | `footnotes` | Enables the footnotes extension per `cmark-gfm`. | `false` |
95
+ | `description_lists` | Enables the description lists extension. | `false` |
96
+ | `front_matter_delimiter` | Enables the front matter extension. | `""` |
97
+ | `shortcodes` | Enables the shortcodes extension. | `true` |
98
+
99
+ For more information on these options, see [the comrak documentation](https://github.com/kivikakk/comrak#usage).
100
+
101
+ ### Plugins
102
+
103
+ In addition to the possibilities provided by generic CommonMark rendering, Commonmarker also supports plugins as a means of
104
+ providing further niceties.
105
+
106
+ #### Syntax Highlighter Plugin
107
+
108
+ The library comes with [a set of pre-existing themes](https://docs.rs/syntect/5.0.0/syntect/highlighting/struct.ThemeSet.html#implementations) for highlighting code:
109
+
110
+ - `"base16-ocean.dark"`
111
+ - `"base16-eighties.dark"`
112
+ - `"base16-mocha.dark"`
113
+ - `"base16-ocean.light"`
114
+ - `"InspiredGitHub"`
115
+ - `"Solarized (dark)"`
116
+ - `"Solarized (light)"`
117
+
118
+ ````ruby
119
+ code = <<~CODE
120
+ ```ruby
121
+ def hello
122
+ puts "hello"
123
+ end
124
+ ```
125
+ CODE
179
126
 
180
- The available extensions are:
127
+ # pass in a theme name from a pre-existing set
128
+ puts Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: "InspiredGitHub" } })
181
129
 
182
- * `:table` - This provides support for tables.
183
- * `:tasklist` - This provides support for task list items.
184
- * `:strikethrough` - This provides support for strikethroughs.
185
- * `:autolink` - This provides support for automatically converting URLs to anchor tags.
186
- * `:tagfilter` - This escapes [several "unsafe" HTML tags](https://github.github.com/gfm/#disallowed-raw-html-extension-), causing them to not have any effect.
130
+ # <pre style="background-color:#ffffff;" lang="ruby"><code>
131
+ # <span style="font-weight:bold;color:#a71d5d;">def </span><span style="font-weight:bold;color:#795da3;">hello
132
+ # </span><span style="color:#62a35c;">puts </span><span style="color:#183691;">&quot;hello&quot;
133
+ # </span><span style="font-weight:bold;color:#a71d5d;">end
134
+ # </span>
135
+ # </code></pre>
136
+ ````
187
137
 
188
- ## Output formats
138
+ By default, the plugin uses the `"base16-ocean.dark"` theme to syntax highlight code.
189
139
 
190
- Like CMark, CommonMarker can generate output in several formats: HTML, XML, plaintext, and commonmark are currently supported.
140
+ To disable this plugin, set the value to `nil`:
191
141
 
192
- ### HTML
142
+ ````ruby
143
+ code = <<~CODE
144
+ ```ruby
145
+ def hello
146
+ puts "hello"
147
+ end
148
+ ```
149
+ CODE
193
150
 
194
- The default output format, HTML, will be generated when calling `to_html` or using `--to=html` on the command line.
151
+ Commonmarker.to_html(code, plugins: { syntax_highlighter: nil })
195
152
 
196
- ```ruby
197
- doc = CommonMarker.render_doc('*Hello* world!', :DEFAULT)
198
- puts(doc.to_html)
153
+ # <pre lang="ruby"><code>def hello
154
+ # puts &quot;hello&quot;
155
+ # end
156
+ # </code></pre>
157
+ ````
199
158
 
200
- <p><em>Hello</em> world!</p>
201
- ```
159
+ To output CSS classes instead of `style` attributes, set the `theme` key to `""`:
202
160
 
203
- ### XML
204
-
205
- XML will be generated when calling `to_xml` or using `--to=xml` on the command line.
161
+ ````ruby
162
+ code = <<~CODE
163
+ ```ruby
164
+ def hello
165
+ puts "hello"
166
+ end
167
+ CODE
206
168
 
207
- ```ruby
208
- doc = CommonMarker.render_doc('*Hello* world!', :DEFAULT)
209
- puts(doc.to_xml)
210
-
211
- <?xml version="1.0" encoding="UTF-8"?>
212
- <!DOCTYPE document SYSTEM "CommonMark.dtd">
213
- <document xmlns="http://commonmark.org/xml/1.0">
214
- <paragraph>
215
- <emph>
216
- <text xml:space="preserve">Hello</text>
217
- </emph>
218
- <text xml:space="preserve"> world!</text>
219
- </paragraph>
220
- </document>
221
- ```
169
+ Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: "" } })
222
170
 
223
- ### Plaintext
171
+ # <pre class="syntax-highlighting"><code><span class="source ruby"><span class="meta function ruby"><span class="keyword control def ruby">def</span></span><span class="meta function ruby"> # <span class="entity name function ruby">hello</span></span>
172
+ # <span class="support function builtin ruby">puts</span> <span class="string quoted double ruby"><span class="punctuation definition string begin ruby">&quot;</span>hello<span class="punctuation definition string end ruby">&quot;</span></span>
173
+ # <span class="keyword control ruby">end</span>\n</span></code></pre>
174
+ ````
224
175
 
225
- Plaintext will be generated when calling `to_plaintext` or using `--to=plaintext` on the command line.
176
+ To use a custom theme, you can provide a `path` to a directory containing `.tmtheme` files to load:
226
177
 
227
178
  ```ruby
228
- doc = CommonMarker.render_doc('*Hello* world!', :DEFAULT)
229
- puts(doc.to_plaintext)
230
-
231
- Hello world!
179
+ Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: "Monokai", path: "./themes" } })
232
180
  ```
233
181
 
234
- ### Commonmark
235
-
236
- Commonmark will be generated when calling `to_commonmark` or using `--to=commonmark` on the command line.
237
-
238
- ``` ruby
239
- text = <<-TEXT
240
- 1. I am a numeric list.
241
- 2. I continue the list.
242
- * Suddenly, an unordered list!
243
- * What fun!
244
- TEXT
182
+ ## Output formats
245
183
 
246
- doc = CommonMarker.render_doc(text, :DEFAULT)
247
- puts(doc.to_commonmark)
184
+ Commonmarker can currently only generate output in one format: HTML.
248
185
 
249
- 1. I am a numeric list.
250
- 2. I continue the list.
186
+ ### HTML
251
187
 
252
- <!-- end list -->
188
+ ```ruby
189
+ puts Commonmarker.to_html('*Hello* world!')
253
190
 
254
- - Suddenly, an unordered list\!
255
- - What fun\!
191
+ # <p><em>Hello</em> world!</p>
256
192
  ```
257
193
 
258
194
  ## Developing locally
@@ -264,7 +200,7 @@ script/bootstrap
264
200
  bundle exec rake compile
265
201
  ```
266
202
 
267
- If there were no errors, you're done! Otherwise, make sure to follow the CMark dependency instructions.
203
+ If there were no errors, you're done! Otherwise, make sure to follow the comrak dependency instructions.
268
204
 
269
205
  ## Benchmarks
270
206
 
@@ -273,16 +209,21 @@ Some rough benchmarks:
273
209
  ```
274
210
  $ bundle exec rake benchmark
275
211
 
276
- input size = 11063727 bytes
212
+ input size = 11064832 bytes
277
213
 
278
- redcarpet
279
- 0.070000 0.020000 0.090000 ( 0.079641)
280
- github-markdown
281
- 0.070000 0.010000 0.080000 ( 0.083535)
214
+ Warming up --------------------------------------
215
+ redcarpet 2.000 i/100ms
216
+ commonmarker with to_html
217
+ 1.000 i/100ms
218
+ kramdown 1.000 i/100ms
219
+ Calculating -------------------------------------
220
+ redcarpet 22.317 (± 4.5%) i/s - 112.000 in 5.036374s
282
221
  commonmarker with to_html
283
- 0.100000 0.010000 0.110000 ( 0.111947)
284
- commonmarker with ruby HtmlRenderer
285
- 1.830000 0.030000 1.860000 ( 1.866203)
286
- kramdown
287
- 4.610000 0.070000 4.680000 ( 4.678398)
222
+ 5.815 0.0%) i/s - 30.000 in 5.168869s
223
+ kramdown 0.327 (± 0.0%) i/s - 2.000 in 6.121486s
224
+
225
+ Comparison:
226
+ redcarpet: 22.3 i/s
227
+ commonmarker with to_html: 5.8 i/s - 3.84x (± 0.00) slower
228
+ kramdown: 0.3 i/s - 68.30x (± 0.00) slower
288
229
  ```
@@ -0,0 +1,13 @@
1
+ [package]
2
+ name = "commonmarker"
3
+ version = "1.0.0"
4
+ edition = "2021"
5
+
6
+ [dependencies]
7
+ magnus = "0.6"
8
+ comrak = { version = "0.20", features = ["shortcodes"] }
9
+ syntect = { version = "5.1", features = ["plist-load"] }
10
+
11
+ [lib]
12
+ name = "commonmarker"
13
+ crate-type = ["cdylib"]
@@ -1,7 +1,4 @@
1
- # frozen_string_literal: true
1
+ require "mkmf"
2
+ require "rb_sys/mkmf"
2
3
 
3
- require 'mkmf'
4
-
5
- $CFLAGS << ' -std=c99'
6
-
7
- create_makefile('commonmarker/commonmarker')
4
+ create_rust_makefile("commonmarker/commonmarker")
@@ -0,0 +1,153 @@
1
+ extern crate core;
2
+
3
+ use std::path::PathBuf;
4
+
5
+ use ::syntect::highlighting::ThemeSet;
6
+ use comrak::{
7
+ adapters::SyntaxHighlighterAdapter,
8
+ markdown_to_html, markdown_to_html_with_plugins,
9
+ plugins::syntect::{SyntectAdapter, SyntectAdapterBuilder},
10
+ ComrakOptions, ComrakPlugins,
11
+ };
12
+ use magnus::{
13
+ define_module, exception, function, r_hash::ForEach, scan_args, Error, RHash, Symbol, Value,
14
+ };
15
+
16
+ mod options;
17
+ use options::iterate_options_hash;
18
+
19
+ mod plugins;
20
+ use plugins::{
21
+ syntax_highlighting::{fetch_syntax_highlighter_path, fetch_syntax_highlighter_theme},
22
+ SYNTAX_HIGHLIGHTER_PLUGIN,
23
+ };
24
+
25
+ mod utils;
26
+
27
+ pub const EMPTY_STR: &str = "";
28
+
29
+ fn commonmark_to_html(args: &[Value]) -> Result<String, magnus::Error> {
30
+ let args = scan_args::scan_args::<_, (), (), (), _, ()>(args)?;
31
+ let (rb_commonmark,): (String,) = args.required;
32
+
33
+ let kwargs = scan_args::get_kwargs::<_, (), (Option<RHash>, Option<RHash>), ()>(
34
+ args.keywords,
35
+ &[],
36
+ &["options", "plugins"],
37
+ )?;
38
+ let (rb_options, rb_plugins) = kwargs.optional;
39
+
40
+ let mut comrak_options = ComrakOptions::default();
41
+
42
+ if let Some(rb_options) = rb_options {
43
+ rb_options.foreach(|key: Symbol, value: RHash| {
44
+ iterate_options_hash(&mut comrak_options, key, value)?;
45
+ Ok(ForEach::Continue)
46
+ })?;
47
+ }
48
+
49
+ if let Some(rb_plugins) = rb_plugins {
50
+ let mut comrak_plugins = ComrakPlugins::default();
51
+
52
+ let syntax_highlighter: Option<&dyn SyntaxHighlighterAdapter>;
53
+ let adapter: SyntectAdapter;
54
+
55
+ let theme = match rb_plugins.get(Symbol::new(SYNTAX_HIGHLIGHTER_PLUGIN)) {
56
+ Some(syntax_highlighter_options) => {
57
+ match fetch_syntax_highlighter_theme(syntax_highlighter_options) {
58
+ Ok(theme) => theme,
59
+ Err(e) => {
60
+ return Err(e);
61
+ }
62
+ }
63
+ }
64
+ None => None, // no `syntax_highlighter:` defined
65
+ };
66
+
67
+ match theme {
68
+ None => syntax_highlighter = None,
69
+ Some(theme) => {
70
+ if theme.is_empty() {
71
+ // no theme? uss css classes
72
+ adapter = SyntectAdapter::new(None);
73
+ syntax_highlighter = Some(&adapter);
74
+ } else {
75
+ let path = match rb_plugins.get(Symbol::new(SYNTAX_HIGHLIGHTER_PLUGIN)) {
76
+ Some(syntax_highlighter_options) => {
77
+ fetch_syntax_highlighter_path(syntax_highlighter_options)?
78
+ }
79
+ None => PathBuf::from("".to_string()), // no `syntax_highlighter:` defined
80
+ };
81
+
82
+ if path.exists() {
83
+ if !path.is_dir() {
84
+ return Err(Error::new(
85
+ exception::arg_error(),
86
+ "`path` needs to be a directory",
87
+ ));
88
+ }
89
+
90
+ let builder = SyntectAdapterBuilder::new();
91
+ let mut ts = ThemeSet::load_defaults();
92
+
93
+ match ts.add_from_folder(&path) {
94
+ Ok(_) => {}
95
+ Err(e) => {
96
+ return Err(Error::new(
97
+ exception::arg_error(),
98
+ format!("failed to load theme set from path: {e}"),
99
+ ));
100
+ }
101
+ }
102
+
103
+ // check if the theme exists in the dir
104
+ match ts.themes.get(&theme) {
105
+ Some(theme) => theme,
106
+ None => {
107
+ return Err(Error::new(
108
+ exception::arg_error(),
109
+ format!("theme `{}` does not exist", theme),
110
+ ));
111
+ }
112
+ };
113
+
114
+ adapter = builder.theme_set(ts).theme(&theme).build();
115
+
116
+ syntax_highlighter = Some(&adapter);
117
+ } else {
118
+ // no path? default theme lookup
119
+ ThemeSet::load_defaults()
120
+ .themes
121
+ .get(&theme)
122
+ .ok_or_else(|| {
123
+ Error::new(
124
+ exception::arg_error(),
125
+ format!("theme `{}` does not exist", theme),
126
+ )
127
+ })?;
128
+ adapter = SyntectAdapter::new(Some(&theme));
129
+ syntax_highlighter = Some(&adapter);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ comrak_plugins.render.codefence_syntax_highlighter = syntax_highlighter;
135
+
136
+ Ok(markdown_to_html_with_plugins(
137
+ &rb_commonmark,
138
+ &comrak_options,
139
+ &comrak_plugins,
140
+ ))
141
+ } else {
142
+ Ok(markdown_to_html(&rb_commonmark, &comrak_options))
143
+ }
144
+ }
145
+
146
+ #[magnus::init]
147
+ fn init() -> Result<(), Error> {
148
+ let module = define_module("Commonmarker")?;
149
+
150
+ module.define_module_function("commonmark_to_html", function!(commonmark_to_html, -1))?;
151
+
152
+ Ok(())
153
+ }