diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-04-30 14:12:28 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-04-30 14:12:28 +0200 |
| commit | f9e115daf54c29358f890b137f50a33a781af680 (patch) | |
| tree | 496de52246629ea8039db6beea94eb779ed2851d /src/library/text | |
| parent | f7c67cde72e6a67f45180856b332bae9863243bd (diff) | |
New block spacing model
Diffstat (limited to 'src/library/text')
| -rw-r--r-- | src/library/text/deco.rs | 2 | ||||
| -rw-r--r-- | src/library/text/mod.rs | 12 | ||||
| -rw-r--r-- | src/library/text/par.rs | 39 | ||||
| -rw-r--r-- | src/library/text/raw.rs | 36 |
4 files changed, 53 insertions, 36 deletions
diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs index 52f8ea80..70040f9c 100644 --- a/src/library/text/deco.rs +++ b/src/library/text/deco.rs @@ -24,7 +24,6 @@ impl<const L: DecoLine> DecoNode<L> { /// tables if `auto`. #[property(shorthand, resolve, fold)] pub const STROKE: Smart<RawStroke> = Smart::Auto; - /// Position of the line relative to the baseline, read from the font tables /// if `auto`. #[property(resolve)] @@ -32,7 +31,6 @@ impl<const L: DecoLine> DecoNode<L> { /// Amount that the line will be longer or shorter than its associated text. #[property(resolve)] pub const EXTENT: RawLength = RawLength::zero(); - /// Whether the line skips sections in which it would collide /// with the glyphs. Does not apply to strikethrough. pub const EVADE: bool = true; diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs index 3cfbc55d..ecc0c546 100644 --- a/src/library/text/mod.rs +++ b/src/library/text/mod.rs @@ -223,11 +223,7 @@ impl Fold for TextSize { } } -castable! { - TextSize, - Expected: "length", - Value::Length(v) => Self(v), -} +castable!(TextSize: RawLength); /// Specifies the bottom or top edge of text. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -290,11 +286,7 @@ impl Resolve for Smart<HorizontalDir> { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct Hyphenate(pub bool); -castable! { - Hyphenate, - Expected: "boolean", - Value::Bool(v) => Self(v), -} +castable!(Hyphenate: bool); impl Resolve for Smart<Hyphenate> { type Output = bool; diff --git a/src/library/text/par.rs b/src/library/text/par.rs index 4694993e..669d07ba 100644 --- a/src/library/text/par.rs +++ b/src/library/text/par.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::sync::Arc; use unicode_bidi::{BidiInfo, Level}; @@ -15,12 +16,12 @@ use crate::util::{EcoString, MaybeShared}; pub struct ParNode(pub StyleVec<ParChild>); /// A uniformly styled atomic piece of a paragraph. -#[derive(Hash)] +#[derive(Hash, PartialEq)] pub enum ParChild { /// A chunk of text. Text(EcoString), - /// A smart quote, may be single (`false`) or double (`true`). - Quote(bool), + /// A single or double smart quote. + Quote { double: bool }, /// Horizontal spacing between other children. Spacing(Spacing), /// An arbitrary inline-level node. @@ -34,10 +35,12 @@ impl ParNode { pub const LEADING: RawLength = Em::new(0.65).into(); /// The extra spacing between paragraphs. #[property(resolve)] - pub const SPACING: RawLength = Em::new(0.55).into(); + pub const SPACING: RawLength = Em::new(1.2).into(); /// The indent the first line of a consecutive paragraph should have. #[property(resolve)] pub const INDENT: RawLength = RawLength::zero(); + /// Whether to allow paragraph spacing when there is paragraph indent. + pub const SPACING_AND_INDENT: bool = false; /// How to align text and inline objects in their line. #[property(resolve)] @@ -50,10 +53,13 @@ impl ParNode { fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> { // The paragraph constructor is special: It doesn't create a paragraph - // since that happens automatically through markup. Instead, it just - // lifts the passed body to the block level so that it won't merge with - // adjacent stuff and it styles the contained paragraphs. - Ok(Content::Block(args.expect("body")?)) + // node. Instead, it just ensures that the passed content lives is in a + // separate paragraph and styles it. + Ok(Content::sequence(vec![ + Content::Parbreak, + args.expect("body")?, + Content::Parbreak, + ])) } } @@ -91,13 +97,22 @@ impl Debug for ParChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::Text(text) => write!(f, "Text({:?})", text), - Self::Quote(double) => write!(f, "Quote({})", double), + Self::Quote { double } => write!(f, "Quote({double})"), Self::Spacing(kind) => write!(f, "{:?}", kind), Self::Node(node) => node.fmt(f), } } } +impl PartialOrd for ParChild { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + match (self, other) { + (Self::Spacing(a), Self::Spacing(b)) => a.partial_cmp(b), + _ => None, + } + } +} + /// A horizontal alignment. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct HorizontalAlign(pub RawAlign); @@ -169,7 +184,7 @@ pub struct LinebreakNode; impl LinebreakNode { fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> { let justified = args.named("justified")?.unwrap_or(false); - Ok(Content::Linebreak(justified)) + Ok(Content::Linebreak { justified }) } } @@ -432,7 +447,7 @@ fn collect<'a>( } Segment::Text(full.len() - prev) } - ParChild::Quote(double) => { + ParChild::Quote { double } => { let prev = full.len(); if styles.get(TextNode::SMART_QUOTES) { let lang = styles.get(TextNode::LANG); @@ -440,7 +455,7 @@ fn collect<'a>( let quotes = Quotes::from_lang(lang, region); let peeked = iter.peek().and_then(|(child, _)| match child { ParChild::Text(text) => text.chars().next(), - ParChild::Quote(_) => Some('"'), + ParChild::Quote { .. } => Some('"'), ParChild::Spacing(_) => Some(SPACING_REPLACE), ParChild::Node(_) => Some(NODE_REPLACE), }); diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs index 13daa1b9..ee6c6356 100644 --- a/src/library/text/raw.rs +++ b/src/library/text/raw.rs @@ -4,6 +4,7 @@ use syntect::highlighting::{FontStyle, Highlighter, Style, Theme, ThemeSet}; use syntect::parsing::SyntaxSet; use super::{FontFamily, Hyphenate, TextNode, Toggle}; +use crate::library::layout::BlockSpacing; use crate::library::prelude::*; use crate::source::SourceId; use crate::syntax::{self, RedNode}; @@ -26,13 +27,20 @@ pub struct RawNode { #[node(showable)] impl RawNode { + /// The language to syntax-highlight in. + #[property(referenced)] + pub const LANG: Option<EcoString> = None; + /// The raw text's font family. Just the normal text family if `none`. #[property(referenced)] pub const FAMILY: Smart<FontFamily> = Smart::Custom(FontFamily::new("IBM Plex Mono")); - /// The language to syntax-highlight in. - #[property(referenced)] - pub const LANG: Option<EcoString> = None; + /// The spacing above block-level raw. + #[property(resolve, shorthand(around))] + pub const ABOVE: Option<BlockSpacing> = Some(Ratio::one().into()); + /// The spacing below block-level raw. + #[property(resolve, shorthand(around))] + pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into()); fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> { Ok(Content::show(Self { @@ -59,7 +67,7 @@ impl Show for RawNode { .unwrap_or(Color::BLACK) .into(); - if matches!( + let mut realized = if matches!( lang.map(|s| s.to_lowercase()).as_deref(), Some("typ" | "typst") ) { @@ -72,7 +80,7 @@ impl Show for RawNode { seq.push(styled(&self.text[range], foreground, style)); }); - Ok(Content::sequence(seq)) + Content::sequence(seq) } else if let Some(syntax) = lang.and_then(|token| SYNTAXES.find_syntax_by_token(&token)) { @@ -80,7 +88,7 @@ impl Show for RawNode { let mut highlighter = HighlightLines::new(syntax, &THEME); for (i, line) in self.text.lines().enumerate() { if i != 0 { - seq.push(Content::Linebreak(false)); + seq.push(Content::Linebreak { justified: false }); } for (style, piece) in highlighter.highlight(line, &SYNTAXES) { @@ -88,10 +96,16 @@ impl Show for RawNode { } } - Ok(Content::sequence(seq)) + Content::sequence(seq) } else { - Ok(Content::Text(self.text.clone())) + Content::Text(self.text.clone()) + }; + + if self.block { + realized = Content::block(realized); } + + Ok(realized) } fn finalize( @@ -109,13 +123,11 @@ impl Show for RawNode { map.set_family(family.clone(), styles); } - realized = realized.styled_with_map(map); - if self.block { - realized = Content::block(realized); + realized = realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW)); } - Ok(realized) + Ok(realized.styled_with_map(map)) } } |
