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 std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert; const assert = std.debug.assert;
const unicode = @import("../../unicode/main.zig");
const pagepkg = @import("page.zig"); const pagepkg = @import("page.zig");
const Page = pagepkg.Page; const Page = pagepkg.Page;
@ -46,16 +47,31 @@ pages: PageList,
viewport: *PageList.Node, viewport: *PageList.Node,
viewport_row: usize, 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. /// The cursor position.
const Cursor = struct { const Cursor = struct {
// The x/y position within the viewport. // The x/y position within the viewport.
x: usize = 0, x: usize,
y: usize = 0, 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 page that the cursor is on and the offset into that page that
// the current y exists. // the current y exists.
page: *PageList.Node, page: *PageList.Node,
page_row: usize, page_row: usize,
page_row_ptr: *pagepkg.Row,
page_cell_ptr: *pagepkg.Cell,
}; };
/// Initialize a new screen. /// Initialize a new screen.
@ -88,12 +104,27 @@ pub fn init(
var page_list: PageList = .{}; var page_list: PageList = .{};
page_list.prepend(page); 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 .{ return .{
.alloc = alloc, .alloc = alloc,
.cols = cols,
.rows = rows,
.page_pool = pool, .page_pool = pool,
.pages = page_list, .pages = page_list,
.viewport = page, .viewport = page,
.viewport_row = 0, .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(); 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 testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;
var s = try Screen.init(alloc, 80, 24, 1000); var s = try Screen.init(alloc, 80, 24, 1000);
defer s.deinit(); defer s.deinit();
try s.testWriteString("hello, world");
} }

View File

@ -107,6 +107,21 @@ pub const Page = struct {
self.* = undefined; 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 { const Layout = struct {
total_size: usize, total_size: usize,
rows_start: usize, rows_start: usize,
@ -184,7 +199,7 @@ pub const Cell = packed struct(u32) {
// }); // });
// } // }
test "Page" { test "Page init" {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;
var page = try Page.init(alloc, .{ var page = try Page.init(alloc, .{
@ -194,3 +209,25 @@ test "Page" {
}); });
defer page.deinit(alloc); 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);
}
}