diff options
| author | Laurenz <laurmaedje@gmail.com> | 2025-07-09 10:16:36 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-09 08:16:36 +0000 |
| commit | e5e1dcd9c01341d2cd3473ac94a70223d5966086 (patch) | |
| tree | d648efad9463cb10270d55ba35210eeb1e91ee22 /crates/typst-library/src/text | |
| parent | 0a3c6939dd274f40672484695d909c2cc0d0d755 (diff) | |
Target-specific native show rules (#6569)
Diffstat (limited to 'crates/typst-library/src/text')
| -rw-r--r-- | crates/typst-library/src/text/deco.rs | 123 | ||||
| -rw-r--r-- | crates/typst-library/src/text/raw.rs | 59 | ||||
| -rw-r--r-- | crates/typst-library/src/text/shift.rs | 83 | ||||
| -rw-r--r-- | crates/typst-library/src/text/smallcaps.rs | 16 | ||||
| -rw-r--r-- | crates/typst-library/src/text/smartquote.rs | 13 |
5 files changed, 31 insertions, 263 deletions
diff --git a/crates/typst-library/src/text/deco.rs b/crates/typst-library/src/text/deco.rs index 8c1d5634..f7d5c33b 100644 --- a/crates/typst-library/src/text/deco.rs +++ b/crates/typst-library/src/text/deco.rs @@ -1,13 +1,6 @@ -use smallvec::smallvec; - -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, Smart, StyleChain, TargetElem, -}; -use crate::html::{attr, tag, HtmlElem}; +use crate::foundations::{elem, Content, Smart}; use crate::layout::{Abs, Corners, Length, Rel, Sides}; -use crate::text::{BottomEdge, BottomEdgeMetric, TextElem, TopEdge, TopEdgeMetric}; +use crate::text::{BottomEdge, BottomEdgeMetric, TopEdge, TopEdgeMetric}; use crate::visualize::{Color, FixedStroke, Paint, Stroke}; /// Underlines text. @@ -16,7 +9,7 @@ use crate::visualize::{Color, FixedStroke, Paint, Stroke}; /// ```example /// This is #underline[important]. /// ``` -#[elem(Show)] +#[elem] pub struct UnderlineElem { /// How to [stroke] the line. /// @@ -78,41 +71,13 @@ pub struct UnderlineElem { pub body: Content, } -impl Show for Packed<UnderlineElem> { - #[typst_macros::time(name = "underline", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - // Note: In modern HTML, `<u>` is not the underline element, but - // rather an "Unarticulated Annotation" element (see HTML spec - // 4.5.22). Using `text-decoration` instead is recommended by MDN. - return Ok(HtmlElem::new(tag::span) - .with_attr(attr::style, "text-decoration: underline") - .with_body(Some(self.body.clone())) - .pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - line: DecoLine::Underline { - stroke: self.stroke.resolve(styles).unwrap_or_default(), - offset: self.offset.resolve(styles), - evade: self.evade.get(styles), - background: self.background.get(styles), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// Adds a line over text. /// /// # Example /// ```example /// #overline[A line over text.] /// ``` -#[elem(Show)] +#[elem] pub struct OverlineElem { /// How to [stroke] the line. /// @@ -180,38 +145,13 @@ pub struct OverlineElem { pub body: Content, } -impl Show for Packed<OverlineElem> { - #[typst_macros::time(name = "overline", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::span) - .with_attr(attr::style, "text-decoration: overline") - .with_body(Some(self.body.clone())) - .pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - line: DecoLine::Overline { - stroke: self.stroke.resolve(styles).unwrap_or_default(), - offset: self.offset.resolve(styles), - evade: self.evade.get(styles), - background: self.background.get(styles), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// Strikes through text. /// /// # Example /// ```example /// This is #strike[not] relevant. /// ``` -#[elem(title = "Strikethrough", Show)] +#[elem(title = "Strikethrough")] pub struct StrikeElem { /// How to [stroke] the line. /// @@ -264,35 +204,13 @@ pub struct StrikeElem { pub body: Content, } -impl Show for Packed<StrikeElem> { - #[typst_macros::time(name = "strike", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::s).with_body(Some(self.body.clone())).pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - // Note that we do not support evade option for strikethrough. - line: DecoLine::Strikethrough { - stroke: self.stroke.resolve(styles).unwrap_or_default(), - offset: self.offset.resolve(styles), - background: self.background.get(styles), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// Highlights text with a background color. /// /// # Example /// ```example /// This is #highlight[important]. /// ``` -#[elem(Show)] +#[elem] pub struct HighlightElem { /// The color to highlight the text with. /// @@ -363,35 +281,6 @@ pub struct HighlightElem { pub body: Content, } -impl Show for Packed<HighlightElem> { - #[typst_macros::time(name = "highlight", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::mark) - .with_body(Some(self.body.clone())) - .pack()); - } - - Ok(self.body.clone().set( - TextElem::deco, - smallvec![Decoration { - line: DecoLine::Highlight { - fill: self.fill.get_cloned(styles), - stroke: self - .stroke - .resolve(styles) - .unwrap_or_default() - .map(|stroke| stroke.map(Stroke::unwrap_or_default)), - top_edge: self.top_edge.get(styles), - bottom_edge: self.bottom_edge.get(styles), - radius: self.radius.resolve(styles).unwrap_or_default(), - }, - extent: self.extent.resolve(styles), - }], - )) - } -} - /// A text decoration. /// /// Can be positioned over, under, or on top of text, or highlight the text with diff --git a/crates/typst-library/src/text/raw.rs b/crates/typst-library/src/text/raw.rs index 67038163..8cddfbfb 100644 --- a/crates/typst-library/src/text/raw.rs +++ b/crates/typst-library/src/text/raw.rs @@ -16,14 +16,13 @@ use crate::diag::{ }; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Bytes, Content, Derived, NativeElement, OneOrMultiple, Packed, - PlainText, Show, ShowSet, Smart, StyleChain, Styles, Synthesize, TargetElem, + cast, elem, scope, Bytes, Content, Derived, OneOrMultiple, Packed, PlainText, + ShowSet, Smart, StyleChain, Styles, Synthesize, }; -use crate::html::{tag, HtmlElem}; -use crate::layout::{BlockBody, BlockElem, Em, HAlignment}; +use crate::layout::{Em, HAlignment}; use crate::loading::{DataSource, Load}; use crate::model::{Figurable, ParElem}; -use crate::text::{FontFamily, FontList, LinebreakElem, LocalName, TextElem, TextSize}; +use crate::text::{FontFamily, FontList, LocalName, TextElem, TextSize}; use crate::visualize::Color; use crate::World; @@ -78,7 +77,6 @@ use crate::World; scope, title = "Raw Text / Code", Synthesize, - Show, ShowSet, LocalName, Figurable, @@ -429,46 +427,6 @@ impl Packed<RawElem> { } } -impl Show for Packed<RawElem> { - #[typst_macros::time(name = "raw", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let lines = self.lines.as_deref().unwrap_or_default(); - - let mut seq = EcoVec::with_capacity((2 * lines.len()).saturating_sub(1)); - for (i, line) in lines.iter().enumerate() { - if i != 0 { - seq.push(LinebreakElem::shared().clone()); - } - - seq.push(line.clone().pack()); - } - - let mut realized = Content::sequence(seq); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(if self.block.get(styles) { - tag::pre - } else { - tag::code - }) - .with_body(Some(realized)) - .pack() - .spanned(self.span())); - } - - if self.block.get(styles) { - // Align the text before inserting it into the block. - realized = realized.aligned(self.align.get(styles).into()); - realized = BlockElem::new() - .with_body(Some(BlockBody::Content(realized))) - .pack() - .spanned(self.span()); - } - - Ok(realized) - } -} - impl ShowSet for Packed<RawElem> { fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); @@ -634,7 +592,7 @@ fn format_theme_error(error: syntect::LoadingError) -> LoadError { /// It allows you to access various properties of the line, such as the line /// number, the raw non-highlighted text, the highlighted text, and whether it /// is the first or last line of the raw block. -#[elem(name = "line", title = "Raw Text / Code Line", Show, PlainText)] +#[elem(name = "line", title = "Raw Text / Code Line", PlainText)] pub struct RawLine { /// The line number of the raw line inside of the raw block, starts at 1. #[required] @@ -653,13 +611,6 @@ pub struct RawLine { pub body: Content, } -impl Show for Packed<RawLine> { - #[typst_macros::time(name = "raw.line", span = self.span())] - fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { - Ok(self.body.clone()) - } -} - impl PlainText for Packed<RawLine> { fn plain_text(&self, text: &mut EcoString) { text.push_str(&self.text); diff --git a/crates/typst-library/src/text/shift.rs b/crates/typst-library/src/text/shift.rs index 1a05d8f9..87ccae63 100644 --- a/crates/typst-library/src/text/shift.rs +++ b/crates/typst-library/src/text/shift.rs @@ -1,13 +1,8 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, Smart, StyleChain, TargetElem, -}; -use crate::html::{tag, HtmlElem}; -use crate::layout::{Em, Length}; -use crate::text::{FontMetrics, TextElem, TextSize}; use ttf_parser::Tag; -use typst_library::text::ScriptMetrics; + +use crate::foundations::{elem, Content, Smart}; +use crate::layout::{Em, Length}; +use crate::text::{FontMetrics, ScriptMetrics, TextSize}; /// Renders text in subscript. /// @@ -17,7 +12,7 @@ use typst_library::text::ScriptMetrics; /// ```example /// Revenue#sub[yearly] /// ``` -#[elem(title = "Subscript", Show)] +#[elem(title = "Subscript")] pub struct SubElem { /// Whether to create artificial subscripts by lowering and scaling down /// regular glyphs. @@ -64,29 +59,6 @@ pub struct SubElem { pub body: Content, } -impl Show for Packed<SubElem> { - #[typst_macros::time(name = "sub", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let body = self.body.clone(); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::sub) - .with_body(Some(body)) - .pack() - .spanned(self.span())); - } - - show_script( - styles, - body, - self.typographic.get(styles), - self.baseline.get(styles), - self.size.get(styles), - ScriptKind::Sub, - ) - } -} - /// Renders text in superscript. /// /// The text is rendered smaller and its baseline is raised. @@ -95,7 +67,7 @@ impl Show for Packed<SubElem> { /// ```example /// 1#super[st] try! /// ``` -#[elem(title = "Superscript", Show)] +#[elem(title = "Superscript")] pub struct SuperElem { /// Whether to create artificial superscripts by raising and scaling down /// regular glyphs. @@ -146,49 +118,6 @@ pub struct SuperElem { pub body: Content, } -impl Show for Packed<SuperElem> { - #[typst_macros::time(name = "super", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let body = self.body.clone(); - - if styles.get(TargetElem::target).is_html() { - return Ok(HtmlElem::new(tag::sup) - .with_body(Some(body)) - .pack() - .spanned(self.span())); - } - - show_script( - styles, - body, - self.typographic.get(styles), - self.baseline.get(styles), - self.size.get(styles), - ScriptKind::Super, - ) - } -} - -fn show_script( - styles: StyleChain, - body: Content, - typographic: bool, - baseline: Smart<Length>, - size: Smart<TextSize>, - kind: ScriptKind, -) -> SourceResult<Content> { - let font_size = styles.resolve(TextElem::size); - Ok(body.set( - TextElem::shift_settings, - Some(ShiftSettings { - typographic, - shift: baseline.map(|l| -Em::from_length(l, font_size)), - size: size.map(|t| Em::from_length(t.0, font_size)), - kind, - }), - )) -} - /// Configuration values for sub- or superscript text. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct ShiftSettings { diff --git a/crates/typst-library/src/text/smallcaps.rs b/crates/typst-library/src/text/smallcaps.rs index 1c283893..199222fe 100644 --- a/crates/typst-library/src/text/smallcaps.rs +++ b/crates/typst-library/src/text/smallcaps.rs @@ -1,7 +1,4 @@ -use crate::diag::SourceResult; -use crate::engine::Engine; -use crate::foundations::{elem, Content, Packed, Show, StyleChain}; -use crate::text::TextElem; +use crate::foundations::{elem, Content}; /// Displays text in small capitals. /// @@ -43,7 +40,7 @@ use crate::text::TextElem; /// = Introduction /// #lorem(40) /// ``` -#[elem(title = "Small Capitals", Show)] +#[elem(title = "Small Capitals")] pub struct SmallcapsElem { /// Whether to turn uppercase letters into small capitals as well. /// @@ -61,15 +58,6 @@ pub struct SmallcapsElem { pub body: Content, } -impl Show for Packed<SmallcapsElem> { - #[typst_macros::time(name = "smallcaps", span = self.span())] - fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let sc = - if self.all.get(styles) { Smallcaps::All } else { Smallcaps::Minuscules }; - Ok(self.body.clone().set(TextElem::smallcaps, Some(sc))) - } -} - /// What becomes small capitals. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Smallcaps { diff --git a/crates/typst-library/src/text/smartquote.rs b/crates/typst-library/src/text/smartquote.rs index 24787d06..375b1cf0 100644 --- a/crates/typst-library/src/text/smartquote.rs +++ b/crates/typst-library/src/text/smartquote.rs @@ -5,9 +5,10 @@ use unicode_segmentation::UnicodeSegmentation; use crate::diag::{bail, HintedStrResult, StrResult}; use crate::foundations::{ array, cast, dict, elem, Array, Dict, FromValue, Packed, PlainText, Smart, Str, + StyleChain, }; use crate::layout::Dir; -use crate::text::{Lang, Region}; +use crate::text::{Lang, Region, TextElem}; /// A language-aware quote that reacts to its context. /// @@ -200,6 +201,16 @@ pub struct SmartQuotes<'s> { } impl<'s> SmartQuotes<'s> { + /// Retrieve the smart quotes as configured by the current styles. + pub fn get_in(styles: StyleChain<'s>) -> Self { + Self::get( + styles.get_ref(SmartQuoteElem::quotes), + styles.get(TextElem::lang), + styles.get(TextElem::region), + styles.get(SmartQuoteElem::alternative), + ) + } + /// Create a new `Quotes` struct with the given quotes, optionally falling /// back to the defaults for a language and region. /// |
