diff --git a/src/font/sprite/Box.zig b/src/font/sprite/Box.zig index 80369d8fd..382aa4206 100644 --- a/src/font/sprite/Box.zig +++ b/src/font/sprite/Box.zig @@ -79,13 +79,15 @@ const Quads = packed struct(u4) { br: bool = false, }; -/// Specification of a git branch node, which can have any of -/// 4 lines connecting to it in vertical or horizontal alignment -const NodeAlign = packed struct(u4) { +/// Specification of a branch drawing node, which consists of a +/// circle which is either empty or filled, and lines connecting +/// optionally between the circle and each of the 4 edges. +const BranchNode = packed struct(u5) { up: bool = false, + right: bool = false, down: bool = false, left: bool = false, - right: bool = false, + filled: bool = false, }; /// Alignment of a figure within a cell @@ -483,14 +485,14 @@ fn draw(self: Box, alloc: Allocator, canvas: *font.sprite.Canvas, cp: u32) !void // '╬' 0x256c => self.draw_lines(canvas, .{ .up = .double, .down = .double, .left = .double, .right = .double }), // '╭' - 0x256d => try self.draw_light_arc(canvas, .br), + 0x256d => try self.draw_arc(canvas, .br, .light), // '╮' - 0x256e => try self.draw_light_arc(canvas, .bl), + 0x256e => try self.draw_arc(canvas, .bl, .light), // '╯' - 0x256f => try self.draw_light_arc(canvas, .tl), + 0x256f => try self.draw_arc(canvas, .tl, .light), // '╰' - 0x2570 => try self.draw_light_arc(canvas, .tr), + 0x2570 => try self.draw_arc(canvas, .tr, .light), // '╱' 0x2571 => self.draw_light_diagonal_upper_right_to_lower_left(canvas), // '╲' @@ -1311,319 +1313,329 @@ fn draw(self: Box, alloc: Allocator, canvas: *font.sprite.Canvas, cp: u32) !void // '🯯' 0x1fbef => self.draw_circle(canvas, Alignment.top_left, true), + // (Below:) + // Branch drawing character set, used for drawing git-like + // graphs in the terminal. Originally implemented in Kitty. + // Ref: + // - https://github.com/kovidgoyal/kitty/pull/7681 + // - https://github.com/kovidgoyal/kitty/pull/7805 + // NOTE: Kitty is GPL licensed, and its code was not referenced + // for these characters, only the loose specification of + // the character set in the pull request descriptions. + // + // TODO(qwerasd): This should be in another file, but really the + // general organization of the sprite font code + // needs to be reworked eventually. + // + //           + //                     + //                     + //             + // '' - 0x0f5d0 => self.hline_middle(canvas, Thickness.light), - + 0x0f5d0 => self.hline_middle(canvas, .light), // '' - 0x0f5d1 => self.vline_middle(canvas, Thickness.light), - + 0x0f5d1 => self.vline_middle(canvas, .light), // '' - // 0x0f5d2 => self.draw_dash_fading(canvas, 4, Direction.LEFT, Thickness.light.height(self.thickness)), - + 0x0f5d2 => self.draw_fading_line(canvas, .right, .light), // '' - // 0x0f5d3 => self.draw_dash_fading(canvas, 4, Direction.RIGHT, Thickness.light.height(self.thickness)), - + 0x0f5d3 => self.draw_fading_line(canvas, .left, .light), // '' - // 0x0f5d4 => self.draw_dash_fading(canvas, 5, Direction.UP, Thickness.light.height(self.thickness)), - + 0x0f5d4 => self.draw_fading_line(canvas, .bottom, .light), // '' - // 0x0f5d5 => self.draw_dash_fading(canvas, 5, Direction.DOWN, Thickness.light.height(self.thickness)), - + 0x0f5d5 => self.draw_fading_line(canvas, .top, .light), // '' - 0x0f5d6 => try self.draw_light_arc(canvas, .br), - + 0x0f5d6 => try self.draw_arc(canvas, .br, .light), // '' - 0x0f5d7 => try self.draw_light_arc(canvas, .bl), - + 0x0f5d7 => try self.draw_arc(canvas, .bl, .light), // '' - 0x0f5d8 => try self.draw_light_arc(canvas, .tr), - + 0x0f5d8 => try self.draw_arc(canvas, .tr, .light), // '' - 0x0f5d9 => try self.draw_light_arc(canvas, .tl), - + 0x0f5d9 => try self.draw_arc(canvas, .tl, .light), // '' 0x0f5da => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tr); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .tr, .light); }, - // '' 0x0f5db => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .br); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .br, .light); }, - // '' 0x0f5dc => { - try self.draw_light_arc(canvas, .tr); - try self.draw_light_arc(canvas, .br); + try self.draw_arc(canvas, .tr, .light); + try self.draw_arc(canvas, .br, .light); }, - // '' 0x0f5dd => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tl); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .tl, .light); }, - // '' 0x0f5de => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .bl); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .bl, .light); }, - // '' 0x0f5df => { - try self.draw_light_arc(canvas, .tl); - try self.draw_light_arc(canvas, .bl); + try self.draw_arc(canvas, .tl, .light); + try self.draw_arc(canvas, .bl, .light); }, // '' 0x0f5e0 => { - try self.draw_light_arc(canvas, .bl); - self.hline_middle(canvas, Thickness.light); + try self.draw_arc(canvas, .bl, .light); + self.hline_middle(canvas, .light); }, - // '' 0x0f5e1 => { - try self.draw_light_arc(canvas, .br); - self.hline_middle(canvas, Thickness.light); + try self.draw_arc(canvas, .br, .light); + self.hline_middle(canvas, .light); }, - // '' 0x0f5e2 => { - try self.draw_light_arc(canvas, .br); - try self.draw_light_arc(canvas, .bl); + try self.draw_arc(canvas, .br, .light); + try self.draw_arc(canvas, .bl, .light); }, - // '' 0x0f5e3 => { - try self.draw_light_arc(canvas, .tl); - self.hline_middle(canvas, Thickness.light); + try self.draw_arc(canvas, .tl, .light); + self.hline_middle(canvas, .light); }, - // '' 0x0f5e4 => { - try self.draw_light_arc(canvas, .tr); - self.hline_middle(canvas, Thickness.light); + try self.draw_arc(canvas, .tr, .light); + self.hline_middle(canvas, .light); }, - // '' 0x0f5e5 => { - try self.draw_light_arc(canvas, .tr); - try self.draw_light_arc(canvas, .tl); + try self.draw_arc(canvas, .tr, .light); + try self.draw_arc(canvas, .tl, .light); }, - // '' 0x0f5e6 => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tl); - try self.draw_light_arc(canvas, .tr); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .tl, .light); + try self.draw_arc(canvas, .tr, .light); }, - // '' 0x0f5e7 => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .bl); - try self.draw_light_arc(canvas, .br); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .bl, .light); + try self.draw_arc(canvas, .br, .light); }, - // '' 0x0f5e8 => { - self.hline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .bl); - try self.draw_light_arc(canvas, .tl); + self.hline_middle(canvas, .light); + try self.draw_arc(canvas, .bl, .light); + try self.draw_arc(canvas, .tl, .light); }, - // '' 0x0f5e9 => { - self.hline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tr); - try self.draw_light_arc(canvas, .br); + self.hline_middle(canvas, .light); + try self.draw_arc(canvas, .tr, .light); + try self.draw_arc(canvas, .br, .light); }, - // '' 0x0f5ea => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tl); - try self.draw_light_arc(canvas, .br); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .tl, .light); + try self.draw_arc(canvas, .br, .light); }, - // '' 0x0f5eb => { - self.vline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tr); - try self.draw_light_arc(canvas, .bl); + self.vline_middle(canvas, .light); + try self.draw_arc(canvas, .tr, .light); + try self.draw_arc(canvas, .bl, .light); }, - // '' 0x0f5ec => { - self.hline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tl); - try self.draw_light_arc(canvas, .br); + self.hline_middle(canvas, .light); + try self.draw_arc(canvas, .tl, .light); + try self.draw_arc(canvas, .br, .light); }, - // '' 0x0f5ed => { - self.hline_middle(canvas, Thickness.light); - try self.draw_light_arc(canvas, .tr); - try self.draw_light_arc(canvas, .bl); + self.hline_middle(canvas, .light); + try self.draw_arc(canvas, .tr, .light); + try self.draw_arc(canvas, .bl, .light); }, - // '' - 0x0f5ee => self.draw_git_node(canvas, .{}, Thickness.light, true), - + 0x0f5ee => self.draw_branch_node(canvas, .{ .filled = true }, .light), // '' - 0x0f5ef => self.draw_git_node(canvas, .{}, Thickness.light, false), + 0x0f5ef => self.draw_branch_node(canvas, .{}, .light), // '' - 0x0f5f0 => { - self.draw_git_node(canvas, .{ .right = true }, Thickness.light, true); - }, - + 0x0f5f0 => self.draw_branch_node(canvas, .{ + .right = true, + .filled = true, + }, .light), // '' - 0x0f5f1 => { - self.draw_git_node(canvas, .{ .right = true }, Thickness.light, false); - }, - + 0x0f5f1 => self.draw_branch_node(canvas, .{ + .right = true, + }, .light), // '' - 0x0f5f2 => { - self.draw_git_node(canvas, .{ .left = true }, Thickness.light, true); - }, - + 0x0f5f2 => self.draw_branch_node(canvas, .{ + .left = true, + .filled = true, + }, .light), // '' - 0x0f5f3 => { - self.draw_git_node(canvas, .{ .left = true }, Thickness.light, false); - }, - + 0x0f5f3 => self.draw_branch_node(canvas, .{ + .left = true, + }, .light), // '' - 0x0f5f4 => { - self.draw_git_node(canvas, .{ .left = true, .right = true }, Thickness.light, true); - }, - + 0x0f5f4 => self.draw_branch_node(canvas, .{ + .left = true, + .right = true, + .filled = true, + }, .light), // '' - 0x0f5f5 => { - self.draw_git_node(canvas, .{ .left = true, .right = true }, Thickness.light, false); - }, - + 0x0f5f5 => self.draw_branch_node(canvas, .{ + .left = true, + .right = true, + }, .light), // '' - 0x0f5f6 => { - self.draw_git_node(canvas, .{ .down = true }, Thickness.light, true); - }, - + 0x0f5f6 => self.draw_branch_node(canvas, .{ + .down = true, + .filled = true, + }, .light), // '' - 0x0f5f7 => { - self.draw_git_node(canvas, .{ .down = true }, Thickness.light, false); - }, - + 0x0f5f7 => self.draw_branch_node(canvas, .{ + .down = true, + }, .light), // '' - 0x0f5f8 => { - self.draw_git_node(canvas, .{ .up = true }, Thickness.light, true); - }, - + 0x0f5f8 => self.draw_branch_node(canvas, .{ + .up = true, + .filled = true, + }, .light), // '' - 0x0f5f9 => { - self.draw_git_node(canvas, .{ .up = true }, Thickness.light, false); - }, - + 0x0f5f9 => self.draw_branch_node(canvas, .{ + .up = true, + }, .light), // '' - 0x0f5fa => { - self.draw_git_node(canvas, .{ .up = true, .down = true }, Thickness.light, true); - }, - + 0x0f5fa => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + .filled = true, + }, .light), // '' - 0x0f5fb => { - self.draw_git_node(canvas, .{ .up = true, .down = true }, Thickness.light, false); - }, - + 0x0f5fb => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + }, .light), // '' - 0x0f5fc => { - self.draw_git_node(canvas, .{ .right = true, .down = true }, Thickness.light, true); - }, - + 0x0f5fc => self.draw_branch_node(canvas, .{ + .right = true, + .down = true, + .filled = true, + }, .light), // '' - 0x0f5fd => { - self.draw_git_node(canvas, .{ .right = true, .down = true }, Thickness.light, false); - }, - + 0x0f5fd => self.draw_branch_node(canvas, .{ + .right = true, + .down = true, + }, .light), // '' - 0x0f5fe => { - self.draw_git_node(canvas, .{ .left = true, .down = true }, Thickness.light, true); - }, - + 0x0f5fe => self.draw_branch_node(canvas, .{ + .left = true, + .down = true, + .filled = true, + }, .light), // '' - 0x0f5ff => { - self.draw_git_node(canvas, .{ .left = true, .down = true }, Thickness.light, false); - }, + 0x0f5ff => self.draw_branch_node(canvas, .{ + .left = true, + .down = true, + }, .light), // '' - 0x0f600 => { - self.draw_git_node(canvas, .{ .up = true, .right = true }, Thickness.light, true); - }, - + 0x0f600 => self.draw_branch_node(canvas, .{ + .up = true, + .right = true, + .filled = true, + }, .light), // '' - 0x0f601 => { - self.draw_git_node(canvas, .{ .up = true, .right = true }, Thickness.light, false); - }, - + 0x0f601 => self.draw_branch_node(canvas, .{ + .up = true, + .right = true, + }, .light), // '' - 0x0f602 => { - self.draw_git_node(canvas, .{ .up = true, .left = true }, Thickness.light, true); - }, - + 0x0f602 => self.draw_branch_node(canvas, .{ + .up = true, + .left = true, + .filled = true, + }, .light), // '' - 0x0f603 => { - self.draw_git_node(canvas, .{ .up = true, .left = true }, Thickness.light, false); - }, - + 0x0f603 => self.draw_branch_node(canvas, .{ + .up = true, + .left = true, + }, .light), // '' - 0x0f604 => { - self.draw_git_node(canvas, .{ .up = true, .down = true, .right = true }, Thickness.light, true); - }, - + 0x0f604 => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + .right = true, + .filled = true, + }, .light), // '' - 0x0f605 => { - self.draw_git_node(canvas, .{ .up = true, .down = true, .right = true }, Thickness.light, false); - }, - + 0x0f605 => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + .right = true, + }, .light), // '' - 0x0f606 => { - self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true }, Thickness.light, true); - }, - + 0x0f606 => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + .left = true, + .filled = true, + }, .light), // '' - 0x0f607 => { - self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true }, Thickness.light, false); - }, - + 0x0f607 => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + .left = true, + }, .light), // '' - 0x0f608 => { - self.draw_git_node(canvas, .{ .down = true, .left = true, .right = true }, Thickness.light, true); - }, - + 0x0f608 => self.draw_branch_node(canvas, .{ + .down = true, + .left = true, + .right = true, + .filled = true, + }, .light), // '' - 0x0f609 => { - self.draw_git_node(canvas, .{ .down = true, .left = true, .right = true }, Thickness.light, false); - }, - + 0x0f609 => self.draw_branch_node(canvas, .{ + .down = true, + .left = true, + .right = true, + }, .light), // '' - 0x0f60a => { - self.draw_git_node(canvas, .{ .up = true, .left = true, .right = true }, Thickness.light, true); - }, - + 0x0f60a => self.draw_branch_node(canvas, .{ + .up = true, + .left = true, + .right = true, + .filled = true, + }, .light), // '' - 0x0f60b => { - self.draw_git_node(canvas, .{ .up = true, .left = true, .right = true }, Thickness.light, false); - }, - + 0x0f60b => self.draw_branch_node(canvas, .{ + .up = true, + .left = true, + .right = true, + }, .light), // '' - 0x0f60c => { - self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true, .right = true }, Thickness.light, true); - }, - + 0x0f60c => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + .left = true, + .right = true, + .filled = true, + }, .light), // '' - 0x0f60d => { - self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true, .right = true }, Thickness.light, false); - }, + 0x0f60d => self.draw_branch_node(canvas, .{ + .up = true, + .down = true, + .left = true, + .right = true, + }, .light), // Not official box characters but special characters we hide // in the high bits of a unicode codepoint. @@ -2116,21 +2128,98 @@ fn draw_cell_diagonal( ) catch {}; } -fn draw_git_node( +fn draw_fading_line( self: Box, canvas: *font.sprite.Canvas, - comptime nodes: NodeAlign, + comptime to: Edge, comptime thickness: Thickness, - comptime filled: bool, ) void { + const thick_px = thickness.height(self.thickness); const float_width: f64 = @floatFromInt(self.width); const float_height: f64 = @floatFromInt(self.height); - const x: f64 = float_width / 2; - const y: f64 = float_height / 2; + // Top of horizontal strokes + const h_top = (self.height -| thick_px) / 2; + // Bottom of horizontal strokes + const h_bottom = h_top +| thick_px; + // Left of vertical strokes + const v_left = (self.width -| thick_px) / 2; + // Right of vertical strokes + const v_right = v_left +| thick_px; - // we need at least 1px leeway to see node + right/left line - const r: f64 = 0.47 * @min(float_width, float_height); + // If we're fading to the top or left, we start with 0.0 + // and increment up as we progress, otherwise we start + // at 255.0 and increment down (negative). + var color: f64 = switch (to) { + .top, .left => 0.0, + .bottom, .right => 255.0, + }; + const inc: f64 = 255.0 / switch (to) { + .top => float_height, + .bottom => -float_height, + .left => float_width, + .right => -float_width, + }; + + switch (to) { + .top, .bottom => { + for (0..self.height) |y| { + for (v_left..v_right) |x| { + canvas.pixel( + @intCast(x), + @intCast(y), + @enumFromInt(@as(u8, @intFromFloat(@round(color)))), + ); + } + color += inc; + } + }, + .left, .right => { + for (0..self.width) |x| { + for (h_top..h_bottom) |y| { + canvas.pixel( + @intCast(x), + @intCast(y), + @enumFromInt(@as(u8, @intFromFloat(@round(color)))), + ); + } + color += inc; + } + }, + } +} + +fn draw_branch_node( + self: Box, + canvas: *font.sprite.Canvas, + node: BranchNode, + comptime thickness: Thickness, +) void { + const thick_px = thickness.height(self.thickness); + const float_width: f64 = @floatFromInt(self.width); + const float_height: f64 = @floatFromInt(self.height); + const float_thick: f64 = @floatFromInt(thick_px); + + // Top of horizontal strokes + const h_top = (self.height -| thick_px) / 2; + // Bottom of horizontal strokes + const h_bottom = h_top +| thick_px; + // Left of vertical strokes + const v_left = (self.width -| thick_px) / 2; + // Right of vertical strokes + const v_right = v_left +| thick_px; + + // We calculate the center of the circle this way + // to ensure it aligns with box drawing characters + // since the lines are sometimes off center to + // make sure they aren't split between pixels. + const cx: f64 = @as(f64, @floatFromInt(v_left)) + float_thick / 2; + const cy: f64 = @as(f64, @floatFromInt(h_top)) + float_thick / 2; + // The radius needs to be the smallest distance from the center to an edge. + const r: f64 = @min( + @min(cx, cy), + @min(float_width - cx, float_height - cy), + ); var ctx: z2d.Context = .{ .surface = canvas.sfc, @@ -2139,29 +2228,30 @@ fn draw_git_node( .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, }, }, - .line_width = @floatFromInt(thickness.height(self.thickness)), + .line_width = float_thick, }; var path = z2d.Path.init(canvas.alloc); defer path.deinit(); - const int_radius: u32 = @intFromFloat(r); + // These @intFromFloat casts shouldn't ever fail since r can never + // be greater than cx or cy, so when subtracting it from them the + // result can never be negative. + if (node.up) + self.rect(canvas, v_left, 0, v_right, @intFromFloat(@ceil(cy - r))); + if (node.right) + self.rect(canvas, @intFromFloat(@floor(cx + r)), h_top, self.width, h_bottom); + if (node.down) + self.rect(canvas, v_left, @intFromFloat(@floor(cy + r)), v_right, self.height); + if (node.left) + self.rect(canvas, 0, h_top, @intFromFloat(@ceil(cx - r)), h_bottom); - if (nodes.up) - self.vline_middle_xy(canvas, 0, (self.height / 2) - int_radius, self.width, thickness); - if (nodes.down) - self.vline_middle_xy(canvas, (self.height / 2) + int_radius, self.height, self.width, thickness); - if (nodes.left) - self.hline_middle_xy(canvas, 0, (self.width / 2) - int_radius, self.height, thickness); - if (nodes.right) - self.hline_middle_xy(canvas, (self.width / 2) + int_radius, self.width, self.height, thickness); - - if (filled) { - path.arc(x, y, r, 0, std.math.pi * 2, false, null) catch return; + if (node.filled) { + path.arc(cx, cy, r, 0, std.math.pi * 2, false, null) catch return; path.close() catch return; ctx.fill(canvas.alloc, path) catch return; } else { - path.arc(x, y, r - ctx.line_width / 2, 0, std.math.pi * 2, false, null) catch return; + path.arc(cx, cy, r - float_thick / 2, 0, std.math.pi * 2, false, null) catch return; path.close() catch return; ctx.stroke(canvas.alloc, path) catch return; } @@ -2492,12 +2582,13 @@ fn draw_edge_triangle( try ctx.fill(canvas.alloc, path); } -fn draw_light_arc( +fn draw_arc( self: Box, canvas: *font.sprite.Canvas, comptime corner: Corner, + comptime thickness: Thickness, ) !void { - const thick_px = Thickness.light.height(self.thickness); + const thick_px = thickness.height(self.thickness); const float_width: f64 = @floatFromInt(self.width); const float_height: f64 = @floatFromInt(self.height); const float_thick: f64 = @floatFromInt(thick_px); @@ -2751,16 +2842,6 @@ fn draw_cursor_bar(self: Box, canvas: *font.sprite.Canvas) void { self.vline(canvas, 0, self.height, 0, thick_px); } -fn vline_middle_xy(self: Box, canvas: *font.sprite.Canvas, y: u32, y2: u32, x: u32, thickness: Thickness) void { - const thick_px = thickness.height(self.thickness); - self.vline(canvas, y, y2, (x -| thick_px) / 2, thick_px); -} - -fn hline_middle_xy(self: Box, canvas: *font.sprite.Canvas, x: u32, x2: u32, y: u32, thickness: Thickness) void { - const thick_px = thickness.height(self.thickness); - self.hline(canvas, x, x2, (y -| thick_px) / 2, thick_px); -} - fn vline_middle(self: Box, canvas: *font.sprite.Canvas, thickness: Thickness) void { const thick_px = thickness.height(self.thickness); self.vline(canvas, 0, self.height, (self.width -| thick_px) / 2, thick_px); @@ -2864,20 +2945,6 @@ fn testRenderAll(self: Box, alloc: Allocator, atlas: *font.Atlas) !void { ); } - // Git Branch characters - cp = 0xf5d0; - while (cp <= 0xf60d) : (cp += 1) { - switch (cp) { - 0xf5d0...0xf60d, - => _ = try self.renderGlyph( - alloc, - atlas, - cp, - ), - else => {}, - } - } - // Symbols for Legacy Computing. cp = 0x1fb00; while (cp <= 0x1fbef) : (cp += 1) { @@ -2932,6 +2999,32 @@ fn testRenderAll(self: Box, alloc: Allocator, atlas: *font.Atlas) !void { else => {}, } } + + // Branch drawing character set, used for drawing git-like + // graphs in the terminal. Originally implemented in Kitty. + // Ref: + // - https://github.com/kovidgoyal/kitty/pull/7681 + // - https://github.com/kovidgoyal/kitty/pull/7805 + // NOTE: Kitty is GPL licensed, and its code was not referenced + // for these characters, only the loose specification of + // the character set in the pull request descriptions. + // + // TODO(qwerasd): This should be in another file, but really the + // general organization of the sprite font code + // needs to be reworked eventually. + // + //           + //                     + //                     + //             + cp = 0xf5d0; + while (cp <= 0xf60d) : (cp += 1) { + _ = try self.renderGlyph( + alloc, + atlas, + cp, + ); + } } test "render all sprites" { diff --git a/src/font/sprite/Face.zig b/src/font/sprite/Face.zig index 650bd2a5f..ca0ed96e8 100644 --- a/src/font/sprite/Face.zig +++ b/src/font/sprite/Face.zig @@ -263,6 +263,21 @@ const Kind = enum { 0x1FBCE...0x1FBEF, => .box, + // Branch drawing character set, used for drawing git-like + // graphs in the terminal. Originally implemented in Kitty. + // Ref: + // - https://github.com/kovidgoyal/kitty/pull/7681 + // - https://github.com/kovidgoyal/kitty/pull/7805 + // NOTE: Kitty is GPL licensed, and its code was not referenced + // for these characters, only the loose specification of + // the character set in the pull request descriptions. + // + //           + //                     + //                     + //             + 0xF5D0...0xF60D => .box, + // Powerline fonts 0xE0B0, 0xE0B4, @@ -276,13 +291,6 @@ const Kind = enum { 0xE0D4, => .powerline, - // (Git Branch) - //           - //                     - //                     - //             - 0xF5D0...0xF60D => .box, - else => null, }; } diff --git a/src/font/sprite/testdata/Box.ppm b/src/font/sprite/testdata/Box.ppm index 29ae539e7..1301a4299 100644 Binary files a/src/font/sprite/testdata/Box.ppm and b/src/font/sprite/testdata/Box.ppm differ