diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-04-13 15:01:19 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-04-13 15:01:19 +0200 |
| commit | d025854457b4c2d1c2285bd1c5e795edad79a749 (patch) | |
| tree | 1375d365a9b9c8981ef7e95708911cc4190dc2f0 /src/library | |
| parent | 67e9313b9127b70b9d7dad6540853025ae90b4a5 (diff) | |
Make language non-optional with english as default
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/text/lang.rs | 39 | ||||
| -rw-r--r-- | src/library/text/mod.rs | 36 | ||||
| -rw-r--r-- | src/library/text/par.rs | 14 |
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()?; |
