Skip to content

Fix split wide characters when overlapping writes occur#930

Merged
sindresorhus merged 1 commit into
vadimdemedes:masterfrom
RyogaK:fix/cjk-overlay-split
Apr 4, 2026
Merged

Fix split wide characters when overlapping writes occur#930
sindresorhus merged 1 commit into
vadimdemedes:masterfrom
RyogaK:fix/cjk-overlay-split

Conversation

@RyogaK

@RyogaK RyogaK commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • When two elements overlap in the output grid (via position="absolute", negative margins, etc.) and the write lands in the middle of a wide (CJK) character, one half of the character was left behind, corrupting terminal output
  • Add left/right boundary checks in Output.write() to replace orphaned halves of wide characters with a space
  • Skip boundary cleanup when the line is empty (e.g. clipped away) to avoid corrupting cells that aren't actually being overwritten

Fixes #929

Design note

When a wide character is partially overwritten, the orphaned cell is replaced with a half-width space. This matches the behavior of vim, tmux, and less, which all replace a split wide character with a space to keep column alignment intact.

Test plan

  • overlay on 2nd cell of CJK character clears the full character — overlay at column 9 (trailing cell of ) replaces with a space
  • overlay on 1st cell of CJK character clears trailing placeholder — overlay at column 10 (leading cell of ) clears orphaned placeholder
  • CJK overlay on 2nd cell of CJK clears both sides — wide overlay spans multiple CJK characters, both boundary characters are cleaned up
  • clipped empty write does not corrupt existing wide characters — a write clipped to nothing does not mutate surrounding cells
  • All existing overflow and text-width tests pass

@RyogaK RyogaK force-pushed the fix/cjk-overlay-split branch from f16886a to e910609 Compare April 3, 2026 20:42
@sindresorhus

Copy link
Copy Markdown
Collaborator

I think this introduces a small regression.

If horizontal clipping slices the incoming write down to an empty string, the new boundary cleanup still runs and mutates the existing wide character even though nothing is actually being written. I manually verified this with a clipped write that should be a no-op:

const output = new Output({width: 4, height: 1});
output.write(0, 0, 'あい', {transformers: []});
output.clip({x1: 1, x2: 1, y1: undefined, y2: undefined});
output.write(0, 0, 'Z', {transformers: []});
output.unclip();

On master the result stays あい. On this branch it becomes , because the clipped write turns into '' but the left/right cleanup still runs anyway.

So I think this needs a guard to skip the cleanup when the sliced line is empty, plus a regresion test for that case.

@RyogaK RyogaK force-pushed the fix/cjk-overlay-split branch 3 times, most recently from 6f52b2b to a54cc8a Compare April 4, 2026 12:42
When two elements overlap in the output grid (e.g. via position="absolute"
or negative margins) and the write lands in the middle of a wide (CJK)
character, one half of the character was left behind, corrupting terminal
output.

Add boundary checks in Output.write() to replace orphaned halves with a
space:
- Left edge: if the first cell is a trailing placeholder, clear its
  leading cell.
- Right edge: if the cell just past the write range is an orphaned
  trailing placeholder, clear it.

Fixes #929
@RyogaK RyogaK force-pushed the fix/cjk-overlay-split branch from a54cc8a to cbab8de Compare April 4, 2026 14:25
@RyogaK

RyogaK commented Apr 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for catching that. Fixed in cbab8de:

  • Added an early continue when the line has no characters to write (e.g. clipped to empty), so the boundary cleanup is skipped entirely.
  • Added a regression test (clipped empty write does not corrupt existing wide characters) that verifies a clipped no-op write leaves existing wide characters intact.

@sindresorhus sindresorhus merged commit 06d53f4 into vadimdemedes:master Apr 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Overlapping write on wide (CJK) character splits it, corrupting terminal output

2 participants