terminal: stream/parser changes

This commit is contained in:
Qwerasd
2024-02-07 00:12:37 -05:00
parent 7da82688b8
commit f8c544c119
2 changed files with 39 additions and 22 deletions

View File

@ -185,7 +185,7 @@ pub const Action = union(enum) {
/// Keeps track of the parameter sep used for CSI params. We allow colons /// Keeps track of the parameter sep used for CSI params. We allow colons
/// to be used ONLY by the 'm' CSI action. /// to be used ONLY by the 'm' CSI action.
const ParamSepState = enum(u8) { pub const ParamSepState = enum(u8) {
none = 0, none = 0,
semicolon = ';', semicolon = ';',
colon = ':', colon = ':',
@ -279,7 +279,7 @@ pub fn next(self: *Parser, c: u8) [3]?Action {
}; };
} }
fn collect(self: *Parser, c: u8) void { pub fn collect(self: *Parser, c: u8) void {
if (self.intermediates_idx >= MAX_INTERMEDIATE) { if (self.intermediates_idx >= MAX_INTERMEDIATE) {
log.warn("invalid intermediates count", .{}); log.warn("invalid intermediates count", .{});
return; return;

View File

@ -74,17 +74,14 @@ pub fn Stream(comptime Handler: type) type {
if (offset >= input.len) return; if (offset >= input.len) return;
try self.next(input[offset]); try self.next(input[offset]);
offset += 1; offset += 1;
} else if (self.parser.state != .ground) {
// If we're not in the ground state then we process until
// we are. This can happen if the last chunk of input put us
// in the middle of a control sequence.
for (input[offset..]) |single| {
try self.nextNonUtf8(single);
offset += 1;
if (self.parser.state == .ground) break;
}
} }
// If we're not in the ground state then we process until
// we are. This can happen if the last chunk of input put us
// in the middle of a control sequence.
offset += try self.consumeUntilGround(input[offset..]);
if (offset >= input.len) return;
// If we're in the ground state then we can use SIMD to process // If we're in the ground state then we can use SIMD to process
// input until we see an ESC (0x1B), since all other characters // input until we see an ESC (0x1B), since all other characters
// up to that point are just UTF-8. // up to that point are just UTF-8.
@ -112,26 +109,46 @@ pub fn Stream(comptime Handler: type) type {
} }
// Process our control sequence. // Process our control sequence.
for (input[offset..]) |single| { self.parser.state = .escape;
try self.nextNonUtf8(single); offset += 1;
offset += 1; offset += try self.consumeUntilGround(input[offset..]);
if (self.parser.state == .ground) break;
}
} }
} }
/// Parses escape sequences until the parser reaches the ground state.
/// Returns the number of bytes consumed from the provided input.
inline fn consumeUntilGround(self: *Self, input: []const u8) !usize {
var offset: usize = 0;
while (self.parser.state != .ground) {
if (offset >= input.len) return input.len;
try self.nextNonUtf8(input[offset]);
offset += 1;
}
return offset;
}
/// Like nextSlice but takes one byte and is necessarilly a scalar /// Like nextSlice but takes one byte and is necessarilly a scalar
/// operation that can't use SIMD. Prefer nextSlice if you can and /// operation that can't use SIMD. Prefer nextSlice if you can and
/// try to get multiple bytes at once. /// try to get multiple bytes at once.
pub fn next(self: *Self, c: u8) !void { pub fn next(self: *Self, c: u8) !void {
// The scalar path can be responsible for decoding UTF-8. // The scalar path can be responsible for decoding UTF-8.
if (self.parser.state == .ground and c != 0x1B) { if (self.parser.state == .ground and c != 0x1B) {
var consumed = false; const res = self.utf8decoder.next(c);
while (!consumed) { const consumed = res[1];
const res = self.utf8decoder.next(c); if (res[0]) |codepoint| {
consumed = res[1]; if (codepoint < 0xF) {
if (res[0]) |codepoint| { try self.execute(@intCast(codepoint));
if (codepoint <= 0xF) { } else {
try self.print(@intCast(codepoint));
}
}
if (!consumed) {
const retry = self.utf8decoder.next(c);
// It should be impossible for the decoder
// to not consume the byte twice in a row.
assert(retry[1] == true);
if (retry[0]) |codepoint| {
if (codepoint < 0xF) {
try self.execute(@intCast(codepoint)); try self.execute(@intCast(codepoint));
} else { } else {
try self.print(@intCast(codepoint)); try self.print(@intCast(codepoint));