diff --git a/src/terminal/Parser.zig b/src/terminal/Parser.zig index 3c7b5bd65..cee846375 100644 --- a/src/terminal/Parser.zig +++ b/src/terminal/Parser.zig @@ -153,18 +153,24 @@ fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action { .print => Action{ .print = c }, .execute => Action{ .execute = c }, .collect => collect: { + if (self.intermediates_idx >= MAX_INTERMEDIATE) { + log.warn("invalid intermediates count", .{}); + break :collect null; + } + self.intermediates[self.intermediates_idx] = c; - // TODO: incr, bounds check + self.intermediates_idx += 1; // The client is expected to perform no action. break :collect null; }, .param => param: { - // TODO: bounds check - // Semicolon separates parameters. If we encounter a semicolon // we need to store and move on to the next parameter. if (c == ';') { + // Ignore too many parameters + if (self.params_idx >= MAX_PARAMS) break :param null; + // Set param final value self.params[self.params_idx] = self.param_acc; self.params_idx += 1; @@ -244,6 +250,25 @@ test { } } +test "esc: ESC ( B" { + var p = init(); + _ = p.next(0x1B); + _ = p.next('('); + + { + const a = p.next('B'); + try testing.expect(p.state == .ground); + try testing.expect(a[0] == null); + try testing.expect(a[1].? == .esc_dispatch); + try testing.expect(a[2] == null); + + const d = a[1].?.esc_dispatch; + try testing.expect(d.final == 'B'); + try testing.expect(d.intermediates.len == 1); + try testing.expect(d.intermediates[0] == '('); + } +} + test "csi: ESC [ H" { var p = init(); _ = p.next(0x1B); diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 31b5cca67..7f361ad33 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -56,6 +56,7 @@ const Cursor = struct { y: usize, // Bold specifies that text written should be bold + // TODO: connect to render bold: bool = false, }; @@ -307,7 +308,15 @@ pub fn eraseDisplay( for (self.screen.items) |*line| line.deinit(alloc); self.screen.clearRetainingCapacity(); }, - else => @panic("unimplemented"), + + .below => { + log.warn("TODO: below eraseDisplay", .{}); + }, + + else => { + log.err("unimplemented display mode: {}", .{mode}); + @panic("unimplemented"); + }, } } @@ -329,7 +338,22 @@ pub fn eraseLine( for (line.items[self.cursor.x..line.items.len]) |*cell| cell.char = 0; }, - else => @panic("unimplemented"), + + .left => { + // If our cursor is outside our screen, we can't erase anything. + if (self.cursor.y >= self.screen.items.len) return; + var line = &self.screen.items[self.cursor.y]; + + // Clear up to our cursor + const end = @minimum(line.items.len - 1, self.cursor.x); + for (line.items[0..end]) |*cell| + cell.char = 0; + }, + + else => { + log.err("unimplemented erase line mode: {}", .{mode}); + @panic("unimplemented"); + }, } }