feat(renderer): add no-header-link option

Add no-header-link option. If set to true, the renderer will not render header links. Defaults to false.
This commit is contained in:
command_block 2024-01-01 05:11:54 +08:00
parent 090eba0db5
commit 436c4e5d7f
2 changed files with 30 additions and 10 deletions

View File

@ -550,6 +550,8 @@ pub struct HtmlConfig {
pub print: Print, pub print: Print,
/// Don't render section labels. /// Don't render section labels.
pub no_section_label: bool, pub no_section_label: bool,
/// Don't render header links.
pub no_header_link: bool,
/// Search settings. If `None`, the default will be used. /// Search settings. If `None`, the default will be used.
pub search: Option<Search>, pub search: Option<Search>,
/// Git repository url. If `None`, the git button will not be shown. /// Git repository url. If `None`, the git button will not be shown.
@ -601,6 +603,7 @@ impl Default for HtmlConfig {
code: Code::default(), code: Code::default(),
print: Print::default(), print: Print::default(),
no_section_label: false, no_section_label: false,
no_header_link: false,
search: None, search: None,
git_repository_url: None, git_repository_url: None,
git_repository_icon: None, git_repository_icon: None,

View File

@ -113,6 +113,7 @@ impl HtmlHandlebars {
rendered, rendered,
&ctx.html_config.playground, &ctx.html_config.playground,
&ctx.html_config.code, &ctx.html_config.code,
&ctx.html_config.no_header_link,
ctx.edition, ctx.edition,
); );
@ -129,6 +130,7 @@ impl HtmlHandlebars {
rendered_index, rendered_index,
&ctx.html_config.playground, &ctx.html_config.playground,
&ctx.html_config.code, &ctx.html_config.code,
&ctx.html_config.no_header_link,
ctx.edition, ctx.edition,
); );
debug!("Creating index.html from {}", ctx_path); debug!("Creating index.html from {}", ctx_path);
@ -194,6 +196,7 @@ impl HtmlHandlebars {
rendered, rendered,
&html_config.playground, &html_config.playground,
&html_config.code, &html_config.code,
&html_config.no_header_link,
ctx.config.rust.edition, ctx.config.rust.edition,
); );
let output_file = get_404_output_file(&html_config.input_404); let output_file = get_404_output_file(&html_config.input_404);
@ -208,9 +211,10 @@ impl HtmlHandlebars {
rendered: String, rendered: String,
playground_config: &Playground, playground_config: &Playground,
code_config: &Code, code_config: &Code,
no_header_link: &bool,
edition: Option<RustEdition>, edition: Option<RustEdition>,
) -> String { ) -> String {
let rendered = build_header_links(&rendered); let rendered = build_header_links(&rendered, no_header_link);
let rendered = fix_code_blocks(&rendered); let rendered = fix_code_blocks(&rendered);
let rendered = add_playground_pre(&rendered, playground_config, edition); let rendered = add_playground_pre(&rendered, playground_config, edition);
let rendered = hide_lines(&rendered, code_config); let rendered = hide_lines(&rendered, code_config);
@ -572,6 +576,7 @@ impl Renderer for HtmlHandlebars {
rendered, rendered,
&html_config.playground, &html_config.playground,
&html_config.code, &html_config.code,
&html_config.no_header_link,
ctx.config.rust.edition, ctx.config.rust.edition,
); );
@ -781,7 +786,7 @@ fn make_data(
/// Goes through the rendered HTML, making sure all header tags have /// Goes through the rendered HTML, making sure all header tags have
/// an anchor respectively so people can link to sections directly. /// an anchor respectively so people can link to sections directly.
fn build_header_links(html: &str) -> String { fn build_header_links(html: &str, no_header_link: &bool) -> String {
static BUILD_HEADER_LINKS: Lazy<Regex> = Lazy::new(|| { static BUILD_HEADER_LINKS: Lazy<Regex> = Lazy::new(|| {
Regex::new(r#"<h(\d)(?: id="([^"]+)")?(?: class="([^"]+)")?>(.*?)</h\d>"#).unwrap() Regex::new(r#"<h(\d)(?: id="([^"]+)")?(?: class="([^"]+)")?>(.*?)</h\d>"#).unwrap()
}); });
@ -810,6 +815,7 @@ fn build_header_links(html: &str) -> String {
caps.get(2).map(|x| x.as_str().to_string()), caps.get(2).map(|x| x.as_str().to_string()),
caps.get(3).map(|x| x.as_str().to_string()), caps.get(3).map(|x| x.as_str().to_string()),
&mut id_counter, &mut id_counter,
&no_header_link,
) )
}) })
.into_owned() .into_owned()
@ -823,12 +829,22 @@ fn insert_link_into_header(
id: Option<String>, id: Option<String>,
classes: Option<String>, classes: Option<String>,
id_counter: &mut HashMap<String, usize>, id_counter: &mut HashMap<String, usize>,
no_header_link: &bool,
) -> String { ) -> String {
let id = id.unwrap_or_else(|| utils::unique_id_from_content(content, id_counter)); let id = id.unwrap_or_else(|| utils::unique_id_from_content(content, id_counter));
let classes = classes let classes = classes
.map(|s| format!(" class=\"{s}\"")) .map(|s| format!(" class=\"{s}\""))
.unwrap_or_default(); .unwrap_or_default();
if *no_header_link {
format!(
r##"<h{level} id="{id}"{classes}>{text}</h{level}>"##,
level = level,
id = id,
text = content,
classes = classes
)
} else {
format!( format!(
r##"<h{level} id="{id}"{classes}><a class="header" href="#{id}">{text}</a></h{level}>"##, r##"<h{level} id="{id}"{classes}><a class="header" href="#{id}">{text}</a></h{level}>"##,
level = level, level = level,
@ -836,6 +852,7 @@ fn insert_link_into_header(
text = content, text = content,
classes = classes classes = classes
) )
}
} }
// The rust book uses annotations for rustdoc to test code snippets, // The rust book uses annotations for rustdoc to test code snippets,
@ -1112,7 +1129,7 @@ mod tests {
]; ];
for (src, should_be) in inputs { for (src, should_be) in inputs {
let got = build_header_links(src); let got = build_header_links(src, &HtmlConfig::default().no_header_link);
assert_eq!(got, should_be); assert_eq!(got, should_be);
} }
} }