Repository: rinja-rs/askama (language: rust)

Issue:
Remove the need to import askama itself when using integration crates
While wording on https://github.com/djc/askama/issues/961, I wandered off to find the cause for the need as the title goes. A rough scan reveals that askama_derive generates some uses of `::askama::`, for example, this:

https://github.com/djc/askama/blob/c2c9bd81708a0201aef49b83df89446e12a41817/askama_derive/src/generator.rs#L93-L96

… which leads to the need, as sub-dependencies can't be used directly. If they are removed, probably we can depend solely on integration crates?

A possible way to do this might be something like

```rust
#[inline]
fn _askama(tail: &str) -> String {
	format!("::{}::askama{tail}",
		#[cfg(feature = "with-actix-web")]
		"askama_actix",
		#[cfg(feature = "with-axum")]
		"askama_axum",
		// ...
	)
}

buf.write("fn render_into(&self, writer: &mut (impl ::std::fmt::Write + ?Sized)) -> ")?;
buf.writeln(&_askama("::Result<()> {"))?;
```

… which isn't pretty, but works.
Document how integration should be imported
The integration section of the "book" looks like this:

> ## {{TARGET}} integration
>
> Enabling the `with-{{target}}` feature appends an implementation of {{target}}'s {{corresponding_trait}} trait for each template type. This makes it easy to trivially return a value of that type in a {{target}} handler.

(repeat for each target)

However, a quick search shows that [you](https://github.com/djc/askama/issues/569#issuecomment-986238576) [need](https://github.com/djc/askama/issues/588#issuecomment-1002212182) [askama_{{target}}](https://github.com/djc/askama/issues/810#issuecomment-1497074654), not askama itself with `with-{{target}}` enabled (or [askama_{{target}} alone](https://github.com/djc/askama/issues/569#issuecomment-986553248)).

On the other hand, the getting started section says nothing more than adding askama itself.

If askama_{{target}} is the canonical way to use integration, maybe document that? I'm happy to PR with some advice on writing alignment.


Discussion / hints:
Well, I wouldn't want to do this in a way that requires adding another intermediate allocation, but perhaps a newtype with a `Display` implementation could do the job. I'd be open to reviewing such a PR.
How about checking for existence of `::askama::`, and if so, splitting the `&str` into head, prefix and tail, then 1) push head, 2) push `#[cfg]` activated prefix, 3) push tail?

This would be a waste of branching in most cases, so probably a separate `fn writeln_askama` or something.
Happy to review a PR that is mindful of the performance impact.
Yeah, I guess we didn't update the documentation after the recommendation changes. The recommendation is indeed that you should import directly from askama_{{target}}, though you may also need to import from askama directly. Happy to review a PR along these lines!

Fix patch:
diff --git a/askama/Cargo.toml b/askama/Cargo.toml
index 7b9575a64..4902c0995 100644
--- a/askama/Cargo.toml
+++ b/askama/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama"
-version = "0.12.1"
+version = "0.13.0"
 description = "Type-safe, compiled Jinja-like templates for Rust"
 documentation = "https://docs.rs/askama"
 keywords = ["markup", "template", "jinja2", "html"]
@@ -39,7 +39,7 @@ mime = []
 mime_guess = []
 
 [dependencies]
-askama_derive = { version = "0.12.0", path = "../askama_derive" }
+askama_derive = { version = "0.13", path = "../askama_derive" }
 askama_escape = { version = "0.10.3", path = "../askama_escape" }
 comrak = { version = "0.21", optional = true, default-features = false }
 dep_humansize = { package = "humansize", version = "2", optional = true }
diff --git a/askama_actix/Cargo.toml b/askama_actix/Cargo.toml
index a46dbffaa..ddb23b189 100644
--- a/askama_actix/Cargo.toml
+++ b/askama_actix/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_actix"
-version = "0.14.0"
+version = "0.15.0"
 description = "Actix-Web integration for Askama templates"
 documentation = "https://docs.rs/askama"
 keywords = ["markup", "template", "jinja2", "html"]
@@ -15,7 +15,7 @@ rust-version = "1.65"
 
 [dependencies]
 actix-web = { version = "4", default-features = false }
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-actix-web"] }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-actix-web"] }
 
 [dev-dependencies]
 actix-rt = { version = "2", default-features = false }
