╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2463 │ │2464 if (self.session.data.enable_ansi) { │ │2465 if (self.child.getGrid()) |fg| { │ │2466 - self.grid = try artBehind(allocator, fg, &self.art, .top_right, root_focus); │ │2466 + self.grid = try artBehind(allocator, fg, &self.art, .top_right, self.session.is_terminal, root_focus);│ │2467 } │ │2468 } │ │2469 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2531 } │ │2532 │ │2533 // composites ANSI art behind a foreground grid │ │2534 - fn artBehind(allocator: std.mem.Allocator, foreground: Grid, art: *AnsiArt, anchor: ArtAnchor, root_focus: *Focus) !Grid { │ │2534 + fn artBehind(allocator: std.mem.Allocator, foreground: Grid, art: *AnsiArt, anchor: ArtAnchor, is_terminal: bool, root_focus: *Focus) !Grid {│ │2535 art.clearGrid(); │ │2536 try art.build(allocator, .{ │ │2537 .min_size = .{ .width = null, .height = null }, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2562 dst.style.fg = sgrSafe(dimColor(dst.style.fg)); │ │2563 dst.style.bg = sgrSafe(dimColor(dst.style.bg)); │ │2564 } else { │ │2565 - dst.style.bg = sgrSafe(dimColor(src.style.bg orelse src.style.fg)); │ │2565 + const background_maybe = sgrSafe(dimColor(src.style.bg orelse src.style.fg));│ │2566 + dst.style.bg = background_maybe; │ │2567 + // change the color of text overlaying ANSI art to ensure │ │2568 + // it is readable. don't do this in the web UI, since we │ │2569 + // have direct control of the theme there (also, inner │ │2570 + // scroll panes allow text to move without a re-render │ │2571 + // by the TUI, which would break this). also don't do this │ │2572 + // if the text is explicitly styled. │ │2573 + if (is_terminal and dst.style.fg == null) { │ │2574 + if (background_maybe) |background| { │ │2575 + // use near-black and near-white, which is easier on the eyes │ │2576 + // while retaining high contrast │ │2577 + const luminance = (@as(u32, background.r) * 299 + │ │2578 + @as(u32, background.g) * 587 + │ │2579 + @as(u32, background.b) * 114) / 1000; │ │2580 + dst.style.fg = if (luminance >= 128) │ │2581 + .{ .r = 16, .g = 16, .b = 16 } │ │2582 + else │ │2583 + .{ .r = 240, .g = 240, .b = 240 }; │ │2584 + } │ │2585 + } │ │2586 } │ │2587 } │ │2588 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