diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/generate_html.rs | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/src/generate_html.rs b/src/generate_html.rs index c0026fb..e531854 100644 --- a/src/generate_html.rs +++ b/src/generate_html.rs @@ -6,8 +6,8 @@ use recipe::*; pub fn generate_html(document: &MarkdownDocument, page: &Page, website: &Website) -> String { let root = page.root(); - let page_name = sanitize_text(&page.name); - let site_name = sanitize_text(&website.name); + let page_name = sanitize_text(&page.name, true); + let site_name = sanitize_text(&website.name, true); let mut parent_url = String::new(); for segment in &page.parents { parent_url.push_str(&make_url_safe(segment)); parent_url.push('/'); @@ -51,7 +51,7 @@ pub fn generate_html(document: &MarkdownDocument, page: &Page, website: &Website pub fn generate_html_redirect(path: &str) -> String { - let path = sanitize_text(path); + let path = sanitize_text(path, false); format!("\ <!DOCTYPE html> <head> @@ -75,7 +75,7 @@ pub fn get_table_of_contents(page: &Page) -> String { return String::new(); } let mut toc = String::from("<details><summary></summary><ul>\n"); - let site_name = sanitize_text(&page.name); + let site_name = sanitize_text(&page.name, true); toc.push_str(&format!("<li class='l1'><a href='#title'>{site_name}</a></li>\n")); for heading in &page.headings { @@ -117,7 +117,7 @@ pub fn document_to_html(document: &MarkdownDocument, page: &Page, website: &Webs Level::Heading3 => tag!("h3", line, format!("id='{}'", make_url_safe(&line_to_html!(line)))), } Block::Paragraph(line) => tag!("p", line), - Block::Math(content) => html!("<div class='math'>{content}</div>"), + Block::Math(content) => html!("<div class='math'>{}</div>", sanitize_text(content, false)), Block::List(lines) => wrap!("ul", for line in lines { // Insert a <br> tag directly after the first untagged colon. let mut depth = 0; @@ -169,7 +169,7 @@ pub fn document_to_html(document: &MarkdownDocument, page: &Page, website: &Webs None => warn!("Page {from:?} embeds nonexistent static file {path:?}"), } } - let label = sanitize_text(label); + let label = sanitize_text(label, true); match extension.to_lowercase().as_str() { "jpg"|"jpeg"|"png"|"webp"|"gif"|"tiff" => html!( "<figure><a href='{path}'><img src='{path}' alt='{label}' title='{label}' /></a></figure>"), @@ -207,7 +207,7 @@ pub fn document_to_html(document: &MarkdownDocument, page: &Page, website: &Webs }), _ => { html!("<pre class='{}'>", language); - html!("{}", sanitize_text(content)); + html!("{}", sanitize_text(content, false)); html!("</pre>"); }, } @@ -258,15 +258,15 @@ fn line_to_html(line: &Line, page: &Page, website: &Website) -> String { for line_element in &line.tokens { match line_element { Token::Normal(text) => { - let text = &sanitize_text(text); html.push_str(text) } + let text = &sanitize_text(text, true); html.push_str(text) } Token::Bold(text) => { - let text = &sanitize_text(text); html.push_str(&format!("<b>{text}</b>")) } + let text = &sanitize_text(text, true); html.push_str(&format!("<b>{text}</b>")) } Token::Italic(text) => { - let text = &sanitize_text(text); html.push_str(&format!("<i>{text}</i>")) } + let text = &sanitize_text(text, true); html.push_str(&format!("<i>{text}</i>")) } Token::Monospace(text) => { - let text = &sanitize_text(text); html.push_str(&format!("<code>{text}</code>")) } + let text = &sanitize_text(text, false); html.push_str(&format!("<code>{text}</code>")) } Token::Math(text) => { - let text = &sanitize_text(text); html.push_str(&format!("<span class='math'>{text}</span>")) } + let text = &sanitize_text(text, false); html.push_str(&format!("<span class='math'>{text}</span>")) } Token::InternalLink(name) => { let (class, label, path) = match name.split_once('#') { Some(("", heading)) => ("heading", heading, format!("#{heading}")), @@ -275,8 +275,8 @@ fn line_to_html(line: &Line, page: &Page, website: &Website) -> String { }; let mut path = make_url_safe(&path); let label = match label.rsplit_once('/') { - Some((_, label)) => sanitize_text(label.trim()), - None => sanitize_text(label.trim()), + Some((_, label)) => sanitize_text(label.trim(), true), + None => sanitize_text(label.trim(), true), }; // Check that the linked internal page exists. if class == "page" { @@ -321,7 +321,7 @@ fn line_to_html(line: &Line, page: &Page, website: &Website) -> String { }; } } - let label = sanitize_text(&label); + let label = sanitize_text(&label, true); html.push_str(&format!("<a href='{path}' class='external'>{label}</a>")); } } @@ -331,8 +331,10 @@ fn line_to_html(line: &Line, page: &Page, website: &Website) -> String { + + /// Replace each HTML-reserved character with an HTML-escaped character. -fn sanitize_text(text: &str) -> String { +fn sanitize_text(text: &str, fancy: bool) -> String { let mut output = String::new(); let chars: Vec<char> = text.chars().collect(); for (i, c) in chars.iter().enumerate() { @@ -352,15 +354,15 @@ fn sanitize_text(text: &str) -> String { }, '<' => output.push_str("<"), '>' => output.push_str(">"), - '"' => match prev.is_whitespace() { + '"' if fancy => match prev.is_whitespace() { true => output.push('“'), false => output.push('”'), }, - '\'' => match prev.is_whitespace() { + '\'' if fancy => match prev.is_whitespace() { true => output.push('‘'), false => output.push('’'), }, - '-' => match prev.is_whitespace() && next.is_whitespace() { + '-' if fancy => match prev.is_whitespace() && next.is_whitespace() { true => output.push('—'), false => output.push('-'), } |