commonmarker 0.19.0 → 0.21.1

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.

Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +2 -3
  3. data/Rakefile +16 -4
  4. data/bin/commonmarker +82 -44
  5. data/commonmarker.gemspec +9 -12
  6. data/ext/commonmarker/blocks.c +89 -29
  7. data/ext/commonmarker/buffer.c +0 -1
  8. data/ext/commonmarker/chunk.h +0 -1
  9. data/ext/commonmarker/cmark-gfm-core-extensions.h +24 -1
  10. data/ext/commonmarker/cmark-gfm.h +14 -8
  11. data/ext/commonmarker/cmark-gfm_version.h +2 -2
  12. data/ext/commonmarker/commonmark.c +9 -4
  13. data/ext/commonmarker/commonmarker.c +120 -78
  14. data/ext/commonmarker/html.c +4 -4
  15. data/ext/commonmarker/inlines.c +21 -14
  16. data/ext/commonmarker/iterator.h +0 -1
  17. data/ext/commonmarker/map.h +0 -1
  18. data/ext/commonmarker/node.h +2 -0
  19. data/ext/commonmarker/parser.h +2 -1
  20. data/ext/commonmarker/render.c +16 -14
  21. data/ext/commonmarker/render.h +0 -1
  22. data/ext/commonmarker/scanners.c +777 -951
  23. data/ext/commonmarker/scanners.h +0 -2
  24. data/ext/commonmarker/table.c +52 -13
  25. data/ext/commonmarker/tasklist.c +34 -13
  26. data/lib/commonmarker.rb +5 -4
  27. data/lib/commonmarker/config.rb +5 -4
  28. data/lib/commonmarker/node.rb +1 -1
  29. data/lib/commonmarker/node/inspect.rb +12 -12
  30. data/lib/commonmarker/renderer.rb +7 -7
  31. data/lib/commonmarker/renderer/html_renderer.rb +22 -35
  32. data/lib/commonmarker/version.rb +1 -1
  33. data/test/benchmark.rb +1 -5
  34. data/test/fixtures/strong.md +1 -0
  35. data/test/fixtures/table.md +10 -0
  36. data/test/test_attributes.rb +3 -3
  37. data/test/test_commands.rb +31 -0
  38. data/test/test_commonmark.rb +11 -11
  39. data/test/test_encoding.rb +1 -2
  40. data/test/test_extensions.rb +40 -52
  41. data/test/test_footnotes.rb +9 -9
  42. data/test/test_gc.rb +2 -0
  43. data/test/test_helper.rb +15 -8
  44. data/test/test_maliciousness.rb +192 -190
  45. data/test/test_node.rb +10 -12
  46. data/test/test_options.rb +15 -15
  47. data/test/test_pathological_inputs.rb +2 -2
  48. data/test/test_plaintext.rb +21 -21
  49. data/test/test_renderer.rb +9 -9
  50. data/test/test_spec.rb +3 -2
  51. data/test/test_tasklists.rb +22 -6
  52. metadata +51 -46
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a9c068146510f80180b4524934cf90ba56044100
4
- data.tar.gz: 5d5ff7d6b1a68340d8e330d6b6a1e9b1d01df944
2
+ SHA256:
3
+ metadata.gz: 1a1380e99f120ae24a27bae6244ffeab5b0b3fe828155828cf8c092d8c83471a
4
+ data.tar.gz: 92c85125c0e4d6f8673312e64e67feda6993a4fc1250661fad3714836bc96454
5
5
  SHA512:
6
- metadata.gz: 828329dac75b03c52a50674a53a994791bc6c26fb05fc7fed4377ff241e7b87560b3dd9b2aa8be0b0a4e2a7ac194500a4e584872c6a1bc44618a13e3cad741f8
7
- data.tar.gz: 5bf814489204bf76b497cd8dd570dd88b1f8af8f9a45847dad091b756b243ae618466e8e85441c4e39a0d22191e3a2001ee15c8309a80ec93f630952c92e0108
6
+ metadata.gz: 5f136c3413348cea8e3a0f3e8b0242ffc8bba92b9004278170ee7d2532e87b6c5d6af73c952d2c31d509143ae2cfe63d96aeca6ff4749a599fefbcad7580214e
7
+ data.tar.gz: 4d33d9cb161d0b484ed9bc353c9c01dd3f8715f533c05a2f7f61a16792433153d19324d1b62a0ae6b6750441917843495349a1140e93d2b1960794ea0346e444
data/README.md CHANGED
@@ -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|
@@ -176,6 +174,7 @@ Both `render_html` and `render_doc` take an optional third argument defining the
176
174
  The available extensions are:
177
175
 
178
176
  * `:table` - This provides support for tables.
177
+ * `:tasklist` - This provides support for task list items.
179
178
  * `:strikethrough` - This provides support for strikethroughs.
180
179
  * `:autolink` - This provides support for automatically converting URLs to anchor tags.
