summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-10-02 13:51:09 +0200
committerGitHub <noreply@github.com>2024-10-02 11:51:09 +0000
commitfcdccc9cbae02be0ac61f5f50f7f1a256fdd2b11 (patch)
tree671065febf3d6474c0d94f27a90c1fd927847414
parentb791aede82cc1424ba38b74200193096390ceecd (diff)
Fix textual grouping (#5097)
-rw-r--r--crates/typst/src/realize.rs51
-rw-r--r--tests/ref/show-text-in-citation.pngbin0 -> 795 bytes
-rw-r--r--tests/suite/styling/show-text.typ12
3 files changed, 38 insertions, 25 deletions
diff --git a/crates/typst/src/realize.rs b/crates/typst/src/realize.rs
index f999bfd4..7c199ff1 100644
--- a/crates/typst/src/realize.rs
+++ b/crates/typst/src/realize.rs
@@ -873,40 +873,41 @@ const fn list_like_grouping<T: ListLike>() -> GroupingRule {
/// as part of a paragraph grouping,
/// - if that's not possible because another grouping is active, temporarily
/// disables textual grouping and revisits the elements.
-fn finish_textual(Grouped { s, start }: Grouped) -> SourceResult<()> {
- // Try to find a regex match in the grouped textual elements.
+fn finish_textual(Grouped { s, mut start }: Grouped) -> SourceResult<()> {
+ // Try to find a regex match in the grouped textual elements. Returns early
+ // if there is one.
if visit_textual(s, start)? {
return Ok(());
}
- // No regex match.
- match s.groupings.last() {
- // Transparently apply the grouped content to an active paragraph. This
- // is more efficient than revisiting everything. Checking the priority
- // is a bit of a hack, but the simplest way to check which rule is
- // active for now.
- Some(grouping) if std::ptr::eq(grouping.rule, &PAR) => {}
-
- // Start a new paragraph based on this textual group.
- None => s.groupings.push(Grouping { rule: &PAR, start }),
-
- // If a non-paragraph grouping is top-level, revisit the grouped
- // content with the `TEXTUAL` rule disabled.
- _ => {
- let elems = s.store_slice(&s.sink[start..]);
- let rules = s.rules;
- s.sink.truncate(start);
- s.rules = &s.rules[1..];
- for &(content, styles) in &elems {
- visit(s, content, styles)?;
- }
- s.rules = rules;
- }
+ // There was no regex match, so we need to collect the text into a paragraph
+ // grouping. To do that, we first terminate all non-paragraph groupings.
+ if in_non_par_grouping(s) {
+ let elems = s.store_slice(&s.sink[start..]);
+ s.sink.truncate(start);
+ finish_grouping_while(s, in_non_par_grouping)?;
+ start = s.sink.len();
+ s.sink.extend(elems);
+ }
+
+ // Now, there are only two options:
+ // 1. We are already in a paragraph group. In this case, the elements just
+ // transparently become part of it.
+ // 2. There is no group at all. In this case, we create one.
+ if s.groupings.is_empty() {
+ s.groupings.push(Grouping { start, rule: &PAR });
}
Ok(())
}
+/// Whether there is an active grouping, but it is not a `PAR` grouping.
+fn in_non_par_grouping(s: &State) -> bool {
+ s.groupings
+ .last()
+ .is_some_and(|grouping| !std::ptr::eq(grouping.rule, &PAR))
+}
+
/// Builds the `ParElem` from inline-level elements.
fn finish_par(mut grouped: Grouped) -> SourceResult<()> {
// Collapse unsupported spaces in-place.
diff --git a/tests/ref/show-text-in-citation.png b/tests/ref/show-text-in-citation.png
new file mode 100644
index 00000000..392487bc
--- /dev/null
+++ b/tests/ref/show-text-in-citation.png
Binary files differ
diff --git a/tests/suite/styling/show-text.typ b/tests/suite/styling/show-text.typ
index 4e031648..af45127c 100644
--- a/tests/suite/styling/show-text.typ
+++ b/tests/suite/styling/show-text.typ
@@ -162,6 +162,18 @@ hi
#show bibliography: none
#bibliography("/assets/bib/works.bib")
+--- show-text-in-citation ---
+#show "A": "B"
+#show "[": "("
+#show "]": ")"
+#show "[2]": set text(red)
+
+@netwok A \
+@arrgh B
+
+#show bibliography: none
+#bibliography("/assets/bib/works.bib")
+
--- show-text-linebreak ---
#show "lo\nwo": set text(red)
Hello #[ ] \