Skip to content

Never split an emoji at the edge of a find snippet or a cut read - #120

Merged
only-cli merged 1 commit into
only-cli:mainfrom
kevin9327:fix/find-snippet-keeps-emoji-whole
Sep 28, 2026
Merged

only-cli merged 1 commit into
only-cli:mainfrom
kevin9327:fix/find-snippet-keeps-emoji-whole

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

#115 stopped the compact view's cap from printing half of a character past U+FFFF. Two other cuts in src/act.js count UTF-16 units the same way and still split one:

  • find's snippet window (search) opens 60 units before the match and runs 200.
  • read's cut of a first block bigger than its whole budget stops at budget * 4 units.

Either edge can land between the two halves of an emoji, and the line then carries a lone surrogate, which a terminal prints as �. A block with the match 60 units after an emoji, and another emoji 200 units on, printed as oc find needle on a page with enough matches to use snippets:

main:   "[1] ... \ude00xxx...needleyyy...\ud83d ..."   isWellFormed: false
branch: "[1] ... 😀xxx...needleyyy... ..."             isWellFormed: true

Change. Each edge steps back one unit when it would land between the halves, the rule render.js already uses at the cap. The snippet's opening edge so takes the whole emoji, and its closing edge and read's cut leave it out. The window width, the ... markers, and the read budget are otherwise unchanged.

Test. tests/act.test.js gains one test covering both: a snippet whose window opens and closes inside an emoji, and a read --budget 10 whose cut at character 40 lands inside one. On main the snippet half fails; with only the snippet fixed, the read half still fails (xxx\ud83d ... cut at ~10 tokens), so each half guards its own edge. Full suite on Windows (Node 24): 316 tests, 313 pass, 3 skipped, 0 fail.

Left alone. The JSON view's same on every item line also cuts a value at 60 units (v.slice(0, 60) in jsonToHTML). It is a different view, so I kept it out of this change. No CHANGELOG line, to keep this round's PRs from conflicting there.

🤖 Generated with Claude Code

only-cli#115 stopped the compact view's cap from printing half of a character
past U+FFFF. Two other cuts count UTF-16 units the same way and were
left as they were: find's snippet window, which opens 60 units before
the match and runs 200, and read's cut of a first block bigger than its
whole budget, at budget * 4 units. Either edge can land between the two
halves of an emoji, and then the line carries a lone surrogate, which a
terminal prints as the replacement character.

Each edge now steps back one unit when it would land there, the rule
render.js already uses. A snippet's opening edge so takes the whole
emoji, and its closing edge and read's cut leave it out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@only-cli
only-cli merged commit 7e683e4 into only-cli:main Sep 28, 2026
5 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.

2 participants