diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-11 12:38:56 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-15 17:24:42 -0300 |
| commit | 682e237df7e8b22f820d14a4adee58e6e2f84268 (patch) | |
| tree | 5d888cb46f1a49e89fc55e2a4c232d3af0265b1d /test/output.zig | |
| parent | 6878e1c309172d624c0d7a3555f6f0217ae6770e (diff) | |
| download | pardes-682e237df7e8b22f820d14a4adee58e6e2f84268.tar.gz pardes-682e237df7e8b22f820d14a4adee58e6e2f84268.zip | |
trunk: resume before the Reload experiment
Empty marker on the last pre-Reload change. Keep the Reload experiment on reload (3801914), its first change on reload-start (200a1fc), and the unfinished performance investigation on reload-perf-wip.
Diffstat (limited to 'test/output.zig')
| -rw-r--r-- | test/output.zig | 87 |
1 files changed, 85 insertions, 2 deletions
diff --git a/test/output.zig b/test/output.zig index 577b8e73..fd4252e1 100644 --- a/test/output.zig +++ b/test/output.zig @@ -11,6 +11,49 @@ const platform = pardes.platform; const font_picker = pardes.font_picker; const fonts = if (font_picker) pardes.fonts else struct {}; +test "search tint survives wrapping and theme changes while selections remain authoritative" { + const text = "nested/path/a.txt:1:5-7 let abc = 1;\n"; + for ([_]u16{ 30, 80 }) |width| { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = width, .rows = 12 }); + defer p.deinit(); + const pane = try p.setTestFile(text); + pane.file.?.output = .{ .from = .search }; + var frame = std.heap.ArenaAllocator.init(std.testing.allocator); + defer frame.deinit(); + for ([_]bool{ false, true }) |bottom| { + p.settings.tag_bottom = bottom; + for ([_]bool{ true, false, true }) |colors| { + p.settings.colors = colors; + const surface = try p.render(frame.allocator()); + var marked: usize = 0; + for (surface.cells) |cell| { + if (std.meta.eql(cell.style.bg, pardes.Color{ .rgb = p.theme().search_bg.? })) marked += 1; + } + try std.testing.expectEqual(@as(usize, if (colors) 3 else 0), marked); + _ = frame.reset(.retain_capacity); + } + } + // The body changes immediately even when dark chrome is still fading. + try std.testing.expect(p.executeBuiltinLine(0, "Theme daybreak")); + const light = try p.render(frame.allocator()); + var light_matches: usize = 0; + for (light.cells) |cell| { + if (!std.meta.eql(cell.style.bg, pardes.Color{ .rgb = p.theme().search_bg.? })) continue; + try std.testing.expectEqualDeep(pardes.Color{ .rgb = p.theme().search_fg.? }, cell.style.fg); + light_matches += 1; + } + try std.testing.expectEqual(@as(usize, 3), light_matches); + pane.mode = .normal; + pane.cur_row = 0; + pane.cur_col = @intCast(std.mem.indexOf(u8, text, "abc").? + 2); + pane.vsel = .{ .active = true, .row = 0, .col = pane.cur_col - 2, .explicit = true }; + const selected = try p.render(frame.allocator()); + for (selected.cells) |cell| + try std.testing.expect(!std.meta.eql(cell.style.bg, pardes.Color{ .rgb = p.theme().search_bg.? })); + try std.testing.expectEqualStrings(text, pane.file.?.content); + } +} + test "location results sort filenames and numeric positions while remapping their anchor" { const before = "z.zig:1:1 z\nb.zig:10:2-3 ten\nb.zig:2:10-12 two-b\nb.zig:2:2-3 two-a\na.zig:99:1 a\nb.zig:2:2-3 duplicate\n"; const after = "a.zig:99:1 a\nb.zig:2:2-3 two-a\nb.zig:2:2-3 duplicate\nb.zig:2:10-12 two-b\nb.zig:10:2-3 ten\nz.zig:1:1 z\n"; @@ -326,6 +369,8 @@ test "Mini syntax colors survive toggles themes and rendering without source acc const id = p.active; const mini = p.panes[id].?; const keyword = std.mem.indexOfScalar(u8, mini.file.?.mini.?.colors, @intFromEnum(pardes.syntax.Syn.keyword)) orelse return error.MissingKeywordColor; + // Direct pane construction bypasses the host update's layout sync. + p.update(.{ .resize = .{ .cols = 80, .rows = 24 } }); const position = modal.positionAt(mini.file.?.content, keyword); const column = panes.File.displayWidth(modal.lineSlice(mini.file.?.content, position.row)[0..position.col]); try tmp.dir.deleteFile(std.testing.io, "demo.zig"); @@ -391,7 +436,7 @@ test "Config prints the startup path and refreshes its one output" { const out = p.panes[opened].?.file.?; for ([_][]const u8{ "Startup config: " ++ path ++ "\n", - "Theme: helix\n", + "Theme: orchard\n", "Shell requested (new panes): " ++ config.default_shell ++ " (default)\n", "Shell effective (last spawn): (none)\n", "Shell pending: on\n", @@ -691,6 +736,44 @@ test "N exactly reverses n across output panes and the ring seam" { try std.testing.expect(saw_first and saw_second); } +test "ThemeSel groups native themes first and skips headings in both directions" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 40 }); + defer p.deinit(); + const source = try p.setTestFile("notes\n"); + p.setThemeIndex(pardes.themes.len - 1); + const original_theme = p.settings.theme; + try std.testing.expect(p.executeBuiltinLine(0, "ThemeSel")); + const tid = source.search_pane orelse return error.MissingThemeList; + const list = p.panes[tid].?; + const content = list.file.?.content; + try std.testing.expectEqual(@as(usize, 0), p.active); + try std.testing.expectEqual(@as(i32, 0), list.cur_row); + try std.testing.expectEqual(@as(usize, 0), list.file.?.scroll); + try std.testing.expectEqualStrings("# Pardes themes", modal.lineSlice(content, 0)); + try std.testing.expectEqualStrings("# Legacy and imported themes", modal.lineSlice(content, pardes.native_theme_count + 2)); + try std.testing.expectEqual(@as(usize, pardes.themes.len + 3), std.mem.count(u8, content, "\n")); + for (pardes.themes, 0..) |theme, i| { + const row = i + 1 + @as(usize, if (i >= pardes.native_theme_count) 2 else 0); + const line = modal.lineSlice(content, row); + try std.testing.expect(std.mem.startsWith(u8, line, "Theme ")); + try std.testing.expectEqualStrings(theme.name, line["Theme ".len..]); + } + // Opening an imported theme's selector must still begin with the natives. + // Walk across the section break without selecting or executing a heading. + for (pardes.themes[0 .. pardes.native_theme_count + 1]) |theme| { + p.update(.{ .key = .{ .cp = 'n' } }); + try std.testing.expectEqual(tid, p.active); + const selected = selectedOutputText(list) orelse return error.MissingThemeSelection; + try std.testing.expectEqualStrings(theme.name, selected["Theme ".len..]); + try std.testing.expectEqual(original_theme, p.settings.theme); + } + p.update(.{ .key = .{ .cp = 'N' } }); + const previous = selectedOutputText(list) orelse return error.MissingThemeSelection; + try std.testing.expectEqualStrings(pardes.themes[pardes.native_theme_count - 1].name, previous["Theme ".len..]); + p.update(.{ .key = .{ .cp = Key.tab } }); + try std.testing.expectEqual(pardes.native_theme_count - 1, p.settings.theme); +} + test "n/N selects command outputs by whole row" { if (platform == .web) return; var cwd_buf: [4096]u8 = undefined; @@ -705,7 +788,7 @@ test "n/N selects command outputs by whole row" { const themes = p.panes[tid].?; try std.testing.expect(panes.Output.fileTraits(themes.file.?.output).commands); p.update(.{ .key = .{ .cp = 'n' } }); - const row0 = std.mem.trimEnd(u8, modal.lineSlice(themes.file.?.content, 0), " \t\r"); + const row0 = std.mem.trimEnd(u8, modal.lineSlice(themes.file.?.content, 1), " \t\r"); try std.testing.expectEqualStrings(row0, selectedOutputText(themes) orelse ""); const theme_before = p.settings.theme; p.update(.{ .key = .{ .cp = 'n' } }); |
