summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library/text/lang.rs39
-rw-r--r--src/library/text/mod.rs36
-rw-r--r--src/library/text/par.rs14
-rw-r--r--tests/ref/text/linebreak.pngbin18645 -> 18653 bytes
-rw-r--r--tests/typ/text/hyphenate.typ10
-rw-r--r--tests/typ/text/justify.typ1
-rw-r--r--tests/typ/text/knuth.typ2
-rw-r--r--tests/typ/text/microtype.typ2
-rw-r--r--tests/typ/text/quotes.typ4
9 files changed, 55 insertions, 53 deletions
diff --git a/src/library/text/lang.rs b/src/library/text/lang.rs
new file mode 100644
index 00000000..343359d1
--- /dev/null
+++ b/src/library/text/lang.rs
@@ -0,0 +1,39 @@
+use crate::eval::Value;
+use crate::geom::Dir;
+
+/// A natural language.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct Lang([u8; 2]);
+
+impl Lang {
+ /// The code for the english language.
+ pub const ENGLISH: Self = Self(*b"en");
+
+ /// Construct a language from a two-byte ISO 639-1 code.
+ pub fn from_str(iso: &str) -> Option<Self> {
+ let mut bytes: [u8; 2] = iso.as_bytes().try_into().ok()?;
+ bytes.make_ascii_lowercase();
+ Some(Self(bytes))
+ }
+
+ /// Return the language code as a string slice.
+ pub fn as_str(&self) -> &str {
+ std::str::from_utf8(&self.0).unwrap_or_default()
+ }
+
+ /// The default direction for the language.
+ pub fn dir(&self) -> Dir {
+ match self.as_str() {
+ "ar" | "dv" | "fa" | "he" | "ks" | "pa" | "ps" | "sd" | "ug" | "ur"
+ | "yi" => Dir::RTL,
+ _ => Dir::LTR,
+ }
+ }
+}
+
+castable! {
+ Lang,
+ Expected: "string",
+ Value::Str(string) => Self::from_str(&string)
+ .ok_or("expected two letter language code")?,
+}
diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs
index a25b2827..636b878c 100644
--- a/src/library/text/mod.rs
+++ b/src/library/text/mod.rs
@@ -1,6 +1,7 @@
//! Text handling and paragraph layout.
mod deco;
+mod lang;
mod link;
mod par;
mod quotes;
@@ -8,6 +9,7 @@ mod raw;
mod shaping;
pub use deco::*;
+pub use lang::*;
pub use link::*;
pub use par::*;
pub use quotes::*;
@@ -64,8 +66,7 @@ impl TextNode {
pub const BOTTOM_EDGE: TextEdge = TextEdge::Metric(VerticalFontMetric::Baseline);
/// An ISO 639-1 language code.
- #[property(referenced)]
- pub const LANG: Option<Lang> = None;
+ pub const LANG: Lang = Lang::ENGLISH;
/// The direction for text and inline objects. When `auto`, the direction is
/// automatically inferred from the language.
#[property(resolve)]
@@ -257,32 +258,6 @@ castable! {
}),
}
-/// A natural language.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct Lang(EcoString);
-
-impl Lang {
- /// The default direction for the language.
- pub fn dir(&self) -> Dir {
- match self.0.as_str() {
- "ar" | "dv" | "fa" | "he" | "ks" | "pa" | "ps" | "sd" | "ug" | "ur"
- | "yi" => Dir::RTL,
- _ => Dir::LTR,
- }
- }
-
- /// Return the language code as a string slice.
- pub fn as_str(&self) -> &str {
- &self.0
- }
-}
-
-castable! {
- Lang,
- Expected: "string",
- Value::Str(string) => Self(string.to_lowercase()),
-}
-
/// The direction of text and inline objects in their line.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct HorizontalDir(pub Dir);
@@ -301,10 +276,7 @@ impl Resolve for Smart<HorizontalDir> {
fn resolve(self, styles: StyleChain) -> Self::Output {
match self {
- Smart::Auto => match styles.get(TextNode::LANG) {
- Some(lang) => lang.dir(),
- None => Dir::LTR,
- },
+ Smart::Auto => styles.get(TextNode::LANG).dir(),
Smart::Custom(dir) => dir.0,
}
}
diff --git a/src/library/text/par.rs b/src/library/text/par.rs
index 19ab1082..232a5d0f 100644
--- a/src/library/text/par.rs
+++ b/src/library/text/par.rs
@@ -408,11 +408,7 @@ fn collect<'a>(
if styles.get(TextNode::SMART_QUOTES) {
// TODO: Also get region.
let lang = styles.get(TextNode::LANG);
- let quotes = lang
- .as_ref()
- .map(|lang| Quotes::from_lang(lang.as_str(), ""))
- .unwrap_or_default();
-
+ let quotes = Quotes::from_lang(lang.as_str(), "");
let peeked = iter.peek().and_then(|(child, _)| match child {
ParChild::Text(text) => text.chars().next(),
ParChild::Quote(_) => Some('"'),
@@ -750,7 +746,7 @@ fn breakpoints<'a>(p: &'a Preparation) -> Breakpoints<'a> {
end: 0,
mandatory: false,
hyphenate: p.get_shared(TextNode::HYPHENATE),
- lang: p.get_shared(TextNode::LANG).map(Option::as_ref),
+ lang: p.get_shared(TextNode::LANG),
}
}
@@ -773,7 +769,7 @@ struct Breakpoints<'a> {
/// Whether to hyphenate if it's the same for all children.
hyphenate: Option<bool>,
/// The text language if it's the same for all children.
- lang: Option<Option<&'a Lang>>,
+ lang: Option<Lang>,
}
impl Iterator for Breakpoints<'_> {
@@ -831,9 +827,9 @@ impl Breakpoints<'_> {
/// The text language at the given offset.
fn lang_at(&self, offset: usize) -> Option<hypher::Lang> {
- let lang = self.lang.unwrap_or_else(|| {
+ let lang = self.lang.or_else(|| {
let shaped = self.p.find(offset)?.text()?;
- shaped.styles.get(TextNode::LANG).as_ref()
+ Some(shaped.styles.get(TextNode::LANG))
})?;
let bytes = lang.as_str().as_bytes().try_into().ok()?;
diff --git a/tests/ref/text/linebreak.png b/tests/ref/text/linebreak.png
index 43ac9c68..4a691d72 100644
--- a/tests/ref/text/linebreak.png
+++ b/tests/ref/text/linebreak.png
Binary files differ
diff --git a/tests/typ/text/hyphenate.typ b/tests/typ/text/hyphenate.typ
index 6bb87b13..4dc5255f 100644
--- a/tests/typ/text/hyphenate.typ
+++ b/tests/typ/text/hyphenate.typ
@@ -6,13 +6,13 @@
#set page(width: auto)
#grid(
columns: (70pt, 60pt),
- text(lang: "en")[Warm welcomes to Typst.],
+ [Warm welcomes to Typst.],
text(lang: "el")[διαμερίσματα. \ λατρευτός],
)
---
// Test disabling hyphenation for short passages.
-#set text(lang: "en", hyphenate: true)
+#set text(hyphenate: true)
Welcome to wonderful experiences. \
Welcome to `wonderful` experiences. \
@@ -20,14 +20,14 @@ Welcome to #text(hyphenate: false)[wonderful] experiences. \
Welcome to wonde#text(hyphenate: false)[rf]ul experiences. \
// Test enabling hyphenation for short passages.
-#set text(lang: "en", hyphenate: false)
+#set text(hyphenate: false)
Welcome to wonderful experiences. \
Welcome to wo#text(hyphenate: true)[nd]erful experiences. \
---
// Hyphenate between shape runs.
#set page(width: 80pt)
-#set text(lang: "en", hyphenate: true)
+#set text(hyphenate: true)
It's a #emph[Tree]beard.
---
@@ -46,5 +46,5 @@ It's a #emph[Tree]beard.
// do that. The test passes if there's just one hyphenation between
// "net" and "works".
#set page(width: 70pt)
-#set text(lang: "en", hyphenate: true)
+#set text(hyphenate: true)
#h(6pt) networks, the rest.
diff --git a/tests/typ/text/justify.typ b/tests/typ/text/justify.typ
index 3659f8ef..0cdef000 100644
--- a/tests/typ/text/justify.typ
+++ b/tests/typ/text/justify.typ
@@ -1,7 +1,6 @@
---
#set page(width: 180pt)
-#set text(lang: "en")
#set par(
justify: true,
indent: 14pt,
diff --git a/tests/typ/text/knuth.typ b/tests/typ/text/knuth.typ
index 33249ef4..5adeee91 100644
--- a/tests/typ/text/knuth.typ
+++ b/tests/typ/text/knuth.typ
@@ -1,6 +1,6 @@
#set page(width: auto, height: auto)
#set par(leading: 4pt, justify: true)
-#set text(lang: "en", family: "Latin Modern Roman")
+#set text(family: "Latin Modern Roman")
#let story = [
In olden times when wishing still helped one, there lived a king whose
diff --git a/tests/typ/text/microtype.typ b/tests/typ/text/microtype.typ
index d3b47f6d..991e0d0d 100644
--- a/tests/typ/text/microtype.typ
+++ b/tests/typ/text/microtype.typ
@@ -4,7 +4,7 @@
// Test hanging punctuation.
#set page(width: 130pt, margins: 15pt)
#set par(justify: true, linebreaks: "simple")
-#set text(lang: "en", size: 9pt)
+#set text(size: 9pt)
#rect(fill: rgb(repr(teal) + "00"), width: 100%)[
This is a little bit of text that builds up to
hang-ing hyphens and dash---es and then, you know,
diff --git a/tests/typ/text/quotes.typ b/tests/typ/text/quotes.typ
index 3f0649e8..b447258f 100644
--- a/tests/typ/text/quotes.typ
+++ b/tests/typ/text/quotes.typ
@@ -24,12 +24,10 @@
---
// Test single pair of quotes.
-#set text(lang: "en")
""
---
// Test sentences with numbers and apostrophes.
-#set text(lang: "en")
The 5'11" 'quick' brown fox jumps over the "lazy" dog's ear.
He said "I'm a big fella."
@@ -40,7 +38,6 @@ The 5\'11\" 'quick\' brown fox jumps over the \"lazy" dog\'s ear.
---
// Test turning smart quotes off.
-#set text(lang: "en")
He's told some books contain questionable "example text".
#set text(smart-quotes: false)
@@ -48,7 +45,6 @@ He's told some books contain questionable "example text".
---
// Test changing properties within text.
-#set text(lang: "en")
"She suddenly started speaking french: #text(lang: "fr")['Je suis une banane.']" Roman told me.
Some people's thought on this would be #text(smart-quotes: false)["strange."]