summaryrefslogtreecommitdiff
path: root/src/library/text
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-04-30 14:12:28 +0200
committerLaurenz <laurmaedje@gmail.com>2022-04-30 14:12:28 +0200
commitf9e115daf54c29358f890b137f50a33a781af680 (patch)
tree496de52246629ea8039db6beea94eb779ed2851d /src/library/text
parentf7c67cde72e6a67f45180856b332bae9863243bd (diff)
New block spacing model
Diffstat (limited to 'src/library/text')
-rw-r--r--src/library/text/deco.rs2
-rw-r--r--src/library/text/mod.rs12
-rw-r--r--src/library/text/par.rs39
-rw-r--r--src/library/text/raw.rs36
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))
}
}