╭ changed ────╮ │build.zig.zon│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 3 .version = "0.0.0", │ │ 4 .dependencies = .{ │ │ 5 .xit = .{ │ │ 6 - .url = "git+https://github.com/xit-vcs/xit#b6b75683bbef5565ad5f5a051b125897cc81057f",│ │ 7 - .hash = "xit-0.0.0-Ub3nDFiLUAFW6PUrE1SlcSzbjg6OTJQorb7hfncQBa9h", │ │ 6 + .url = "git+https://github.com/xit-vcs/xit#e2e8f0057475a296a0932664f2413ab9153f6985",│ │ 7 + .hash = "xit-0.0.0-Ub3nDFiLUAHphIf4WaLAkaC48z4_muk4hHYepGcuDcX5", │ │ 8 }, │ │ 9 }, │ │10 .paths = .{ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────╮ │src/embed/index.html│ ╰────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │54 vertical-align: top; │ │55 } │ │56 │ │57 + /* a double-width rune pinned to its two grid cells so its advance│ │58 + width can't shift the rest of the row. */ │ │59 + #grid .w2 { │ │60 + width: 2ch; │ │61 + overflow: hidden; │ │62 + } │ │63 + │ │64 /* overlay elements share the grid's coordinate system since │ │65 their parent (.page) is the positioning ancestor and the │ │66 grid sits at its top-left. */ │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │380 defer items.deinit(allocator); │ │381 // when filtered, the first item clears the filter │ │382 if (data.tag.len != 0) │ │383 - try items.append(allocator, .{ .text = "╳", .link = try issuesLink(session.page_arena, data.identity, .open, "", "") });│ │383 + try items.append(allocator, .{ .text = "✕", .link = try issuesLink(session.page_arena, data.identity, .open, "", "") });│ │384 for (data.tags) |tag| │ │385 try items.append(allocator, .{ .text = tag, .link = try tagLink(session.page_arena, data.identity, .open, tag) }); │ │386 try tf.setItems(allocator, items.items); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │784 first = false; │ │785 } │ │786 │ │787 - try appendEscapedHtml(allocator, output, if (covered_by_scroll) " " else (cell.rune orelse " ")); │ │787 + if (covered_by_scroll) { │ │788 + try appendEscapedHtml(allocator, output, " "); │ │789 + } else if (cell.continuation) { │ │790 + // the wide rune to the left was emitted 2ch wide, covering this column │ │791 + } else if (cell.rune) |rune| { │ │792 + // a double-width rune is pinned inside a 2ch span so the │ │793 + // fallback glyph's advance width can't shift the rest of the row │ │794 + const wide = x + 1 < grid.size.width and grid.cells.items[try grid.cells.at(.{ y, x + 1 })].continuation;│ │795 + if (wide) { │ │796 + try output.appendSlice(allocator, "<span class=\"w2\">"); │ │797 + try appendEscapedHtml(allocator, output, rune); │ │798 + try output.appendSlice(allocator, "</span>"); │ │799 + } else { │ │800 + try appendEscapedHtml(allocator, output, rune); │ │801 + } │ │802 + } else { │ │803 + try appendEscapedHtml(allocator, output, " "); │ │804 + } │ │805 } │ │806 if (open_tag) |t| try output.appendSlice(allocator, t.closeTag()); │ │807 try output.append(allocator, '\n'); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