diff --git a/askama_axum/Cargo.toml b/askama_axum/Cargo.toml
index d566c1ea3..f8a77b192 100644
--- a/askama_axum/Cargo.toml
+++ b/askama_axum/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_axum"
-version = "0.4.0"
+version = "0.5.0"
 edition = "2021"
 rust-version = "1.65"
 description = "Axum integration for Askama templates"
@@ -14,7 +14,7 @@ workspace = ".."
 readme = "README.md"
 
 [dependencies]
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-axum", "mime", "mime_guess"] }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-axum", "mime", "mime_guess"] }
 axum-core = "0.4"
 http = "1.0"
 
diff --git a/askama_derive/Cargo.toml b/askama_derive/Cargo.toml
index 183958a74..a130ba10c 100644
--- a/askama_derive/Cargo.toml
+++ b/askama_derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_derive"
-version = "0.12.5"
+version = "0.13.0"
 description = "Procedural macro package for Askama"
 homepage = "https://github.com/djc/askama"
 repository = "https://github.com/djc/askama"
diff --git a/askama_derive/src/config.rs b/askama_derive/src/config.rs
index b7959b1e6..c5ce1b412 100644
--- a/askama_derive/src/config.rs
+++ b/askama_derive/src/config.rs
@@ -5,7 +5,7 @@ use std::{env, fs};
 #[cfg(feature = "serde")]
 use serde::Deserialize;
 
-use crate::CompileError;
+use crate::{CompileError, CRATE};
 use parser::node::Whitespace;
 use parser::Syntax;
 