181
180
  * `: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}")
@@ -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::Parse
17
+ render_options = CommonMarker::Config::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)
93
+ if options.renderer
94
+ renderer = CommonMarker::HtmlRenderer.new(extensions: options.active_extensions)
57
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
@@ -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,30 @@ 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
- s.test_files = Dir.glob('test/**/*')
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]
27
24
 
28
25
  s.rdoc_options += ['-x', 'ext/commonmarker/cmark/.*']
29
26
 
30
27
  s.add_dependency 'ruby-enum', '~> 0.5'
31
28
 
29
+ s.add_development_dependency 'awesome_print'
30
+ s.add_development_dependency 'json', '~> 2.3'
32
31
  s.add_development_dependency 'minitest', '~> 5.6'
33
32
  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
33
  s.add_development_dependency 'rake'
38
- s.add_development_dependency 'rdoc', '~> 5.1'
34
+ s.add_development_dependency 'rake-compiler', '~> 0.9'
35
+ s.add_development_dependency 'rdoc', '~> 6.2'
39
36
  s.add_development_dependency 'rubocop'
40
37
  s.add_development_dependency 'rubocop-standard'
41
38
  end
@@ -36,6 +36,10 @@ static bool S_last_line_blank(const cmark_node *node) {
36
36
  return (node->flags & CMARK_NODE__LAST_LINE_BLANK) != 0;
37
37
  }
38
38
 
39
+ static bool S_last_line_checked(const cmark_node *node) {
40
+ return (node->flags & CMARK_NODE__LAST_LINE_CHECKED) != 0;
41
+ }
42
+
39
43
  static CMARK_INLINE cmark_node_type S_type(const cmark_node *node) {
40
44
  return (cmark_node_type)node->type;
41
45
  }
@@ -47,6 +51,10 @@ static void S_set_last_line_blank(cmark_node *node, bool is_blank) {
47
51
  node->flags &= ~CMARK_NODE__LAST_LINE_BLANK;
48
52
  }
49
53
 
54
+ static void S_set_last_line_checked(cmark_node *node) {
55
+ node->flags |= CMARK_NODE__LAST_LINE_CHECKED;
56
+ }
57
+
50
58
  static CMARK_INLINE bool S_is_line_end_char(char c) {
51
59
  return (c == '\n' || c == '\r');
52
60
  }
@@ -121,8 +129,6 @@ static void cmark_parser_reset(cmark_parser *parser) {
121
129
  parser->root = document;
122
130
  parser->current = document;
123
131
 
124
- parser->last_buffer_ended_with_cr = false;
125
-
126
132
  parser->syntax_extensions = saved_exts;
127
133
  parser->inline_syntax_extensions = saved_inline_exts;
128
134
  parser->options = saved_options;
@@ -234,19 +240,35 @@ static void remove_trailing_blank_lines(cmark_strbuf *ln) {
234
240
 
235
241
  // Check to see if a node ends with a blank line, descending
236
242
  // if needed into lists and sublists.
237
- static bool ends_with_blank_line(cmark_node *node) {
238
- cmark_node *cur = node;
239
- while (cur != NULL) {
240
- if (S_last_line_blank(cur)) {
241
- return true;
242
- }
243
- if (S_type(cur) == CMARK_NODE_LIST || S_type(cur) == CMARK_NODE_ITEM) {
244
- cur = cur->last_child;
245
- } else {
246
- cur = NULL;
247
- }
243
+ static bool S_ends_with_blank_line(cmark_node *node) {
244
+ if (S_last_line_checked(node)) {
245
+ return(S_last_line_blank(node));
246
+ } else if ((S_type(node) == CMARK_NODE_LIST ||
247
+ S_type(node) == CMARK_NODE_ITEM) && node->last_child) {
248
+ S_set_last_line_checked(node);
249
+ return(S_ends_with_blank_line(node->last_child));
250
+ } else {
251
+ S_set_last_line_checked(node);
252
+ return (S_last_line_blank(node));
248
253
  }
249
- return false;
254
+ }
255
+
256
+ // returns true if content remains after link defs are resolved.
257
+ static bool resolve_reference_link_definitions(
258
+ cmark_parser *parser,
259
+ cmark_node *b) {
260
+ bufsize_t pos;
261
+ cmark_strbuf *node_content = &b->content;
262
+ cmark_chunk chunk = {node_content->ptr, node_content->size, 0};
263
+ while (chunk.len && chunk.data[0] == '[' &&
264
+ (pos = cmark_parse_reference_inline(parser->mem, &chunk,
265
+ parser->refmap))) {
266
+
267
+ chunk.data += pos;
268
+ chunk.len -= pos;
269
+ }
270
+ cmark_strbuf_drop(node_content, (node_content->size - chunk.len));
271
+ return !is_blank(&b->content, 0);
250
272
  }
251
273
 
252
274
  static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
@@ -254,6 +276,7 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
254
276
  cmark_node *item;
255
277
  cmark_node *subitem;
256
278
  cmark_node *parent;
279
+ bool has_content;
257
280
 
258
281
  parent = b->parent;
259
282
  assert(b->flags &
@@ -283,15 +306,8 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
283
306
  switch (S_type(b)) {
284
307
  case CMARK_NODE_PARAGRAPH:
285
308
  {
286
- cmark_chunk chunk = {node_content->ptr, node_content->size, 0};
287
- while (chunk.len && chunk.data[0] == '[' &&
288
- (pos = cmark_parse_reference_inline(parser->mem, &chunk, parser->refmap))) {
289
-
290
- chunk.data += pos;
291
- chunk.len -= pos;
292
- }
293
- cmark_strbuf_drop(node_content, (node_content->size - chunk.len));
294
- if (is_blank(node_content, 0)) {
309
+ has_content = resolve_reference_link_definitions(parser, b);
310
+ if (!has_content) {
295
311
  // remove blank node (former reference def)
296
312
  cmark_node_free(b);
297
313
  }
@@ -343,7 +359,8 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
343
359
  // spaces between them:
344
360
  subitem = item->first_child;
345
361
  while (subitem) {
346
- if (ends_with_blank_line(subitem) && (item->next || subitem->next)) {
362
+ if ((item->next || subitem->next) &&
363
+ S_ends_with_blank_line(subitem)) {
347
364
  b->as.list.tight = false;
348
365
  break;
349
366
  }
@@ -748,6 +765,40 @@ static void chop_trailing_hashtags(cmark_chunk *ch) {
748
765
  }
749
766
  }
750
767
 
768
+ // Check for thematic break. On failure, return 0 and update
769
+ // thematic_break_kill_pos with the index at which the
770
+ // parse fails. On success, return length of match.
771
+ // "...three or more hyphens, asterisks,
772
+ // or underscores on a line by themselves. If you wish, you may use
773
+ // spaces between the hyphens or asterisks."
774
+ static int S_scan_thematic_break(cmark_parser *parser, cmark_chunk *input,
775
+ bufsize_t offset) {
776
+ bufsize_t i;
777
+ char c;
778
+ char nextc = '\0';
779
+ int count;
780
+ i = offset;
781
+ c = peek_at(input, i);
782
+ if (!(c == '*' || c == '_' || c == '-')) {
783
+ parser->thematic_break_kill_pos = i;
784
+ return 0;
785
+ }
786
+ count = 1;
787
+ while ((nextc = peek_at(input, ++i))) {
788
+ if (nextc == c) {
789
+ count++;
790
+ } else if (nextc != ' ' && nextc != '\t') {
791
+ break;
792
+ }
793
+ }
794
+ if (count >= 3 && (nextc == '\r' || nextc == '\n')) {
795
+ return (i - offset) + 1;
796
+ } else {
797
+ parser->thematic_break_kill_pos = i;
798
+ return 0;
799
+ }
800
+ }
801
+
751
802
  // Find first nonspace character from current offset, setting
752
803
  // parser->first_nonspace, parser->first_nonspace_column,
753
804
  // parser->indent, and parser->blank. Does not advance parser->offset.
@@ -1040,6 +1091,7 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
1040
1091
  bufsize_t matched = 0;
1041
1092
  int lev = 0;
1042
1093
  bool save_partially_consumed_tab;
1094
+ bool has_content;
1043
1095
  int save_offset;
1044
1096
  int save_column;
1045
1097
 
@@ -1112,13 +1164,20 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
1112
1164
  } else if (!indented && cont_type == CMARK_NODE_PARAGRAPH &&
1113
1165
  (lev =
1114
1166
  scan_setext_heading_line(input, parser->first_nonspace))) {
1115
- (*container)->type = (uint16_t)CMARK_NODE_HEADING;
1116
- (*container)->as.heading.level = lev;
1117
- (*container)->as.heading.setext = true;
1118
- S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
1167
+ // finalize paragraph, resolving reference links
1168
+ has_content = resolve_reference_link_definitions(parser, *container);
1169
+
1170
+ if (has_content) {
1171
+
1172
+ (*container)->type = (uint16_t)CMARK_NODE_HEADING;
1173
+ (*container)->as.heading.level = lev;
1174
+ (*container)->as.heading.setext = true;
1175
+ S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
1176
+ }
1119
1177
  } else if (!indented &&
1120
1178
  !(cont_type == CMARK_NODE_PARAGRAPH && !all_matched) &&
1121
- (matched = scan_thematic_break(input, parser->first_nonspace))) {
1179
+ (parser->thematic_break_kill_pos <= parser->first_nonspace) &&
1180
+ (matched = S_scan_thematic_break(parser, input, parser->first_nonspace))) {
1122
1181
  // it's only now that we know the line is not part of a setext heading:
1123
1182
  *container = add_child(parser, *container, CMARK_NODE_THEMATIC_BREAK,
1124
1183
  parser->first_nonspace + 1);
@@ -1377,6 +1436,7 @@ static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
1377
1436
  parser->column = 0;
1378
1437
  parser->first_nonspace = 0;
1379
1438
  parser->first_nonspace_column = 0;
1439
+ parser->thematic_break_kill_pos = 0;
1380
1440
  parser->indent = 0;
1381
1441
  parser->blank = false;
1382
1442
  parser->partially_consumed_tab = false;