diff options
Diffstat (limited to 'test/panes.zig')
| -rw-r--r-- | test/panes.zig | 87 |
1 files changed, 54 insertions, 33 deletions
diff --git a/test/panes.zig b/test/panes.zig index 662ea3a5..40b4b6ba 100644 --- a/test/panes.zig +++ b/test/panes.zig @@ -2,6 +2,7 @@ const std = @import("std"); const pardes = @import("pardes"); const panes = pardes.panes; const layout = pardes.layout; +const animation = pardes.animation; const Pardes = pardes.Pardes; const Pane = pardes.Pane; const Key = pardes.Key; @@ -18,17 +19,17 @@ fn setTag(pane: *Pane, text: []const u8) !void { } const TagLayerTests = struct { - const Kind = @FieldType(pardes.TagLayer, "kind"); - fn findLayer(p: *Pardes, kind: Kind, id: usize) !*pardes.TagLayer { + const Kind = @FieldType(pardes.Layer, "kind"); + fn findLayer(p: *Pardes, kind: Kind, id: usize) !*pardes.Layer { for (&p.surface.tag_layers) |*layer| { - if (layer.cols > 0 and layer.kind == kind and layer.id == id) return layer; + if (layer.rows > 0 and layer.kind == kind and layer.id == id) return layer; } return error.MissingTagLayer; } - fn mouse(layer: *const pardes.TagLayer, x: f32, kind: pardes.Mouse.Kind) pardes.Mouse { + fn mouse(layer: *const pardes.Layer, x: f32, kind: pardes.Mouse.Kind) pardes.Mouse { const y = (@as(f32, @floatFromInt(layer.viewport.y)) + 0.5) * 20; - return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .tag_hit = layer.hitAt(x, y, 10, 20, 5, 10) }; + return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .tag_hit = layer.tagHit(x, y, 10, 20, 5, 10) }; } test "compact tag layers render and edit Unicode text beyond body column capacity" { @@ -70,7 +71,7 @@ const TagLayerTests = struct { try std.testing.expectEqualStrings("body\n", pane.file.?.content); p.update(.{ .key = .{ .cp = Key.escape } }); const rect = p.rects[0]; - const track: layout.Track = .{ + const track: animation.Track = .{ .serial = pane.serial, .pane = 0, .effect = .zoom, @@ -199,14 +200,16 @@ test "a tag with a newline in it is as tall as its lines, and each line is typed const body_y = p.bodyTop(pane, r); try std.testing.expectEqual(if (bottom) r.y else r.y + 2, body_y); try std.testing.expectEqualStrings("b", surface.at(r.x + config.GUTTER + panes.File.gutterWidth(pane), body_y).grapheme()); - // a layer to a line, for a pixel shell - var lines: usize = 0; + // one layer, a row to each line, for a pixel shell + var layers: usize = 0; for (p.surface.tagLayers()) |*layer| { - if (layer.cols == 0 or layer.kind != .pane or layer.id != 0) continue; - try std.testing.expectEqual(tag_y + layer.line, layer.viewport.y); - lines += 1; + if (layer.rows == 0 or layer.kind != .pane or layer.id != 0) continue; + try std.testing.expectEqual(tag_y, layer.viewport.y); + try std.testing.expectEqual(@as(u16, 2), layer.rows); + try std.testing.expectEqual(@as(u16, 2), layer.viewport.h); + layers += 1; } - try std.testing.expectEqual(@as(usize, 2), lines); + try std.testing.expectEqual(@as(usize, 1), layers); // a click on the second line puts the tag's cursor on it p.update(.{ .key = .{ .cp = Key.escape } }); p.update(.{ .key = .{ .cp = ':' } }); @@ -305,7 +308,7 @@ const TagNavigationTests = struct { try std.testing.expectEqual(@as(usize, 2), got.n); for (ranges[0..got.n]) |range| try std.testing.expectEqualStrings("S", text[@min(range.anchor, range.head)..@max(range.anchor, range.head)]); // the body's selection is its own - try std.testing.expectEqual(@as(u8, 0), pane.body.nsel); + try std.testing.expectEqual(@as(u16, 0), pane.body.nsel); // `/` from the tag is the body's search, as acme's Look from a tag is key(p, ','); key(p, '/'); @@ -314,6 +317,19 @@ const TagNavigationTests = struct { try std.testing.expect(pane.prompt == .none and pane.focus == .body); } + test "ms and md edit a tag's own text, and the text the edit made is read back whole" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 20 }); + defer p.deinit(); + const pane = try p.setTestFile("body\n"); + p.update(.tick); + key(p, ':'); // the tag, on `Save` the first time + for ("miwms(") |cp| key(p, cp); + try std.testing.expect(std.mem.indexOf(u8, pardes.tagline.curTail(pane), "(Save)") != null); + for ("md(") |cp| key(p, cp); + try std.testing.expect(std.mem.indexOf(u8, pardes.tagline.curTail(pane), " Save ") != null); + try std.testing.expect(std.mem.indexOf(u8, pardes.tagline.curTail(pane), "(") == null); + } + test "the keyboard reaches a tag's path, which it can select and yank but not edit" { const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 20 }); defer p.deinit(); @@ -325,7 +341,7 @@ const TagNavigationTests = struct { try std.testing.expectEqual(@as(i32, 0), pane.tag.cur_col); key(p, 'E'); key(p, 'y'); - try std.testing.expectEqualStrings("/test.txt", p.yank.?); + try std.testing.expectEqualStrings("/test.txt", p.registers.text(p.gpa, '"').?); // an edit that reaches into it is refused, the cursor with it const before = try std.testing.allocator.dupe(u8, try pardes.edit.flatSurface(p, &pane.tag)); defer std.testing.allocator.free(before); @@ -540,11 +556,11 @@ const TagNavigationTests = struct { }; const BodyHitTests = struct { - fn mouse(layer: *const pardes.BodyLayer, row: u16, col: u16, kind: pardes.Mouse.Kind) pardes.Mouse { + fn mouse(layer: *const pardes.Layer, row: u16, col: u16, kind: pardes.Mouse.Kind) pardes.Mouse { const width: f32 = if (row < layer.context_rows) 8 else 10; const x = @as(f32, @floatFromInt(layer.viewport.x)) * 10 + (@as(f32, @floatFromInt(col)) + 0.5) * width; const y = layer.rowTop(row, 20, 10) + layer.rowHeight(row, 20, 10) / 2; - return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .body_hit = layer.hitAt(x, y, 10, 20, 8, 10).? }; + return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .body_hit = layer.bodyHit(x, y, 10, 20, 8, 10).? }; } test "compact TreeContext mouse follows source rows in reclaimed space" { @@ -672,7 +688,7 @@ const TreeContextTests = struct { const y = layer.rowTop(row, 20, 10) + 9.5; const x = @as(f32, @floatFromInt(layer.viewport.x)) * 10 + 5; // A one-pixel separator remains inside its existing header row. - try std.testing.expectEqual(row, layer.hitAt(x, y, 10, 20, 8, 10).?.row); + try std.testing.expectEqual(row, layer.bodyHit(x, y, 10, 20, 8, 10).?.row); } pane.scrollBy(-5); _ = try p.render(frame.allocator()); @@ -848,12 +864,12 @@ const TtySelectionTests = struct { const x = rect.x + config.GUTTER; const y = p.bodyTop(pane, rect); JumpSelectionTests.drag(p, x + 1, y, x + 3, y); - try std.testing.expectEqualStrings("lph", p.yank orelse return error.MissingAutomaticTtyYank); + try std.testing.expectEqualStrings("lph", p.registers.text(p.gpa, '"') orelse return error.MissingAutomaticTtyYank); p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } }); p.update(.{ .key = .{ .cp = 'l' } }); try std.testing.expectEqual(@as(i32, 4), pane.body.cur_col); p.update(.{ .key = .{ .cp = 'y' } }); - try std.testing.expectEqualStrings("a", p.yank.?); + try std.testing.expectEqualStrings("a", p.registers.text(p.gpa, '"').?); try noChildInput(p); } @@ -881,7 +897,7 @@ const TtySelectionTests = struct { const expected = if (prompt) "$ ab" else "lph\nrav"; try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); try std.testing.expectEqualStrings(expected, pardes.test_api.heldSelection(p, 0).?); - try std.testing.expectEqualStrings(expected, p.yank orelse return error.MissingAutomaticTtyYank); + try std.testing.expectEqualStrings(expected, p.registers.text(p.gpa, '"') orelse return error.MissingAutomaticTtyYank); try noChildInput(p); try std.testing.expect(p.executeBuiltinLine(0, "ClipYank")); @@ -897,7 +913,7 @@ const TtySelectionTests = struct { } try std.testing.expectEqualStrings(expected, pardes.test_api.heldSelection(p, 0).?); p.update(.{ .key = .{ .cp = 'y' } }); - try std.testing.expectEqualStrings(expected, p.yank.?); + try std.testing.expectEqualStrings(expected, p.registers.text(p.gpa, '"').?); try noChildInput(p); p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } }); try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); @@ -908,7 +924,7 @@ const TtySelectionTests = struct { _ = try p.render(frame.allocator()); try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); try std.testing.expectEqualStrings(expected, pardes.test_api.heldSelection(p, 0).?); - try std.testing.expectEqualStrings(expected, p.yank.?); + try std.testing.expectEqualStrings(expected, p.registers.text(p.gpa, '"').?); try noChildInput(p); } } @@ -940,7 +956,7 @@ const TtySelectionTests = struct { const sx = source.x + config.GUTTER; const sy = if (p.settings.tag_bottom) source.y else source.y + pardes.BOX_H; JumpSelectionTests.drag(p, sx + 1, sy, sx + 3, sy + 1); - try std.testing.expectEqualStrings("lph\nrav", p.yank orelse return error.MissingAutomaticTtyYank); + try std.testing.expectEqualStrings("lph\nrav", p.registers.text(p.gpa, '"') orelse return error.MissingAutomaticTtyYank); try noChildInput(p); const target = p.rects[1]; @@ -1001,7 +1017,7 @@ const TtySelectionTests = struct { try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); if (bracketed) p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[?2004h" } }); try std.testing.expectEqual(bracketed, panes.Terminal.bracketedPaste(pane)); - p.yank = try p.gpa.dupe(u8, "one\ntwo"); // what a `y` anywhere left behind + p.registers.put(p.gpa, '"', "one\ntwo", 0, 1, true); // what a `y` anywhere left behind var buf: [256]u8 = undefined; _ = childInput(p, &buf); @@ -1033,7 +1049,7 @@ const TtySelectionTests = struct { ); } // ...and neither chord put the clipboard in the register on its way. - try std.testing.expectEqualStrings("one\ntwo", p.yank orelse ""); + try std.testing.expectEqualStrings("one\ntwo", p.registers.text(p.gpa, '"') orelse ""); } } }; @@ -1941,7 +1957,11 @@ test "a prompt owns the pipe behavior through cancellation and submission" { p.update(.{ .key = .{ .cp = Key.enter } }); const pending = p.pipe.wait orelse return error.MissingPipe; try std.testing.expectEqual(how, pending.how); - try std.testing.expectEqualStrings("cat", pending.command); + // `$` runs the command in a subshell that reports its status + if (how == .keep) + try std.testing.expect(std.mem.indexOf(u8, pending.command, "\ncat\n") != null) + else + try std.testing.expectEqualStrings("cat", pending.command); try std.testing.expectEqual(@as(usize, 1), pending.inputs.len); try std.testing.expectEqualStrings(if (how.pipes()) "one" else "", pending.inputs[0].bytes); try std.testing.expect(pane.prompt == .none); @@ -1967,8 +1987,8 @@ test "prompt cancellation restores the selection before regex previews" { p.update(.{ .key = .{ .cp = case.pattern[0], .text = case.pattern } }); try std.testing.expectEqual(case.secondary, pane.body.nsel); p.update(.{ .key = .{ .cp = Key.escape } }); - try std.testing.expectEqual(@as(u8, 0), pane.body.nsel); - try std.testing.expectEqual(@as(u8, 0), pane.nsel_snap); + try std.testing.expectEqual(@as(u16, 0), pane.body.nsel); + try std.testing.expectEqual(@as(u16, 0), pane.nsel_snap); try std.testing.expectEqual(@as(i32, 10), pane.body.cur_col); try std.testing.expectEqual(@as(i32, 0), pane.body.vsel.col); try std.testing.expect(pane.body.vsel.active and pane.body.vsel.explicit); @@ -2744,7 +2764,7 @@ const OutputTests = struct { try fillResults(p, 0, "/", .{ .query = .hover }, "", try p.gpa.dupe(u8, "short\n"), null); try std.testing.expectEqualStrings("short\n", result.file.?.content); try std.testing.expect(!result.body.vsel.active and !result.body.msel.active and !result.body.select); - try std.testing.expectEqual(@as(u8, 0), result.body.nsel); + try std.testing.expectEqual(@as(u16, 0), result.body.nsel); try std.testing.expectEqual(@as(i32, 0), result.body.cur_row); try std.testing.expectEqual(@as(i32, 0), result.body.cur_col); try std.testing.expectEqual(@as(usize, 0), result.file.?.scroll); @@ -4242,7 +4262,7 @@ test "an empty counted paste leaves no count for the next motion" { const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 60, .rows = 12 }); defer p.deinit(); const pane = try p.setTestFile("abcdefgh\n"); - if (empty_register) p.yank = try p.gpa.dupe(u8, ""); + if (empty_register) p.registers.put(p.gpa, '"', "", 0, 1, true); for ("3p") |cp| p.update(.{ .key = .{ .cp = cp } }); try std.testing.expectEqual(modal.Normal.State{}, pane.body.normal); p.update(.{ .key = .{ .cp = 'l' } }); @@ -4543,11 +4563,12 @@ const LookResetTests = struct { pane.body.cur_col = 3; pane.body.vsel = .{ .active = true, .explicit = true, .row = 0, .col = 0 }; pane.body.msel = .{ .active = true, .r0 = 0, .r1 = 1 }; + _ = pane.body.reserveSels(); pane.body.sels[0] = .{ .row = 1, .col = 2, .arow = 0, .acol = 1 }; pane.body.nsel = 1; pane.body.select = true; pane.body.normal.count = 5; - pane.body.append_at = .{ .row = 0, .col = 3 }; + pane.body.restore_cursor = true; pane.body.sticky_col = 7; for (0..pane.sel.len) |slot| { pane.clearPointerSelection(slot); @@ -4564,10 +4585,10 @@ const LookResetTests = struct { fn cleared(pane: *const Pane) !void { try std.testing.expect(!pane.body.msel.active); - try std.testing.expectEqual(@as(u8, 0), pane.body.nsel); + try std.testing.expectEqual(@as(u16, 0), pane.body.nsel); try std.testing.expect(!pane.body.select); try std.testing.expectEqual(modal.Normal.State{}, pane.body.normal); - try std.testing.expect(pane.body.append_at == null); + try std.testing.expect(!pane.body.restore_cursor); try std.testing.expectEqual(@as(i32, -1), pane.body.sticky_col); for (pane.sel) |selection| try std.testing.expectEqual(.none, selection.state); for (pane.pointer_selections) |selection| try std.testing.expect(selection == null); |
