qiita_marker 0.23.2.1 → 0.23.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +19 -17
  3. data/README.md +2 -0
  4. data/Rakefile +57 -56
  5. data/bin/qiita_marker +2 -7
  6. data/ext/qiita_marker/autolink.c +57 -10
  7. data/ext/qiita_marker/cmark-gfm_version.h +2 -2
  8. data/ext/qiita_marker/html.c +1 -1
  9. data/ext/qiita_marker/qfm.h +3 -0
  10. data/ext/qiita_marker/qfm_custom_block.c +1 -14
  11. data/ext/qiita_marker/qfm_mention_no_emphasis.c +1 -1
  12. data/ext/qiita_marker/qiita_marker.c +30 -44
  13. data/ext/qiita_marker/scanners.c +2438 -2450
  14. data/ext/qiita_marker/table.c +28 -2
  15. data/lib/qiita_marker/config.rb +5 -3
  16. data/lib/qiita_marker/node/inspect.rb +8 -18
  17. data/lib/qiita_marker/node.rb +6 -6
  18. data/lib/qiita_marker/renderer/html_renderer.rb +39 -39
  19. data/lib/qiita_marker/renderer.rb +5 -5
  20. data/lib/qiita_marker/version.rb +1 -1
  21. data/lib/qiita_marker.rb +9 -11
  22. data/qiita_marker.gemspec +27 -29
  23. metadata +3 -61
  24. data/test/benchmark.rb +0 -32
  25. data/test/fixtures/curly.md +0 -1
  26. data/test/fixtures/dingus.md +0 -10
  27. data/test/fixtures/strong.md +0 -1
  28. data/test/fixtures/table.md +0 -10
  29. data/test/test_attributes.rb +0 -24
  30. data/test/test_basics.rb +0 -35
  31. data/test/test_commands.rb +0 -72
  32. data/test/test_commonmark.rb +0 -36
  33. data/test/test_doc.rb +0 -130
  34. data/test/test_encoding.rb +0 -23
  35. data/test/test_extensions.rb +0 -116
  36. data/test/test_footnotes.rb +0 -60
  37. data/test/test_gc.rb +0 -47
  38. data/test/test_helper.rb +0 -71
  39. data/test/test_linebreaks.rb +0 -15
  40. data/test/test_maliciousness.rb +0 -262
  41. data/test/test_node.rb +0 -89
  42. data/test/test_options.rb +0 -37
  43. data/test/test_pathological_inputs.rb +0 -94
  44. data/test/test_plaintext.rb +0 -46
  45. data/test/test_qfm_code_data_metadata.rb +0 -26
  46. data/test/test_qfm_custom_block.rb +0 -23
  47. data/test/test_qfm_mention_no_emphasis.rb +0 -60
  48. data/test/test_renderer.rb +0 -47
  49. data/test/test_smartpunct.rb +0 -27
  50. data/test/test_spec.rb +0 -30
  51. data/test/test_tasklists.rb +0 -43
  52. data/test/test_xml.rb +0 -107
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0579157ad4abb4038246ef4dc4752fd1de6cd281daa619b2ef42adec5b147982'
4
- data.tar.gz: c671815ff61ab460fcf6c3a42a614018a250c62ceaa41ee0aa3e899f34c12b16
3
+ metadata.gz: 15bfc4813af77558d6c0b4ffbb931229e00d558d0c417048b636ce7c27ac31a7
4
+ data.tar.gz: af9febe461508838d294f9d2d20dfe896c30c467b82b50b36924040c7287c070
5
5
  SHA512:
6
- metadata.gz: 32f16ce193b82d6a7214c851fdd81126d42d872fdd4508b798ccfc4faba4668793274f88f9ef25e61ae57545041d1062c65169b05cd756eec55df0aa042d0140
7
- data.tar.gz: da050452749a3eee8d998db24aa45d6a8b1a282672283e427f8deca374405bfaebe572e954c7906ceb84bea2ff08ad737da05707b2ed5d378158d2738ac0e318
6
+ metadata.gz: 2fc608ddea2a044b4c64b9f32e8dbc44cf838213f6c67e9457f36fa303b7223a20c932a261e3f21fac256ceab34d018b9c6d9757ce86eecf250a3aefa585407b
7
+ data.tar.gz: 66b65a1652e9a0904423490cb8999de85d21928f169f72965ca2b90bc32cfadda46193662ebdae70dea6bcb5819a349256a24911f53c65d168bd9285db107968
data/LICENSE.txt CHANGED
@@ -1,21 +1,23 @@
1
- MIT License
1
+ Copyright (c) 2015 Garen J. Torikian
2
+ Copyright (c) 2021 Qiita Inc.
2
3
 
