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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 237799ebff0e881aabc44799deac5c31a201307b
4
- data.tar.gz: c2ebbe9b5bf5cc3ff8cb218c92a280eeb6aca70f
2
+ SHA256:
3
+ metadata.gz: f5356237deaf85df9914e0c7fa3f121fa0301579653b83b006df4dd8404c65f2
4
+ data.tar.gz: 9d4a09830e1c107dec28e47a3c0ab96f2cc6bcd9786982e38607752022ec12f1
5
5
  SHA512:
6
- metadata.gz: 2d5122a6869dc1b0e112a7ca8afcadfc53fda72c75f5bc0486e7046e59094f67f72f80955af1cc5fd6604ecea76361ee511c124b47f1c66f3f01496cf5a6b6ad
7
- data.tar.gz: 39f7183d9f048c72729a916cefca93fecdc55e95054ff019fdeddc2ad94be5dbeb61c2c4ef7175373a0c2d520a72ad3743e415700bcbade0eb5dcdc37443ed16
6
+ metadata.gz: 7e43f365eb266fa8c0627572999a2102df7dd65e0404917c5fa6054b532c526a35ad5d0ef9423cf68033edc52fb0c20da79ca73d7345b04d4493f33bff35ed73
7
+ data.tar.gz: 0e5da729c2247288a1bf60672f572f785def6e2a1726afeaf87aa1332d083e4834d52c403479a36437f9c0a9e99548569f7d5bc092a405304ccef81ac71096b1
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CommonMarker
2
2
 
