diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 56071ce22..030ed8d64 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1908,7 +1908,7 @@ fn rebuildCells2( // font shaping by row. In the future, we will also do dirty tracking // by row. var row_it = screen.pages.rowIterator(.right_down, .{ .viewport = .{} }, null); - var y: usize = 0; + var y: terminal.size.CellCountInt = 0; while (row_it.next()) |row| { defer y += 1; diff --git a/src/renderer/metal/cell.zig b/src/renderer/metal/cell.zig index 2073be6e0..f55e99adb 100644 --- a/src/renderer/metal/cell.zig +++ b/src/renderer/metal/cell.zig @@ -232,7 +232,10 @@ test Contents { // Assert that get returns null for everything. for (0..rows) |y| { for (0..cols) |x| { - try testing.expect(c.get(.bg, .{ .x = x, .y = y }) == null); + try testing.expect(c.get(.bg, .{ + .x = @intCast(x), + .y = @intCast(y), + }) == null); } } @@ -250,7 +253,10 @@ test Contents { c.clear(1); for (0..rows) |y| { for (0..cols) |x| { - try testing.expect(c.get(.bg, .{ .x = x, .y = y }) == null); + try testing.expect(c.get(.bg, .{ + .x = @intCast(x), + .y = @intCast(y), + }) == null); } } } diff --git a/src/renderer/metal/shaders.zig b/src/renderer/metal/shaders.zig index f764e4909..2d7fb9700 100644 --- a/src/renderer/metal/shaders.zig +++ b/src/renderer/metal/shaders.zig @@ -287,12 +287,12 @@ fn initPostPipeline( /// This is a single parameter for the terminal cell shader. pub const CellText = extern struct { mode: Mode, - grid_pos: [2]u16, glyph_pos: [2]u32 = .{ 0, 0 }, glyph_size: [2]u32 = .{ 0, 0 }, glyph_offset: [2]i32 = .{ 0, 0 }, color: [4]u8, bg_color: [4]u8, + grid_pos: [2]u16, cell_width: u8, pub const Mode = enum(u8) { diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 1946a84aa..95df3e911 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -1421,7 +1421,7 @@ fn resizeWithoutReflowGrowCols( // Keeps track of all our copied rows. Assertions at the end is that // we copied exactly our page size. - var copied: usize = 0; + var copied: size.CellCountInt = 0; // This function has an unfortunate side effect in that it causes memory // fragmentation on rows if the columns are increasing in a way that @@ -2545,7 +2545,7 @@ pub fn cellIterator( pub const RowIterator = struct { page_it: PageIterator, chunk: ?PageIterator.Chunk = null, - offset: usize = 0, + offset: size.CellCountInt = 0, pub fn next(self: *RowIterator) ?Pin { const chunk = self.chunk orelse return null; @@ -2767,8 +2767,8 @@ pub const PageIterator = struct { pub const Chunk = struct { page: *List.Node, - start: usize, - end: usize, + start: size.CellCountInt, + end: size.CellCountInt, pub fn rows(self: Chunk) []Row { const rows_ptr = self.page.data.rows.ptr(self.page.data.memory); @@ -2944,8 +2944,8 @@ fn growRows(self: *PageList, n: usize) !void { /// should limit the number of active pins as much as possible. pub const Pin = struct { page: *List.Node, - y: usize = 0, - x: usize = 0, + y: size.CellCountInt = 0, + x: size.CellCountInt = 0, pub fn rowAndCell(self: Pin) struct { row: *pagepkg.Row, @@ -3104,7 +3104,7 @@ pub const Pin = struct { pub fn left(self: Pin, n: usize) Pin { assert(n <= self.x); var result = self; - result.x -= n; + result.x -= std.math.cast(size.CellCountInt, n) orelse result.x; return result; } @@ -3112,7 +3112,8 @@ pub const Pin = struct { pub fn right(self: Pin, n: usize) Pin { assert(self.x + n < self.page.data.size.cols); var result = self; - result.x += n; + result.x +|= std.math.cast(size.CellCountInt, n) orelse + std.math.maxInt(size.CellCountInt); return result; } @@ -3147,7 +3148,8 @@ pub const Pin = struct { const rows = self.page.data.size.rows - (self.y + 1); if (n <= rows) return .{ .offset = .{ .page = self.page, - .y = n + self.y, + .y = std.math.cast(size.CellCountInt, self.y + n) orelse + std.math.maxInt(size.CellCountInt), .x = self.x, } }; @@ -3165,7 +3167,8 @@ pub const Pin = struct { } }; if (n_left <= page.data.size.rows) return .{ .offset = .{ .page = page, - .y = n_left - 1, + .y = std.math.cast(size.CellCountInt, n_left - 1) orelse + std.math.maxInt(size.CellCountInt), .x = self.x, } }; n_left -= page.data.size.rows; @@ -3184,7 +3187,8 @@ pub const Pin = struct { // Index fits within this page if (n <= self.y) return .{ .offset = .{ .page = self.page, - .y = self.y - n, + .y = std.math.cast(size.CellCountInt, self.y - n) orelse + std.math.maxInt(size.CellCountInt), .x = self.x, } }; @@ -3198,7 +3202,8 @@ pub const Pin = struct { } }; if (n_left <= page.data.size.rows) return .{ .offset = .{ .page = page, - .y = page.data.size.rows - n_left, + .y = std.math.cast(size.CellCountInt, page.data.size.rows - n_left) orelse + std.math.maxInt(size.CellCountInt), .x = self.x, } }; n_left -= page.data.size.rows; @@ -3210,8 +3215,8 @@ const Cell = struct { page: *List.Node, row: *pagepkg.Row, cell: *pagepkg.Cell, - row_idx: usize, - col_idx: usize, + row_idx: size.CellCountInt, + col_idx: size.CellCountInt, /// Get the cell style. /// @@ -3231,7 +3236,7 @@ const Cell = struct { /// this file then consider a different approach and ask yourself very /// carefully if you really need this. pub fn screenPoint(self: Cell) point.Point { - var y: usize = self.row_idx; + var y: size.CellCountInt = self.row_idx; var page = self.page; while (page.prev) |prev| { y += prev.data.size.rows; @@ -3402,7 +3407,7 @@ test "PageList pointFromPin traverse pages" { try testing.expectEqual(point.Point{ .screen = .{ - .y = expected_y, + .y = @intCast(expected_y), .x = 2, }, }, s.pointFromPin(.screen, .{ @@ -5629,7 +5634,7 @@ test "PageList resize (no reflow) more rows adds blank rows if cursor at bottom" // Go through our active, we should get only 3,4,5 for (0..3) |y| { - const get = s.getCell(.{ .active = .{ .y = y } }).?; + const get = s.getCell(.{ .active = .{ .y = @intCast(y) } }).?; const expected: u21 = @intCast(y + 2); try testing.expectEqual(expected, get.cell.content.codepoint); } @@ -6557,7 +6562,7 @@ test "PageList resize reflow less cols no wrapped rows" { while (it.next()) |offset| { for (0..4) |x| { var offset_copy = offset; - offset_copy.x = x; + offset_copy.x = @intCast(x); const rac = offset_copy.rowAndCell(); const cells = offset.page.data.getCells(rac.row); try testing.expectEqual(@as(usize, 5), cells.len); @@ -7247,7 +7252,7 @@ test "PageList resize reflow less cols copy style" { while (it.next()) |offset| { for (0..s.cols - 1) |x| { var offset_copy = offset; - offset_copy.x = x; + offset_copy.x = @intCast(x); const rac = offset_copy.rowAndCell(); const style_id = rac.cell.style_id; try testing.expect(style_id != 0); diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 98c3daa21..58e4e681b 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -1412,8 +1412,8 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) ! if (mapbuilder) |*b| { for (0..encode_len) |_| try b.append(.{ .page = chunk.page, - .y = y, - .x = x, + .y = @intCast(y), + .x = @intCast(x), }); } } @@ -1425,8 +1425,8 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) ! if (mapbuilder) |*b| { for (0..encode_len) |_| try b.append(.{ .page = chunk.page, - .y = y, - .x = x, + .y = @intCast(y), + .x = @intCast(x), }); } } @@ -1441,7 +1441,7 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) ! try strbuilder.append('\n'); if (mapbuilder) |*b| try b.append(.{ .page = chunk.page, - .y = y, + .y = @intCast(y), .x = chunk.page.data.size.cols - 1, }); } @@ -3959,7 +3959,10 @@ test "Screen: resize (no reflow) less rows trims blank lines" { // Write only a background color into the remaining rows for (1..s.pages.rows) |y| { - const list_cell = s.pages.getCell(.{ .active = .{ .x = 0, .y = y } }).?; + const list_cell = s.pages.getCell(.{ .active = .{ + .x = 0, + .y = @intCast(y), + } }).?; list_cell.cell.* = .{ .content_tag = .bg_color_rgb, .content = .{ .color_rgb = .{ .r = 0xFF, .g = 0, .b = 0 } }, @@ -3991,7 +3994,10 @@ test "Screen: resize (no reflow) more rows trims blank lines" { // Write only a background color into the remaining rows for (1..s.pages.rows) |y| { - const list_cell = s.pages.getCell(.{ .active = .{ .x = 0, .y = y } }).?; + const list_cell = s.pages.getCell(.{ .active = .{ + .x = 0, + .y = @intCast(y), + } }).?; list_cell.cell.* = .{ .content_tag = .bg_color_rgb, .content = .{ .color_rgb = .{ .r = 0xFF, .g = 0, .b = 0 } }, @@ -4118,7 +4124,10 @@ test "Screen: resize (no reflow) more rows with soft wrapping" { // Every second row should be wrapped for (0..6) |y| { - const list_cell = s.pages.getCell(.{ .screen = .{ .x = 0, .y = y } }).?; + const list_cell = s.pages.getCell(.{ .screen = .{ + .x = 0, + .y = @intCast(y), + } }).?; const row = list_cell.row; const wrapped = (y % 2 == 0); try testing.expectEqual(wrapped, row.wrap); @@ -4135,7 +4144,10 @@ test "Screen: resize (no reflow) more rows with soft wrapping" { // Every second row should be wrapped for (0..6) |y| { - const list_cell = s.pages.getCell(.{ .screen = .{ .x = 0, .y = y } }).?; + const list_cell = s.pages.getCell(.{ .screen = .{ + .x = 0, + .y = @intCast(y), + } }).?; const row = list_cell.row; const wrapped = (y % 2 == 0); try testing.expectEqual(wrapped, row.wrap); diff --git a/src/terminal/Selection.zig b/src/terminal/Selection.zig index 9da0f134e..d1bd4accb 100644 --- a/src/terminal/Selection.zig +++ b/src/terminal/Selection.zig @@ -435,7 +435,7 @@ pub fn adjust( const cells = next.page.data.getCells(rac.row); if (page.Cell.hasTextAny(cells)) { end_pin.* = next; - end_pin.x = cells.len - 1; + end_pin.x = @intCast(cells.len - 1); break; } } diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 94d32e1a8..9ddec218e 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -4169,7 +4169,10 @@ test "Terminal: insertLines colors with bg color" { } for (0..t.cols) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 1 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 1, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -5297,7 +5300,10 @@ test "Terminal: index bottom of primary screen background sgr" { defer testing.allocator.free(str); try testing.expectEqualStrings("\n\n\nA", str); for (0..5) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 4 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 4, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -5349,7 +5355,10 @@ test "Terminal: index bottom of scroll region with background SGR" { } for (0..t.cols) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 2 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 2, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -5961,7 +5970,10 @@ test "Terminal: deleteLines colors with bg color" { } for (0..t.cols) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 4 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 4, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -6148,7 +6160,10 @@ test "Terminal: deleteLines resets wrap" { } for (0..t.rows) |y| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = 0, .y = y } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = 0, + .y = @intCast(y), + } }).?; const row = list_cell.row; try testing.expect(!row.wrap); } @@ -7183,7 +7198,10 @@ test "Terminal: deleteChars preserves background sgr" { try testing.expectEqualStrings("AB23", str); } for (t.cols - 2..t.cols) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 0 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 0, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -7573,7 +7591,10 @@ test "Terminal: eraseLine right preserves background sgr" { defer testing.allocator.free(str); try testing.expectEqualStrings("A", str); for (1..5) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 0 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 0, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -7727,7 +7748,10 @@ test "Terminal: eraseLine left preserves background sgr" { defer testing.allocator.free(str); try testing.expectEqualStrings(" CDE", str); for (0..2) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 0 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 0, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -7847,7 +7871,10 @@ test "Terminal: eraseLine complete preserves background sgr" { defer testing.allocator.free(str); try testing.expectEqualStrings("", str); for (0..5) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 0 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 0, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -8096,7 +8123,10 @@ test "Terminal: eraseDisplay erase below preserves SGR bg" { defer testing.allocator.free(str); try testing.expectEqualStrings("ABC\nD", str); for (1..5) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 1 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 1, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, @@ -8271,7 +8301,10 @@ test "Terminal: eraseDisplay erase above preserves SGR bg" { defer testing.allocator.free(str); try testing.expectEqualStrings("\n F\nGHI", str); for (0..2) |x| { - const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 1 } }).?; + const list_cell = t.screen.pages.getCell(.{ .active = .{ + .x = @intCast(x), + .y = 1, + } }).?; try testing.expect(list_cell.cell.content_tag == .bg_color_rgb); try testing.expectEqual(Cell.RGB{ .r = 0xFF, diff --git a/src/terminal/kitty/graphics_storage.zig b/src/terminal/kitty/graphics_storage.zig index 1071f065a..547f78b97 100644 --- a/src/terminal/kitty/graphics_storage.zig +++ b/src/terminal/kitty/graphics_storage.zig @@ -5,6 +5,7 @@ const ArenaAllocator = std.heap.ArenaAllocator; const terminal = @import("../main.zig"); const point = @import("../point.zig"); +const size = @import("../size.zig"); const command = @import("graphics_command.zig"); const PageList = @import("../PageList.zig"); const Screen = @import("../Screen.zig"); @@ -265,13 +266,13 @@ pub const ImageStorage = struct { ); }, - .intersect_cell => |v| { + .intersect_cell => |v| intersect_cell: { self.deleteIntersecting( alloc, t, .{ .active = .{ - .x = v.x, - .y = v.y, + .x = std.math.cast(size.CellCountInt, v.x) orelse break :intersect_cell, + .y = std.math.cast(size.CellCountInt, v.y) orelse break :intersect_cell, } }, v.delete, {}, @@ -279,13 +280,13 @@ pub const ImageStorage = struct { ); }, - .intersect_cell_z => |v| { + .intersect_cell_z => |v| intersect_cell_z: { self.deleteIntersecting( alloc, t, .{ .active = .{ - .x = v.x, - .y = v.y, + .x = std.math.cast(size.CellCountInt, v.x) orelse break :intersect_cell_z, + .y = std.math.cast(size.CellCountInt, v.y) orelse break :intersect_cell_z, } }, v.delete, v.z, @@ -317,7 +318,7 @@ pub const ImageStorage = struct { // v.y is in active coords so we want to convert it to a pin // so we can compare by page offsets. const target_pin = t.screen.pages.pin(.{ .active = .{ - .y = v.y, + .y = std.math.cast(size.CellCountInt, v.y) orelse break :row, } }) orelse break :row; var it = self.placements.iterator(); diff --git a/src/terminal/point.zig b/src/terminal/point.zig index 41b7a3558..45aa28dea 100644 --- a/src/terminal/point.zig +++ b/src/terminal/point.zig @@ -1,6 +1,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; +const size = @import("size.zig"); /// The possible reference locations for a point. When someone says "(42, 80)" in the context of a terminal, that could mean multiple /// things: it is in the current visible viewport? the current active @@ -65,8 +66,8 @@ pub const Point = union(Tag) { }; pub const Coordinate = struct { - x: usize = 0, - y: usize = 0, + x: size.CellCountInt = 0, + y: size.CellCountInt = 0, pub fn eql(self: Coordinate, other: Coordinate) bool { return self.x == other.x and self.y == other.y;