mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 17:26: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 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");
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user