diff options
| author | +merlan #flirora <uruwi@protonmail.com> | 2024-07-14 09:48:40 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-14 13:48:40 +0000 |
| commit | 17ee3df1ba99183fc074e91dfba3e9189dae1c0c (patch) | |
| tree | f2b9f3ba7e437dc176fe4056f4689e5f8a012595 /crates | |
| parent | a3f3a1a83330e3fe9a686fbe4c0eda9f1e9e99b2 (diff) | |
Wrap outline entry body in LRE/RLE + make smart quotes ignore directional control characters (#4491)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/typst/src/layout/inline/collect.rs | 4 | ||||
| -rw-r--r-- | crates/typst/src/layout/inline/linebreak.rs | 5 | ||||
| -rw-r--r-- | crates/typst/src/layout/inline/mod.rs | 2 | ||||
| -rw-r--r-- | crates/typst/src/model/outline.rs | 8 | ||||
| -rw-r--r-- | crates/typst/src/text/mod.rs | 10 | ||||
| -rw-r--r-- | crates/typst/src/text/smartquote.rs | 6 |
6 files changed, 27 insertions, 8 deletions
diff --git a/crates/typst/src/layout/inline/collect.rs b/crates/typst/src/layout/inline/collect.rs index f1607460..b6a847f5 100644 --- a/crates/typst/src/layout/inline/collect.rs +++ b/crates/typst/src/layout/inline/collect.rs @@ -201,7 +201,7 @@ pub fn collect<'a>( ); let peeked = iter.peek().and_then(|(child, _)| { if let Some(elem) = child.to_packed::<TextElem>() { - elem.text().chars().next() + elem.text().chars().find(|c| !is_default_ignorable(*c)) } else if child.is::<SmartQuoteElem>() { Some('"') } else if child.is::<SpaceElem>() @@ -302,7 +302,7 @@ impl<'a> Collector<'a> { } fn push_segment(&mut self, segment: Segment<'a>, is_quote: bool) { - if let Some(last) = self.full.chars().last() { + if let Some(last) = self.full.chars().rev().find(|c| !is_default_ignorable(*c)) { self.quoter.last(last, is_quote); } diff --git a/crates/typst/src/layout/inline/linebreak.rs b/crates/typst/src/layout/inline/linebreak.rs index 9deaa92a..075d24b3 100644 --- a/crates/typst/src/layout/inline/linebreak.rs +++ b/crates/typst/src/layout/inline/linebreak.rs @@ -953,3 +953,8 @@ where } } } + +/// Whether a codepoint is Unicode `Default_Ignorable`. +pub fn is_default_ignorable(c: char) -> bool { + DEFAULT_IGNORABLE_DATA.as_borrowed().contains(c) +} diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs index f89de169..821b4f57 100644 --- a/crates/typst/src/layout/inline/mod.rs +++ b/crates/typst/src/layout/inline/mod.rs @@ -10,7 +10,7 @@ use comemo::{Track, Tracked, TrackedMut}; use self::collect::{collect, Item, Segment, SpanMapper}; use self::finalize::finalize; use self::line::{commit, line, Line}; -use self::linebreak::{linebreak, Breakpoint}; +use self::linebreak::{is_default_ignorable, linebreak, Breakpoint}; use self::prepare::{prepare, Preparation}; use self::shaping::{ cjk_punct_style, is_of_cj_script, shape_range, ShapedGlyph, ShapedText, diff --git a/crates/typst/src/model/outline.rs b/crates/typst/src/model/outline.rs index 09047285..ec1e5f1b 100644 --- a/crates/typst/src/model/outline.rs +++ b/crates/typst/src/model/outline.rs @@ -483,7 +483,7 @@ impl OutlineEntry { impl Show for Packed<OutlineEntry> { #[typst_macros::time(name = "outline.entry", span = self.span())] - fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut seq = vec![]; let elem = self.element(); @@ -500,7 +500,11 @@ impl Show for Packed<OutlineEntry> { }; // The body text remains overridable. - seq.push(self.body().clone().linked(Destination::Location(location))); + crate::text::isolate( + self.body().clone().linked(Destination::Location(location)), + styles, + &mut seq, + ); // Add filler symbols between the section name and page number. if let Some(filler) = self.fill() { diff --git a/crates/typst/src/text/mod.rs b/crates/typst/src/text/mod.rs index 7648f08f..d42e4df8 100644 --- a/crates/typst/src/text/mod.rs +++ b/crates/typst/src/text/mod.rs @@ -1299,3 +1299,13 @@ cast! { ret }, } + +/// Pushes `text` wrapped in LRE/RLE + PDF to `out`. +pub(crate) fn isolate(text: Content, styles: StyleChain, out: &mut Vec<Content>) { + out.push(TextElem::packed(match TextElem::dir_in(styles) { + Dir::RTL => "\u{202B}", + _ => "\u{202A}", + })); + out.push(text); + out.push(TextElem::packed("\u{202C}")); +} diff --git a/crates/typst/src/text/smartquote.rs b/crates/typst/src/text/smartquote.rs index 236d0636..797f0804 100644 --- a/crates/typst/src/text/smartquote.rs +++ b/crates/typst/src/text/smartquote.rs @@ -123,7 +123,7 @@ impl SmartQuoter { /// Process the last seen character. pub fn last(&mut self, c: char, is_quote: bool) { - self.expect_opening = is_ignorable(c) || is_opening_bracket(c); + self.expect_opening = is_exterior_to_quote(c) || is_opening_bracket(c); self.last_num = c.is_numeric(); if !is_quote { self.prev_quote_type = None; @@ -150,7 +150,7 @@ impl SmartQuoter { self.prev_quote_type = Some(double); quotes.open(double) } else if self.quote_depth > 0 - && (peeked.is_ascii_punctuation() || is_ignorable(peeked)) + && (peeked.is_ascii_punctuation() || is_exterior_to_quote(peeked)) { self.quote_depth -= 1; quotes.close(double) @@ -168,7 +168,7 @@ impl Default for SmartQuoter { } } -fn is_ignorable(c: char) -> bool { +fn is_exterior_to_quote(c: char) -> bool { c.is_whitespace() || is_newline(c) } |
