Commit Diff


commit - 8fdcd6d1ef8eb3670e5a29dc8d51fac32fd4546b
commit + 080678415d1f58a00080317e612af2dd2f6135e9
blob - e296698df90a959cf47d867a845648b0cc66077c
blob + 44f92662798219638306d3b6f1c7905418f338a9
--- kssg.rs
+++ kssg.rs
@@ -555,8 +555,9 @@ fn build() {
             String::new()
         };
 
-        let html = if posts[i].meta.toc {
-            add_heading_ids(&posts[i].html_content)
+        let is_post = posts[i].out_path.starts_with("public/posts");
+        let html = if is_post || posts[i].meta.toc {
+            add_heading_ids(&posts[i].html_content, is_post)
         } else {
             posts[i].html_content.clone()
         };
@@ -864,23 +865,23 @@ fn generate_toc(html: &str) -> String {
     toc
 }
 
-fn add_heading_ids(html: &str) -> String {
+fn add_heading_ids(html: &str, linkify: bool) -> String {
     let mut result = String::with_capacity(html.len());
     let mut pos = 0;
     while pos < html.len() {
-        let h2 = html[pos..].find("<h2>");
-        let h3 = html[pos..].find("<h3>");
-        let (level, start) = match (h2, h3) {
-            (Some(a), Some(b)) => {
-                if a <= b {
-                    (2, pos + a)
-                } else {
-                    (3, pos + b)
+        let mut best: Option<(u8, usize)> = None;
+        for level in 2u8..=6 {
+            let tag = format!("<h{}>", level);
+            if let Some(i) = html[pos..].find(&tag) {
+                let abs = pos + i;
+                if best.map(|(_, p)| abs < p).unwrap_or(true) {
+                    best = Some((level, abs));
                 }
             }
-            (Some(a), None) => (2, pos + a),
-            (None, Some(b)) => (3, pos + b),
-            (None, None) => break,
+        }
+        let (level, start) = match best {
+            Some(v) => v,
+            None => break,
         };
         let tag_end = start + 4; // len of "<hN>"
         let close = format!("</h{}>", level);
@@ -891,13 +892,19 @@ fn add_heading_ids(html: &str) -> String {
                 continue;
             }
         };
-        let text = html[tag_end..end]
-            .replace("<code>", "")
-            .replace("</code>", "");
+        let inner = &html[tag_end..end];
+        let text = inner.replace("<code>", "").replace("</code>", "");
         let id = slugify(&text);
         result.push_str(&html[pos..start]);
-        result.push_str(&format!("<h{} id=\"{}\">", level, id));
-        result.push_str(&html[tag_end..end + close.len()]);
+        if linkify {
+            result.push_str(&format!(
+                "<h{} id=\"{}\"><a href=\"#{}\">{}</a></h{}>",
+                level, id, id, inner, level,
+            ));
+        } else {
+            result.push_str(&format!("<h{} id=\"{}\">", level, id));
+            result.push_str(&html[tag_end..end + close.len()]);
+        }
         pos = end + close.len();
     }
     result.push_str(&html[pos..]);