From 5aff804d348175bd5f71057b395874e15282d4ab Mon Sep 17 00:00:00 2001 From: AdamMagued Date: Fri, 2 Oct 2026 21:00:51 +0000 Subject: [PATCH] fix: enable IUTF8 input flag by default on darwin pseudo-terminals Set the IUTF8 flag in termios iflag on darwin when opening a pseudo-terminal. Without IUTF8, the Darwin terminal driver line discipline deletes single bytes instead of whole UTF-8 characters when backspace/delete (0x7f) is sent, resulting in mangled multibyte characters in canonical mode. Fixes #138 --- pty_darwin.go | 7 +++++++ pty_darwin_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 pty_darwin_test.go diff --git a/pty_darwin.go b/pty_darwin.go index 91efb14..6e627bc 100644 --- a/pty_darwin.go +++ b/pty_darwin.go @@ -40,6 +40,13 @@ func open() (pty, tty *os.File, err error) { if err != nil { return nil, nil, err } + + var tios syscall.Termios + if err := ioctl(t, syscall.TIOCGETA, unsafe.Pointer(&tios)); err == nil { + tios.Iflag |= syscall.IUTF8 + _ = ioctl(t, syscall.TIOCSETA, unsafe.Pointer(&tios)) + } + return p, t, nil } diff --git a/pty_darwin_test.go b/pty_darwin_test.go new file mode 100644 index 0000000..2c636b9 --- /dev/null +++ b/pty_darwin_test.go @@ -0,0 +1,29 @@ +//go:build darwin +// +build darwin + +package pty + +import ( + "bufio" + "testing" +) + +func TestDarwinIUTF8(t *testing.T) { + t.Parallel() + + pty, tty := openClose(t) + + // Write multibyte UTF-8 characters followed by Delete (0x7f) and a newline. + // With IUTF8 enabled, erasing deletes the entire multibyte character rather than only the final byte. + const input = "小明\x7f\n" + n, err := pty.WriteString(input) + noError(t, err, "Unexpected error writing input") + assert(t, len(input), n, "Unexpected count returned from WriteString") + + r := bufio.NewReader(tty) + line, err := r.ReadString('\n') + noError(t, err, "Unexpected error reading from tty") + + expected := "小\n" + assert(t, expected, line, "Expected multibyte character to be deleted cleanly") +}