Update pages-data.json with new content and structure for cpp-httplib documentation

This commit is contained in:
yhirose
2026-03-02 17:22:52 -05:00
parent 2e124cde02
commit 74807d24a7
30 changed files with 1894 additions and 1814 deletions

View File

@@ -1,6 +1,7 @@
use crate::config::{NavLink, SiteConfig};
use crate::defaults;
use crate::markdown::{Frontmatter, MarkdownRenderer};
use crate::utils::copy_dir_recursive;
use anyhow::{Context, Result};
use serde::Serialize;
use std::fs;
@@ -55,7 +56,10 @@ struct Page {
pub fn build(src: &Path, out: &Path) -> Result<()> {
let config = SiteConfig::load(src)?;
let renderer = MarkdownRenderer::new(config.highlight_theme());
let renderer = MarkdownRenderer::new(
config.highlight_dark_theme(),
config.highlight_light_theme(),
);
// Build Tera: start with embedded defaults, then override with user templates
let tera = build_tera(src)?;
@@ -89,7 +93,7 @@ pub fn build(src: &Path, out: &Path) -> Result<()> {
for page in &pages {
// Collect search data for pages-data.json
let plain_body = strip_html_tags(&page.html_content);
let plain_body = strip_html_tags(&remove_light_theme_blocks(&page.html_content));
let truncated_body: String = plain_body.chars().take(500).collect();
page_data_entries.push(PageDataEntry {
title: page.frontmatter.title.clone(),
@@ -405,24 +409,6 @@ fn copy_default_static(out: &Path) -> Result<()> {
Ok(())
}
fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
for entry in WalkDir::new(src).into_iter().filter_map(|e| e.ok()) {
let path = entry.path();
let rel = path.strip_prefix(src)?;
let target = dst.join(rel);
if path.is_dir() {
fs::create_dir_all(&target)?;
} else {
if let Some(parent) = target.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(path, &target)?;
}
}
Ok(())
}
/// Strip HTML tags from a string and collapse whitespace into a single space,
/// producing a plain-text representation suitable for search indexing.
fn strip_html_tags(html: &str) -> String {
@@ -446,3 +432,37 @@ fn strip_html_tags(html: &str) -> String {
let collapsed: String = result.split_whitespace().collect::<Vec<_>>().join(" ");
collapsed
}
/// Remove `<div data-code-theme="light">...</div>` blocks so that
/// dual-theme code snippets are only indexed once.
fn remove_light_theme_blocks(html: &str) -> String {
const MARKER: &str = "<div data-code-theme=\"light\"";
let mut result = String::with_capacity(html.len());
let mut remaining = html;
while let Some(start) = remaining.find(MARKER) {
result.push_str(&remaining[..start]);
remaining = &remaining[start..];
let mut depth: usize = 0;
let mut i = 0;
while i < remaining.len() {
if remaining[i..].starts_with("<div") {
depth += 1;
i += 4;
} else if remaining[i..].starts_with("</div>") {
depth -= 1;
i += 6;
if depth == 0 {
break;
}
} else {
i += remaining[i..].chars().next().map_or(1, |c| c.len_utf8());
}
}
remaining = &remaining[i..];
}
result.push_str(remaining);
result
}

View File

@@ -59,7 +59,8 @@ impl I18n {
#[derive(Debug, Deserialize)]
pub struct Highlight {
pub theme: Option<String>,
pub dark_theme: Option<String>,
pub light_theme: Option<String>,
}
impl SiteConfig {
@@ -81,10 +82,16 @@ impl SiteConfig {
Ok(config)
}
pub fn highlight_theme(&self) -> &str {
pub fn highlight_dark_theme(&self) -> &str {
self.highlight
.as_ref()
.and_then(|h| h.theme.as_deref())
.and_then(|h| h.dark_theme.as_deref())
.unwrap_or("base16-ocean.dark")
}
pub fn highlight_light_theme(&self) -> Option<&str> {
self.highlight
.as_ref()
.and_then(|h| h.light_theme.as_deref())
}
}

View File

@@ -3,6 +3,7 @@ mod config;
mod defaults;
mod markdown;
mod serve;
mod utils;
use anyhow::Result;
use clap::{Parser, Subcommand, CommandFactory};

View File

@@ -16,15 +16,17 @@ pub struct Frontmatter {
pub struct MarkdownRenderer {
syntax_set: SyntaxSet,
theme_set: ThemeSet,
theme_name: String,
dark_theme: String,
light_theme: Option<String>,
}
impl MarkdownRenderer {
pub fn new(theme_name: &str) -> Self {
pub fn new(dark_theme: &str, light_theme: Option<&str>) -> Self {
Self {
syntax_set: SyntaxSet::load_defaults_newlines(),
theme_set: ThemeSet::load_defaults(),
theme_name: theme_name.to_string(),
dark_theme: dark_theme.to_string(),
light_theme: light_theme.map(|s| s.to_string()),
}
}
@@ -84,16 +86,31 @@ impl MarkdownRenderer {
}
fn highlight_code(&self, code: &str, lang: &str) -> String {
if lang.is_empty() {
return format!("<pre><code>{}</code></pre>", escape_html(code));
let syntax = if lang.is_empty() {
self.syntax_set.find_syntax_plain_text()
} else {
self.syntax_set
.find_syntax_by_token(lang)
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
};
let dark_html = self.highlight_with_theme(code, syntax, &self.dark_theme);
match &self.light_theme {
Some(light) => {
let light_html = self.highlight_with_theme(code, syntax, light);
format!(
concat!(
"<div class=\"code-block-wrapper\">",
"<div data-code-theme=\"dark\">{}</div>",
"<div data-code-theme=\"light\">{}</div>",
"</div>",
),
dark_html, light_html
)
}
None => dark_html,
}
let syntax = self
.syntax_set
.find_syntax_by_token(lang)
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
self.highlight_with_theme(code, syntax, &self.theme_name)
}
fn highlight_with_theme(

View File

@@ -1,5 +1,6 @@
use crate::builder;
use crate::config::SiteConfig;
use crate::utils::copy_dir_recursive;
use anyhow::{Context, Result};
use notify::{Event, RecursiveMode, Watcher};
use socket2::{Domain, Protocol, Socket, Type};
@@ -280,24 +281,6 @@ fn send_ws_text_frame(mut stream: &TcpStream, msg: &str) -> Result<()> {
Ok(())
}
fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
for entry in WalkDir::new(src).into_iter().filter_map(|e| e.ok()) {
let path = entry.path();
let rel = path.strip_prefix(src)?;
let target = dst.join(rel);
if path.is_dir() {
fs::create_dir_all(&target)?;
} else {
if let Some(parent) = target.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(path, &target)?;
}
}
Ok(())
}
fn guess_mime(path: &Path) -> String {
match path.extension().and_then(|e| e.to_str()) {
Some("html") => "text/html; charset=utf-8".to_string(),

22
docs-gen/src/utils.rs Normal file
View File

@@ -0,0 +1,22 @@
use anyhow::Result;
use std::fs;
use std::path::Path;
use walkdir::WalkDir;
pub fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
for entry in WalkDir::new(src).into_iter().filter_map(|e| e.ok()) {
let path = entry.path();
let rel = path.strip_prefix(src)?;
let target = dst.join(rel);
if path.is_dir() {
fs::create_dir_all(&target)?;
} else {
if let Some(parent) = target.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(path, &target)?;
}
}
Ok(())
}