diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 8a5713333..c1bed792f 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -3224,7 +3224,7 @@ pub const Pin = struct { /// Returns the grapheme codepoints for the given cell. These are only /// the EXTRA codepoints and not the first codepoint. - pub fn grapheme(self: Pin, cell: *pagepkg.Cell) ?[]u21 { + pub fn grapheme(self: Pin, cell: *const pagepkg.Cell) ?[]u21 { return self.page.data.lookupGrapheme(cell); } diff --git a/src/terminal/kitty/graphics_unicode.zig b/src/terminal/kitty/graphics_unicode.zig index 21f3657e5..ff1e60955 100644 --- a/src/terminal/kitty/graphics_unicode.zig +++ b/src/terminal/kitty/graphics_unicode.zig @@ -32,21 +32,60 @@ pub const PlacementIterator = struct { // A row must have graphemes to possibly have virtual placements // since virtual placements are done via diacritics. if (row.rowAndCell().row.grapheme) { + // TODO: document + const prev: ?Placement = null; + _ = prev; + // Iterate over our remaining cells and find one with a placeholder. const cells = row.cells(.right); - for (cells, row.x..) |cell, x| { + for (cells, row.x..) |*cell, x| { if (cell.codepoint() != placeholder) continue; + // TODO: we need to support non-grapheme cells that just + // do continuations all the way through. + assert(cell.hasGrapheme()); + + // "row" now points to the top-left pin of the placement. + row.x = @intCast(x); + + // Build our placement + var p: Placement = .{ + .pin = row.*, + + // Filled in below. Marked as undefined so we can catch + // bugs with safety checks. + .col = undefined, + .row = undefined, + + // For now we don't build runs and we always produce + // single cell placements. + .width = 1, + .height = 1, + }; + + // Determine our row/col by looking at the diacritics. + const cps: []const u21 = row.grapheme(cell) orelse &.{}; + if (cps.len > 0) { + p.row = getIndex(cps[0]) orelse @panic("TODO: invalid"); + if (cps.len > 1) { + p.col = getIndex(cps[1]) orelse @panic("TODO: invalid"); + if (cps.len > 2) { + @panic("TODO: higher 8 bits of image ID"); + } + } + } else @panic("TODO: continuations"); + if (x == cells.len - 1) { // We are at the end of this row so move to the next row self.row = self.row_it.next(); } else { - // We can move right to the next cell. - row.x = @intCast(x + 1); + // We can move right to the next cell. row is a pointer + // to self.row so we can modify it directly. + assert(@intFromPtr(row) == @intFromPtr(&self.row)); + row.x += 1; } - // TODO - return .{}; + return p; } } @@ -60,16 +99,30 @@ pub const PlacementIterator = struct { /// A virtual placement in the terminal. This can represent more than /// one cell if the cells combine to be a run. -pub const Placement = struct {}; +pub const Placement = struct { + /// The top-left pin of the placement. This can be used to get the + /// screen x/y. + pin: terminal.Pin, + + /// Starting row/col index for the image itself. This is the "fragment" + /// of the image we want to show in this placement. This is 0-indexed. + col: u32, + row: u32, + + /// The width/height in cells of this placement. + width: u32, + height: u32, +}; /// Get the row/col index for a diacritic codepoint. These are 0-indexed. -pub fn getIndex(cp: u21) ?usize { - return std.sort.binarySearch(u21, cp, diacritics, {}, (struct { +pub fn getIndex(cp: u21) ?u32 { + const idx = std.sort.binarySearch(u21, cp, diacritics, {}, (struct { fn order(context: void, lhs: u21, rhs: u21) std.math.Order { _ = context; return std.math.order(lhs, rhs); } - }).order); + }).order) orelse return null; + return @intCast(idx); } /// These are the diacritics used with the Kitty graphics protocol @@ -425,7 +478,8 @@ test "unicode placement: single" { var it = placementIterator(pin, null); { const p = it.next().?; - _ = p; + try testing.expectEqual(0, p.row); + try testing.expectEqual(0, p.col); } try testing.expect(it.next() == null); } diff --git a/src/terminal/page.zig b/src/terminal/page.zig index 396e976be..18b63f126 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -1220,7 +1220,7 @@ pub const Page = struct { /// Returns the codepoints for the given cell. These are the codepoints /// in addition to the first codepoint. The first codepoint is NOT /// included since it is on the cell itself. - pub fn lookupGrapheme(self: *const Page, cell: *Cell) ?[]u21 { + pub fn lookupGrapheme(self: *const Page, cell: *const Cell) ?[]u21 { const cell_offset = getOffset(Cell, self.memory, cell); const map = self.grapheme_map.map(self.memory); const slice = map.get(cell_offset) orelse return null;