╭ changed ────────╮ │src/ui/widget.zig│ ╰─────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │1576 width = @max(width, row.items.len); │ │1577 try rows.append(allocator, row); │ │1578 row = .empty; │ │1579 + i += 1; │ │1580 + } else if (byte == '\r') { │ │1581 + // git may checkout the ansi art with crlf line endings on windows │ │1582 i += 1; │ │1583 } else if (byte == 0x1B and i + 1 < content.len and content[i + 1] == '[') {│ │1584 // CSI: scan to the final byte (0x40..0x7E); apply it if it's 'm' │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1733 .max_size = constraint.max_size, │ │1734 }, root_focus); │ │1735 │ │1733 - if (!self.session.data.enable_ansi) return; │ │1736 const foreground = self.child.getGrid() orelse return; │ │1737 + // terminals show the art only once they report a background to fade it toward │ │1738 + const backdrop: ?Grid.Color.Rgb = if (self.session.is_terminal) self.session.terminal_background orelse return else null;│ │1739 self.art.content = self.session.data.ansi_art; │ │1736 - try self.buildArt(allocator, foreground.size, root_focus); │ │1737 - if (!self.session.is_terminal) return; │ │1738 - const art_grid = self.art.getGrid() orelse return; │ │1739 - self.grid = try artBehind(allocator, foreground, art_grid); │ │1740 + try self.art.build(allocator, .{ │ │1741 + .min_size = .{ .width = null, .height = null }, │ │1742 + .max_size = .{ .width = foreground.size.width, .height = foreground.size.height }, │ │1743 + }, root_focus); │ │1744 + // the web fades the art with css opacity instead │ │1745 + const art_backdrop = backdrop orelse return; │ │1746 + if (self.art.grid) |*art_grid| { │ │1747 + for (art_grid.cells) |*cell| { │ │1748 + cell.style.fg = fadeColor(cell.style.fg, art_backdrop); │ │1749 + cell.style.bg = fadeColor(cell.style.bg, art_backdrop); │ │1750 + } │ │1751 + self.grid = try artBehind(allocator, foreground, art_grid.*); │ │1752 + } │ │1753 } │ │1754 │ │1755 pub fn input(self: *AnsiBackground, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │1783 return true; │ │1784 } │ │1785 │ │1773 - // the art is dimmed to this fraction of its brightness so foreground text│ │1774 - // stays legible over it │ │1775 - const art_brightness = 35; // percent │ │1786 + // the art is faded toward the background at this opacity so foreground │ │1787 + // text stays legible over it │ │1788 + pub const art_opacity = 25; // percent │ │1789 │ │1790 // the art parser only emits truecolor, so a palette color never occurs │ │1791 fn artRgb(color: ?Grid.Color) ?Grid.Color.Rgb { │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1796 }; │ │1797 } │ │1798 │ │1786 - fn dimColor(color: ?Grid.Color) ?Grid.Color { │ │1799 + fn fadeColor(color: ?Grid.Color, backdrop: Grid.Color.Rgb) ?Grid.Color { │ │1800 const v = artRgb(color) orelse return color; │ │1788 - return .{ .rgb = .{ │ │1789 - .r = @intCast(@as(u16, v.r) * art_brightness / 100), │ │1790 - .g = @intCast(@as(u16, v.g) * art_brightness / 100), │ │1791 - .b = @intCast(@as(u16, v.b) * art_brightness / 100), │ │1792 - } }; │ │1793 - } │ │1794 - │ │1795 - fn buildArt(self: *AnsiBackground, allocator: std.mem.Allocator, size: layout.Size, root_focus: *Focus) !void { │ │1796 - try self.art.build(allocator, .{ │ │1797 - .min_size = .{ .width = null, .height = null }, │ │1798 - .max_size = .{ .width = size.width, .height = size.height }, │ │1799 - }, root_focus); │ │1800 - if (self.art.grid) |*grid| { │ │1801 - for (grid.cells) |*cell| { │ │1802 - cell.style.fg = dimColor(cell.style.fg); │ │1803 - cell.style.bg = dimColor(cell.style.bg); │ │1801 + const blend = struct { │ │1802 + fn f(c: u8, b: u8) u8 { │ │1803 + return @intCast((@as(u16, c) * art_opacity + @as(u16, b) * (100 - art_opacity)) / 100); │ │1804 } │ │1805 - } │ │1805 + }.f; │ │1806 + return .{ .rgb = .{ .r = blend(v.r, backdrop.r), .g = blend(v.g, backdrop.g), .b = blend(v.b, backdrop.b) } };│ │1807 } │ │1808 │ │1809 // terminals that don't support truecolor misparse a "38;2;r;g;b"/"48;2;…" │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