Commit 67e542d
* fix(editor): preserve U+00A0 non-breaking space (#3037)
Non-breaking spaces were silently normalized to regular spaces at every
ingestion point, so typed/pasted/imported nbsps never reached the
changeset and users could not glue words against line-wrap in French or
other languages that require nbsp typography.
Removed the four strip sites that replaced U+00A0 with U+0020:
- src/node/db/Pad.ts cleanText
- src/static/js/contentcollector.ts textify
- src/static/js/ace2_inner.ts textify
- src/static/js/ace2_inner.ts importText raw-text guard
Updated both processSpaces functions (domline and ExportHtml) to tokenize
U+00A0 as a separate unit, emit it verbatim as , and treat it as
content (not whitespace) for the run-collapse bookkeeping so adjacent
regular-space runs aren't miscounted.
Added backend round-trip tests for spliceText and setText, and extended
the cleanText case table. Updated the existing contentcollector and
importexport specs whose expectations encoded the previous buggy
behavior; they now assert genuine nbsp preservation.
Verified manually in Firefox: clipboard U+00A0 → paste → pad → getText
returns c2 a0; getHTML emits `100 km`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(contentcollector): collapse display-artifact nbsp runs on DOM read-back
processSpaces is a lossy one-way display transform: leading/trailing
spaces and all-but-the-last of a run get rendered as so HTML
doesn't collapse them. When incorporateUserChanges reads text back from
the DOM, those display-artifact nbsps were being stored in the changeset
model instead of being normalized back to plain spaces.
This broke handleReturnIndentation, whose /^ *(?:)/ regex only matches
ASCII spaces: auto-indent after `foo:\n` produced 4 spaces instead of
the expected prev-indent (2) + THE_TAB (4) = 6, because the previous
line's model had nbsps where it used to have spaces.
Fix: in contentcollector.textify, collapse any [ ]+ run back to
plain spaces UNLESS the run is pure U+00A0 AND strictly interior to
word chars. That preserves user-intended typographic nbsps like
"100 km" while undoing the one-way display transform.
Updated 7 contentcollector tests and 7 importexport tests whose
assertions needed to reflect the new rule (boundary/mixed runs collapse;
pure-interior nbsp runs preserve).
Fixes the Playwright regression in indentation.spec.ts:117 that the
previous commit introduced.
* fix(contentcollector): canonicalize nbsp runs at line assembly, not per text node
Addresses Qodo code review feedback on PR #7585.
## Bug fix — nbsp lost at DOM text-node boundary
The previous approach ran the "collapse display-artifact nbsp" rule inside
textify(), which is called per individual DOM TEXT_NODE. A user-intended
nbsp sitting at a text-node boundary (e.g., <span>100</span><span> km
</span>) was incorrectly seen as non-interior (before === '' for the second
text node) and normalized back to a regular space.
Fix: move the canonicalization out of textify() and run it on each
fully assembled line string inside cc.finish(). The rule remains:
[ ]+ run -> plain spaces
UNLESS pure U+00A0 AND strictly interior to non-ws chars
It is length-preserving, so attribute offsets and line lengths are
unaffected.
Added a regression test (contentcollector.spec.ts) for the cross-span
case.
## Docs concern
Reverted the type-only addition of spliceText to PadType. spliceText
is an existing Pad runtime method; the backend test now uses a cast
(`(pad as any).spliceText`) so the PR does not expand the declared
public type surface, avoiding a separate documentation requirement.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent de5feb2 commit 67e542d
8 files changed
Lines changed: 85 additions & 17 deletions
File tree
- src
- node
- db
- utils
- static/js
- tests/backend/specs
- api
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | | - | |
55 | | - | |
| 54 | + | |
56 | 55 | | |
57 | 56 | | |
58 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
537 | 537 | | |
538 | 538 | | |
539 | 539 | | |
540 | | - | |
| 540 | + | |
541 | 541 | | |
542 | | - | |
543 | | - | |
| 542 | + | |
| 543 | + | |
544 | 544 | | |
545 | 545 | | |
546 | 546 | | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
547 | 550 | | |
548 | 551 | | |
549 | 552 | | |
| |||
578 | 581 | | |
579 | 582 | | |
580 | 583 | | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
581 | 587 | | |
582 | 588 | | |
583 | 589 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
476 | 476 | | |
477 | 477 | | |
478 | 478 | | |
479 | | - | |
480 | | - | |
| 479 | + | |
| 480 | + | |
481 | 481 | | |
482 | 482 | | |
483 | 483 | | |
| |||
2042 | 2042 | | |
2043 | 2043 | | |
2044 | 2044 | | |
2045 | | - | |
| 2045 | + | |
2046 | 2046 | | |
2047 | 2047 | | |
2048 | 2048 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
82 | | - | |
83 | 82 | | |
84 | 83 | | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
85 | 107 | | |
86 | 108 | | |
87 | 109 | | |
| |||
642 | 664 | | |
643 | 665 | | |
644 | 666 | | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
645 | 673 | | |
646 | 674 | | |
647 | 675 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
231 | 231 | | |
232 | 232 | | |
233 | 233 | | |
234 | | - | |
| 234 | + | |
235 | 235 | | |
236 | 236 | | |
237 | | - | |
| 237 | + | |
238 | 238 | | |
239 | 239 | | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
240 | 243 | | |
241 | 244 | | |
242 | 245 | | |
| |||
271 | 274 | | |
272 | 275 | | |
273 | 276 | | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
274 | 280 | | |
275 | 281 | | |
276 | 282 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
48 | 51 | | |
49 | 52 | | |
50 | 53 | | |
| |||
53 | 56 | | |
54 | 57 | | |
55 | 58 | | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
56 | 75 | | |
57 | 76 | | |
58 | 77 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
82 | | - | |
83 | | - | |
| 82 | + | |
| 83 | + | |
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
| |||
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
94 | | - | |
95 | | - | |
| 94 | + | |
| 95 | + | |
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
188 | | - | |
| 188 | + | |
189 | 189 | | |
190 | 190 | | |
191 | 191 | | |
| |||
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
200 | | - | |
| 200 | + | |
201 | 201 | | |
202 | 202 | | |
203 | 203 | | |
| |||
359 | 359 | | |
360 | 360 | | |
361 | 361 | | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
362 | 372 | | |
363 | 373 | | |
364 | 374 | | |
| |||
0 commit comments