terminal/new: print some characters (test string)

This commit is contained in:
Mitchell Hashimoto
2024-02-18 22:11:21 -08:00
parent 1216603e68
commit 0a27e5a58b
2 changed files with 106 additions and 4 deletions

View File

@ -3,6 +3,7 @@ const Screen = @This();
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const unicode = @import("../../unicode/main.zig");
const pagepkg = @import("page.zig");
const Page = pagepkg.Page;
@ -46,16 +47,31 @@ pages: PageList,
viewport: *PageList.Node,
viewport_row: usize,
/// The current cursor position
cursor: Cursor,
/// The current desired screen dimensions. I say "desired" because individual
/// pages may still be a different size and not yet reflowed since we lazily
/// reflow text.
cols: usize,
rows: usize,
/// The cursor position.
const Cursor = struct {
// The x/y position within the viewport.
x: usize = 0,
y: usize = 0,
x: usize,
y: usize,
/// The "last column flag (LCF)" as its called. If this is set then the
/// next character print will force a soft-wrap.
pending_wrap: bool = false,
// The page that the cursor is on and the offset into that page that
// the current y exists.
page: *PageList.Node,
page_row: usize,
page_row_ptr: *pagepkg.Row,
page_cell_ptr: *pagepkg.Cell,
};
/// Initialize a new screen.
@ -88,12 +104,27 @@ pub fn init(
var page_list: PageList = .{};
page_list.prepend(page);
const cursor_row_ptr, const cursor_cell_ptr = ptr: {
const rac = page.data.getRowAndCell(0, 0);
break :ptr .{ rac.row, rac.cell };
};
return .{
.alloc = alloc,
.cols = cols,
.rows = rows,
.page_pool = pool,
.pages = page_list,
.viewport = page,
.viewport_row = 0,
.cursor = .{
.x = 0,
.y = 0,
.page = page,
.page_row = 0,
.page_row_ptr = cursor_row_ptr,
.page_cell_ptr = cursor_cell_ptr,
},
};
}
@ -104,10 +135,44 @@ pub fn deinit(self: *Screen) void {
self.page_pool.deinit();
}
test {
fn testWriteString(self: *Screen, text: []const u8) !void {
const view = try std.unicode.Utf8View.init(text);
var iter = view.iterator();
while (iter.nextCodepoint()) |c| {
if (self.cursor.x == self.cols) {
@panic("wrap not implemented");
}
const width: usize = if (c <= 0xFF) 1 else @intCast(unicode.table.get(c).width);
if (width == 0) {
@panic("zero-width todo");
}
assert(width == 1 or width == 2);
switch (width) {
1 => {
self.cursor.page_cell_ptr.codepoint = c;
self.cursor.x += 1;
if (self.cursor.x < self.cols) {
const cell_ptr: [*]pagepkg.Cell = @ptrCast(self.cursor.page_cell_ptr);
self.cursor.page_cell_ptr = @ptrCast(cell_ptr + 1);
} else {
@panic("wrap not implemented");
}
},
2 => @panic("todo double-width"),
else => unreachable,
}
}
}
test "Screen read and write" {
const testing = std.testing;
const alloc = testing.allocator;
var s = try Screen.init(alloc, 80, 24, 1000);
defer s.deinit();
try s.testWriteString("hello, world");
}

View File

@ -107,6 +107,21 @@ pub const Page = struct {
self.* = undefined;
}
/// Get the row and cell for the given X/Y within this page.
pub fn getRowAndCell(self: *const Page, x: usize, y: usize) struct {
row: *Row,
cell: *Cell,
} {
assert(y < self.capacity.rows);
assert(x < self.capacity.cols);
const rows = self.rows.ptr(self.memory);
const row = &rows[y];
const cell = &row.cells.ptr(self.memory)[x];
return .{ .row = row, .cell = cell };
}
const Layout = struct {
total_size: usize,
rows_start: usize,
@ -184,7 +199,7 @@ pub const Cell = packed struct(u32) {
// });
// }
test "Page" {
test "Page init" {
const testing = std.testing;
const alloc = testing.allocator;
var page = try Page.init(alloc, .{
@ -194,3 +209,25 @@ test "Page" {
});
defer page.deinit(alloc);
}
test "Page read and write cells" {
const testing = std.testing;
const alloc = testing.allocator;
var page = try Page.init(alloc, .{
.cols = 10,
.rows = 10,
.styles = 8,
});
defer page.deinit(alloc);
for (0..page.capacity.rows) |y| {
const rac = page.getRowAndCell(1, y);
rac.cell.codepoint = @intCast(y);
}
// Read it again
for (0..page.capacity.rows) |y| {
const rac = page.getRowAndCell(1, y);
try testing.expectEqual(@as(u21, @intCast(y)), rac.cell.codepoint);
}
}