From c0f6d2004afebfa9412ba0c2d598ef8287197c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20d=27Herbais=20de=20Thun?= Date: Mon, 6 Nov 2023 21:37:50 +0100 Subject: Content rework 2 - Electric Boogaloo (#2504) --- crates/typst-library/src/text/deco.rs | 8 ++-- crates/typst-library/src/text/misc.rs | 15 ++++-- crates/typst-library/src/text/mod.rs | 21 ++++++--- crates/typst-library/src/text/quote.rs | 13 +++--- crates/typst-library/src/text/quotes.rs | 1 + crates/typst-library/src/text/raw.rs | 79 +++++++++++++++++--------------- crates/typst-library/src/text/shaping.rs | 17 +++---- crates/typst-library/src/text/shift.rs | 6 +-- 8 files changed, 93 insertions(+), 67 deletions(-) (limited to 'crates/typst-library/src/text') diff --git a/crates/typst-library/src/text/deco.rs b/crates/typst-library/src/text/deco.rs index 136dfad8..d8167788 100644 --- a/crates/typst-library/src/text/deco.rs +++ b/crates/typst-library/src/text/deco.rs @@ -78,7 +78,7 @@ pub struct UnderlineElem { impl Show for UnderlineElem { #[tracing::instrument(name = "UnderlineElem::show", skip_all)] fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { - Ok(self.body().styled(TextElem::set_deco(Decoration { + Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Underline { stroke: self.stroke(styles).unwrap_or_default(), offset: self.offset(styles), @@ -170,7 +170,7 @@ pub struct OverlineElem { impl Show for OverlineElem { #[tracing::instrument(name = "OverlineElem::show", skip_all)] fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { - Ok(self.body().styled(TextElem::set_deco(Decoration { + Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Overline { stroke: self.stroke(styles).unwrap_or_default(), offset: self.offset(styles), @@ -247,7 +247,7 @@ pub struct StrikeElem { impl Show for StrikeElem { #[tracing::instrument(name = "StrikeElem::show", skip_all)] fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { - Ok(self.body().styled(TextElem::set_deco(Decoration { + Ok(self.body().clone().styled(TextElem::set_deco(Decoration { // Note that we do not support evade option for strikethrough. line: DecoLine::Strikethrough { stroke: self.stroke(styles).unwrap_or_default(), @@ -317,7 +317,7 @@ pub struct HighlightElem { impl Show for HighlightElem { #[tracing::instrument(name = "HighlightElem::show", skip_all)] fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { - Ok(self.body().styled(TextElem::set_deco(Decoration { + Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Highlight { fill: self.fill(styles), top_edge: self.top_edge(styles), diff --git a/crates/typst-library/src/text/misc.rs b/crates/typst-library/src/text/misc.rs index 73657345..9f768f11 100644 --- a/crates/typst-library/src/text/misc.rs +++ b/crates/typst-library/src/text/misc.rs @@ -2,9 +2,15 @@ use super::TextElem; use crate::prelude::*; /// A text space. -#[elem(Behave, Unlabellable, PlainText)] +#[elem(Behave, Unlabellable, PlainText, Repr)] pub struct SpaceElem {} +impl Repr for SpaceElem { + fn repr(&self) -> EcoString { + EcoString::inline("[ ]") + } +} + impl Behave for SpaceElem { fn behaviour(&self) -> Behaviour { Behaviour::Weak(2) @@ -98,7 +104,10 @@ pub struct StrongElem { impl Show for StrongElem { #[tracing::instrument(name = "StrongElem::show", skip_all)] fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { - Ok(self.body().styled(TextElem::set_delta(Delta(self.delta(styles))))) + Ok(self + .body() + .clone() + .styled(TextElem::set_delta(Delta(self.delta(styles))))) } } @@ -153,7 +162,7 @@ pub struct EmphElem { impl Show for EmphElem { #[tracing::instrument(name = "EmphElem::show", skip(self))] fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult { - Ok(self.body().styled(TextElem::set_emph(Toggle))) + Ok(self.body().clone().styled(TextElem::set_emph(Toggle))) } } diff --git a/crates/typst-library/src/text/mod.rs b/crates/typst-library/src/text/mod.rs index 27dd4a3f..84a68d6f 100644 --- a/crates/typst-library/src/text/mod.rs +++ b/crates/typst-library/src/text/mod.rs @@ -64,7 +64,7 @@ pub(super) fn define(global: &mut Scope) { /// With a function call. /// ]) /// ``` -#[elem(Construct, PlainText)] +#[elem(Construct, PlainText, Repr)] pub struct TextElem { /// A font family name or priority list of font family names. /// @@ -97,6 +97,7 @@ pub struct TextElem { /// هذا عربي. /// ``` #[default(FontList(vec![FontFamily::new("Linux Libertine")]))] + #[borrowed] pub font: FontList, /// Whether to allow last resort font fallback when the primary font list @@ -558,8 +559,8 @@ pub struct TextElem { pub body: Content, /// The text. - #[internal] #[required] + #[variant(0)] pub text: EcoString, /// A delta to apply on the font weight. @@ -595,6 +596,12 @@ impl TextElem { } } +impl Repr for TextElem { + fn repr(&self) -> EcoString { + eco_format!("[{}]", self.text) + } +} + impl Construct for TextElem { fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult { // The text constructor is special: It doesn't create a text element. @@ -608,7 +615,7 @@ impl Construct for TextElem { impl PlainText for TextElem { fn plain_text(&self, text: &mut EcoString) { - text.push_str(&self.text()); + text.push_str(self.text()); } } @@ -644,12 +651,12 @@ cast! { #[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct FontList(pub Vec); -impl IntoIterator for FontList { - type IntoIter = std::vec::IntoIter; - type Item = FontFamily; +impl<'a> IntoIterator for &'a FontList { + type IntoIter = std::slice::Iter<'a, FontFamily>; + type Item = &'a FontFamily; fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() + self.0.iter() } } diff --git a/crates/typst-library/src/text/quote.rs b/crates/typst-library/src/text/quote.rs index 86be2416..c555df2d 100644 --- a/crates/typst-library/src/text/quote.rs +++ b/crates/typst-library/src/text/quote.rs @@ -101,6 +101,7 @@ pub struct QuoteElem { /// /// #bibliography("works.bib") /// ``` + #[borrowed] attribution: Option, /// The quote. @@ -108,7 +109,7 @@ pub struct QuoteElem { body: Content, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Hash)] pub enum Attribution { Content(Content), Label(Label), @@ -126,7 +127,7 @@ cast! { impl Show for QuoteElem { fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { - let mut realized = self.body(); + let mut realized = self.body().clone(); let block = self.block(styles); if self.quotes(styles) == Smart::Custom(true) || !block { @@ -140,16 +141,16 @@ impl Show for QuoteElem { if block { realized = BlockElem::new().with_body(Some(realized)).pack(); - if let Some(attribution) = self.attribution(styles) { + if let Some(attribution) = self.attribution(styles).as_ref() { let mut seq = vec![TextElem::packed('—'), SpaceElem::new().pack()]; match attribution { Attribution::Content(content) => { - seq.push(content); + seq.push(content.clone()); } Attribution::Label(label) => { seq.push( - CiteElem::new(label) + CiteElem::new(*label) .with_form(Some(CitationForm::Prose)) .pack(), ); @@ -164,7 +165,7 @@ impl Show for QuoteElem { realized = PadElem::new(realized).pack(); } else if let Some(Attribution::Label(label)) = self.attribution(styles) { - realized += SpaceElem::new().pack() + CiteElem::new(label).pack(); + realized += SpaceElem::new().pack() + CiteElem::new(*label).pack(); } Ok(realized) diff --git a/crates/typst-library/src/text/quotes.rs b/crates/typst-library/src/text/quotes.rs index 37e664fd..035ba422 100644 --- a/crates/typst-library/src/text/quotes.rs +++ b/crates/typst-library/src/text/quotes.rs @@ -78,6 +78,7 @@ pub struct SmartquoteElem { /// #set smartquote(quotes: (single: ("[[", "]]"), double: auto)) /// 'Das sind eigene Anführungszeichen.' /// ``` + #[borrowed] pub quotes: Smart, } diff --git a/crates/typst-library/src/text/raw.rs b/crates/typst-library/src/text/raw.rs index d16659be..4f672be9 100644 --- a/crates/typst-library/src/text/raw.rs +++ b/crates/typst-library/src/text/raw.rs @@ -17,7 +17,7 @@ use super::{ FontFamily, FontList, Hyphenate, LinebreakElem, SmartquoteElem, TextElem, TextSize, }; use crate::layout::BlockElem; -use crate::meta::{Figurable, LocalName}; +use crate::meta::Figurable; use crate::prelude::*; // Shorthand for highlighter closures. @@ -145,6 +145,7 @@ pub struct RawElem { /// /// This is ```typ also *Typst*```, but inline! /// ```` + #[borrowed] pub lang: Option, /// The horizontal alignment that each line in a raw block should have. @@ -225,11 +226,13 @@ pub struct RawElem { let (theme_path, theme_data) = parse_theme(vm, args)?; theme_path.map(Some) )] + #[borrowed] pub theme: Option, /// The raw file buffer of syntax theme file. #[internal] #[parse(theme_data.map(Some))] + #[borrowed] pub theme_data: Option, /// The size for a tab stop in spaces. A tab is replaced with enough spaces to @@ -252,7 +255,7 @@ pub struct RawElem { /// Made accessible for the [`raw.line` element]($raw.line). /// Allows more styling control in `show` rules. #[synthesized] - pub lines: Vec, + pub lines: Vec, } #[scope] @@ -280,17 +283,20 @@ impl RawElem { impl Synthesize for RawElem { fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { - self.push_lang(self.lang(styles)); + self.push_lang(self.lang(styles).clone()); - let mut text = self.text(); + let mut text = self.text().clone(); if text.contains('\t') { let tab_size = RawElem::tab_size_in(styles); text = align_tabs(&text, tab_size); } + let count = text.lines().count() as i64; + let lang = self .lang(styles) .as_ref() + .as_ref() .map(|s| s.to_lowercase()) .or(Some("txt".into())); @@ -298,12 +304,12 @@ impl Synthesize for RawElem { load_syntaxes(&self.syntaxes(styles), &self.syntaxes_data(styles)).unwrap() }); - let theme = self.theme(styles).map(|theme_path| { - load_theme(theme_path, self.theme_data(styles).unwrap()).unwrap() + let theme = self.theme(styles).as_ref().as_ref().map(|theme_path| { + load_theme(theme_path, self.theme_data(styles).as_ref().as_ref().unwrap()) + .unwrap() }); let theme = theme.as_deref().unwrap_or(&THEME); - let foreground = theme.settings.foreground.unwrap_or(synt::Color::BLACK); let mut seq = vec![]; @@ -319,15 +325,12 @@ impl Synthesize for RawElem { synt::Highlighter::new(theme), &mut |_, range, style| styled(&text[range], foreground, style), &mut |i, range, line| { - seq.push( - RawLine::new( - i + 1, - text.split(is_newline).count() as i64, - EcoString::from(&text[range]), - Content::sequence(line.drain(..)), - ) - .pack(), - ); + seq.push(RawLine::new( + i + 1, + count, + EcoString::from(&text[range]), + Content::sequence(line.drain(..)), + )); }, ) .highlight(); @@ -342,7 +345,6 @@ impl Synthesize for RawElem { }) }) { let mut highlighter = syntect::easy::HighlightLines::new(syntax, theme); - let len = text.lines().count(); for (i, line) in text.lines().enumerate() { let mut line_content = vec![]; for (style, piece) in @@ -351,18 +353,23 @@ impl Synthesize for RawElem { line_content.push(styled(piece, foreground, style)); } - seq.push( - RawLine::new( - i as i64 + 1, - len as i64, - EcoString::from(line), - Content::sequence(line_content), - ) - .pack(), - ); + seq.push(RawLine::new( + i as i64 + 1, + count, + EcoString::from(line), + Content::sequence(line_content), + )); } } else { - seq.extend(text.lines().map(TextElem::packed)); + let lines = text.lines(); + seq.extend(lines.enumerate().map(|(i, line)| { + RawLine::new( + i as i64 + 1, + count, + EcoString::from(line), + TextElem::packed(line), + ) + })); }; self.push_lines(seq); @@ -375,12 +382,12 @@ impl Show for RawElem { #[tracing::instrument(name = "RawElem::show", skip_all)] fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult { let mut lines = EcoVec::with_capacity((2 * self.lines().len()).saturating_sub(1)); - for (i, line) in self.lines().into_iter().enumerate() { + for (i, line) in self.lines().iter().enumerate() { if i != 0 { lines.push(LinebreakElem::new().pack()); } - lines.push(line); + lines.push(line.clone().pack()); } let mut realized = Content::sequence(lines); @@ -408,7 +415,7 @@ impl Finalize for RawElem { } impl LocalName for RawElem { - fn local_name(&self, lang: Lang, region: Option) -> &'static str { + fn local_name(lang: Lang, region: Option) -> &'static str { match lang { Lang::ALBANIAN => "List", Lang::ARABIC => "قائمة", @@ -443,7 +450,7 @@ impl Figurable for RawElem {} impl PlainText for RawElem { fn plain_text(&self, text: &mut EcoString) { - text.push_str(&self.text()); + text.push_str(self.text()); } } @@ -475,13 +482,13 @@ pub struct RawLine { impl Show for RawLine { fn show(&self, _vt: &mut Vt, _styles: StyleChain) -> SourceResult { - Ok(self.body()) + Ok(self.body().clone()) } } impl PlainText for RawLine { fn plain_text(&self, text: &mut EcoString) { - text.push_str(&self.text()); + text.push_str(self.text()); } } @@ -617,7 +624,7 @@ fn to_syn(color: Color) -> synt::Color { } /// A list of bibliography file paths. -#[derive(Debug, Default, Clone, Hash)] +#[derive(Debug, Default, Clone, PartialEq, Hash)] pub struct SyntaxPaths(Vec); cast! { @@ -681,7 +688,7 @@ fn parse_syntaxes( } #[comemo::memoize] -fn load_theme(path: EcoString, bytes: Bytes) -> StrResult> { +fn load_theme(path: &str, bytes: &Bytes) -> StrResult> { let mut cursor = std::io::Cursor::new(bytes.as_slice()); synt::ThemeSet::load_from_reader(&mut cursor) @@ -705,7 +712,7 @@ fn parse_theme( let data = vm.world().file(id).at(span)?; // Check that parsing works. - let _ = load_theme(path.clone(), data.clone()).at(span)?; + let _ = load_theme(&path, &data).at(span)?; Ok((Some(path), Some(data))) } diff --git a/crates/typst-library/src/text/shaping.rs b/crates/typst-library/src/text/shaping.rs index 0cfffce0..f7cf90bd 100644 --- a/crates/typst-library/src/text/shaping.rs +++ b/crates/typst-library/src/text/shaping.rs @@ -8,7 +8,7 @@ use typst::font::{Font, FontStyle, FontVariant}; use typst::util::SliceExt; use unicode_script::{Script, UnicodeScript}; -use super::{decorate, FontFamily, NumberType, NumberWidth, TextElem}; +use super::{decorate, NumberType, NumberWidth, TextElem}; use crate::layout::SpanMapper; use crate::prelude::*; @@ -320,7 +320,7 @@ impl<'a> ShapedText<'a> { for family in families(self.styles) { if let Some(font) = world .book() - .select(family.as_str(), self.variant) + .select(family, self.variant) .and_then(|id| world.font(id)) { expand(&font, None); @@ -424,7 +424,7 @@ impl<'a> ShapedText<'a> { None }; let mut chain = families(self.styles) - .map(|family| book.select(family.as_str(), self.variant)) + .map(|family| book.select(family, self.variant)) .chain(fallback_func.iter().map(|f| f())) .flatten(); @@ -593,11 +593,11 @@ pub fn shape<'a>( } /// Shape text with font fallback using the `families` iterator. -fn shape_segment( +fn shape_segment<'a>( ctx: &mut ShapingContext, base: usize, text: &str, - mut families: impl Iterator + Clone, + mut families: impl Iterator + Clone, ) { // Fonts dont have newlines and tabs. if text.chars().all(|c| c == '\n' || c == '\t') { @@ -608,7 +608,7 @@ fn shape_segment( let world = ctx.vt.world; let book = world.book(); let mut selection = families.find_map(|family| { - book.select(family.as_str(), ctx.variant) + book.select(family, ctx.variant) .and_then(|id| world.font(id)) .filter(|font| !ctx.used.contains(font)) }); @@ -871,7 +871,7 @@ pub fn variant(styles: StyleChain) -> FontVariant { } /// Resolve a prioritized iterator over the font families. -pub fn families(styles: StyleChain) -> impl Iterator + Clone { +pub fn families(styles: StyleChain) -> impl Iterator + Clone { const FALLBACKS: &[&str] = &[ "linux libertine", "twitter color emoji", @@ -883,7 +883,8 @@ pub fn families(styles: StyleChain) -> impl Iterator + Clone let tail = if TextElem::fallback_in(styles) { FALLBACKS } else { &[] }; TextElem::font_in(styles) .into_iter() - .chain(tail.iter().copied().map(FontFamily::new)) + .map(|family| family.as_str()) + .chain(tail.iter().copied()) } /// Collect the tags of the OpenType features to apply. diff --git a/crates/typst-library/src/text/shift.rs b/crates/typst-library/src/text/shift.rs index 6cb4d895..903982ef 100644 --- a/crates/typst-library/src/text/shift.rs +++ b/crates/typst-library/src/text/shift.rs @@ -44,7 +44,7 @@ pub struct SubElem { impl Show for SubElem { #[tracing::instrument(name = "SubElem::show", skip_all)] fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult { - let body = self.body(); + let body = self.body().clone(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, true) { @@ -104,7 +104,7 @@ pub struct SuperElem { impl Show for SuperElem { #[tracing::instrument(name = "SuperElem::show", skip_all)] fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult { - let body = self.body(); + let body = self.body().clone(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, false) { @@ -127,7 +127,7 @@ fn search_text(content: &Content, sub: bool) -> Option { if content.is::() { Some(' '.into()) } else if let Some(elem) = content.to::() { - convert_script(&elem.text(), sub) + convert_script(elem.text(), sub) } else if let Some(children) = content.to_sequence() { let mut full = EcoString::new(); for item in children { -- cgit v1.2.3