3
- [![Build Status](https://travis-ci.org/gjtorikian/commonmarker.svg)](https://travis-ci.org/gjtorikian/commonmarker) [![Gem Version](https://badge.fury.io/rb/commonmarker.svg)](http://badge.fury.io/rb/commonmarker)
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
- print(myrenderer.render(doc))
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(test:unit)
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(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)
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
- # Usage: commonmarker [--html-renderer] [--list-extensions] [--extension=EXTENSION] [FILE..]
5
- # Convert one or more CommonMark files to HTML and write to standard output.
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
- if ARGV.include?('--version') or ARGV.include?('-v')
22
- puts "commonmarker #{CommonMarker::VERSION}"
23
- exit 0
24
- end
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
- root = File.expand_path('../../', __FILE__)
27
- $:.unshift File.expand_path('lib', root)
28
-
29
- extensions = CommonMarker.extensions
30
- active_extensions = []
31
-
32
- renderer = nil
33
- ARGV.delete_if do |arg|
34
- if arg =~ /^--html-renderer$/
35
- renderer = true
36
- true
37
- elsif arg =~ /^--list-extensions$/
38
- puts extensions
39
- exit 0
40
- elsif arg =~ /^--extension=(.+)$/
41
- if extensions.include?($1)
42
- active_extensions << $1.intern
43
- else
44
- STDERR.puts "extension #$1 not found"
45
- exit 1
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
- doc = CommonMarker.render_doc(ARGF.read, :DEFAULT, active_extensions)
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
- STDOUT.write(renderer.render(doc))
93
+ if options.renderer
94
+ renderer = CommonMarker::HtmlRenderer.new(extensions: options.active_extensions)
95
+ $stdout.write(renderer.render(doc))
58
96
  else
59
- STDOUT.write(doc.to_html(:DEFAULT, active_extensions))
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('../lib', __FILE__)
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 = ['Garen Torikian', 'Ashe Connor']
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(LICENSE.txt README.md Rakefile commonmarker.gemspec bin/commonmarker)
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(lib ext)
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.add_dependency 'ruby-enum', '~> 0.5'
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 'rdoc', '~> 5.1'
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
- char *cmark_gfm_extensions_get_tasklist_state(cmark_node *node);
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 rb_mNodeError;
11
- static VALUE rb_mNode;
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(rb_mNode, rb_mark_c_struct, free_func, node);
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(rb_mNodeError, "error parsing document");
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(rb_mNodeError, "invalid node of type %d", node_type);
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(rb_mNodeError, "could not create node of type %d", node_type);
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(rb_mNodeError, "error parsing document");
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(rb_mNodeError, "could not get string content");
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(rb_mNodeError, "could not set string content");
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(rb_mNodeError, "invalid node type %d", node_type);
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(rb_mNodeError, "could not insert before");
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(rb_mNodeError, "could not insert after");
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(rb_mNodeError, "could not prepend child");
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(rb_mNodeError, "could not append child");
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(rb_mNodeError, "could not get url");
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(rb_mNodeError, "could not set url");
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(rb_mNodeError, "could not get title");
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(rb_mNodeError, "could not set title");
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(rb_mNodeError, "could not get header_level");
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(rb_mNodeError, "could not set header_level");
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(rb_mNodeError, "could not get list_type");
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(rb_mNodeError, "invalid list_type");
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(rb_mNodeError, "could not set list_type");
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(rb_mNodeError, "can't get list_start for non-ordered list %d",
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(rb_mNodeError, "could not set list_start");
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(rb_mNodeError, "can't get list_tight for non-list");
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(rb_mNodeError, "could not set list_tight");
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(rb_mNodeError, "could not get fence_info");
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(rb_mNodeError, "could not set fence_info");
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 rb_node_get_tasklist_state(VALUE self) {
1038
- const char *tasklist_state;
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 = cmark_gfm_extensions_get_tasklist_state(node);
1049
+ tasklist_state = cmark_gfm_extensions_get_tasklist_item_checked(node);
1043
1050
 
1044
- if (tasklist_state == NULL) {
1045
- rb_raise(rb_mNodeError, "could not get tasklist_state");
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
- return rb_str_new2(tasklist_state);
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(rb_mNodeError, "could not get column_count or alignments");
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 rb_str_new2(result);
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 rb_str_new2(result);
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
- rb_mNodeError = rb_define_class_under(module, "NodeError", rb_eStandardError);
1168
- rb_mNode = rb_define_class_under(module, "Node", rb_cObject);
1169
- rb_define_singleton_method(rb_mNode, "markdown_to_html", rb_markdown_to_html,
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(rb_mNode, "new", rb_node_new, 1);
1172
- rb_define_singleton_method(rb_mNode, "parse_document", rb_parse_document, 4);
1173
- rb_define_method(rb_mNode, "string_content", rb_node_get_string_content, 0);
1174
- rb_define_method(rb_mNode, "string_content=", rb_node_set_string_content, 1);
1175
- rb_define_method(rb_mNode, "type", rb_node_get_type, 0);
1176
- rb_define_method(rb_mNode, "type_string", rb_node_get_type_string, 0);
1177
- rb_define_method(rb_mNode, "sourcepos", rb_node_get_sourcepos, 0);
1178
- rb_define_method(rb_mNode, "delete", rb_node_unlink, 0);
1179
- rb_define_method(rb_mNode, "first_child", rb_node_first_child, 0);
1180
- rb_define_method(rb_mNode, "next", rb_node_next, 0);
1181
- rb_define_method(rb_mNode, "insert_before", rb_node_insert_before, 1);
1182
- rb_define_method(rb_mNode, "_render_html", rb_render_html, 2);
1183
- rb_define_method(rb_mNode, "_render_commonmark", rb_render_commonmark, -1);
1184
- rb_define_method(rb_mNode, "_render_plaintext", rb_render_plaintext, -1);
1185
- rb_define_method(rb_mNode, "insert_after", rb_node_insert_after, 1);
1186
- rb_define_method(rb_mNode, "prepend_child", rb_node_prepend_child, 1);
1187
- rb_define_method(rb_mNode, "append_child", rb_node_append_child, 1);
1188
- rb_define_method(rb_mNode, "last_child", rb_node_last_child, 0);
1189
- rb_define_method(rb_mNode, "parent", rb_node_parent, 0);
1190
- rb_define_method(rb_mNode, "previous", rb_node_previous, 0);
1191
- rb_define_method(rb_mNode, "url", rb_node_get_url, 0);
1192
- rb_define_method(rb_mNode, "url=", rb_node_set_url, 1);
1193
- rb_define_method(rb_mNode, "title", rb_node_get_title, 0);
1194
- rb_define_method(rb_mNode, "title=", rb_node_set_title, 1);
1195
- rb_define_method(rb_mNode, "header_level", rb_node_get_header_level, 0);
1196
- rb_define_method(rb_mNode, "header_level=", rb_node_set_header_level, 1);
1197
- rb_define_method(rb_mNode, "list_type", rb_node_get_list_type, 0);
1198
- rb_define_method(rb_mNode, "list_type=", rb_node_set_list_type, 1);
1199
- rb_define_method(rb_mNode, "list_start", rb_node_get_list_start, 0);
1200
- rb_define_method(rb_mNode, "list_start=", rb_node_set_list_start, 1);
1201
- rb_define_method(rb_mNode, "list_tight", rb_node_get_list_tight, 0);
1202
- rb_define_method(rb_mNode, "list_tight=", rb_node_set_list_tight, 1);
1203
- rb_define_method(rb_mNode, "fence_info", rb_node_get_fence_info, 0);
1204
- rb_define_method(rb_mNode, "fence_info=", rb_node_set_fence_info, 1);
1205
- rb_define_method(rb_mNode, "table_alignments", rb_node_get_table_alignments, 0);
1206
- rb_define_method(rb_mNode, "tasklist_state", rb_node_get_tasklist_state, 0);
1207
-
1208
- rb_define_method(rb_mNode, "html_escape_href", rb_html_escape_href, 1);
1209
- rb_define_method(rb_mNode, "html_escape_html", rb_html_escape_html, 1);
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
  }