Selkie.git | lib/Selkie/App/Internal/ | Terminal.rakumod
=begin pod
=head1 NAME
Selkie::App::Internal::Terminal - internal terminal cleanup role for Selkie::App
=head1 DESCRIPTION
Implementation detail composed by C<Selkie::App>. It is not part of the stable
1.0 application API.
Captures the terminal's C<termios> state before notcurses enters raw-style
mode and restores it during shutdown. The capture/restore pair is implemented
with in-process C<tcgetattr>/C<tcsetattr> NativeCall bindings rather than by
shelling out to C<stty>. Spawning a child process during shutdown proved
fragile in two ways seen in the wild:
=item If the process's working directory has been deleted or renamed while
the app was running, C<posix_spawn> fails with ENOENT before the command
even runs — the C<stty> restore silently can't happen.
=item A failed spawn surfaces as an C<X::Proc::Unsuccessful> broken on a
thread-pool thread, which escapes a caller-side C<try> and can propagate
out of C<Selkie::App.shutdown>, skipping C<notcurses_stop> and the
escape-sequence backstop entirely — the exact wedged-terminal outcome the
restore existed to prevent.
An in-process C<tcsetattr> has neither failure mode: it needs no child
process, no working directory, and reports failure via a return code.
The termios snapshot is treated as an opaque byte blob. Platform selection,
the POSIX ABI, controlling-terminal writes, and flow-control behavior live in
C<Selkie::App::Internal::TerminalPlatform>, shared with snapshot tests. On
Windows those operations are explicit no-ops, before any POSIX path or symbol
can be reached.
=end pod
unit role Selkie::App::Internal::Terminal;
use NativeCall;
use Selkie::App::Internal::TerminalPlatform;
use Selkie::App::Internal::TerminalSequences;
has CArray[uint8] $!saved-tty-state;
method !emit-terminal-cleanup(--> Nil) {
write-controlling-terminal(app-terminal-cleanup-sequence);
}
method !capture-tty-state(--> CArray[uint8]) {
capture-controlling-terminal-state;
}
method !restore-tty-state(--> Nil) {
restore-controlling-terminal-state($!saved-tty-state);
}