summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/panes.zig117
1 files changed, 117 insertions, 0 deletions
diff --git a/test/panes.zig b/test/panes.zig
index 97dc3927..a7e59923 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -518,6 +518,122 @@ const JumpSelectionTests = struct {
}
};
+const TagNameTintTests = struct {
+ const name_fg = [3]u8{ 231, 137, 43 };
+ const tag_fg = [3]u8{ 111, 122, 133 };
+
+ fn configure(p: *Pardes) void {
+ var theme = p.theme().*;
+ theme.tag_name_fg = name_fg;
+ theme.tag_fg = tag_fg;
+ p.custom_theme = theme;
+ p.chrome_animation.snap(pardes.ChromeTheme.fromTheme(p.theme()));
+ p.settings.focus_tint = false;
+ p.presentation.enabled = false;
+ }
+
+ fn check(p: *Pardes, id: usize, name: []const u8) !usize {
+ const pane = p.panes[id].?;
+ var arena = std.heap.ArenaAllocator.init(p.gpa);
+ defer arena.deinit();
+ const surface = try p.render(arena.allocator());
+ const text = try p.tagText(arena.allocator(), pane);
+ const base = std.mem.lastIndexOfScalar(u8, name, '/') orelse return error.MissingDirectory;
+ const rect = p.rects[id];
+ const y = if (p.settings.tag_bottom) rect.y + rect.h - pardes.BOX_H else rect.y;
+ const left = rect.x + config.GUTTER;
+ var visible_name: usize = 0;
+ var at: usize = 0;
+ while (at < text.len) : (at = modal.nextGrapheme(text, at)) {
+ const start: i32 = @as(i32, @intCast(panes.File.rawDisplayCol(text, at))) - pane.tag_scroll;
+ const end = start + @as(i32, @intCast(panes.File.displayWidth(text[at..modal.nextGrapheme(text, at)])));
+ var col = @max(0, start);
+ while (col < end and col < rect.w - config.GUTTER) : (col += 1) {
+ const in_name = at > base and at < name.len;
+ const fg = if (in_name) name_fg else tag_fg;
+ try std.testing.expectEqual(pardes.Color{ .rgb = fg }, surface.at(left + @as(u16, @intCast(col)), y).style.fg);
+ if (in_name) visible_name += 1;
+ }
+ }
+ return visible_name;
+ }
+
+ test "tag filename tint excludes directories dirty marker and output commands" {
+ for ([_]bool{ false, true }) |bottom| {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 24 });
+ defer p.deinit();
+ const pane = try p.setTestFile("body\n");
+ p.gpa.free(pane.file.?.path);
+ pane.file.?.path = try p.gpa.dupe(u8, "/project/็•Œfile.zig");
+ pane.file.?.revision += 1;
+ configure(p);
+ defer p.custom_theme = null;
+ p.settings.tag_bottom = bottom;
+ try std.testing.expect((try check(p, 0, pane.file.?.path)) > 0);
+ try panes.Output.fillResults(p, 0, "/project", .search, "tint", try p.gpa.dupe(u8, "no matches\n"), null);
+ const id = pane.search_pane.?;
+ p.update(.tick);
+ try std.testing.expect((try check(p, id, p.panes[id].?.file.?.path)) > 0);
+ }
+ }
+
+ test "tag filename tint follows scrolled Unicode staged names and yields to selection" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 38, .rows = 14 });
+ defer p.deinit();
+ const pane = try p.setTestFile("body\n");
+ const old = pane.file.?.path.len;
+ configure(p);
+ defer p.custom_theme = null;
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'i' } });
+ pane.tag_anchor = 0;
+ pane.tag_col = @intCast(old - 1);
+ pane.tag_sel = true;
+ const name = "/a/very/long/directory/that/extends/past/the/tag/็•Œe\u{301}name-with-a-long-tail.zig";
+ p.update(.{ .paste = name });
+ try std.testing.expectEqualStrings(name, pane.tag_name[0..pane.tag_name_len.?]);
+ pane.tag_col = @intCast(std.mem.indexOf(u8, name, "็•Œ").?);
+ pane.tag_sel = false;
+ try std.testing.expect((try check(p, 0, name)) > 0);
+ try std.testing.expect(pane.tag_scroll > 0);
+ pane.tag_anchor = pane.tag_col;
+ pane.tag_sel = true;
+ pane.tag_scroll += 4; // bring both cells of the selected wide glyph into view
+ var arena = std.heap.ArenaAllocator.init(p.gpa);
+ defer arena.deinit();
+ const surface = try p.render(arena.allocator());
+ const x = p.rects[0].x + config.GUTTER + @as(u16, @intCast(panes.File.rawDisplayCol(name, pane.tag_col) - pane.tag_scroll));
+ const y = if (p.settings.tag_bottom) p.rects[0].y + p.rects[0].h - pardes.BOX_H else p.rects[0].y;
+ try std.testing.expectEqual(pardes.Color{ .rgb = p.theme().sel_fg }, surface.at(x, y).style.fg);
+ try std.testing.expectEqual(pardes.Color{ .rgb = p.theme().sel_fg }, surface.at(x + 1, y).style.fg);
+ }
+
+ test "tag filename tint legacy themes retain distinct active foreground" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 70, .rows = 14 });
+ defer p.deinit();
+ const pane = try p.setTestFile("body\n");
+ p.gpa.free(pane.file.?.path);
+ pane.file.?.path = try p.gpa.dupe(u8, "/dir/file.zig");
+ configure(p);
+ defer p.custom_theme = null;
+ p.custom_theme.?.tag_name_fg = null;
+ const active_fg = [3]u8{ 175, 183, 194 };
+ p.custom_theme.?.tag_active_fg = active_fg;
+ p.chrome_animation.snap(pardes.ChromeTheme.fromTheme(p.theme()));
+ var arena = std.heap.ArenaAllocator.init(p.gpa);
+ defer arena.deinit();
+ for ([_]bool{ false, true }) |active| {
+ p.settings.focus_tint = active;
+ const surface = try p.render(arena.allocator());
+ const x = p.rects[0].x + config.GUTTER;
+ const y = if (p.settings.tag_bottom) p.rects[0].y + p.rects[0].h - pardes.BOX_H else p.rects[0].y;
+ const fg = if (active) active_fg else tag_fg;
+ try std.testing.expectEqual(pardes.Color{ .rgb = fg }, surface.at(x + 1, y).style.fg);
+ try std.testing.expectEqual(pardes.Color{ .rgb = fg }, surface.at(x + 5, y).style.fg);
+ }
+ }
+};
+
test "pane filename edits stage commit and cancel without changing body or command tail" {
const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 70, .rows = 12 });
defer p.deinit();
@@ -3259,6 +3375,7 @@ const TerminalTests = struct {
};
test {
+ _ = TagNameTintTests;
_ = TreeContextTests;
_ = TtySelectionTests;
_ = ClickCursorTests;