Public buffer getChars and translateToString truncate multi-codepoint graphemes
@schickling-assistant is already working on this.
Since Oct 1, 2026.
- #201 by @schickling-assistant — open
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- typescript, wasm
Research direction
Start with Buffer.getLine(), BufferCell.getChars(), and translateToString(), then compare their scalar-cell handling with the existing viewport and scrollback grapheme accessors. Reproduce the examples with Bun 1.4.2 and verify that exported buffer text preserves each complete grapheme while retaining existing line snapshot behavior and empty wide-character spacer cells.
Written by the indexing model from the issue text.
Description
Problem
[email protected] public buffer getChars() and translateToString() truncate multi-codepoint graphemes. The real WASM core retains the complete text; this report is specifically about buffer export, not visible canvas rendering or parsing.
Minimal reproduction
After bun add [email protected], run with Bun 1.4.2:
import { Ghostty, Terminal } from 'ghostty-web'
const ghostty = await Ghostty.load()
for (const input of ['ASCII', 'é', '👩💻', '👋🏽', '🇺🇸']) {
const core = ghostty.createTerminal(24, 2)
const terminal = new Terminal({ ghostty, cols: 24, rows: 2 })
// Headless setup only: attach the real WASM core to the public buffer wrapper.
terminal.wasmTerm = core
core.write(input)
const line = terminal.buffer.active.getLine(0)
console.log({ input, buffer: line.translateToString(true),
firstCell: line.getCell(0).getChars(), core: core.getGraphemeString(0, 0) })
// Do not dispose these instances: teardown corruption is separately tracked in #141.
}
Expected: buffer export equals input. Actual: ASCII matches, but é becomes e, 👩💻 becomes 👩, 👋🏽 becomes 👋, and 🇺🇸 becomes 🇺. The low-level grapheme lookup returns complete text in every case. Reproduced on Linux x64.
Root cause / proposed fix
Buffer.getLine() only forwards scalar cells to BufferLine; BufferCell.getChars() uses String.fromCodePoint(cell.codepoint) without consulting grapheme_len or the existing viewport/scrollback grapheme accessors. translateToString() concatenates these truncated values.
Snapshot complete grapheme text alongside the scalar cells when creating a buffer line, using the appropriate viewport or scrollback lookup. This preserves existing line snapshot behavior and empty wide-character spacer cells.
Repeated open/closed issue and PR searches found no matching buffer-export report. Related but distinct: #141 tracks memory corruption when freeing terminals containing these graphemes; this is not a duplicate report for that teardown bug.
Posted on behalf of @schickling
| field | value |
|---|---|
agent_identity |
unknown |
session |
dev5.01a09047 |
agent_persona |
generalist |
agent_supervisor |
unavailable |
agent_tool |
OMP |
agent_tool_version |
18.4.4 |
agent_runtime |
OMP 18.4.4 |
agent_model |
anthropic/claude-opus-5-5 |
worktree |
dotfiles/main |
tooling_profile |
dotfiles@7a9494a |
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 182
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from coder/ghostty-web
-
buffer translateToString()/getChars() return '' for empty cells, collapsing cursor-positioned textOpen
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
coder/ghostty-web#205 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
coder/ghostty-web#204 ·
-
Alt+<printable key> sends the bare key with no ESC prefix (readline/emacs/tmux meta bindings lost)Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
coder/ghostty-web#203 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
coder/ghostty-web#199 ·
-
Difficulty 3/5 1-2 days Newbie friendliness 72/100
coder/ghostty-web#198 ·
All issues in coder/ghostty-web
Similar issues
-
enhancement
Difficulty 1/5 Under an hour Newbie friendliness 80/100
alunduil/projects-v2-sync#21 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
-
enhancement minor
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
testcontainers/testcontainers-node#1539 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
christopher-buss/eslint-plugin-flawless#72 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
openwatersio/slackwater-database#281 ·
Maintainers usually reply within 1 day