summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/text
diff options
context:
space:
mode:
authorSébastien d'Herbais de Thun <sebastien.d.herbais@gmail.com>2023-11-06 21:37:50 +0100
committerGitHub <noreply@github.com>2023-11-06 21:37:50 +0100
commitc0f6d2004afebfa9412ba0c2d598ef8287197c42 (patch)
tree4bb034ca671e7d1982a306f5aecfc4f78a01841d /crates/typst-library/src/text
parent8fd546760c7c425398f0114997c8085a481d8d2a (diff)
Content rework 2 - Electric Boogaloo (#2504)
Diffstat (limited to 'crates/typst-library/src/text')
-rw-r--r--crates/typst-library/src/text/deco.rs8
-rw-r--r--crates/typst-library/src/text/misc.rs15
-rw-r--r--crates/typst-library/src/text/mod.rs21
-rw-r--r--crates/typst-library/src/text/quote.rs13
-rw-r--r--crates/typst-library/src/text/quotes.rs1
-rw-r--r--crates/typst-library/src/text/raw.rs79
-rw-r--r--crates/typst-library/src/text/shaping.rs17
-rw-r--r--crates/typst-library/src/text/shift.rs6
8 files changed, 93 insertions, 67 deletions
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<Content> {
- 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<Content> {
- 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<Content> {
- 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<Content> {
- 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<Content> {
- 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<Content> {
- 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<Content> {
// 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<FontFamily>);
-impl IntoIterator for FontList {
- type IntoIter = std::vec::IntoIter<FontFamily>;
- 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<Attribution>,
/// 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<Content> {
- 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<QuoteDict>,
}
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<EcoString>,
/// 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<EcoString>,
/// The raw file buffer of syntax theme file.
#[internal]
#[parse(theme_data.map(Some))]
+ #[borrowed]
pub theme_data: Option<Bytes>,
/// 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<Content>,
+ pub lines: Vec<RawLine>,
}
#[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<Content> {
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<Region>) -> &'static str {
+ fn local_name(lang: Lang, region: Option<Region>) -> &'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<Content> {
- 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<EcoString>);
cast! {
@@ -681,7 +688,7 @@ fn parse_syntaxes(
}
#[comemo::memoize]
-fn load_theme(path: EcoString, bytes: Bytes) -> StrResult<Arc<synt::Theme>> {
+fn load_theme(path: &str, bytes: &Bytes) -> StrResult<Arc<synt::Theme>> {
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<Item = FontFamily> + Clone,
+ mut families: impl Iterator<Item = &'a str> + 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<Item = FontFamily> + Clone {
+pub fn families(styles: StyleChain) -> impl Iterator<Item = &str> + Clone {
const FALLBACKS: &[&str] = &[
"linux libertine",
"twitter color emoji",
@@ -883,7 +883,8 @@ pub fn families(styles: StyleChain) -> impl Iterator<Item = FontFamily> + 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<Content> {
- 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<Content> {
- 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<EcoString> {
if content.is::<SpaceElem>() {
Some(' '.into())
} else if let Some(elem) = content.to::<TextElem>() {
- 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 {