commonmarker 0.23.10 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1182 -0
  3. data/Cargo.toml +7 -0
  4. data/README.md +217 -170
  5. data/ext/commonmarker/Cargo.toml +20 -0
  6. data/ext/commonmarker/extconf.rb +3 -6
  7. data/ext/commonmarker/src/lib.rs +103 -0
  8. data/ext/commonmarker/src/node.rs +1151 -0
  9. data/ext/commonmarker/src/options.rs +175 -0
  10. data/ext/commonmarker/src/plugins/syntax_highlighting.rs +166 -0
  11. data/ext/commonmarker/src/plugins.rs +6 -0
  12. data/ext/commonmarker/src/utils.rs +8 -0
  13. data/lib/commonmarker/config.rb +92 -40
  14. data/lib/commonmarker/constants.rb +7 -0
  15. data/lib/commonmarker/extension.rb +14 -0
  16. data/lib/commonmarker/node/ast.rb +8 -0
  17. data/lib/commonmarker/node/inspect.rb +14 -4
  18. data/lib/commonmarker/node.rb +29 -47
  19. data/lib/commonmarker/renderer.rb +1 -127
  20. data/lib/commonmarker/utils.rb +22 -0
  21. data/lib/commonmarker/version.rb +2 -2
  22. data/lib/commonmarker.rb +27 -25
  23. metadata +38 -186
  24. data/Rakefile +0 -109
  25. data/bin/commonmarker +0 -118
  26. data/commonmarker.gemspec +0 -38
  27. data/ext/commonmarker/arena.c +0 -104
  28. data/ext/commonmarker/autolink.c +0 -508
  29. data/ext/commonmarker/autolink.h +0 -8
  30. data/ext/commonmarker/blocks.c +0 -1622
  31. data/ext/commonmarker/buffer.c +0 -278
  32. data/ext/commonmarker/buffer.h +0 -116
  33. data/ext/commonmarker/case_fold_switch.inc +0 -4327
  34. data/ext/commonmarker/chunk.h +0 -135
  35. data/ext/commonmarker/cmark-gfm-core-extensions.h +0 -54
  36. data/ext/commonmarker/cmark-gfm-extension_api.h +0 -737
  37. data/ext/commonmarker/cmark-gfm-extensions_export.h +0 -42
  38. data/ext/commonmarker/cmark-gfm.h +0 -833
  39. data/ext/commonmarker/cmark-gfm_export.h +0 -42
  40. data/ext/commonmarker/cmark-gfm_version.h +0 -7
  41. data/ext/commonmarker/cmark.c +0 -55
  42. data/ext/commonmarker/cmark_ctype.c +0 -44
  43. data/ext/commonmarker/cmark_ctype.h +0 -33
  44. data/ext/commonmarker/commonmark.c +0 -514
  45. data/ext/commonmarker/commonmarker.c +0 -1308
  46. data/ext/commonmarker/commonmarker.h +0 -16
  47. data/ext/commonmarker/config.h +0 -76
  48. data/ext/commonmarker/core-extensions.c +0 -27
  49. data/ext/commonmarker/entities.inc +0 -2138
  50. data/ext/commonmarker/ext_scanners.c +0 -879
  51. data/ext/commonmarker/ext_scanners.h +0 -24
  52. data/ext/commonmarker/footnotes.c +0 -63
  53. data/ext/commonmarker/footnotes.h +0 -27
  54. data/ext/commonmarker/houdini.h +0 -57
  55. data/ext/commonmarker/houdini_href_e.c +0 -100
  56. data/ext/commonmarker/houdini_html_e.c +0 -66
  57. data/ext/commonmarker/houdini_html_u.c +0 -149
  58. data/ext/commonmarker/html.c +0 -502
  59. data/ext/commonmarker/html.h +0 -27
  60. data/ext/commonmarker/inlines.c +0 -1788
  61. data/ext/commonmarker/inlines.h +0 -29
  62. data/ext/commonmarker/iterator.c +0 -159
  63. data/ext/commonmarker/iterator.h +0 -26
  64. data/ext/commonmarker/latex.c +0 -468
  65. data/ext/commonmarker/linked_list.c +0 -37
  66. data/ext/commonmarker/man.c +0 -274
  67. data/ext/commonmarker/map.c +0 -129
  68. data/ext/commonmarker/map.h +0 -44
  69. data/ext/commonmarker/node.c +0 -1045
  70. data/ext/commonmarker/node.h +0 -167
  71. data/ext/commonmarker/parser.h +0 -59
  72. data/ext/commonmarker/plaintext.c +0 -218
  73. data/ext/commonmarker/plugin.c +0 -36
  74. data/ext/commonmarker/plugin.h +0 -34
  75. data/ext/commonmarker/references.c +0 -43
  76. data/ext/commonmarker/references.h +0 -26
  77. data/ext/commonmarker/registry.c +0 -63
  78. data/ext/commonmarker/registry.h +0 -24
  79. data/ext/commonmarker/render.c +0 -213
  80. data/ext/commonmarker/render.h +0 -62
  81. data/ext/commonmarker/scanners.c +0 -14056
  82. data/ext/commonmarker/scanners.h +0 -70
  83. data/ext/commonmarker/scanners.re +0 -341
  84. data/ext/commonmarker/strikethrough.c +0 -167
  85. data/ext/commonmarker/strikethrough.h +0 -9
  86. data/ext/commonmarker/syntax_extension.c +0 -149
  87. data/ext/commonmarker/syntax_extension.h +0 -34
  88. data/ext/commonmarker/table.c +0 -917
  89. data/ext/commonmarker/table.h +0 -12
  90. data/ext/commonmarker/tagfilter.c +0 -60
  91. data/ext/commonmarker/tagfilter.h +0 -8
  92. data/ext/commonmarker/tasklist.c +0 -156
  93. data/ext/commonmarker/tasklist.h +0 -8
  94. data/ext/commonmarker/utf8.c +0 -317
  95. data/ext/commonmarker/utf8.h +0 -35
  96. data/ext/commonmarker/xml.c +0 -182
  97. data/lib/commonmarker/renderer/html_renderer.rb +0 -256
