mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
terminal/new: print some characters (test string)
This commit is contained in:
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user