commonmarker 1.0.0.pre3 → 1.0.0.pre4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da5f808bdc6b8da3d906a59415bf48e54a87f2422bac68c93cc3c4ccaafb7768
4
- data.tar.gz: f4f09bc3ec9805601fae7343fec173e720a2a10d49d1f96203c940d827a7aa3a
3
+ metadata.gz: cd21ee99fece0e097eb4e0b1edd044036f6954384d3afa1bf5cc7a805057b3e1
4
+ data.tar.gz: b31e054f04ee1ece9023068dc3101a0cbc581d53fad12aa9b9dba9ce83c7956a
5
5
  SHA512:
6
- metadata.gz: 14ac414938023c18c37d487b230bdeeb9cd866393fca75846af13b8f2e8f1558980470eec679db127f38b8512bd20c730537d49803d81fce4917b08f7bfaeabf
7
- data.tar.gz: 520453ba4666fb5b68346560b9f0fe2de8e299b6ed5998c741109f848a7a94eb9731e6509b9421bdd4c5f820a5dfb373f217d49d1cc5047ba539574482ef03c7
6
+ metadata.gz: 22bc0c05dc6bc035852e6a5062876337afcb402e44205bf132cd69bd4cbc1dcfda74b74f36d346bb440c44e8251f5c4ed167fe929ae836d382187afd0a1e7540
7
+ data.tar.gz: 7a30e65a73e4c91673349b0fd5ec7a1dc74ab710e6c298a6576ec636af0adf91e7e802afc5c4aea02f2ee4cc6e802e9ec3d1e1e94318df5a3dbbf09089e3d2c2
data/README.md CHANGED
@@ -39,9 +39,11 @@ Commonmarker.to_html('"Hi *there*"', options: {
39
39
 
40
40
  The second argument is optional--[see below](#options) for more information.
41
41
 
42
- ## Parse and Render Options
42
+ ## Options and plugins
43
43
 
44
- Commonmarker accepts the same options that comrak does, as a hash dictionary with symbol keys:
44
+ ### Options
45
+
46
+ Commonmarker accepts the same parse, render, and extensions options that comrak does, as a hash dictionary with symbol keys:
45
47
 
46
48
  ```ruby
47
49
  Commonmarker.to_html('"Hi *there*"', options:{
@@ -95,6 +97,36 @@ Commonmarker.to_html('"Hi *there*"', options: {
95
97
 
96
98
  For more information on these options, see [the comrak documentation](https://github.com/kivikakk/comrak#usage).
97
99
 
100
+ ### Plugins
101
+
102
+ In addition to the possibilities provided by generic CommonMark rendering, Commonmarker also supports plugins as a means of
103
+ providing further niceties. For example:
104
+
105
+ code = <<~CODE
106
+ ```ruby
107
+ def hello
108
+ puts "hello"
109
+ end
110
+
111
+ CODE
112
+
113
+ Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: "Inspired GitHub" } })
114
+
115
+ # <pre style="background-color:#ffffff;" lang="ruby"><code>
116
+ # <span style="font-weight:bold;color:#a71d5d;">def </span><span style="font-weight:bold;color:#795da3;">hello
117
+ # </span><span style="color:#323232;"> </span><span style="color:#62a35c;">puts </span><span style="color:#183691;">&quot;hello&quot;
118
+ # </span><span style="font-weight:bold;color:#a71d5d;">end
119
+ # </span>
120
+ # </code></pre>
121
+
122
+ You can disable plugins just the same as with options, by passing `nil`:
123
+
124
+ ```ruby
125
+ Commonmarker.to_html(code, plugins: { syntax_highlighter: nil })
126
+ # or
127
+ Commonmarker.to_html(code, plugins: { syntax_highlighter: { theme: nil } })
128
+ ```
129
+
98
130
  ## Output formats
99
131
 
100
132
  Commonmarker can currently only generate output in one format: HTML.
@@ -102,8 +134,7 @@ Commonmarker can currently only generate output in one format: HTML.
102
134
  ### HTML
103
135
 
