Skip to content

Commit 992504e

Browse files
authored
Fix NO-BREAK SPACE (U+00A0) column width calculation (#448)
* Fix NO-BREAK SPACE (U+00A0) column width calculation The condition `irune <= 0xA0` incorrectly treated U+00A0 (NO-BREAK SPACE) as non-printable, returning width -1. This caused cursor positioning issues in applications that use NBSP in their output. Changed to `irune < 0xA0` so that NO-BREAK SPACE correctly returns width 1 (handled by the default case at end of function), matching the behavior of regular space (U+0020). * Add test for NO-BREAK SPACE (U+00A0) width Verifies that NBSP has width 1 and cursor positioning works correctly when NBSP is used (e.g., after prompt characters like in Claude Code).
1 parent a48c5da commit 992504e

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

Sources/SwiftTerm/Utilities.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,9 @@ struct UnicodeUtil {
331331
if irune < 0x7f {
332332
return 1
333333
}
334-
// more non-printable characters
335-
if irune <= 0xA0 {
334+
// C1 control characters (0x7F-0x9F) return -1
335+
// Note: 0xA0 (NO-BREAK SPACE) is excluded - it should have width 1
336+
if irune < 0xA0 {
336337
return -1
337338
}
338339
// if irune < 127 {

Tests/SwiftTermTests/UnicodeTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,5 +274,30 @@ final class SwiftTermUnicode {
274274
#expect(line == "\(sequence)X")
275275
}
276276

277+
@Test func testNoBreakSpaceWidth() {
278+
let h = HeadlessTerminal (queue: SwiftTermTests.queue) { exitCode in }
279+
let t = h.terminal!
280+
281+
// Test NO-BREAK SPACE (U+00A0) positioning
282+
// NBSP should have width 1, same as regular space
283+
// This is important for applications like Claude Code that use NBSP after prompt
284+
t.feed (text: ">\u{00A0}x") // > + NBSP + x
285+
286+
// '>' at col 0 (width 1)
287+
#expect(t.getCharacter(col: 0, row: 0) == ">")
288+
#expect(t.getCharData(col: 0, row: 0)?.width == 1)
289+
290+
// NBSP at col 1 (width 1, NOT -1)
291+
#expect(t.getCharacter(col: 1, row: 0) == "\u{00A0}")
292+
#expect(t.getCharData(col: 1, row: 0)?.width == 1)
293+
294+
// 'x' at col 2 (width 1)
295+
#expect(t.getCharacter(col: 2, row: 0) == "x")
296+
#expect(t.getCharData(col: 2, row: 0)?.width == 1)
297+
298+
// Cursor should be at column 3
299+
#expect(t.buffer.x == 3)
300+
}
301+
277302
}
278303
#endif

0 commit comments

Comments
 (0)