Wrap outline entry body in LRE/RLE + make smart quotes ignore directional control characters (#4491)

Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
+merlan #flirora 2024-07-14 09:48:40 -04:00 committed by GitHub
parent a3f3a1a833
commit 17ee3df1ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 39 additions and 8 deletions

View File

@ -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);
}

View File

@ -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)
}

View File

@ -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,

View File

@ -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() {

View File

@ -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}"));
}

View File

@ -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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

View File

@ -176,3 +176,10 @@ Ok ...
// Error: 2-55 heading must have a location
// Hint: 2-55 try using a query or a show rule to customize the outline.entry instead
#outline.entry(1, heading[Hello], [World!], none, [1])
--- issue-4476-rtl-title-ending-in-ltr-text ---
#set text(lang: "he")
#outline()
= הוקוס Pocus
= זוהי כותרת שתורגמה על ידי מחשב

View File

@ -69,6 +69,11 @@ Some people's thought on this would be #[#set smartquote(enabled: false); "stran
"'test' statement" \
"statement 'test'"
--- smartquote-with-embedding-chars ---
#set text(lang: "fr")
"#"\u{202A}"bonjour#"\u{202C}"" \
#"\u{202A}""bonjour"#"\u{202C}"
--- smartquote-custom ---
// Use language quotes for missing keys, allow partial reset
#set smartquote(quotes: "«»")