104
136
  ```ruby
105
- html = CommonMarker.to_html('*Hello* world!', :DEFAULT)
106
- puts(html)
137
+ puts Commonmarker.to_html('*Hello* world!')
107
138
 
108
139
  # <p><em>Hello</em> world!</p>
109
140
  ```
@@ -5,7 +5,7 @@ edition = "2021"
5
5
 
6
6
  [dependencies]
7
7
  magnus = "0.4"
8
- comrak = "0.14"
8
+ comrak = "0.15"
9
9
 
10
10
  [lib]
11
11
  name = "commonmarker"
@@ -1,29 +1,85 @@
1
1
  extern crate core;
2
2
 
3
- use comrak::{markdown_to_html, ComrakOptions};
4
- use magnus::{define_module, function, r_hash::ForEach, Error, RHash, Symbol};
3
+ use comrak::{
4
+ adapters::SyntaxHighlighterAdapter, markdown_to_html, markdown_to_html_with_plugins,
5
+ plugins::syntect::SyntectAdapter, ComrakOptions, ComrakPlugins,
6
+ };
7
+ use magnus::{define_module, function, r_hash::ForEach, scan_args, Error, RHash, Symbol, Value};
5
8
 
6
- mod comrak_options;
7
- use comrak_options::iterate_options_hash;
9
+ mod options;
10
+ use options::iterate_options_hash;
11
+
12
+ mod plugins;
13
+ use plugins::{
14
+ syntax_highlighting::{
15
+ fetch_syntax_highlighter_theme, SYNTAX_HIGHLIGHTER_PLUGIN_DEFAULT_THEME,
16
+ },
17
+ SYNTAX_HIGHLIGHTER_PLUGIN,
18
+ };
19
+
20
+ mod utils;
21
+
22
+ pub const EMPTY_STR: &str = "";
23
+
24
+ fn commonmark_to_html<'a>(args: &[Value]) -> Result<String, magnus::Error> {
25
+ let args = scan_args::scan_args(args)?;
26
+ let (rb_commonmark,): (String,) = args.required;
27
+ let _: () = args.optional;
28
+ let _: () = args.splat;
29
+ let _: () = args.trailing;
30
+ let _: () = args.block;
31
+
32
+ let kwargs = scan_args::get_kwargs::<_, (), (Option<RHash>, Option<RHash>), ()>(
33
+ args.keywords,
34
+ &[],
35
+ &["options", "plugins"],
36
+ )?;
37
+ let (rb_options, rb_plugins) = kwargs.optional;
8
38
 
9
- fn commonmark_to_html(rb_commonmark: String, rb_options: magnus::RHash) -> String {
10
39
  let mut comrak_options = ComrakOptions::default();
11
40
 
12
- rb_options
13
- .foreach(|key: Symbol, value: RHash| {
14
- iterate_options_hash(&mut comrak_options, key, value).unwrap();
41
+ if let Some(rb_options) = rb_options {
42
+ rb_options.foreach(|key: Symbol, value: RHash| {
43
+ iterate_options_hash(&mut comrak_options, key, value)?;
15
44
  Ok(ForEach::Continue)
16
- })
17
- .unwrap();
45
+ })?;
46
+ }
47
+
48
+ if let Some(rb_plugins) = rb_plugins {
49
+ let mut comrak_plugins = ComrakPlugins::default();
50
+
51
+ let syntax_highlighter: Option<&dyn SyntaxHighlighterAdapter>;
52
+ let adapter: SyntectAdapter;
53
+
54
+ let theme = match rb_plugins.get(Symbol::new(SYNTAX_HIGHLIGHTER_PLUGIN)) {
55
+ Some(theme_val) => fetch_syntax_highlighter_theme(theme_val)?,
56
+ None => SYNTAX_HIGHLIGHTER_PLUGIN_DEFAULT_THEME.to_string(), // no `syntax_highlighter:` defined
57
+ };
58
+
59
+ if theme.is_empty() || theme == "none" {
60
+ syntax_highlighter = None;
61
+ } else {
62
+ adapter = SyntectAdapter::new(&theme);
63
+ syntax_highlighter = Some(&adapter);
64
+ }
65
+
66
+ comrak_plugins.render.codefence_syntax_highlighter = syntax_highlighter;
18
67
 
19
- markdown_to_html(&rb_commonmark, &comrak_options)
68
+ Ok(markdown_to_html_with_plugins(
69
+ &rb_commonmark,
70
+ &comrak_options,
71
+ &comrak_plugins,
72
+ ))
73
+ } else {
74
+ Ok(markdown_to_html(&rb_commonmark, &comrak_options))
75
+ }
20
76
  }
