Skip to content

Commit 93c2902

Browse files
committed
feat: also expose permalink metadata field to the current page metadata context instead of exposing it only for the posts context.
1 parent e19cf94 commit 93c2902

File tree

3 files changed

+56
-41
lines changed

3 files changed

+56
-41
lines changed

src/cmd/build.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,10 @@ async fn process_build_entry(
176176
.await
177177
.wrap_err_with(|| format!("{}: {:?}", "Failed to read HTML file".bold(), path))?;
178178
let meta_path = path.with_extension("meta.toml");
179+
let meta_rel_path = meta_path.strip_prefix(&paths.build)?.to_path_buf();
179180

180181
// Handle metadata loading with proper error fallback
181-
let metadata = shared::load_metadata(meta_path).await;
182+
let metadata = shared::load_metadata(meta_path, meta_rel_path, &site_config.root_url).await;
182183

183184
// Metadata schema validation
184185
if let Some(schema) = &site_config.content_schema {

src/cmd/serve.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::{config, fs, shared};
3434
/// to organize and manage the file structure of the site.
3535
#[derive(Debug)]
3636
struct SitePaths {
37+
build: PathBuf,
3738
content: PathBuf,
3839
assets: PathBuf,
3940
templates: PathBuf,
@@ -57,6 +58,7 @@ impl SitePaths {
5758
fn new(root: PathBuf) -> Self {
5859
debug!("Initializing site paths");
5960
let paths = Self {
61+
build: root.join(".build"),
6062
content: root.join("content"),
6163
assets: root.join("assets"),
6264
theme_assets: root.join("theme/assets"),
@@ -369,10 +371,9 @@ async fn execute_actions(actions: FileActions, state: Arc<ServerState>) {
369371

370372
// Validate metadata if schema exists
371373
if let Some(schema) = &state.config.content_schema {
372-
let build_dir = state.paths.content.parent().unwrap().join(".build");
373374
let validation_warnings = shared::validate_content_metadata(
374375
&path,
375-
&build_dir,
376+
&state.paths.build,
376377
&state.paths.content,
377378
schema,
378379
true,
@@ -396,8 +397,7 @@ async fn execute_actions(actions: FileActions, state: Arc<ServerState>) {
396397

397398
// Re-collect pages metadata on content changes
398399
if !actions.rebuild_paths.is_empty() || !actions.cleanup_paths.is_empty() {
399-
let build_dir = state.paths.content.parent().unwrap().join(".build");
400-
match shared::collect_all_posts_metadata(&build_dir, &state.routes_url).await {
400+
match shared::collect_all_posts_metadata(&state.paths.build, &state.routes_url).await {
401401
Ok(new_posts) => {
402402
let mut posts_lock = state.posts.write().await;
403403
*posts_lock = new_posts;
@@ -734,7 +734,8 @@ async fn handle_html_content(
734734
) -> Result<Response<Body>> {
735735
debug!(path = %path.display(), "Rendering HTML content");
736736
let meta_path = path.with_extension("meta.toml");
737-
let metadata = shared::load_metadata(meta_path).await;
737+
let rel_path = meta_path.strip_prefix(".build")?.to_path_buf();
738+
let metadata = shared::load_metadata(meta_path, rel_path, &state.routes_url).await;
738739
let layout = metadata
739740
.get("layout")
740741
.and_then(|v| v.as_str())
@@ -753,7 +754,10 @@ async fn handle_html_content(
753754
.map_err(|e| eyre!("Template error: {}", e))?;
754755
// Always use the proper URL to the development server for template links that refers
755756
// to the local URL, this is useful when running the server exposed to LAN network
756-
body = body.replace(&state.config.root_url.replace("://", ":&#x2F;&#x2F;"), &state.routes_url);
757+
body = body.replace(
758+
&state.config.root_url.replace("://", ":&#x2F;&#x2F;"),
759+
&state.routes_url,
760+
);
757761

758762
inject_livereload_script(&mut body);
759763
Ok(Response::builder()
@@ -921,8 +925,7 @@ async fn setup_server_state(
921925

922926
let (reload_tx, _) = broadcast::channel(16);
923927

924-
let build_dir = root_dir.join(".build");
925-
let posts = shared::collect_all_posts_metadata(&build_dir, &routes_url).await?;
928+
let posts = shared::collect_all_posts_metadata(&paths.build, &routes_url).await?;
926929

927930
Ok(Arc::new(ServerState {
928931
reload_tx: Arc::new(reload_tx),

src/shared/mod.rs

+43-32
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,12 @@ pub async fn init_tera(templates_dir: &str, theme_templates_dir: &Path) -> Resul
227227
///
228228
/// # Arguments
229229
/// * `path` - The path to the metadata file.
230+
/// * `rel_path` - Relative path to the metadata file without the build directory prefix.
231+
/// * `routes_url` - The URL used for routing.
230232
///
231233
/// # Returns
232234
/// * `toml::Value` - The parsed metadata or an empty table if an error occurs.
233-
pub async fn load_metadata(path: PathBuf) -> toml::Value {
235+
pub async fn load_metadata(path: PathBuf, rel_path: PathBuf, routes_url: &str) -> toml::Value {
234236
match tokio::fs::read_to_string(&path).await {
235237
Ok(content) => {
236238
let mut value = toml::from_str(&content).unwrap_or_else(|e| {
@@ -247,6 +249,37 @@ pub async fn load_metadata(path: PathBuf) -> toml::Value {
247249
}
248250
}
249251

252+
// Generate permalink from file structure
253+
// Remove .meta.toml
254+
let mut permalink_path = rel_path.with_extension("").with_extension("");
255+
256+
// Handle index pages
257+
if let Some(file_name) = permalink_path.file_name() {
258+
if file_name == "index" {
259+
permalink_path = permalink_path
260+
.parent()
261+
.unwrap_or_else(|| Path::new(""))
262+
.to_path_buf();
263+
}
264+
}
265+
266+
// Convert to URL path
267+
let permalink_str = permalink_path
268+
.to_string_lossy()
269+
.trim_start_matches('/')
270+
.to_string();
271+
272+
let permalink = if permalink_str.is_empty() {
273+
format!("{}/", routes_url)
274+
} else {
275+
format!("{}/{}/", routes_url, permalink_str)
276+
};
277+
278+
// Add permalink and html content to metadata
279+
if let toml::Value::Table(ref mut table) = value {
280+
table.insert("permalink".to_string(), toml::Value::String(permalink));
281+
}
282+
250283
value
251284
}
252285
Err(e) => {
@@ -280,7 +313,12 @@ pub async fn validate_content_metadata(
280313
let relative_path = path.strip_prefix(content_dir).unwrap();
281314
let meta_path = build_dir.join(relative_path).with_extension("meta.toml");
282315

283-
let metadata = load_metadata(meta_path).await;
316+
let rel_path = meta_path
317+
.clone()
318+
.strip_prefix(build_dir)
319+
.map(|p| p.to_path_buf())?;
320+
// We do not need to do anything with the metadata permalink here so we pass an empty string to it
321+
let metadata = load_metadata(meta_path, rel_path, "").await;
284322
let metadata_map = metadata
285323
.as_table()
286324
.unwrap()
@@ -325,43 +363,16 @@ pub async fn collect_all_posts_metadata(
325363
})
326364
{
327365
let meta_path = entry.path();
328-
let mut metadata = load_metadata(entry.path().to_path_buf()).await;
366+
let rel_path = meta_path.strip_prefix(build_dir)?.to_path_buf();
367+
let mut metadata = load_metadata(entry.path().to_path_buf(), rel_path, routes_url).await;
329368

330369
// TODO: this won't hot reload if the content changes, should be passed as an argument instead
331370
// Get the raw html content
332371
let html_file = entry.path().with_extension("").with_extension("html");
333372
let html = tokio::fs::read_to_string(&html_file).await?;
334373

335-
// Generate permalink from file structure
336-
let rel_path = meta_path.strip_prefix(build_dir)?;
337-
// Remove .meta.toml
338-
let mut permalink_path = rel_path.with_extension("").with_extension("");
339-
340-
// Handle index pages
341-
if let Some(file_name) = permalink_path.file_name() {
342-
if file_name == "index" {
343-
permalink_path = permalink_path
344-
.parent()
345-
.unwrap_or_else(|| Path::new(""))
346-
.to_path_buf();
347-
}
348-
}
349-
350-
// Convert to URL path
351-
let permalink_str = permalink_path
352-
.to_string_lossy()
353-
.trim_start_matches('/')
354-
.to_string();
355-
356-
let permalink = if permalink_str.is_empty() {
357-
format!("{}/", routes_url)
358-
} else {
359-
format!("{}/{}/", routes_url, permalink_str)
360-
};
361-
362-
// Add permalink and html content to metadata
374+
// Add html content to metadata
363375
if let toml::Value::Table(ref mut table) = metadata {
364-
table.insert("permalink".to_string(), toml::Value::String(permalink));
365376
table.insert("raw".to_string(), toml::Value::String(html));
366377
}
367378
posts.push(metadata);

0 commit comments

Comments
 (0)