fix: keep non-breaking spaces in text

Since the `u` flag was added to the whitespace regex in TextConverter
(7f03acf), `\s` also matches U+00A0, so ` ` and literal non-breaking
spaces were turned into regular spaces. Leave U+00A0 out of the collapse.

EmphasisConverter used trim(), which does not strip U+00A0, so a
non-breaking space at the edge of <em>/<strong> would now end up inside
the delimiters (`**Total:&nbsp;**`), where it stops them from flanking the
text. Strip it there too; like before, it becomes a regular space outside
the delimiters.

Fixes #258
This commit is contained in:
dualfroz committed 2026-10-03 02:31:49 +02:00
1 parent 87f03af20c
commit af172f8665
3 files changed
+18 -6

No files matched your search

+8 -4
View File
@@ -40,7 +40,11 @@ class EmphasisConverter implements ConverterInterface, ConfigurationAwareInterfa
$tag = $this->getNormTag($element);
$value = $element->getValue();
if (! \trim($value)) {
// Unlike trim(), this also strips non-breaking spaces, which would keep the delimiters from flanking the text
$content = \preg_replace('~^\s+|\s+$~u', '', $value);
\assert(\is_string($content));
if (! $content) {
return $value;
}
@@ -50,8 +54,8 @@ class EmphasisConverter implements ConverterInterface, ConfigurationAwareInterfa
$style = Coerce::toString($this->config->getOption('bold_style'));
}
$prefix = \ltrim($value) !== $value ? ' ' : '';
$suffix = \rtrim($value) !== $value ? ' ' : '';
$prefix = \preg_match('~^\s~u', $value) === 1 ? ' ' : '';
$suffix = \preg_match('~\s$~u', $value) === 1 ? ' ' : '';
/* If this node is immediately preceded or followed by one of the same type don't emit
* the start or end $style, respectively. This prevents <em>foo</em><em>bar</em> from
@@ -60,7 +64,7 @@ class EmphasisConverter implements ConverterInterface, ConfigurationAwareInterfa
$preStyle = $this->getNormTag($element->getPreviousSibling()) === $tag ? '' : $style;
$postStyle = $this->getNormTag($element->getNextSibling()) === $tag ? '' : $style;
return $prefix . $preStyle . \trim($value) . $postStyle . $suffix;
return $prefix . $preStyle . $content . $postStyle . $suffix;
}
/**
+2 -2
View File
@@ -15,8 +15,8 @@ class TextConverter implements ConverterInterface
// Remove leftover \n at the beginning of the line
$markdown = \ltrim($markdown, "\n");
// Replace sequences of invisible characters with spaces
$markdown = \preg_replace('~\s+~u', ' ', $markdown);
// Replace sequences of invisible characters with spaces, keeping non-breaking spaces
$markdown = \preg_replace('~[^\S\x{00A0}]+~u', ' ', $markdown);
\assert(\is_string($markdown));
// Escape the following characters: '*', '_', '[', ']' and '\'
+8
View File
@@ -378,6 +378,14 @@ EOT;
$this->assertHtmlGivesMarkdown('<code>&lt;p&gt;Some sample HTML&lt;/p&gt;</code>', '`<p>Some sample HTML</p>`');
}
public function testNonBreakingSpaces(): void
{
$this->assertHtmlGivesMarkdown('<p>This is a test and&nbsp;test</p>', "This is a test and\u{00A0}test");
$this->assertHtmlGivesMarkdown("<p>12,50\u{00A0}\u{00A0}€ \n total</p>", "12,50\u{00A0}\u{00A0}€ total");
$this->assertHtmlGivesMarkdown('<p><strong>Total:&nbsp;</strong>12,50&nbsp;€</p>', "**Total:** 12,50\u{00A0}€");
$this->assertHtmlGivesMarkdown('<p>a<em>&nbsp;</em>b</p>', "a\u{00A0}b");
}
public function testSetOption(): void
{
$markdown = new HtmlConverter();