this repo has no description
1const std = @import("std");
2
3/// Control bytes. See man 7 ascii
4pub const C0 = enum(u8) {
5 NUL = 0x00,
6 SOH = 0x01,
7 STX = 0x02,
8 ETX = 0x03,
9 EOT = 0x04,
10 ENQ = 0x05,
11 ACK = 0x06,
12 BEL = 0x07,
13 BS = 0x08,
14 HT = 0x09,
15 LF = 0x0a,
16 VT = 0x0b,
17 FF = 0x0c,
18 CR = 0x0d,
19 SO = 0x0e,
20 SI = 0x0f,
21 DLE = 0x10,
22 DC1 = 0x11,
23 DC2 = 0x12,
24 DC3 = 0x13,
25 DC4 = 0x14,
26 NAK = 0x15,
27 SYN = 0x16,
28 ETB = 0x17,
29 CAN = 0x18,
30 EM = 0x19,
31 SUB = 0x1a,
32 ESC = 0x1b,
33 FS = 0x1c,
34 GS = 0x1d,
35 RS = 0x1e,
36 US = 0x1f,
37};
38
39pub const CSI = struct {
40 intermediate: ?u8 = null,
41 private_marker: ?u8 = null,
42
43 final: u8,
44 params: []const u8,
45
46 pub fn hasIntermediate(self: CSI, b: u8) bool {
47 return b == self.intermediate orelse return false;
48 }
49
50 pub fn hasPrivateMarker(self: CSI, b: u8) bool {
51 return b == self.private_marker orelse return false;
52 }
53
54 pub fn iterator(self: CSI, comptime T: type) ParamIterator(T) {
55 return .{ .bytes = self.params };
56 }
57
58 pub fn format(self: CSI, writer: anytype) !void {
59 if (self.private_marker == null and self.intermediate == null)
60 try writer.print("CSI {s} {c}", .{
61 self.params,
62 self.final,
63 })
64 else if (self.private_marker != null and self.intermediate == null)
65 try writer.print("CSI {c} {s} {c}", .{
66 self.private_marker.?,
67 self.params,
68 self.final,
69 })
70 else if (self.private_marker == null and self.intermediate != null)
71 try writer.print("CSI {s} {c} {c}", .{
72 self.params,
73 self.intermediate.?,
74 self.final,
75 })
76 else
77 try writer.print("CSI {c} {s} {c} {c}", .{
78 self.private_marker.?,
79 self.params,
80 self.intermediate.?,
81 self.final,
82 });
83 }
84};
85
86pub fn ParamIterator(T: type) type {
87 return struct {
88 const Self = @This();
89
90 bytes: []const u8,
91 idx: usize = 0,
92 /// indicates the next parameter will be a sub parameter of the current
93 next_is_sub: bool = false,
94 /// indicates the current parameter was an empty string
95 is_empty: bool = false,
96
97 pub fn next(self: *Self) ?T {
98 // reset state
99 self.next_is_sub = false;
100 self.is_empty = false;
101
102 const start = self.idx;
103 var val: T = 0;
104 while (self.idx < self.bytes.len) {
105 defer self.idx += 1; // defer so we trigger on return as well
106 const b = self.bytes[self.idx];
107 switch (b) {
108 0x30...0x39 => {
109 val = (val * 10) + (b - 0x30);
110 if (self.idx == self.bytes.len - 1) return val;
111 },
112 ':', ';' => {
113 self.next_is_sub = b == ':';
114 self.is_empty = self.idx == start;
115 return val;
116 },
117 else => return null,
118 }
119 }
120 return null;
121 }
122
123 /// verifies there are at least n more parameters
124 pub fn hasAtLeast(self: *Self, n: usize) bool {
125 const start = self.idx;
126 defer self.idx = start;
127
128 var i: usize = 0;
129 while (self.next()) |_| {
130 i += 1;
131 if (i >= n) return true;
132 }
133 return i >= n;
134 }
135 };
136}