Skip to main content

aetna_core/widgets/
code_block.rs

1//! Code block — surface-tinted monospace block for fenced code.
2//!
3//! Mirrors HTML's `<pre><code>` shape: a bordered, rounded surface that
4//! wraps a multi-line monospace body. The body uses the `mono` font path
5//! at `TEXT_SM` size and does not wrap — long lines extend horizontally
6//! rather than reflowing, the same convention shadcn's typography uses
7//! for fenced code (`overflow-x-auto`). Author wraps the result in
8//! `scroll([...])` for horizontal scroll if desired; that integration is
9//! out of scope for this primitive.
10//!
11//! Two entry points: [`code_block`] takes a verbatim string and renders
12//! it as one mono text leaf, while [`code_block_chrome`] takes any
13//! pre-built body `El` (typically a styled [`text_runs`] paragraph
14//! produced by a syntax highlighter) and applies the same surface
15//! chrome — used by `aetna-markdown` to render highlighted fenced code
16//! without duplicating the chrome tokens.
17//!
18//! ```ignore
19//! use aetna_core::prelude::*;
20//!
21//! code_block("fn main() {\n    println!(\"hi\");\n}")
22//! ```
23
24use std::panic::Location;
25
26use crate::style::StyleProfile;
27use crate::tokens;
28use crate::tree::*;
29use crate::widgets::text::text;
30
31#[track_caller]
32pub fn code_block(s: impl Into<String>) -> El {
33    let loc = Location::caller();
34    let body = text(s)
35        .at_loc(loc)
36        .mono()
37        .font_size(tokens::TEXT_SM.size)
38        .nowrap_text()
39        .width(Size::Hug)
40        .height(Size::Hug);
41    code_block_chrome_at(body, loc)
42}
43
44/// Wrap an author-supplied body `El` in the standard code-block surface
45/// chrome (sunken muted fill, themed border, rounded corners,
46/// `SPACE_3` padding). Used by syntax-highlighter integrations that
47/// need the same chrome around a styled `text_runs([...])` paragraph
48/// rather than a plain mono text leaf.
49#[track_caller]
50pub fn code_block_chrome(body: El) -> El {
51    code_block_chrome_at(body, Location::caller())
52}
53
54fn code_block_chrome_at(body: El, loc: &'static Location<'static>) -> El {
55    column([body])
56        .at_loc(loc)
57        .style_profile(StyleProfile::Surface)
58        .surface_role(SurfaceRole::Sunken)
59        .fill(tokens::MUTED)
60        .stroke(tokens::BORDER)
61        .default_radius(tokens::RADIUS_MD)
62        .default_padding(Sides::all(tokens::SPACE_3))
63        .width(Size::Fill(1.0))
64        .height(Size::Hug)
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn code_block_wraps_mono_body_in_sunken_surface() {
73        let block = code_block("fn main() {\n    println!(\"hi\");\n}");
74
75        assert_eq!(block.kind, Kind::Group);
76        assert_eq!(block.axis, Axis::Column);
77        assert_eq!(block.style_profile, StyleProfile::Surface);
78        assert_eq!(block.surface_role, SurfaceRole::Sunken);
79        assert_eq!(block.fill, Some(tokens::MUTED));
80        assert_eq!(block.stroke, Some(tokens::BORDER));
81        assert_eq!(block.padding, Sides::all(tokens::SPACE_3));
82        assert_eq!(block.width, Size::Fill(1.0));
83        assert_eq!(block.children.len(), 1);
84
85        let body = &block.children[0];
86        assert_eq!(body.kind, Kind::Text);
87        assert!(body.font_mono);
88        assert_eq!(body.font_size, tokens::TEXT_SM.size);
89        assert_eq!(body.text_wrap, TextWrap::NoWrap);
90        assert_eq!(
91            body.text.as_deref(),
92            Some("fn main() {\n    println!(\"hi\");\n}")
93        );
94    }
95}