Skip to content

Commit 4fc70a7

Browse files
committed
fix(tui): wire ProgramOptions output
Pass the configured output callback into the built-in stdio display terminal so all terminal writes and flushes are redirected as documented. Preserve the controlling TTY for inputTTY mode and cover the callback behavior. Fixes #6
1 parent 27da33f commit 4fc70a7

6 files changed

Lines changed: 43 additions & 8 deletions

File tree

pkgs/artisanal/lib/src/platform/platform_io.dart

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,20 @@ Future<({int exitCode, String stdout, String stderr})?> runProcess(
8181
}
8282
}
8383

84-
Terminal createDefaultTerminal({bool inputTTY = false}) {
84+
Terminal createDefaultTerminal({
85+
bool inputTTY = false,
86+
void Function(String)? output,
87+
}) {
8588
if (inputTTY) {
8689
final control = TtyTerminal.tryOpen();
8790
if (control != null) {
88-
return SplitTerminal(control: control, output: StdioTerminal());
91+
return SplitTerminal(
92+
control: control,
93+
output: StdioTerminal(output: output),
94+
);
8995
}
9096
}
91-
return StdioTerminal();
97+
return StdioTerminal(output: output);
9298
}
9399

94100
Stream<List<int>>? ttyOpenRead() {

pkgs/artisanal/lib/src/platform/platform_stub.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ Future<({int exitCode, String stdout, String stderr})?> runProcess(
3030
Map<String, String>? environment,
3131
}) async => null;
3232

33-
Terminal createDefaultTerminal({bool inputTTY = false}) =>
34-
throw UnsupportedError('Default terminal requires dart:io');
33+
Terminal createDefaultTerminal({
34+
bool inputTTY = false,
35+
void Function(String)? output,
36+
}) => throw UnsupportedError('Default terminal requires dart:io');
3537

3638
Stream<List<int>>? ttyOpenRead() => null;
3739

pkgs/artisanal/lib/src/terminal/terminal_io_impl.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,18 @@ class StdioTerminal implements Terminal {
1616
///
1717
/// If [stdout] or [stdin] are not provided, uses the process's
1818
/// standard streams.
19-
StdioTerminal({io.Stdout? stdout, io.Stdin? stdin})
19+
StdioTerminal({io.Stdout? stdout, io.Stdin? stdin, this.output})
2020
: _stdout = stdout ?? io.stdout,
2121
_stdin = stdin ?? io.stdin;
2222

2323
final io.Stdout _stdout;
2424
final io.Stdin _stdin;
2525

26+
/// Optional sink for terminal bytes.
27+
///
28+
/// When provided, writes are redirected here instead of process stdout.
29+
final void Function(String)? output;
30+
2631
// Stdout flush in Dart binds the underlying StreamSink; any concurrent write
2732
// while a flush is in flight will throw:
2833
// StateError: Bad state: StreamSink is bound to a stream
@@ -94,6 +99,11 @@ class StdioTerminal implements Terminal {
9499
@override
95100
void write(String text) {
96101
if (text.isEmpty) return;
102+
final sink = output;
103+
if (sink != null) {
104+
sink(text);
105+
return;
106+
}
97107
if (_stdoutFlushInFlight != null) {
98108
_stdoutPending.write(text);
99109
_stdoutPendingLen += text.length;
@@ -118,6 +128,7 @@ class StdioTerminal implements Terminal {
118128

119129
@override
120130
Future<void> flush() {
131+
if (output != null) return Future<void>.value();
121132
final existing = _stdoutFlushInFlight;
122133
if (existing != null) return existing;
123134

pkgs/artisanal/lib/src/terminal/terminal_io_stub.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ import 'terminal_base.dart';
66
/// Web-safe API stub for the native stdio terminal implementation.
77
class StdioTerminal extends StringTerminal {
88
/// Creates a stub terminal on platforms without `dart:io`.
9-
StdioTerminal({Object? stdout, Object? stdin});
9+
StdioTerminal({Object? stdout, Object? stdin, void Function(String)? output});
1010
}

pkgs/artisanal/lib/src/tui/program.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1602,7 +1602,10 @@ class Program<M extends Model> with HotReloadMixin {
16021602

16031603
/// Sets up the terminal and renderer.
16041604
Future<void> _setup() async {
1605-
_terminal ??= platform.createDefaultTerminal(inputTTY: _options.inputTTY);
1605+
_terminal ??= platform.createDefaultTerminal(
1606+
inputTTY: _options.inputTTY,
1607+
output: _options.output,
1608+
);
16061609

16071610
// Enable raw mode for character-by-character input
16081611
_terminal!.enableRawMode();

pkgs/artisanal/test/terminal/plumbing_parity_test.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ void main() {
3535
expect(caps.useBackspace, isTrue);
3636
});
3737

38+
test(
39+
'StdioTerminal redirects writes to the configured output callback',
40+
() {
41+
final writes = <String>[];
42+
final terminal = StdioTerminal(output: writes.add);
43+
44+
terminal.write('screen bytes');
45+
terminal.writeln('line');
46+
47+
expect(writes, ['screen bytes', 'line${Platform.lineTerminator}']);
48+
},
49+
);
50+
3851
test('StringTerminal optimizeMovements returns safe defaults', () {
3952
final terminal = StringTerminal();
4053
final caps = terminal.optimizeMovements();

0 commit comments

Comments
 (0)