From b6106c52cef9ca2411bf11b13fa85214edddbd8e Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Mon, 2 Dec 2024 19:57:34 -0800 Subject: [PATCH] Load templates from relative paths Templates can now be placed directly next to the source file that they are defined in as a default. This relies on an unstable rust compiler feature, which exposes the source file to proc macros. See for more info. This requires the nightly compiler to run, and enabling the proc_macro_span and procmacro2_semver_exempt cfg flags. To build / test: ```shell RUSTFLAGS='--cfg proc_macro_span --cfg procmacro2_semver_exempt' \ cargo +nightly build ``` Fixes: --- askama/Cargo.toml | 6 ++++++ askama/tests/relative_paths.rs | 18 ++++++++++++++++++ askama/tests/relative_paths.txt | 1 + askama_derive/Cargo.toml | 6 ++++++ askama_derive/src/config.rs | 17 ++++++++++++++++- 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 askama/tests/relative_paths.rs create mode 100644 askama/tests/relative_paths.txt diff --git a/askama/Cargo.toml b/askama/Cargo.toml index 6c8fb258..d087ffa0 100644 --- a/askama/Cargo.toml +++ b/askama/Cargo.toml @@ -29,6 +29,12 @@ with-axum = ["askama_derive/with-axum"] with-rocket = ["askama_derive/with-rocket"] with-warp = ["askama_derive/with-warp"] +## Enables the ability to put templates in a directory relative to the source file that uses them. +## Requires a nightly compiler and adding: +## RUSTFLAGS='--cfg proc_macro_span --cfg procmacro2_semver_exempt' +## to your cargo build command. +relative-paths = ["askama_derive/relative-paths"] + [dependencies] askama_derive = { version = "0.13", path = "../askama_derive" } askama_escape = { version = "0.11", path = "../askama_escape" } diff --git a/askama/tests/relative_paths.rs b/askama/tests/relative_paths.rs new file mode 100644 index 00000000..4664cc2b --- /dev/null +++ b/askama/tests/relative_paths.rs @@ -0,0 +1,18 @@ +#[cfg(feature = "relative-paths")] +mod relative_paths { + use askama::Template; + + #[derive(Template)] + #[template(path = "relative_paths.txt")] + struct RelativePathTemplate { + name: String, + } + + #[test] + fn test_relative_paths() { + let t = RelativePathTemplate { + name: "world".to_string(), + }; + assert_eq!(t.render().unwrap(), "Hello, world!"); + } +} diff --git a/askama/tests/relative_paths.txt b/askama/tests/relative_paths.txt new file mode 100644 index 00000000..272c22e1 --- /dev/null +++ b/askama/tests/relative_paths.txt @@ -0,0 +1 @@ +Hello, {{ name }}! \ No newline at end of file diff --git a/askama_derive/Cargo.toml b/askama_derive/Cargo.toml index b1c3981f..9ffd82d7 100644 --- a/askama_derive/Cargo.toml +++ b/askama_derive/Cargo.toml @@ -24,6 +24,12 @@ with-axum = [] with-rocket = [] with-warp = [] +## Enables the ability to put templates in a directory relative to the source file that uses them. +## Requires a nightly compiler and adding: +## RUSTFLAGS='--cfg proc_macro_span --cfg procmacro2_semver_exempt' +## to your cargo build command. +relative-paths = [] + [dependencies] parser = { package = "askama_parser", version = "0.3.1", path = "../askama_parser" } mime = "0.3" diff --git a/askama_derive/src/config.rs b/askama_derive/src/config.rs index aac8123a..f792f823 100644 --- a/askama_derive/src/config.rs +++ b/askama_derive/src/config.rs @@ -26,7 +26,22 @@ impl<'a> Config<'a> { template_whitespace: Option<&str>, ) -> std::result::Result, CompileError> { let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let default_dirs = vec![root.join("templates")]; + let root_path = root.join("templates"); + let default_dirs; + #[cfg(feature = "relative-paths")] + { + let source = proc_macro2::Span::call_site().source_file(); + default_dirs = if source.is_real() { + let relative_path = source.path().parent().unwrap().to_path_buf(); + vec![relative_path, root_path] + } else { + vec![root_path] + }; + } + #[cfg(not(feature = "relative-paths"))] + { + default_dirs = vec![root_path]; + } let mut syntaxes = BTreeMap::new(); syntaxes.insert(DEFAULT_SYNTAX_NAME.to_string(), Syntax::default());