aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/device_attributes.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/terminal/device_attributes.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/device_attributes.zig')
-rw-r--r--vendor/libghostty-vt/src/terminal/device_attributes.zig227
1 files changed, 227 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/terminal/device_attributes.zig b/vendor/libghostty-vt/src/terminal/device_attributes.zig
new file mode 100644
index 00000000..38d08117
--- /dev/null
+++ b/vendor/libghostty-vt/src/terminal/device_attributes.zig
@@ -0,0 +1,227 @@
+const std = @import("std");
+const testing = std.testing;
+const lib = @import("lib.zig");
+
+/// The device attribute request type (CSI c).
+pub const Req = lib.Enum(lib.target, &.{
+ "primary", // Blank
+ "secondary", // >
+ "tertiary", // =
+});
+
+/// Response data for all device attribute queries.
+pub const Attributes = struct {
+ /// Reply to CSI c (DA1).
+ primary: Primary = .{},
+
+ /// Reply to CSI > c (DA2).
+ secondary: Secondary = .{},
+
+ /// Reply to CSI = c (DA3).
+ tertiary: Tertiary = .{},
+
+ /// Encode the response for the given request type into the writer.
+ pub fn encode(
+ self: Attributes,
+ req: Req,
+ writer: *std.Io.Writer,
+ ) std.Io.Writer.Error!void {
+ switch (req) {
+ .primary => try self.primary.encode(writer),
+ .secondary => try self.secondary.encode(writer),
+ .tertiary => try self.tertiary.encode(writer),
+ }
+ }
+};
+
+/// Primary device attributes (DA1).
+///
+/// Response format: CSI ? Pp ; Ps... c
+/// where Pp is the conformance level and Ps are feature flags.
+pub const Primary = struct {
+ /// Conformance level sent as the first parameter.
+ conformance_level: ConformanceLevel = .vt220,
+
+ /// Optional feature attributes.
+ features: []const Feature = &.{.ansi_color},
+
+ /// DA1 feature attribute codes.
+ pub const Feature = enum(u16) {
+ columns_132 = 1,
+ printer = 2,
+ regis = 3,
+ sixel = 4,
+ selective_erase = 6,
+ user_defined_keys = 8,
+ national_replacement = 9,
+ technical_characters = 15,
+ locator = 16,
+ terminal_state = 17,
+ windowing = 18,
+ horizontal_scrolling = 21,
+ ansi_color = 22,
+ rectangular_editing = 28,
+ ansi_text_locator = 29,
+ clipboard = 52,
+ _,
+ };
+
+ /// Encode the primary DA response into the writer.
+ pub fn encode(self: Primary, writer: *std.Io.Writer) std.Io.Writer.Error!void {
+ try writer.print("\x1b[?{}", .{@intFromEnum(self.conformance_level)});
+ for (self.features) |feature| try writer.print(";{}", .{@intFromEnum(feature)});
+ try writer.writeAll("c");
+ }
+};
+
+/// Secondary device attributes (DA2).
+///
+/// Response format: CSI > Pp ; Pv ; Pc c
+pub const Secondary = struct {
+ /// Terminal type identifier (Pp parameter from secondary DA response).
+ device_type: DeviceType = .vt220,
+
+ /// Firmware/patch version number.
+ firmware_version: u16 = 0,
+
+ /// ROM cartridge registration number. Always 0 for emulators.
+ rom_cartridge: u16 = 0,
+
+ /// Encode the secondary DA response into the writer.
+ pub fn encode(self: Secondary, writer: *std.Io.Writer) std.Io.Writer.Error!void {
+ try writer.print("\x1b[>{};{};{}c", .{
+ @intFromEnum(self.device_type),
+ self.firmware_version,
+ self.rom_cartridge,
+ });
+ }
+};
+
+/// Tertiary device attributes (DA3).
+///
+/// Response format: DCS ! | D...D ST
+/// where D...D is the unit ID as hex digits (DECRPTUI).
+pub const Tertiary = struct {
+ /// Unit ID (DECRPTUI). Encoded as 8 uppercase hex digits.
+ /// Meaningless for emulators nowadays. The actual DEC manuals
+ /// appear to split this into two 16-bit fields but since there
+ /// is no practical usage I know if I'm simplifying this.
+ unit_id: u32 = 0,
+
+ /// Encode the tertiary DA response into the writer.
+ pub fn encode(
+ self: Tertiary,
+ writer: *std.Io.Writer,
+ ) std.Io.Writer.Error!void {
+ try writer.print(
+ "\x1bP!|{X:0>8}\x1b\\",
+ .{self.unit_id},
+ );
+ }
+};
+
+/// Conformance level reported as the first parameter (Pp) in the
+/// primary device attributes (DA1) response.
+pub const ConformanceLevel = enum(u16) {
+ // VT100-series have per-model values.
+ vt100 = 1,
+ vt132 = 4,
+ vt102 = 6,
+ vt131 = 7,
+ vt125 = 12,
+
+ // VT200+ use 60 + decTerminalID/100.
+ /// Level 2 conformance (VT200 series, e.g. VT220, VT240).
+ level_2 = 62,
+ /// Level 3 conformance (VT300 series, e.g. VT320, VT340).
+ level_3 = 63,
+ /// Level 4 conformance (VT400 series, e.g. VT420).
+ level_4 = 64,
+ /// Level 5 conformance (VT500 series, e.g. VT510, VT520, VT525).
+ level_5 = 65,
+
+ _,
+
+ pub const vt101 = ConformanceLevel.vt100;
+ pub const vt220 = ConformanceLevel.level_2;
+ pub const vt240 = ConformanceLevel.level_2;
+ pub const vt320 = ConformanceLevel.level_3;
+ pub const vt340 = ConformanceLevel.level_3;
+ pub const vt420 = ConformanceLevel.level_4;
+ pub const vt510 = ConformanceLevel.level_5;
+ pub const vt520 = ConformanceLevel.level_5;
+ pub const vt525 = ConformanceLevel.level_5;
+};
+
+/// Terminal type identifier reported as the Pp parameter in the
+/// secondary device attributes (DA2) response. Values correspond
+/// to the decTerminalID resource in xterm.
+pub const DeviceType = enum(u16) {
+ vt100 = 0,
+ vt220 = 1,
+ vt240 = 2,
+ vt330 = 18,
+ vt340 = 19,
+ vt320 = 24,
+ vt382 = 32,
+ vt420 = 41,
+ vt510 = 61,
+ vt520 = 64,
+ vt525 = 65,
+ _,
+};
+
+test "primary default" {
+ var buf: [64]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try (Primary{}).encode(&writer);
+ try testing.expectEqualStrings("\x1b[?62;22c", writer.buffered());
+}
+
+test "primary with clipboard" {
+ var buf: [64]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try (Primary{ .features = &.{ .ansi_color, .clipboard } }).encode(&writer);
+ try testing.expectEqualStrings("\x1b[?62;22;52c", writer.buffered());
+}
+
+test "primary with multiple features" {
+ var buf: [64]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try (Primary{
+ .conformance_level = .vt420,
+ .features = &.{ .columns_132, .selective_erase, .ansi_color },
+ }).encode(&writer);
+ try testing.expectEqualStrings("\x1b[?64;1;6;22c", writer.buffered());
+}
+
+test "primary no features" {
+ var buf: [64]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try (Primary{
+ .conformance_level = .vt100,
+ .features = &.{},
+ }).encode(&writer);
+ try testing.expectEqualStrings("\x1b[?1c", writer.buffered());
+}
+
+test "secondary default" {
+ var buf: [64]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try (Secondary{}).encode(&writer);
+ try testing.expectEqualStrings("\x1b[>1;0;0c", writer.buffered());
+}
+
+test "tertiary default" {
+ var buf: [64]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try (Tertiary{}).encode(&writer);
+ try testing.expectEqualStrings("\x1bP!|00000000\x1b\\", writer.buffered());
+}
+
+test "tertiary custom unit id" {
+ var buf: [64]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buf);
+ try (Tertiary{ .unit_id = 0xAABBCCDD }).encode(&writer);
+ try testing.expectEqualStrings("\x1bP!|AABBCCDD\x1b\\", writer.buffered());
+}