From e29faca73e07eb90aa0c8f6f33e55c8ace77a3c4 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 18:40:43 -0300 Subject: A blank whose ink alone changed is skipped in vaxis's own frame diff, not weighed up per cell in the tty --- build.zig | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) (limited to 'build.zig') diff --git a/build.zig b/build.zig index 8646be05..2419dd59 100644 --- a/build.zig +++ b/build.zig @@ -864,11 +864,59 @@ pub fn build(b: *std.Build) void { \\} \\ ; + // vaxis's render, patched the same way: a blank whose ink alone + // changed is not sent, since a blank's ink shows nowhere. A fade + // (InactiveDim on a focus change) sent every blank of every pane it + // touched again: 7 KB a click for three shell panes. The terminal + // keeps the old ink there, and so does vaxis's last frame. + const render_path = vaxis_dep.path("src/Vaxis.zig").getPath(b); + var render_src = std.Io.Dir.cwd().readFileAlloc(io, render_path, b.allocator, .limited(1 << 20)) catch @panic("read vaxis Vaxis.zig"); + const render_anchor = + \\ if ((!self.refresh and + \\ last.eql(cell) and + ; + if (std.mem.count(u8, render_src, render_anchor) != 1) std.debug.panic("vaxis's Vaxis.zig changed at `{s}`: redo its patch in build.zig", .{render_anchor}); + render_src = std.mem.replaceOwned(u8, b.allocator, render_src, render_anchor, + \\ if ((!self.refresh and + \\ (last.eql(cell) or blankInkOnly(&last, &cell)) and // pardes's patch (its build.zig) + \\ + ) catch @panic("OOM"); + const blank_ink = + \\ + \\/// pardes's patch (its build.zig): a blank cell (a space, no underline, + \\/// strike or reverse) that differs from the last frame's blank in its + \\/// ink alone, which shows nowhere. + \\inline fn blankInkOnly(last: *const InternalScreen.InternalCell, cell: *const Cell) bool { + \\ if (!(cell.char.grapheme.len == 1 and cell.char.grapheme[0] == ' ')) return false; + \\ if (last.default or cell.default) return false; + \\ if (!(last.char.items.len == 1 and last.char.items[0] == ' ')) return false; + \\ const s = cell.style; + \\ if (s.reverse or s.strikethrough or s.ul_style != .off) return false; + \\ if (!std.mem.eql(u8, last.uri.items, cell.link.uri)) return false; + \\ // Field by field: Style.eql is slow, and this runs for every blank + \\ // a scrolling shell moves. + \\ const l = last.style; + \\ return sameColor(l.bg, s.bg) and sameColor(l.ul, s.ul) and l.ul_style == s.ul_style and + \\ l.bold == s.bold and l.dim == s.dim and l.italic == s.italic and l.blink == s.blink and + \\ !l.reverse and !l.strikethrough and l.invisible == s.invisible; + \\} + \\ + \\inline fn sameColor(a: Cell.Color, b: Cell.Color) bool { + \\ return switch (a) { + \\ .default => b == .default, + \\ .index => |i| b == .index and b.index == i, + \\ .rgb => |rgb| b == .rgb and rgb[0] == b.rgb[0] and rgb[1] == b.rgb[1] and rgb[2] == b.rgb[2], + \\ }; + \\} + \\ + ; const files = b.addWriteFiles(); _ = files.add("Parser.zig", b.fmt("{s}{s}", .{ src, cursor_report })); + _ = files.add("Vaxis.zig", b.fmt("{s}{s}", .{ render_src, blank_ink })); _ = files.addCopyFile(vaxis_dep.path("src/widgets/terminal/Parser.zig"), "widgets/terminal/Parser.zig"); - // Suffixes: this leaves out both Parser.zig files, written above. - _ = files.addCopyDirectory(vaxis_dep.path("src"), "", .{ .exclude_extensions = &.{"Parser.zig"} }); + // Suffixes: this leaves out both Parser.zig files and Vaxis.zig, + // written above. + _ = files.addCopyDirectory(vaxis_dep.path("src"), "", .{ .exclude_extensions = &.{ "Parser.zig", "Vaxis.zig" } }); vaxis_mod.root_source_file = files.getDirectory().path(b, "main.zig"); } -- cgit v1.3