mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-05 15:18:40 +00:00
terminal/snapshot: 8-byte grid cells with blank elision
Rework the PAGE grid encoding for codec speed and size. This is a
breaking change to the work-in-progress version 1 wire format.
Cells were previously a fixed 16-byte header plus inline grapheme
suffixes: one byte each for content kind, width, and flags, a
reserved byte, 16-bit style and hyperlink IDs, a 32-bit value, and an
always-present 32-bit suffix count that was almost always zero. Cells
are now one 64-bit little-endian word with a documented bit registry
that carries the hyperlink ID in its high bits. The layout
deliberately coincides with the native cell so clean rows encode as a
straight copy of page memory and decode as one bulk read plus an
in-place normalization pass; a comptime check falls back to a
portable field-by-field codec if the native layout ever diverges.
Each row header also gains an encoded cell count so trailing default
cells are elided instead of spending 16 bytes apiece encoding
nothing: on typical shell output most of every row is blank, and
measurement showed 97% of encoded snapshot bytes were zero. Grapheme
suffixes move out of the cell stream into a per-grid section of
(row, column, codepoints) entries, which keeps row decoding
fixed-stride and bulk-copyable.
Decode ID remapping switches from hash maps to direct-indexed tables
sized by the 16-bit encoded ID space, removing per-styled-cell hash
lookups.
Benchmark deltas at this commit (terminal-snapshot, M-series,
ReleaseFast, 1 MB corpora):
ascii lines 1-70: 34.16 MB -> 7.66 MB (4.5x)
encode 92.8 -> 18.2 ms, decode 119.8 -> 28.0 ms
ascii full-wrap: 16.01 MB -> 8.04 MB (2.0x)
encode 43.6 -> 18.4 ms, decode 56.2 -> 25.6 ms
utf8: 4.33 MB -> 1.90 MB (2.3x)
encode 12.4 -> 4.9 ms, decode 19.0 -> 9.6 ms
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -63,19 +63,19 @@
|
||||
//! | hyperlink_count entries |
|
||||
//! +---------------------------+
|
||||
//! | Grid |
|
||||
//! | one record per row |
|
||||
//! | rows and grapheme section |
|
||||
//! +---------------------------+
|
||||
//!
|
||||
//! Style entry = encoded ID + style record
|
||||
//! Hyperlink entry = encoded ID + hyperlink record
|
||||
//! Grid = row 0 ... row (rows - 1)
|
||||
//! Row = row header + cell 0 ... cell (columns - 1)
|
||||
//! Cell = cell header + grapheme suffix codepoints
|
||||
//! Grid = row 0 ... row (rows - 1) + grapheme suffix section
|
||||
//! Row = row header + encoded cells
|
||||
//! ```
|
||||
//!
|
||||
//! Following the header, the payload contains exactly `style_count` style
|
||||
//! records and `hyperlink_count` hyperlink records, followed by exactly
|
||||
//! `rows` row records. There is no padding between records.
|
||||
//! `rows` row records and one grapheme suffix section. There is no padding
|
||||
//! between records.
|
||||
//!
|
||||
//! Each style begins with an ID (`u16`) followed by the typical style
|
||||
//! binary representation (in style.zig). The ID is what cells will use
|
||||
@@ -119,6 +119,7 @@ const PayloadEncodeError = hyperlink.EncodeError || grid.EncodeError;
|
||||
|
||||
const PayloadDecodeError = std.Io.Reader.Error ||
|
||||
Header.CapacityError ||
|
||||
grid.DecodeError ||
|
||||
error{
|
||||
/// The hyperlink kind is not defined by snapshot version 1.
|
||||
InvalidKind,
|
||||
@@ -284,15 +285,13 @@ fn decodePayloadBody(
|
||||
page.pauseIntegrityChecks(true);
|
||||
defer page.pauseIntegrityChecks(false);
|
||||
|
||||
var style_remap = grid.StyleRemap.init(alloc);
|
||||
defer style_remap.deinit();
|
||||
style_remap.ensureTotalCapacity(header.style_count) catch
|
||||
var style_remap = grid.StyleRemap.init(alloc) catch
|
||||
return error.OutOfMemory;
|
||||
defer style_remap.deinit(alloc);
|
||||
|
||||
var hyperlink_remap = grid.HyperlinkRemap.init(alloc);
|
||||
defer hyperlink_remap.deinit();
|
||||
hyperlink_remap.ensureTotalCapacity(header.hyperlink_count) catch
|
||||
var hyperlink_remap = grid.HyperlinkRemap.init(alloc) catch
|
||||
return error.OutOfMemory;
|
||||
defer hyperlink_remap.deinit(alloc);
|
||||
|
||||
// Styles
|
||||
for (0..header.style_count) |_| {
|
||||
@@ -316,10 +315,7 @@ fn decodePayloadBody(
|
||||
valid,
|
||||
) catch 0;
|
||||
} else 0;
|
||||
style_remap.putAssumeCapacityNoClobber(
|
||||
native_id,
|
||||
decoded_id,
|
||||
);
|
||||
style_remap.put(native_id, decoded_id);
|
||||
}
|
||||
|
||||
// Hyperlinks
|
||||
@@ -338,10 +334,7 @@ fn decodePayloadBody(
|
||||
|
||||
// Zero records an ignored table entry. Grid decoding treats every
|
||||
// reference to it as no hyperlink.
|
||||
hyperlink_remap.putAssumeCapacityNoClobber(
|
||||
native_id,
|
||||
decoded_id,
|
||||
);
|
||||
hyperlink_remap.put(native_id, decoded_id);
|
||||
}
|
||||
|
||||
// Rows and cells
|
||||
@@ -860,8 +853,7 @@ test "decode accepts unordered sparse style IDs and ignores zero" {
|
||||
var descending: [
|
||||
Header.len +
|
||||
2 * (2 + style.len) +
|
||||
1 +
|
||||
16
|
||||
7
|
||||
]u8 = undefined;
|
||||
var descending_writer: std.Io.Writer = .fixed(&descending);
|
||||
try header.encode(&descending_writer);
|
||||
@@ -869,8 +861,9 @@ test "decode accepts unordered sparse style IDs and ignores zero" {
|
||||
try style.encode(.{ .flags = .{ .bold = true } }, &descending_writer);
|
||||
try io.writeInt(&descending_writer, TerminalStyleId, 2);
|
||||
try style.encode(.{ .flags = .{ .italic = true } }, &descending_writer);
|
||||
try descending_writer.writeByte(0);
|
||||
try descending_writer.splatByteAll(0, 16);
|
||||
try descending_writer.writeByte(0); // row flags
|
||||
try io.writeInt(&descending_writer, u16, 0); // cell count
|
||||
try io.writeInt(&descending_writer, u32, 0); // grapheme section
|
||||
|
||||
var descending_reader: std.Io.Reader = .fixed(
|
||||
descending_writer.buffered(),
|
||||
@@ -893,7 +886,7 @@ test "decode accepts unordered sparse style IDs and ignores zero" {
|
||||
.string_capacity_bytes = 0,
|
||||
};
|
||||
|
||||
var zero: [Header.len + 2 + style.len + 17]u8 = undefined;
|
||||
var zero: [Header.len + 2 + style.len + 7]u8 = undefined;
|
||||
var zero_writer: std.Io.Writer = .fixed(&zero);
|
||||
try one_header.encode(&zero_writer);
|
||||
try io.writeInt(&zero_writer, TerminalStyleId, 0);
|
||||
@@ -936,8 +929,7 @@ test "decode accepts unordered sparse hyperlink IDs" {
|
||||
var encoded: [
|
||||
Header.len +
|
||||
2 * 14 +
|
||||
1 +
|
||||
16
|
||||
7
|
||||
]u8 = undefined;
|
||||
var writer: std.Io.Writer = .fixed(&encoded);
|
||||
try header.encode(&writer);
|
||||
@@ -945,8 +937,9 @@ test "decode accepts unordered sparse hyperlink IDs" {
|
||||
try hyperlink.encode(first, &writer);
|
||||
try io.writeInt(&writer, TerminalHyperlinkId, 2);
|
||||
try hyperlink.encode(second, &writer);
|
||||
try writer.writeByte(0);
|
||||
try writer.splatByteAll(0, 16);
|
||||
try writer.writeByte(0); // row flags
|
||||
try io.writeInt(&writer, u16, 0); // cell count
|
||||
try io.writeInt(&writer, u32, 0); // grapheme section
|
||||
|
||||
var reader: std.Io.Reader = .fixed(writer.buffered());
|
||||
var decoded = try decodePayload(
|
||||
@@ -973,15 +966,15 @@ test "decode defaults missing sparse cell references" {
|
||||
.string_capacity_bytes = 0,
|
||||
};
|
||||
|
||||
var style_encoded: [Header.len + 1 + 16]u8 = undefined;
|
||||
var style_encoded: [Header.len + 3 + 8 + 4]u8 = undefined;
|
||||
var style_writer: std.Io.Writer = .fixed(&style_encoded);
|
||||
try style_header.encode(&style_writer);
|
||||
try style_writer.writeByte(0);
|
||||
try style_writer.writeAll(&.{ 0, 0, 0, 0 });
|
||||
try io.writeInt(&style_writer, TerminalStyleId, 1);
|
||||
try io.writeInt(&style_writer, TerminalHyperlinkId, 0);
|
||||
try io.writeInt(&style_writer, u32, 0);
|
||||
try io.writeInt(&style_writer, u32, 0);
|
||||
try style_writer.writeByte(0); // row flags
|
||||
try io.writeInt(&style_writer, u16, 1); // cell count
|
||||
try io.writeInt(&style_writer, u64, @bitCast(grid.Cell{
|
||||
.style_id = 1,
|
||||
}));
|
||||
try io.writeInt(&style_writer, u32, 0); // grapheme section
|
||||
|
||||
var style_reader: std.Io.Reader = .fixed(style_writer.buffered());
|
||||
var style_page = try decodePayload(
|
||||
@@ -1006,15 +999,16 @@ test "decode defaults missing sparse cell references" {
|
||||
.string_capacity_bytes = 0,
|
||||
};
|
||||
|
||||
var hyperlink_encoded: [Header.len + 1 + 16]u8 = undefined;
|
||||
var hyperlink_encoded: [Header.len + 3 + 8 + 4]u8 = undefined;
|
||||
var hyperlink_writer: std.Io.Writer = .fixed(&hyperlink_encoded);
|
||||
try hyperlink_header.encode(&hyperlink_writer);
|
||||
try hyperlink_writer.writeByte(0);
|
||||
try hyperlink_writer.writeAll(&.{ 0, 0, 0, 0 });
|
||||
try io.writeInt(&hyperlink_writer, TerminalStyleId, 0);
|
||||
try io.writeInt(&hyperlink_writer, TerminalHyperlinkId, 1);
|
||||
try io.writeInt(&hyperlink_writer, u32, 0);
|
||||
try io.writeInt(&hyperlink_writer, u32, 0);
|
||||
try hyperlink_writer.writeByte(0); // row flags
|
||||
try io.writeInt(&hyperlink_writer, u16, 1); // cell count
|
||||
try io.writeInt(&hyperlink_writer, u64, @bitCast(grid.Cell{
|
||||
.hyperlink = true,
|
||||
.hyperlink_id = 1,
|
||||
}));
|
||||
try io.writeInt(&hyperlink_writer, u32, 0); // grapheme section
|
||||
|
||||
var hyperlink_reader: std.Io.Reader = .fixed(
|
||||
hyperlink_writer.buffered(),
|
||||
@@ -1044,41 +1038,42 @@ test "decode normalizes invalid grid semantics" {
|
||||
.string_capacity_bytes = 0,
|
||||
};
|
||||
|
||||
var encoded: [Header.len + 1 + 3 * 16 + 12]u8 = undefined;
|
||||
var encoded: [Header.len + 3 + 3 * 8 + 4 + 10]u8 = undefined;
|
||||
var writer: std.Io.Writer = .fixed(&encoded);
|
||||
try header.encode(&writer);
|
||||
|
||||
// Preserve wrap while degrading the unknown semantic-prompt value to none
|
||||
// and ignoring all reserved row bits.
|
||||
try writer.writeByte(0xFD);
|
||||
try io.writeInt(&writer, u16, 3);
|
||||
|
||||
// An unknown content and width kind, invalid semantic content, reserved
|
||||
// bytes, and suffix data all degrade to a blank narrow output cell.
|
||||
try writer.writeAll(&.{ 3, 4, 0xFF, 0xFF });
|
||||
try io.writeInt(&writer, TerminalStyleId, 0);
|
||||
try io.writeInt(&writer, TerminalHyperlinkId, 0);
|
||||
try io.writeInt(&writer, u32, 0xD800);
|
||||
try io.writeInt(&writer, u32, 1);
|
||||
try io.writeInt(&writer, u32, 0x110000);
|
||||
// A text cell replaces an invalid Unicode scalar with U+FFFD while its
|
||||
// reserved semantic content degrades to output.
|
||||
try io.writeInt(&writer, u64, @bitCast(grid.Cell{
|
||||
.content = 0xD800,
|
||||
.semantic_content = 3,
|
||||
}));
|
||||
|
||||
// A recognized text cell replaces an invalid Unicode scalar with U+FFFD.
|
||||
// Its valid suffix cannot fit the advertised zero capacity, so decoding
|
||||
// preserves the base character and drops the optional suffix.
|
||||
try writer.writeAll(&.{ 0, 0, 0, 0 });
|
||||
try io.writeInt(&writer, TerminalStyleId, 0);
|
||||
try io.writeInt(&writer, TerminalHyperlinkId, 0);
|
||||
try io.writeInt(&writer, u32, 0xD800);
|
||||
try io.writeInt(&writer, u32, 1);
|
||||
try io.writeInt(&writer, u32, 'x');
|
||||
// A declared grapheme suffix cannot fit the advertised zero capacity,
|
||||
// so decoding preserves the base character and drops the suffix.
|
||||
try io.writeInt(&writer, u64, @bitCast(grid.Cell{
|
||||
.kind = 1,
|
||||
.content = 'x',
|
||||
}));
|
||||
|
||||
// Reserved palette bits and a nonsensical suffix do not obscure the valid
|
||||
// low palette byte; the suffix is consumed and ignored.
|
||||
try writer.writeAll(&.{ 1, 0, 0, 0xFF });
|
||||
try io.writeInt(&writer, TerminalStyleId, 0);
|
||||
try io.writeInt(&writer, TerminalHyperlinkId, 0);
|
||||
try io.writeInt(&writer, u32, 0xFFFFFF07);
|
||||
// Reserved palette content bits do not obscure the valid low palette
|
||||
// byte.
|
||||
try io.writeInt(&writer, u64, @bitCast(grid.Cell{
|
||||
.kind = 2,
|
||||
.content = 0xFFFF07,
|
||||
}));
|
||||
|
||||
// The grapheme section carries the suffix for the second cell.
|
||||
try io.writeInt(&writer, u32, 1);
|
||||
try io.writeInt(&writer, u32, 'x');
|
||||
try io.writeInt(&writer, u16, 0);
|
||||
try io.writeInt(&writer, u16, 1);
|
||||
try io.writeInt(&writer, u16, 1);
|
||||
try io.writeInt(&writer, u32, 0x0301);
|
||||
|
||||
var reader: std.Io.Reader = .fixed(writer.buffered());
|
||||
var page = try decodePayload(&reader, std.testing.allocator);
|
||||
@@ -1091,7 +1086,7 @@ test "decode normalizes invalid grid semantics" {
|
||||
terminal_page.Row.SemanticPrompt.none,
|
||||
first.row.semantic_prompt,
|
||||
);
|
||||
try std.testing.expectEqual(@as(u21, 0), first.cell.codepoint());
|
||||
try std.testing.expectEqual(@as(u21, 0xFFFD), first.cell.codepoint());
|
||||
try std.testing.expectEqual(
|
||||
terminal_page.Cell.Wide.narrow,
|
||||
first.cell.wide,
|
||||
@@ -1104,7 +1099,7 @@ test "decode normalizes invalid grid semantics" {
|
||||
try std.testing.expect(!first.cell.hasGrapheme());
|
||||
|
||||
const second = page.getRowAndCell(1, 0).cell;
|
||||
try std.testing.expectEqual(@as(u21, 0xFFFD), second.codepoint());
|
||||
try std.testing.expectEqual(@as(u21, 'x'), second.codepoint());
|
||||
try std.testing.expect(!second.hasGrapheme());
|
||||
|
||||
const third = page.getRowAndCell(2, 0).cell;
|
||||
|
||||
@@ -205,6 +205,7 @@ const Allocator = std.mem.Allocator;
|
||||
const hyperlink = @import("hyperlink.zig");
|
||||
const test_fixture = @import("fixture.zig");
|
||||
const io = @import("io.zig");
|
||||
const grid = @import("grid.zig");
|
||||
const page = @import("page.zig");
|
||||
const record = @import("record.zig");
|
||||
const style = @import("style.zig");
|
||||
@@ -2261,20 +2262,14 @@ test "SCREEN decode ignores a PAGE with an empty hyperlink URI" {
|
||||
|
||||
// One narrow codepoint cell refers to the hyperlink table entry above.
|
||||
// Since that entry is ignored, the cell must restore without a hyperlink.
|
||||
try page_payload.writeByte(0);
|
||||
try page_payload.writeAll(&.{ 0, 0, 0, 0 });
|
||||
try io.writeInt(
|
||||
page_payload,
|
||||
terminal_style.Id,
|
||||
0,
|
||||
);
|
||||
try io.writeInt(
|
||||
page_payload,
|
||||
terminal_hyperlink.Id,
|
||||
1,
|
||||
);
|
||||
try io.writeInt(page_payload, u32, 'A');
|
||||
try io.writeInt(page_payload, u32, 0);
|
||||
try page_payload.writeByte(0); // row flags
|
||||
try io.writeInt(page_payload, u16, 1); // cell count
|
||||
try io.writeInt(page_payload, u64, @bitCast(grid.Cell{
|
||||
.content = 'A',
|
||||
.hyperlink = true,
|
||||
.hyperlink_id = 1,
|
||||
}));
|
||||
try io.writeInt(page_payload, u32, 0); // grapheme section
|
||||
try stream.finish();
|
||||
|
||||
var source: std.Io.Reader = .fixed(destination.written());
|
||||
|
||||
@@ -914,18 +914,28 @@ types:
|
||||
type: grid_row(columns)
|
||||
repeat: expr
|
||||
repeat-expr: num_rows
|
||||
- id: num_grapheme_entries
|
||||
type: u4
|
||||
- id: grapheme_entries
|
||||
type: grapheme_entry(num_rows, columns)
|
||||
repeat: expr
|
||||
repeat-expr: num_grapheme_entries
|
||||
|
||||
grid_row:
|
||||
params:
|
||||
- id: num_cells
|
||||
- id: columns
|
||||
type: u2
|
||||
seq:
|
||||
- id: flags
|
||||
type: grid_row_flags
|
||||
- id: cell_count
|
||||
type: u2
|
||||
valid:
|
||||
expr: _ <= columns
|
||||
- id: cells
|
||||
type: grid_cell(_index, num_cells, flags.wrap)
|
||||
type: grid_cell(_index, columns, flags.wrap)
|
||||
repeat: expr
|
||||
repeat-expr: num_cells
|
||||
repeat-expr: cell_count
|
||||
|
||||
grid_row_flags:
|
||||
seq:
|
||||
@@ -942,6 +952,17 @@ types:
|
||||
value: (raw >> 2) & 0x3
|
||||
|
||||
grid_cell:
|
||||
doc: |
|
||||
One 64-bit little-endian cell word. The word is parsed as two 32-bit
|
||||
halves so every derived field stays within JavaScript's safe integer
|
||||
range, following the same approach as mode_set.
|
||||
|
||||
Canonical rules validated here: reserved semantic content is not
|
||||
emitted, the hyperlink flag matches a nonzero hyperlink ID, codepoint
|
||||
content is a Unicode scalar value, palette content uses only its low
|
||||
eight bits, and spacer relationships match the preceding cell. Wide
|
||||
markers cannot be validated forward because their spacer tail may be
|
||||
the next cell or the implicit narrow cell after a short row.
|
||||
params:
|
||||
- id: index
|
||||
type: u2
|
||||
@@ -950,59 +971,61 @@ types:
|
||||
- id: row_wrap
|
||||
type: bool
|
||||
seq:
|
||||
- id: content_kind
|
||||
type: u1
|
||||
valid:
|
||||
max: 2
|
||||
- id: width
|
||||
type: u1
|
||||
- id: lo
|
||||
type: u4
|
||||
- id: hi
|
||||
type: u4
|
||||
valid:
|
||||
expr: |
|
||||
_ <= 3 and
|
||||
(_ != 2 or
|
||||
semantic_content <= 2 and
|
||||
hyperlink == (hyperlink_id != 0) and
|
||||
(content_kind >= 2 or
|
||||
(content <= 0x10ffff and
|
||||
not (content >= 0xd800 and content <= 0xdfff))) and
|
||||
(content_kind != 2 or content <= 0xff) and
|
||||
(width != 2 or
|
||||
(index > 0 and _parent.cells[index - 1].width == 1)) and
|
||||
(_ != 3 or
|
||||
(index + 1 == columns and row_wrap))
|
||||
- id: flags
|
||||
type: grid_cell_flags
|
||||
- id: reserved
|
||||
type: u1
|
||||
valid: 0
|
||||
- id: style_id
|
||||
(width != 3 or (index + 1 == columns and row_wrap))
|
||||
instances:
|
||||
content_kind:
|
||||
value: lo % 4
|
||||
content:
|
||||
value: (lo / 4) % 16777216
|
||||
style_id:
|
||||
value: (lo / 67108864) + (hi % 1024) * 64
|
||||
width:
|
||||
value: (hi / 1024) % 4
|
||||
protected:
|
||||
value: (hi / 4096) % 2 != 0
|
||||
hyperlink:
|
||||
value: (hi / 8192) % 2 != 0
|
||||
semantic_content:
|
||||
value: (hi / 16384) % 4
|
||||
hyperlink_id:
|
||||
value: hi / 65536
|
||||
|
||||
grapheme_entry:
|
||||
seq:
|
||||
- id: row
|
||||
type: u2
|
||||
- id: hyperlink_id
|
||||
valid:
|
||||
expr: _ < num_rows
|
||||
- id: col
|
||||
type: u2
|
||||
- id: value
|
||||
type: u4
|
||||
valid:
|
||||
expr: |
|
||||
content_kind == 0 ?
|
||||
(_ <= 0x10ffff and not (_ >= 0xd800 and _ <= 0xdfff) and _ != 0x10eeee) :
|
||||
content_kind == 1 ?
|
||||
_ <= 0xff :
|
||||
_ <= 0xffffff
|
||||
- id: num_graphemes
|
||||
type: u4
|
||||
expr: _ < columns
|
||||
- id: num_codepoints
|
||||
type: u2
|
||||
valid:
|
||||
expr: |
|
||||
content_kind == 0 ?
|
||||
(_ == 0 or value != 0) :
|
||||
_ == 0
|
||||
- id: graphemes
|
||||
min: 1
|
||||
- id: codepoints
|
||||
type: u4
|
||||
repeat: expr
|
||||
repeat-expr: num_graphemes
|
||||
repeat-expr: num_codepoints
|
||||
valid:
|
||||
expr: _ <= 0x10ffff and not (_ >= 0xd800 and _ <= 0xdfff) and _ != 0x10eeee
|
||||
|
||||
grid_cell_flags:
|
||||
seq:
|
||||
- id: raw
|
||||
type: u1
|
||||
valid:
|
||||
expr: (_ & 0xf8) == 0 and ((_ >> 1) & 0x3) <= 2
|
||||
instances:
|
||||
protected:
|
||||
value: (raw & (1 << 0)) != 0
|
||||
semantic_content:
|
||||
value: (raw >> 1) & 0x3
|
||||
expr: _ <= 0x10ffff and not (_ >= 0xd800 and _ <= 0xdfff)
|
||||
params:
|
||||
- id: num_rows
|
||||
type: u2
|
||||
- id: columns
|
||||
type: u2
|
||||
|
||||
93
src/terminal/snapshot/testdata/complete-v1.hex
vendored
93
src/terminal/snapshot/testdata/complete-v1.hex
vendored
@@ -78,65 +78,52 @@ ee ee 80 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x0000037a
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000003ec
|
||||
00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000003fc
|
||||
|
||||
# offset 0x0000040c: page record, payload 119 bytes
|
||||
03 00 77 00 00 00 48 b7 91 cb 02 00 03 00 00 00 # 0x0000040c
|
||||
00 00 10 00 c0 00 00 04 00 00 00 08 00 00 00 00 # 0x0000041c
|
||||
00 00 00 00 00 00 00 43 00 00 00 00 00 00 00 00 # 0x0000042c
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x0000043c
|
||||
00 00 00 00 00 00 00 00 44 00 00 00 00 00 00 00 # 0x0000044c
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x0000045c
|
||||
00 00 00 00 00 00 00 00 00 45 00 00 00 00 00 00 # 0x0000046c
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x0000047c
|
||||
00 # 0x0000048c
|
||||
# offset 0x0000040c: page record, payload 57 bytes
|
||||
03 00 39 00 00 00 26 5a 94 0b 02 00 03 00 00 00 # 0x0000040c
|
||||
00 00 10 00 c0 00 00 04 00 00 00 08 00 00 00 01 # 0x0000041c
|
||||
00 0c 01 00 00 00 00 00 00 00 01 00 10 01 00 00 # 0x0000042c
|
||||
00 00 00 00 00 01 00 14 01 00 00 00 00 00 00 00 # 0x0000043c
|
||||
00 00 00 # 0x0000044c
|
||||
|
||||
# offset 0x0000048d: screen record, payload 54 bytes
|
||||
02 00 36 00 00 00 ce 1f 9f 08 01 00 01 00 00 00 # 0x0000048d
|
||||
00 00 00 00 00 00 01 00 02 00 01 00 00 00 00 00 # 0x0000049d
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000004ad
|
||||
00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000004bd
|
||||
# offset 0x0000044f: screen record, payload 54 bytes
|
||||
02 00 36 00 00 00 ce 1f 9f 08 01 00 01 00 00 00 # 0x0000044f
|
||||
00 00 00 00 00 00 01 00 02 00 01 00 00 00 00 00 # 0x0000045f
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x0000046f
|
||||
00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x0000047f
|
||||
|
||||
# offset 0x000004cd: page record, payload 119 bytes
|
||||
03 00 77 00 00 00 84 a6 e9 08 02 00 03 00 00 00 # 0x000004cd
|
||||
00 00 80 00 c0 00 00 02 00 00 00 08 00 00 03 00 # 0x000004dd
|
||||
00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 00 # 0x000004ed
|
||||
00 00 00 00 00 00 00 6e 00 00 00 00 00 00 00 03 # 0x000004fd
|
||||
00 00 00 00 00 00 00 00 61 00 00 00 00 00 00 00 # 0x0000050d
|
||||
00 00 00 00 00 00 00 00 74 00 00 00 00 00 00 00 # 0x0000051d
|
||||
03 00 00 00 00 00 00 00 00 65 00 00 00 00 00 00 # 0x0000052d
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x0000053d
|
||||
00 # 0x0000054d
|
||||
# offset 0x0000048f: page record, payload 73 bytes
|
||||
03 00 49 00 00 00 37 af 30 0e 02 00 03 00 00 00 # 0x0000048f
|
||||
00 00 80 00 c0 00 00 02 00 00 00 08 00 00 03 02 # 0x0000049f
|
||||
00 c8 01 00 00 00 00 00 00 b8 01 00 00 00 00 00 # 0x000004af
|
||||
00 03 02 00 84 01 00 00 00 00 00 00 d0 01 00 00 # 0x000004bf
|
||||
00 00 00 00 03 01 00 94 01 00 00 00 00 00 00 00 # 0x000004cf
|
||||
00 00 00 # 0x000004df
|
||||
|
||||
# offset 0x0000054e: continuation record, payload 0 bytes
|
||||
07 00 00 00 00 00 27 80 63 d1 # 0x0000054e
|
||||
# offset 0x000004e2: continuation record, payload 0 bytes
|
||||
07 00 00 00 00 00 27 80 63 d1 # 0x000004e2
|
||||
|
||||
# offset 0x00000558: ready record, payload 32 bytes
|
||||
05 00 20 00 00 00 d4 d1 fc d0 8d 69 76 c1 6e c6 # 0x00000558
|
||||
88 21 bd 10 97 41 97 35 63 2d ce 9e 3c b8 fa cf # 0x00000568
|
||||
57 04 f5 4b e0 70 66 5e 7e b6 # 0x00000578
|
||||
# offset 0x000004ec: ready record, payload 32 bytes
|
||||
05 00 20 00 00 00 5d f3 97 80 41 a2 18 18 cb 82 # 0x000004ec
|
||||
8c 97 b6 58 14 60 26 9a 88 2e be d4 c3 4b 83 c9 # 0x000004fc
|
||||
9d 32 9d de e6 70 17 4a 5d bc # 0x0000050c
|
||||
|
||||
# offset 0x00000582: history record, payload 6 bytes
|
||||
04 00 06 00 00 00 20 32 ed e1 00 00 02 00 00 00 # 0x00000582
|
||||
# offset 0x00000516: history record, payload 6 bytes
|
||||
04 00 06 00 00 00 20 32 ed e1 00 00 02 00 00 00 # 0x00000516
|
||||
|
||||
# offset 0x00000592: page record, payload 86 bytes
|
||||
03 00 56 00 00 00 52 3b 6e 8d 02 00 02 00 00 00 # 0x00000592
|
||||
00 00 10 00 c0 00 00 04 00 00 00 08 00 00 00 00 # 0x000005a2
|
||||
00 00 00 00 00 00 00 42 00 00 00 00 00 00 00 00 # 0x000005b2
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000005c2
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000005d2
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000005e2
|
||||
# offset 0x00000526: page record, payload 38 bytes
|
||||
03 00 26 00 00 00 9e 10 a2 93 02 00 02 00 00 00 # 0x00000526
|
||||
00 00 10 00 c0 00 00 04 00 00 00 08 00 00 00 01 # 0x00000536
|
||||
00 08 01 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x00000546
|
||||
|
||||
# offset 0x000005f2: page record, payload 86 bytes
|
||||
03 00 56 00 00 00 fb bc 15 06 02 00 02 00 00 00 # 0x000005f2
|
||||
00 00 10 00 c0 00 00 04 00 00 00 08 00 00 00 00 # 0x00000602
|
||||
00 00 00 00 00 00 00 41 00 00 00 00 00 00 00 00 # 0x00000612
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x00000622
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x00000632
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x00000642
|
||||
# offset 0x00000556: page record, payload 38 bytes
|
||||
03 00 26 00 00 00 70 e1 36 3a 02 00 02 00 00 00 # 0x00000556
|
||||
00 00 10 00 c0 00 00 04 00 00 00 08 00 00 00 01 # 0x00000566
|
||||
00 04 01 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x00000576
|
||||
|
||||
# offset 0x00000652: history record, payload 6 bytes
|
||||
04 00 06 00 00 00 b8 7a ba b1 01 00 00 00 00 00 # 0x00000652
|
||||
# offset 0x00000586: history record, payload 6 bytes
|
||||
04 00 06 00 00 00 b8 7a ba b1 01 00 00 00 00 00 # 0x00000586
|
||||
|
||||
# offset 0x00000662: finish record, payload 32 bytes
|
||||
06 00 20 00 00 00 f3 a4 cf b6 f2 2b 17 88 1a 28 # 0x00000662
|
||||
a7 27 6e f7 de bc 7a 52 f9 a4 f9 c3 32 5b e0 09 # 0x00000672
|
||||
8a 1a 7d a0 9f 8b 32 31 67 41 # 0x00000682
|
||||
# offset 0x00000596: finish record, payload 32 bytes
|
||||
06 00 20 00 00 00 20 0f e0 7e 10 4f 2c da 90 fa # 0x00000596
|
||||
65 19 a9 73 26 75 2a 5b 33 cd 9d fa 73 81 86 07 # 0x000005a6
|
||||
9e 57 d4 83 41 9f a9 81 64 e7 # 0x000005b6
|
||||
|
||||
30
src/terminal/snapshot/testdata/grid-v1.hex
vendored
30
src/terminal/snapshot/testdata/grid-v1.hex
vendored
@@ -6,27 +6,9 @@
|
||||
# Generated by its snapshot test; review before replacing.
|
||||
# On mismatch, the candidate is copied to the repository root.
|
||||
|
||||
# row 0: prompt
|
||||
04
|
||||
|
||||
# row 0, cell 0: protected prompt, wide "A"
|
||||
00 01 05 00 00 00 00 00 41 00 00 00 00 00 00 00
|
||||
|
||||
# row 0, cell 1: input spacer tail
|
||||
00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
# row 0, cell 2: "x" with two grapheme suffixes
|
||||
00 00 00 00 00 00 00 00 78 00 00 00 02 00 00 00
|
||||
01 03 00 00 02 03 00 00
|
||||
|
||||
# row 1: wrapped prompt continuation
|
||||
0b
|
||||
|
||||
# row 1, cell 0: palette background 7
|
||||
01 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00
|
||||
|
||||
# row 1, cell 1: protected RGB background
|
||||
02 00 01 00 00 00 00 00 aa bb cc 00 00 00 00 00
|
||||
|
||||
# row 1, cell 2: spacer head
|
||||
00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
# offset 0x00000000: encoded bytes
|
||||
04 03 00 04 01 00 00 00 94 00 00 00 00 00 00 00 # 0x00000000
|
||||
48 00 00 e1 01 00 00 00 00 00 00 0b 03 00 1e 00 # 0x00000010
|
||||
00 00 00 00 00 00 ab ee 32 03 00 10 00 00 00 00 # 0x00000020
|
||||
00 00 00 0c 00 00 01 00 00 00 00 00 02 00 02 00 # 0x00000030
|
||||
01 03 00 00 02 03 00 00 # 0x00000040
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
# On mismatch, the candidate is copied to the repository root.
|
||||
|
||||
# offset 0x00000000: encoded bytes
|
||||
03 00 25 00 00 00 8c 05 d6 d3 01 00 01 00 00 00 # 0x00000000
|
||||
03 00 1b 00 00 00 5e 0d 0a d4 01 00 01 00 00 00 # 0x00000000
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x00000010
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x00000020
|
||||
00 00 00 00 00 # 0x00000020
|
||||
|
||||
12
src/terminal/snapshot/testdata/page-v1.hex
vendored
12
src/terminal/snapshot/testdata/page-v1.hex
vendored
@@ -15,10 +15,8 @@
|
||||
00 00 03 00 00 00 00 00 01 2a 00 00 00 00 00 00 # 0x00000024
|
||||
00 00 00 00 01 00 02 01 00 00 00 61 05 00 00 00 # 0x00000034
|
||||
61 6c 70 68 61 03 00 01 04 03 02 01 04 00 00 00 # 0x00000044
|
||||
62 65 74 61 04 00 01 05 00 01 00 01 00 41 00 00 # 0x00000054
|
||||
00 00 00 00 00 00 02 02 00 03 00 03 00 00 00 00 # 0x00000064
|
||||
00 00 00 00 00 01 00 00 00 01 00 01 00 07 00 00 # 0x00000074
|
||||
00 00 00 00 00 0b 00 00 00 00 00 00 00 00 78 00 # 0x00000084
|
||||
00 00 02 00 00 00 01 03 00 00 02 03 00 00 02 00 # 0x00000094
|
||||
01 00 00 00 00 00 aa bb cc 00 00 00 00 00 00 03 # 0x000000a4
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 # 0x000000b4
|
||||
62 65 74 61 04 03 00 04 01 00 04 00 b4 01 00 00 # 0x00000054
|
||||
00 00 0c 00 68 03 00 1e 00 00 04 00 20 01 00 0b # 0x00000064
|
||||
03 00 e1 01 00 00 00 00 00 00 ab ee 32 03 00 10 # 0x00000074
|
||||
00 00 00 00 00 00 00 0c 00 00 01 00 00 00 01 00 # 0x00000084
|
||||
00 00 02 00 01 03 00 00 02 03 00 00 # 0x00000094
|
||||
|
||||
Reference in New Issue
Block a user