@@ -93,7 +93,7 @@ impl<'a> Config<'a> {
             }
         }
         for (extensions, path) in DEFAULT_ESCAPERS {
-            escapers.push((str_set(extensions), (*path).to_string()));
+            escapers.push((str_set(extensions), format!("{CRATE}{path}")));
         }
 
         Ok(Config {
@@ -299,9 +299,9 @@ pub(crate) fn get_template_source(tpl_path: &Path) -> std::result::Result<String
 static CONFIG_FILE_NAME: &str = "askama.toml";
 static DEFAULT_SYNTAX_NAME: &str = "default";
 static DEFAULT_ESCAPERS: &[(&[&str], &str)] = &[
-    (&["html", "htm", "svg", "xml"], "::askama::Html"),
-    (&["md", "none", "txt", "yml", ""], "::askama::Text"),
-    (&["j2", "jinja", "jinja2"], "::askama::Html"),
+    (&["html", "htm", "svg", "xml"], "::Html"),
+    (&["md", "none", "txt", "yml", ""], "::Text"),
+    (&["j2", "jinja", "jinja2"], "::Html"),
 ];
 
 #[cfg(test)]
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index 327fde5f8..bc7b887f6 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -5,7 +5,7 @@ use std::{cmp, hash, mem, str};
 use crate::config::WhitespaceHandling;
 use crate::heritage::{Context, Heritage};
 use crate::input::{Source, TemplateInput};
-use crate::CompileError;
+use crate::{CompileError, CRATE};
 
 use parser::node::{
     Call, Comment, CondTest, If, Include, Let, Lit, Loop, Match, Target, Whitespace, Ws,
@@ -90,11 +90,10 @@ impl<'a> Generator<'a> {
         ctx: &'a Context<'_>,
         buf: &mut Buffer,
     ) -> Result<(), CompileError> {
-        self.write_header(buf, "::askama::Template", None)?;
-        buf.writeln(
-            "fn render_into(&self, writer: &mut (impl ::std::fmt::Write + ?Sized)) -> \
-             ::askama::Result<()> {",
-        )?;
+        self.write_header(buf, &format!("{CRATE}::Template"), None)?;
+        buf.write("fn render_into(&self, writer: &mut (impl ::std::fmt::Write + ?Sized)) -> ");
+        buf.write(CRATE);
+        buf.writeln("::Result<()> {")?;
 
         // Make sure the compiler understands that the generated code depends on the template files.
         for path in self.contexts.keys() {
@@ -121,7 +120,8 @@ impl<'a> Generator<'a> {
         }?;
 
         self.flush_ws(Ws(None, None));
-        buf.writeln("::askama::Result::Ok(())")?;
+        buf.write(CRATE);
+        buf.writeln("::Result::Ok(())")?;
         buf.writeln("}")?;
 
         buf.writeln("const EXTENSION: ::std::option::Option<&'static ::std::primitive::str> = ")?;
@@ -145,7 +145,8 @@ impl<'a> Generator<'a> {
         self.write_header(buf, "::std::fmt::Display", None)?;
         buf.writeln("#[inline]")?;
         buf.writeln("fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {")?;
-        buf.writeln("::askama::Template::render_into(self, f).map_err(|_| ::std::fmt::Error {})")?;
+        buf.write(CRATE);
+        buf.writeln("::Template::render_into(self, f).map_err(|_| ::std::fmt::Error {})")?;
         buf.writeln("}")?;
         buf.writeln("}")
     }
@@ -226,13 +227,13 @@ impl<'a> Generator<'a> {
                 #where_clause
             )
         ))?;
-        buf.writeln("type Error = ::askama::Error;")?;
+        buf.writeln("type Error = ::askama_hyper::Error;")?;
         buf.writeln("#[inline]")?;
         buf.writeln(&format!(
             "{} {{",
             quote!(fn try_from(value: &#ident #orig_ty_generics) -> Result<Self, Self::Error>)
         ))?;
-        buf.writeln("::askama::Template::render(value).map(Into::into)")?;
+        buf.writeln("::askama_hyper::Template::render(value).map(Into::into)")?;
         buf.writeln("}")?;
         buf.writeln("}")
     }
@@ -307,7 +308,7 @@ impl<'a> Generator<'a> {
         buf.writeln("#[inline]")?;
         buf.writeln(
             "fn respond_to(self, _: &'askama1 ::askama_rocket::Request) \
-             -> ::askama_rocket::Result<'askama2> {",
+             -> ::askama_rocket::RocketResult<'askama2> {",
         )?;
         buf.writeln("::askama_rocket::respond(&self)")?;
 
@@ -324,9 +325,10 @@ impl<'a> Generator<'a> {
             None,
         )?;
         buf.writeln(
-            "type Error = ::askama_tide::askama::Error;\n\
+            "type Error = ::askama_tide::Error;\n\
             #[inline]\n\
-            fn try_into(self) -> ::askama_tide::askama::Result<::askama_tide::tide::Body> {",
+            fn try_into(self) -> \
+			::askama_tide::Result<::askama_tide::tide::Body> {",
         )?;
         buf.writeln("::askama_tide::try_into_body(&self)")?;
         buf.writeln("}")?;
@@ -638,7 +640,9 @@ impl<'a> Generator<'a> {
         self.locals.push();
         buf.write("for (");
         self.visit_target(buf, true, true, &loop_block.var);
-        buf.writeln(", _loop_item) in ::askama::helpers::TemplateLoop::new(_iter) {")?;
+        buf.write(", _loop_item) in ");
+        buf.write(CRATE);
+        buf.writeln("::helpers::TemplateLoop::new(_iter) {")?;
 
         if has_else_nodes {
             buf.writeln("_did_loop = true;")?;
@@ -1046,7 +1050,7 @@ impl<'a> Generator<'a> {
                     let expression = match wrapped {
                         Wrapped => expr_buf.buf,
                         Unwrapped => format!(
-                            "::askama::MarkupDisplay::new_unsafe(&({}), {})",
+                            "{CRATE}::MarkupDisplay::new_unsafe(&({}), {})",
                             expr_buf.buf, self.input.escaper
                         ),
                     };
@@ -1166,7 +1170,9 @@ impl<'a> Generator<'a> {
     ) -> Result<DisplayWrap, CompileError> {
         buf.write("::core::result::Result::map_err(");
         self.visit_expr(buf, expr)?;
-        buf.write(", |err| ::askama::shared::Error::Custom(::core::convert::Into::into(err)))?");
+        buf.write(", |err| ");
+        buf.write(CRATE);
+        buf.write("::shared::Error::Custom(::core::convert::Into::into(err)))?");
         Ok(DisplayWrap::Unwrapped)
     }
 
@@ -1201,7 +1207,7 @@ impl<'a> Generator<'a> {
         };
 
         buf.write(&format!(
-            "::askama::filters::markdown({}, &",
+            "{CRATE}::filters::markdown({}, &",
             self.input.escaper
         ));
         self.visit_expr(buf, md)?;
@@ -1273,11 +1279,11 @@ impl<'a> Generator<'a> {
         const FILTERS: [&str; 2] = ["safe", "yaml"];
         if FILTERS.contains(&name) {
             buf.write(&format!(
-                "::askama::filters::{}({}, ",
+                "{CRATE}::filters::{}({}, ",
                 name, self.input.escaper
             ));
         } else if crate::BUILT_IN_FILTERS.contains(&name) {
-            buf.write(&format!("::askama::filters::{name}("));
+            buf.write(&format!("{CRATE}::filters::{name}("));
         } else {
             buf.write(&format!("filters::{name}("));
         }
@@ -1313,7 +1319,8 @@ impl<'a> Generator<'a> {
                 .ok_or_else(|| CompileError::from("invalid escaper for escape filter"))?,
             None => self.input.escaper,
         };
-        buf.write("::askama::filters::escape(");
+        buf.write(CRATE);
+        buf.write("::filters::escape(");
         buf.write(escaper);
         buf.write(", ");
         self._visit_args(buf, &args[..1])?;
@@ -1366,7 +1373,8 @@ impl<'a> Generator<'a> {
         buf: &mut Buffer,
         args: &[Expr<'_>],
     ) -> Result<(), CompileError> {
-        buf.write("::askama::filters::join((&");
+        buf.write(CRATE);
+        buf.write("::filters::join((&");
         for (i, arg) in args.iter().enumerate() {
             if i > 0 {
                 buf.write(", &");
@@ -1476,7 +1484,9 @@ impl<'a> Generator<'a> {
                         buf.writeln(");")?;
                         buf.writeln("let _len = _cycle.len();")?;
                         buf.writeln("if _len == 0 {")?;
-                        buf.writeln("return ::core::result::Result::Err(::askama::Error::Fmt(::core::fmt::Error));")?;
+                        buf.write("return ::core::result::Result::Err(");
+                        buf.write(CRATE);
+                        buf.writeln("::Error::Fmt(::core::fmt::Error));")?;
                         buf.writeln("}")?;
                         buf.writeln("_cycle[_loop_item.index % _len]")?;
                         buf.writeln("})")?;
@@ -1815,6 +1825,7 @@ impl Buffer {
             }
             self.start = false;
         }
+
         self.buf.push_str(s);
     }
 
diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs
index 65160c51c..07858a2ac 100644
--- a/askama_derive/src/lib.rs
+++ b/askama_derive/src/lib.rs
@@ -156,3 +156,23 @@ const BUILT_IN_FILTERS: &[&str] = &[
     "markdown",
     "yaml",
 ];
+
+const CRATE: &str = if cfg!(feature = "with-actix-web") {
+    "::askama_actix"
+} else if cfg!(feature = "with-axum") {
+    "::askama_axum"
+} else if cfg!(feature = "with-gotham") {
+    "::askama_gotham"
+} else if cfg!(feature = "with-hyper") {
+    "::askama_hyper"
+} else if cfg!(feature = "with-mendes") {
+    "::askama_mendes"
+} else if cfg!(feature = "with-rocket") {
+    "::askama_rocket"
+} else if cfg!(feature = "with-tide") {
+    "::askama_tide"
+} else if cfg!(feature = "with-warp") {
+    "::askama_warp"
+} else {
+    "::askama"
+};
diff --git a/askama_gotham/Cargo.toml b/askama_gotham/Cargo.toml
index 15ea50755..f35fee79e 100644
--- a/askama_gotham/Cargo.toml
+++ b/askama_gotham/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_gotham"
-version = "0.14.0"
+version = "0.15.0"
 description = "Gotham integration for Askama templates"
 documentation = "https://docs.rs/askama"
 keywords = ["markup", "template", "jinja2", "html"]
@@ -14,7 +14,7 @@ edition = "2021"
 rust-version = "1.65"
 
 [dependencies]
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-gotham", "mime", "mime_guess"] }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-gotham", "mime", "mime_guess"] }
 gotham = { version = "0.7", default-features = false }
 
 [dev-dependencies]
diff --git a/askama_hyper/Cargo.toml b/askama_hyper/Cargo.toml
index 02fcc58fe..1e78bde35 100644
--- a/askama_hyper/Cargo.toml
+++ b/askama_hyper/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_hyper"
-version = "0.1.0"
+version = "0.2.0"
 description = "Hyper integration for Askama templates"
 documentation = "https://docs.rs/askama"
 keywords = ["markup", "template", "jinja2", "html"]
@@ -14,7 +14,7 @@ edition = "2021"
 rust-version = "1.65"
 
 [dependencies]
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-hyper"] }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-hyper"] }
 hyper = { version = "0.14", default-features = false }
 
 [dev-dependencies]
diff --git a/askama_mendes/Cargo.toml b/askama_mendes/Cargo.toml
index ae5a0a412..b70c58aa7 100644
--- a/askama_mendes/Cargo.toml
+++ b/askama_mendes/Cargo.toml
@@ -14,7 +14,7 @@ edition = "2021"
 rust-version = "1.65"
 
 [dependencies]
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-mendes", "mime", "mime_guess"] }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-mendes", "mime", "mime_guess"] }
 mendes = "0.5.0"
 
 [dev-dependencies]
diff --git a/askama_rocket/Cargo.toml b/askama_rocket/Cargo.toml
index f05933872..6d1f6c6ba 100644
--- a/askama_rocket/Cargo.toml
+++ b/askama_rocket/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_rocket"
-version = "0.12.0"
+version = "0.13.0"
 description = "Rocket integration for Askama templates"
 documentation = "https://docs.rs/askama"
 keywords = ["markup", "template", "jinja2", "html"]
@@ -14,8 +14,8 @@ edition = "2021"
 rust-version = "1.65"
 
 [dependencies]
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-rocket", "mime", "mime_guess"] }
-rocket = { version = "0.5.0", default-features = false }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-rocket", "mime", "mime_guess"] }
+rocket = { version = "0.5", default-features = false }
 
 [dev-dependencies]
 futures-lite = "2.0.0"
diff --git a/askama_rocket/src/lib.rs b/askama_rocket/src/lib.rs
index e2e84be22..c302d19ae 100644
--- a/askama_rocket/src/lib.rs
+++ b/askama_rocket/src/lib.rs
@@ -8,9 +8,9 @@ pub use askama::*;
 use rocket::http::{Header, Status};
 pub use rocket::request::Request;
 use rocket::response::Response;
-pub use rocket::response::{Responder, Result};
+pub use rocket::response::{Responder, Result as RocketResult};
 
-pub fn respond<T: Template>(t: &T) -> Result<'static> {
+pub fn respond<T: Template>(t: &T) -> RocketResult<'static> {
     let rsp = t.render().map_err(|_| Status::InternalServerError)?;
     Response::build()
         .header(Header::new("content-type", T::MIME_TYPE))
diff --git a/askama_tide/Cargo.toml b/askama_tide/Cargo.toml
index 42762accd..27d227bfe 100644
--- a/askama_tide/Cargo.toml
+++ b/askama_tide/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_tide"
-version = "0.15.1"
+version = "0.16.0"
 edition = "2021"
 rust-version = "1.65"
 description = "Tide integration for Askama templates"
@@ -13,7 +13,7 @@ workspace = ".."
 readme = "README.md"
 
 [dependencies]
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-tide"] }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-tide"] }
 tide = { version = "0.16", default-features = false }
 
 [dev-dependencies]
diff --git a/askama_tide/src/lib.rs b/askama_tide/src/lib.rs
index 2dfb697d6..57c1672aa 100644
--- a/askama_tide/src/lib.rs
+++ b/askama_tide/src/lib.rs
@@ -2,7 +2,6 @@
 #![deny(elided_lifetimes_in_paths)]
 #![deny(unreachable_pub)]
 
-pub use askama;
 pub use tide;
 
 pub use askama::*;
diff --git a/askama_warp/Cargo.toml b/askama_warp/Cargo.toml
index b0efe4886..b198d137a 100644
--- a/askama_warp/Cargo.toml
+++ b/askama_warp/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "askama_warp"
-version = "0.13.0"
+version = "0.14.0"
 description = "Warp integration for Askama templates"
 documentation = "https://docs.rs/askama"
 keywords = ["markup", "template", "jinja2", "html"]
@@ -14,7 +14,7 @@ edition = "2021"
 rust-version = "1.65"
 
 [dependencies]
-askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-warp", "mime", "mime_guess"] }
+askama = { version = "0.13", path = "../askama", default-features = false, features = ["with-warp", "mime", "mime_guess"] }
 warp = { version = "0.3", default-features = false }
 
 [dev-dependencies]
diff --git a/book/src/getting_started.md b/book/src/getting_started.md
index c82b2b889..09283cd41 100644
--- a/book/src/getting_started.md
+++ b/book/src/getting_started.md
@@ -4,8 +4,7 @@ First, add the following to your crate's `Cargo.toml`:
 
 ```toml
 # in section [dependencies]
-askama = "0.11.2"
-
+askama = "0.12.1"
 ```
 
 Now create a directory called `templates` in your crate root.
@@ -35,3 +34,25 @@ fn main() {
 ```
 
 You should now be able to compile and run this code.
+
+## Using integrations
+
+To use one of the [integrations](./integrations.md), with axum as an example:
+
+First, add this to your `Cargo.toml` instead:
+
+```toml
+# in section [dependencies]
+askama_axum = "0.4.0"
+```
+
+Then, import from askama_axum instead of askama:
+
+```rust
+use askama_axum::Template;
+```
+
+This enables the implementation for axum's `IntoResponse` trait,
+so an instance of the template can be returned as a response.
+
+For other integrations, import and use their crate accordingly.
diff --git a/book/src/integrations.md b/book/src/integrations.md
index 918b887fa..c56999aae 100644
--- a/book/src/integrations.md
+++ b/book/src/integrations.md
@@ -2,6 +2,9 @@
 
 ## Rocket integration
 
+In your template definitions, replace `askama::Template` with
+[`askama_rocket::Template`][askama_rocket].
+
 Enabling the `with-rocket` feature appends an implementation of Rocket's
 `Responder` trait for each template type. This makes it easy to trivially
 return a value of that type in a Rocket handler. See
@@ -14,6 +17,9 @@ handled by your error catcher.
 
 ## Actix-web integration
 
+In your template definitions, replace `askama::Template` with
+[`askama_actix::Template`][askama_actix].
+
 Enabling the `with-actix-web` feature appends an implementation of Actix-web's
 `Responder` trait for each template type. This makes it easy to trivially return
 a value of that type in an Actix-web handler. See
@@ -22,6 +28,9 @@ from the Askama test suite for more on how to integrate.
 
 ## Axum integration
 
+In your template definitions, replace `askama::Template` with
+[`askama_axum::Template`][askama_axum].
+
 Enabling the `with-axum` feature appends an implementation of Axum's
 `IntoResponse` trait for each template type. This makes it easy to trivially
 return a value of that type in a Axum handler. See
@@ -34,6 +43,9 @@ This preserves the response chain if any custom error handling needs to occur.
 
 ## Gotham integration
 
+In your template definitions, replace `askama::Template` with
+[`askama_gotham::Template`][askama_gotham].
+
 Enabling the `with-gotham` feature appends an implementation of Gotham's
 `IntoResponse` trait for each template type. This makes it easy to trivially
 return a value of that type in a Gotham handler. See
@@ -46,6 +58,9 @@ This preserves the response chain if any custom error handling needs to occur.
 
 ## Warp integration
 
+In your template definitions, replace `askama::Template` with
+[`askama_warp::Template`][askama_warp].
+
 Enabling the `with-warp` feature appends an implementation of Warp's `Reply`
 trait for each template type. This makes it simple to return a template from
 a Warp filter. See [the example](https://github.com/djc/askama/blob/main/askama_warp/tests/warp.rs)
@@ -53,9 +68,19 @@ from the Askama test suite for more on how to integrate.
 
 ## Tide integration
 
+In your template definitions, replace `askama::Template` with
+[`askama_tide::Template`][askama_tide].
+
 Enabling the `with-tide` feature appends `Into<tide::Response>` and
 `TryInto<tide::Body>` implementations for each template type. This
 provides the ability for tide apps to build a response directly from
 a template, or to append a templated body to an existing
 `Response`. See [the example](https://github.com/djc/askama/blob/main/askama_tide/tests/tide.rs)
 from the Askama test suite for more on how to integrate.
+
+[askama_rocket]: https://docs.rs/askama_rocket
+[askama_actix]: https://docs.rs/askama_actix
+[askama_axum]: https://docs.rs/askama_axum
+[askama_gotham]: https://docs.rs/askama_gotham
+[askama_warp]: https://docs.rs/askama_warp
+[askama_tide]: https://docs.rs/askama_tide


Test patch:
diff --git a/testing/Cargo.toml b/testing/Cargo.toml
index 6c7b95891..9d6c673e5 100644
--- a/testing/Cargo.toml
+++ b/testing/Cargo.toml
@@ -13,7 +13,7 @@ serde-json = ["serde_json", "askama/serde-json"]
 markdown = ["comrak", "askama/markdown"]
 
 [dependencies]
-askama = { path = "../askama", version = "0.12" }
+askama = { path = "../askama", version = "0.13" }
 comrak = { version = "0.21", default-features = false, optional = true }
 phf = { version = "0.11", features = ["macros" ]}
 serde_json = { version = "1.0", optional = true }