commonmarker 0.20.1 → 0.22.0
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 +5 -5
- data/README.md +14 -14
- data/Rakefile +16 -4
- data/bin/commonmarker +83 -45
- data/commonmarker.gemspec +9 -13
- data/ext/commonmarker/cmark-gfm-core-extensions.h +24 -1
- data/ext/commonmarker/commonmarker.c +130 -80
- data/ext/commonmarker/node.h +1 -0
- data/ext/commonmarker/table.c +52 -13
- data/ext/commonmarker/tasklist.c +33 -13
- data/lib/commonmarker.rb +5 -4
- data/lib/commonmarker/config.rb +33 -39
- data/lib/commonmarker/node.rb +2 -2
- data/lib/commonmarker/node/inspect.rb +15 -17
- data/lib/commonmarker/renderer.rb +13 -9
- data/lib/commonmarker/renderer/html_renderer.rb +22 -35
- data/lib/commonmarker/version.rb +1 -1
- data/test/benchmark.rb +1 -5
- data/test/fixtures/strong.md +1 -0
- data/test/fixtures/table.md +10 -0
- data/test/test_attributes.rb +3 -3
- data/test/test_commands.rb +31 -0
- data/test/test_commonmark.rb +13 -13
- data/test/test_doc.rb +29 -29
- data/test/test_encoding.rb +4 -5
- data/test/test_extensions.rb +57 -69
- data/test/test_footnotes.rb +30 -9
- data/test/test_gc.rb +2 -0
- data/test/test_helper.rb +17 -10
- data/test/test_maliciousness.rb +192 -190
- data/test/test_node.rb +10 -12
- data/test/test_options.rb +15 -15
- data/test/test_pathological_inputs.rb +12 -12
- data/test/test_plaintext.rb +21 -21
- data/test/test_renderer.rb +27 -10
- data/test/test_spec.rb +3 -2
- data/test/test_tasklists.rb +16 -6
- metadata +54 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f5356237deaf85df9914e0c7fa3f121fa0301579653b83b006df4dd8404c65f2
|
4
|
+
data.tar.gz: 9d4a09830e1c107dec28e47a3c0ab96f2cc6bcd9786982e38607752022ec12f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e43f365eb266fa8c0627572999a2102df7dd65e0404917c5fa6054b532c526a35ad5d0ef9423cf68033edc52fb0c20da79ca73d7345b04d4493f33bff35ed73
|
7
|
+
data.tar.gz: 0e5da729c2247288a1bf60672f572f785def6e2a1726afeaf87aa1332d083e4834d52c403479a36437f9c0a9e99548569f7d5bc092a405304ccef81ac71096b1
|
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.
|
@@ -112,10 +112,8 @@ class MyHtmlRenderer < CommonMarker::HtmlRenderer
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
|
-
# this renderer prints directly to STDOUT, instead
|
116
|
-
# of returning a string
|
117
115
|
myrenderer = MyHtmlRenderer.new
|
118
|
-
|
116
|
+
puts myrenderer.render(doc)
|
119
117
|
|
120
118
|
# Print any warnings to STDERR
|
121
119
|
renderer.warnings.each do |w|
|
@@ -141,16 +139,17 @@ CommonMarker accepts the same options that CMark does, as symbols. Note that the
|
|
141
139
|
|
142
140
|
### Render options
|
143
141
|
|
144
|
-
| Name | Description
|
145
|
-
| ------------------ | -----------
|
146
|
-
| `:DEFAULT` | The default rendering system.
|
147
|
-
| `:UNSAFE` | Allow raw/custom HTML and unsafe links.
|
148
|
-
| `:GITHUB_PRE_LANG` | Use GitHub-style `<pre lang>` for fenced code blocks.
|
149
|
-
| `:HARDBREAKS` | Treat `\n` as hardbreaks (by adding `<br/>`).
|
150
|
-
| `:NOBREAKS` | Translate `\n` in the source to a single whitespace.
|
151
|
-
| `:SOURCEPOS` | Include source position in rendered HTML.
|
152
|
-
| `:TABLE_PREFER_STYLE_ATTRIBUTES` | Use `style` insted of `align` for table cells |
|
153
|
-
| `:FULL_INFO_STRING` | Include full info strings of code blocks in separate attribute |
|
142
|
+
| Name | Description |
|
143
|
+
| ------------------ | ----------- |
|
144
|
+
| `:DEFAULT` | The default rendering system. |
|
145
|
+
| `:UNSAFE` | Allow raw/custom HTML and unsafe links. |
|
146
|
+
| `:GITHUB_PRE_LANG` | Use GitHub-style `<pre lang>` for fenced code blocks. |
|
147
|
+
| `:HARDBREAKS` | Treat `\n` as hardbreaks (by adding `<br/>`). |
|
148
|
+
| `:NOBREAKS` | Translate `\n` in the source to a single whitespace. |
|
149
|
+
| `:SOURCEPOS` | Include source position in rendered HTML. |
|
150
|
+
| `:TABLE_PREFER_STYLE_ATTRIBUTES` | Use `style` insted of `align` for table cells. |
|
151
|
+
| `:FULL_INFO_STRING` | Include full info strings of code blocks in separate attribute. |
|
152
|
+
| `:FOOTNOTES` | Render footnotes. |
|
154
153
|
|
155
154
|
### Passing options
|
156
155
|
|
@@ -176,6 +175,7 @@ Both `render_html` and `render_doc` take an optional third argument defining the
|
|
176
175
|
The available extensions are:
|
177
176
|
|
178
177
|
* `:table` - This provides support for tables.
|
178
|
+
* `:tasklist` - This provides support for task list items.
|
179
179
|
* `:strikethrough` - This provides support for strikethroughs.
|
180
180
|
* `:autolink` - This provides support for automatically converting URLs to anchor tags.
|
181
181
|
* `:tagfilter` - This escapes [several "unsafe" HTML tags](https://github.github.com/gfm/#disallowed-raw-html-extension-), causing them to not have any effect.
|
data/Rakefile
CHANGED
@@ -5,7 +5,6 @@ require 'rake/clean'
|
|
5
5
|
require 'rake/extensiontask'
|
6
6
|
require 'digest/md5'
|
7
7
|
|
8
|
-
|
9
8
|
host_os = RbConfig::CONFIG['host_os']
|
10
9
|
require 'devkit' if host_os == 'mingw32'
|
11
10
|
|
@@ -36,7 +35,7 @@ end
|
|
36
35
|
task 'test:unit' => :compile
|
37
36
|
|
38
37
|
desc 'Run unit and conformance tests'
|
39
|
-
task test: %w
|
38
|
+
task test: %w[test:unit]
|
40
39
|
|
41
40
|
require 'rubocop/rake_task'
|
42
41
|
|
@@ -47,7 +46,7 @@ task :benchmark do
|
|
47
46
|
if ENV['FETCH_PROGIT']
|
48
47
|
`rm -rf test/progit`
|
49
48
|
`git clone https://github.com/progit/progit.git test/progit`
|
50
|
-
langs = %w
|
49
|
+
langs = %w[ar az be ca cs de en eo es es-ni fa fi fr hi hu id it ja ko mk nl no-nb pl pt-br ro ru sr th tr uk vi zh zh-tw]
|
51
50
|
langs.each do |lang|
|
52
51
|
`cat test/progit/#{lang}/*/*.markdown >> test/benchinput.md`
|
53
52
|
end
|
@@ -77,13 +76,26 @@ RDoc::Task.new do |rd|
|
|
77
76
|
rd.options << '--fileboxes'
|
78
77
|
end
|
79
78
|
|
79
|
+
desc 'Generate the documentation and run a web server'
|
80
|
+
task serve: [:rdoc] do
|
81
|
+
require 'webrick'
|
82
|
+
|
83
|
+
puts 'Navigate to http://localhost:3000 to see the docs'
|
84
|
+
|
85
|
+
server = WEBrick::HTTPServer.new Port: 3000
|
86
|
+
server.mount '/', WEBrick::HTTPServlet::FileHandler, 'docs'
|
87
|
+
trap('INT') { server.stop }
|
88
|
+
server.start
|
89
|
+
end
|
90
|
+
|
80
91
|
desc 'Generate and publish docs to gh-pages'
|
81
92
|
task publish: [:rdoc] do
|
93
|
+
require 'tmpdir'
|
82
94
|
require 'shellwords'
|
83
95
|
|
84
96
|
Dir.mktmpdir do |tmp|
|
85
97
|
system "mv docs/* #{tmp}"
|
86
|
-
system 'git checkout gh-pages'
|
98
|
+
system 'git checkout origin/gh-pages'
|
87
99
|
system 'rm -rf *'
|
88
100
|
system "mv #{tmp}/* ."
|
89
101
|
message = Shellwords.escape("Site updated at #{Time.now.utc}")
|
data/bin/commonmarker
CHANGED
@@ -1,60 +1,98 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
# If no FILE argument is provided, text will be read from STDIN.
|
7
|
-
# With --html-renderer, use the HtmlRenderer renderer rather than the native C
|
8
|
-
# renderer.
|
9
|
-
# With --extension=EXTENSION, EXTENSION will be used for parsing, and HTML
|
10
|
-
# output unless --html-renderer is specified.
|
11
|
-
if ARGV.include?('--help') or ARGV.include?('-h')
|
12
|
-
File.read(__FILE__).split("\n").grep(/^# /).each do |line|
|
13
|
-
puts line[2..-1]
|
14
|
-
end
|
15
|
-
exit 0
|
16
|
-
end
|
4
|
+
require 'optparse'
|
5
|
+
require 'ostruct'
|
17
6
|
|
18
7
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
19
8
|
require 'commonmarker'
|
20
9
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
10
|
+
root = File.expand_path('..', __dir__)
|
11
|
+
$LOAD_PATH.unshift File.expand_path('lib', root)
|
12
|
+
|
13
|
+
def parse_options
|
14
|
+
options = OpenStruct.new
|
15
|
+
extensions = CommonMarker.extensions
|
16
|
+
parse_options = CommonMarker::Config::OPTS.fetch(:parse)
|
17
|
+
render_options = CommonMarker::Config::OPTS.fetch(:render)
|
18
|
+
|
19
|
+
options.active_extensions = []
|
20
|
+
options.active_parse_options = [:DEFAULT]
|
21
|
+
options.active_render_options = [:DEFAULT]
|
22
|
+
|
23
|
+
option_parser = OptionParser.new do |opts|
|
24
|
+
opts.banner = 'Usage: commonmarker [--html-renderer] [--extension=EXTENSION]'
|
25
|
+
opts.separator ' [--parse-option=OPTION]'
|
26
|
+
opts.separator ' [--render-option=OPTION]'
|
27
|
+
opts.separator ' [FILE..]'
|
28
|
+
opts.separator ''
|
29
|
+
opts.separator 'Convert one or more CommonMark files to HTML and write to standard output.'
|
30
|
+
opts.separator 'If no FILE argument is provided, text will be read from STDIN.'
|
31
|
+
opts.separator ''
|
32
|
+
|
33
|
+
opts.on('--extension=EXTENSION', Array, 'Use EXTENSION for parsing and HTML output (unless --html-renderer is specified)') do |values|
|
34
|
+
values.each do |value|
|
35
|
+
if extensions.include?(value)
|
36
|
+
options.active_extensions << value.to_sym
|
37
|
+
else
|
38
|
+
abort("extension '#{value}' not found")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on('-h', '--help', 'Prints this help') do
|
44
|
+
puts opts
|
45
|
+
puts
|
46
|
+
puts "Available extentions: #{extensions.join(', ')}"
|
47
|
+
puts "Available parse options: #{parse_options.keys.join(', ')}"
|
48
|
+
puts "Available render options: #{render_options.keys.join(', ')}"
|
49
|
+
puts
|
50
|
+
puts 'See the README for more information on these.'
|
51
|
+
exit
|
52
|
+
end
|
25
53
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
54
|
+
opts.on('--html-renderer', 'Use the HtmlRenderer renderer rather than the native C renderer') do
|
55
|
+
options.renderer = true
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on('--parse-option=OPTION', Array, 'OPTION passed during parsing') do |values|
|
59
|
+
values.each do |value|
|
60
|
+
if parse_options.key?(value.to_sym)
|
61
|
+
options.active_parse_options << value.to_sym
|
62
|
+
else
|
63
|
+
abort("parse-option '#{value}' not found")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on('--render-option=OPTION', Array, 'OPTION passed during rendering') do |values|
|
69
|
+
values.each do |value|
|
70
|
+
if render_options.key?(value.to_sym)
|
71
|
+
options.active_render_options << value.to_sym
|
72
|
+
else
|
73
|
+
abort("render-option '#{value}' not found")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
opts.on('-v', '--version', 'Version information') do
|
79
|
+
puts "commonmarker #{CommonMarker::VERSION}"
|
80
|
+
exit
|
46
81
|
end
|
47
|
-
true
|
48
|
-
else
|
49
|
-
false
|
50
82
|
end
|
83
|
+
|
84
|
+
option_parser.parse!
|
85
|
+
|
86
|
+
options
|
51
87
|
end
|
52
88
|
|
53
|
-
|
89
|
+
options = parse_options
|
90
|
+
|
91
|
+
doc = CommonMarker.render_doc(ARGF.read, options.active_parse_options, options.active_extensions)
|
54
92
|
|
55
|
-
if renderer
|
56
|
-
renderer = CommonMarker::HtmlRenderer.new(extensions: active_extensions)
|
57
|
-
|
93
|
+
if options.renderer
|
94
|
+
renderer = CommonMarker::HtmlRenderer.new(extensions: options.active_extensions)
|
95
|
+
$stdout.write(renderer.render(doc))
|
58
96
|
else
|
59
|
-
|
97
|
+
$stdout.write(doc.to_html(options.active_render_options, options.active_extensions))
|
60
98
|
end
|
data/commonmarker.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
5
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
5
|
require 'commonmarker/version'
|
7
6
|
|
@@ -10,32 +9,29 @@ Gem::Specification.new do |s|
|
|
10
9
|
s.version = CommonMarker::VERSION
|
11
10
|
s.summary = 'CommonMark parser and renderer. Written in C, wrapped in Ruby.'
|
12
11
|
s.description = 'A fast, safe, extensible parser for CommonMark. This wraps the official libcmark library.'
|
13
|
-
s.authors
|
12
|
+
s.authors = ['Garen Torikian', 'Ashe Connor']
|
14
13
|
s.homepage = 'https://github.com/gjtorikian/commonmarker'
|
15
14
|
s.license = 'MIT'
|
16
|
-
s.required_ruby_version = '>= 2.0.0'
|
17
15
|
|
18
|
-
s.files = %w
|
16
|
+
s.files = %w[LICENSE.txt README.md Rakefile commonmarker.gemspec bin/commonmarker]
|
19
17
|
s.files += Dir.glob('lib/**/*.rb')
|
20
18
|
s.files += Dir.glob('ext/commonmarker/*.*')
|
21
19
|
s.test_files = Dir.glob('test/**/*').reject { |f| f == 'test/benchinput.md' || f.start_with?('test/progit/') }
|
22
20
|
s.extensions = ['ext/commonmarker/extconf.rb']
|
23
21
|
|
24
|
-
s.test_files = s.files.grep(%r{^test/})
|
25
22
|
s.executables = ['commonmarker']
|
26
|
-
s.require_paths = %w
|
23
|
+
s.require_paths = %w[lib ext]
|
24
|
+
s.required_ruby_version = ['>= 2.6', '< 4.0']
|
27
25
|
|
28
26
|
s.rdoc_options += ['-x', 'ext/commonmarker/cmark/.*']
|
29
27
|
|
30
|
-
s.
|
31
|
-
|
28
|
+
s.add_development_dependency 'awesome_print'
|
29
|
+
s.add_development_dependency 'json', '~> 2.3'
|
32
30
|
s.add_development_dependency 'minitest', '~> 5.6'
|
33
31
|
s.add_development_dependency 'minitest-focus', '~> 1.1'
|
34
|
-
s.add_development_dependency 'rake-compiler', '~> 0.9'
|
35
|
-
s.add_development_dependency 'json', '~> 1.8.1'
|
36
|
-
s.add_development_dependency 'awesome_print'
|
37
32
|
s.add_development_dependency 'rake'
|
38
|
-
s.add_development_dependency '
|
33
|
+
s.add_development_dependency 'rake-compiler', '~> 0.9'
|
34
|
+
s.add_development_dependency 'rdoc', '~> 6.2'
|
39
35
|
s.add_development_dependency 'rubocop'
|
40
36
|
s.add_development_dependency 'rubocop-standard'
|
41
37
|
end
|
@@ -7,6 +7,7 @@ extern "C" {
|
|
7
7
|
|
8
8
|
#include "cmark-gfm-extension_api.h"
|
9
9
|
#include "cmark-gfm-extensions_export.h"
|
10
|
+
#include "config.h" // for bool
|
10
11
|
#include <stdint.h>
|
11
12
|
|
12
13
|
CMARK_GFM_EXTENSIONS_EXPORT
|
@@ -15,14 +16,36 @@ void cmark_gfm_core_extensions_ensure_registered(void);
|
|
15
16
|
CMARK_GFM_EXTENSIONS_EXPORT
|
16
17
|
uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node);
|
17
18
|
|
19
|
+
/** Sets the number of columns for the table, returning 1 on success and 0 on error.
|
20
|
+
*/
|
21
|
+
CMARK_GFM_EXTENSIONS_EXPORT
|
22
|
+
int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns);
|
23
|
+
|
18
24
|
CMARK_GFM_EXTENSIONS_EXPORT
|
19
25
|
uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node);
|
20
26
|
|
27
|
+
/** Sets the alignments for the table, returning 1 on success and 0 on error.
|
28
|
+
*/
|
29
|
+
CMARK_GFM_EXTENSIONS_EXPORT
|
30
|
+
int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments);
|
31
|
+
|
21
32
|
CMARK_GFM_EXTENSIONS_EXPORT
|
22
33
|
int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node);
|
23
34
|
|
35
|
+
/** Sets whether the node is a table header row, returning 1 on success and 0 on error.
|
36
|
+
*/
|
37
|
+
CMARK_GFM_EXTENSIONS_EXPORT
|
38
|
+
int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header);
|
39
|
+
|
40
|
+
CMARK_GFM_EXTENSIONS_EXPORT
|
41
|
+
bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node);
|
42
|
+
/* For backwards compatibility */
|
43
|
+
#define cmark_gfm_extensions_tasklist_is_checked cmark_gfm_extensions_get_tasklist_item_checked
|
44
|
+
|
45
|
+
/** Sets whether a tasklist item is "checked" (completed), returning 1 on success and 0 on error.
|
46
|
+
*/
|
24
47
|
CMARK_GFM_EXTENSIONS_EXPORT
|
25
|
-
|
48
|
+
int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked);
|
26
49
|
|
27
50
|
#ifdef __cplusplus
|
28
51
|
}
|
@@ -7,8 +7,8 @@
|
|
7
7
|
#include "syntax_extension.h"
|
8
8
|
#include "cmark-gfm-core-extensions.h"
|
9
9
|
|
10
|
-
static VALUE
|
11
|
-
static VALUE
|
10
|
+
static VALUE rb_eNodeError;
|
11
|
+
static VALUE rb_cNode;
|
12
12
|
|
13
13
|
static VALUE sym_document;
|
14
14
|
static VALUE sym_blockquote;
|
@@ -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;
|
@@ -94,7 +101,7 @@ static VALUE rb_node_to_value(cmark_node *node) {
|
|
94
101
|
|
95
102
|
/* Only free tree roots. */
|
96
103
|
free_func = cmark_node_parent(node) ? NULL : rb_free_c_struct;
|
97
|
-
val = Data_Wrap_Struct(
|
104
|
+
val = Data_Wrap_Struct(rb_cNode, rb_mark_c_struct, free_func, node);
|
98
105
|
cmark_node_set_user_data(node, (void *)val);
|
99
106
|
|
100
107
|
return val;
|
@@ -166,7 +173,7 @@ static VALUE rb_markdown_to_html(VALUE self, VALUE rb_text, VALUE rb_options, VA
|
|
166
173
|
doc = cmark_parser_finish(parser);
|
167
174
|
if (doc == NULL) {
|
168
175
|
cmark_arena_reset();
|
169
|
-
rb_raise(
|
176
|
+
rb_raise(rb_eNodeError, "error parsing document");
|
170
177
|
}
|
171
178
|
|
172
179
|
cmark_mem *default_mem = cmark_get_default_mem_allocator();
|
@@ -250,11 +257,11 @@ static VALUE rb_node_new(VALUE self, VALUE type) {
|
|
250
257
|
else if (type == sym_footnote_definition)
|
251
258
|
node_type = CMARK_NODE_FOOTNOTE_DEFINITION;
|
252
259
|
else
|
253
|
-
rb_raise(
|
260
|
+
rb_raise(rb_eNodeError, "invalid node of type %d", node_type);
|
254
261
|
|
255
262
|
node = cmark_node_new(node_type);
|
256
263
|
if (node == NULL) {
|
257
|
-
rb_raise(
|
264
|
+
rb_raise(rb_eNodeError, "could not create node of type %d", node_type);
|
258
265
|
}
|
259
266
|
|
260
267
|
return rb_node_to_value(node);
|
@@ -283,7 +290,7 @@ static VALUE rb_parse_document(VALUE self, VALUE rb_text, VALUE rb_len,
|
|
283
290
|
cmark_parser_feed(parser, text, len);
|
284
291
|
doc = cmark_parser_finish(parser);
|
285
292
|
if (doc == NULL) {
|
286
|
-
rb_raise(
|
293
|
+
rb_raise(rb_eNodeError, "error parsing document");
|
287
294
|
}
|
288
295
|
cmark_parser_free(parser);
|
289
296
|
|
@@ -302,7 +309,7 @@ static VALUE rb_node_get_string_content(VALUE self) {
|
|
302
309
|
|
303
310
|
text = cmark_node_get_literal(node);
|
304
311
|
if (text == NULL) {
|
305
|
-
rb_raise(
|
312
|
+
rb_raise(rb_eNodeError, "could not get string content");
|
306
313
|
}
|
307
314
|
|
308
315
|
return encode_utf8_string(text);
|
@@ -324,7 +331,7 @@ static VALUE rb_node_set_string_content(VALUE self, VALUE s) {
|
|
324
331
|
text = StringValueCStr(s);
|
325
332
|
|
326
333
|
if (!cmark_node_set_literal(node, text)) {
|
327
|
-
rb_raise(
|
334
|
+
rb_raise(rb_eNodeError, "could not set string content");
|
328
335
|
}
|
329
336
|
|
330
337
|
return Qnil;
|
@@ -412,7 +419,7 @@ static VALUE rb_node_get_type(VALUE self) {
|
|
412
419
|
s = node->extension->get_type_string_func(node->extension, node);
|
413
420
|
return ID2SYM(rb_intern(s));
|
414
421
|
}
|
415
|
-
rb_raise(
|
422
|
+
rb_raise(rb_eNodeError, "invalid node type %d", node_type);
|
416
423
|
}
|
417
424
|
|
418
425
|
return symbol;
|
@@ -512,7 +519,7 @@ static VALUE rb_node_insert_before(VALUE self, VALUE sibling) {
|
|
512
519
|
Data_Get_Struct(sibling, cmark_node, node2);
|
513
520
|
|
514
521
|
if (!cmark_node_insert_before(node1, node2)) {
|
515
|
-
rb_raise(
|
522
|
+
rb_raise(rb_eNodeError, "could not insert before");
|
516
523
|
}
|
517
524
|
|
518
525
|
rb_parent_added(sibling);
|
@@ -638,7 +645,7 @@ static VALUE rb_node_insert_after(VALUE self, VALUE sibling) {
|
|
638
645
|
Data_Get_Struct(sibling, cmark_node, node2);
|
639
646
|
|
640
647
|
if (!cmark_node_insert_after(node1, node2)) {
|
641
|
-
rb_raise(
|
648
|
+
rb_raise(rb_eNodeError, "could not insert after");
|
642
649
|
}
|
643
650
|
|
644
651
|
rb_parent_added(sibling);
|
@@ -661,7 +668,7 @@ static VALUE rb_node_prepend_child(VALUE self, VALUE child) {
|
|
661
668
|
Data_Get_Struct(child, cmark_node, node2);
|
662
669
|
|
663
670
|
if (!cmark_node_prepend_child(node1, node2)) {
|
664
|
-
rb_raise(
|
671
|
+
rb_raise(rb_eNodeError, "could not prepend child");
|
665
672
|
}
|
666
673
|
|
667
674
|
rb_parent_added(child);
|
@@ -684,7 +691,7 @@ static VALUE rb_node_append_child(VALUE self, VALUE child) {
|
|
684
691
|
Data_Get_Struct(child, cmark_node, node2);
|
685
692
|
|
686
693
|
if (!cmark_node_append_child(node1, node2)) {
|
687
|
-
rb_raise(
|
694
|
+
rb_raise(rb_eNodeError, "could not append child");
|
688
695
|
}
|
689
696
|
|
690
697
|
rb_parent_added(child);
|
@@ -744,7 +751,7 @@ static VALUE rb_node_get_url(VALUE self) {
|
|
744
751
|
|
745
752
|
text = cmark_node_get_url(node);
|
746
753
|
if (text == NULL) {
|
747
|
-
rb_raise(
|
754
|
+
rb_raise(rb_eNodeError, "could not get url");
|
748
755
|
}
|
749
756
|
|
750
757
|
return rb_str_new2(text);
|
@@ -766,7 +773,7 @@ static VALUE rb_node_set_url(VALUE self, VALUE url) {
|
|
766
773
|
text = StringValueCStr(url);
|
767
774
|
|
768
775
|
if (!cmark_node_set_url(node, text)) {
|
769
|
-
rb_raise(
|
776
|
+
rb_raise(rb_eNodeError, "could not set url");
|
770
777
|
}
|
771
778
|
|
772
779
|
return Qnil;
|
@@ -785,7 +792,7 @@ static VALUE rb_node_get_title(VALUE self) {
|
|
785
792
|
|
786
793
|
text = cmark_node_get_title(node);
|
787
794
|
if (text == NULL) {
|
788
|
-
rb_raise(
|
795
|
+
rb_raise(rb_eNodeError, "could not get title");
|
789
796
|
}
|
790
797
|
|
791
798
|
return rb_str_new2(text);
|
@@ -807,7 +814,7 @@ static VALUE rb_node_set_title(VALUE self, VALUE title) {
|
|
807
814
|
text = StringValueCStr(title);
|
808
815
|
|
809
816
|
if (!cmark_node_set_title(node, text)) {
|
810
|
-
rb_raise(
|
817
|
+
rb_raise(rb_eNodeError, "could not set title");
|
811
818
|
}
|
812
819
|
|
813
820
|
return Qnil;
|
@@ -827,7 +834,7 @@ static VALUE rb_node_get_header_level(VALUE self) {
|
|
827
834
|
header_level = cmark_node_get_header_level(node);
|
828
835
|
|
829
836
|
if (header_level == 0) {
|
830
|
-
rb_raise(
|
837
|
+
rb_raise(rb_eNodeError, "could not get header_level");
|
831
838
|
}
|
832
839
|
|
833
840
|
return INT2NUM(header_level);
|
@@ -849,7 +856,7 @@ static VALUE rb_node_set_header_level(VALUE self, VALUE level) {
|
|
849
856
|
l = FIX2INT(level);
|
850
857
|
|
851
858
|
if (!cmark_node_set_header_level(node, l)) {
|
852
|
-
rb_raise(
|
859
|
+
rb_raise(rb_eNodeError, "could not set header_level");
|
853
860
|
}
|
854
861
|
|
855
862
|
return Qnil;
|
@@ -874,7 +881,7 @@ static VALUE rb_node_get_list_type(VALUE self) {
|
|
874
881
|
} else if (list_type == CMARK_ORDERED_LIST) {
|
875
882
|
symbol = sym_ordered_list;
|
876
883
|
} else {
|
877
|
-
rb_raise(
|
884
|
+
rb_raise(rb_eNodeError, "could not get list_type");
|
878
885
|
}
|
879
886
|
|
880
887
|
return symbol;
|
@@ -899,11 +906,11 @@ static VALUE rb_node_set_list_type(VALUE self, VALUE list_type) {
|
|
899
906
|
} else if (list_type == sym_ordered_list) {
|
900
907
|
type = CMARK_ORDERED_LIST;
|
901
908
|
} else {
|
902
|
-
rb_raise(
|
909
|
+
rb_raise(rb_eNodeError, "invalid list_type");
|
903
910
|
}
|
904
911
|
|
905
912
|
if (!cmark_node_set_list_type(node, type)) {
|
906
|
-
rb_raise(
|
913
|
+
rb_raise(rb_eNodeError, "could not set list_type");
|
907
914
|
}
|
908
915
|
|
909
916
|
return Qnil;
|
@@ -922,7 +929,7 @@ static VALUE rb_node_get_list_start(VALUE self) {
|
|
922
929
|
|
923
930
|
if (cmark_node_get_type(node) != CMARK_NODE_LIST ||
|
924
931
|
cmark_node_get_list_type(node) != CMARK_ORDERED_LIST) {
|
925
|
-
rb_raise(
|
932
|
+
rb_raise(rb_eNodeError, "can't get list_start for non-ordered list %d",
|
926
933
|
cmark_node_get_list_type(node));
|
927
934
|
}
|
928
935
|
|
@@ -946,7 +953,7 @@ static VALUE rb_node_set_list_start(VALUE self, VALUE start) {
|
|
946
953
|
s = FIX2INT(start);
|
947
954
|
|
948
955
|
if (!cmark_node_set_list_start(node, s)) {
|
949
|
-
rb_raise(
|
956
|
+
rb_raise(rb_eNodeError, "could not set list_start");
|
950
957
|
}
|
951
958
|
|
952
959
|
return Qnil;
|
@@ -964,7 +971,7 @@ static VALUE rb_node_get_list_tight(VALUE self) {
|
|
964
971
|
Data_Get_Struct(self, cmark_node, node);
|
965
972
|
|
966
973
|
if (cmark_node_get_type(node) != CMARK_NODE_LIST) {
|
967
|
-
rb_raise(
|
974
|
+
rb_raise(rb_eNodeError, "can't get list_tight for non-list");
|
968
975
|
}
|
969
976
|
|
970
977
|
flag = cmark_node_get_list_tight(node);
|
@@ -986,7 +993,7 @@ static VALUE rb_node_set_list_tight(VALUE self, VALUE tight) {
|
|
986
993
|
t = RTEST(tight);
|
987
994
|
|
988
995
|
if (!cmark_node_set_list_tight(node, t)) {
|
989
|
-
rb_raise(
|
996
|
+
rb_raise(rb_eNodeError, "could not set list_tight");
|
990
997
|
}
|
991
998
|
|
992
999
|
return Qnil;
|
@@ -1006,7 +1013,7 @@ static VALUE rb_node_get_fence_info(VALUE self) {
|
|
1006
1013
|
fence_info = cmark_node_get_fence_info(node);
|
1007
1014
|
|
1008
1015
|
if (fence_info == NULL) {
|
1009
|
-
rb_raise(
|
1016
|
+
rb_raise(rb_eNodeError, "could not get fence_info");
|
1010
1017
|
}
|
1011
1018
|
|
1012
1019
|
return rb_str_new2(fence_info);
|
@@ -1028,24 +1035,64 @@ static VALUE rb_node_set_fence_info(VALUE self, VALUE info) {
|
|
1028
1035
|
text = StringValueCStr(info);
|
1029
1036
|
|
1030
1037
|
if (!cmark_node_set_fence_info(node, text)) {
|
1031
|
-
rb_raise(
|
1038
|
+
rb_raise(rb_eNodeError, "could not set fence_info");
|
1032
1039
|
}
|
1033
1040
|
|
1034
1041
|
return Qnil;
|
1035
1042
|
}
|
1036
1043
|
|
1037
|
-
static VALUE
|
1038
|
-
|
1044
|
+
static VALUE rb_node_get_tasklist_item_checked(VALUE self) {
|
1045
|
+
int tasklist_state;
|
1039
1046
|
cmark_node *node;
|
1040
1047
|
Data_Get_Struct(self, cmark_node, node);
|
1041
1048
|
|
1042
|
-
tasklist_state =
|
1049
|
+
tasklist_state = cmark_gfm_extensions_get_tasklist_item_checked(node);
|
1043
1050
|
|
1044
|
-
if (tasklist_state ==
|
1045
|
-
|
1051
|
+
if (tasklist_state == 1) {
|
1052
|
+
return Qtrue;
|
1053
|
+
} else {
|
1054
|
+
return Qfalse;
|
1046
1055
|
}
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
/*
|
1059
|
+
* Public: Sets the checkbox state of the current node (must be a `:tasklist`).
|
1060
|
+
*
|
1061
|
+
* item_checked - A {Boolean} representing the new checkbox state
|
1062
|
+
*
|
1063
|
+
* Returns a {Boolean} representing the new checkbox state.
|
1064
|
+
* Raises a NodeError if the checkbox state can't be set.
|
1065
|
+
*/
|
1066
|
+
static VALUE rb_node_set_tasklist_item_checked(VALUE self, VALUE item_checked) {
|
1067
|
+
int tasklist_state;
|
1068
|
+
cmark_node *node;
|
1069
|
+
Data_Get_Struct(self, cmark_node, node);
|
1070
|
+
tasklist_state = RTEST(item_checked);
|
1047
1071
|
|
1048
|
-
|
1072
|
+
if (!cmark_gfm_extensions_set_tasklist_item_checked(node, tasklist_state)) {
|
1073
|
+
rb_raise(rb_eNodeError, "could not set tasklist_item_checked");
|
1074
|
+
};
|
1075
|
+
|
1076
|
+
if (tasklist_state) {
|
1077
|
+
return Qtrue;
|
1078
|
+
} else {
|
1079
|
+
return Qfalse;
|
1080
|
+
}
|
1081
|
+
}
|
1082
|
+
|
1083
|
+
// TODO: remove this, superseded by the above method
|
1084
|
+
static VALUE rb_node_get_tasklist_state(VALUE self) {
|
1085
|
+
int tasklist_state;
|
1086
|
+
cmark_node *node;
|
1087
|
+
Data_Get_Struct(self, cmark_node, node);
|
1088
|
+
|
1089
|
+
tasklist_state = cmark_gfm_extensions_get_tasklist_item_checked(node);
|
1090
|
+
|
1091
|
+
if (tasklist_state == 1) {
|
1092
|
+
return rb_str_new2("checked");
|
1093
|
+
} else {
|
1094
|
+
return rb_str_new2("unchecked");
|
1095
|
+
}
|
1049
1096
|
}
|
1050
1097
|
|
1051
1098
|
static VALUE rb_node_get_table_alignments(VALUE self) {
|
@@ -1059,7 +1106,7 @@ static VALUE rb_node_get_table_alignments(VALUE self) {
|
|
1059
1106
|
alignments = cmark_gfm_extensions_get_table_alignments(node);
|
1060
1107
|
|
1061
1108
|
if (!column_count || !alignments) {
|
1062
|
-
rb_raise(
|
1109
|
+
rb_raise(rb_eNodeError, "could not get column_count or alignments");
|
1063
1110
|
}
|
1064
1111
|
|
1065
1112
|
ary = rb_ary_new();
|
@@ -1090,7 +1137,8 @@ static VALUE rb_html_escape_href(VALUE self, VALUE rb_text) {
|
|
1090
1137
|
if (houdini_escape_href(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
|
1091
1138
|
RSTRING_LEN(rb_text))) {
|
1092
1139
|
result = (char *)cmark_strbuf_detach(&buf);
|
1093
|
-
return
|
1140
|
+
return encode_source_string(result, rb_text);
|
1141
|
+
|
1094
1142
|
}
|
1095
1143
|
|
1096
1144
|
return rb_text;
|
@@ -1110,7 +1158,7 @@ static VALUE rb_html_escape_html(VALUE self, VALUE rb_text) {
|
|
1110
1158
|
if (houdini_escape_html0(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
|
1111
1159
|
RSTRING_LEN(rb_text), 0)) {
|
1112
1160
|
result = (char *)cmark_strbuf_detach(&buf);
|
1113
|
-
return
|
1161
|
+
return encode_source_string(result, rb_text);
|
1114
1162
|
}
|
1115
1163
|
|
1116
1164
|
return rb_text;
|
@@ -1164,49 +1212,51 @@ __attribute__((visibility("default"))) void Init_commonmarker() {
|
|
1164
1212
|
|
1165
1213
|
module = rb_define_module("CommonMarker");
|
1166
1214
|
rb_define_singleton_method(module, "extensions", rb_extensions, 0);
|
1167
|
-
|
1168
|
-
|
1169
|
-
rb_define_singleton_method(
|
1215
|
+
rb_eNodeError = rb_define_class_under(module, "NodeError", rb_eStandardError);
|
1216
|
+
rb_cNode = rb_define_class_under(module, "Node", rb_cObject);
|
1217
|
+
rb_define_singleton_method(rb_cNode, "markdown_to_html", rb_markdown_to_html,
|
1170
1218
|
3);
|
1171
|
-
rb_define_singleton_method(
|
1172
|
-
rb_define_singleton_method(
|
1173
|
-
rb_define_method(
|
1174
|
-
rb_define_method(
|
1175
|
-
rb_define_method(
|
1176
|
-
rb_define_method(
|
1177
|
-
rb_define_method(
|
1178
|
-
rb_define_method(
|
1179
|
-
rb_define_method(
|
1180
|
-
rb_define_method(
|
1181
|
-
rb_define_method(
|
1182
|
-
rb_define_method(
|
1183
|
-
rb_define_method(
|
1184
|
-
rb_define_method(
|
1185
|
-
rb_define_method(
|
1186
|
-
rb_define_method(
|
1187
|
-
rb_define_method(
|
1188
|
-
rb_define_method(
|
1189
|
-
rb_define_method(
|
1190
|
-
rb_define_method(
|
1191
|
-
rb_define_method(
|
1192
|
-
rb_define_method(
|
1193
|
-
rb_define_method(
|
1194
|
-
rb_define_method(
|
1195
|
-
rb_define_method(
|
1196
|
-
rb_define_method(
|
1197
|
-
rb_define_method(
|
1198
|
-
rb_define_method(
|
1199
|
-
rb_define_method(
|
1200
|
-
rb_define_method(
|
1201
|
-
rb_define_method(
|
1202
|
-
rb_define_method(
|
1203
|
-
rb_define_method(
|
1204
|
-
rb_define_method(
|
1205
|
-
rb_define_method(
|
1206
|
-
rb_define_method(
|
1207
|
-
|
1208
|
-
rb_define_method(
|
1209
|
-
|
1219
|
+
rb_define_singleton_method(rb_cNode, "new", rb_node_new, 1);
|
1220
|
+
rb_define_singleton_method(rb_cNode, "parse_document", rb_parse_document, 4);
|
1221
|
+
rb_define_method(rb_cNode, "string_content", rb_node_get_string_content, 0);
|
1222
|
+
rb_define_method(rb_cNode, "string_content=", rb_node_set_string_content, 1);
|
1223
|
+
rb_define_method(rb_cNode, "type", rb_node_get_type, 0);
|
1224
|
+
rb_define_method(rb_cNode, "type_string", rb_node_get_type_string, 0);
|
1225
|
+
rb_define_method(rb_cNode, "sourcepos", rb_node_get_sourcepos, 0);
|
1226
|
+
rb_define_method(rb_cNode, "delete", rb_node_unlink, 0);
|
1227
|
+
rb_define_method(rb_cNode, "first_child", rb_node_first_child, 0);
|
1228
|
+
rb_define_method(rb_cNode, "next", rb_node_next, 0);
|
1229
|
+
rb_define_method(rb_cNode, "insert_before", rb_node_insert_before, 1);
|
1230
|
+
rb_define_method(rb_cNode, "_render_html", rb_render_html, 2);
|
1231
|
+
rb_define_method(rb_cNode, "_render_commonmark", rb_render_commonmark, -1);
|
1232
|
+
rb_define_method(rb_cNode, "_render_plaintext", rb_render_plaintext, -1);
|
1233
|
+
rb_define_method(rb_cNode, "insert_after", rb_node_insert_after, 1);
|
1234
|
+
rb_define_method(rb_cNode, "prepend_child", rb_node_prepend_child, 1);
|
1235
|
+
rb_define_method(rb_cNode, "append_child", rb_node_append_child, 1);
|
1236
|
+
rb_define_method(rb_cNode, "last_child", rb_node_last_child, 0);
|
1237
|
+
rb_define_method(rb_cNode, "parent", rb_node_parent, 0);
|
1238
|
+
rb_define_method(rb_cNode, "previous", rb_node_previous, 0);
|
1239
|
+
rb_define_method(rb_cNode, "url", rb_node_get_url, 0);
|
1240
|
+
rb_define_method(rb_cNode, "url=", rb_node_set_url, 1);
|
1241
|
+
rb_define_method(rb_cNode, "title", rb_node_get_title, 0);
|
1242
|
+
rb_define_method(rb_cNode, "title=", rb_node_set_title, 1);
|
1243
|
+
rb_define_method(rb_cNode, "header_level", rb_node_get_header_level, 0);
|
1244
|
+
rb_define_method(rb_cNode, "header_level=", rb_node_set_header_level, 1);
|
1245
|
+
rb_define_method(rb_cNode, "list_type", rb_node_get_list_type, 0);
|
1246
|
+
rb_define_method(rb_cNode, "list_type=", rb_node_set_list_type, 1);
|
1247
|
+
rb_define_method(rb_cNode, "list_start", rb_node_get_list_start, 0);
|
1248
|
+
rb_define_method(rb_cNode, "list_start=", rb_node_set_list_start, 1);
|
1249
|
+
rb_define_method(rb_cNode, "list_tight", rb_node_get_list_tight, 0);
|
1250
|
+
rb_define_method(rb_cNode, "list_tight=", rb_node_set_list_tight, 1);
|
1251
|
+
rb_define_method(rb_cNode, "fence_info", rb_node_get_fence_info, 0);
|
1252
|
+
rb_define_method(rb_cNode, "fence_info=", rb_node_set_fence_info, 1);
|
1253
|
+
rb_define_method(rb_cNode, "table_alignments", rb_node_get_table_alignments, 0);
|
1254
|
+
rb_define_method(rb_cNode, "tasklist_state", rb_node_get_tasklist_state, 0);
|
1255
|
+
rb_define_method(rb_cNode, "tasklist_item_checked?", rb_node_get_tasklist_item_checked, 0);
|
1256
|
+
rb_define_method(rb_cNode, "tasklist_item_checked=", rb_node_set_tasklist_item_checked, 1);
|
1257
|
+
|
1258
|
+
rb_define_method(rb_cNode, "html_escape_href", rb_html_escape_href, 1);
|
1259
|
+
rb_define_method(rb_cNode, "html_escape_html", rb_html_escape_html, 1);
|
1210
1260
|
|
1211
1261
|
cmark_gfm_core_extensions_ensure_registered();
|
1212
1262
|
}
|