Rust library to generate static websites
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: TIL the reason why my doctests never worked

+194 -166
+1 -1
benchmarks/md-benchmark/Cargo.toml
··· 1 1 [package] 2 2 name = "md-benchmark" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [dependencies]
+3 -2
benchmarks/md-benchmark/src/lib.rs
··· 1 1 use maudit::{ 2 - content::{glob_markdown, UntypedMarkdownContent}, 3 - content_sources, coronate, routes, BuildOptions, 2 + BuildOptions, 3 + content::{UntypedMarkdownContent, glob_markdown}, 4 + content_sources, coronate, routes, 4 5 }; 5 6 mod page; 6 7
+1 -1
benchmarks/overhead/Cargo.toml
··· 1 1 [package] 2 2 name = "overhead-benchmark" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [dependencies]
+1 -1
benchmarks/overhead/src/lib.rs
··· 1 - use maudit::{content_sources, coronate, routes, BuildOptions}; 1 + use maudit::{BuildOptions, content_sources, coronate, routes}; 2 2 mod page; 3 3 4 4 pub fn build_website() {
+1 -1
benchmarks/realistic-blog/Cargo.toml
··· 1 1 [package] 2 2 name = "realistic-blog-benchmark" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [dependencies]
+1 -1
benchmarks/realistic-blog/src/layout.rs
··· 1 - use maud::{html, Markup, PreEscaped}; 1 + use maud::{Markup, PreEscaped, html}; 2 2 use maudit::route::PageContext; 3 3 4 4 pub fn layout(ctx: &mut PageContext, content: String) -> Markup {
+3 -2
benchmarks/realistic-blog/src/lib.rs
··· 3 3 4 4 use content::ArticleContent; 5 5 use maudit::{ 6 - content::{glob_markdown_with_options, shortcodes::MarkdownShortcodes, MarkdownOptions}, 7 - content_sources, coronate, routes, BuildOptions, 6 + BuildOptions, 7 + content::{MarkdownOptions, glob_markdown_with_options, shortcodes::MarkdownShortcodes}, 8 + content_sources, coronate, routes, 8 9 }; 9 10 10 11 mod routes {
+1 -1
benchmarks/realistic-blog/src/routes/index.rs
··· 5 5 content::ArticleContent, 6 6 layout::layout, 7 7 routes::{ 8 - article::{ArticleParams, ArticlesParams}, 9 8 Article, Articles, 9 + article::{ArticleParams, ArticlesParams}, 10 10 }, 11 11 }; 12 12
+3 -3
crates/maudit-cli/Cargo.toml
··· 3 3 description = "CLI to operate on maudit projects." 4 4 version = "0.5.1" 5 5 license = "MIT" 6 - edition = "2021" 6 + edition = "2024" 7 7 8 8 [[bin]] 9 9 name = "maudit" ··· 19 19 tower-http = { version = "0.6.2", features = ["fs", "trace"] } 20 20 tracing = "0.1" 21 21 tracing-subscriber = { version = "=0.3.19", features = [ 22 - "env-filter", 23 - "chrono", 22 + "env-filter", 23 + "chrono", 24 24 ] } 25 25 notify = "6.1.1" 26 26 notify-debouncer-full = "0.3.1"
+4 -4
crates/maudit-cli/src/dev.rs
··· 4 4 5 5 use colored::Colorize; 6 6 use filterer::should_watch_path; 7 - use notify::{event::ModifyKind, EventKind, RecursiveMode, Watcher}; 8 - use notify_debouncer_full::{new_debouncer, DebounceEventResult, DebouncedEvent}; 7 + use notify::{EventKind, RecursiveMode, Watcher, event::ModifyKind}; 8 + use notify_debouncer_full::{DebounceEventResult, DebouncedEvent, new_debouncer}; 9 9 use quanta::Instant; 10 - use server::{update_status, WebSocketMessage}; 10 + use server::{WebSocketMessage, update_status}; 11 11 use std::path::Path; 12 12 use std::sync::Arc; 13 13 use tokio::sync::broadcast; 14 14 use tokio_util::sync::CancellationToken; 15 15 use tracing::{debug, error, info}; 16 16 17 - use crate::logging::{format_elapsed_time, FormatElapsedTimeOptions}; 17 + use crate::logging::{FormatElapsedTimeOptions, format_elapsed_time}; 18 18 19 19 fn should_rebuild_for_event(event: &DebouncedEvent) -> bool { 20 20 event.paths.iter().any(|path| {
+4 -4
crates/maudit-cli/src/dev/filterer.rs
··· 3 3 /// Simple file path filter for the dev server 4 4 pub fn should_watch_path(path: &Path) -> bool { 5 5 // Skip .DS_Store files 6 - if let Some(file_name) = path.file_name() { 7 - if file_name == ".DS_Store" { 8 - return false; 9 - } 6 + if let Some(file_name) = path.file_name() 7 + && file_name == ".DS_Store" 8 + { 9 + return false; 10 10 } 11 11 12 12 // Skip dist and target directories
+6 -6
crates/maudit-cli/src/dev/server.rs
··· 1 1 use axum::{ 2 - body::{to_bytes, Body}, 2 + Router, 3 + body::{Body, to_bytes}, 3 4 extract::{ 4 - ws::{Message, WebSocket, WebSocketUpgrade}, 5 5 Request, State, 6 + ws::{Message, WebSocket, WebSocketUpgrade}, 6 7 }, 7 8 handler::HandlerWithoutStateExt, 8 9 http::{HeaderValue, StatusCode}, 9 10 middleware::{self, Next}, 10 11 response::{IntoResponse, Response}, 11 12 routing::get, 12 - Router, 13 13 }; 14 14 use quanta::Instant; 15 15 use serde_json::json; 16 16 use tokio::{net::TcpSocket, signal, sync::broadcast}; 17 - use tracing::{debug, Level}; 17 + use tracing::{Level, debug}; 18 18 19 19 use std::net::{IpAddr, SocketAddr}; 20 20 use std::sync::Arc; ··· 24 24 }; 25 25 26 26 use axum::extract::connect_info::ConnectInfo; 27 - use futures::{stream::StreamExt, SinkExt}; 27 + use futures::{SinkExt, stream::StreamExt}; 28 28 29 - use crate::server_utils::{find_open_port, log_server_start, CustomOnResponse}; 29 + use crate::server_utils::{CustomOnResponse, find_open_port, log_server_start}; 30 30 use axum::http::header; 31 31 use local_ip_address::local_ip; 32 32 use tokio::fs;
+1 -1
crates/maudit-cli/src/init.rs
··· 5 5 6 6 use colored::Colorize; 7 7 use flate2::read::GzDecoder; 8 - use inquire::{validator::Validation, Confirm, Select, Text}; 8 + use inquire::{Confirm, Select, Text, validator::Validation}; 9 9 use quanta::Instant; 10 10 use rand::seq::IndexedRandom; 11 11 use spinach::{Color, Spinner};
+1 -1
crates/maudit-cli/src/logging.rs
··· 2 2 use std::{fmt, time::Duration}; 3 3 use tracing::{Event, Subscriber}; 4 4 use tracing_subscriber::{ 5 - fmt::{format, FmtContext, FormatEvent, FormatFields}, 5 + fmt::{FmtContext, FormatEvent, FormatFields, format}, 6 6 layer::SubscriberExt, 7 7 registry::LookupSpan, 8 8 util::SubscriberInitExt,
+4 -4
crates/maudit-cli/src/preview/server.rs
··· 2 2 use std::path::PathBuf; 3 3 4 4 use axum::{ 5 + Router, 5 6 handler::HandlerWithoutStateExt, 6 - http::{header, StatusCode}, 7 + http::{StatusCode, header}, 7 8 response::IntoResponse, 8 - Router, 9 9 }; 10 10 use quanta::Instant; 11 11 use tokio::{fs, net::TcpSocket}; 12 - use tracing::{debug, Level}; 12 + use tracing::{Level, debug}; 13 13 14 14 use tower_http::{ 15 15 services::ServeDir, 16 16 trace::{DefaultMakeSpan, TraceLayer}, 17 17 }; 18 18 19 - use crate::server_utils::{find_open_port, log_server_start, CustomOnResponse}; 19 + use crate::server_utils::{CustomOnResponse, find_open_port, log_server_start}; 20 20 21 21 pub async fn start_preview_web_server(dist_dir: PathBuf, host: bool) { 22 22 let start_time = Instant::now();
+2 -2
crates/maudit-cli/src/server_utils.rs
··· 8 8 }; 9 9 use tokio::net::TcpSocket; 10 10 use tower_http::trace::OnResponse; 11 - use tracing::{debug, info, Span}; 11 + use tracing::{Span, debug, info}; 12 12 13 - use crate::logging::{format_elapsed_time, FormatElapsedTimeOptions}; 13 + use crate::logging::{FormatElapsedTimeOptions, format_elapsed_time}; 14 14 15 15 pub fn log_server_start(start_time: Instant, host: bool, addr: SocketAddr, server_type: &str) { 16 16 info!(name: "SKIP_FORMAT", "");
+2 -2
crates/maudit-macros/Cargo.toml
··· 3 3 description = "Procedural macros for the maudit crate" 4 4 license = "MIT" 5 5 version = "0.5.0" 6 - edition = "2021" 6 + edition = "2024" 7 7 8 8 [lib] 9 9 proc-macro = true 10 10 11 11 [dependencies] 12 12 syn = { version = "2.0", features = ["full"] } 13 - quote = "1.0" 13 + quote = "1.0"
+5 -5
crates/maudit-macros/src/lib.rs
··· 1 1 use proc_macro::TokenStream; 2 2 use quote::quote; 3 3 use syn::parse::{self, Parse, ParseStream, Parser as _, Result}; 4 - use syn::{parse_macro_input, Expr, ItemStruct}; 4 + use syn::{Expr, ItemStruct, parse_macro_input}; 5 5 6 6 struct Args { 7 7 path: Expr, ··· 107 107 } 108 108 109 109 fn is_option_type(ty: &syn::Type) -> bool { 110 - if let syn::Type::Path(type_path) = ty { 111 - if let Some(segment) = type_path.path.segments.last() { 112 - return segment.ident == "Option"; 113 - } 110 + if let syn::Type::Path(type_path) = ty 111 + && let Some(segment) = type_path.path.segments.last() 112 + { 113 + return segment.ident == "Option"; 114 114 } 115 115 false 116 116 }
+3 -3
crates/maudit/src/assets.rs
··· 36 36 impl Default for RouteAssetsOptions { 37 37 fn default() -> Self { 38 38 let default_build_options = BuildOptions::default(); 39 - let page_assets_optiosn = default_build_options.route_assets_options(); 39 + let page_assets_options = default_build_options.route_assets_options(); 40 40 41 41 Self { 42 42 assets_dir: default_build_options.assets.assets_dir, 43 - output_assets_dir: page_assets_optiosn.assets_dir, 44 - hashing_strategy: page_assets_optiosn.hashing_strategy, 43 + output_assets_dir: page_assets_options.assets_dir, 44 + hashing_strategy: page_assets_options.hashing_strategy, 45 45 } 46 46 } 47 47 }
+17
crates/maudit/src/assets/image.rs
··· 60 60 pub format: Option<ImageFormat>, 61 61 } 62 62 63 + /// Represents an image asset, typically obtained using `ctx.assets.add_image` in a route. 64 + /// 65 + /// # Example 66 + /// ```rust 67 + /// use maudit::route::prelude::*; 68 + /// 69 + /// #[route("/example")] 70 + /// pub struct ExampleRoute; 71 + /// 72 + /// impl Route for ExampleRoute { 73 + /// fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 74 + /// let image = ctx.assets.add_image("path/to/image.png"); 75 + /// 76 + /// format!("<img src=\"{}\" alt=\"Example Image\" />", image.url()) 77 + /// } 78 + /// } 79 + /// ``` 63 80 #[derive(Clone, Debug, Hash, PartialEq, Eq)] 64 81 pub struct Image { 65 82 pub path: PathBuf,
+8 -8
crates/maudit/src/build/options.rs
··· 6 6 /// 7 7 /// ## Examples 8 8 /// Default values: 9 - /// ```rs 9 + /// ```rust 10 10 /// use maudit::{ 11 11 /// content_sources, coronate, routes, BuildOptions, BuildOutput, 12 12 /// }; ··· 20 20 /// } 21 21 /// ``` 22 22 /// Custom values: 23 - /// ```rs 23 + /// ```rust 24 24 /// use maudit::{ 25 - /// content_sources, coronate, routes, BuildOptions, BuildOutput, 25 + /// content_sources, coronate, routes, BuildOptions, BuildOutput, AssetsOptions, 26 26 /// }; 27 27 /// 28 28 /// fn main() -> Result<BuildOutput, Box<dyn std::error::Error>> { ··· 30 30 /// routes![], 31 31 /// content_sources![], 32 32 /// BuildOptions { 33 - /// output_dir: "public".to_string(), 34 - /// static_dir: "static".to_string(), 33 + /// output_dir: "public".into(), 34 + /// static_dir: "static".into(), 35 35 /// assets: AssetsOptions { 36 - /// assets_dir: "_assets".to_string(), 37 - /// tailwind_binary_path: "./node_modules/.bin/tailwindcss".to_string(), 36 + /// assets_dir: "_assets".into(), 37 + /// tailwind_binary_path: "./node_modules/.bin/tailwindcss".into(), 38 38 /// ..Default::default() 39 39 /// }, 40 40 /// ..Default::default() ··· 114 114 /// Provides default values for [`crate::coronate()`]. Designed to work for most projects. 115 115 /// 116 116 /// ## Examples 117 - /// ```rs 117 + /// ```rust 118 118 /// use maudit::{ 119 119 /// content_sources, coronate, routes, BuildOptions, BuildOutput, 120 120 /// };
+17 -16
crates/maudit/src/content.rs
··· 29 29 /// Helps implement a struct as a Markdown content entry. 30 30 /// 31 31 /// ## Example 32 - /// ```rs 32 + /// ```rust 33 33 /// use maudit::{coronate, content_sources, routes, BuildOptions, BuildOutput}; 34 34 /// use maudit::content::{markdown_entry, glob_markdown}; 35 35 /// ··· 51 51 /// ``` 52 52 /// 53 53 /// ## Expand 54 - /// ```rs 54 + /// ```rust 55 55 /// use maudit::content::{markdown_entry}; 56 56 /// 57 57 /// #[markdown_entry] ··· 61 61 /// } 62 62 /// ``` 63 63 /// expands to 64 - /// ```rs 64 + /// ```rust 65 65 /// #[derive(serde::Deserialize)] 66 66 /// pub struct Article { 67 67 /// pub title: String, ··· 88 88 /// 89 89 /// Can only access content sources that have been defined in [`coronate()`](crate::coronate). 90 90 /// 91 - /// ## Example 91 + /// # Example 92 92 /// In `main.rs`: 93 - /// ```rs 93 + /// ```rust 94 94 /// use maudit::{coronate, content_sources, routes, BuildOptions, BuildOutput}; 95 95 /// use maudit::content::{markdown_entry, glob_markdown}; 96 96 /// ··· 112 112 /// ``` 113 113 /// 114 114 /// In a page: 115 - /// ```rs 115 + /// ```rust 116 116 /// use maudit::route::prelude::*; 117 117 /// # use maudit::content::markdown_entry; 118 118 /// # ··· 125 125 /// #[route("/articles/[article]")] 126 126 /// pub struct Article; 127 127 /// 128 - /// #[derive(Params)] 128 + /// #[derive(Params, Clone)] 129 129 /// pub struct ArticleParams { 130 130 /// pub article: String, 131 131 /// } ··· 135 135 /// let params = ctx.params::<ArticleParams>(); 136 136 /// let articles = ctx.content.get_source::<ArticleContent>("articles"); 137 137 /// let article = articles.get_entry(&params.article); 138 - /// article.render(ctx).into() 138 + /// article.render(ctx) 139 139 /// } 140 140 /// 141 - /// fn pages(&self, ctx: &mut DynamicRouteContext) -> Vec<ArticleParams> { 141 + /// fn pages(&self, ctx: &mut DynamicRouteContext) -> Pages<ArticleParams> { 142 142 /// let articles = ctx.content.get_source::<ArticleContent>("articles"); 143 143 /// 144 - /// articles.into_params(|entry| ArticleParams { 145 - /// article: entry.id.clone(), 146 - /// }) 144 + /// articles.into_pages(|entry| Page::from_params(ArticleParams { 145 + /// article: entry.id.clone(), 146 + /// })) 147 147 /// } 148 148 /// } 149 149 /// ``` ··· 204 204 /// A single entry of a [`ContentSource`]. 205 205 /// 206 206 /// ## Example 207 - /// ```rs 207 + /// ```rust 208 208 /// use maudit::route::prelude::*; 209 209 /// # use maudit::content::markdown_entry; 210 210 /// # ··· 226 226 /// fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 227 227 /// let articles = ctx.content.get_source::<ArticleContent>("articles"); 228 228 /// let article = articles.get_entry("my-article"); // returns a Entry<ArticleContent> 229 - /// article.render(ctx).into() 229 + /// 230 + /// article.render(ctx) 230 231 /// } 231 232 /// } 232 233 /// ``` ··· 335 336 /// Mostly seen as the return type of [`content_sources!`](crate::content_sources). 336 337 /// 337 338 /// ## Example 338 - /// ```rs 339 + /// ```rust 339 340 /// use maudit::route::prelude::*; 340 341 /// use maudit::content::{glob_markdown, ContentSources}; 341 342 /// use maudit::content_sources; ··· 350 351 /// pub fn content_sources() -> ContentSources { 351 352 /// content_sources!["docs" => glob_markdown::<ArticleContent>("content/docs/*.md")] 352 353 /// } 353 - pub struct ContentSources(pub(crate) Vec<Box<dyn ContentSourceInternal>>); 354 + pub struct ContentSources(pub Vec<Box<dyn ContentSourceInternal>>); 354 355 355 356 impl From<Vec<Box<dyn ContentSourceInternal>>> for ContentSources { 356 357 fn from(content_sources: Vec<Box<dyn ContentSourceInternal>>) -> Self {
+1 -1
crates/maudit/src/content/highlight.rs
··· 89 89 90 90 impl HighlightOptions { 91 91 /// Parse the value after the opening of a fenced Markdown code block 92 - /// e.g. for ```rs ins=0, you'd get lang: "rs", ins: "0" 92 + /// e.g. for ```rust ins=0, you'd get lang: "rs", ins: "0" 93 93 pub fn new_from_fence(fence: &str, theme_path: impl Into<String>) -> Self { 94 94 // TODO: Write the parser for this, lol 95 95 let language = fence.to_string();
+17 -11
crates/maudit/src/content/markdown.rs
··· 29 29 /// Can be used to generate a table of contents. 30 30 /// 31 31 /// ## Example 32 - /// ```rs 32 + /// ```rust 33 33 /// use maudit::route::prelude::*; 34 34 /// use maud::{html, Markup}; 35 35 /// # use maudit::content::markdown_entry; ··· 114 114 /// Assumes that the Markdown content has no frontmatter. 115 115 /// 116 116 /// ## Example 117 - /// ```rs 117 + /// ```rust 118 118 /// use maudit::{coronate, content_sources, routes, BuildOptions, BuildOutput}; 119 119 /// use maudit::content::{glob_markdown, UntypedMarkdownContent}; 120 120 /// ··· 181 181 /// Typically used by [`content_sources!`](crate::content_sources) to define a Markdown content source in [`coronate()`](crate::coronate). 182 182 /// 183 183 /// ## Example 184 - /// ```rs 184 + /// ```rust 185 185 /// use maudit::{coronate, content_sources, routes, BuildOptions, BuildOutput}; 186 186 /// use maudit::content::{markdown_entry, glob_markdown_with_options, MarkdownOptions}; 187 187 /// ··· 195 195 /// coronate( 196 196 /// routes![], 197 197 /// content_sources![ 198 - /// "articles" => glob_markdown_with_options::<ArticleContent>("content/articles/*.md", ) 198 + /// "articles" => glob_markdown_with_options::<ArticleContent>("content/articles/*.md", MarkdownOptions { 199 + /// highlight_theme: "base16-ocean.dark".to_string(), 200 + /// ..Default::default() 201 + /// }) 199 202 /// ], 200 203 /// BuildOptions::default(), 201 204 /// ) ··· 255 258 /// To provide custom options for Markdown rendering, use [`glob_markdown_with_options`] instead. 256 259 /// 257 260 /// ## Example 258 - /// ```rs 261 + /// ```rust 259 262 /// use maudit::{coronate, content_sources, routes, BuildOptions, BuildOutput}; 260 263 /// use maudit::content::{markdown_entry, glob_markdown}; 261 264 /// ··· 321 324 322 325 /// Render Markdown content to HTML with optional custom components. 323 326 /// 327 + /// To be able to resolve and include images, a path to the Markdown file and a mutable reference to the current [`PageContext`](crate::route::PageContext) must be provided. 328 + /// 324 329 /// ## Example 325 - /// ```rs 330 + /// ```rust 326 331 /// use maudit::content::{render_markdown, MarkdownOptions, MarkdownComponents}; 327 332 /// use maudit::content::components::HeadingComponent; 328 333 /// 329 334 /// // Without components 330 335 /// let markdown = r#"# Hello, world!"#; 331 - /// let html = render_markdown(markdown, None); 336 + /// let html = render_markdown(markdown, None, None, None); 332 337 /// 333 338 /// // With components 334 339 /// struct MyCustomHeading; ··· 350 355 /// 351 356 /// let options = MarkdownOptions { 352 357 /// components: MarkdownComponents::new().heading(MyCustomHeading), 358 + /// ..Default::default() 353 359 /// }; 354 - /// let html = render_markdown(markdown, Some(&options)); 360 + /// let html = render_markdown(markdown, Some(&options), None, None); 355 361 /// ``` 356 362 pub fn render_markdown( 357 363 content: &str, ··· 817 823 /// and automatically populates the headings for table of contents generation. 818 824 /// 819 825 /// ## Example 820 - /// ```rs 821 - /// use maudit::content::{parse_markdown_with_frontmatter, markdown_entry}; 826 + /// ```rust 827 + /// use maudit::content::{parse_markdown_with_frontmatter, markdown_entry, MarkdownContent}; 822 828 /// 823 829 /// #[markdown_entry] 824 830 /// pub struct ArticleContent { ··· 831 837 /// description: "A great article" 832 838 /// --- 833 839 /// 834 - /// # Introduction 840 + /// ## Introduction 835 841 /// 836 842 /// This is the content. 837 843 /// "#;
+1 -1
crates/maudit/src/content/markdown/components.rs
··· 483 483 #[cfg(test)] 484 484 mod tests { 485 485 use super::*; 486 - use crate::content::{render_markdown, MarkdownOptions}; 486 + use crate::content::{MarkdownOptions, render_markdown}; 487 487 488 488 struct TestCustomHeading; 489 489
+16 -19
crates/maudit/src/lib.rs
··· 30 30 //! Traits and methods for [Maud](https://maud.lambda.xyz), a macro for writing HTML templates. 31 31 //! 32 32 //! ## Example 33 - //! ```rs 33 + //! ```rust 34 34 //! use maudit::route::prelude::*; 35 35 //! use maud::{html, Markup}; 36 36 //! 37 37 //! #[route("/")] 38 38 //! pub struct Index; 39 39 //! 40 - //! impl Route<PageParams, (), Markup> for Index { 41 - //! fn render(&self, ctx: &mut PageContext) -> Markup { 40 + //! impl Route for Index { 41 + //! fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 42 42 //! html! { 43 43 //! h1 { "Hello, world!" } 44 44 //! } ··· 63 63 /// This can be useful to conditionally enable features or logging that should only be active during development. 64 64 /// Oftentimes, this is used to disable some expensive operations that would slow down build times during development. 65 65 pub fn is_dev() -> bool { 66 - if option_env!("MAUDIT_DEV") == Some("true") { 67 - return true; 68 - } 69 - 70 66 env::var("MAUDIT_DEV").map(|v| v == "true").unwrap_or(false) 71 67 } 72 68 ··· 74 70 /// Helps to define every route that should be build by [`coronate()`]. 75 71 /// 76 72 /// ## Example 77 - /// ```rs 73 + /// ```rust 78 74 /// use maudit::{ 79 75 /// content_sources, coronate, routes, BuildOptions, BuildOutput, 80 76 /// }; ··· 84 80 /// # 85 81 /// # #[route("/")] 86 82 /// # pub struct Index; 87 - /// # impl Route<PageParams, (), String> for Index { 88 - /// # fn render(&self, _ctx: &mut PageContext) -> String { 89 - /// # "Hello, world!".to_string() 83 + /// # impl Route for Index { 84 + /// # fn render(&self, _ctx: &mut PageContext) -> impl Into<RenderResult> { 85 + /// # "Hello, world!" 90 86 /// # } 91 87 /// # } 88 + /// # 92 89 /// # #[route("/article")] 93 90 /// # pub struct Article; 94 91 /// # 95 - /// # impl Route<PageParams, (), String> for Article { 96 - /// # fn render(&self, _ctx: &mut PageContext) -> String { 97 - /// # "Hello, world!".to_string() 92 + /// # impl Route for Article { 93 + /// # fn render(&self, _ctx: &mut PageContext) -> impl Into<RenderResult> { 94 + /// # "Hello, world!" 98 95 /// # } 99 96 /// # } 100 97 /// # } ··· 117 114 /// Helps to define all sources of content that should be loaded by [`coronate()`]. 118 115 /// 119 116 /// ## Example 120 - /// ```rs 117 + /// ```rust 121 118 /// use maudit::{ 122 119 /// content_sources, coronate, routes, BuildOptions, BuildOutput, 123 120 /// }; ··· 141 138 /// ``` 142 139 /// 143 140 /// ## Expand 144 - /// ```rs 141 + /// ```rust 145 142 /// # use maudit::{content_sources}; 146 143 /// # use maudit::content::{glob_markdown, markdown_entry}; 147 144 /// # #[markdown_entry] ··· 155 152 /// ]; 156 153 /// ``` 157 154 /// expands to 158 - /// ```rs 155 + /// ```rust 159 156 /// # use maudit::content::{glob_markdown, markdown_entry}; 160 157 /// # #[markdown_entry] 161 158 /// # pub struct ArticleContent { ··· 177 174 /// Can be used to create a generator tag in the output HTML. 178 175 /// 179 176 /// ## Example 180 - /// ```rs 177 + /// ```rust 181 178 /// use maudit::GENERATOR; 182 179 /// 183 180 /// format!("<meta name=\"generator\" content=\"{}\">", GENERATOR); ··· 188 185 /// 189 186 /// ## Example 190 187 /// Should be called from the main function of the binary crate. 191 - /// ```rs 188 + /// ```rust 192 189 /// use maudit::{ 193 190 /// content_sources, coronate, routes, BuildOptions, BuildOutput, 194 191 /// };
+15 -14
crates/maudit/src/route.rs
··· 19 19 /// End users should rarely need to interact with this enum directly. 20 20 /// 21 21 /// ## Example 22 - /// ```rs 22 + /// ```rust 23 23 /// use maudit::route::prelude::*; 24 24 /// 25 25 /// #[route("/")] ··· 173 173 /// Helper function to create paginated routes from any iterator 174 174 /// 175 175 /// Example: 176 - /// ```rs 176 + /// ```rust 177 177 /// use maudit::route::prelude::*; 178 178 /// 179 179 /// #[route("/tags/[page]")] ··· 235 235 /// Allows to access various data and assets in a [`Route`] implementation. 236 236 /// 237 237 /// ## Example 238 - /// ```rs 238 + /// ```rust 239 239 /// use maudit::route::prelude::*; 240 240 /// use maud::html; 241 241 /// # use maudit::content::markdown_entry; ··· 253 253 /// fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 254 254 /// let logo = ctx.assets.add_image("logo.png"); 255 255 /// let last_entries = &ctx.content.get_source::<ArticleContent>("articles").entries; 256 + /// 256 257 /// html! { 257 258 /// main { 258 259 /// (logo) ··· 262 263 /// } 263 264 /// } 264 265 /// } 265 - /// }.into() 266 + /// } 266 267 /// } 267 268 /// } 268 269 pub struct PageContext<'a> { ··· 347 348 /// Allows to access the content source in the [`Page::pages`] method. 348 349 /// 349 350 /// ## Example 350 - /// ```rs 351 + /// ```rust 351 352 /// use maudit::route::prelude::*; 352 353 /// # use maudit::content::markdown_entry; 353 354 /// # ··· 360 361 /// #[route("/articles/[article]")] 361 362 /// pub struct Article; 362 363 /// 363 - /// #[derive(Params)] 364 + /// #[derive(Params, Clone)] 364 365 /// pub struct ArticleParams { 365 366 /// pub article: String, 366 367 /// } ··· 370 371 /// let params = ctx.params::<ArticleParams>(); 371 372 /// let articles = ctx.content.get_source::<ArticleContent>("articles"); 372 373 /// let article = articles.get_entry(&params.article); 373 - /// article.render().into() 374 + /// article.render(ctx) 374 375 /// } 375 376 /// 376 - /// fn pages(&self, ctx: &mut DynamicRouteContext) -> Vec<ArticleParams> { 377 + /// fn pages(&self, ctx: &mut DynamicRouteContext) -> Pages<ArticleParams> { 377 378 /// let articles = ctx.content.get_source::<ArticleContent>("articles"); 378 379 /// 379 - /// articles.into_params(|entry| ArticleParams { 380 - /// article: entry.id.clone(), 381 - /// }) 380 + /// articles.into_pages(|entry| Page::from_params(ArticleParams { 381 + /// article: entry.id.clone(), 382 + /// })) 382 383 /// } 383 384 /// } 384 385 /// ``` ··· 392 393 /// The page struct implementing this trait can be passed to [`coronate()`](crate::coronate), through the [`routes!`](crate::routes) macro, to be built. 393 394 /// 394 395 /// ## Example 395 - /// ```rs 396 + /// ```rust 396 397 /// use maudit::route::prelude::*; 397 398 /// 398 399 /// #[route("/")] ··· 400 401 /// 401 402 /// impl Route for Index { 402 403 /// fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 403 - /// "<h1>Hello, world!</h1>".into() 404 + /// "<h1>Hello, world!</h1>" 404 405 /// } 405 406 /// } 406 407 /// ``` ··· 729 730 //! This module is meant to be glob imported in your routes files. 730 731 //! 731 732 //! ## Example 732 - //! ```rs 733 + //! ```rust 733 734 //! use maudit::route::prelude::*; 734 735 //! ``` 735 736 pub use super::{
+2 -2
crates/oubli/Cargo.toml
··· 3 3 description = "Library for generating documentation websites with Maudit." 4 4 version = "0.1.4" 5 5 license = "MIT" 6 - edition = "2021" 6 + edition = "2024" 7 7 8 8 [dependencies] 9 9 maudit = { path = "../maudit", version = "0.6.1" } 10 10 maud = { workspace = true } 11 - serde = { workspace = true } 11 + serde = { workspace = true }
+2 -2
crates/oubli/src/archetypes/blog.rs
··· 1 1 //! Blog archetype. 2 2 //! Represents a markdown blog archetype, with an index page and individual entry pages. 3 3 use crate::layouts::layout; 4 - use maud::{html, Markup}; 4 + use maud::{Markup, html}; 5 5 use maudit::content::markdown_entry; 6 - use maudit::route::prelude::*; 7 6 use maudit::route::FullRoute; 7 + use maudit::route::prelude::*; 8 8 9 9 pub fn blog_index_content<T: FullRoute>( 10 10 route: impl FullRoute,
+1 -1
crates/oubli/src/layouts/layout.rs
··· 1 - use maud::{html, Markup, PreEscaped}; 1 + use maud::{Markup, PreEscaped, html}; 2 2 3 3 pub fn layout(title: &str, content: String) -> Markup { 4 4 html! {
+4 -4
crates/oubli/src/lib.rs
··· 4 4 use maudit::{ 5 5 content::{ContentSourceInternal, ContentSources}, 6 6 coronate, 7 - route::{prelude::Params, FullRoute}, 7 + route::{FullRoute, prelude::Params}, 8 8 }; 9 9 10 10 // Re-expose Maudit's public API. 11 - pub use maudit::{content_sources, routes, BuildOptions, BuildOutput}; 11 + pub use maudit::{BuildOptions, BuildOutput, content_sources, routes}; 12 12 // Expose the archetypes module. 13 13 pub mod archetypes { 14 14 pub mod blog; ··· 34 34 /// Helps to define every archetype that should be build by [`forget()`]. 35 35 /// 36 36 /// ## Example 37 - /// ```rs 37 + /// ```rust 38 38 /// use oubli::{Archetype, archetypes, content_sources, forget, routes, BuildOptions, BuildOutput}; 39 39 /// 40 40 /// fn main() -> Result<BuildOutput, Box<dyn std::error::Error>> { ··· 107 107 /// sources generated by these archetypes are merged with the routes and content sources provided directly. 108 108 /// 109 109 /// ## Example 110 - /// ```rs 110 + /// ```rust 111 111 /// use oubli::{Archetype, archetypes, content_sources, forget, routes, BuildOptions, BuildOutput}; 112 112 /// 113 113 /// fn main() -> Result<BuildOutput, Box<dyn std::error::Error>> {
+1 -1
examples/basics/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-example-basics" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [package.metadata.maudit]
+1 -1
examples/basics/src/layout.rs
··· 1 - use maud::{html, Markup, DOCTYPE}; 1 + use maud::{DOCTYPE, Markup, html}; 2 2 3 3 pub fn layout(content: Markup) -> Markup { 4 4 html! {
+1 -1
examples/basics/src/main.rs
··· 1 1 mod layout; 2 2 3 - use maudit::{coronate, routes, BuildOptions, BuildOutput}; 3 + use maudit::{BuildOptions, BuildOutput, coronate, routes}; 4 4 5 5 mod routes { 6 6 mod index;
+1 -1
examples/blog/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-example-blog" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [package.metadata.maudit]
+1 -1
examples/blog/src/layout.rs
··· 1 - use maud::{html, Markup, PreEscaped}; 1 + use maud::{Markup, PreEscaped, html}; 2 2 3 3 pub fn layout(content: String) -> Markup { 4 4 html! {
+1 -1
examples/blog/src/main.rs
··· 2 2 mod layout; 3 3 use content::ArticleContent; 4 4 use maudit::{ 5 - content::glob_markdown, content_sources, coronate, routes, BuildOptions, BuildOutput, 5 + BuildOptions, BuildOutput, content::glob_markdown, content_sources, coronate, routes, 6 6 }; 7 7 8 8 mod routes {
+1 -1
examples/blog/src/routes/index.rs
··· 4 4 use crate::{ 5 5 content::ArticleContent, 6 6 layout::layout, 7 - routes::{article::ArticleParams, Article}, 7 + routes::{Article, article::ArticleParams}, 8 8 }; 9 9 10 10 #[route("/")]
+1 -1
examples/empty/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-example-empty" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [package.metadata.maudit]
+1 -1
examples/empty/src/main.rs
··· 1 - use maudit::{content_sources, coronate, routes, BuildOptions, BuildOutput}; 1 + use maudit::{BuildOptions, BuildOutput, content_sources, coronate, routes}; 2 2 3 3 mod routes { 4 4 mod index;
+1 -1
examples/image-processing/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-example-image-processing" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [package.metadata.maudit]
+1 -1
examples/image-processing/src/layout.rs
··· 1 - use maud::{html, Markup, DOCTYPE}; 1 + use maud::{DOCTYPE, Markup, html}; 2 2 3 3 pub fn layout(content: Markup) -> Markup { 4 4 html! {
+1 -1
examples/image-processing/src/main.rs
··· 1 1 mod layout; 2 2 3 - use maudit::{coronate, routes, BuildOptions, BuildOutput}; 3 + use maudit::{BuildOptions, BuildOutput, coronate, routes}; 4 4 5 5 mod routes { 6 6 mod index;
+1 -1
examples/kitchen-sink/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-example-kitchen-sink" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [package.metadata.maudit]
+1 -1
examples/kitchen-sink/src/main.rs
··· 1 - use maudit::{coronate, routes, AssetsOptions, BuildOptions, BuildOutput}; 1 + use maudit::{AssetsOptions, BuildOptions, BuildOutput, coronate, routes}; 2 2 3 3 mod routes { 4 4 mod dynamic;
+1 -1
examples/library/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-example-library" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [package.metadata.maudit]
+1 -1
examples/library/src/build.rs
··· 1 1 use std::fs; 2 2 3 3 use maudit::{ 4 + BuildOptions, 4 5 assets::RouteAssets, 5 6 content::{ContentSources, RouteContent}, 6 7 route::{DynamicRouteContext, FullRoute, PageContext, PageParams, RouteType}, 7 - BuildOptions, 8 8 }; 9 9 10 10 pub fn build_website(
+1 -1
examples/library/src/layout.rs
··· 1 - use maud::{html, Markup, PreEscaped}; 1 + use maud::{Markup, PreEscaped, html}; 2 2 3 3 pub fn layout(content: String) -> Markup { 4 4 html! {
+1 -1
examples/library/src/main.rs
··· 1 1 mod content; 2 2 mod layout; 3 3 use content::ArticleContent; 4 - use maudit::{content::glob_markdown, content_sources, routes, BuildOptions}; 4 + use maudit::{BuildOptions, content::glob_markdown, content_sources, routes}; 5 5 6 6 use crate::build::build_website; 7 7
+1 -1
examples/library/src/routes/index.rs
··· 4 4 use crate::{ 5 5 content::ArticleContent, 6 6 layout::layout, 7 - routes::{article::ArticleParams, Article}, 7 + routes::{Article, article::ArticleParams}, 8 8 }; 9 9 10 10 #[route("/")]
+1 -1
examples/markdown-components/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-example-markdown-components" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [package.metadata.maudit]
+4 -1
examples/markdown-components/src/components.rs
··· 75 75 76 76 format!( 77 77 "<figure class=\"image-wrapper\"><img src=\"{}\" alt=\"{}\" class=\"responsive-image\"{} /><figcaption>{}</figcaption></figure>", 78 - url, alt, title_attr, title.unwrap_or_default() 78 + url, 79 + alt, 80 + title_attr, 81 + title.unwrap_or_default() 79 82 ) 80 83 } 81 84 }
+2 -2
examples/markdown-components/src/main.rs
··· 1 - use maudit::content::{glob_markdown_with_options, MarkdownComponents, MarkdownOptions}; 2 - use maudit::{content_sources, coronate, routes, BuildOptions, BuildOutput}; 1 + use maudit::content::{MarkdownComponents, MarkdownOptions, glob_markdown_with_options}; 2 + use maudit::{BuildOptions, BuildOutput, content_sources, coronate, routes}; 3 3 4 4 mod components; 5 5 mod routes;
+1 -1
examples/markdown-components/src/routes.rs
··· 1 - use maud::{html, PreEscaped, DOCTYPE}; 1 + use maud::{DOCTYPE, PreEscaped, html}; 2 2 use maudit::content::markdown_entry; 3 3 use maudit::route::prelude::*; 4 4
+1 -1
examples/oubli-basics/Cargo.toml
··· 1 1 [package] 2 2 name = "oubli-example-basics" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [dependencies]
+1 -1
examples/oubli-basics/src/layout.rs
··· 1 - use maud::{html, Markup, DOCTYPE}; 1 + use maud::{DOCTYPE, Markup, html}; 2 2 3 3 pub fn layout(content: Markup) -> Markup { 4 4 html! {
+1 -1
examples/oubli-basics/src/main.rs
··· 1 1 mod layout; 2 2 3 - use oubli::{archetypes, forget, routes, Archetype, BuildOptions, BuildOutput}; 3 + use oubli::{Archetype, BuildOptions, BuildOutput, archetypes, forget, routes}; 4 4 5 5 mod routes { 6 6 mod index;
+1 -1
website/Cargo.toml
··· 1 1 [package] 2 2 name = "maudit-website" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 publish = false 6 6 7 7 [dependencies]
+1 -1
website/content/docs/installation.md
··· 6 6 7 7 ## Prerequisites 8 8 9 - - [Rust (1.83 or later)](https://www.rust-lang.org) 9 + - [Rust (1.85 or later)](https://www.rust-lang.org) 10 10 - A code editor (e.g. Visual Studio Code, RustRover, Helix, etc.) 11 11 - A terminal emulator (e.g. Windows Terminal, Terminal.app, Ghostty, etc.) 12 12
+1 -1
website/src/content.rs
··· 1 1 use maud::{PreEscaped, Render}; 2 2 use maudit::content::{ 3 - glob_markdown, glob_markdown_with_options, markdown_entry, ContentSources, MarkdownOptions, 3 + ContentSources, MarkdownOptions, glob_markdown, glob_markdown_with_options, markdown_entry, 4 4 }; 5 5 use maudit::content_sources; 6 6 use serde::Deserialize;
+1 -1
website/src/layout.rs
··· 1 - use maud::{html, Markup, PreEscaped, DOCTYPE}; 1 + use maud::{DOCTYPE, Markup, PreEscaped, html}; 2 2 mod docs_sidebars; 3 3 mod header; 4 4
+1 -1
website/src/layout/docs_sidebars.rs
··· 1 - use maud::{html, Markup}; 1 + use maud::{Markup, html}; 2 2 use maudit::{content::MarkdownHeading, route::PageContext}; 3 3 4 4 use crate::content::{DocsContent, DocsSection};
+1 -1
website/src/layout/header.rs
··· 1 - use maud::html; 2 1 use maud::Markup; 3 2 use maud::PreEscaped; 3 + use maud::html; 4 4 use maudit::route::PageContext; 5 5 6 6 pub fn header(ctx: &mut PageContext, bottom_border: bool) -> Markup {
+1 -1
website/src/main.rs
··· 1 1 use content::content_sources; 2 - use maudit::{coronate, routes, AssetsOptions, BuildOptions, BuildOutput}; 2 + use maudit::{AssetsOptions, BuildOptions, BuildOutput, coronate, routes}; 3 3 4 4 mod content; 5 5 mod layout;
+2 -2
website/src/routes/404.rs
··· 1 - use maud::{html, PreEscaped}; 1 + use maud::{PreEscaped, html}; 2 2 use maudit::route::prelude::*; 3 3 4 - use crate::layout::{layout, SeoMeta}; 4 + use crate::layout::{SeoMeta, layout}; 5 5 6 6 #[route("404.html")] 7 7 pub struct NotFound;
+7 -6
website/src/routes/docs.rs
··· 1 - use maud::{html, Markup, PreEscaped}; 1 + use maud::{Markup, PreEscaped, html}; 2 2 use maudit::{content::EntryInner, route::prelude::*}; 3 3 4 4 use crate::{ 5 5 content::DocsContent, 6 - layout::{docs_layout, SeoMeta}, 6 + layout::{SeoMeta, docs_layout}, 7 7 }; 8 8 9 9 #[route("/docs/")] ··· 16 16 .get_source::<DocsContent>("docs") 17 17 .get_entry("index"); 18 18 19 - let headings = index_page.data(ctx).get_headings().clone(); 19 + let headings = index_page.data(ctx).get_headings(); 20 20 21 21 docs_layout( 22 22 render_entry(index_page, ctx), 23 23 ctx, 24 - &headings, 24 + headings, 25 25 Some(SeoMeta { 26 26 title: "Documentation".to_string(), 27 27 description: Some( ··· 79 79 80 80 let entry_data = entry.data(ctx); 81 81 82 - let headings = entry_data.get_headings().clone(); 82 + let headings = entry_data.get_headings(); 83 + 83 84 docs_layout( 84 85 render_entry(entry, ctx), 85 86 ctx, 86 - &headings, 87 + headings, 87 88 Some(SeoMeta { 88 89 title: format!("{} - Documentation", entry_data.title), 89 90 description: entry_data.description.clone(),