diff --git a/src/markdown.rs b/src/markdown.rs
index b4d500d..3bc93d5 100644
--- a/src/markdown.rs
+++ b/src/markdown.rs
@@ -3,9 +3,9 @@ use std::collections::HashSet;
pub fn render_markdown(input: &str) -> String {
let html = tetratto_shared::markdown::render_markdown_dirty(&parse_page(&parse_details(
&parse_text_color(&parse_highlight(&parse_link(&parse_image(
- &parse_image_size(&parse_underline(&parse_comment(
+ &parse_image_size(&parse_toc(&parse_underline(&parse_comment(
&input.replace("[/]", "
"),
- ))),
+ )))),
)))),
)))
.replace("$per", "%");
@@ -883,3 +883,88 @@ pub fn parse_details(input: &str) -> String {
output
}
+
+/// Get the list of headers needed for [`parse_toc`].
+pub fn get_toc_list(input: &str) -> (String, String) {
+ let mut output = String::new();
+ let mut toc = String::new();
+ let mut in_pre = false;
+
+ for line in input.split("\n") {
+ if line.starts_with("```") {
+ in_pre = !in_pre;
+ output.push_str(&format!("{line}\n"));
+ continue;
+ }
+
+ if in_pre {
+ output.push_str(&format!("{line}\n"));
+ continue;
+ }
+
+ // not in pre
+ if line.starts_with("#") {
+ // get heading count
+ let mut hc = 0;
+
+ for x in line.chars() {
+ if x != '#' {
+ break;
+ }
+
+ hc += 1;
+ }
+
+ // add heading with id
+ let x = line.replacen(&"#".repeat(hc), "", 1);
+ let htext = x.trim();
+
+ let id = htext.to_lowercase().replace(" ", "_");
+ output.push_str(&format!("{htext}\n"));
+
+ // add heading to toc
+ toc += &format!("{}- [{htext}](#{id})\n", " ".repeat(hc));
+
+ // ...
+ continue;
+ }
+
+ // otherwise
+ output.push_str(&format!("{line}\n"));
+ }
+
+ (toc, output)
+}
+
+/// Parse the `[toc]` table-of-contents syntax.
+pub fn parse_toc(input: &str) -> String {
+ let (toc_list, new_input) = get_toc_list(input);
+
+ let mut output = String::new();
+ let mut in_pre = false;
+
+ for line in new_input.split("\n") {
+ if line.starts_with("```") {
+ in_pre = !in_pre;
+ output.push_str(&format!("{line}\n"));
+ continue;
+ }
+
+ if in_pre {
+ output.push_str(&format!("{line}\n"));
+ continue;
+ }
+
+ // not in pre
+ if line.len() == 5 && line.to_lowercase() == "[toc]" {
+ // add toc
+ output.push_str(&toc_list);
+ continue;
+ }
+
+ // otherwise
+ output.push_str(&format!("{line}\n"));
+ }
+
+ output
+}