commonmarker 0.21.2 → 0.23.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of commonmarker might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +83 -8
- data/bin/commonmarker +34 -14
- data/commonmarker.gemspec +3 -3
- data/ext/commonmarker/blocks.c +13 -2
- data/ext/commonmarker/cmark-gfm_version.h +2 -2
- data/ext/commonmarker/commonmark.c +14 -4
- data/ext/commonmarker/commonmarker.c +81 -29
- data/ext/commonmarker/ext_scanners.c +360 -640
- data/ext/commonmarker/footnotes.c +23 -0
- data/ext/commonmarker/footnotes.h +2 -0
- data/ext/commonmarker/html.c +40 -19
- data/ext/commonmarker/inlines.c +69 -11
- data/ext/commonmarker/node.h +7 -0
- data/ext/commonmarker/table.c +98 -53
- data/lib/commonmarker/config.rb +36 -39
- data/lib/commonmarker/errors.rb +12 -0
- data/lib/commonmarker/node/inspect.rb +3 -5
- data/lib/commonmarker/node.rb +10 -0
- data/lib/commonmarker/renderer.rb +1 -1
- data/lib/commonmarker/version.rb +1 -1
- data/lib/commonmarker.rb +1 -3
- data/test/benchmark.rb +25 -18
- data/test/test_basics.rb +17 -0
- data/test/test_commands.rb +41 -0
- data/test/test_encoding.rb +3 -0
- data/test/test_extensions.rb +3 -0
- data/test/test_footnotes.rb +24 -12
- data/test/test_maliciousness.rb +1 -6
- data/test/test_renderer.rb +17 -0
- data/test/test_smartpunct.rb +5 -2
- data/test/test_xml.rb +107 -0
- metadata +30 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc6d71b6e85fb61abc438252b07369d3264982cf8fb327d96e5e8333bb23841e
|
4
|
+
data.tar.gz: 1911965561ddf20104db09c44c4e5d25f65a277a28b825bc0c03bb172779a623
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59737cb433c3f4f3d53e06d3466f1f3dcd8a40e201e8b0f26be4d553f45667137e05d980100304e720d0e8fda178da3eaa9e421608cf4e53c6d159ff9261ae3e
|
7
|
+
data.tar.gz: c3088c3219da29bdb0356f46a5b7a7f2881410c825e101f7ced3964760bfcfcb5cef57e7f3ebf5bd9f686b974ad80887fc93899e616afb211dc0e648d6352cd2
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# CommonMarker
|
2
2
|
|
3
|
-
|
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)
|
4
4
|
|
5
5
|
Ruby wrapper for [libcmark-gfm](https://github.com/github/cmark),
|
6
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.
|
@@ -130,26 +130,31 @@ CommonMarker accepts the same options that CMark does, as symbols. Note that the
|
|
130
130
|
| Name | Description
|
131
131
|
| ----------------------------- | -----------
|
132
132
|
| `:DEFAULT` | The default parsing system.
|
133
|
+
| `:SOURCEPOS` | Include source position in nodes
|
133
134
|
| `:UNSAFE` | Allow raw/custom HTML and unsafe links.
|
134
|
-
| `:
|
135
|
-
| `:LIBERAL_HTML_TAG` | Support liberal parsing of inline HTML tags.
|
135
|
+
| `:VALIDATE_UTF8` | Replace illegal sequences with the replacement character `U+FFFD`.
|
136
136
|
| `:SMART` | Use smart punctuation (curly quotes, etc.).
|
137
|
+
| `:LIBERAL_HTML_TAG` | Support liberal parsing of inline HTML tags.
|
138
|
+
| `:FOOTNOTES` | Parse footnotes.
|
137
139
|
| `:STRIKETHROUGH_DOUBLE_TILDE` | Parse strikethroughs by double tildes (compatibility with [redcarpet](https://github.com/vmg/redcarpet))
|
138
|
-
| `:VALIDATE_UTF8` | Replace illegal sequences with the replacement character `U+FFFD`.
|
139
140
|
|
140
141
|
### Render options
|
141
142
|
|
142
143
|
| Name | Description |
|
143
144
|
| ------------------ | ----------- |
|
144
145
|
| `:DEFAULT` | The default rendering system. |
|
145
|
-
| `:
|
146
|
-
| `:GITHUB_PRE_LANG` | Use GitHub-style `<pre lang>` for fenced code blocks. |
|
146
|
+
| `:SOURCEPOS` | Include source position in rendered HTML. |
|
147
147
|
| `:HARDBREAKS` | Treat `\n` as hardbreaks (by adding `<br/>`). |
|
148
|
+
| `:UNSAFE` | Allow raw/custom HTML and unsafe links. |
|
148
149
|
| `:NOBREAKS` | Translate `\n` in the source to a single whitespace. |
|
149
|
-
| `:
|
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)) |
|
150
156
|
| `:TABLE_PREFER_STYLE_ATTRIBUTES` | Use `style` insted of `align` for table cells. |
|
151
157
|
| `:FULL_INFO_STRING` | Include full info strings of code blocks in separate attribute. |
|
152
|
-
| `:FOOTNOTES` | Render footnotes. |
|
153
158
|
|
154
159
|
### Passing options
|
155
160
|
|
@@ -180,6 +185,76 @@ The available extensions are:
|
|
180
185
|
* `:autolink` - This provides support for automatically converting URLs to anchor tags.
|
181
186
|
* `:tagfilter` - This escapes [several "unsafe" HTML tags](https://github.github.com/gfm/#disallowed-raw-html-extension-), causing them to not have any effect.
|
182
187
|
|
188
|
+
## Output formats
|
189
|
+
|
190
|
+
Like CMark, CommonMarker can generate output in several formats: HTML, XML, plaintext, and commonmark are currently supported.
|
191
|
+
|
192
|
+
### HTML
|
193
|
+
|
194
|
+
The default output format, HTML, will be generated when calling `to_html` or using `--to=html` on the command line.
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
doc = CommonMarker.render_doc('*Hello* world!', :DEFAULT)
|
198
|
+
puts(doc.to_html)
|
199
|
+
|
200
|
+
<p><em>Hello</em> world!</p>
|
201
|
+
```
|
202
|
+
|
203
|
+
### XML
|
204
|
+
|
205
|
+
XML will be generated when calling `to_xml` or using `--to=xml` on the command line.
|
206
|
+
|
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
|
+
```
|
222
|
+
|
223
|
+
### Plaintext
|
224
|
+
|
225
|
+
Plaintext will be generated when calling `to_plaintext` or using `--to=plaintext` on the command line.
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
doc = CommonMarker.render_doc('*Hello* world!', :DEFAULT)
|
229
|
+
puts(doc.to_plaintext)
|
230
|
+
|
231
|
+
Hello world!
|
232
|
+
```
|
233
|
+
|
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
|
245
|
+
|
246
|
+
doc = CommonMarker.render_doc(text, :DEFAULT)
|
247
|
+
puts(doc.to_commonmark)
|
248
|
+
|
249
|
+
1. I am a numeric list.
|
250
|
+
2. I continue the list.
|
251
|
+
|
252
|
+
<!-- end list -->
|
253
|
+
|
254
|
+
- Suddenly, an unordered list\!
|
255
|
+
- What fun\!
|
256
|
+
```
|
257
|
+
|
183
258
|
## Developing locally
|
184
259
|
|
185
260
|
After cloning the repo:
|
data/bin/commonmarker
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'optparse'
|
5
|
-
require 'ostruct'
|
6
5
|
|
7
6
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
8
7
|
require 'commonmarker'
|
@@ -11,17 +10,16 @@ root = File.expand_path('..', __dir__)
|
|
11
10
|
$LOAD_PATH.unshift File.expand_path('lib', root)
|
12
11
|
|
13
12
|
def parse_options
|
14
|
-
options =
|
13
|
+
options = Struct.new(:active_extensions, :active_parse_options, :active_render_options, :output_format, :renderer)
|
14
|
+
.new([], [:DEFAULT], [:DEFAULT], :html)
|
15
15
|
extensions = CommonMarker.extensions
|
16
|
-
parse_options = CommonMarker::Config::
|
17
|
-
render_options = CommonMarker::Config::
|
18
|
-
|
19
|
-
options.active_extensions = []
|
20
|
-
options.active_parse_options = [:DEFAULT]
|
21
|
-
options.active_render_options = [:DEFAULT]
|
16
|
+
parse_options = CommonMarker::Config::OPTS.fetch(:parse)
|
17
|
+
render_options = CommonMarker::Config::OPTS.fetch(:render)
|
18
|
+
format_options = CommonMarker::Config::OPTS.fetch(:format)
|
22
19
|
|
23
20
|
option_parser = OptionParser.new do |opts|
|
24
21
|
opts.banner = 'Usage: commonmarker [--html-renderer] [--extension=EXTENSION]'
|
22
|
+
opts.separator ' [--to=FORMAT]'
|
25
23
|
opts.separator ' [--parse-option=OPTION]'
|
26
24
|
opts.separator ' [--render-option=OPTION]'
|
27
25
|
opts.separator ' [FILE..]'
|
@@ -43,6 +41,7 @@ def parse_options
|
|
43
41
|
opts.on('-h', '--help', 'Prints this help') do
|
44
42
|
puts opts
|
45
43
|
puts
|
44
|
+
puts "Available formats: #{format_options.join(', ')}"
|
46
45
|
puts "Available extentions: #{extensions.join(', ')}"
|
47
46
|
puts "Available parse options: #{parse_options.keys.join(', ')}"
|
48
47
|
puts "Available render options: #{render_options.keys.join(', ')}"
|
@@ -51,7 +50,16 @@ def parse_options
|
|
51
50
|
exit
|
52
51
|
end
|
53
52
|
|
54
|
-
opts.on('
|
53
|
+
opts.on('-tFORMAT', '--to=FORMAT', String, 'Specify output FORMAT') do |value|
|
54
|
+
value = value.to_sym
|
55
|
+
if format_options.include?(value)
|
56
|
+
options.output_format = value
|
57
|
+
else
|
58
|
+
abort("format '#{value}' not found")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on('--html-renderer', 'Use the HtmlRenderer renderer rather than the native C renderer (only valid when format is html)') do
|
55
63
|
options.renderer = true
|
56
64
|
end
|
57
65
|
|
@@ -88,11 +96,23 @@ end
|
|
88
96
|
|
89
97
|
options = parse_options
|
90
98
|
|
99
|
+
abort("format '#{options.output_format}' does not support using the HtmlRenderer renderer") if
|
100
|
+
options.renderer && options.output_format != :html
|
101
|
+
|
91
102
|
doc = CommonMarker.render_doc(ARGF.read, options.active_parse_options, options.active_extensions)
|
92
103
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
104
|
+
case options.output_format
|
105
|
+
when :html
|
106
|
+
if options.renderer
|
107
|
+
renderer = CommonMarker::HtmlRenderer.new(options: options.active_render_options, extensions: options.active_extensions)
|
108
|
+
$stdout.write(renderer.render(doc))
|
109
|
+
else
|
110
|
+
$stdout.write(doc.to_html(options.active_render_options, options.active_extensions))
|
111
|
+
end
|
112
|
+
when :xml
|
113
|
+
$stdout.write(doc.to_xml(options.active_render_options))
|
114
|
+
when :commonmark
|
115
|
+
$stdout.write(doc.to_commonmark(options.active_render_options))
|
116
|
+
when :plaintext
|
117
|
+
$stdout.write(doc.to_plaintext(options.active_render_options))
|
98
118
|
end
|
data/commonmarker.gemspec
CHANGED
@@ -21,11 +21,11 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
s.executables = ['commonmarker']
|
23
23
|
s.require_paths = %w[lib ext]
|
24
|
-
s.required_ruby_version = ['>= 2.
|
24
|
+
s.required_ruby_version = ['>= 2.6', '< 4.0']
|
25
25
|
|
26
|
-
s.
|
26
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
27
27
|
|
28
|
-
s.
|
28
|
+
s.rdoc_options += ['-x', 'ext/commonmarker/cmark/.*']
|
29
29
|
|
30
30
|
s.add_development_dependency 'awesome_print'
|
31
31
|
s.add_development_dependency 'json', '~> 2.3'
|
data/ext/commonmarker/blocks.c
CHANGED
@@ -468,7 +468,6 @@ static void process_footnotes(cmark_parser *parser) {
|
|
468
468
|
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
469
469
|
cur = cmark_iter_get_node(iter);
|
470
470
|
if (ev_type == CMARK_EVENT_EXIT && cur->type == CMARK_NODE_FOOTNOTE_DEFINITION) {
|
471
|
-
cmark_node_unlink(cur);
|
472
471
|
cmark_footnote_create(map, cur);
|
473
472
|
}
|
474
473
|
}
|
@@ -485,6 +484,15 @@ static void process_footnotes(cmark_parser *parser) {
|
|
485
484
|
if (!footnote->ix)
|
486
485
|
footnote->ix = ++ix;
|
487
486
|
|
487
|
+
// store a reference to this footnote reference's footnote definition
|
488
|
+
// this is used by renderers when generating label ids
|
489
|
+
cur->parent_footnote_def = footnote->node;
|
490
|
+
|
491
|
+
// keep track of a) count of how many times this footnote def has been
|
492
|
+
// referenced, and b) which reference index this footnote ref is at.
|
493
|
+
// this is used by renderers when generating links and backreferences.
|
494
|
+
cur->footnote.ref_ix = ++footnote->node->footnote.def_count;
|
495
|
+
|
488
496
|
char n[32];
|
489
497
|
snprintf(n, sizeof(n), "%d", footnote->ix);
|
490
498
|
cmark_chunk_free(parser->mem, &cur->as.literal);
|
@@ -515,13 +523,16 @@ static void process_footnotes(cmark_parser *parser) {
|
|
515
523
|
qsort(map->sorted, map->size, sizeof(cmark_map_entry *), sort_footnote_by_ix);
|
516
524
|
for (unsigned int i = 0; i < map->size; ++i) {
|
517
525
|
cmark_footnote *footnote = (cmark_footnote *)map->sorted[i];
|
518
|
-
if (!footnote->ix)
|
526
|
+
if (!footnote->ix) {
|
527
|
+
cmark_node_unlink(footnote->node);
|
519
528
|
continue;
|
529
|
+
}
|
520
530
|
cmark_node_append_child(parser->root, footnote->node);
|
521
531
|
footnote->node = NULL;
|
522
532
|
}
|
523
533
|
}
|
524
534
|
|
535
|
+
cmark_unlink_footnotes_map(map);
|
525
536
|
cmark_map_free(map);
|
526
537
|
}
|
527
538
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#ifndef CMARK_GFM_VERSION_H
|
2
2
|
#define CMARK_GFM_VERSION_H
|
3
3
|
|
4
|
-
#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) |
|
5
|
-
#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.
|
4
|
+
#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 3)
|
5
|
+
#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.3"
|
6
6
|
|
7
7
|
#endif
|
@@ -477,7 +477,13 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
477
477
|
case CMARK_NODE_FOOTNOTE_REFERENCE:
|
478
478
|
if (entering) {
|
479
479
|
LIT("[^");
|
480
|
-
|
480
|
+
|
481
|
+
char *footnote_label = renderer->mem->calloc(node->parent_footnote_def->as.literal.len + 1, sizeof(char));
|
482
|
+
memmove(footnote_label, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len);
|
483
|
+
|
484
|
+
OUT(footnote_label, false, LITERAL);
|
485
|
+
renderer->mem->free(footnote_label);
|
486
|
+
|
481
487
|
LIT("]");
|
482
488
|
}
|
483
489
|
break;
|
@@ -486,9 +492,13 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
486
492
|
if (entering) {
|
487
493
|
renderer->footnote_ix += 1;
|
488
494
|
LIT("[^");
|
489
|
-
|
490
|
-
|
491
|
-
|
495
|
+
|
496
|
+
char *footnote_label = renderer->mem->calloc(node->as.literal.len + 1, sizeof(char));
|
497
|
+
memmove(footnote_label, node->as.literal.data, node->as.literal.len);
|
498
|
+
|
499
|
+
OUT(footnote_label, false, LITERAL);
|
500
|
+
renderer->mem->free(footnote_label);
|
501
|
+
|
492
502
|
LIT("]:\n");
|
493
503
|
|
494
504
|
cmark_strbuf_puts(renderer->prefix, " ");
|
@@ -45,6 +45,13 @@ static VALUE encode_utf8_string(const char *c_string) {
|
|
45
45
|
return string;
|
46
46
|
}
|
47
47
|
|
48
|
+
/* Encode a C string using the encoding from Ruby string +source+. */
|
49
|
+
static VALUE encode_source_string(const char *c_string, VALUE source) {
|
50
|
+
VALUE string = rb_str_new2(c_string);
|
51
|
+
rb_enc_copy(string, source);
|
52
|
+
return string;
|
53
|
+
}
|
54
|
+
|
48
55
|
static void rb_mark_c_struct(void *data) {
|
49
56
|
cmark_node *node = data;
|
50
57
|
cmark_node *child;
|
@@ -108,25 +115,23 @@ static void rb_parent_removed(VALUE val) {
|
|
108
115
|
RDATA(val)->dfree = rb_free_c_struct;
|
109
116
|
}
|
110
117
|
|
111
|
-
static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions
|
118
|
+
static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions) {
|
112
119
|
int options;
|
113
|
-
int extensions_len;
|
114
120
|
VALUE rb_ext_name;
|
115
121
|
int i;
|
116
122
|
|
117
|
-
|
123
|
+
FIXNUM_P(rb_options);
|
124
|
+
options = FIX2INT(rb_options);
|
125
|
+
|
118
126
|
Check_Type(rb_extensions, T_ARRAY);
|
119
127
|
|
120
|
-
|
121
|
-
extensions_len = RARRAY_LEN(rb_extensions);
|
128
|
+
cmark_parser *parser = cmark_parser_new(options);
|
122
129
|
|
123
|
-
|
124
|
-
|
125
|
-
rb_ext_name = RARRAY_PTR(rb_extensions)[i];
|
130
|
+
for (i = 0; i < RARRAY_LEN(rb_extensions); ++i) {
|
131
|
+
rb_ext_name = rb_ary_entry(rb_extensions, i);
|
126
132
|
|
127
133
|
if (!SYMBOL_P(rb_ext_name)) {
|
128
134
|
cmark_parser_free(parser);
|
129
|
-
cmark_arena_reset();
|
130
135
|
rb_raise(rb_eTypeError, "extension names should be Symbols; got a %"PRIsVALUE"", rb_obj_class(rb_ext_name));
|
131
136
|
}
|
132
137
|
|
@@ -135,7 +140,6 @@ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark
|
|
135
140
|
|
136
141
|
if (!syntax_extension) {
|
137
142
|
cmark_parser_free(parser);
|
138
|
-
cmark_arena_reset();
|
139
143
|
rb_raise(rb_eArgError, "extension %s not found", rb_id2name(SYM2ID(rb_ext_name)));
|
140
144
|
}
|
141
145
|
|
@@ -150,33 +154,57 @@ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark
|
|
150
154
|
*
|
151
155
|
*/
|
152
156
|
static VALUE rb_markdown_to_html(VALUE self, VALUE rb_text, VALUE rb_options, VALUE rb_extensions) {
|
153
|
-
char *
|
154
|
-
int len;
|
157
|
+
char *html;
|
155
158
|
cmark_parser *parser;
|
156
159
|
cmark_node *doc;
|
160
|
+
|
157
161
|
Check_Type(rb_text, T_STRING);
|
158
|
-
Check_Type(rb_options, T_FIXNUM);
|
159
162
|
|
160
|
-
parser = prepare_parser(rb_options, rb_extensions
|
163
|
+
parser = prepare_parser(rb_options, rb_extensions);
|
161
164
|
|
162
|
-
|
163
|
-
|
165
|
+
cmark_parser_feed(parser, StringValuePtr(rb_text), RSTRING_LEN(rb_text));
|
166
|
+
doc = cmark_parser_finish(parser);
|
164
167
|
|
165
|
-
|
168
|
+
if (doc == NULL) {
|
169
|
+
cmark_parser_free(parser);
|
170
|
+
rb_raise(rb_eNodeError, "error parsing document");
|
171
|
+
}
|
172
|
+
|
173
|
+
html = cmark_render_html(doc, parser->options, parser->syntax_extensions);
|
174
|
+
|
175
|
+
cmark_parser_free(parser);
|
176
|
+
cmark_node_free(doc);
|
177
|
+
|
178
|
+
return rb_utf8_str_new_cstr(html);
|
179
|
+
}
|
180
|
+
|
181
|
+
/*
|
182
|
+
* Internal: Parses a Markdown string into an HTML string.
|
183
|
+
*
|
184
|
+
*/
|
185
|
+
static VALUE rb_markdown_to_xml(VALUE self, VALUE rb_text, VALUE rb_options, VALUE rb_extensions) {
|
186
|
+
char *xml;
|
187
|
+
cmark_parser *parser;
|
188
|
+
cmark_node *doc;
|
189
|
+
|
190
|
+
Check_Type(rb_text, T_STRING);
|
191
|
+
|
192
|
+
parser = prepare_parser(rb_options, rb_extensions);
|
193
|
+
|
194
|
+
cmark_parser_feed(parser, StringValuePtr(rb_text), RSTRING_LEN(rb_text));
|
166
195
|
doc = cmark_parser_finish(parser);
|
196
|
+
|
167
197
|
if (doc == NULL) {
|
168
|
-
|
198
|
+
cmark_parser_free(parser);
|
169
199
|
rb_raise(rb_eNodeError, "error parsing document");
|
170
200
|
}
|
171
201
|
|
172
|
-
|
173
|
-
html = cmark_render_html_with_mem(doc, FIX2INT(rb_options), parser->syntax_extensions, default_mem);
|
174
|
-
cmark_arena_reset();
|
202
|
+
xml = cmark_render_xml(doc, parser->options);
|
175
203
|
|
176
|
-
|
177
|
-
|
204
|
+
cmark_parser_free(parser);
|
205
|
+
cmark_node_free(doc);
|
178
206
|
|
179
|
-
return
|
207
|
+
return rb_utf8_str_new_cstr(xml);
|
180
208
|
}
|
181
209
|
|
182
210
|
/*
|
@@ -267,18 +295,17 @@ static VALUE rb_node_new(VALUE self, VALUE type) {
|
|
267
295
|
static VALUE rb_parse_document(VALUE self, VALUE rb_text, VALUE rb_len,
|
268
296
|
VALUE rb_options, VALUE rb_extensions) {
|
269
297
|
char *text;
|
270
|
-
int len
|
298
|
+
int len;
|
271
299
|
cmark_parser *parser;
|
272
300
|
cmark_node *doc;
|
273
301
|
Check_Type(rb_text, T_STRING);
|
274
302
|
Check_Type(rb_len, T_FIXNUM);
|
275
303
|
Check_Type(rb_options, T_FIXNUM);
|
276
304
|
|
277
|
-
parser = prepare_parser(rb_options, rb_extensions
|
305
|
+
parser = prepare_parser(rb_options, rb_extensions);
|
278
306
|
|
279
307
|
text = (char *)RSTRING_PTR(rb_text);
|
280
308
|
len = FIX2INT(rb_len);
|
281
|
-
options = FIX2INT(rb_options);
|
282
309
|
|
283
310
|
cmark_parser_feed(parser, text, len);
|
284
311
|
doc = cmark_parser_finish(parser);
|
@@ -567,6 +594,27 @@ static VALUE rb_render_html(VALUE self, VALUE rb_options, VALUE rb_extensions) {
|
|
567
594
|
return ruby_html;
|
568
595
|
}
|
569
596
|
|
597
|
+
/* Internal: Convert the node to an XML string.
|
598
|
+
*
|
599
|
+
* Returns a {String}.
|
600
|
+
*/
|
601
|
+
static VALUE rb_render_xml(VALUE self, VALUE rb_options) {
|
602
|
+
int options;
|
603
|
+
cmark_node *node;
|
604
|
+
Check_Type(rb_options, T_FIXNUM);
|
605
|
+
|
606
|
+
options = FIX2INT(rb_options);
|
607
|
+
|
608
|
+
Data_Get_Struct(self, cmark_node, node);
|
609
|
+
|
610
|
+
char *xml = cmark_render_xml(node, options);
|
611
|
+
VALUE ruby_xml = rb_str_new2(xml);
|
612
|
+
|
613
|
+
free(xml);
|
614
|
+
|
615
|
+
return ruby_xml;
|
616
|
+
}
|
617
|
+
|
570
618
|
/* Internal: Convert the node to a CommonMark string.
|
571
619
|
*
|
572
620
|
* Returns a {String}.
|
@@ -1130,7 +1178,8 @@ static VALUE rb_html_escape_href(VALUE self, VALUE rb_text) {
|
|
1130
1178
|
if (houdini_escape_href(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
|
1131
1179
|
RSTRING_LEN(rb_text))) {
|
1132
1180
|
result = (char *)cmark_strbuf_detach(&buf);
|
1133
|
-
return
|
1181
|
+
return encode_source_string(result, rb_text);
|
1182
|
+
|
1134
1183
|
}
|
1135
1184
|
|
1136
1185
|
return rb_text;
|
@@ -1150,7 +1199,7 @@ static VALUE rb_html_escape_html(VALUE self, VALUE rb_text) {
|
|
1150
1199
|
if (houdini_escape_html0(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
|
1151
1200
|
RSTRING_LEN(rb_text), 0)) {
|
1152
1201
|
result = (char *)cmark_strbuf_detach(&buf);
|
1153
|
-
return
|
1202
|
+
return encode_source_string(result, rb_text);
|
1154
1203
|
}
|
1155
1204
|
|
1156
1205
|
return rb_text;
|
@@ -1208,6 +1257,8 @@ __attribute__((visibility("default"))) void Init_commonmarker() {
|
|
1208
1257
|
rb_cNode = rb_define_class_under(module, "Node", rb_cObject);
|
1209
1258
|
rb_define_singleton_method(rb_cNode, "markdown_to_html", rb_markdown_to_html,
|
1210
1259
|
3);
|
1260
|
+
rb_define_singleton_method(rb_cNode, "markdown_to_xml", rb_markdown_to_xml,
|
1261
|
+
3);
|
1211
1262
|
rb_define_singleton_method(rb_cNode, "new", rb_node_new, 1);
|
1212
1263
|
rb_define_singleton_method(rb_cNode, "parse_document", rb_parse_document, 4);
|
1213
1264
|
rb_define_method(rb_cNode, "string_content", rb_node_get_string_content, 0);
|
@@ -1220,6 +1271,7 @@ __attribute__((visibility("default"))) void Init_commonmarker() {
|
|
1220
1271
|
rb_define_method(rb_cNode, "next", rb_node_next, 0);
|
1221
1272
|
rb_define_method(rb_cNode, "insert_before", rb_node_insert_before, 1);
|
1222
1273
|
rb_define_method(rb_cNode, "_render_html", rb_render_html, 2);
|
1274
|
+
rb_define_method(rb_cNode, "_render_xml", rb_render_xml, 1);
|
1223
1275
|
rb_define_method(rb_cNode, "_render_commonmark", rb_render_commonmark, -1);
|
1224
1276
|
rb_define_method(rb_cNode, "_render_plaintext", rb_render_plaintext, -1);
|
1225
1277
|
rb_define_method(rb_cNode, "insert_after", rb_node_insert_after, 1);
|