mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-05 15:18:40 +00:00
terminal/snapshot: report invalid decoder states
Decoder.next treated calls before READY and calls after any prior decode error as unreachable. Network or mux glue that retried after a truncated history record, or invoked next before setup completed, could therefore turn a recoverable protocol misuse into a process panic. Add DecoderNotReady and DecoderFailed to NextError and return them for the start and failed states. Keep finished calls idempotent, and cover both an early call and a retry after FINISH truncation.
This commit is contained in:
@@ -413,6 +413,12 @@ pub const Decoder = struct {
|
||||
page.DecodeError ||
|
||||
Allocator.Error ||
|
||||
error{
|
||||
/// `next` was called before `ready` completed successfully.
|
||||
DecoderNotReady,
|
||||
|
||||
/// A prior `next` call failed and invalidated the stream position.
|
||||
DecoderFailed,
|
||||
|
||||
/// A HISTORY names a key not declared by TERMINAL.
|
||||
UnexpectedHistoryKey,
|
||||
|
||||
@@ -457,7 +463,8 @@ pub const Decoder = struct {
|
||||
switch (self.state) {
|
||||
// `ready` must succeed before history exists to decode, and a
|
||||
// failed decoder no longer knows its stream position.
|
||||
.start, .failed => unreachable,
|
||||
.start => return error.DecoderNotReady,
|
||||
.failed => return error.DecoderFailed,
|
||||
.finished => return null,
|
||||
.history => {},
|
||||
}
|
||||
@@ -1774,6 +1781,23 @@ test "incremental decode restores a renderable terminal at READY" {
|
||||
try testing.expectEqualStrings(&test_complete_fixture, reencoded.written());
|
||||
}
|
||||
|
||||
test "incremental next reports invalid decoder states" {
|
||||
const testing = std.testing;
|
||||
var source: std.Io.Reader = .fixed("");
|
||||
var decoder: Decoder = .init(&source);
|
||||
var terminal_value = try Terminal.init(
|
||||
testing.io,
|
||||
testing.allocator,
|
||||
.{ .cols = 1, .rows = 1 },
|
||||
);
|
||||
defer terminal_value.deinit(testing.allocator);
|
||||
|
||||
try testing.expectError(
|
||||
error.DecoderNotReady,
|
||||
decoder.next(testing.allocator, &terminal_value),
|
||||
);
|
||||
}
|
||||
|
||||
test "incremental decode applies history below live PTY output" {
|
||||
const testing = std.testing;
|
||||
|
||||
@@ -2065,6 +2089,10 @@ test "incremental decode failure leaves applied history usable" {
|
||||
error.EndOfStream,
|
||||
decoder.next(testing.allocator, &restored),
|
||||
);
|
||||
try testing.expectError(
|
||||
error.DecoderFailed,
|
||||
decoder.next(testing.allocator, &restored),
|
||||
);
|
||||
|
||||
// The transferred terminal was never owned by the decoder: it remains
|
||||
// valid with the contiguous history prefix that did apply, and only
|
||||
|
||||
Reference in New Issue
Block a user