3
- Copyright 2021 Qiita Inc.
4
+ MIT License
4
5
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
11
13
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
14
16
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -20,6 +20,7 @@ In addition to CommonMarker's options and extensions, the following are availabl
20
20
  | Name | Description |
21
21
  | --- | --- |
22
22
  | `:MENTION_NO_EMPHASIS` | Prevent parsing mentions as emphasis. |
23
+ | `:AUTOLINK_CLASS_NAME` | Append `class="autolink"` to extension's autolinks. |
23
24
 
24
25
  #### Render options
25
26
 
@@ -27,6 +28,7 @@ In addition to CommonMarker's options and extensions, the following are availabl
27
28
  | --- | --- |
28
29
  | `:CODE_DATA_METADATA` | Use `<code data-metadata>` for fenced code blocks. |
29
30
  | `:MENTION_NO_EMPHASIS` | Prevent parsing mentions as emphasis. |
31
+ | `:AUTOLINK_CLASS_NAME` | Append `class="autolink"` to extension's autolinks. |
30
32
 
31
33
  ### Original extensions
32
34
 
data/Rakefile CHANGED
@@ -1,113 +1,114 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
4
- require 'rake/clean'
5
- require 'rake/extensiontask'
6
- require 'digest/md5'
3
+ require "date"
4
+ require "rake/clean"
5
+ require "rake/extensiontask"
6
+ require "digest/md5"
7
7
 
8
- host_os = RbConfig::CONFIG['host_os']
9
- require 'devkit' if host_os == 'mingw32'
8
+ host_os = RbConfig::CONFIG["host_os"]
9
+ require "devkit" if host_os == "mingw32"
10
10
 
11
11
  task default: [:test]
12
12
 
13
13
  # Gem Spec
14
- gem_spec = Gem::Specification.load('qiita_marker.gemspec')
14
+ gem_spec = Gem::Specification.load("qiita_marker.gemspec")
15
15
 
16
16
  # Ruby Extension
17
- Rake::ExtensionTask.new('qiita_marker', gem_spec) do |ext|
18
- ext.lib_dir = File.join('lib', 'qiita_marker')
17
+ Rake::ExtensionTask.new("qiita_marker", gem_spec) do |ext|
18
+ ext.lib_dir = File.join("lib", "qiita_marker")
19
19
  end
20
20
 
21
21
  # Packaging
22
- require 'bundler/gem_tasks'
22
+ require "bundler/gem_tasks"
23
23
 
24
24
  # Testing
25
- require 'rake/testtask'
25
+ require "rake/testtask"
26
26
 
27
- Rake::TestTask.new('test:unit') do |t|
28
- t.libs << 'lib'
29
- t.libs << 'test'
30
- t.pattern = 'test/test_*.rb'
27
+ Rake::TestTask.new("test:unit") do |t|
28
+ t.libs << "lib"
29
+ t.libs << "test"
30
+ t.pattern = "test/test_*.rb"
31
31
  t.verbose = true
32
32
  t.warning = false
33
33
  end
34
34
 
35
- task 'test:unit' => :compile
35
+ desc "Run unit tests"
36
+ task "test:unit" => :compile
36
37
 
37
- desc 'Run unit and conformance tests'
38
- task test: %w[test:unit]
38
+ desc "Run unit and conformance tests"
39
+ task test: ["test:unit"]
39
40
 
40
- require 'rubocop/rake_task'
41
+ require "rubocop/rake_task"
41
42
 
42
43
  RuboCop::RakeTask.new(:rubocop)
43
44
 
44
- desc 'Run benchmarks'
45
+ desc "Run benchmarks"
45
46
  task :benchmark do
