folders work

This commit is contained in:
2025-06-25 14:56:54 +02:00
parent fbc41654e0
commit b0b6625810
2 changed files with 65 additions and 29 deletions

View File

@@ -15,4 +15,5 @@ notify = "6.1"
syntect = { version = "5.1", features = ["default"] }
regex = "1.10"
clap = { version = "4.4", features = ["derive"] }
serde_json = "1.0"
serde_json = "1.0"
html-escape = "0.2.13"

View File

@@ -4,7 +4,7 @@ use std::fs;
use std::path::{Path, PathBuf};
use chrono::{DateTime, Utc};
use serde::Deserialize;
use pulldown_cmark::{Parser, Options, html};
use pulldown_cmark::{Parser, Options, html, Event, Tag, CowStr};
use gray_matter::engine::YAML;
use gray_matter::Matter;
use ammonia::clean;
@@ -77,29 +77,6 @@ fn process_anchor_links(content: &str) -> String {
}).to_string()
}
fn highlight_code_blocks(html: &str) -> String {
let ss = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
let theme = &ts.themes["base16-ocean.dark"];
// Simple code block detection and highlighting
// In a real implementation, you'd want to parse the HTML and handle code blocks properly
let re = regex::Regex::new(r#"<pre><code class="language-([^"]+)">([^<]+)</code></pre>"#).unwrap();
re.replace_all(html, |caps: &regex::Captures| {
let lang = &caps[1];
let code = &caps[2];
if let Some(syntax) = ss.find_syntax_by_token(lang) {
match highlighted_html_for_string(code, &ss, syntax, theme) {
Ok(highlighted) => highlighted,
Err(_) => caps[0].to_string(),
}
} else {
caps[0].to_string()
}
}).to_string()
}
pub fn get_post_by_slug(slug: &str) -> Result<Post, Box<dyn std::error::Error>> {
let posts_dir = get_posts_directory();
let file_path = posts_dir.join(format!("{}.md", slug));
@@ -124,12 +101,70 @@ pub fn get_post_by_slug(slug: &str) -> Result<Post, Box<dyn std::error::Error>>
let created_at = get_file_creation_date(&file_path)?;
let processed_markdown = process_anchor_links(&result.content);
let mut html_output = String::new();
let parser = Parser::new_ext(&processed_markdown, Options::all());
html::push_html(&mut html_output, parser);
let mut html_output = String::new();
let mut heading_text = String::new();
let mut in_heading = false;
let mut heading_level = 0;
let mut in_code_block = false;
let mut code_block_lang = String::new();
let mut code_block_content = String::new();
let mut events = Vec::new();
let ss = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
let theme = &ts.themes["base16-ocean.dark"];
for event in parser {
match &event {
Event::Start(Tag::Heading(level, _, _)) => {
in_heading = true;
heading_level = *level as usize;
heading_text.clear();
},
Event::End(Tag::Heading(_, _, _)) => {
in_heading = false;
let id = slugify(&heading_text);
events.push(Event::Html(CowStr::Boxed(format!("<h{lvl} id=\"{id}\">", lvl=heading_level, id=id).into_boxed_str())));
events.push(Event::Text(CowStr::Boxed(heading_text.clone().into_boxed_str())));
events.push(Event::Html(CowStr::Boxed(format!("</h{lvl}>", lvl=heading_level).into_boxed_str())));
},
Event::Text(text) if in_heading => {
heading_text.push_str(text);
},
Event::Start(Tag::CodeBlock(kind)) => {
in_code_block = true;
code_block_content.clear();
code_block_lang = match kind {
pulldown_cmark::CodeBlockKind::Fenced(lang) => lang.to_string(),
pulldown_cmark::CodeBlockKind::Indented => String::new(),
};
},
Event::End(Tag::CodeBlock(_)) => {
in_code_block = false;
// Highlight code block
let highlighted = if !code_block_lang.is_empty() {
if let Some(syntax) = ss.find_syntax_by_token(&code_block_lang) {
highlighted_html_for_string(&code_block_content, &ss, syntax, theme).unwrap_or_else(|_| format!("<pre><code>{}</code></pre>", html_escape::encode_text(&code_block_content)))
} else {
format!("<pre><code>{}</code></pre>", html_escape::encode_text(&code_block_content))
}
} else {
// No language specified
format!("<pre><code>{}</code></pre>", html_escape::encode_text(&code_block_content))
};
events.push(Event::Html(CowStr::Boxed(highlighted.into_boxed_str())));
},
Event::Text(text) if in_code_block => {
code_block_content.push_str(text);
},
_ if !in_heading && !in_code_block => {
events.push(event);
},
_ => {},
}
}
html::push_html(&mut html_output, events.into_iter());
let highlighted_html = highlight_code_blocks(&html_output);
let sanitized_html = clean(&highlighted_html);
let sanitized_html = clean(&html_output);
Ok(Post {
slug: slug.to_string(),