add Terminal.writeBytes with a persistent UTF-8 decoder (T-373)
The terminal's only ingestion API was write(String), so both byte consumers decoded per chunk — a multi-byte rune split across PTY reads (or a tail window starting mid-character, which FileTailFollower does by construction) rendered as U+FFFD garbage. writeBytes feeds a per-instance chunked Utf8Decoder that carries partial-rune state across calls; the terminal pane and the Bash live-tail follower now use it, and write(String) stays for tests and programmatic writes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
/// dependency.
|
||||
library;
|
||||
|
||||
import 'dart:convert' show utf8;
|
||||
|
||||
import 'package:clide/src/terminal/src/core/buffer/cell_offset.dart';
|
||||
import 'package:clide/src/terminal/src/core/input/keys.dart';
|
||||
import 'package:clide/src/terminal/src/core/mouse/button.dart';
|
||||
@@ -121,6 +123,29 @@ void main() {
|
||||
t.write('\x1b[31mred'); // SGR red foreground
|
||||
expect(t.cursor.foreground, isNot(0)); // foreground was set
|
||||
});
|
||||
|
||||
// T-373: byte consumers used to utf8.decode per chunk — a rune split
|
||||
// across PTY reads rendered as U+FFFD garbage.
|
||||
test('writeBytes joins a multi-byte rune split across two calls', () {
|
||||
final t = _Recorder().build();
|
||||
final euro = utf8.encode('€'); // 3 bytes: E2 82 AC
|
||||
t.writeBytes(euro.sublist(0, 1));
|
||||
t.writeBytes(euro.sublist(1));
|
||||
expect(t.buffer.lines[0].getCodePoint(0), '€'.codeUnitAt(0));
|
||||
});
|
||||
|
||||
test('writeBytes decodes consecutive whole chunks like write', () {
|
||||
final t = _Recorder().build();
|
||||
t.writeBytes(utf8.encode('héllo'));
|
||||
final line = [for (var i = 0; i < 5; i++) t.buffer.lines[0].getCodePoint(i)];
|
||||
expect(String.fromCharCodes(line), 'héllo');
|
||||
});
|
||||
|
||||
test('writeBytes with an empty chunk is a no-op', () {
|
||||
final t = _Recorder().build();
|
||||
t.writeBytes(const []);
|
||||
expect(t.buffer.cursorX, 0);
|
||||
});
|
||||
});
|
||||
|
||||
group('Terminal — keyInput', () {
|
||||
|
||||
Reference in New Issue
Block a user