summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-04-13 15:01:19 +0200
committerLaurenz <laurmaedje@gmail.com>2022-04-13 15:01:19 +0200
commitd025854457b4c2d1c2285bd1c5e795edad79a749 (patch)
tree1375d365a9b9c8981ef7e95708911cc4190dc2f0 /src/library
parent67e9313b9127b70b9d7dad6540853025ae90b4a5 (diff)
Make language non-optional with english as default
Diffstat (limited to 'src/library')
-rw-r--r--src/library/text/lang.rs39
-rw-r--r--src/library/text/mod.rs36
-rw-r--r--src/library/text/par.rs14
3 files changed, 48 insertions, 41 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()?;