gitlab-glfm-markdown 0.0.29-aarch64-linux-gnu → 0.0.30-aarch64-linux-gnu
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 +17 -15
- data/README.md +38 -36
- data/ext/glfm_markdown/Cargo.toml +5 -3
- data/ext/glfm_markdown/src/glfm.rs +280 -47
- data/ext/glfm_markdown/src/lib.rs +2 -0
- data/ext/glfm_markdown/src/main.rs +17 -0
- data/lib/glfm_markdown/3.1/glfm_markdown.so +0 -0
- data/lib/glfm_markdown/3.2/glfm_markdown.so +0 -0
- data/lib/glfm_markdown/3.3/glfm_markdown.so +0 -0
- data/lib/glfm_markdown/3.4/glfm_markdown.so +0 -0
- data/lib/glfm_markdown/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 878c75b3bdaef03ccd49af2b1bfb36b92b6febcb94c2c972d690ceb7128ccfd0
|
4
|
+
data.tar.gz: 4dd78f5a5485e1d99672e64f67c027a0b53bd184f3e9fce1168b45a0358d8b20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fbc3086ae1c29921045fd3059828f4a7cc71817bed3851a16c78723b4c581b32d40ed533e1a0cf2b0f0870a1a56e7d78a1c9af7e5475e493090185fefd43514
|
7
|
+
data.tar.gz: 351ecd608e11ccc2905251b27b5adebeeac472bfb7f46a3edbda53ac9461762edfc9f1947276acf59282cd8c9cd13b12b928eccc7d62ce4f67b18ab1fd2af5d9
|
data/Cargo.lock
CHANGED
@@ -181,9 +181,9 @@ dependencies = [
|
|
181
181
|
|
182
182
|
[[package]]
|
183
183
|
name = "clap"
|
184
|
-
version = "4.
|
184
|
+
version = "4.4.18"
|
185
185
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
186
|
-
checksum = "
|
186
|
+
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
|
187
187
|
dependencies = [
|
188
188
|
"clap_builder",
|
189
189
|
"clap_derive",
|
@@ -191,9 +191,9 @@ dependencies = [
|
|
191
191
|
|
192
192
|
[[package]]
|
193
193
|
name = "clap_builder"
|
194
|
-
version = "4.
|
194
|
+
version = "4.4.18"
|
195
195
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
196
|
-
checksum = "
|
196
|
+
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
|
197
197
|
dependencies = [
|
198
198
|
"anstream",
|
199
199
|
"anstyle",
|
@@ -203,9 +203,9 @@ dependencies = [
|
|
203
203
|
|
204
204
|
[[package]]
|
205
205
|
name = "clap_derive"
|
206
|
-
version = "4.
|
206
|
+
version = "4.4.7"
|
207
207
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
208
|
-
checksum = "
|
208
|
+
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
|
209
209
|
dependencies = [
|
210
210
|
"heck",
|
211
211
|
"proc-macro2",
|
@@ -215,9 +215,9 @@ dependencies = [
|
|
215
215
|
|
216
216
|
[[package]]
|
217
217
|
name = "clap_lex"
|
218
|
-
version = "0.
|
218
|
+
version = "0.6.0"
|
219
219
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
220
|
-
checksum = "
|
220
|
+
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
221
221
|
|
222
222
|
[[package]]
|
223
223
|
name = "colorchoice"
|
@@ -227,9 +227,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
|
227
227
|
|
228
228
|
[[package]]
|
229
229
|
name = "comrak"
|
230
|
-
version = "0.
|
230
|
+
version = "0.39.0"
|
231
231
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
232
|
-
checksum = "
|
232
|
+
checksum = "d5c834ca54c5a20588b358f34d1533b4b498ddb5fd979cec6b22d0e8867a2449"
|
233
233
|
dependencies = [
|
234
234
|
"caseless",
|
235
235
|
"emojis",
|
@@ -320,12 +320,14 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
320
320
|
|
321
321
|
[[package]]
|
322
322
|
name = "glfm_markdown"
|
323
|
-
version = "0.0.
|
323
|
+
version = "0.0.30"
|
324
324
|
dependencies = [
|
325
325
|
"clap",
|
326
326
|
"comrak",
|
327
|
+
"lazy_static",
|
327
328
|
"magnus",
|
328
329
|
"rb-sys",
|
330
|
+
"regex",
|
329
331
|
]
|
330
332
|
|
331
333
|
[[package]]
|
@@ -342,9 +344,9 @@ checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
|
342
344
|
|
343
345
|
[[package]]
|
344
346
|
name = "heck"
|
345
|
-
version = "0.
|
347
|
+
version = "0.4.1"
|
346
348
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
347
|
-
checksum = "
|
349
|
+
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
348
350
|
|
349
351
|
[[package]]
|
350
352
|
name = "indexmap"
|
@@ -729,9 +731,9 @@ dependencies = [
|
|
729
731
|
|
730
732
|
[[package]]
|
731
733
|
name = "strsim"
|
732
|
-
version = "0.
|
734
|
+
version = "0.10.0"
|
733
735
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
734
|
-
checksum = "
|
736
|
+
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
735
737
|
|
736
738
|
[[package]]
|
737
739
|
name = "syn"
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Implements GLFM (as used by GitLab) using the Rust-based markdown parser [comrak](https://github.com/kivikakk/comrak)
|
7
7
|
and providing a Ruby interface.\
|
8
|
-
_Currently using `comrak 0.
|
8
|
+
_Currently using `comrak 0.39.0`_.
|
9
9
|
|
10
10
|
This project is still in constant flux, so interfaces and functionality can change at any time.
|
11
11
|
|
@@ -32,41 +32,43 @@ GLFMMarkdown.to_html('# header', options: { sourcepos: true })
|
|
32
32
|
|
33
33
|
### Options
|
34
34
|
|
35
|
-
| Option name
|
36
|
-
|
37
|
-
| `autolink`
|
38
|
-
| `description_lists`
|
39
|
-
| `escape`
|
40
|
-
| `escape_char_spans`
|
41
|
-
| `figure_with_caption`
|
42
|
-
| `footnotes`
|
43
|
-
| `full_info_string`
|
44
|
-
| `gemojis`
|
45
|
-
| `gfm_quirks`
|
46
|
-
| `github_pre_lang`
|
47
|
-
| `greentext`
|
48
|
-
| `hardbreaks`
|
49
|
-
| `header_ids <PREFIX>`
|
50
|
-
| `ignore_empty_links`
|
51
|
-
| `ignore_setext`
|
52
|
-
| `math_code`
|
53
|
-
| `math_dollars`
|
54
|
-
| `multiline_block_quotes`
|
55
|
-
| `
|
56
|
-
| `
|
57
|
-
| `
|
58
|
-
| `
|
59
|
-
| `
|
60
|
-
| `
|
61
|
-
| `
|
62
|
-
| `
|
63
|
-
| `
|
64
|
-
| `
|
65
|
-
| `
|
66
|
-
| `
|
67
|
-
| `
|
68
|
-
| `
|
69
|
-
| `
|
35
|
+
| Option name | Description |
|
36
|
+
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
37
|
+
| `autolink` | Enable the `autolink` extension |
|
38
|
+
| `description_lists` | Enable the `description-lists` extension |
|
39
|
+
| `escape` | Escape raw HTML instead of clobbering it |
|
40
|
+
| `escape_char_spans` | Wrap escaped characters in a `<span>` to allow any post-processing to recognize them |
|
41
|
+
| `figure_with_caption` | Render the image as a figure element with the title as its caption |
|
42
|
+
| `footnotes` | Enable the `footnotes` extension |
|
43
|
+
| `full_info_string` | Enable full info strings for code blocks |
|
44
|
+
| `gemojis` | Enable the `gemojis` extensions - translate gemojis into UTF-8 characters |
|
45
|
+
| `gfm_quirks` | Enables GFM-style quirks in output HTML, such as not nesting <strong> tags |
|
46
|
+
| `github_pre_lang` | Use GitHub-style `<pre lang>` for code blocks |
|
47
|
+
| `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 |
|
48
|
+
| `hardbreaks` | Treat newlines as hard line breaks |
|
49
|
+
| `header_ids <PREFIX>` | Enable the `header-id` extension, with the given ID prefix |
|
50
|
+
| `ignore_empty_links` | Ignore empty links in input |
|
51
|
+
| `ignore_setext` | Ignore setext headings in input |
|
52
|
+
| `math_code` | Enables `math code` extension, using math code syntax |
|
53
|
+
| `math_dollars` | Enables `math dollars` extension, using math dollar syntax |
|
54
|
+
| `multiline_block_quotes` | Enable the `multiline-block-quotes` extension |
|
55
|
+
| `default_html` | Disables any custom HTML, and returns default HTML from `comrak` |
|
56
|
+
| `placeholder_detection` | Detect placeholder variables in the format `%{placeholder}` |
|
57
|
+
| `relaxed_autolinks` | Enable relaxing of autolink parsing, allowing links to be recognized when in brackets |
|
58
|
+
| `relaxed_tasklist_character` | Enable relaxing which character is allowed in tasklists |
|
59
|
+
| `sourcepos` | Include source mappings in HTML attributes |
|
60
|
+
| `smart` | Use smart punctuation |
|
61
|
+
| `spoiler` | Enable the `spoiler` extension - use double vertical bars |
|
62
|
+
| `strikethrough` | Enable the `strikethrough` extension |
|
63
|
+
| `superscript` | Enable the `superscript` extension |
|
64
|
+
| `table` | Enable the `table` extension |
|
65
|
+
| `tagfilter` | Enable the `tagfilter` extension |
|
66
|
+
| `tasklist` | Enable the `tasklist` extension |
|
67
|
+
| `underline` | Enables the `underline` extension - use double underscores |
|
68
|
+
| `unsafe` | Allow raw HTML and dangerous URLs |
|
69
|
+
| `wikilinks_title_after_pipe` | Enable the `wikilinks_title_after_pipe` extension |
|
70
|
+
| `wikilinks_title_before_pipe` | Enable the `wikilinks_title_before_pipe` extension |
|
71
|
+
| `debug` | Show debug information |
|
70
72
|
|
71
73
|
## Dingus / Demo
|
72
74
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[package]
|
2
2
|
name = "glfm_markdown"
|
3
|
-
version = "0.0.
|
3
|
+
version = "0.0.30"
|
4
4
|
edition = "2021"
|
5
5
|
authors = ["digitalmoksha <bwalker@gitlab.com>"]
|
6
6
|
description = "GitLab Flavored Markdown parser and formatter. 100% CommonMark-compatible. Experimental."
|
@@ -14,10 +14,12 @@ name = "glfm_markdown"
|
|
14
14
|
required-features = ["cli"]
|
15
15
|
|
16
16
|
[dependencies]
|
17
|
-
clap = { version = "4.
|
18
|
-
comrak = { version = "0.
|
17
|
+
clap = { version = "=4.4.18", optional = true, features = ["derive", "string"] }
|
18
|
+
comrak = { version = "0.39.0", default-features = false, features = ["shortcodes"] }
|
19
19
|
magnus = "0.6.2"
|
20
20
|
rb-sys = { version = "0.9.86", default-features = false, features = ["stable-api-compiled-fallback"] }
|
21
|
+
regex = "1.11.1"
|
22
|
+
lazy_static = "1.5.0"
|
21
23
|
|
22
24
|
[features]
|
23
25
|
cli = ["clap", "comrak/syntect"]
|
@@ -1,4 +1,16 @@
|
|
1
|
-
|
1
|
+
use comrak::html::{ChildRendering, Context};
|
2
|
+
use comrak::nodes::{AstNode, NodeValue};
|
3
|
+
use comrak::{create_formatter, html, parse_document, Arena, Plugins};
|
4
|
+
use lazy_static::lazy_static;
|
5
|
+
use regex::Regex;
|
6
|
+
use std::io;
|
7
|
+
use std::io::{BufWriter, Write};
|
8
|
+
|
9
|
+
lazy_static! {
|
10
|
+
static ref PLACEHOLDER_REGEX: Regex = Regex::new(r"%(\{|%7B)(\w{1,30})(}|%7D)").unwrap();
|
11
|
+
}
|
12
|
+
|
13
|
+
#[derive(Debug, Clone)]
|
2
14
|
pub struct RenderOptions {
|
3
15
|
pub alerts: bool,
|
4
16
|
pub autolink: bool,
|
@@ -38,56 +50,277 @@ pub struct RenderOptions {
|
|
38
50
|
pub wikilinks_title_after_pipe: bool,
|
39
51
|
pub wikilinks_title_before_pipe: bool,
|
40
52
|
|
53
|
+
/// Only use default comrak HTML formatting
|
54
|
+
pub default_html: bool,
|
55
|
+
|
56
|
+
/// Detect and mark potential placeholder variables, which
|
57
|
+
/// have the format `%{PLACEHOLDER}`
|
58
|
+
pub placeholder_detection: bool,
|
59
|
+
|
41
60
|
pub debug: bool,
|
42
61
|
}
|
43
62
|
|
63
|
+
pub struct RenderUserData {
|
64
|
+
pub default_html: bool,
|
65
|
+
pub placeholder_detection: bool,
|
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
|
+
placeholder_detection: options.placeholder_detection,
|
74
|
+
debug: options.debug,
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
impl From<&RenderOptions> for comrak::Options<'_> {
|
80
|
+
fn from(options: &RenderOptions) -> Self {
|
81
|
+
let mut comrak_options = comrak::Options::default();
|
82
|
+
|
83
|
+
comrak_options.extension.alerts = options.alerts;
|
84
|
+
comrak_options.extension.autolink = options.autolink;
|
85
|
+
comrak_options.extension.description_lists = options.description_lists;
|
86
|
+
comrak_options.extension.footnotes = options.footnotes;
|
87
|
+
// comrak_options.extension.front_matter_delimiter = options.front_matter_delimiter;
|
88
|
+
comrak_options.extension.greentext = options.greentext;
|
89
|
+
comrak_options.extension.header_ids = options.header_ids.clone();
|
90
|
+
comrak_options.extension.math_code = options.math_code;
|
91
|
+
comrak_options.extension.math_dollars = options.math_dollars;
|
92
|
+
comrak_options.extension.multiline_block_quotes = options.multiline_block_quotes;
|
93
|
+
comrak_options.extension.shortcodes = options.gemojis;
|
94
|
+
comrak_options.extension.spoiler = options.spoiler;
|
95
|
+
comrak_options.extension.strikethrough = options.strikethrough;
|
96
|
+
comrak_options.extension.subscript = options.subscript;
|
97
|
+
comrak_options.extension.superscript = options.superscript;
|
98
|
+
comrak_options.extension.table = options.table;
|
99
|
+
comrak_options.extension.tagfilter = options.tagfilter;
|
100
|
+
comrak_options.extension.tasklist = options.tasklist;
|
101
|
+
comrak_options.extension.underline = options.underline;
|
102
|
+
comrak_options.extension.wikilinks_title_after_pipe = options.wikilinks_title_after_pipe;
|
103
|
+
comrak_options.extension.wikilinks_title_before_pipe = options.wikilinks_title_before_pipe;
|
104
|
+
|
105
|
+
comrak_options.render.escape = options.escape;
|
106
|
+
comrak_options.render.escaped_char_spans = options.escaped_char_spans;
|
107
|
+
comrak_options.render.figure_with_caption = options.figure_with_caption;
|
108
|
+
comrak_options.render.full_info_string = options.full_info_string;
|
109
|
+
comrak_options.render.gfm_quirks = options.gfm_quirks;
|
110
|
+
comrak_options.render.github_pre_lang = options.github_pre_lang;
|
111
|
+
comrak_options.render.hardbreaks = options.hardbreaks;
|
112
|
+
comrak_options.render.ignore_empty_links = options.ignore_empty_links;
|
113
|
+
comrak_options.render.ignore_setext = options.ignore_setext;
|
114
|
+
comrak_options.render.sourcepos = options.sourcepos;
|
115
|
+
// comrak_options.render.syntax_highlighting = options.syntax_highlighting;
|
116
|
+
|
117
|
+
comrak_options.render.unsafe_ = options.unsafe_;
|
118
|
+
|
119
|
+
// comrak_options.parse.default_info_string = options.default_info_string;
|
120
|
+
comrak_options.parse.relaxed_autolinks = options.relaxed_autolinks;
|
121
|
+
comrak_options.parse.relaxed_tasklist_matching = options.relaxed_tasklist_character;
|
122
|
+
comrak_options.parse.smart = options.smart;
|
123
|
+
|
124
|
+
comrak_options
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
44
128
|
pub fn render(text: String, options: RenderOptions) -> String {
|
45
|
-
|
129
|
+
render_with_plugins(text, options, &comrak::Plugins::default())
|
130
|
+
}
|
131
|
+
|
132
|
+
fn render_with_plugins(text: String, render_options: RenderOptions, plugins: &Plugins) -> String {
|
133
|
+
let user_data = RenderUserData::from(&render_options);
|
134
|
+
let options = comrak::Options::from(&render_options);
|
135
|
+
|
136
|
+
if user_data.default_html {
|
137
|
+
return comrak::markdown_to_html_with_plugins(&text, &options, plugins);
|
138
|
+
}
|
139
|
+
|
140
|
+
let arena = Arena::new();
|
141
|
+
let root = parse_document(&arena, &text, &options);
|
142
|
+
let mut bw = BufWriter::new(Vec::new());
|
143
|
+
|
144
|
+
CustomFormatter::format_document_with_plugins(root, &options, &mut bw, plugins, user_data)
|
145
|
+
.unwrap();
|
146
|
+
String::from_utf8(bw.into_inner().unwrap()).unwrap()
|
46
147
|
}
|
47
148
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
149
|
+
// The important thing to remember is that this overrides the default behavior of the
|
150
|
+
// specified nodes. If we do override a node, then it's our responsibility to ensure that
|
151
|
+
// any changes in the `comrak` code for those nodes is backported to here, such as when
|
152
|
+
// `figcaption` support was added.
|
153
|
+
// One idea to limit that would be having the ability to specify attributes that would
|
154
|
+
// be inserted when a node is rendered. That would allow us to (in many cases) just
|
155
|
+
// inject the changes we need. Such a feature would need to be added to `comrak`.
|
156
|
+
create_formatter!(CustomFormatter<RenderUserData>, {
|
157
|
+
NodeValue::Text(_) => |context, node, entering| {
|
158
|
+
return render_text(context, node, entering);
|
159
|
+
},
|
160
|
+
NodeValue::Link(_) => |context, node, entering| {
|
161
|
+
return render_link(context, node, entering);
|
162
|
+
},
|
163
|
+
NodeValue::Image(_) => |context, node, entering| {
|
164
|
+
return render_image(context, node, entering);
|
165
|
+
}
|
166
|
+
});
|
167
|
+
|
168
|
+
fn render_image<'a>(
|
169
|
+
context: &mut Context<RenderUserData>,
|
170
|
+
node: &'a AstNode<'a>,
|
171
|
+
entering: bool,
|
172
|
+
) -> io::Result<ChildRendering> {
|
173
|
+
let NodeValue::Image(ref nl) = node.data.borrow().value else {
|
174
|
+
panic!("Attempt to render invalid node as image")
|
175
|
+
};
|
176
|
+
|
177
|
+
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(nl.url.as_str())) {
|
178
|
+
return html::format_node_default(context, node, entering);
|
179
|
+
}
|
180
|
+
|
181
|
+
if entering {
|
182
|
+
if context.options.render.figure_with_caption {
|
183
|
+
context.write_all(b"<figure>")?;
|
184
|
+
}
|
185
|
+
context.write_all(b"<img")?;
|
186
|
+
html::render_sourcepos(context, node)?;
|
187
|
+
context.write_all(b" src=\"")?;
|
188
|
+
let url = nl.url.as_bytes();
|
189
|
+
if context.options.render.unsafe_ || !html::dangerous_url(url) {
|
190
|
+
if let Some(rewriter) = &context.options.extension.image_url_rewriter {
|
191
|
+
context.escape_href(rewriter.to_html(&nl.url).as_bytes())?;
|
192
|
+
} else {
|
193
|
+
context.escape_href(url)?;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
context.write_all(b"\"")?;
|
198
|
+
|
199
|
+
if PLACEHOLDER_REGEX.is_match(nl.url.as_str()) {
|
200
|
+
context.write_all(b" data-placeholder")?;
|
201
|
+
}
|
202
|
+
|
203
|
+
context.write_all(b" alt=\"")?;
|
204
|
+
|
205
|
+
return Ok(ChildRendering::Plain);
|
206
|
+
} else {
|
207
|
+
if !nl.title.is_empty() {
|
208
|
+
context.write_all(b"\" title=\"")?;
|
209
|
+
context.escape(nl.title.as_bytes())?;
|
210
|
+
}
|
211
|
+
context.write_all(b"\" />")?;
|
212
|
+
if context.options.render.figure_with_caption {
|
213
|
+
if !nl.title.is_empty() {
|
214
|
+
context.write_all(b"<figcaption>")?;
|
215
|
+
context.escape(nl.title.as_bytes())?;
|
216
|
+
context.write_all(b"</figcaption>")?;
|
217
|
+
}
|
218
|
+
context.write_all(b"</figure>")?;
|
219
|
+
};
|
220
|
+
}
|
221
|
+
|
222
|
+
Ok(ChildRendering::HTML)
|
223
|
+
}
|
224
|
+
|
225
|
+
fn render_link<'a>(
|
226
|
+
context: &mut Context<RenderUserData>,
|
227
|
+
node: &'a AstNode<'a>,
|
228
|
+
entering: bool,
|
229
|
+
) -> io::Result<ChildRendering> {
|
230
|
+
let NodeValue::Link(ref nl) = node.data.borrow().value else {
|
231
|
+
panic!("Attempt to render invalid node as link")
|
232
|
+
};
|
233
|
+
|
234
|
+
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(nl.url.as_str())) {
|
235
|
+
return html::format_node_default(context, node, entering);
|
236
|
+
}
|
237
|
+
|
238
|
+
let parent_node = node.parent();
|
239
|
+
|
240
|
+
if !context.options.parse.relaxed_autolinks
|
241
|
+
|| (parent_node.is_none()
|
242
|
+
|| !matches!(
|
243
|
+
parent_node.unwrap().data.borrow().value,
|
244
|
+
NodeValue::Link(..)
|
245
|
+
))
|
246
|
+
{
|
247
|
+
if entering {
|
248
|
+
context.write_all(b"<a")?;
|
249
|
+
html::render_sourcepos(context, node)?;
|
250
|
+
context.write_all(b" href=\"")?;
|
251
|
+
let url = nl.url.as_bytes();
|
252
|
+
if context.options.render.unsafe_ || !html::dangerous_url(url) {
|
253
|
+
if let Some(rewriter) = &context.options.extension.link_url_rewriter {
|
254
|
+
context.escape_href(rewriter.to_html(&nl.url).as_bytes())?;
|
255
|
+
} else {
|
256
|
+
context.escape_href(url)?;
|
257
|
+
}
|
258
|
+
}
|
259
|
+
context.write_all(b"\"")?;
|
260
|
+
|
261
|
+
if !nl.title.is_empty() {
|
262
|
+
context.write_all(b" title=\"")?;
|
263
|
+
context.escape(nl.title.as_bytes())?;
|
264
|
+
}
|
265
|
+
|
266
|
+
if PLACEHOLDER_REGEX.is_match(nl.url.as_str()) {
|
267
|
+
context.write_all(b" data-placeholder")?;
|
268
|
+
}
|
269
|
+
|
270
|
+
context.write_all(b">")?;
|
271
|
+
} else {
|
272
|
+
context.write_all(b"</a>")?;
|
273
|
+
}
|
274
|
+
}
|
275
|
+
|
276
|
+
Ok(ChildRendering::HTML)
|
277
|
+
}
|
278
|
+
|
279
|
+
fn render_text<'a>(
|
280
|
+
context: &mut Context<RenderUserData>,
|
281
|
+
node: &'a AstNode<'a>,
|
282
|
+
entering: bool,
|
283
|
+
) -> io::Result<ChildRendering> {
|
284
|
+
let NodeValue::Text(ref literal) = node.data.borrow().value else {
|
285
|
+
panic!("Attempt to render invalid node as text")
|
286
|
+
};
|
287
|
+
|
288
|
+
if !(context.user.placeholder_detection && PLACEHOLDER_REGEX.is_match(literal)) {
|
289
|
+
return html::format_node_default(context, node, entering);
|
290
|
+
}
|
291
|
+
|
292
|
+
// Don't currently support placeholders in the text inside links or images.
|
293
|
+
// If the text has an underscore in it, then the parser will not combine
|
294
|
+
// the multiple text nodes in `comrak`'s `postprocess_text_nodes`, breaking up
|
295
|
+
// the placeholder into multiple text nodes.
|
296
|
+
// For example, `[%{a_b}](link)`.
|
297
|
+
let parent = node.parent().unwrap();
|
298
|
+
if matches!(
|
299
|
+
parent.data.borrow().value,
|
300
|
+
NodeValue::Link(_) | NodeValue::Image(_)
|
301
|
+
) {
|
302
|
+
return html::format_node_default(context, node, entering);
|
303
|
+
}
|
304
|
+
|
305
|
+
if entering {
|
306
|
+
let mut cursor: usize = 0;
|
307
|
+
|
308
|
+
for mat in PLACEHOLDER_REGEX.find_iter(literal) {
|
309
|
+
if mat.start() > cursor {
|
310
|
+
context.escape(literal[cursor..mat.start()].as_bytes())?;
|
311
|
+
}
|
312
|
+
|
313
|
+
context.write_all(b"<span data-placeholder>")?;
|
314
|
+
context.escape(literal[mat.start()..mat.end()].as_bytes())?;
|
315
|
+
context.write_all(b"</span>")?;
|
316
|
+
|
317
|
+
cursor = mat.end();
|
318
|
+
}
|
319
|
+
|
320
|
+
if cursor < literal.len() {
|
321
|
+
context.escape(literal[cursor..literal.len()].as_bytes())?;
|
322
|
+
}
|
323
|
+
}
|
324
|
+
|
325
|
+
Ok(ChildRendering::HTML)
|
93
326
|
}
|
@@ -53,6 +53,8 @@ pub fn render_to_html_rs(text: String, options: RHash) -> String {
|
|
53
53
|
wikilinks_title_after_pipe: get_bool_opt("wikilinks_title_after_pipe", options),
|
54
54
|
wikilinks_title_before_pipe: get_bool_opt("wikilinks_title_before_pipe", options),
|
55
55
|
|
56
|
+
default_html: get_bool_opt("default_html", options),
|
57
|
+
placeholder_detection: get_bool_opt("placeholder_detection", options),
|
56
58
|
debug: get_bool_opt("debug", options),
|
57
59
|
};
|
58
60
|
|
@@ -32,6 +32,10 @@ struct Args {
|
|
32
32
|
#[arg(long)]
|
33
33
|
escaped_char_spans: bool,
|
34
34
|
|
35
|
+
/// Render the image as a figure element with the title as its caption
|
36
|
+
#[arg(long)]
|
37
|
+
figure_with_caption: bool,
|
38
|
+
|
35
39
|
/// Enable 'footnotes' extension
|
36
40
|
#[arg(long)]
|
37
41
|
footnotes: bool,
|
@@ -158,6 +162,15 @@ struct Args {
|
|
158
162
|
#[arg(long)]
|
159
163
|
wikilinks_title_before_pipe: bool,
|
160
164
|
|
165
|
+
/// Only use default comrak HTML formatting
|
166
|
+
#[arg(long)]
|
167
|
+
default_html: bool,
|
168
|
+
|
169
|
+
/// Detect and marks potential placeholder variables, which
|
170
|
+
/// have the format `%{PLACEHOLDER}`
|
171
|
+
#[arg(long)]
|
172
|
+
placeholder_detection: bool,
|
173
|
+
|
161
174
|
/// Show debug information
|
162
175
|
#[arg(long)]
|
163
176
|
debug: bool,
|
@@ -184,6 +197,7 @@ fn main() {
|
|
184
197
|
description_lists: cli.description_lists,
|
185
198
|
escape: cli.escape,
|
186
199
|
escaped_char_spans: cli.escaped_char_spans,
|
200
|
+
figure_with_caption: cli.figure_with_caption,
|
187
201
|
footnotes: cli.footnotes,
|
188
202
|
// front_matter_delimiter:
|
189
203
|
full_info_string: cli.full_info_string,
|
@@ -214,6 +228,9 @@ fn main() {
|
|
214
228
|
unsafe_: cli.unsafe_,
|
215
229
|
wikilinks_title_after_pipe: cli.wikilinks_title_after_pipe,
|
216
230
|
wikilinks_title_before_pipe: cli.wikilinks_title_before_pipe,
|
231
|
+
|
232
|
+
default_html: cli.default_html,
|
233
|
+
placeholder_detection: cli.placeholder_detection,
|
217
234
|
debug: cli.debug,
|
218
235
|
};
|
219
236
|
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.30
|
5
5
|
platform: aarch64-linux-gnu
|
6
6
|
authors:
|
7
7
|
- Brett Walker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rb_sys
|