@@ -0,0 +1,175 @@
1
+ use std::borrow::Cow;
2
+
3
+ use comrak::ComrakOptions;
4
+
5
+ use magnus::value::ReprValue;
6
+ use magnus::TryConvert;
7
+ use magnus::{class, r_hash::ForEach, Error, RHash, Symbol, Value};
8
+
9
+ use crate::utils::try_convert_string;
10
+
11
+ const PARSE_SMART: &str = "smart";
12
+ const PARSE_DEFAULT_INFO_STRING: &str = "default_info_string";
13
+ const PARSE_RELAXED_AUTOLINKS: &str = "relaxed_autolinks";
14
+
15
+ fn iterate_parse_options(comrak_options: &mut ComrakOptions, options_hash: RHash) {
16
+ options_hash
17
+ .foreach(|key: Symbol, value: Value| {
18
+ match key.name() {
19
+ Ok(Cow::Borrowed(PARSE_SMART)) => {
20
+ comrak_options.parse.smart = TryConvert::try_convert(value)?;
21
+ }
22
+ Ok(Cow::Borrowed(PARSE_DEFAULT_INFO_STRING)) => {
23
+ comrak_options.parse.default_info_string = try_convert_string(value);
24
+ }
25
+ Ok(Cow::Borrowed(PARSE_RELAXED_AUTOLINKS)) => {
26
+ comrak_options.parse.relaxed_autolinks = TryConvert::try_convert(value)?;
27
+ }
28
+ _ => {}
29
+ }
30
+ Ok(ForEach::Continue)
31
+ })
32
+ .unwrap();
33
+ }
34
+
35
+ const RENDER_HARDBREAKS: &str = "hardbreaks";
36
+ const RENDER_GITHUB_PRE_LANG: &str = "github_pre_lang";
37
+ const RENDER_WIDTH: &str = "width";
38
+ const RENDER_UNSAFE: &str = "unsafe";
39
+ const RENDER_ESCAPE: &str = "escape";
40
+ const RENDER_SOURCEPOS: &str = "sourcepos";
41
+ const RENDER_ESCAPED_CHAR_SPANS: &str = "escaped_char_spans";
42
+
43
+ fn iterate_render_options(comrak_options: &mut ComrakOptions, options_hash: RHash) {
44
+ options_hash
45
+ .foreach(|key: Symbol, value: Value| {
46
+ match key.name() {
47
+ Ok(Cow::Borrowed(RENDER_HARDBREAKS)) => {
48
+ comrak_options.render.hardbreaks = TryConvert::try_convert(value)?;
49
+ }
50
+ Ok(Cow::Borrowed(RENDER_GITHUB_PRE_LANG)) => {
51
+ comrak_options.render.github_pre_lang = TryConvert::try_convert(value)?;
52
+ }
53
+ Ok(Cow::Borrowed(RENDER_WIDTH)) => {
54
+ comrak_options.render.width = TryConvert::try_convert(value)?;
55
+ }
56
+ Ok(Cow::Borrowed(RENDER_UNSAFE)) => {
57
+ comrak_options.render.unsafe_ = TryConvert::try_convert(value)?;
58
+ }
59
+ Ok(Cow::Borrowed(RENDER_ESCAPE)) => {
60
+ comrak_options.render.escape = TryConvert::try_convert(value)?;
61
+ }
62
+ Ok(Cow::Borrowed(RENDER_SOURCEPOS)) => {
63
+ comrak_options.render.sourcepos = TryConvert::try_convert(value)?;
64
+ }
65
+ Ok(Cow::Borrowed(RENDER_ESCAPED_CHAR_SPANS)) => {
66
+ comrak_options.render.escaped_char_spans = TryConvert::try_convert(value)?;
67
+ }
68
+ _ => {}
69
+ }
70
+ Ok(ForEach::Continue)
71
+ })
72
+ .unwrap();
73
+ }
74
+
75
+ const EXTENSION_STRIKETHROUGH: &str = "strikethrough";
76
+ const EXTENSION_TAGFILTER: &str = "tagfilter";
77
+ const EXTENSION_TABLE: &str = "table";
78
+ const EXTENSION_AUTOLINK: &str = "autolink";
79
+ const EXTENSION_TASKLIST: &str = "tasklist";
80
+ const EXTENSION_SUPERSCRIPT: &str = "superscript";
81
+ const EXTENSION_HEADER_IDS: &str = "header_ids";
82
+ const EXTENSION_FOOTNOTES: &str = "footnotes";
83
+ const EXTENSION_DESCRIPTION_LISTS: &str = "description_lists";
84
+ const EXTENSION_FRONT_MATTER_DELIMITER: &str = "front_matter_delimiter";
85
+ const EXTENSION_SHORTCODES: &str = "shortcodes";
86
+ const EXTENSION_MULTILINE_BLOCK_QUOTES: &str = "multiline_block_quotes";
87
+ const EXTENSION_MATH_DOLLARS: &str = "math_dollars";
88
+ const EXTENSION_MATH_CODE: &str = "math_code";
89
+ const EXTENSION_WIKILINKS_TITLE_AFTER_PIPE: &str = "wikilinks_title_after_pipe";
90
+ const EXTENSION_WIKILINKS_TITLE_BEFORE_PIPE: &str = "wikilinks_title_before_pipe";
91
+
92
+ fn iterate_extension_options(comrak_options: &mut ComrakOptions, options_hash: RHash) {
93
+ options_hash
94
+ .foreach(|key: Symbol, value: Value| {
95
+ match key.name() {
96
+ Ok(Cow::Borrowed(EXTENSION_STRIKETHROUGH)) => {
97
+ comrak_options.extension.strikethrough = TryConvert::try_convert(value)?;
98
+ }
99
+ Ok(Cow::Borrowed(EXTENSION_TAGFILTER)) => {
100
+ comrak_options.extension.tagfilter = TryConvert::try_convert(value)?;
101
+ }
102
+ Ok(Cow::Borrowed(EXTENSION_TABLE)) => {
103
+ comrak_options.extension.table = TryConvert::try_convert(value)?;
104
+ }
105
+ Ok(Cow::Borrowed(EXTENSION_AUTOLINK)) => {
106
+ comrak_options.extension.autolink = TryConvert::try_convert(value)?;
107
+ }
108
+ Ok(Cow::Borrowed(EXTENSION_TASKLIST)) => {
109
+ comrak_options.extension.tasklist = TryConvert::try_convert(value)?;
110
+ }
111
+ Ok(Cow::Borrowed(EXTENSION_SUPERSCRIPT)) => {
112
+ comrak_options.extension.superscript = TryConvert::try_convert(value)?;
113
+ }
114
+ Ok(Cow::Borrowed(EXTENSION_HEADER_IDS)) => {
115
+ comrak_options.extension.header_ids = try_convert_string(value);
116
+ }
117
+ Ok(Cow::Borrowed(EXTENSION_FOOTNOTES)) => {
118
+ comrak_options.extension.footnotes = TryConvert::try_convert(value)?;
119
+ }
120
+ Ok(Cow::Borrowed(EXTENSION_DESCRIPTION_LISTS)) => {
121
+ comrak_options.extension.description_lists = TryConvert::try_convert(value)?;
122
+ }
123
+ Ok(Cow::Borrowed(EXTENSION_FRONT_MATTER_DELIMITER)) => {
124
+ if let Some(option) = try_convert_string(value) {
125
+ if !option.is_empty() {
126
+ comrak_options.extension.front_matter_delimiter = Some(option);
127
+ }
128
+ }
129
+ }
130
+ Ok(Cow::Borrowed(EXTENSION_SHORTCODES)) => {
131
+ comrak_options.extension.shortcodes = TryConvert::try_convert(value)?;
132
+ }
133
+ Ok(Cow::Borrowed(EXTENSION_MULTILINE_BLOCK_QUOTES)) => {
134
+ comrak_options.extension.multiline_block_quotes =
135
+ TryConvert::try_convert(value)?;
136
+ }
137
+ Ok(Cow::Borrowed(EXTENSION_MATH_DOLLARS)) => {
138
+ comrak_options.extension.math_dollars = TryConvert::try_convert(value)?;
139
+ }
140
+ Ok(Cow::Borrowed(EXTENSION_MATH_CODE)) => {
141
+ comrak_options.extension.math_code = TryConvert::try_convert(value)?;
142
+ }
143
+ Ok(Cow::Borrowed(EXTENSION_WIKILINKS_TITLE_AFTER_PIPE)) => {
144
+ comrak_options.extension.wikilinks_title_after_pipe =
145
+ TryConvert::try_convert(value)?;
146
+ }
147
+ Ok(Cow::Borrowed(EXTENSION_WIKILINKS_TITLE_BEFORE_PIPE)) => {
148
+ comrak_options.extension.wikilinks_title_before_pipe =
149
+ TryConvert::try_convert(value)?;
150
+ }
151
+ _ => {}
152
+ }
153
+ Ok(ForEach::Continue)
154
+ })
155
+ .unwrap();
156
+ }
157
+
158
+ pub fn iterate_options_hash(
159
+ comrak_options: &mut ComrakOptions,
160
+ key: Symbol,
161
+ value: RHash,
162
+ ) -> Result<ForEach, Error> {
163
+ assert!(value.is_kind_of(class::hash()));
164
+
165
+ if key.name().unwrap() == "parse" {
166
+ iterate_parse_options(comrak_options, value);
167
+ }
168
+ if key.name().unwrap() == "render" {
169
+ iterate_render_options(comrak_options, value);
170
+ }
171
+ if key.name().unwrap() == "extension" {
172
+ iterate_extension_options(comrak_options, value);
173
+ }
174
+ Ok(ForEach::Continue)
175
+ }
@@ -0,0 +1,166 @@
1
+ use std::path::PathBuf;
2
+
3
+ use comrak::plugins::syntect::{SyntectAdapter, SyntectAdapterBuilder};
4
+
5
+ use magnus::value::ReprValue;
6
+ use magnus::{exception, RHash, Symbol, TryConvert, Value};
7
+ use syntect::highlighting::ThemeSet;
8
+
9
+ use crate::EMPTY_STR;
10
+
11
+ pub fn construct_syntax_highlighter_from_plugin(
12
+ rb_plugins: Option<RHash>,
13
+ ) -> Result<Option<SyntectAdapter>, magnus::Error> {
14
+ match rb_plugins {
15
+ None => Ok(None),
16
+ Some(rb_plugins) => {
17
+ let theme = match rb_plugins.get(Symbol::new(super::SYNTAX_HIGHLIGHTER_PLUGIN)) {
18
+ Some(syntax_highlighter_options) => {
19
+ match fetch_syntax_highlighter_theme(syntax_highlighter_options) {
20
+ Ok(theme) => theme,
21
+ Err(e) => {
22
+ return Err(e);
23
+ }
24
+ }
25
+ }
26
+ None => None, // no `syntax_highlighter:` defined
27
+ };
28
+
29
+ let adapter: SyntectAdapter;
30
+
31
+ match theme {
32
+ None => Ok(None),
33
+ Some(theme) => {
34
+ if theme.is_empty() {
35
+ // no theme? uss css classes
36
+ adapter = SyntectAdapter::new(None);
37
+ Ok(Some(adapter))
38
+ } else {
39
+ let path =
40
+ match rb_plugins.get(Symbol::new(super::SYNTAX_HIGHLIGHTER_PLUGIN)) {
41
+ Some(syntax_highlighter_options) => {
42
+ fetch_syntax_highlighter_path(syntax_highlighter_options)?
43
+ }
44
+ None => PathBuf::from("".to_string()), // no `syntax_highlighter:` defined
45
+ };
46
+
47
+ if path.exists() {
48
+ if !path.is_dir() {
49
+ return Err(magnus::Error::new(
50
+ exception::arg_error(),
51
+ "`path` needs to be a directory",
52
+ ));
53
+ }
54
+
55
+ let builder = SyntectAdapterBuilder::new();
56
+ let mut ts = ThemeSet::load_defaults();
57
+
58
+ match ts.add_from_folder(&path) {
59
+ Ok(_) => {}
60
+ Err(e) => {
61
+ return Err(magnus::Error::new(
62
+ exception::arg_error(),
63
+ format!("failed to load theme set from path: {e}"),
64
+ ));
65
+ }
66
+ }
67
+
68
+ // check if the theme exists in the dir
69
+ match ts.themes.get(&theme) {
70
+ Some(theme) => theme,
71
+ None => {
72
+ return Err(magnus::Error::new(
73
+ exception::arg_error(),
74
+ format!("theme `{}` does not exist", theme),
75
+ ));
76
+ }
77
+ };
78
+
79
+ adapter = builder.theme_set(ts).theme(&theme).build();
80
+
81
+ Ok(Some(adapter))
82
+ } else {
83
+ // no path? default theme lookup
84
+ ThemeSet::load_defaults()
85
+ .themes
86
+ .get(&theme)
87
+ .ok_or_else(|| {
88
+ magnus::Error::new(
89
+ exception::arg_error(),
90
+ format!("theme `{}` does not exist", theme),
91
+ )
92
+ })?;
93
+ adapter = SyntectAdapter::new(Some(&theme));
94
+ Ok(Some(adapter))
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+
103
+ fn fetch_syntax_highlighter_theme(value: Value) -> Result<Option<String>, magnus::Error> {
104
+ if value.is_nil() {
105
+ // `syntax_highlighter: nil`
106
+ return Ok(None);
107
+ }
108
+
109
+ let syntax_highlighter_plugin: RHash = match TryConvert::try_convert(value) {
110
+ Ok(plugin) => plugin, // `syntax_highlighter: { theme: "<something>" }`
111
+ Err(e) => {
112
+ // not a hash!
113
+ return Err(e);
114
+ }
115
+ };
116
+
117
+ if syntax_highlighter_plugin.is_nil() || syntax_highlighter_plugin.is_empty() {
118
+ return Err(magnus::Error::new(
119
+ magnus::exception::type_error(),
120
+ "theme cannot be blank hash",
121
+ ));
122
+ }
123
+
124
+ let theme_key = Symbol::new(super::SYNTAX_HIGHLIGHTER_PLUGIN_THEME_KEY);
125
+
126
+ match syntax_highlighter_plugin.get(theme_key) {
127
+ Some(theme) => {
128
+ if theme.is_nil() {
129
+ return Err(magnus::Error::new(
130
+ magnus::exception::type_error(),
131
+ "theme cannot be nil",
132
+ ));
133
+ }
134
+ Ok(TryConvert::try_convert(theme)?)
135
+ }
136
+ None => {
137
+ // `syntax_highlighter: { theme: nil }`
138
+ Ok(None)
139
+ }
140
+ }
141
+ }
142
+
143
+ fn fetch_syntax_highlighter_path(value: Value) -> Result<PathBuf, magnus::Error> {
144
+ if value.is_nil() {
145
+ // `syntax_highlighter: nil`
146
+ return Ok(PathBuf::from(EMPTY_STR));
147
+ }
148
+
149
+ let syntax_highlighter_plugin: RHash = TryConvert::try_convert(value)?;
150
+ let path_key = Symbol::new(super::SYNTAX_HIGHLIGHTER_PLUGIN_PATH_KEY);
151
+
152
+ match syntax_highlighter_plugin.get(path_key) {
153
+ Some(path) => {
154
+ if path.is_nil() {
155
+ // `syntax_highlighter: { path: nil }`
156
+ return Ok(PathBuf::from(EMPTY_STR));
157
+ }
158
+ let val: String = TryConvert::try_convert(path)?;
159
+ Ok(PathBuf::from(val))
160
+ }
161
+ None => {
162
+ // `syntax_highlighter: { }`
163
+ Ok(PathBuf::from(EMPTY_STR))
164
+ }
165
+ }
166
+ }
@@ -0,0 +1,6 @@
1
+ pub mod syntax_highlighting;
2
+
3
+ pub const SYNTAX_HIGHLIGHTER_PLUGIN: &str = "syntax_highlighter";
4
+
5
+ pub const SYNTAX_HIGHLIGHTER_PLUGIN_THEME_KEY: &str = "theme";
6
+ pub const SYNTAX_HIGHLIGHTER_PLUGIN_PATH_KEY: &str = "path";
@@ -0,0 +1,8 @@
1
+ use magnus::{TryConvert, Value};
2
+
3
+ pub fn try_convert_string(value: Value) -> Option<String> {
4
+ match TryConvert::try_convert(value) {
5
+ Ok(s) => Some(s),
6
+ Err(_) => None,
7
+ }
8
+ }
@@ -1,54 +1,106 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module CommonMarker
4
- # For Ruby::Enum, these must be classes, not modules
3
+ module Commonmarker
5
4
  module Config
6
- # See https://github.com/github/cmark-gfm/blob/master/src/cmark-gfm.h#L673
7
- OPTS = {
5
+ # For details, see
6
+ # https://github.com/kivikakk/comrak/blob/162ef9354deb2c9b4a4e05be495aa372ba5bb696/src/main.rs#L201
7
+ OPTIONS = {
8
8
  parse: {
9
- DEFAULT: 0,
10
- SOURCEPOS: (1 << 1),
11
- UNSAFE: (1 << 17),
12
- VALIDATE_UTF8: (1 << 9),
13
- SMART: (1 << 10),
14
- LIBERAL_HTML_TAG: (1 << 12),
15
- FOOTNOTES: (1 << 13),
16
- STRIKETHROUGH_DOUBLE_TILDE: (1 << 14),
9
+ smart: false,
10
+ default_info_string: "",
11
+ relaxed_autolinks: false,
17
12
  }.freeze,
18
13
  render: {
19
- DEFAULT: 0,
20
- SOURCEPOS: (1 << 1),
21
- HARDBREAKS: (1 << 2),
22
- UNSAFE: (1 << 17),
23
- NOBREAKS: (1 << 4),
24
- VALIDATE_UTF8: (1 << 9),
25
- SMART: (1 << 10),
26
- GITHUB_PRE_LANG: (1 << 11),
27
- LIBERAL_HTML_TAG: (1 << 12),
28
- FOOTNOTES: (1 << 13),
29
- STRIKETHROUGH_DOUBLE_TILDE: (1 << 14),
30
- TABLE_PREFER_STYLE_ATTRIBUTES: (1 << 15),
31
- FULL_INFO_STRING: (1 << 16),
14
+ hardbreaks: true,
15
+ github_pre_lang: true,
16
+ width: 80,
17
+ unsafe: false,
18
+ escape: false,
19
+ sourcepos: false,
20
+ escaped_char_spans: true,
32
21
  }.freeze,
33
- format: [:html, :xml, :commonmark, :plaintext].freeze,
22
+ extension: {
23
+ strikethrough: true,
24
+ tagfilter: true,
25
+ table: true,
26
+ autolink: true,
27
+ tasklist: true,
28
+ superscript: false,
29
+ header_ids: "",
30
+ footnotes: false,
31
+ description_lists: false,
32
+ front_matter_delimiter: "",
33
+ shortcodes: true,
34
+ multiline_block_quotes: false,
35
+ math_dollars: false,
36
+ math_code: false,
37
+ wikilinks_title_before_pipe: false,
38
+ wikilinks_title_after_pipe: false,
39
+ },
40
+ format: [:html].freeze,
34
41
  }.freeze
35
42
 
43
+ PLUGINS = {
44
+ syntax_highlighter: {
45
+ theme: "base16-ocean.dark",
46
+ path: "",
47
+ },
48
+ }
49
+
36
50
  class << self
37
- def process_options(option, type)
38
- case option
39
- when Symbol
40
- OPTS.fetch(type).fetch(option)
41
- when Array
42
- raise TypeError if option.none?
43
-
44
- # neckbearding around. the map will both check the opts and then bitwise-OR it
45
- OPTS.fetch(type).fetch_values(*option).inject(0, :|)
46
- else
47
- raise TypeError, "option type must be a valid symbol or array of symbols within the #{name}::OPTS[:#{type}] context"
51
+ include Commonmarker::Utils
52
+
53
+ def merged_with_defaults(options)
54
+ Commonmarker::Config::OPTIONS.merge(process_options(options))
55
+ end
56
+
57
+ def process_options(options)
58
+ {
59
+ parse: process_parse_options(options[:parse]),
60
+ render: process_render_options(options[:render]),
61
+ extension: process_extension_options(options[:extension]),
62
+ }
63
+ end
64
+
65
+ def process_plugins(plugins)
66
+ {
67
+ syntax_highlighter: process_syntax_highlighter_plugin(plugins&.fetch(:syntax_highlighter, nil)),
68
+ }
69
+ end
70
+ end
71
+
72
+ [:parse, :render, :extension].each do |type|
73
+ define_singleton_method :"process_#{type}_options" do |option|
74
+ Commonmarker::Config::OPTIONS[type].each_with_object({}) do |(key, value), hash|
75
+ if option.nil? # option not provided, go for the default
76
+ hash[key] = value
77
+ next
78
+ end
79
+
80
+ # option explicitly not included, remove it
81
+ next if option[key].nil?
82
+
83
+ hash[key] = fetch_kv(option, key, value, type)
48
84
  end
49
- rescue KeyError => e
50
- raise TypeError, "option ':#{e.key}' does not exist for #{name}::OPTS[:#{type}]"
51
85
  end
52
- end
86
+ end
87
+
88
+ [:syntax_highlighter].each do |type|
89
+ define_singleton_method :"process_#{type}_plugin" do |plugin|
90
+ return if plugin.nil? # plugin explicitly nil, remove it
91
+
92
+ Commonmarker::Config::PLUGINS[type].each_with_object({}) do |(key, value), hash|
93
+ if plugin.nil? # option not provided, go for the default
94
+ hash[key] = value
95
+ next
96
+ end
97
+
98
+ # option explicitly not included, remove it
99
+ next if plugin[key].nil?
100
+
101
+ hash[key] = fetch_kv(plugin, key, value, type)
102
+ end
103
+ end
104
+ end
53
105
  end
54
106
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Commonmarker
4
+ module Constants
5
+ BOOLS = [true, false].freeze
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ # native precompiled gems package shared libraries in <gem_dir>/lib/commonmarker/<ruby_version>
5
+ # load the precompiled extension file
6
+ ruby_version = /\d+\.\d+/.match(RUBY_VERSION)
7
+ require_relative "#{ruby_version}/commonmarker"
8
+ rescue LoadError
9
+ # fall back to the extension compiled upon installation.
10
+ # use "require" instead of "require_relative" because non-native gems will place C extension files
11
+ # in Gem::BasicSpecification#extension_dir after compilation (during normal installation), which
12
+ # is in $LOAD_PATH but not necessarily relative to this file (see nokogiri#2300)
13
+ require "commonmarker/commonmarker"
14
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Commonmarker
4
+ class Node
5
+ class Ast
6
+ end
7
+ end
8
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "pp"
4
4
 
5
- module CommonMarker
5
+ module Commonmarker
6
6
  class Node
7
7
  module Inspect
8
8
  PP_INDENT_SIZE = 2
@@ -16,9 +16,19 @@ module CommonMarker
16
16
  printer.group(PP_INDENT_SIZE, "#<#{self.class}(#{type}):", ">") do
17
17
  printer.breakable
18
18
 
19
- attrs = [:sourcepos, :string_content, :url, :title, :header_level, :list_type, :list_start, :list_tight, :fence_info].map do |name|
19
+ attrs = [
20
+ :source_position,
21
+ :string_content,
22
+ :url,
23
+ :title,
24
+ :header_level,
25
+ :list_type,
26
+ :list_start,
27
+ :list_tight,
28
+ :fence_info,
29
+ ].filter_map do |name|
20
30
  [name, __send__(name)]
21
- rescue NodeError
31
+ rescue StandardError
22
32
  nil
23
33
  end.compact
24
34
 
@@ -34,7 +44,7 @@ module CommonMarker
34
44
  node = first_child
35
45
  while node
36
46
  children << node
37
- node = node.next
47
+ node = node.next_sibling
38
48
  end
39
49
  printer.text("children=")
40
50
  printer.pp(children)
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "commonmarker/node/ast"
3
4
  require "commonmarker/node/inspect"
4
5
 
5
- module CommonMarker
6
+ module Commonmarker
6
7
  class Node
7
8
  include Enumerable
8
9
  include Inspect
@@ -19,65 +20,46 @@ module CommonMarker
19
20
  end
20
21
  end
21
22
 
22
- # Public: Convert the node to an HTML string.
23
- #
24
- # options - A {Symbol} or {Array of Symbol}s indicating the render options
25
- # extensions - An {Array of Symbol}s indicating the extensions to use
26
- #
27
- # Returns a {String}.
28
- def to_html(options = :DEFAULT, extensions = [])
29
- opts = Config.process_options(options, :render)
30
- _render_html(opts, extensions).force_encoding("utf-8")
31
- end
23
+ # Public: Iterate over the children (if any) of the current pointer.
24
+ def each
25
+ return enum_for(:each) unless block_given?
32
26
 
33
- # Public: Convert the node to an XML string.
34
- #
35
- # options - A {Symbol} or {Array of Symbol}s indicating the render options
36
- #
37
- # Returns a {String}.
38
- def to_xml(options = :DEFAULT)
39
- opts = Config.process_options(options, :render)
40
- _render_xml(opts).force_encoding("utf-8")
27
+ child = first_child
28
+ while child
29
+ next_child = child.next_sibling
30
+ yield child
31
+ child = next_child
32
+ end
41
33
  end
42
34
 
43
- # Public: Convert the node to a CommonMark string.
35
+ # Public: Converts a node to an HTML string.
44
36
  #
45
- # options - A {Symbol} or {Array of Symbol}s indicating the render options
46
- # width - Column to wrap the output at
37
+ # options - A {Hash} of render, parse, and extension options to transform the text.
38
+ # plugins - A {Hash} of additional plugins.
47
39
  #
48
- # Returns a {String}.
49
- def to_commonmark(options = :DEFAULT, width = 120)
50
- opts = Config.process_options(options, :render)
51
- _render_commonmark(opts, width).force_encoding("utf-8")
40
+ # Returns a {String} of HTML.
41
+ def to_html(options: Commonmarker::Config::OPTIONS, plugins: Commonmarker::Config::PLUGINS)
42
+ raise TypeError, "options must be a Hash; got a #{options.class}!" unless options.is_a?(Hash)
43
+
44
+ opts = Config.process_options(options)
45
+ plugins = Config.process_plugins(plugins)
46
+
47
+ node_to_html(options: opts, plugins: plugins).force_encoding("utf-8")
52
48
  end
53
49
 
54
- # Public: Convert the node to a plain text string.
50
+ # Public: Convert the node to a CommonMark string.
55
51
  #
56
52
  # options - A {Symbol} or {Array of Symbol}s indicating the render options
57
- # width - Column to wrap the output at
53
+ # plugins - A {Hash} of additional plugins.
58
54
  #
59
55
  # Returns a {String}.
60
- def to_plaintext(options = :DEFAULT, width = 120)
61
- opts = Config.process_options(options, :render)
62
- _render_plaintext(opts, width).force_encoding("utf-8")
63
- end
64
-
65
- # Public: Iterate over the children (if any) of the current pointer.
66
- def each
67
- return enum_for(:each) unless block_given?
56
+ def to_commonmark(options: Commonmarker::Config::OPTIONS, plugins: Commonmarker::Config::PLUGINS)
57
+ raise TypeError, "options must be a Hash; got a #{options.class}!" unless options.is_a?(Hash)
68
58
 
69
- child = first_child
70
- while child
71
- nextchild = child.next
72
- yield child
73
- child = nextchild
74
- end
75
- end
59
+ opts = Config.process_options(options)
60
+ plugins = Config.process_plugins(plugins)
76
61
 
77
- # Deprecated: Please use `each` instead
78
- def each_child(&block)
79
- warn("[DEPRECATION] `each_child` is deprecated. Please use `each` instead.")
80
- each(&block)
62
+ node_to_commonmark(options: opts, plugins: plugins).force_encoding("utf-8")
81
63
  end
82
64
  end
83
65
  end