46
- if ENV['FETCH_PROGIT']
47
- `rm -rf test/progit`
48
- `git clone https://github.com/progit/progit.git test/progit`
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]
47
+ if ENV["FETCH_PROGIT"]
48
+ %x(rm -rf test/progit)
49
+ %x(git clone https://github.com/progit/progit.git test/progit)
50
+ langs = ["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"]
50
51
  langs.each do |lang|
51
- `cat test/progit/#{lang}/*/*.markdown >> test/benchinput.md`
52
+ %x(cat test/progit/#{lang}/*/*.markdown >> test/benchinput.md)
52
53
  end
53
54
  end
54
- $LOAD_PATH.unshift 'lib'
55
- load 'test/benchmark.rb'
55
+ $LOAD_PATH.unshift("lib")
56
+ load "test/benchmark.rb"
56
57
  end
57
58
 
58
- desc 'Match C style of cmark'
59
+ desc "Match C style of cmark"
59
60
  task :format do
60
- sh 'clang-format -style llvm -i ext/qiita_marker/*.c ext/qiita_marker/*.h'
61
+ sh "clang-format -style llvm -i ext/qiita_marker/*.c ext/qiita_marker/*.h"
61
62
  end
62
63
 
63
64
  # Documentation
64
- require 'rdoc/task'
65
+ require "rdoc/task"
65
66
 
66
- desc 'Generate API documentation'
67
+ desc "Generate API documentation"
67
68
  RDoc::Task.new do |rd|
68
- rd.rdoc_dir = 'docs'
69
- rd.main = 'README.md'
70
- rd.rdoc_files.include 'README.md', 'lib/**/*.rb', 'ext/qiita_marker/qiita_marker.c'
71
-
72
- rd.options << '--markup tomdoc'
73
- rd.options << '--inline-source'
74
- rd.options << '--line-numbers'
75
- rd.options << '--all'
76
- rd.options << '--fileboxes'
69
+ rd.rdoc_dir = "docs"
70
+ rd.main = "README.md"
71
+ rd.rdoc_files.include("README.md", "lib/**/*.rb", "ext/qiita_marker/qiita_marker.c")
72
+
73
+ rd.options << "--markup tomdoc"
74
+ rd.options << "--inline-source"
75
+ rd.options << "--line-numbers"
76
+ rd.options << "--all"
77
+ rd.options << "--fileboxes"
77
78
  end
78
79
 
79
- desc 'Generate the documentation and run a web server'
80
+ desc "Generate the documentation and run a web server"
80
81
  task serve: [:rdoc] do
81
- require 'webrick'
82
+ require "webrick"
82
83
 
83
- puts 'Navigate to http://localhost:3000 to see the docs'
84
+ puts "Navigate to http://localhost:3000 to see the docs"
84
85
 
85
- server = WEBrick::HTTPServer.new Port: 3000
86
- server.mount '/', WEBrick::HTTPServlet::FileHandler, 'docs'
87
- trap('INT') { server.stop }
86
+ server = WEBrick::HTTPServer.new(Port: 3000)
87
+ server.mount("/", WEBrick::HTTPServlet::FileHandler, "docs")
88
+ trap("INT") { server.stop }
88
89
  server.start
89
90
  end
90
91
 
91
- desc 'Generate and publish docs to gh-pages'
92
+ desc "Generate and publish docs to gh-pages"
92
93
  task publish: [:rdoc] do
93
- require 'tmpdir'
94
- require 'shellwords'
94
+ require "tmpdir"
95
+ require "shellwords"
95
96
 
96
97
  Dir.mktmpdir do |tmp|
97
98
  system "mv docs/* #{tmp}"
98
- system 'git checkout origin/gh-pages'
99
- system 'rm -rf *'
99
+ system "git checkout origin/gh-pages"
100
+ system "rm -rf *"
100
101
  system "mv #{tmp}/* ."
101
102
  message = Shellwords.escape("Site updated at #{Time.now.utc}")
102
- system 'git add .'
103
+ system "git add ."
103
104
  system "git commit -am #{message}"
104
- system 'git push origin gh-pages --force'
105
- system 'git checkout master'
106
- system 'echo yolo'
105
+ system "git push origin gh-pages --force"
106
+ system "git checkout master"
107
+ system "echo yolo"
107
108
  end
108
109
  end
109
110
 
110
111
  # Custom tasks
111
- Dir.glob('tasks/*.rake').each do |f|
112
+ Dir.glob("tasks/*.rake").each do |f|
112
113
  load f
113
114
  end
data/bin/qiita_marker CHANGED
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'optparse'
5
- require 'ostruct'
6
5
 
7
6
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
8
7
  require 'qiita_marker'
@@ -11,17 +10,13 @@ root = File.expand_path('..', __dir__)
11
10
  $LOAD_PATH.unshift File.expand_path('lib', root)
12
11
 
13
12
  def parse_options
14
- options = OpenStruct.new
13
+ options = Struct.new(:active_extensions, :active_parse_options, :active_render_options, :output_format, :renderer)
14
+ .new([], [:DEFAULT], [:DEFAULT], :html)
15
15
  extensions = QiitaMarker.extensions
16
16
  parse_options = QiitaMarker::Config::OPTS.fetch(:parse)
17
17
  render_options = QiitaMarker::Config::OPTS.fetch(:render)
18
18
  format_options = QiitaMarker::Config::OPTS.fetch(:format)
19
19
 
20
- options.active_extensions = []
21
- options.active_parse_options = [:DEFAULT]
22
- options.active_render_options = [:DEFAULT]
23
- options.output_format = :html
24
-
25
20
  option_parser = OptionParser.new do |opts|
26
21
  opts.banner = 'Usage: qiita_marker [--html-renderer] [--extension=EXTENSION]'
27
22
  opts.separator ' [--to=FORMAT]'
@@ -1,5 +1,9 @@
1
1
  #include "autolink.h"
2
+ #include "houdini.h"
3
+ #include "qfm.h"
4
+ #include "scanners.h"
2
5
  #include <parser.h>
6
+ #include <render.h>
3
7
  #include <string.h>
4
8
  #include <utf8.h>
5
9
 
@@ -9,6 +13,11 @@
9
13
  #include <strings.h>
10
14
  #endif
11
15
 
16
+ static void escape_html(cmark_strbuf *dest, const unsigned char *source,
17
+ bufsize_t length) {
18
+ houdini_escape_html0(dest, source, length, 0);
19
+ }
20
+
12
21
  static int is_valid_hostchar(const uint8_t *link, size_t link_len) {
13
22
  int32_t ch;
14
23
  int r = cmark_utf8proc_iterate(link, (bufsize_t)link_len, &ch);
@@ -144,7 +153,8 @@ static size_t check_domain(uint8_t *data, size_t size, int allow_short) {
144
153
  }
145
154
 
146
155
  static cmark_node *www_match(cmark_parser *parser, cmark_node *parent,
147
- cmark_inline_parser *inline_parser) {
156
+ cmark_inline_parser *inline_parser,
157
+ cmark_syntax_extension *ext) {
148
158
  cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
149
159
  size_t max_rewind = cmark_inline_parser_get_offset(inline_parser);
150
160
  uint8_t *data = chunk->data + max_rewind;
@@ -176,6 +186,9 @@ static cmark_node *www_match(cmark_parser *parser, cmark_node *parent,
176
186
  cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end));
177
187
 
178
188
  cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);
189
+ if (parser->options & CMARK_OPT_AUTOLINK_CLASS_NAME) {
190
+ cmark_node_set_syntax_extension(node, ext);
191
+ }
179
192
 
180
193
  cmark_strbuf buf;
181
194
  cmark_strbuf_init(parser->mem, &buf, 10);
@@ -199,7 +212,8 @@ static cmark_node *www_match(cmark_parser *parser, cmark_node *parent,
199
212
  }
200
213
 
201
214
  static cmark_node *url_match(cmark_parser *parser, cmark_node *parent,
202
- cmark_inline_parser *inline_parser) {
215
+ cmark_inline_parser *inline_parser,
216
+ cmark_syntax_extension *ext) {
203
217
  size_t link_end, domain_len;
204
218
  int rewind = 0;
205
219
 
@@ -237,6 +251,9 @@ static cmark_node *url_match(cmark_parser *parser, cmark_node *parent,
237
251
  cmark_node_unput(parent, rewind);
238
252
 
239
253
  cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);
254
+ if (parser->options & CMARK_OPT_AUTOLINK_CLASS_NAME) {
255
+ cmark_node_set_syntax_extension(node, ext);
256
+ }
240
257
 
241
258
  cmark_chunk url = cmark_chunk_dup(chunk, max_rewind - rewind,
242
259
  (bufsize_t)(link_end + rewind));
@@ -257,10 +274,10 @@ static cmark_node *match(cmark_syntax_extension *ext, cmark_parser *parser,
257
274
  return NULL;
258
275
 
259
276
  if (c == ':')
260
- return url_match(parser, parent, inline_parser);
277
+ return url_match(parser, parent, inline_parser, ext);
261
278
 
262
279
  if (c == 'w')
263
- return www_match(parser, parent, inline_parser);
280
+ return www_match(parser, parent, inline_parser, ext);
264
281
 
265
282
  return NULL;
266
283
 
@@ -269,7 +286,8 @@ static cmark_node *match(cmark_syntax_extension *ext, cmark_parser *parser,
269
286
  // inline was finished in inlines.c.
270
287
  }
271
288
 
272
- static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset, int depth) {
289
+ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset,
290
+ int depth, cmark_syntax_extension *ext) {
273
291
  // postprocess_text can recurse very deeply if there is a very long line of
274
292
  // '@' only. Stop at a reasonable depth to ensure it cannot crash.
275
293
  if (depth > 1000) return;
@@ -311,7 +329,7 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset,
311
329
  }
312
330
 
313
331
  if (rewind == 0 || ns > 0) {
314
- postprocess_text(parser, text, max_rewind + 1 + offset, depth + 1);
332
+ postprocess_text(parser, text, max_rewind + 1 + offset, depth + 1, ext);
315
333
  return;
316
334
  }
317
335
 
@@ -331,20 +349,23 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset,
331
349
 
332
350
  if (link_end < 2 || nb != 1 || np == 0 ||
333
351
  (!cmark_isalpha(data[link_end - 1]) && data[link_end - 1] != '.')) {
334
- postprocess_text(parser, text, max_rewind + 1 + offset, depth + 1);
352
+ postprocess_text(parser, text, max_rewind + 1 + offset, depth + 1, ext);
335
353
  return;
336
354
  }
337
355
 
338
356
  link_end = autolink_delim(data, link_end);
339
357
 
340
358
  if (link_end == 0) {
341
- postprocess_text(parser, text, max_rewind + 1 + offset, depth + 1);
359
+ postprocess_text(parser, text, max_rewind + 1 + offset, depth + 1, ext);
342
360
  return;
343
361
  }
344
362
 
345
363
  cmark_chunk_to_cstr(parser->mem, &text->as.literal);
346
364
 
347
365
  cmark_node *link_node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);
366
+ if (parser->options & CMARK_OPT_AUTOLINK_CLASS_NAME) {
367
+ cmark_node_set_syntax_extension(link_node, ext);
368
+ }
348
369
  cmark_strbuf buf;
349
370
  cmark_strbuf_init(parser->mem, &buf, 10);
350
371
  cmark_strbuf_puts(&buf, "mailto:");
@@ -373,7 +394,7 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset,
373
394
  text->as.literal.len = offset + max_rewind - rewind;
374
395
  text->as.literal.data[text->as.literal.len] = 0;
375
396
 
376
- postprocess_text(parser, post, 0, depth + 1);
397
+ postprocess_text(parser, post, 0, depth + 1, ext);
377
398
  }
378
399
 
379
400
  static cmark_node *postprocess(cmark_syntax_extension *ext, cmark_parser *parser, cmark_node *root) {
@@ -400,7 +421,7 @@ static cmark_node *postprocess(cmark_syntax_extension *ext, cmark_parser *parser
400
421
  }
401
422
 
402
423
  if (ev == CMARK_EVENT_ENTER && node->type == CMARK_NODE_TEXT) {
403
- postprocess_text(parser, node, 0, /*depth*/0);
424
+ postprocess_text(parser, node, 0, /*depth*/ 0, ext);
404
425
  }
405
426
  }
406
427
 
@@ -409,12 +430,38 @@ static cmark_node *postprocess(cmark_syntax_extension *ext, cmark_parser *parser
409
430
  return root;
410
431
  }
411
432
 
433
+ static void html_render(cmark_syntax_extension *extension,
434
+ cmark_html_renderer *renderer, cmark_node *node,
435
+ cmark_event_type ev_type, int options) {
436
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
437
+ cmark_strbuf *html = renderer->html;
438
+
439
+ if (entering) {
440
+ cmark_strbuf_puts(html, "<a href=\"");
441
+ if ((options & CMARK_OPT_UNSAFE) ||
442
+ !(scan_dangerous_url(&node->as.link.url, 0))) {
443
+ houdini_escape_href(html, node->as.link.url.data, node->as.link.url.len);
444
+ }
445
+ if (node->as.link.title.len) {
446
+ cmark_strbuf_puts(html, "\" title=\"");
447
+ escape_html(html, node->as.link.title.data, node->as.link.title.len);
448
+ }
449
+ if (options & CMARK_OPT_AUTOLINK_CLASS_NAME) {
450
+ cmark_strbuf_puts(html, "\" class=\"autolink");
451
+ }
452
+ cmark_strbuf_puts(html, "\">");
453
+ } else {
454
+ cmark_strbuf_puts(html, "</a>");
455
+ }
456
+ }
457
+
412
458
  cmark_syntax_extension *create_autolink_extension(void) {
413
459
  cmark_syntax_extension *ext = cmark_syntax_extension_new("autolink");
414
460
  cmark_llist *special_chars = NULL;
415
461
 
416
462
  cmark_syntax_extension_set_match_inline_func(ext, match);
417
463
  cmark_syntax_extension_set_postprocess_func(ext, postprocess);
464
+ cmark_syntax_extension_set_html_render_func(ext, html_render);
418
465
 
419
466
  cmark_mem *mem = cmark_get_default_mem_allocator();
420
467
  special_chars = cmark_llist_append(mem, special_chars, (void *)':');
@@ -1,7 +1,7 @@
1
1
  #ifndef CMARK_GFM_VERSION_H
2
2
  #define CMARK_GFM_VERSION_H
3
3
 
4
- #define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 2)
5
- #define CMARK_GFM_VERSION_STRING "0.29.0.gfm.2"
4
+ #define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 4)
5
+ #define CMARK_GFM_VERSION_STRING "0.29.0.gfm.4"
6
6
 
7
7
  #endif
@@ -227,7 +227,7 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
227
227
  cmark_strbuf_puts(html, "<pre");
228
228
  cmark_html_render_sourcepos(node, html, options);
229
229
  cmark_strbuf_puts(html, "><code data-metadata=\"");
230
- escape_html(html, node->as.code.info.data, first_tag);
230
+ escape_html(html, node->as.code.info.data, node->as.code.info.len);
231
231
  if (first_tag < node->as.code.info.len &&
232
232
  (options & CMARK_OPT_FULL_INFO_STRING)) {
233
233
  cmark_strbuf_puts(html, "\" data-meta=\"");
@@ -12,6 +12,9 @@ extern "C" {
12
12
  /* Prevent parsing Qiita-style Mentions as emphasis. */
13
13
  #define CMARK_OPT_MENTION_NO_EMPHASIS (1 << 26)
14
14
 
15
+ /* Render autolinks with class name */
16
+ #define CMARK_OPT_AUTOLINK_CLASS_NAME (1 << 27)
17
+
15
18
  #ifdef __cplusplus
16
19
  }
17
20
  #endif
@@ -157,20 +157,7 @@ static int can_contain(cmark_syntax_extension *self, cmark_node *node,
157
157
  cmark_node_type child_type) {
158
158
  cmark_node_type node_type = cmark_node_get_type(node);
159
159
 
160
- if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
161
- return
162
- // Block
163
- child_type == CMARK_NODE_LIST || child_type == CMARK_NODE_PARAGRAPH ||
164
- // Inline
165
- child_type == CMARK_NODE_TEXT || child_type == CMARK_NODE_CODE ||
166
- child_type == CMARK_NODE_HTML_INLINE || child_type == CMARK_NODE_EMPH ||
167
- child_type == CMARK_NODE_STRONG || child_type == CMARK_NODE_LINK ||
168
- child_type == CMARK_NODE_IMAGE ||
169
- child_type == CMARK_NODE_FOOTNOTE_REFERENCE ||
170
- child_type == CMARK_NODE_STRIKETHROUGH;
171
- }
172
-
173
- return 0;
160
+ return node_type == CMARK_NODE_QFM_CUSTOM_BLOCK;
174
161
  }
175
162
 
176
163
  static int contains_inlines(cmark_syntax_extension *self, cmark_node *node) {
@@ -1,5 +1,5 @@
1
- #include "cmark_ctype.h"
2
1
  #include "cmark-gfm.h"
2
+ #include "cmark_ctype.h"
3
3
  #include "config.h"
4
4
 
5
5
  static bool is_wordchar(char c) {