Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Nested group's suffixes may get trimmed #411

@YDX-2147483647

Description

@YDX-2147483647

For the following CSL, you would expect the result to be prefix.prefix.Text.anything-suffix.suffix..
But in Typst v0.14.0-rc.2, it is prefix.prefix.Text.anything-suffix., where the outer suffix is neglected.

<layout>
  <group prefix="prefix." suffix="suffix.">
    <group prefix="prefix." suffix="anything-suffix.">
      <text value="Text." />
    </group>
  </group>
</layout>
Full CSL
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0"
  demote-non-dropping-particle="never">
  <!-- This style was edited with the Visual CSL Editor
  (https://editor.citationstyles.org/visualEditor/) -->
  <info>
    <title>No Title</title>
    <id>http://www.zotero.org/styles/no-title</id>
    <link rel="self" href="http://www.zotero.org/styles/no-title" />
    <updated>2025-10-24T00:51:54+00:00</updated>
  </info>
  <citation>
    <layout>
      <text value="" />
    </layout>
  </citation>
  <bibliography>
    <layout>
      <group prefix="prefix." suffix="suffix.">
        <group prefix="prefix." suffix="anything-suffix.">
          <text value="Text." />
        </group>
      </group>
    </layout>
  </bibliography>
</style>

Cause

If apply_suffix function sees the text is already ended with the suffix, it will not do suffix.

hayagriva/src/csl/mod.rs

Lines 2798 to 2815 in 799cfdc

/// Apply a suffix, but only if the location was followed by something.
/// Delete any prefix if not.
fn apply_suffix(&mut self, affixes: &Affixes, loc: (DisplayLoc, usize)) {
if !self.writing.has_content_since(&loc) {
self.discard_elem(loc.0);
} else {
if let Some(suffix) = &affixes.suffix {
let do_suffix = if !self.writing.buf.is_empty() {
!self.writing.buf.as_string_mut().ends_with(suffix.as_str())
} else if let Some(l) = self.writing.elem_stack.last_mut().last_text() {
!l.text.ends_with(suffix)
} else {
true
};
if do_suffix {
self.push_str(suffix);
}

This code dates back to 2023-10 (01c5f39, #66).

Debug

Simply deleting the logic (let do_suffix = true) will fail two tests (but no new passes).

❌ Test bugreports_AsmJournals should pass but failed (Expected: <b>Doe Co.</b>, Got: <b>Doe Co</b>.)
❌ Test bugreports_UndefinedNotString should pass but failed (Expected: <b>n.d.</b>, Got: <b>n.d</b>.)

Test target/haya-cache/test-suite/processor-tests/humans/bugreports_AsmJournals.txt failed
Expected:
<div class="csl-bib-body">
  <div class="csl-entry">
    <div class="csl-left-margin">1. </div><div class="csl-right-inline"><b>Doe Co.</b> 1965. His Collectively Anonymous Life.</div>
  </div>
</div>

Got:
<div class="csl-bib-body"><div class="csl-entry"><div class="csl-left-margin">1. </div><div class="csl-right-inline"><b>Doe Co</b>. 1965. His Collectively Anonymous Life.</div></div></div>
Test target/haya-cache/test-suite/processor-tests/humans/bugreports_UndefinedNotString.txt failed
Expected:
<div class="csl-bib-body">
  <div class="csl-entry">
    <div class="csl-left-margin">[1]</div><div class="csl-right-inline"><i>FOO BAR</i> <b>n.d.</b></div>
  </div>
</div>

Got:
<div class="csl-bib-body"><div class="csl-entry"><div class="csl-left-margin">[1]</div><div class="csl-right-inline"><i>FOO BAR</i> <b>n.d</b>.</div></div></div>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions