Merge pull request #2839 from ehuss/to_url_path

Add ToUrlPath helper trait
This commit is contained in:
Eric Huss 2025-09-15 14:50:47 +00:00 committed by GitHub
commit 1daa650d61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 27 additions and 24 deletions

View file

@ -6,14 +6,6 @@ use std::io::Write;
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use tracing::{debug, trace}; use tracing::{debug, trace};
/// Naively replaces any path separator with a forward-slash '/'
pub fn normalize_path(path: &str) -> String {
use std::path::is_separator;
path.chars()
.map(|ch| if is_separator(ch) { '/' } else { ch })
.collect::<String>()
}
/// Write the given data to a file, creating it first if necessary /// Write the given data to a file, creating it first if necessary
pub fn write_file<P: AsRef<Path>>(build_dir: &Path, filename: P, content: &[u8]) -> Result<()> { pub fn write_file<P: AsRef<Path>>(build_dir: &Path, filename: P, content: &[u8]) -> Result<()> {
let path = build_dir.join(filename); let path = build_dir.join(filename);

View file

@ -1,6 +1,7 @@
use super::helpers; use super::helpers;
use super::static_files::StaticFiles; use super::static_files::StaticFiles;
use crate::theme::Theme; use crate::theme::Theme;
use crate::utils::ToUrlPath;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use handlebars::Handlebars; use handlebars::Handlebars;
use mdbook_core::book::{Book, BookItem, Chapter}; use mdbook_core::book::{Book, BookItem, Chapter};
@ -122,9 +123,7 @@ impl HtmlHandlebars {
.as_ref() .as_ref()
.unwrap() .unwrap()
.with_extension("html") .with_extension("html")
.to_str() .to_url_path();
.unwrap()
.replace('\\', "//");
let obj = json!( { let obj = json!( {
"title": ch.name, "title": ch.name,
"link": path, "link": path,
@ -1048,7 +1047,7 @@ fn collect_redirects_for_path(
path: &Path, path: &Path,
redirects: &HashMap<String, String>, redirects: &HashMap<String, String>,
) -> Result<BTreeMap<String, String>> { ) -> Result<BTreeMap<String, String>> {
let path = format!("/{}", path.display().to_string().replace('\\', "/")); let path = format!("/{}", path.to_url_path());
if redirects.contains_key(&path) { if redirects.contains_key(&path) {
bail!( bail!(
"redirect found for existing chapter at `{path}`\n\ "redirect found for existing chapter at `{path}`\n\

View file

@ -1,3 +1,4 @@
use crate::utils::ToUrlPath;
use std::path::Path; use std::path::Path;
use std::{cmp::Ordering, collections::BTreeMap}; use std::{cmp::Ordering, collections::BTreeMap};
@ -109,12 +110,7 @@ impl HelperDef for RenderToc {
let path_exists = match item.get("path") { let path_exists = match item.get("path") {
Some(path) if !path.is_empty() => { Some(path) if !path.is_empty() => {
out.write("<a href=\"")?; out.write("<a href=\"")?;
let tmp = Path::new(path) let tmp = Path::new(path).with_extension("html").to_url_path();
.with_extension("html")
.to_str()
.unwrap()
// Hack for windows who tends to use `\` as separator instead of `/`
.replace('\\', "/");
// Add link // Add link
out.write(&tmp)?; out.write(&tmp)?;

View file

@ -1,6 +1,7 @@
use super::static_files::StaticFiles; use super::static_files::StaticFiles;
use crate::theme::searcher; use crate::theme::searcher;
use anyhow::{Context, Result, bail}; use crate::utils::ToUrlPath;
use anyhow::{Result, bail};
use elasticlunr::{Index, IndexBuilder}; use elasticlunr::{Index, IndexBuilder};
use mdbook_core::book::{Book, Chapter}; use mdbook_core::book::{Book, Chapter};
use mdbook_core::config::{Search, SearchChapterSettings}; use mdbook_core::config::{Search, SearchChapterSettings};
@ -124,11 +125,9 @@ fn render_item(
.path .path
.as_ref() .as_ref()
.expect("Checked that path exists above"); .expect("Checked that path exists above");
let filepath = Path::new(&chapter_path).with_extension("html"); let anchor_base = Path::new(&chapter_path)
let filepath = filepath .with_extension("html")
.to_str() .to_url_path();
.with_context(|| "Could not convert HTML path to str")?;
let anchor_base = utils::fs::normalize_path(filepath);
let options = HtmlRenderOptions::new(&chapter_path); let options = HtmlRenderOptions::new(&chapter_path);
let mut p = new_cmark_parser(&chapter.content, &options.markdown_options).peekable(); let mut p = new_cmark_parser(&chapter.content, &options.markdown_options).peekable();

View file

@ -2,6 +2,7 @@
mod html_handlebars; mod html_handlebars;
pub mod theme; pub mod theme;
pub(crate) mod utils;
pub use html_handlebars::HtmlHandlebars; pub use html_handlebars::HtmlHandlebars;
use mdbook_core::config::HtmlConfig; use mdbook_core::config::HtmlConfig;

View file

@ -0,0 +1,16 @@
//! Utilities for processing HTML.
use std::path::Path;
/// Helper trait for converting a [`Path`] to a string suitable for an HTML path.
pub(crate) trait ToUrlPath {
fn to_url_path(&self) -> String;
}
impl ToUrlPath for Path {
fn to_url_path(&self) -> String {
// We're generally assuming that all paths we deal with are utf-8.
// The replace here is to handle Windows paths.
self.to_str().unwrap().replace('\\', "/")
}
}