1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! Public configuration types for HTML rendering.
//!
//! Keeping options separate from the renderer implementation makes the public API easy
//! to scan: this module owns only user-supplied configuration and lightweight enums.
/// HTML renderer options.
///
/// Use [`HtmlRendererOptions::new`] or [`Default::default`] for the documented
/// defaults.
#[derive(Debug, Clone)]
pub struct HtmlRendererOptions {
/// Use XHTML-style self-closing tags (e.g., `<br />`).
///
/// Default: `false`.
pub xhtml: bool,
/// Add soft breaks between inline elements.
///
/// Default: `"\n"`.
pub soft_break: String,
/// Add hard breaks.
///
/// Default: `"<br>\n"`.
pub hard_break: String,
/// Enable syntax highlighting for code blocks.
///
/// Default: `false`.
pub highlight: bool,
/// Sanitize HTML output.
///
/// Default: `false`.
pub sanitize: bool,
/// Convert `.md` links to `.html` links for SSG output.
///
/// Default: `false`.
pub convert_md_links: bool,
/// Base URL for absolute link conversion (e.g., "/" or "/docs/").
///
/// Default: `"/"`.
pub base_url: String,
/// Source file path for relative link resolution.
/// Used to determine if the current file is an index file.
///
/// Default: empty string.
pub source_path: String,
/// Enable line annotations for code blocks using fence meta.
///
/// Default: `false`.
pub code_annotations: bool,
/// Fence meta key used to read code annotations.
///
/// Default: `"annotate"`.
pub code_annotation_meta_key: String,
/// Code annotation syntax mode.
///
/// Default: [`CodeAnnotationSyntax::Attribute`].
pub code_annotation_syntax: CodeAnnotationSyntax,
/// Enable line numbers for all code blocks by default.
///
/// Default: `false`.
pub code_annotation_default_line_numbers: bool,
/// Maximum heading depth included in inline TOCs.
///
/// Default: `3`.
pub toc_max_depth: u8,
/// Auto-link bare URLs in text. When enabled, any occurrence in a text
/// node that starts with one of [`Self::autolink_patterns`] is wrapped
/// in an `<a>` tag. Auto-linking is suppressed inside an existing link.
///
/// Default: `false`.
pub autolink_urls: bool,
/// URL prefix patterns recognised by [`Self::autolink_urls`]. Defaults
/// to `["http://", "https://"]`. Register additional schemes (e.g.
/// `"ftp://"`, `"mailto:"`) by pushing onto this vec.
///
/// Default: `["http://", "https://"]`.
pub autolink_patterns: Vec<String>,
/// When auto-linking, emit `target="_blank" rel="noopener noreferrer"`.
/// Independent from the existing markdown-link behaviour, which always
/// adds the attributes for http/https hrefs.
///
/// Default: `true`.
pub autolink_target_blank: bool,
}
impl HtmlRendererOptions {
/// Creates new options with default values.
#[must_use]
pub fn new() -> Self {
Self {
xhtml: false,
soft_break: "\n".to_string(),
hard_break: "<br>\n".to_string(),
highlight: false,
sanitize: false,
convert_md_links: false,
base_url: "/".to_string(),
source_path: String::new(),
code_annotations: false,
code_annotation_meta_key: "annotate".to_string(),
code_annotation_syntax: CodeAnnotationSyntax::Attribute,
code_annotation_default_line_numbers: false,
toc_max_depth: 3,
autolink_urls: false,
autolink_patterns: Vec::from([String::from("http://"), String::from("https://")]),
autolink_target_blank: true,
}
}
}
impl Default for HtmlRendererOptions {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CodeAnnotationSyntax {
/// Read `annotate="kind:line"` style metadata from the code-fence info string.
///
/// This is the stable ox-content syntax and is useful when authored Markdown should
/// stay independent from a particular documentation theme.
Attribute,
/// Read VitePress-compatible fence metadata and inline `// [!code ...]` directives.
///
/// Use this when importing or sharing Markdown with VitePress projects that already
/// use `{1,3}`, `[title]`, `:line-numbers`, or inline diff/focus annotations.
VitePress,
/// Accept both ox-content attributes and VitePress-compatible directives.
///
/// Attribute annotations are applied first, then VitePress metadata can add titles,
/// line numbers, and inline directives without replacing existing classes.
Both,
}
impl CodeAnnotationSyntax {
pub(super) fn includes_attribute(self) -> bool {
matches!(self, Self::Attribute | Self::Both)
}
pub(super) fn includes_vitepress(self) -> bool {
matches!(self, Self::VitePress | Self::Both)
}
}