From bcca7955ff7debeca01f2ede41c0199508445ad7 Mon Sep 17 00:00:00 2001 From: Alex Chen Date: Thu, 16 Jul 2026 10:31:01 +0000 Subject: [PATCH] fix(links): support spaces in #include file paths Parse the full include/rustdoc_include target instead of splitting on whitespace, so paths like `fila a.md` work. Line ranges still work (`fila a.md:1:2`). Playground links keep whitespace-separated properties. Fixes #2812. Signed-off-by: Alex Chen --- .../src/builtin_preprocessors/links.rs | 65 ++++++++++++++++++- tests/testsuite/includes.rs | 3 + .../includes/all_includes/src/fila a.md | 3 + .../includes/all_includes/src/includes.md | 4 ++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tests/testsuite/includes/all_includes/src/fila a.md diff --git a/crates/mdbook-driver/src/builtin_preprocessors/links.rs b/crates/mdbook-driver/src/builtin_preprocessors/links.rs index e369086fb4..581146346e 100644 --- a/crates/mdbook-driver/src/builtin_preprocessors/links.rs +++ b/crates/mdbook-driver/src/builtin_preprocessors/links.rs @@ -285,13 +285,21 @@ impl<'a> Link<'a> { (_, Some(typ), Some(title)) if typ.as_str() == "title" => { Some(LinkType::Title(title.as_str())) } + // Include directives take the full remaining capture as the path so + // file names may contain spaces. Playground still splits on whitespace + // because it accepts trailing properties after the path. + (_, Some(typ), Some(rest)) if typ.as_str() == "include" => { + Some(parse_include_path(rest.as_str().trim())) + } + (_, Some(typ), Some(rest)) if typ.as_str() == "rustdoc_include" => { + Some(parse_rustdoc_include_path(rest.as_str().trim())) + } (_, Some(typ), Some(rest)) => { let mut path_props = rest.as_str().split_whitespace(); let file_arg = path_props.next(); let props: Vec<&str> = path_props.collect(); match (typ.as_str(), file_arg) { - ("include", Some(pth)) => Some(parse_include_path(pth)), ("playground", Some(pth)) => Some(LinkType::Playground(pth.into(), props)), ("playpen", Some(pth)) => { warn!( @@ -301,7 +309,6 @@ impl<'a> Link<'a> { ); Some(LinkType::Playground(pth.into(), props)) } - ("rustdoc_include", Some(pth)) => Some(parse_rustdoc_include_path(pth)), _ => None, } } @@ -644,6 +651,60 @@ mod tests { ); } + #[test] + fn test_find_links_with_space_in_path() { + let s = "Some random text with {{#include fila a.md}}..."; + let res = find_links(s).collect::>(); + assert_eq!( + res, + vec![Link { + start_index: 22, + end_index: 44, + link_type: LinkType::Include( + PathBuf::from("fila a.md"), + RangeOrAnchor::Range(LineRange::from(..)), + ), + link_text: "{{#include fila a.md}}", + }] + ); + } + + #[test] + fn test_find_links_with_space_in_path_and_range() { + let s = "Some random text with {{#include fila a.md:1:2}}..."; + let res = find_links(s).collect::>(); + assert_eq!( + res, + vec![Link { + start_index: 22, + end_index: 48, + link_type: LinkType::Include( + PathBuf::from("fila a.md"), + RangeOrAnchor::Range(LineRange::from(0..2)), + ), + link_text: "{{#include fila a.md:1:2}}", + }] + ); + } + + #[test] + fn test_find_links_rustdoc_include_with_space_in_path() { + let s = "Some random text with {{#rustdoc_include fila a.rs}}..."; + let res = find_links(s).collect::>(); + assert_eq!( + res, + vec![Link { + start_index: 22, + end_index: 52, + link_type: LinkType::RustdocInclude( + PathBuf::from("fila a.rs"), + RangeOrAnchor::Range(LineRange::from(..)), + ), + link_text: "{{#rustdoc_include fila a.rs}}", + }] + ); + } + #[test] fn test_find_links_with_anchor() { let s = "Some random text with {{#include file.rs:anchor}}..."; diff --git a/tests/testsuite/includes.rs b/tests/testsuite/includes.rs index 42d71ddcbe..671c656e95 100644 --- a/tests/testsuite/includes.rs +++ b/tests/testsuite/includes.rs @@ -12,6 +12,9 @@ fn include() {

Basic Includes

Sample

This is a sample include.

+

File with space in name

+

File With Space

+

This file name contains a space.

"##]], ) .check_main_file( diff --git a/tests/testsuite/includes/all_includes/src/fila a.md b/tests/testsuite/includes/all_includes/src/fila a.md new file mode 100644 index 0000000000..5bcc2e576d --- /dev/null +++ b/tests/testsuite/includes/all_includes/src/fila a.md @@ -0,0 +1,3 @@ +# File With Space + +This file name contains a space. diff --git a/tests/testsuite/includes/all_includes/src/includes.md b/tests/testsuite/includes/all_includes/src/includes.md index 539aa93907..08c9bfcda9 100644 --- a/tests/testsuite/includes/all_includes/src/includes.md +++ b/tests/testsuite/includes/all_includes/src/includes.md @@ -2,3 +2,7 @@ {{#include sample.md}} +## File with space in name + +{{#include fila a.md}} +