21
77
 
22
78
  #[magnus::init]
23
79
  fn init() -> Result<(), Error> {
24
80
  let module = define_module("Commonmarker")?;
25
81
 
26
- module.define_module_function("commonmark_to_html", function!(commonmark_to_html, 2))?;
82
+ module.define_module_function("commonmark_to_html", function!(commonmark_to_html, -1))?;
27
83
 
28
84
  Ok(())
29
85
  }
@@ -4,6 +4,8 @@ use comrak::ComrakOptions;
4
4
 
5
5
  use magnus::{class, r_hash::ForEach, Error, RHash, Symbol, Value};
6
6
 
7
+ use crate::utils::try_convert_string;
8
+
7
9
  const PARSE_SMART: &str = "smart";
8
10
  const PARSE_DEFAULT_INFO_STRING: &str = "default_info_string";
9
11
 
@@ -126,11 +128,3 @@ pub fn iterate_options_hash(
126
128
  }
127
129
  Ok(ForEach::Continue)
128
130
  }
129
-
130
- fn try_convert_string(value: Value) -> Option<String> {
131
- if value.is_kind_of(class::string()) {
132
- Some(value.try_convert::<String>().unwrap())
133
- } else {
134
- None
135
- }
136
- }
@@ -0,0 +1,30 @@
1
+ use magnus::{RHash, Symbol, Value};
2
+
3
+ use crate::EMPTY_STR;
4
+
5
+ pub const SYNTAX_HIGHLIGHTER_PLUGIN_THEME_KEY: &str = "theme";
6
+ pub const SYNTAX_HIGHLIGHTER_PLUGIN_DEFAULT_THEME: &str = "base16-ocean.dark";
7
+
8
+ pub fn fetch_syntax_highlighter_theme(value: Value) -> Result<String, magnus::Error> {
9
+ if value.is_nil() {
10
+ // `syntax_highlighter: nil`
11
+ return Ok(EMPTY_STR.to_string());
12
+ }
13
+
14
+ let syntax_highlighter_plugin = value.try_convert::<RHash>()?;
15
+ let theme_key = Symbol::new(SYNTAX_HIGHLIGHTER_PLUGIN_THEME_KEY);
16
+
17
+ match syntax_highlighter_plugin.get(theme_key) {
18
+ Some(theme) => {
19
+ if theme.is_nil() {
20
+ // `syntax_highlighter: { theme: nil }`
21
+ return Ok(EMPTY_STR.to_string());
22
+ }
23
+ Ok(theme.try_convert::<String>()?)
24
+ }
25
+ None => {
26
+ // `syntax_highlighter: { }`
27
+ Ok(EMPTY_STR.to_string())
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,21 @@
1
+ // use comrak::ComrakPlugins;
2
+ // use magnus::{class, r_hash::ForEach, RHash, Symbol, Value};
3
+
4
+ // use crate::plugins::syntax_highlighting::fetch_syntax_highlighter_theme;
5
+
6
+ pub mod syntax_highlighting;
7
+
8
+ pub const SYNTAX_HIGHLIGHTER_PLUGIN: &str = "syntax_highlighter";
9
+
10
+ // pub fn iterate_plugins_hash(
11
+ // comrak_plugins: &mut ComrakPlugins,
12
+ // mut theme: String,
13
+ // key: Symbol,
14
+ // value: Value,
15
+ // ) -> Result<ForEach, magnus::Error> {
16
+ // if key.name().unwrap() == SYNTAX_HIGHLIGHTER_PLUGIN {
17
+ // theme = fetch_syntax_highlighter_theme(value)?;
18
+ // }
19
+
20
+ // Ok(ForEach::Continue)
21
+ // }
@@ -0,0 +1,8 @@
1
+ use magnus::Value;
2
+
3
+ pub fn try_convert_string(value: Value) -> Option<String> {
4
+ match value.try_convert::<String>() {
5
+ Ok(s) => Some(s),
6
+ Err(_) => None,
7
+ }
8
+ }
@@ -4,7 +4,7 @@ module Commonmarker
4
4
  module Config
5
5
  # For details, see
6
6
  # https://github.com/kivikakk/comrak/blob/162ef9354deb2c9b4a4e05be495aa372ba5bb696/src/main.rs#L201
7
- OPTS = {
7
+ OPTIONS = {
8
8
  parse: {
9
9
  smart: false,
10
10
  default_info_string: "",
@@ -31,9 +31,17 @@ module Commonmarker
31
31
  format: [:html].freeze,
32
32
  }.freeze
33
33
 
34
+ PLUGINS = {
35
+ syntax_highlighter: {
36
+ theme: "base16-ocean.dark",
37
+ },
38
+ }
39
+
34
40
  class << self
41
+ include Commonmarker::Utils
42
+
35
43
  def merged_with_defaults(options)
36
- Commonmarker::Config::OPTS.merge(process_options(options))
44
+ Commonmarker::Config::OPTIONS.merge(process_options(options))
37
45
  end
38
46
 
39
47
  def process_options(options)
@@ -43,29 +51,44 @@ module Commonmarker
43
51
  extension: process_extension_options(options[:extension]),
44
52
  }
45
53
  end
46
- end
47
54
 
48
- BOOLS = [true, false]
49
- ["parse", "render", "extension"].each do |type|
50
- define_singleton_method :"process_#{type}_options" do |options|
51
- Commonmarker::Config::OPTS[type.to_sym].each_with_object({}) do |(key, value), hash|
52
- if options.nil? # option not provided, go for the default
55
+ def process_plugins(plugins)
56
+ {
57
+ syntax_highlighter: process_syntax_highlighter_plugin(plugins&.fetch(:syntax_highlighter, nil)),
58
+ }
59
+ end
60
+ end
61
+
62
+ [:parse, :render, :extension].each do |type|
63
+ define_singleton_method :"process_#{type}_options" do |option|
64
+ Commonmarker::Config::OPTIONS[type].each_with_object({}) do |(key, value), hash|
65
+ if option.nil? # option not provided, go for the default
53
66
  hash[key] = value
54
67
  next
55
68
  end
56
69
 
57
70
  # option explicitly not included, remove it
58
- next if options[key].nil?
71
+ next if option[key].nil?
59
72
 
60
- value_klass = value.class
61
- if BOOLS.include?(value) && BOOLS.include?(options[key])
62
- hash[key] = options[key]
63
- elsif options[key].is_a?(value_klass)
64
- hash[key] = options[key]
65
- else
66
- expected_type = BOOLS.include?(value) ? "Boolean" : value_klass.to_s
67
- raise TypeError, "#{type}_options[:#{key}] must be a #{expected_type}; got #{options[key].class}"
73
+ hash[key] = fetch_kv(option, key, value, type)
74
+ end
75
+ end
76
+ end
77
+
78
+ [:syntax_highlighter].each do |type|
79
+ define_singleton_method :"process_#{type}_plugin" do |plugin|
80
+ return nil if plugin.nil? # plugin explicitly nil, remove it
81
+
82
+ Commonmarker::Config::PLUGINS[type].each_with_object({}) do |(key, value), hash|
83
+ if plugin.nil? # option not provided, go for the default
84
+ hash[key] = value
85
+ next
68
86
  end
87
+
88
+ # option explicitly not included, remove it
89
+ next if plugin[key].nil?
90
+
91
+ hash[key] = fetch_kv(plugin, key, value, type)
69
92
  end
70
93
  end
71
94
  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
@@ -3,7 +3,7 @@
3
3
  begin
4
4
  # native precompiled gems package shared libraries in <gem_dir>/lib/commonmarker/<ruby_version>
5
5
  # load the precompiled extension file
6
- ruby_version = /\d+\.\d+/.match(::RUBY_VERSION)
6
+ ruby_version = /\d+\.\d+/.match(RUBY_VERSION)
7
7
  require_relative "#{ruby_version}/commonmarker"
8
8
  rescue LoadError
9
9
  # fall back to the extension compiled upon installation.
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "commonmarker/constants"
4
+
5
+ module Commonmarker
6
+ module Utils
7
+ include Commonmarker::Constants
8
+
9
+ def fetch_kv(option, key, value, type)
10
+ value_klass = value.class
11
+
12
+ if Constants::BOOLS.include?(value) && BOOLS.include?(option[key])
13
+ option[key]
14
+ elsif option[key].is_a?(value_klass)
15
+ option[key]
16
+ else
17
+ expected_type = Constants::BOOLS.include?(value) ? "Boolean" : value_klass.to_s
18
+ raise TypeError, "#{type} option `:#{key}` must be #{expected_type}; got #{option[key].class}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Commonmarker
4
- VERSION = "1.0.0.pre3"
4
+ VERSION = "1.0.0.pre4"
5
5
  end
data/lib/commonmarker.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "commonmarker/extension"
4
4
 
5
+ require "commonmarker/utils"
5
6
  require "commonmarker/config"
6
7
  require "commonmarker/renderer"
7
8
  require "commonmarker/version"
@@ -16,15 +17,19 @@ module Commonmarker
16
17
  # Public: Parses a CommonMark string into an HTML string.
17
18
  #
18
19
  # text - A {String} of text
19
- # option - A {Hash} of render, parse, and extension options to transform the text.
20
+ # options - A {Hash} of render, parse, and extension options to transform the text.
21
+ # plugins - A {Hash} of additional plugins.
20
22
  #
21
23
  # Returns a {String} of converted HTML.
22
- def to_html(text, options: Commonmarker::Config::OPTS)
24
+ def to_html(text, options: Commonmarker::Config::OPTIONS, plugins: Commonmarker::Config::PLUGINS)
23
25
  raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
26
+ raise TypeError, "text must be UTF-8 encoded; got #{text.encoding}!" unless text.encoding.name == "UTF-8"
24
27
  raise TypeError, "options must be a Hash; got a #{options.class}!" unless options.is_a?(Hash)
25
28
 
26
29
  opts = Config.process_options(options)
27
- commonmark_to_html(text.encode("UTF-8"), opts)
30
+ plugins = Config.process_plugins(plugins)
31
+
32
+ commonmark_to_html(text, options: opts, plugins: plugins)
28
33
  end
29
34
  end
30
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commonmarker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre3
4
+ version: 1.0.0.pre4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-11-30 00:00:00.000000000 Z
12
+ date: 2022-12-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rb_sys
@@ -81,12 +81,17 @@ files:
81
81
  - ext/commonmarker/Cargo.toml
82
82
  - ext/commonmarker/_util.rb
83
83
  - ext/commonmarker/extconf.rb
84
- - ext/commonmarker/src/comrak_options.rs
85
84
  - ext/commonmarker/src/lib.rs
85
+ - ext/commonmarker/src/options.rs
86
+ - ext/commonmarker/src/plugins.rs
87
+ - ext/commonmarker/src/plugins/syntax_highlighting.rs
88
+ - ext/commonmarker/src/utils.rs
86
89
  - lib/commonmarker.rb
87
90
  - lib/commonmarker/config.rb
91
+ - lib/commonmarker/constants.rb
88
92
  - lib/commonmarker/extension.rb
89
93
  - lib/commonmarker/renderer.rb
94
+ - lib/commonmarker/utils.rb
90
95
  - lib/commonmarker/version.rb
91
96
  homepage: https://github.com/gjtorikian/commonmarker
92
97
  licenses: