diff --git a/crates/typst-library/src/layout/par.rs b/crates/typst-library/src/layout/par.rs index 235791052..d3cd6cbff 100644 --- a/crates/typst-library/src/layout/par.rs +++ b/crates/typst-library/src/layout/par.rs @@ -642,7 +642,7 @@ fn collect<'a>( }; if let Some(last) = full.chars().last() { - quoter.last(last); + quoter.last(last, child.is::()); } spans.push(segment.len(), child.span()); diff --git a/crates/typst-library/src/text/quotes.rs b/crates/typst-library/src/text/quotes.rs index bc3d00a06..cf4a03d5e 100644 --- a/crates/typst-library/src/text/quotes.rs +++ b/crates/typst-library/src/text/quotes.rs @@ -66,6 +66,8 @@ pub struct Quoter { expect_opening: bool, /// Whether the last character was numeric. last_num: bool, + /// The previous type of quote character, if it was an opening quote. + prev_quote_type: Option, } impl Quoter { @@ -75,13 +77,17 @@ impl Quoter { quote_depth: 0, expect_opening: true, last_num: false, + prev_quote_type: None, } } /// Process the last seen character. - pub fn last(&mut self, c: char) { + pub fn last(&mut self, c: char, is_quote: bool) { self.expect_opening = is_ignorable(c) || is_opening_bracket(c); self.last_num = c.is_numeric(); + if !is_quote { + self.prev_quote_type = None; + } } /// Process and substitute a quote. @@ -92,8 +98,16 @@ impl Quoter { peeked: Option, ) -> &'a str { let peeked = peeked.unwrap_or(' '); - if self.expect_opening { + let mut expect_opening = self.expect_opening; + if let Some(prev_double) = self.prev_quote_type.take() { + if double != prev_double { + expect_opening = true; + } + } + + if expect_opening { self.quote_depth += 1; + self.prev_quote_type = Some(double); quotes.open(double) } else if self.quote_depth > 0 && (peeked.is_ascii_punctuation() || is_ignorable(peeked)) diff --git a/tests/ref/text/quotes.png b/tests/ref/text/quotes.png index 8d3702b2e..757e7478d 100644 Binary files a/tests/ref/text/quotes.png and b/tests/ref/text/quotes.png differ diff --git a/tests/typ/text/quotes.typ b/tests/typ/text/quotes.typ index ec8c5e6ad..e8a56b4d5 100644 --- a/tests/typ/text/quotes.typ +++ b/tests/typ/text/quotes.typ @@ -60,3 +60,9 @@ He's told some books contain questionable "example text". "She suddenly started speaking french: #text(lang: "fr")['Je suis une banane.']" Roman told me. Some people's thought on this would be #[#set smartquote(enabled: false); "strange."] + +--- +// Test nested double and single quotes. +"'test statement'" \ +"'test' statement" \ +"statement 'test'"