commonmarker 0.23.10 → 2.0.2
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.
- checksums.yaml +4 -4
- data/Cargo.lock +1158 -0
- data/Cargo.toml +7 -0
- data/README.md +233 -172
- data/ext/commonmarker/Cargo.toml +20 -0
- data/ext/commonmarker/extconf.rb +3 -6
- data/ext/commonmarker/src/lib.rs +103 -0
- data/ext/commonmarker/src/node.rs +1167 -0
- data/ext/commonmarker/src/options.rs +216 -0
- data/ext/commonmarker/src/plugins/syntax_highlighting.rs +166 -0
- data/ext/commonmarker/src/plugins.rs +6 -0
- data/ext/commonmarker/src/utils.rs +8 -0
- data/lib/commonmarker/config.rb +91 -40
- data/lib/commonmarker/constants.rb +7 -0
- data/lib/commonmarker/extension.rb +14 -0
- data/lib/commonmarker/node/ast.rb +8 -0
- data/lib/commonmarker/node/inspect.rb +14 -4
- data/lib/commonmarker/node.rb +29 -47
- data/lib/commonmarker/renderer.rb +1 -127
- data/lib/commonmarker/utils.rb +22 -0
- data/lib/commonmarker/version.rb +2 -2
- data/lib/commonmarker.rb +27 -25
- metadata +43 -191
- data/Rakefile +0 -109
- data/bin/commonmarker +0 -118
- data/commonmarker.gemspec +0 -38
- data/ext/commonmarker/arena.c +0 -104
- data/ext/commonmarker/autolink.c +0 -508
- data/ext/commonmarker/autolink.h +0 -8
- data/ext/commonmarker/blocks.c +0 -1622
- data/ext/commonmarker/buffer.c +0 -278
- data/ext/commonmarker/buffer.h +0 -116
- data/ext/commonmarker/case_fold_switch.inc +0 -4327
- data/ext/commonmarker/chunk.h +0 -135
- data/ext/commonmarker/cmark-gfm-core-extensions.h +0 -54
- data/ext/commonmarker/cmark-gfm-extension_api.h +0 -737
- data/ext/commonmarker/cmark-gfm-extensions_export.h +0 -42
- data/ext/commonmarker/cmark-gfm.h +0 -833
- data/ext/commonmarker/cmark-gfm_export.h +0 -42
- data/ext/commonmarker/cmark-gfm_version.h +0 -7
- data/ext/commonmarker/cmark.c +0 -55
- data/ext/commonmarker/cmark_ctype.c +0 -44
- data/ext/commonmarker/cmark_ctype.h +0 -33
- data/ext/commonmarker/commonmark.c +0 -514
- data/ext/commonmarker/commonmarker.c +0 -1308
- data/ext/commonmarker/commonmarker.h +0 -16
- data/ext/commonmarker/config.h +0 -76
- data/ext/commonmarker/core-extensions.c +0 -27
- data/ext/commonmarker/entities.inc +0 -2138
- data/ext/commonmarker/ext_scanners.c +0 -879
- data/ext/commonmarker/ext_scanners.h +0 -24
- data/ext/commonmarker/footnotes.c +0 -63
- data/ext/commonmarker/footnotes.h +0 -27
- data/ext/commonmarker/houdini.h +0 -57
- data/ext/commonmarker/houdini_href_e.c +0 -100
- data/ext/commonmarker/houdini_html_e.c +0 -66
- data/ext/commonmarker/houdini_html_u.c +0 -149
- data/ext/commonmarker/html.c +0 -502
- data/ext/commonmarker/html.h +0 -27
- data/ext/commonmarker/inlines.c +0 -1788
- data/ext/commonmarker/inlines.h +0 -29
- data/ext/commonmarker/iterator.c +0 -159
- data/ext/commonmarker/iterator.h +0 -26
- data/ext/commonmarker/latex.c +0 -468
- data/ext/commonmarker/linked_list.c +0 -37
- data/ext/commonmarker/man.c +0 -274
- data/ext/commonmarker/map.c +0 -129
- data/ext/commonmarker/map.h +0 -44
- data/ext/commonmarker/node.c +0 -1045
- data/ext/commonmarker/node.h +0 -167
- data/ext/commonmarker/parser.h +0 -59
- data/ext/commonmarker/plaintext.c +0 -218
- data/ext/commonmarker/plugin.c +0 -36
- data/ext/commonmarker/plugin.h +0 -34
- data/ext/commonmarker/references.c +0 -43
- data/ext/commonmarker/references.h +0 -26
- data/ext/commonmarker/registry.c +0 -63
- data/ext/commonmarker/registry.h +0 -24
- data/ext/commonmarker/render.c +0 -213
- data/ext/commonmarker/render.h +0 -62
- data/ext/commonmarker/scanners.c +0 -14056
- data/ext/commonmarker/scanners.h +0 -70
- data/ext/commonmarker/scanners.re +0 -341
- data/ext/commonmarker/strikethrough.c +0 -167
- data/ext/commonmarker/strikethrough.h +0 -9
- data/ext/commonmarker/syntax_extension.c +0 -149
- data/ext/commonmarker/syntax_extension.h +0 -34
- data/ext/commonmarker/table.c +0 -917
- data/ext/commonmarker/table.h +0 -12
- data/ext/commonmarker/tagfilter.c +0 -60
- data/ext/commonmarker/tagfilter.h +0 -8
- data/ext/commonmarker/tasklist.c +0 -156
- data/ext/commonmarker/tasklist.h +0 -8
- data/ext/commonmarker/utf8.c +0 -317
- data/ext/commonmarker/utf8.h +0 -35
- data/ext/commonmarker/xml.c +0 -182
- data/lib/commonmarker/renderer/html_renderer.rb +0 -256
data/Cargo.toml
ADDED
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# Commonmarker
|
2
2
|
|
3
|
-
|
3
|
+
Ruby wrapper for Rust's [comrak](https://github.com/kivikakk/comrak) crate.
|
4
4
|
|
5
|
-
|
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.
|
5
|
+
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.
|
7
6
|
|
8
|
-
|
7
|
+
> [!NOTE]
|
8
|
+
> By default, several extensions not in any spec have been enabled, for the sake of end user convenience when generating HTML.
|
9
|
+
>
|
10
|
+
> For more information on the available options and extensions, see [the documentation below](#options-and-plugins).
|
9
11
|
|
10
12
|
## Installation
|
11
13
|
|
@@ -25,45 +27,75 @@ Or install it yourself as:
|
|
25
27
|
|
26
28
|
### Converting to HTML
|
27
29
|
|
28
|
-
Call `
|
30
|
+
Call `to_html` on a string to convert it to HTML:
|
29
31
|
|
30
|
-
```
|
32
|
+
```ruby
|
31
33
|
require 'commonmarker'
|
32
|
-
|
33
|
-
|
34
|
+
Commonmarker.to_html('"Hi *there*"', options: {
|
35
|
+
parse: { smart: true }
|
36
|
+
})
|
37
|
+
# => <p>“Hi <em>there</em>”</p>\n
|
34
38
|
```
|
35
39
|
|
36
|
-
The second argument is optional--[see below](#options) for more information.
|
40
|
+
(The second argument is optional--[see below](#options-and-plugins) for more information.)
|
37
41
|
|
38
42
|
### Generating a document
|
39
43
|
|
40
|
-
You can also parse a string to receive a `
|
44
|
+
You can also parse a string to receive a `:document` node. You can then print that node to HTML, iterate over the children, and do other fun node stuff. For example:
|
41
45
|
|
42
|
-
```
|
46
|
+
```ruby
|
43
47
|
require 'commonmarker'
|
44
48
|
|
45
|
-
doc =
|
46
|
-
|
49
|
+
doc = Commonmarker.parse("*Hello* world", options: {
|
50
|
+
parse: { smart: true }
|
51
|
+
})
|
52
|
+
puts(doc.to_html) # => <p><em>Hello</em> world</p>\n
|
47
53
|
|
48
54
|
doc.walk do |node|
|
49
|
-
puts node.type # [:document, :paragraph, :
|
55
|
+
puts node.type # => [:document, :paragraph, :emph, :text, :text]
|
50
56
|
end
|
51
57
|
```
|
52
58
|
|
53
|
-
The second argument is optional--[see below](#options) for more information.
|
59
|
+
(The second argument is optional--[see below](#options-and-plugins) for more information.)
|
60
|
+
|
61
|
+
When it comes to modifying the document, you can perform the following operations:
|
62
|
+
|
63
|
+
- `insert_before`
|
64
|
+
- `insert_after`
|
65
|
+
- `prepend_child`
|
66
|
+
- `append_child`
|
67
|
+
- `delete`
|
68
|
+
|
69
|
+
You can also get the source position of a node by calling `source_position`:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
doc = Commonmarker.parse("*Hello* world")
|
73
|
+
puts doc.first_child.first_child.source_position
|
74
|
+
# => {:start_line=>1, :start_column=>1, :end_line=>1, :end_column=>7}
|
75
|
+
```
|
76
|
+
|
77
|
+
You can also modify the following attributes:
|
54
78
|
|
55
|
-
|
79
|
+
- `url`
|
80
|
+
- `title`
|
81
|
+
- `header_level`
|
82
|
+
- `list_type`
|
83
|
+
- `list_start`
|
84
|
+
- `list_tight`
|
85
|
+
- `fence_info`
|
86
|
+
|
87
|
+
#### Example: Walking the AST
|
56
88
|
|
57
89
|
You can use `walk` or `each` to iterate over nodes:
|
58
90
|
|
59
91
|
- `walk` will iterate on a node and recursively iterate on a node's children.
|
60
|
-
- `each` will iterate on a node
|
92
|
+
- `each` will iterate on a node's direct children, but no further.
|
61
93
|
|
62
|
-
```
|
94
|
+
```ruby
|
63
95
|
require 'commonmarker'
|
64
96
|
|
65
|
-
# parse
|
66
|
-
doc =
|
97
|
+
# parse some string
|
98
|
+
doc = Commonmarker.parse("# The site\n\n [GitHub](https://www.github.com)")
|
67
99
|
|
68
100
|
# Walk tree and print out URLs for links
|
69
101
|
doc.walk do |node|
|
@@ -71,17 +103,7 @@ doc.walk do |node|
|
|
71
103
|
printf("URL = %s\n", node.url)
|
72
104
|
end
|
73
105
|
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
|
106
|
+
# => URL = https://www.github.com
|
85
107
|
|
86
108
|
# Transform links to regular text
|
87
109
|
doc.walk do |node|
|
@@ -90,169 +112,197 @@ doc.walk do |node|
|
|
90
112
|
node.delete
|
91
113
|
end
|
92
114
|
end
|
115
|
+
# => <h1><a href=\"#the-site\"></a>The site</h1>\n<p>GitHub</p>\n
|
93
116
|
```
|
94
117
|
|
95
|
-
|
118
|
+
#### Example: Converting a document back into raw CommonMark
|
96
119
|
|
97
|
-
You can
|
120
|
+
You can use `to_commonmark` on a node to render it as raw text:
|
98
121
|
|
99
|
-
```
|
100
|
-
|
101
|
-
def initialize
|
102
|
-
super
|
103
|
-
@headerid = 1
|
104
|
-
end
|
122
|
+
```ruby
|
123
|
+
require 'commonmarker'
|
105
124
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
125
|
+
# parse some string
|
126
|
+
doc = Commonmarker.parse("# The site\n\n [GitHub](https://www.github.com)")
|
127
|
+
|
128
|
+
# Transform links to regular text
|
129
|
+
doc.walk do |node|
|
130
|
+
if node.type == :link
|
131
|
+
node.insert_before(node.first_child)
|
132
|
+
node.delete
|
112
133
|
end
|
113
134
|
end
|
114
135
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# Print any warnings to STDERR
|
119
|
-
renderer.warnings.each do |w|
|
120
|
-
STDERR.write("#{w}\n")
|
121
|
-
end
|
136
|
+
doc.to_commonmark
|
137
|
+
# => # The site\n\nGitHub\n
|
122
138
|
```
|
123
139
|
|
124
|
-
## Options
|
140
|
+
## Options and plugins
|
125
141
|
|
126
|
-
|
142
|
+
### Options
|
127
143
|
|
128
|
-
|
144
|
+
Commonmarker accepts the same parse, render, and extensions options that comrak does, as a hash dictionary with symbol keys:
|
129
145
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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))
|
140
|
-
|
141
|
-
### Render options
|
142
|
-
|
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
|
146
|
+
```ruby
|
147
|
+
Commonmarker.to_html('"Hi *there*"', options:{
|
148
|
+
parse: { smart: true },
|
149
|
+
render: { hardbreaks: false}
|
150
|
+
})
|
166
151
|
```
|
167
152
|
|
168
|
-
|
153
|
+
Note that there is a distinction in comrak for "parse" options and "render" options, which are represented in the tables below. As well, if you wish to disable any-non boolean option, pass in `nil`.
|
169
154
|
|
170
|
-
|
171
|
-
CommonMarker.render_html("\"'Shelob' is my name.\"", [:HARDBREAKS, :SOURCEPOS])
|
172
|
-
```
|
155
|
+
### Parse options
|
173
156
|
|
174
|
-
|
157
|
+
| Name | Description | Default |
|
158
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
159
|
+
| `smart` | Punctuation (quotes, full-stops and hyphens) are converted into 'smart' punctuation. | `false` |
|
160
|
+
| `default_info_string` | The default info string for fenced code blocks. | `""` |
|
161
|
+
| `relaxed_tasklist_matching` | Enables relaxing of the tasklist extension matching, allowing any non-space to be used for the "checked" state instead of only `x` and `X`. | `false` |
|
162
|
+
| `relaxed_autolinks` | Enable relaxing of the autolink extension parsing, allowing links to be recognized when in brackets, as well as permitting any url scheme. | `false` |
|
175
163
|
|
176
|
-
|
164
|
+
### Render options
|
177
165
|
|
178
|
-
|
166
|
+
| Name | Description | Default |
|
167
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------ | ------- |
|
168
|
+
| `hardbreaks` | [Soft line breaks](http://spec.commonmark.org/0.27/#soft-line-breaks) translate into hard line breaks. | `true` |
|
169
|
+
| `github_pre_lang` | GitHub-style `<pre lang="xyz">` is used for fenced code blocks with info tags. | `true` |
|
170
|
+
| `full_info_string` | Gives info string data after a space in a `data-meta` attribute on code blocks. | `false` |
|
171
|
+
| `width` | The wrap column when outputting CommonMark. | `80` |
|
172
|
+
| `unsafe` | Allow rendering of raw HTML and potentially dangerous links. | `false` |
|
173
|
+
| `escape` | Escape raw HTML instead of clobbering it. | `false` |
|
174
|
+
| `sourcepos` | Include source position attribute in HTML and XML output. | `false` |
|
175
|
+
| `escaped_char_spans` | Wrap escaped characters in span tags. | `true` |
|
176
|
+
| `ignore_setext` | Ignores setext-style headings. | `false` |
|
177
|
+
| `ignore_empty_links` | Ignores empty links, leaving the Markdown text in place. | `false` |
|
178
|
+
| `gfm_quirks` | Outputs HTML with GFM-style quirks; namely, not nesting `<strong>` inlines. | `false` |
|
179
|
+
| `prefer_fenced` | Always output fenced code blocks, even where an indented one could be used. | `false` |
|
180
|
+
|
181
|
+
As well, there are several extensions which you can toggle in the same manner:
|
179
182
|
|
180
|
-
|
183
|
+
```ruby
|
184
|
+
Commonmarker.to_html('"Hi *there*"', options: {
|
185
|
+
extension: { footnotes: true, description_lists: true },
|
186
|
+
render: { hardbreaks: false }
|
187
|
+
})
|
188
|
+
```
|
181
189
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
190
|
+
### Extension options
|
191
|
+
|
192
|
+
| Name | Description | Default |
|
193
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------- |
|
194
|
+
| `strikethrough` | Enables the [strikethrough extension](https://github.github.com/gfm/#strikethrough-extension-) from the GFM spec. | `true` |
|
195
|
+
| `tagfilter` | Enables the [tagfilter extension](https://github.github.com/gfm/#disallowed-raw-html-extension-) from the GFM spec. | `true` |
|
196
|
+
| `table` | Enables the [table extension](https://github.github.com/gfm/#tables-extension-) from the GFM spec. | `true` |
|
197
|
+
| `autolink` | Enables the [autolink extension](https://github.github.com/gfm/#autolinks-extension-) from the GFM spec. | `true` |
|
198
|
+
| `tasklist` | Enables the [task list extension](https://github.github.com/gfm/#task-list-items-extension-) from the GFM spec. | `true` |
|
199
|
+
| `superscript` | Enables the superscript Comrak extension. | `false` |
|
200
|
+
| `header_ids` | Enables the header IDs Comrak extension. from the GFM spec. | `""` |
|
201
|
+
| `footnotes` | Enables the footnotes extension per `cmark-gfm`. | `false` |
|
202
|
+
| `description_lists` | Enables the description lists extension. | `false` |
|
203
|
+
| `front_matter_delimiter` | Enables the front matter extension. | `""` |
|
204
|
+
| `multiline_block_quotes` | Enables the multiline block quotes extension. | `false` |
|
205
|
+
| `math_dollars`, `math_code` | Enables the math extension. | `false` |
|
206
|
+
| `shortcodes` | Enables the shortcodes extension. | `true` |
|
207
|
+
| `wikilinks_title_before_pipe` | Enables the wikilinks extension, placing the title before the dividing pipe. | `false` |
|
208
|
+
| `wikilinks_title_after_pipe` | Enables the shortcodes extension, placing the title after the dividing pipe. | `false` |
|
209
|
+
| `underline` | Enables the underline extension. | `false` |
|
210
|
+
| `spoiler` | Enables the spoiler extension. | `false` |
|
211
|
+
| `greentext` | Enables the greentext extension. | `false` |
|
212
|
+
|
213
|
+
For more information on these options, see [the comrak documentation](https://github.com/kivikakk/comrak#usage).
|
214
|
+
|
215
|
+
### Plugins
|
216
|
+
|
217
|
+
In addition to the possibilities provided by generic CommonMark rendering, Commonmarker also supports plugins as a means of
|
218
|
+
providing further niceties.
|
219
|
+
|
220
|
+
#### Syntax Highlighter Plugin
|
221
|
+
|
222
|
+
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:
|
223
|
+
|
224
|
+
- `"base16-ocean.dark"`
|
225
|
+
- `"base16-eighties.dark"`
|
226
|
+
- `"base16-mocha.dark"`
|
227
|
+
- `"base16-ocean.light"`
|
228
|
+
- `"InspiredGitHub"`
|
229
|
+
- `"Solarized (dark)"`
|
230
|
+
- `"Solarized (light)"`
|
231
|
+
|
232
|
+
````ruby
|
233
|
+
code = <<~CODE
|
234
|
+
```ruby
|
235
|
+
def hello
|
236
|
+
puts "hello"
|
237
|
+
end
|
238
|
+
```
|
239
|
+
CODE
|
187
240
|
|
188
|
-
|
241
|
+
# pass in a theme name from a pre-existing set
|
242
|
+
puts Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: "InspiredGitHub" } })
|
189
243
|
|
190
|
-
|
244
|
+
# <pre style="background-color:#ffffff;" lang="ruby"><code>
|
245
|
+
# <span style="font-weight:bold;color:#a71d5d;">def </span><span style="font-weight:bold;color:#795da3;">hello
|
246
|
+
# </span><span style="color:#62a35c;">puts </span><span style="color:#183691;">"hello"
|
247
|
+
# </span><span style="font-weight:bold;color:#a71d5d;">end
|
248
|
+
# </span>
|
249
|
+
# </code></pre>
|
250
|
+
````
|
191
251
|
|
192
|
-
|
252
|
+
By default, the plugin uses the `"base16-ocean.dark"` theme to syntax highlight code.
|
193
253
|
|
194
|
-
|
254
|
+
To disable this plugin, set the value to `nil`:
|
195
255
|
|
196
|
-
|
197
|
-
|
198
|
-
|
256
|
+
````ruby
|
257
|
+
code = <<~CODE
|
258
|
+
```ruby
|
259
|
+
def hello
|
260
|
+
puts "hello"
|
261
|
+
end
|
262
|
+
```
|
263
|
+
CODE
|
199
264
|
|
200
|
-
|
201
|
-
```
|
265
|
+
Commonmarker.to_html(code, plugins: { syntax_highlighter: nil })
|
202
266
|
|
203
|
-
|
267
|
+
# <pre lang="ruby"><code>def hello
|
268
|
+
# puts "hello"
|
269
|
+
# end
|
270
|
+
# </code></pre>
|
271
|
+
````
|
204
272
|
|
205
|
-
|
273
|
+
To output CSS classes instead of `style` attributes, set the `theme` key to `""`:
|
206
274
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
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
|
-
```
|
275
|
+
````ruby
|
276
|
+
code = <<~CODE
|
277
|
+
```ruby
|
278
|
+
def hello
|
279
|
+
puts "hello"
|
280
|
+
end
|
281
|
+
CODE
|
222
282
|
|
223
|
-
|
283
|
+
Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: "" } })
|
224
284
|
|
225
|
-
|
285
|
+
# <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>
|
286
|
+
# <span class="support function builtin ruby">puts</span> <span class="string quoted double ruby"><span class="punctuation definition string begin ruby">"</span>hello<span class="punctuation definition string end ruby">"</span></span>
|
287
|
+
# <span class="keyword control ruby">end</span>\n</span></code></pre>
|
288
|
+
````
|
226
289
|
|
227
|
-
|
228
|
-
doc = CommonMarker.render_doc('*Hello* world!', :DEFAULT)
|
229
|
-
puts(doc.to_plaintext)
|
290
|
+
To use a custom theme, you can provide a `path` to a directory containing `.tmtheme` files to load:
|
230
291
|
|
231
|
-
|
292
|
+
```ruby
|
293
|
+
Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: "Monokai", path: "./themes" } })
|
232
294
|
```
|
233
295
|
|
234
|
-
|
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
|
296
|
+
## Output formats
|
245
297
|
|
246
|
-
|
247
|
-
puts(doc.to_commonmark)
|
298
|
+
Commonmarker can currently only generate output in one format: HTML.
|
248
299
|
|
249
|
-
|
250
|
-
2. I continue the list.
|
300
|
+
### HTML
|
251
301
|
|
252
|
-
|
302
|
+
```ruby
|
303
|
+
puts Commonmarker.to_html('*Hello* world!')
|
253
304
|
|
254
|
-
|
255
|
-
- What fun\!
|
305
|
+
# <p><em>Hello</em> world!</p>
|
256
306
|
```
|
257
307
|
|
258
308
|
## Developing locally
|
@@ -264,25 +314,36 @@ script/bootstrap
|
|
264
314
|
bundle exec rake compile
|
265
315
|
```
|
266
316
|
|
267
|
-
If there were no errors, you're done! Otherwise, make sure to follow the
|
317
|
+
If there were no errors, you're done! Otherwise, make sure to follow the comrak dependency instructions.
|
268
318
|
|
269
319
|
## Benchmarks
|
270
320
|
|
271
|
-
Some rough benchmarks:
|
272
|
-
|
273
321
|
```
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
322
|
+
❯ bundle exec rake benchmark
|
323
|
+
input size = 11064832 bytes
|
324
|
+
|
325
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
|
326
|
+
Warming up --------------------------------------
|
327
|
+
Markly.render_html 1.000 i/100ms
|
328
|
+
Markly::Node#to_html 1.000 i/100ms
|
329
|
+
Commonmarker.to_html 1.000 i/100ms
|
330
|
+
Commonmarker::Node.to_html
|
331
|
+
1.000 i/100ms
|
332
|
+
Kramdown::Document#to_html
|
333
|
+
1.000 i/100ms
|
334
|
+
Calculating -------------------------------------
|
335
|
+
Markly.render_html 15.606 (±25.6%) i/s - 71.000 in 5.047132s
|
336
|
+
Markly::Node#to_html 15.692 (±25.5%) i/s - 72.000 in 5.095810s
|
337
|
+
Commonmarker.to_html 4.482 (± 0.0%) i/s - 23.000 in 5.137680s
|
338
|
+
Commonmarker::Node.to_html
|
339
|
+
5.092 (±19.6%) i/s - 25.000 in 5.072220s
|
340
|
+
Kramdown::Document#to_html
|
341
|
+
0.379 (± 0.0%) i/s - 2.000 in 5.277770s
|
342
|
+
|
343
|
+
Comparison:
|
344
|
+
Markly::Node#to_html: 15.7 i/s
|
345
|
+
Markly.render_html: 15.6 i/s - same-ish: difference falls within error
|
346
|
+
Commonmarker::Node.to_html: 5.1 i/s - 3.08x slower
|
347
|
+
Commonmarker.to_html: 4.5 i/s - 3.50x slower
|
348
|
+
Kramdown::Document#to_html: 0.4 i/s - 41.40x slower
|
288
349
|
```
|
@@ -0,0 +1,20 @@
|
|
1
|
+
[package]
|
2
|
+
name = "commonmarker"
|
3
|
+
version = "1.0.0"
|
4
|
+
edition = "2021"
|
5
|
+
rust-version = "1.75.0"
|
6
|
+
publish = false
|
7
|
+
|
8
|
+
[dependencies]
|
9
|
+
magnus = { version = "0.7", features = ["rb-sys"] }
|
10
|
+
rb-sys = { version = "*", default-features = false, features = [
|
11
|
+
"stable-api-compiled-fallback",
|
12
|
+
] }
|
13
|
+
comrak = { version = "0.32", features = ["shortcodes"] }
|
14
|
+
syntect = { version = "5.2", features = ["plist-load"] }
|
15
|
+
typed-arena = "2.0"
|
16
|
+
rctree = "0.6"
|
17
|
+
|
18
|
+
[lib]
|
19
|
+
name = "commonmarker"
|
20
|
+
crate-type = ["cdylib"]
|
data/ext/commonmarker/extconf.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
extern crate core;
|
2
|
+
|
3
|
+
use comrak::{markdown_to_html_with_plugins, parse_document, ComrakOptions};
|
4
|
+
use magnus::{define_module, function, r_hash::ForEach, scan_args, Error, RHash, Symbol, Value};
|
5
|
+
use node::CommonmarkerNode;
|
6
|
+
use plugins::syntax_highlighting::construct_syntax_highlighter_from_plugin;
|
7
|
+
|
8
|
+
mod options;
|
9
|
+
use options::iterate_options_hash;
|
10
|
+
|
11
|
+
mod plugins;
|
12
|
+
|
13
|
+
use typed_arena::Arena;
|
14
|
+
|
15
|
+
mod node;
|
16
|
+
mod utils;
|
17
|
+
|
18
|
+
pub const EMPTY_STR: &str = "";
|
19
|
+
|
20
|
+
fn commonmark_parse(args: &[Value]) -> Result<CommonmarkerNode, magnus::Error> {
|
21
|
+
let args = scan_args::scan_args::<_, (), (), (), _, ()>(args)?;
|
22
|
+
let (rb_commonmark,): (String,) = args.required;
|
23
|
+
|
24
|
+
let kwargs =
|
25
|
+
scan_args::get_kwargs::<_, (), (Option<RHash>,), ()>(args.keywords, &[], &["options"])?;
|
26
|
+
let (rb_options,) = kwargs.optional;
|
27
|
+
|
28
|
+
let mut comrak_options = ComrakOptions::default();
|
29
|
+
|
30
|
+
if let Some(rb_options) = rb_options {
|
31
|
+
rb_options.foreach(|key: Symbol, value: RHash| {
|
32
|
+
iterate_options_hash(&mut comrak_options, key, value)?;
|
33
|
+
Ok(ForEach::Continue)
|
34
|
+
})?;
|
35
|
+
}
|
36
|
+
|
37
|
+
let arena = Arena::new();
|
38
|
+
let root = parse_document(&arena, &rb_commonmark, &comrak_options);
|
39
|
+
|
40
|
+
CommonmarkerNode::new_from_comrak_node(root)
|
41
|
+
}
|
42
|
+
|
43
|
+
fn commonmark_to_html(args: &[Value]) -> Result<String, magnus::Error> {
|
44
|
+
let args = scan_args::scan_args::<_, (), (), (), _, ()>(args)?;
|
45
|
+
let (rb_commonmark,): (String,) = args.required;
|
46
|
+
|
47
|
+
let kwargs = scan_args::get_kwargs::<_, (), (Option<RHash>, Option<RHash>), ()>(
|
48
|
+
args.keywords,
|
49
|
+
&[],
|
50
|
+
&["options", "plugins"],
|
51
|
+
)?;
|
52
|
+
let (rb_options, rb_plugins) = kwargs.optional;
|
53
|
+
|
54
|
+
let comrak_options = match format_options(rb_options) {
|
55
|
+
Ok(options) => options,
|
56
|
+
Err(err) => return Err(err),
|
57
|
+
};
|
58
|
+
|
59
|
+
let mut comrak_plugins = comrak::Plugins::default();
|
60
|
+
|
61
|
+
let syntect_adapter = match construct_syntax_highlighter_from_plugin(rb_plugins) {
|
62
|
+
Ok(Some(adapter)) => Some(adapter),
|
63
|
+
Ok(None) => None,
|
64
|
+
Err(err) => return Err(err),
|
65
|
+
};
|
66
|
+
|
67
|
+
match syntect_adapter {
|
68
|
+
Some(ref adapter) => comrak_plugins.render.codefence_syntax_highlighter = Some(adapter),
|
69
|
+
None => comrak_plugins.render.codefence_syntax_highlighter = None,
|
70
|
+
}
|
71
|
+
|
72
|
+
Ok(markdown_to_html_with_plugins(
|
73
|
+
&rb_commonmark,
|
74
|
+
&comrak_options,
|
75
|
+
&comrak_plugins,
|
76
|
+
))
|
77
|
+
}
|
78
|
+
|
79
|
+
fn format_options<'c>(rb_options: Option<RHash>) -> Result<comrak::Options<'c>, magnus::Error> {
|
80
|
+
let mut comrak_options = ComrakOptions::default();
|
81
|
+
|
82
|
+
if let Some(rb_options) = rb_options {
|
83
|
+
rb_options.foreach(|key: Symbol, value: RHash| {
|
84
|
+
iterate_options_hash(&mut comrak_options, key, value)?;
|
85
|
+
Ok(ForEach::Continue)
|
86
|
+
})?;
|
87
|
+
}
|
88
|
+
|
89
|
+
Ok(comrak_options)
|
90
|
+
}
|
91
|
+
|
92
|
+
#[magnus::init]
|
93
|
+
fn init() -> Result<(), Error> {
|
94
|
+
let m_commonmarker = define_module("Commonmarker")?;
|
95
|
+
|
96
|
+
m_commonmarker.define_module_function("commonmark_parse", function!(commonmark_parse, -1))?;
|
97
|
+
m_commonmarker
|
98
|
+
.define_module_function("commonmark_to_html", function!(commonmark_to_html, -1))?;
|
99
|
+
|
100
|
+
node::init(m_commonmarker).expect("cannot define Commonmarker::Node class");
|
101
|
+
|
102
|
+
Ok(())
|
103
|
+
}
|