diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-12-20 17:11:42 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-12-20 17:14:46 +0100 |
| commit | 08daade59f3e0005916881fddd1a774a86278fbb (patch) | |
| tree | fcd9646cf7673862e07b58ee983cb6472e200eaf /library | |
| parent | 13807ce020d18b13d636493f957c8c3828a14259 (diff) | |
Document text sub- and superscripts
Diffstat (limited to 'library')
| -rw-r--r-- | library/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/src/text/shift.rs | 157 |
2 files changed, 121 insertions, 37 deletions
diff --git a/library/src/lib.rs b/library/src/lib.rs index da05a8de..6b6cae17 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -53,6 +53,7 @@ fn scope() -> Scope { std.def_func::<math::AccNode>("acc"); std.def_func::<math::FracNode>("frac"); std.def_func::<math::BinomNode>("binom"); + std.def_func::<math::ScriptNode>("script"); std.def_func::<math::SqrtNode>("sqrt"); std.def_func::<math::FloorNode>("floor"); std.def_func::<math::CeilNode>("ceil"); diff --git a/library/src/text/shift.rs b/library/src/text/shift.rs index 5ea3b5ea..1d78d857 100644 --- a/library/src/text/shift.rs +++ b/library/src/text/shift.rs @@ -5,39 +5,134 @@ use super::{variant, SpaceNode, TextNode, TextSize}; use crate::prelude::*; /// # Subscript -/// Sub- or superscript text. +/// Set text in subscript. /// -/// The text is rendered smaller and its baseline is raised/lowered. To provide -/// the best typography possible, we first try to transform the text to -/// superscript codepoints. If that fails, we fall back to rendering shrunk -/// normal letters in a raised way. +/// The text is rendered smaller and its baseline is lowered. +/// +/// _Note:_ In the future, this might be unified with the [script](@script) +/// function that handles subscripts in math. +/// +/// ## Example +/// ``` +/// Revenue#sub[yearly] +/// ``` /// /// ## Parameters /// - body: Content (positional, required) -/// The text to display in sub- or superscript. +/// The text to display in subscript. /// /// ## Category /// text #[func] #[capable(Show)] #[derive(Debug, Hash)] -pub struct ShiftNode<const S: ShiftKind>(pub Content); +pub struct SubNode(pub Content); -/// Shift the text into superscript. -pub type SuperNode = ShiftNode<SUPERSCRIPT>; +#[node] +impl SubNode { + /// Whether to prefer the dedicated subscript characters of the font. + /// + /// If this is enabled, Typst first tries to transform the text to subscript + /// codepoints. If that fails, it falls back to rendering lowered and shrunk + /// normal letters. + /// + /// # Example + /// ``` + /// N#sub(typographic: true)[1] + /// N#sub(typographic: false)[1] + /// ``` + pub const TYPOGRAPHIC: bool = true; + /// The baseline shift for synthetic subcripts. Does not apply if + /// `typographic` is true and the font has subscript codepoints for the + /// given `body`. + pub const BASELINE: Length = Em::new(0.2).into(); + /// The font size for synthetic subscripts. Does not apply if + /// `typographic` is true and the font has subscript codepoints for the + /// given `body`. + pub const SIZE: TextSize = TextSize(Em::new(0.6).into()); + + fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { + Ok(Self(args.expect("body")?).pack()) + } -/// Shift the text into subscript. -pub type SubNode = ShiftNode<SUBSCRIPT>; + fn field(&self, name: &str) -> Option<Value> { + match name { + "body" => Some(Value::Content(self.0.clone())), + _ => None, + } + } +} + +impl Show for SubNode { + fn show( + &self, + vt: &mut Vt, + _: &Content, + styles: StyleChain, + ) -> SourceResult<Content> { + let mut transformed = None; + if styles.get(Self::TYPOGRAPHIC) { + if let Some(text) = search_text(&self.0, true) { + if is_shapable(vt, &text, styles) { + transformed = Some(TextNode::packed(text)); + } + } + }; + + Ok(transformed.unwrap_or_else(|| { + let mut map = StyleMap::new(); + map.set(TextNode::BASELINE, styles.get(Self::BASELINE)); + map.set(TextNode::SIZE, styles.get(Self::SIZE)); + self.0.clone().styled_with_map(map) + })) + } +} + +/// # Superscript +/// Set text in superscript. +/// +/// The text is rendered smaller and its baseline is raised. +/// +/// _Note:_ In the future, this might be unified with the [script](@script) +/// function that handles superscripts in math. +/// +/// ## Example +/// ``` +/// 1#super[st] try! +/// ``` +/// +/// ## Parameters +/// - body: Content (positional, required) +/// The text to display in superscript. +/// +/// ## Category +/// text +#[func] +#[capable(Show)] +#[derive(Debug, Hash)] +pub struct SuperNode(pub Content); #[node] -impl<const S: ShiftKind> ShiftNode<S> { - /// Whether to prefer the dedicated sub- and superscript characters of the - /// font. +impl SuperNode { + /// Whether to prefer the dedicated superscript characters of the font. + /// + /// If this is enabled, Typst first tries to transform the text to + /// superscript codepoints. If that fails, it falls back to rendering + /// raised and shrunk normal letters. + /// + /// # Example + /// ``` + /// N#super(typographic: true)[1] + /// N#super(typographic: false)[1] + /// ``` pub const TYPOGRAPHIC: bool = true; - /// The baseline shift for synthetic sub- and superscripts. - pub const BASELINE: Length = - Em::new(if S == SUPERSCRIPT { -0.5 } else { 0.2 }).into(); - /// The font size for synthetic sub- and superscripts. + /// The baseline shift for synthetic superscripts. Does not apply if + /// `typographic` is true and the font has superscript codepoints for the + /// given `body`. + pub const BASELINE: Length = Em::new(-0.5).into(); + /// The font size for synthetic superscripts. Does not apply if + /// `typographic` is true and the font has superscript codepoints for the + /// given `body`. pub const SIZE: TextSize = TextSize(Em::new(0.6).into()); fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { @@ -52,7 +147,7 @@ impl<const S: ShiftKind> ShiftNode<S> { } } -impl<const S: ShiftKind> Show for ShiftNode<S> { +impl Show for SuperNode { fn show( &self, vt: &mut Vt, @@ -61,7 +156,7 @@ impl<const S: ShiftKind> Show for ShiftNode<S> { ) -> SourceResult<Content> { let mut transformed = None; if styles.get(Self::TYPOGRAPHIC) { - if let Some(text) = search_text(&self.0, S) { + if let Some(text) = search_text(&self.0, false) { if is_shapable(vt, &text, styles) { transformed = Some(TextNode::packed(text)); } @@ -79,15 +174,15 @@ impl<const S: ShiftKind> Show for ShiftNode<S> { /// Find and transform the text contained in `content` to the given script kind /// if and only if it only consists of `Text`, `Space`, and `Empty` leaf nodes. -fn search_text(content: &Content, mode: ShiftKind) -> Option<EcoString> { +fn search_text(content: &Content, sub: bool) -> Option<EcoString> { if content.is::<SpaceNode>() { Some(' '.into()) } else if let Some(text) = content.to::<TextNode>() { - convert_script(&text.0, mode) + convert_script(&text.0, sub) } else if let Some(seq) = content.to::<SequenceNode>() { let mut full = EcoString::new(); for item in seq.0.iter() { - match search_text(item, mode) { + match search_text(item, sub) { Some(text) => full.push_str(&text), None => return None, } @@ -117,12 +212,9 @@ fn is_shapable(vt: &Vt, text: &str, styles: StyleChain) -> bool { /// Convert a string to sub- or superscript codepoints if all characters /// can be mapped to such a codepoint. -fn convert_script(text: &str, mode: ShiftKind) -> Option<EcoString> { +fn convert_script(text: &str, sub: bool) -> Option<EcoString> { let mut result = EcoString::with_capacity(text.len()); - let converter = match mode { - SUPERSCRIPT => to_superscript_codepoint, - SUBSCRIPT | _ => to_subscript_codepoint, - }; + let converter = if sub { to_subscript_codepoint } else { to_superscript_codepoint }; for c in text.chars() { match converter(c) { @@ -180,12 +272,3 @@ fn to_subscript_codepoint(c: char) -> Option<char> { _ => return None, }) } - -/// A category of script. -pub type ShiftKind = usize; - -/// Text that is rendered smaller and raised, also known as superior. -const SUPERSCRIPT: ShiftKind = 0; - -/// Text that is rendered smaller and lowered, also known as inferior. -const SUBSCRIPT: ShiftKind = 1; |
