gitlab-glfm-markdown 0.0.38-x86_64-darwin → 0.0.39-x86_64-darwin
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.
- checksums.yaml +4 -4
- data/Cargo.lock +5 -5
- data/README.md +11 -9
- data/ext/{glfm_markdown → gitlab_glfm_markdown}/Cargo.lock +5 -5
- data/ext/{glfm_markdown → gitlab_glfm_markdown}/Cargo.toml +4 -4
- data/ext/{glfm_markdown → gitlab_glfm_markdown}/extconf.rb +1 -1
- data/ext/{glfm_markdown → gitlab_glfm_markdown}/src/formatter.rs +223 -154
- data/ext/{glfm_markdown → gitlab_glfm_markdown}/src/glfm.rs +17 -32
- data/ext/{glfm_markdown → gitlab_glfm_markdown}/src/main.rs +44 -41
- data/lib/{glfm_markdown.rb → gitlab-glfm-markdown.rb} +3 -5
- data/lib/gitlab_glfm_markdown/3.1/gitlab_glfm_markdown.bundle +0 -0
- data/lib/gitlab_glfm_markdown/3.2/gitlab_glfm_markdown.bundle +0 -0
- data/lib/gitlab_glfm_markdown/3.3/gitlab_glfm_markdown.bundle +0 -0
- data/lib/gitlab_glfm_markdown/3.4/gitlab_glfm_markdown.bundle +0 -0
- data/lib/{glfm_markdown → gitlab_glfm_markdown}/loader.rb +2 -2
- data/lib/{glfm_markdown → gitlab_glfm_markdown}/version.rb +1 -1
- metadata +16 -16
- data/lib/glfm_markdown/3.1/glfm_markdown.bundle +0 -0
- data/lib/glfm_markdown/3.2/glfm_markdown.bundle +0 -0
- data/lib/glfm_markdown/3.3/glfm_markdown.bundle +0 -0
- data/lib/glfm_markdown/3.4/glfm_markdown.bundle +0 -0
- /data/ext/{glfm_markdown → gitlab_glfm_markdown}/src/lib.rs +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9eb694119506621492b7659d1bd522f97566ed823af69be586e50646be82e7fa
|
|
4
|
+
data.tar.gz: 07b289e75140bf136a4cbdbaf0d2d68ab23972afe83685827c89036859a6af23
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f58b420de6e7db1c756fc37351d2320400a9862940d0597fb8eb7a7a5fc2e20d15f08fde63ac78061e8bd2974ae203d3ac7ee507974e53c824f81feb07005d44
|
|
7
|
+
data.tar.gz: 4ed99885946862f293e63a73d8e3f95443be22214999c1e6323a6cc78dc95640b5addc02329593566062fa22b8fc5e5ca07e4984a972c1680372fd5b865e359d
|
data/Cargo.lock
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This file is automatically @generated by Cargo.
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
|
-
version =
|
|
3
|
+
version = 4
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "adler2"
|
|
@@ -221,9 +221,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
|
|
221
221
|
|
|
222
222
|
[[package]]
|
|
223
223
|
name = "comrak"
|
|
224
|
-
version = "0.
|
|
224
|
+
version = "0.48.0"
|
|
225
225
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
226
|
-
checksum = "
|
|
226
|
+
checksum = "48bf2260aceee247c6c5639f5751dc635211895066d782d2a28fb87f2e0d5613"
|
|
227
227
|
dependencies = [
|
|
228
228
|
"caseless",
|
|
229
229
|
"emojis",
|
|
@@ -306,8 +306,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
306
306
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
307
307
|
|
|
308
308
|
[[package]]
|
|
309
|
-
name = "
|
|
310
|
-
version = "0.0.
|
|
309
|
+
name = "gitlab-glfm-markdown"
|
|
310
|
+
version = "0.0.39"
|
|
311
311
|
dependencies = [
|
|
312
312
|
"clap",
|
|
313
313
|
"comrak",
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/releases)
|
|
5
5
|
|
|
6
6
|
Implements GLFM (as used by GitLab) using the Rust-based Markdown parser
|
|
7
|
-
[Comrak](https://github.com/kivikakk/comrak) (0.
|
|
7
|
+
[Comrak](https://github.com/kivikakk/comrak) (0.48.0), providing a Ruby interface.
|
|
8
8
|
|
|
9
9
|
This project is still in constant flux, so interfaces and functionality can change at any time.
|
|
10
10
|
|
|
@@ -26,7 +26,7 @@ Try on command line:
|
|
|
26
26
|
rake compile
|
|
27
27
|
bin/console
|
|
28
28
|
|
|
29
|
-
require '
|
|
29
|
+
require 'gitlab-glfm-markdown'
|
|
30
30
|
|
|
31
31
|
GLFMMarkdown.to_html('# header', options: { sourcepos: true })
|
|
32
32
|
```
|
|
@@ -37,9 +37,10 @@ GLFMMarkdown.to_html('# header', options: { sourcepos: true })
|
|
|
37
37
|
|-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
38
38
|
| `autolink` | Enable the `autolink` extension |
|
|
39
39
|
| `cjk_friendly_emphasis` | Enable the [`cjk_friendly_emphasis` extension](https://github.com/tats-u/markdown-cjk-friendly) |
|
|
40
|
+
| `default_html` | Disables any custom HTML, and returns default HTML from `comrak` |
|
|
40
41
|
| `description_lists` | Enable the `description-lists` extension |
|
|
41
|
-
| `escape` | Escape raw HTML instead of clobbering it |
|
|
42
42
|
| `escape_char_spans` | Wrap escaped characters in a `<span>` to allow any post-processing to recognize them |
|
|
43
|
+
| `escape` | Escape raw HTML instead of clobbering it |
|
|
43
44
|
| `figure_with_caption` | Render the image as a figure element with the title as its caption |
|
|
44
45
|
| `footnotes` | Enable the `footnotes` extension |
|
|
45
46
|
| `full_info_string` | Enable full info strings for code blocks |
|
|
@@ -48,6 +49,7 @@ GLFMMarkdown.to_html('# header', options: { sourcepos: true })
|
|
|
48
49
|
| `github_pre_lang` | Use GitHub-style `<pre lang>` for code blocks |
|
|
49
50
|
| `greentext` | Enable the `greentext` extension - requires at least one space after a `>` character to generate a blockquote, and restarts blockquote nesting across unique lines of input |
|
|
50
51
|
| `hardbreaks` | Treat newlines as hard line breaks |
|
|
52
|
+
| `header_accessibility` | Use new header/anchor combination in HTML output, per [!112](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/merge_requests/112). |
|
|
51
53
|
| `header_ids <PREFIX>` | Enable the `header-id` extension, with the given ID prefix |
|
|
52
54
|
| `ignore_empty_links` | Ignore empty links in input |
|
|
53
55
|
| `ignore_setext` | Ignore setext headings in input |
|
|
@@ -55,24 +57,24 @@ GLFMMarkdown.to_html('# header', options: { sourcepos: true })
|
|
|
55
57
|
| `math_code` | Enables `math code` extension, using math code syntax |
|
|
56
58
|
| `math_dollars` | Enables `math dollars` extension, using math dollar syntax |
|
|
57
59
|
| `multiline_block_quotes` | Enable the `multiline-block-quotes` extension |
|
|
58
|
-
| `
|
|
60
|
+
| `only_escape_chars <CHARS>` | When the 'escaped_char_spans' render option is enabled, only emit `<span data-escaped-char>` around the given characters. |
|
|
59
61
|
| `placeholder_detection` | Detect placeholder variables in the format `%{placeholder}` |
|
|
60
62
|
| `relaxed_autolinks` | Enable relaxing of autolink parsing, allowing links to be recognized when in brackets, with any scheme, and with dot-less hostnames |
|
|
61
63
|
| `relaxed_tasklist_character` | Enable relaxing which character is allowed in tasklists |
|
|
62
|
-
| `sourcepos` | Include source mappings in HTML attributes |
|
|
63
64
|
| `smart` | Use smart punctuation |
|
|
65
|
+
| `sourcepos` | Include source mappings in HTML attributes |
|
|
64
66
|
| `spoiler` | Enable the `spoiler` extension - use double vertical bars |
|
|
65
67
|
| `strikethrough` | Enable the `strikethrough` extension |
|
|
66
68
|
| `superscript` | Enable the `superscript` extension |
|
|
67
69
|
| `table` | Enable the `table` extension |
|
|
68
70
|
| `tagfilter` | Enable the `tagfilter` extension |
|
|
69
|
-
| `tasklist` | Enable the `tasklist` extension |
|
|
70
71
|
| `tasklist_classes` | Output classes on tasklist elements so that they can be styled with CSS |
|
|
72
|
+
| `tasklist_in_table` | Enables parsing tasklist items within tables when they're the only content of a table cell |
|
|
73
|
+
| `tasklist` | Enable the `tasklist` extension |
|
|
71
74
|
| `underline` | Enables the `underline` extension - use double underscores |
|
|
72
75
|
| `unsafe` | Allow raw HTML and dangerous URLs |
|
|
73
76
|
| `wikilinks_title_after_pipe` | Enable the `wikilinks_title_after_pipe` extension |
|
|
74
77
|
| `wikilinks_title_before_pipe` | Enable the `wikilinks_title_before_pipe` extension |
|
|
75
|
-
| `debug` | Show debug information |
|
|
76
78
|
|
|
77
79
|
## Dingus / Demo
|
|
78
80
|
|
|
@@ -85,8 +87,8 @@ https://gitlab-org.gitlab.io/ruby/gems/gitlab-glfm-markdown
|
|
|
85
87
|
A command line executable can be built for debugging.
|
|
86
88
|
|
|
87
89
|
```
|
|
88
|
-
cargo run --bin
|
|
89
|
-
cargo run --bin
|
|
90
|
+
cargo run --bin gitlab-glfm-markdown --features="cli" -- --help
|
|
91
|
+
cargo run --bin gitlab-glfm-markdown --features="cli" -- --sourcepos
|
|
90
92
|
```
|
|
91
93
|
|
|
92
94
|
There is a VSCode workspace that allows you to `Debug executable`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This file is automatically @generated by Cargo.
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
|
-
version =
|
|
3
|
+
version = 4
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "adler2"
|
|
@@ -221,9 +221,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
|
|
221
221
|
|
|
222
222
|
[[package]]
|
|
223
223
|
name = "comrak"
|
|
224
|
-
version = "0.
|
|
224
|
+
version = "0.48.0"
|
|
225
225
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
226
|
-
checksum = "
|
|
226
|
+
checksum = "48bf2260aceee247c6c5639f5751dc635211895066d782d2a28fb87f2e0d5613"
|
|
227
227
|
dependencies = [
|
|
228
228
|
"caseless",
|
|
229
229
|
"emojis",
|
|
@@ -306,8 +306,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
306
306
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
307
307
|
|
|
308
308
|
[[package]]
|
|
309
|
-
name = "
|
|
310
|
-
version = "0.0.
|
|
309
|
+
name = "gitlab-glfm-markdown"
|
|
310
|
+
version = "0.0.39"
|
|
311
311
|
dependencies = [
|
|
312
312
|
"clap",
|
|
313
313
|
"comrak",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
3
|
-
version = "0.0.
|
|
2
|
+
name = "gitlab-glfm-markdown"
|
|
3
|
+
version = "0.0.39"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["digitalmoksha <bwalker@gitlab.com>", "Asherah Connor <aconnor@gitlab.com>"]
|
|
6
6
|
description = "GitLab Flavored Markdown parser and formatter. 100% CommonMark-compatible. Experimental."
|
|
@@ -10,12 +10,12 @@ publish = false
|
|
|
10
10
|
crate-type = ["cdylib"]
|
|
11
11
|
|
|
12
12
|
[[bin]]
|
|
13
|
-
name = "
|
|
13
|
+
name = "gitlab-glfm-markdown"
|
|
14
14
|
required-features = ["cli"]
|
|
15
15
|
|
|
16
16
|
[dependencies]
|
|
17
17
|
clap = { version = "=4.4.18", optional = true, features = ["derive", "string"] }
|
|
18
|
-
comrak = { version = "0.
|
|
18
|
+
comrak = { version = "0.48.0", default-features = false, features = ["shortcodes"] }
|
|
19
19
|
magnus = "0.8.2"
|
|
20
20
|
rb-sys = { version = "0.9.117", default-features = false, features = ["stable-api-compiled-fallback"] }
|
|
21
21
|
regex = "1.11.1"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'mkmf'
|
|
4
4
|
require 'rb_sys/mkmf'
|
|
5
5
|
|
|
6
|
-
create_rust_makefile('
|
|
6
|
+
create_rust_makefile('gitlab_glfm_markdown/gitlab_glfm_markdown') do |r|
|
|
7
7
|
r.auto_install_rust_toolchain = false
|
|
8
8
|
# Ensure all Rust dependencies are pinned when building
|
|
9
9
|
r.extra_cargo_args = ["--locked"]
|
|
@@ -1,104 +1,99 @@
|
|
|
1
1
|
use std::fmt::{self, Write};
|
|
2
|
+
use std::sync::LazyLock;
|
|
2
3
|
|
|
3
|
-
use comrak::html::{render_sourcepos, ChildRendering, Context};
|
|
4
|
-
use comrak::nodes::{AstNode, ListType, NodeValue};
|
|
5
|
-
use comrak::{create_formatter, html};
|
|
6
|
-
use lazy_static::lazy_static;
|
|
4
|
+
use comrak::html::{collect_text, format_node_default, render_sourcepos, ChildRendering, Context};
|
|
5
|
+
use comrak::nodes::{AstNode, ListType, NodeHeading, NodeLink, NodeList, NodeValue};
|
|
6
|
+
use comrak::{create_formatter, html, node_matches};
|
|
7
7
|
use regex::Regex;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
9
|
+
use crate::glfm::RenderOptions;
|
|
10
|
+
|
|
11
|
+
static PLACEHOLDER_REGEX: LazyLock<Regex> =
|
|
12
|
+
LazyLock::new(|| Regex::new(r"%\{(?:\w{1,30})}").unwrap());
|
|
14
13
|
|
|
15
14
|
pub struct RenderUserData {
|
|
16
15
|
pub default_html: bool,
|
|
17
16
|
pub inapplicable_tasks: bool,
|
|
18
17
|
pub placeholder_detection: bool,
|
|
19
18
|
pub only_escape_chars: Option<Vec<char>>,
|
|
20
|
-
pub
|
|
19
|
+
pub header_accessibility: bool,
|
|
20
|
+
|
|
21
|
+
last_heading: Option<String>,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
impl From<&RenderOptions> for RenderUserData {
|
|
25
|
+
fn from(options: &RenderOptions) -> Self {
|
|
26
|
+
RenderUserData {
|
|
27
|
+
default_html: options.default_html,
|
|
28
|
+
inapplicable_tasks: options.inapplicable_tasks,
|
|
29
|
+
placeholder_detection: options.placeholder_detection,
|
|
30
|
+
only_escape_chars: options.only_escape_chars.clone(),
|
|
31
|
+
header_accessibility: options.header_accessibility,
|
|
32
|
+
last_heading: None,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
21
35
|
}
|
|
22
36
|
|
|
23
37
|
// The important thing to remember is that this overrides the default behavior of the
|
|
24
38
|
// specified nodes. If we do override a node, then it's our responsibility to ensure that
|
|
25
|
-
// any changes in the
|
|
39
|
+
// any changes in the Comrak code for those nodes is backported to here, such as when
|
|
26
40
|
// `figcaption` support was added.
|
|
41
|
+
//
|
|
27
42
|
// One idea to limit that would be having the ability to specify attributes that would
|
|
28
43
|
// be inserted when a node is rendered. That would allow us to (in many cases) just
|
|
29
|
-
// inject the changes we need. Such a feature would need to be added to
|
|
44
|
+
// inject the changes we need. Such a feature would need to be added to Comrak.
|
|
30
45
|
create_formatter!(CustomFormatter<RenderUserData>, {
|
|
31
|
-
NodeValue::Text(
|
|
32
|
-
return render_text(context, node, entering);
|
|
46
|
+
NodeValue::Text(ref literal) => |context, node, entering| {
|
|
47
|
+
return render_text(context, node, entering, literal);
|
|
33
48
|
},
|
|
34
|
-
NodeValue::Link(
|
|
35
|
-
return render_link(context, node, entering);
|
|
49
|
+
NodeValue::Link(ref nl) => |context, node, entering| {
|
|
50
|
+
return render_link(context, node, entering, nl);
|
|
36
51
|
},
|
|
37
|
-
NodeValue::Image(
|
|
38
|
-
return render_image(context, node, entering);
|
|
52
|
+
NodeValue::Image(ref nl) => |context, node, entering| {
|
|
53
|
+
return render_image(context, node, entering, nl);
|
|
39
54
|
},
|
|
40
|
-
NodeValue::List(
|
|
41
|
-
return render_list(context, node, entering);
|
|
55
|
+
NodeValue::List(ref nl) => |context, node, entering| {
|
|
56
|
+
return render_list(context, node, entering, nl);
|
|
42
57
|
},
|
|
43
|
-
NodeValue::TaskItem(
|
|
44
|
-
return render_task_item(context, node, entering);
|
|
58
|
+
NodeValue::TaskItem(symbol) => |context, node, entering| {
|
|
59
|
+
return render_task_item(context, node, entering, symbol);
|
|
45
60
|
},
|
|
46
61
|
NodeValue::Escaped => |context, node, entering| {
|
|
47
62
|
return render_escaped(context, node, entering);
|
|
48
63
|
},
|
|
64
|
+
NodeValue::Heading(ref nh) => |context, node, entering| {
|
|
65
|
+
return render_heading(context, node, entering, nh);
|
|
66
|
+
},
|
|
49
67
|
});
|
|
50
68
|
|
|
51
|
-
fn
|
|
69
|
+
fn render_text<'a>(
|
|
52
70
|
context: &mut Context<RenderUserData>,
|
|
53
71
|
node: &'a AstNode<'a>,
|
|
54
72
|
entering: bool,
|
|
73
|
+
literal: &str,
|
|
55
74
|
) -> Result<ChildRendering, fmt::Error> {
|
|
56
|
-
|
|
57
|
-
unreachable!()
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(&nl.url)) {
|
|
75
|
+
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(literal)) {
|
|
61
76
|
return html::format_node_default(context, node, entering);
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
if entering {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
context.write_str(" src=\"")?;
|
|
71
|
-
if context.options.render.r#unsafe || !html::dangerous_url(&nl.url) {
|
|
72
|
-
if let Some(rewriter) = &context.options.extension.image_url_rewriter {
|
|
73
|
-
context.escape_href(&rewriter.to_html(&nl.url))?;
|
|
74
|
-
} else {
|
|
75
|
-
context.escape_href(&nl.url)?;
|
|
80
|
+
let mut cursor: usize = 0;
|
|
81
|
+
|
|
82
|
+
for mat in PLACEHOLDER_REGEX.find_iter(literal) {
|
|
83
|
+
if mat.start() > cursor {
|
|
84
|
+
context.escape(&literal[cursor..mat.start()])?;
|
|
76
85
|
}
|
|
77
|
-
}
|
|
78
86
|
|
|
79
|
-
|
|
87
|
+
context.write_str("<span data-placeholder>")?;
|
|
88
|
+
context.escape(&literal[mat.start()..mat.end()])?;
|
|
89
|
+
context.write_str("</span>")?;
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
context.write_str(" data-placeholder")?;
|
|
91
|
+
cursor = mat.end();
|
|
83
92
|
}
|
|
84
93
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return Ok(ChildRendering::Plain);
|
|
88
|
-
} else {
|
|
89
|
-
if !nl.title.is_empty() {
|
|
90
|
-
context.write_str("\" title=\"")?;
|
|
91
|
-
context.escape(&nl.title)?;
|
|
94
|
+
if cursor < literal.len() {
|
|
95
|
+
context.escape(&literal[cursor..])?;
|
|
92
96
|
}
|
|
93
|
-
context.write_str("\" />")?;
|
|
94
|
-
if context.options.render.figure_with_caption {
|
|
95
|
-
if !nl.title.is_empty() {
|
|
96
|
-
context.write_str("<figcaption>")?;
|
|
97
|
-
context.escape(&nl.title)?;
|
|
98
|
-
context.write_str("</figcaption>")?;
|
|
99
|
-
}
|
|
100
|
-
context.write_str("</figure>")?;
|
|
101
|
-
};
|
|
102
97
|
}
|
|
103
98
|
|
|
104
99
|
Ok(ChildRendering::HTML)
|
|
@@ -108,11 +103,8 @@ fn render_link<'a>(
|
|
|
108
103
|
context: &mut Context<RenderUserData>,
|
|
109
104
|
node: &'a AstNode<'a>,
|
|
110
105
|
entering: bool,
|
|
106
|
+
nl: &NodeLink,
|
|
111
107
|
) -> Result<ChildRendering, fmt::Error> {
|
|
112
|
-
let NodeValue::Link(ref nl) = node.data.borrow().value else {
|
|
113
|
-
unreachable!()
|
|
114
|
-
};
|
|
115
|
-
|
|
116
108
|
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(&nl.url)) {
|
|
117
109
|
return html::format_node_default(context, node, entering);
|
|
118
110
|
}
|
|
@@ -144,9 +136,8 @@ fn render_link<'a>(
|
|
|
144
136
|
context.escape(&nl.title)?;
|
|
145
137
|
}
|
|
146
138
|
|
|
147
|
-
if
|
|
148
|
-
|
|
149
|
-
}
|
|
139
|
+
// This path only taken if placeholder detection is enabled, and the regex matched.
|
|
140
|
+
context.write_str(" data-placeholder")?;
|
|
150
141
|
|
|
151
142
|
context.write_str(">")?;
|
|
152
143
|
} else {
|
|
@@ -157,21 +148,70 @@ fn render_link<'a>(
|
|
|
157
148
|
Ok(ChildRendering::HTML)
|
|
158
149
|
}
|
|
159
150
|
|
|
151
|
+
fn render_image<'a>(
|
|
152
|
+
context: &mut Context<RenderUserData>,
|
|
153
|
+
node: &'a AstNode<'a>,
|
|
154
|
+
entering: bool,
|
|
155
|
+
nl: &NodeLink,
|
|
156
|
+
) -> Result<ChildRendering, fmt::Error> {
|
|
157
|
+
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(&nl.url)) {
|
|
158
|
+
return html::format_node_default(context, node, entering);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if entering {
|
|
162
|
+
if context.options.render.figure_with_caption {
|
|
163
|
+
context.write_str("<figure>")?;
|
|
164
|
+
}
|
|
165
|
+
context.write_str("<img")?;
|
|
166
|
+
html::render_sourcepos(context, node)?;
|
|
167
|
+
context.write_str(" src=\"")?;
|
|
168
|
+
if context.options.render.r#unsafe || !html::dangerous_url(&nl.url) {
|
|
169
|
+
if let Some(rewriter) = &context.options.extension.image_url_rewriter {
|
|
170
|
+
context.escape_href(&rewriter.to_html(&nl.url))?;
|
|
171
|
+
} else {
|
|
172
|
+
context.escape_href(&nl.url)?;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
context.write_str("\"")?;
|
|
177
|
+
|
|
178
|
+
// This path only taken if placeholder detection is enabled, and the regex matched.
|
|
179
|
+
context.write_str(" data-placeholder")?;
|
|
180
|
+
|
|
181
|
+
context.write_str(" alt=\"")?;
|
|
182
|
+
|
|
183
|
+
return Ok(ChildRendering::Plain);
|
|
184
|
+
} else {
|
|
185
|
+
if !nl.title.is_empty() {
|
|
186
|
+
context.write_str("\" title=\"")?;
|
|
187
|
+
context.escape(&nl.title)?;
|
|
188
|
+
}
|
|
189
|
+
context.write_str("\" />")?;
|
|
190
|
+
if context.options.render.figure_with_caption {
|
|
191
|
+
if !nl.title.is_empty() {
|
|
192
|
+
context.write_str("<figcaption>")?;
|
|
193
|
+
context.escape(&nl.title)?;
|
|
194
|
+
context.write_str("</figcaption>")?;
|
|
195
|
+
}
|
|
196
|
+
context.write_str("</figure>")?;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
Ok(ChildRendering::HTML)
|
|
201
|
+
}
|
|
202
|
+
|
|
160
203
|
// Overridden to use class `task-list` instead of `contains-task-list`
|
|
161
204
|
// to align with GitLab class usage
|
|
162
205
|
fn render_list<'a>(
|
|
163
206
|
context: &mut Context<RenderUserData>,
|
|
164
207
|
node: &'a AstNode<'a>,
|
|
165
208
|
entering: bool,
|
|
209
|
+
nl: &NodeList,
|
|
166
210
|
) -> Result<ChildRendering, fmt::Error> {
|
|
167
211
|
if !entering || !context.options.render.tasklist_classes {
|
|
168
212
|
return html::format_node_default(context, node, entering);
|
|
169
213
|
}
|
|
170
214
|
|
|
171
|
-
let NodeValue::List(ref nl) = node.data.borrow().value else {
|
|
172
|
-
unreachable!()
|
|
173
|
-
};
|
|
174
|
-
|
|
175
215
|
context.cr()?;
|
|
176
216
|
match nl.list_type {
|
|
177
217
|
ListType::Bullet => {
|
|
@@ -204,143 +244,172 @@ fn render_task_item<'a>(
|
|
|
204
244
|
context: &mut Context<RenderUserData>,
|
|
205
245
|
node: &'a AstNode<'a>,
|
|
206
246
|
entering: bool,
|
|
247
|
+
symbol: Option<char>,
|
|
207
248
|
) -> Result<ChildRendering, fmt::Error> {
|
|
208
249
|
if !context.user.inapplicable_tasks {
|
|
209
250
|
return html::format_node_default(context, node, entering);
|
|
210
251
|
}
|
|
211
252
|
|
|
212
|
-
let
|
|
213
|
-
|
|
253
|
+
let Some(symbol) = symbol else {
|
|
254
|
+
return html::format_node_default(context, node, entering);
|
|
214
255
|
};
|
|
215
256
|
|
|
216
|
-
if symbol
|
|
257
|
+
if symbol == 'x' || symbol == 'X' {
|
|
217
258
|
return html::format_node_default(context, node, entering);
|
|
218
259
|
}
|
|
219
260
|
|
|
261
|
+
// We only proceed past this point if:
|
|
262
|
+
//
|
|
263
|
+
// * inapplicable_tasks is enabled; and,
|
|
264
|
+
// * the symbol is present (the tasklist didn't contain a ' '), and isn't 'x' or 'X'.
|
|
265
|
+
//
|
|
266
|
+
// There are three possibilities remaining:
|
|
267
|
+
//
|
|
268
|
+
// * the symbol is '~': we write out an inapplicable task item.
|
|
269
|
+
// * the symbol is a different Unicode whitespace: we write out an incomplete task item,
|
|
270
|
+
// per Comrak.
|
|
271
|
+
// * the symbol is something else: we write out the source Markdown that would've been entered,
|
|
272
|
+
// to act like a non-match.
|
|
273
|
+
//
|
|
274
|
+
// TODO: have Comrak accept a list of acceptable tasklist symbols instead. :)
|
|
275
|
+
|
|
276
|
+
let write_li = node
|
|
277
|
+
.parent()
|
|
278
|
+
.map(|p| node_matches!(p, NodeValue::List(_)))
|
|
279
|
+
.unwrap_or_default();
|
|
280
|
+
|
|
220
281
|
if entering {
|
|
221
|
-
|
|
222
|
-
if matches!(symbol, Some('~')) {
|
|
282
|
+
if symbol == '~' {
|
|
223
283
|
context.cr()?;
|
|
224
|
-
|
|
225
|
-
|
|
284
|
+
if write_li {
|
|
285
|
+
context.write_str("<li")?;
|
|
286
|
+
context.write_str(" class=\"inapplicable")?;
|
|
226
287
|
|
|
227
|
-
|
|
228
|
-
|
|
288
|
+
if context.options.render.tasklist_classes {
|
|
289
|
+
context.write_str(" task-list-item")?;
|
|
290
|
+
}
|
|
291
|
+
context.write_str("\"")?;
|
|
292
|
+
html::render_sourcepos(context, node)?;
|
|
293
|
+
context.write_str(">")?;
|
|
229
294
|
}
|
|
230
|
-
context.write_str("\"")?;
|
|
231
|
-
|
|
232
|
-
html::render_sourcepos(context, node)?;
|
|
233
|
-
context.write_str(">")?;
|
|
234
295
|
context.write_str("<input type=\"checkbox\"")?;
|
|
235
|
-
|
|
296
|
+
if !write_li {
|
|
297
|
+
html::render_sourcepos(context, node)?;
|
|
298
|
+
}
|
|
236
299
|
if context.options.render.tasklist_classes {
|
|
237
300
|
context.write_str(" class=\"task-list-item-checkbox\"")?;
|
|
238
301
|
}
|
|
239
302
|
|
|
240
303
|
context.write_str(" data-inapplicable disabled=\"\"> ")?;
|
|
241
|
-
} else {
|
|
242
|
-
// Don't allow unsupported symbols to render a checkbox
|
|
304
|
+
} else if symbol.is_whitespace() {
|
|
243
305
|
context.cr()?;
|
|
244
|
-
|
|
245
|
-
|
|
306
|
+
if write_li {
|
|
307
|
+
context.write_str("<li")?;
|
|
308
|
+
if context.options.render.tasklist_classes {
|
|
309
|
+
context.write_str(" class=\"task-list-item\"")?;
|
|
310
|
+
}
|
|
311
|
+
render_sourcepos(context, node)?;
|
|
312
|
+
context.write_str(">")?;
|
|
313
|
+
}
|
|
314
|
+
context.write_str("<input type=\"checkbox\"")?;
|
|
315
|
+
if !write_li {
|
|
316
|
+
render_sourcepos(context, node)?;
|
|
317
|
+
}
|
|
246
318
|
if context.options.render.tasklist_classes {
|
|
247
|
-
context.write_str(" class=\"task-list-item\"")?;
|
|
319
|
+
context.write_str(" class=\"task-list-item-checkbox\"")?;
|
|
320
|
+
}
|
|
321
|
+
context.write_str(" disabled=\"\" /> ")?;
|
|
322
|
+
} else {
|
|
323
|
+
context.cr()?;
|
|
324
|
+
if write_li {
|
|
325
|
+
context.write_str("<li")?;
|
|
326
|
+
if context.options.render.tasklist_classes {
|
|
327
|
+
context.write_str(" class=\"task-list-item\"")?;
|
|
328
|
+
}
|
|
329
|
+
html::render_sourcepos(context, node)?;
|
|
330
|
+
context.write_str(">")?;
|
|
248
331
|
}
|
|
249
|
-
|
|
250
|
-
html::render_sourcepos(context, node)?;
|
|
251
|
-
context.write_str(">")?;
|
|
252
332
|
context.write_str("[")?;
|
|
253
|
-
context.escape(&symbol.
|
|
333
|
+
context.escape(&symbol.to_string())?;
|
|
254
334
|
context.write_str("] ")?;
|
|
255
335
|
}
|
|
256
|
-
} else {
|
|
336
|
+
} else if write_li {
|
|
257
337
|
context.write_str("</li>\n")?;
|
|
258
338
|
}
|
|
259
339
|
|
|
260
340
|
Ok(ChildRendering::HTML)
|
|
261
341
|
}
|
|
262
342
|
|
|
263
|
-
fn
|
|
343
|
+
fn render_escaped<'a>(
|
|
264
344
|
context: &mut Context<RenderUserData>,
|
|
265
345
|
node: &'a AstNode<'a>,
|
|
266
346
|
entering: bool,
|
|
267
347
|
) -> Result<ChildRendering, fmt::Error> {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(literal)) {
|
|
273
|
-
return html::format_node_default(context, node, entering);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Don't currently support placeholders in the text inside links or images.
|
|
277
|
-
// If the text has an underscore in it, then the parser will not combine
|
|
278
|
-
// the multiple text nodes in `comrak`'s `postprocess_text_nodes`, breaking up
|
|
279
|
-
// the placeholder into multiple text nodes.
|
|
280
|
-
// For example, `[%{a_b}](link)`.
|
|
281
|
-
let parent = node.parent().unwrap();
|
|
282
|
-
if matches!(
|
|
283
|
-
parent.data.borrow().value,
|
|
284
|
-
NodeValue::Link(_) | NodeValue::Image(_)
|
|
285
|
-
) {
|
|
286
|
-
return html::format_node_default(context, node, entering);
|
|
348
|
+
if !context.options.render.escaped_char_spans {
|
|
349
|
+
return Ok(ChildRendering::HTML);
|
|
287
350
|
}
|
|
288
351
|
|
|
289
|
-
if
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
352
|
+
if context
|
|
353
|
+
.user
|
|
354
|
+
.only_escape_chars
|
|
355
|
+
.as_ref()
|
|
356
|
+
.map_or(true, |only_escape_chars| {
|
|
357
|
+
with_node_text_content(node, false, |content| {
|
|
358
|
+
content.chars().count() == 1
|
|
359
|
+
&& only_escape_chars.contains(&content.chars().next().unwrap())
|
|
360
|
+
})
|
|
361
|
+
})
|
|
362
|
+
{
|
|
363
|
+
if entering {
|
|
364
|
+
context.write_str("<span data-escaped-char")?;
|
|
365
|
+
render_sourcepos(context, node)?;
|
|
366
|
+
context.write_str(">")?;
|
|
367
|
+
} else {
|
|
299
368
|
context.write_str("</span>")?;
|
|
300
|
-
|
|
301
|
-
cursor = mat.end();
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if cursor < literal.len() {
|
|
305
|
-
context.escape(&literal[cursor..literal.len()])?;
|
|
306
369
|
}
|
|
307
370
|
}
|
|
308
371
|
|
|
309
372
|
Ok(ChildRendering::HTML)
|
|
310
373
|
}
|
|
311
374
|
|
|
312
|
-
fn
|
|
375
|
+
fn render_heading<'a>(
|
|
313
376
|
context: &mut Context<RenderUserData>,
|
|
314
377
|
node: &'a AstNode<'a>,
|
|
315
378
|
entering: bool,
|
|
379
|
+
nh: &NodeHeading,
|
|
316
380
|
) -> Result<ChildRendering, fmt::Error> {
|
|
317
|
-
if !context.
|
|
318
|
-
return
|
|
381
|
+
if !context.user.header_accessibility || context.plugins.render.heading_adapter.is_some() {
|
|
382
|
+
return format_node_default(context, node, entering);
|
|
319
383
|
}
|
|
320
384
|
|
|
321
|
-
if
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
let
|
|
327
|
-
context
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
.as_ref()
|
|
331
|
-
.unwrap()
|
|
332
|
-
.contains(&c)
|
|
333
|
-
})
|
|
334
|
-
{
|
|
335
|
-
if entering {
|
|
336
|
-
context.write_str("<span data-escaped-char")?;
|
|
337
|
-
render_sourcepos(context, node)?;
|
|
338
|
-
context.write_str(">")?;
|
|
339
|
-
} else {
|
|
340
|
-
context.write_str("</span>")?;
|
|
385
|
+
if entering {
|
|
386
|
+
context.cr()?;
|
|
387
|
+
write!(context, "<h{}", nh.level)?;
|
|
388
|
+
|
|
389
|
+
if let Some(ref prefix) = context.options.extension.header_ids {
|
|
390
|
+
let text_content = collect_text(node);
|
|
391
|
+
let id = context.anchorizer.anchorize(&text_content);
|
|
392
|
+
write!(context, r##" id="{prefix}{id}""##)?;
|
|
393
|
+
context.user.last_heading = Some(id);
|
|
341
394
|
}
|
|
342
|
-
}
|
|
343
395
|
|
|
396
|
+
render_sourcepos(context, node)?;
|
|
397
|
+
context.write_str(">")?;
|
|
398
|
+
} else {
|
|
399
|
+
if context.options.extension.header_ids.is_some() {
|
|
400
|
+
let id = context.user.last_heading.take().unwrap();
|
|
401
|
+
let text_content = collect_text(node);
|
|
402
|
+
write!(
|
|
403
|
+
context,
|
|
404
|
+
r##"<a href="#{id}" aria-label="Link to heading '"##
|
|
405
|
+
)?;
|
|
406
|
+
context.escape(&text_content)?;
|
|
407
|
+
context.write_str(r#"'" data-heading-content=""#)?;
|
|
408
|
+
context.escape(&text_content)?;
|
|
409
|
+
context.write_str(r#"" class="anchor"></a>"#)?;
|
|
410
|
+
}
|
|
411
|
+
writeln!(context, "</h{}>", nh.level)?;
|
|
412
|
+
}
|
|
344
413
|
Ok(ChildRendering::HTML)
|
|
345
414
|
}
|
|
346
415
|
|
|
@@ -10,6 +10,8 @@ pub struct RenderOptions {
|
|
|
10
10
|
pub alerts: bool,
|
|
11
11
|
pub autolink: bool,
|
|
12
12
|
pub cjk_friendly_emphasis: bool,
|
|
13
|
+
/// Only use default comrak HTML formatting
|
|
14
|
+
pub default_html: bool,
|
|
13
15
|
// pub default_info_string: String,
|
|
14
16
|
pub description_lists: bool,
|
|
15
17
|
pub escape: bool,
|
|
@@ -23,16 +25,27 @@ pub struct RenderOptions {
|
|
|
23
25
|
pub github_pre_lang: bool,
|
|
24
26
|
pub greentext: bool,
|
|
25
27
|
pub hardbreaks: bool,
|
|
28
|
+
/// Use new header/anchor combination in HTML output, per
|
|
29
|
+
/// https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/merge_requests/112.
|
|
30
|
+
pub header_accessibility: bool,
|
|
26
31
|
pub header_ids: Option<String>,
|
|
27
32
|
pub ignore_empty_links: bool,
|
|
28
33
|
pub ignore_setext: bool,
|
|
34
|
+
/// Detect inapplicable tasks (`- [~]`)
|
|
35
|
+
pub inapplicable_tasks: bool,
|
|
29
36
|
pub math_code: bool,
|
|
30
37
|
pub math_dollars: bool,
|
|
31
38
|
pub multiline_block_quotes: bool,
|
|
39
|
+
/// When the 'escaped_char_spans' render option is enabled, only emit `<span
|
|
40
|
+
/// data-escaped-char>` around the given characters.
|
|
41
|
+
pub only_escape_chars: Option<Vec<char>>,
|
|
42
|
+
/// Detect and mark potential placeholder variables, which
|
|
43
|
+
/// have the format `%{PLACEHOLDER}`
|
|
44
|
+
pub placeholder_detection: bool,
|
|
32
45
|
pub relaxed_autolinks: bool,
|
|
33
46
|
pub relaxed_tasklist_character: bool,
|
|
34
|
-
pub sourcepos: bool,
|
|
35
47
|
pub smart: bool,
|
|
48
|
+
pub sourcepos: bool,
|
|
36
49
|
pub spoiler: bool,
|
|
37
50
|
pub strikethrough: bool,
|
|
38
51
|
pub subscript: bool,
|
|
@@ -42,40 +55,11 @@ pub struct RenderOptions {
|
|
|
42
55
|
pub tagfilter: bool,
|
|
43
56
|
pub tasklist: bool,
|
|
44
57
|
pub tasklist_classes: bool,
|
|
58
|
+
pub tasklist_in_table: bool,
|
|
45
59
|
pub underline: bool,
|
|
46
60
|
pub r#unsafe: bool,
|
|
47
61
|
pub wikilinks_title_after_pipe: bool,
|
|
48
62
|
pub wikilinks_title_before_pipe: bool,
|
|
49
|
-
|
|
50
|
-
/// GLFM specific options
|
|
51
|
-
|
|
52
|
-
/// Only use default comrak HTML formatting
|
|
53
|
-
pub default_html: bool,
|
|
54
|
-
|
|
55
|
-
/// Detect inapplicable tasks (`- [~]`)
|
|
56
|
-
pub inapplicable_tasks: bool,
|
|
57
|
-
|
|
58
|
-
/// Detect and mark potential placeholder variables, which
|
|
59
|
-
/// have the format `%{PLACEHOLDER}`
|
|
60
|
-
pub placeholder_detection: bool,
|
|
61
|
-
|
|
62
|
-
/// When the 'escaped_char_spans' render option is enabled, only emit `<span
|
|
63
|
-
/// data-escaped-char>` around the given characters.
|
|
64
|
-
pub only_escape_chars: Option<Vec<char>>,
|
|
65
|
-
|
|
66
|
-
pub debug: bool,
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
impl From<&RenderOptions> for RenderUserData {
|
|
70
|
-
fn from(options: &RenderOptions) -> Self {
|
|
71
|
-
RenderUserData {
|
|
72
|
-
default_html: options.default_html,
|
|
73
|
-
inapplicable_tasks: options.inapplicable_tasks,
|
|
74
|
-
placeholder_detection: options.placeholder_detection,
|
|
75
|
-
only_escape_chars: options.only_escape_chars.clone(),
|
|
76
|
-
debug: options.debug,
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
63
|
}
|
|
80
64
|
|
|
81
65
|
impl From<&RenderOptions> for comrak::Options<'_> {
|
|
@@ -120,10 +104,11 @@ impl From<&RenderOptions> for comrak::Options<'_> {
|
|
|
120
104
|
comrak_options.render.r#unsafe = options.r#unsafe;
|
|
121
105
|
|
|
122
106
|
// comrak_options.parse.default_info_string = options.default_info_string;
|
|
107
|
+
comrak_options.parse.ignore_setext = options.ignore_setext;
|
|
123
108
|
comrak_options.parse.relaxed_autolinks = options.relaxed_autolinks;
|
|
124
109
|
comrak_options.parse.relaxed_tasklist_matching = options.relaxed_tasklist_character;
|
|
125
110
|
comrak_options.parse.smart = options.smart;
|
|
126
|
-
comrak_options.parse.
|
|
111
|
+
comrak_options.parse.tasklist_in_table = options.tasklist_in_table;
|
|
127
112
|
|
|
128
113
|
comrak_options
|
|
129
114
|
}
|
|
@@ -14,6 +14,10 @@ struct Args {
|
|
|
14
14
|
#[arg(value_name = "FILE")]
|
|
15
15
|
file: Option<String>,
|
|
16
16
|
|
|
17
|
+
/// Write output to FILE instead of stdout
|
|
18
|
+
#[arg(short, long, value_name = "FILE")]
|
|
19
|
+
output: Option<String>,
|
|
20
|
+
|
|
17
21
|
/// Enable 'alerts' extension
|
|
18
22
|
#[arg(long)]
|
|
19
23
|
alerts: bool,
|
|
@@ -22,6 +26,14 @@ struct Args {
|
|
|
22
26
|
#[arg(long)]
|
|
23
27
|
autolink: bool,
|
|
24
28
|
|
|
29
|
+
/// Enable 'cjk_friendly_emphasis' extension
|
|
30
|
+
#[arg(long)]
|
|
31
|
+
cjk_friendly_emphasis: bool,
|
|
32
|
+
|
|
33
|
+
/// Only use default comrak HTML formatting
|
|
34
|
+
#[arg(long)]
|
|
35
|
+
default_html: bool,
|
|
36
|
+
|
|
25
37
|
/// Enable 'description-lists' extension
|
|
26
38
|
#[arg(long)]
|
|
27
39
|
description_lists: bool,
|
|
@@ -72,6 +84,11 @@ struct Args {
|
|
|
72
84
|
#[arg(long)]
|
|
73
85
|
hardbreaks: bool,
|
|
74
86
|
|
|
87
|
+
/// Use new header/anchor combination in HTML output, per
|
|
88
|
+
/// https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/merge_requests/112.
|
|
89
|
+
#[arg(long)]
|
|
90
|
+
header_accessibility: bool,
|
|
91
|
+
|
|
75
92
|
/// Enable the 'header IDs' extension, with the given ID prefix
|
|
76
93
|
#[arg(long, value_name = "PREFIX")]
|
|
77
94
|
header_ids: Option<String>,
|
|
@@ -84,6 +101,10 @@ struct Args {
|
|
|
84
101
|
#[arg(long)]
|
|
85
102
|
ignore_setext: bool,
|
|
86
103
|
|
|
104
|
+
/// Detect inapplicable tasks (`- [~]`)
|
|
105
|
+
#[arg(long)]
|
|
106
|
+
inapplicable_tasks: bool,
|
|
107
|
+
|
|
87
108
|
/// Enables `math code` extension, using math code syntax
|
|
88
109
|
#[arg(long)]
|
|
89
110
|
math_code: bool,
|
|
@@ -96,9 +117,15 @@ struct Args {
|
|
|
96
117
|
#[arg(long)]
|
|
97
118
|
multiline_block_quotes: bool,
|
|
98
119
|
|
|
99
|
-
///
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
/// When the 'escaped_char_spans' render option is enabled, only emit `<span
|
|
121
|
+
/// data-escaped-char>` around the characters in the supplied string.
|
|
122
|
+
#[arg(long)]
|
|
123
|
+
only_escape_chars: Option<String>,
|
|
124
|
+
|
|
125
|
+
/// Detect and marks potential placeholder variables, which
|
|
126
|
+
/// have the format `%{PLACEHOLDER}`
|
|
127
|
+
#[arg(long)]
|
|
128
|
+
placeholder_detection: bool,
|
|
102
129
|
|
|
103
130
|
/// Enable relaxing of autolink parsing, allowing links to be recognized when in brackets
|
|
104
131
|
#[arg(long)]
|
|
@@ -108,14 +135,14 @@ struct Args {
|
|
|
108
135
|
#[arg(long)]
|
|
109
136
|
relaxed_tasklist_character: bool,
|
|
110
137
|
|
|
111
|
-
/// Include source mappings in HTML attributes
|
|
112
|
-
#[arg(long)]
|
|
113
|
-
sourcepos: bool,
|
|
114
|
-
|
|
115
138
|
/// Use smart punctuation
|
|
116
139
|
#[arg(long)]
|
|
117
140
|
smart: bool,
|
|
118
141
|
|
|
142
|
+
/// Include source mappings in HTML attributes
|
|
143
|
+
#[arg(long)]
|
|
144
|
+
sourcepos: bool,
|
|
145
|
+
|
|
119
146
|
/// Enables spoilers using double vertical bars
|
|
120
147
|
#[arg(long)]
|
|
121
148
|
spoiler: bool,
|
|
@@ -152,6 +179,10 @@ struct Args {
|
|
|
152
179
|
#[arg(long)]
|
|
153
180
|
tasklist_classes: bool,
|
|
154
181
|
|
|
182
|
+
/// Enables parsing tasklist items within tables when they're the only content of a table cell
|
|
183
|
+
#[arg(long)]
|
|
184
|
+
tasklist_in_table: bool,
|
|
185
|
+
|
|
155
186
|
/// Enables underlines using double underscores
|
|
156
187
|
#[arg(long)]
|
|
157
188
|
underline: bool,
|
|
@@ -167,34 +198,6 @@ struct Args {
|
|
|
167
198
|
/// Enable 'wikilink_title_before_pipe' extension
|
|
168
199
|
#[arg(long)]
|
|
169
200
|
wikilinks_title_before_pipe: bool,
|
|
170
|
-
|
|
171
|
-
/// Only use default comrak HTML formatting
|
|
172
|
-
#[arg(long)]
|
|
173
|
-
default_html: bool,
|
|
174
|
-
|
|
175
|
-
/// GLFM specific options
|
|
176
|
-
|
|
177
|
-
/// Detect inapplicable tasks (`- [~]`)
|
|
178
|
-
#[arg(long)]
|
|
179
|
-
inapplicable_tasks: bool,
|
|
180
|
-
|
|
181
|
-
/// Detect and marks potential placeholder variables, which
|
|
182
|
-
/// have the format `%{PLACEHOLDER}`
|
|
183
|
-
#[arg(long)]
|
|
184
|
-
placeholder_detection: bool,
|
|
185
|
-
|
|
186
|
-
/// When the 'escaped_char_spans' render option is enabled, only emit `<span
|
|
187
|
-
/// data-escaped-char>` around the characters in the supplied string.
|
|
188
|
-
#[arg(long)]
|
|
189
|
-
only_escape_chars: Option<String>,
|
|
190
|
-
|
|
191
|
-
/// Enable 'cjk_friendly_emphasis' extension
|
|
192
|
-
#[arg(long)]
|
|
193
|
-
cjk_friendly_emphasis: bool,
|
|
194
|
-
|
|
195
|
-
/// Show debug information
|
|
196
|
-
#[arg(long)]
|
|
197
|
-
debug: bool,
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
fn main() {
|
|
@@ -216,6 +219,7 @@ fn main() {
|
|
|
216
219
|
autolink: cli.autolink,
|
|
217
220
|
cjk_friendly_emphasis: cli.cjk_friendly_emphasis,
|
|
218
221
|
// default_info_string:
|
|
222
|
+
default_html: cli.default_html,
|
|
219
223
|
description_lists: cli.description_lists,
|
|
220
224
|
escape: cli.escape,
|
|
221
225
|
escaped_char_spans: cli.escaped_char_spans,
|
|
@@ -228,6 +232,7 @@ fn main() {
|
|
|
228
232
|
github_pre_lang: cli.github_pre_lang,
|
|
229
233
|
greentext: cli.greentext,
|
|
230
234
|
hardbreaks: cli.hardbreaks,
|
|
235
|
+
header_accessibility: cli.header_accessibility,
|
|
231
236
|
header_ids: cli.header_ids,
|
|
232
237
|
ignore_empty_links: cli.ignore_empty_links,
|
|
233
238
|
ignore_setext: cli.ignore_setext,
|
|
@@ -235,10 +240,12 @@ fn main() {
|
|
|
235
240
|
math_code: cli.math_code,
|
|
236
241
|
math_dollars: cli.math_dollars,
|
|
237
242
|
multiline_block_quotes: cli.multiline_block_quotes,
|
|
243
|
+
only_escape_chars: cli.only_escape_chars.map(|s| s.chars().collect()),
|
|
244
|
+
placeholder_detection: cli.placeholder_detection,
|
|
238
245
|
relaxed_autolinks: cli.relaxed_autolinks,
|
|
239
246
|
relaxed_tasklist_character: cli.relaxed_tasklist_character,
|
|
240
|
-
sourcepos: cli.sourcepos,
|
|
241
247
|
smart: cli.smart,
|
|
248
|
+
sourcepos: cli.sourcepos,
|
|
242
249
|
spoiler: cli.spoiler,
|
|
243
250
|
strikethrough: cli.strikethrough,
|
|
244
251
|
subscript: cli.subscript,
|
|
@@ -248,15 +255,11 @@ fn main() {
|
|
|
248
255
|
tagfilter: cli.tagfilter,
|
|
249
256
|
tasklist: cli.tasklist,
|
|
250
257
|
tasklist_classes: cli.tasklist_classes,
|
|
258
|
+
tasklist_in_table: cli.tasklist_in_table,
|
|
251
259
|
underline: cli.underline,
|
|
252
260
|
r#unsafe: cli.r#unsafe,
|
|
253
261
|
wikilinks_title_after_pipe: cli.wikilinks_title_after_pipe,
|
|
254
262
|
wikilinks_title_before_pipe: cli.wikilinks_title_before_pipe,
|
|
255
|
-
|
|
256
|
-
default_html: cli.default_html,
|
|
257
|
-
placeholder_detection: cli.placeholder_detection,
|
|
258
|
-
only_escape_chars: cli.only_escape_chars.map(|s| s.chars().collect()),
|
|
259
|
-
debug: cli.debug,
|
|
260
263
|
};
|
|
261
264
|
|
|
262
265
|
let result = render(&source, &options);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
4
|
-
require_relative '
|
|
3
|
+
require_relative 'gitlab_glfm_markdown/version'
|
|
4
|
+
require_relative 'gitlab_glfm_markdown/loader'
|
|
5
5
|
|
|
6
6
|
load_rust_extension
|
|
7
7
|
|
|
@@ -27,9 +27,7 @@ module GLFMMarkdown
|
|
|
27
27
|
tagfilter: false,
|
|
28
28
|
tasklist: true,
|
|
29
29
|
tasklist_classes: true,
|
|
30
|
-
unsafe: true
|
|
31
|
-
|
|
32
|
-
debug: false
|
|
30
|
+
unsafe: true
|
|
33
31
|
}.freeze
|
|
34
32
|
|
|
35
33
|
class << self
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
def load_rust_extension
|
|
4
4
|
ruby_version = /(\d+\.\d+)/.match(RUBY_VERSION)
|
|
5
|
-
require "
|
|
5
|
+
require "gitlab_glfm_markdown/#{ruby_version}/gitlab_glfm_markdown"
|
|
6
6
|
rescue LoadError
|
|
7
|
-
require '
|
|
7
|
+
require 'gitlab_glfm_markdown/gitlab_glfm_markdown'
|
|
8
8
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-glfm-markdown
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.39
|
|
5
5
|
platform: x86_64-darwin
|
|
6
6
|
authors:
|
|
7
7
|
- Brett Walker
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2025-
|
|
12
|
+
date: 2025-11-14 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rb_sys
|
|
@@ -64,20 +64,20 @@ files:
|
|
|
64
64
|
- Cargo.lock
|
|
65
65
|
- LICENSE
|
|
66
66
|
- README.md
|
|
67
|
-
- ext/
|
|
68
|
-
- ext/
|
|
69
|
-
- ext/
|
|
70
|
-
- ext/
|
|
71
|
-
- ext/
|
|
72
|
-
- ext/
|
|
73
|
-
- ext/
|
|
74
|
-
- lib/
|
|
75
|
-
- lib/
|
|
76
|
-
- lib/
|
|
77
|
-
- lib/
|
|
78
|
-
- lib/
|
|
79
|
-
- lib/
|
|
80
|
-
- lib/
|
|
67
|
+
- ext/gitlab_glfm_markdown/Cargo.lock
|
|
68
|
+
- ext/gitlab_glfm_markdown/Cargo.toml
|
|
69
|
+
- ext/gitlab_glfm_markdown/extconf.rb
|
|
70
|
+
- ext/gitlab_glfm_markdown/src/formatter.rs
|
|
71
|
+
- ext/gitlab_glfm_markdown/src/glfm.rs
|
|
72
|
+
- ext/gitlab_glfm_markdown/src/lib.rs
|
|
73
|
+
- ext/gitlab_glfm_markdown/src/main.rs
|
|
74
|
+
- lib/gitlab-glfm-markdown.rb
|
|
75
|
+
- lib/gitlab_glfm_markdown/3.1/gitlab_glfm_markdown.bundle
|
|
76
|
+
- lib/gitlab_glfm_markdown/3.2/gitlab_glfm_markdown.bundle
|
|
77
|
+
- lib/gitlab_glfm_markdown/3.3/gitlab_glfm_markdown.bundle
|
|
78
|
+
- lib/gitlab_glfm_markdown/3.4/gitlab_glfm_markdown.bundle
|
|
79
|
+
- lib/gitlab_glfm_markdown/loader.rb
|
|
80
|
+
- lib/gitlab_glfm_markdown/version.rb
|
|
81
81
|
homepage: https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown
|
|
82
82
|
licenses:
|
|
83
83
|
- MIT
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|