summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig239
1 files changed, 120 insertions, 119 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index 97860cfe..15b2c49b 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -240,6 +240,7 @@ pub const pdf_raster_policy: PdfRasterPolicy = switch (platform) {
};
pub const Pane = panes.Pane;
+const Text = panes.Text;
pub const MAX_PANES = 16;
pub const BodyLayer = @import("body_layer.zig").Layer;
@@ -875,19 +876,19 @@ test "Togglettymode builtin and keyboard chord share mode transitions including
try std.testing.expect(std.mem.indexOf(u8, Pardes.curTail(pane), " Mode ") != null);
p.seedTail(pane);
try std.testing.expect(pane.appendTag(" Togglettymode"));
- try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(Text.Mode.tty, pane.body.mode);
try std.testing.expect(p.executeBuiltinLine(0, "Togglettymode"));
- try std.testing.expectEqual(Pane.Mode.normal, pane.mode);
+ try std.testing.expectEqual(Text.Mode.normal, pane.body.mode);
p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } });
- try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(Text.Mode.tty, pane.body.mode);
p.enterTagEdit(pane, -1);
- try std.testing.expectEqual(Pane.Mode.insert, pane.mode);
+ try std.testing.expectEqual(Text.Mode.insert, pane.body.mode);
try std.testing.expect(p.executeBuiltinLine(0, "Togglettymode"));
- try std.testing.expectEqual(Pane.Mode.normal, pane.mode);
+ try std.testing.expectEqual(Text.Mode.normal, pane.body.mode);
try std.testing.expect(!pane.tag_edit);
p.enterTagEdit(pane, -1);
p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } });
- try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(Text.Mode.tty, pane.body.mode);
try std.testing.expect(!pane.tag_edit);
p.acknowledgePanelPresentation(&.{});
@@ -896,10 +897,10 @@ test "Togglettymode builtin and keyboard chord share mode transitions including
const y = p.rects[0].y;
p.update(.{ .mouse = .{ .button = .middle, .kind = .press, .col = x, .row = y } });
p.update(.{ .mouse = .{ .button = .middle, .kind = .release, .col = x, .row = y } });
- try std.testing.expectEqual(Pane.Mode.normal, pane.mode);
+ try std.testing.expectEqual(Text.Mode.normal, pane.body.mode);
const file = try p.setTestFile("unchanged\n");
try std.testing.expect(p.executeBuiltinLine(0, "Togglettymode"));
- try std.testing.expectEqual(Pane.Mode.normal, file.mode);
+ try std.testing.expectEqual(Text.Mode.normal, file.body.mode);
try std.testing.expectEqualStrings("unchanged\n", file.file.?.content);
}
@@ -1143,7 +1144,7 @@ test "Tty spawns a raw shell in the caller's directory" {
try std.testing.expect(free != 0);
const nt = p.panes[free] orelse return error.NoNewPane;
try std.testing.expect(nt.isTerminal());
- try std.testing.expect(nt.mode == .tty);
+ try std.testing.expect(nt.body.mode == .tty);
var found = false;
while (p.nextEffect()) |effect| switch (effect) {
@@ -1165,7 +1166,7 @@ test "Tty9p marks only the new Linux terminal for a mounted shell" {
try std.testing.expect(p.active != 0);
try std.testing.expect(!p.panes[0].?.v9fs_on_spawn);
const pane = p.panes[p.active].?;
- try std.testing.expect(pane.isTerminal() and pane.mode == .tty);
+ try std.testing.expect(pane.isTerminal() and pane.body.mode == .tty);
try std.testing.expect(pane.v9fs_on_spawn);
try std.testing.expect(!pane.greet);
try std.testing.expect(!exec.takesCommandLine(p, p.active));
@@ -1753,7 +1754,7 @@ test "owned cwd EOF failure retains the pane and Del retries its close" {
p.update(.{ .eof = .{ .pane = 0 } });
try std.testing.expectEqual(parent, p.panes[0].?);
try std.testing.expectEqual(parent, child.cwd.inherited);
- try std.testing.expectEqual(Pane.Mode.normal, parent.mode);
+ try std.testing.expectEqual(Text.Mode.normal, parent.body.mode);
try std.testing.expect(std.mem.indexOf(u8, parent.msg[0..parent.msg_len], "Del retries close") != null);
try std.testing.expectEqual(@as(usize, 0), p.effects_len);
allocator.fail_index = std.math.maxInt(usize);
@@ -2626,7 +2627,7 @@ test "Unicode display cells map back to body and tag byte cursors" {
// Both halves map to its one byte boundary.
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .press, .col = text_x + 2, .row = body_y } });
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .release, .col = text_x + 2, .row = body_y } });
- try std.testing.expectEqual(@as(i32, 1), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, 1), pane.body.cur_col);
// A click in the wide path glyph likewise becomes a byte cursor at the
// grapheme start; arrow motion then advances by the full UTF-8 cluster.
@@ -2660,8 +2661,8 @@ test "tabbed file aligns syntax cursor and mouse at the nearest insertion gap" {
@memset(f.highlights, @intFromEnum(syntax.Syn.none));
@memset(f.highlights[1..7], @intFromEnum(syntax.Syn.keyword));
f.syntax_dirty = false;
- pane.cur_row = 0;
- pane.cur_col = 1;
+ pane.body.cur_row = 0;
+ pane.body.cur_col = 1;
var frame = std.heap.ArenaAllocator.init(gpa);
defer frame.deinit();
@@ -2678,14 +2679,14 @@ test "tabbed file aligns syntax cursor and mouse at the nearest insertion gap" {
const click_x = text_x + config.tab_width + 2;
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .press, .col = click_x, .row = body_y } });
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .release, .col = click_x, .row = body_y } });
- try std.testing.expectEqual(@as(i32, 3), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, 3), pane.body.cur_col);
const line = modal.lineSlice(f.content, 0);
const virtual: u16 = 3;
const blank_x = text_x + @as(u16, @intCast(panes.File.displayWidth(line))) + virtual;
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .press, .col = blank_x, .row = body_y } });
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .release, .col = blank_x, .row = body_y } });
- try std.testing.expectEqual(@as(i32, @intCast(line.len)), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, @intCast(line.len)), pane.body.cur_col);
_ = frame.reset(.retain_capacity);
const virtual_surface = try p.render(frame.allocator());
@@ -3887,7 +3888,7 @@ pub const Pardes = struct {
},
.tty, .tty_shell => {
_ = try p.newShell(0, "");
- p.panes[0].?.mode = .tty;
+ p.panes[0].?.body.mode = .tty;
p.oneColumn();
// A bare tty is still an editor: it opens with somewhere to put
// text under the shell. The shell keeps the keyboard.
@@ -4108,8 +4109,8 @@ pub const Pardes = struct {
if (comptime pdf_enabled) if (pane.pdf) |*pv| panes.Pdf.deinitPane(p, pane, pv);
if (pane.file) |*file| panes.File.deinit(p, pane, file);
if (pane.ovl) |o| p.gpa.free(o.text);
- for (pane.ed_undo[0..pane.ed_undo_len]) |sn| if (sn.ovl) |o| p.gpa.free(o.text);
- for (pane.ed_redo[0..pane.ed_redo_len]) |sn| if (sn.ovl) |o| p.gpa.free(o.text);
+ for (pane.body.ed_undo[0..pane.body.ed_undo_len]) |sn| if (sn.ovl) |o| p.gpa.free(o.text);
+ for (pane.body.ed_redo[0..pane.body.ed_redo_len]) |sn| if (sn.ovl) |o| p.gpa.free(o.text);
panes.Terminal.deinitEmulator(pane, p.gpa);
pane.clearCwd();
pane.fs.deinit(p.gpa);
@@ -4159,7 +4160,7 @@ pub const Pardes = struct {
errdefer p.gpa.free(content);
const np = try panes.Output.open(p, free, paneDir(src), .{ .cmd = .New }, "", content);
np.cwd = .{ .inherited = src };
- np.cur_pinned = true;
+ np.body.cur_pinned = true;
return np;
}
@@ -4170,7 +4171,7 @@ pub const Pardes = struct {
const content = try p.gpa.dupe(u8, "");
errdefer p.gpa.free(content);
const np = try panes.Output.open(p, free, dir, .{ .cmd = .New }, "", content);
- np.cur_pinned = true;
+ np.body.cur_pinned = true;
return np;
}
@@ -4685,7 +4686,7 @@ pub const Pardes = struct {
ctlfs.pty.noteMarks(p, o.pane, pane);
},
.eof => |e| p.removePane(e.pane, null) catch |err| {
- if (p.panes[e.pane]) |pane| pane.mode = .normal;
+ if (p.panes[e.pane]) |pane| pane.body.mode = .normal;
p.reportError(e.pane, "terminal exited; Del retries close", err);
},
.lsp_resp => |r| p.lspResponse(r.id, r.rows),
@@ -4839,12 +4840,12 @@ pub const Pardes = struct {
const edit0: i32 = @intCast((p.tagPrefix(pane) catch return).len);
p.seedTail(pane);
if (!pane.tag_init) return;
- if (!pane.tag_edit) pane.tag_mode = pane.mode;
+ if (!pane.tag_edit) pane.tag_mode = pane.body.mode;
pane.tag_edit = true;
pane.tag_sel = false;
// a one-line tag has no use for normal mode: always insert
- pane.mode = .insert;
- pane.normal.clear();
+ pane.body.mode = .insert;
+ pane.body.normal.clear();
const end = edit0 + @as(i32, @intCast(pane.tag_tail_len));
const tail = pane.tagSlice();
const lead: i32 = @intCast(tail.len - std.mem.trimStart(u8, tail, " ").len);
@@ -4870,8 +4871,8 @@ pub const Pardes = struct {
pub fn exitTagEdit(pane: *Pane) void {
if (pane.tag_edit and pane.prompt == .none) pane.tag_saved_col = pane.tag_col;
if (pane.isTerminal()) {
- if (pane.tag_edit) pane.mode = pane.tag_mode;
- } else pane.mode = .normal;
+ if (pane.tag_edit) pane.body.mode = pane.tag_mode;
+ } else pane.body.mode = .normal;
pane.tag_edit = false;
pane.tag_sel = false;
pane.tag_name_len = null;
@@ -5054,7 +5055,7 @@ pub const Pardes = struct {
const id = p.active;
const body_mode = pane.tag_mode;
exitTagEdit(pane); // leave the tag FIRST: Del frees the pane
- pane.mode = body_mode;
+ pane.body.mode = body_mode;
exec.runBuiltin(p, cmd, id, "", txt);
return;
}
@@ -5075,7 +5076,7 @@ pub const Pardes = struct {
else
cur));
pane.tag_sel = false;
- pane.mode = .insert;
+ pane.body.mode = .insert;
return;
}
const dir: ?Builtin = for (config.window_keys) |wk| {
@@ -5096,7 +5097,7 @@ pub const Pardes = struct {
const dest = p.panes[p.active] orelse return;
exitTagEdit(pane); // the pane we left is fully out of its tag...
p.enterTagEdit(dest, -1);
- if (dest.tag_edit) dest.mode = .normal;
+ if (dest.tag_edit) dest.body.mode = .normal;
return;
}
if (lineMotion(text, cur, key)) |r| setTagRange(pane, text, r);
@@ -5244,7 +5245,7 @@ pub const Pardes = struct {
p.exitHeader();
p.active = d;
p.enterTagEdit(pane, -1);
- if (pane.tag_edit) pane.mode = .normal;
+ if (pane.tag_edit) pane.body.mode = .normal;
return;
}
if (hit(key, config.topbar_up)) {
@@ -5268,19 +5269,19 @@ pub const Pardes = struct {
pub fn cycleMode(p: *Pardes, id: usize) void {
const pane = p.panes[id] orelse return;
if (pane.file == null and !pane.isTerminal()) return;
- const previous = if (pane.tag_edit) pane.tag_mode else pane.mode;
+ const previous = if (pane.tag_edit) pane.tag_mode else pane.body.mode;
p.active = id;
p.exitHeader();
if (pane.tag_edit) exitTagEdit(pane);
- pane.mode = previous;
+ pane.body.mode = previous;
switch (previous) {
.tty => {
- pane.mode = .normal;
- pane.normal.clear();
+ pane.body.mode = .normal;
+ pane.body.normal.clear();
},
- .normal => edit.enterInsert(p, pane, .at, 1),
+ .normal => edit.enterInsert(p, &pane.body, .at, 1),
.insert => {
- edit.exitInsert(p, pane);
+ edit.exitInsert(p, &pane.body);
if (pane.isTerminal()) panes.Terminal.enterTty(p, id);
},
}
@@ -5293,9 +5294,9 @@ pub const Pardes = struct {
p.active = id;
p.exitHeader();
if (pane.tag_edit) exitTagEdit(pane);
- if (pane.mode == .tty) {
- pane.mode = .normal;
- pane.normal.clear();
+ if (pane.body.mode == .tty) {
+ pane.body.mode = .normal;
+ pane.body.normal.clear();
} else panes.Terminal.enterTty(p, id);
}
@@ -5312,7 +5313,7 @@ pub const Pardes = struct {
}
if (p.topbar_col != null) return p.topbarKey(key);
const pane = p.panes[p.active] orelse return;
- if (pane.isTerminal() and pane.mode == .tty and !pane.tag_edit) {
+ if (pane.isTerminal() and pane.body.mode == .tty and !pane.tag_edit) {
p.leader_on = false;
p.ctrl_w_pending = false;
if (key.ctrl and !key.alt and key.cp == p.opts.tty_toggle)
@@ -5350,7 +5351,7 @@ pub const Pardes = struct {
}
// insert mode owns Ctrl-w (delete word backward, helix); the focus
// prefix applies outside raw tty mode
- if (hit(key, config.window_prefix) and pane.mode != .insert) {
+ if (hit(key, config.window_prefix) and pane.body.mode != .insert) {
p.ctrl_w_pending = true;
return;
}
@@ -5403,27 +5404,27 @@ pub const Pardes = struct {
.none, .del_side => unreachable,
}
exitTagEdit(pane);
- pane.mode = .normal;
- pane.normal.clear();
+ pane.body.mode = .normal;
+ pane.body.normal.clear();
return;
}
if (pane.tag_edit) {
- if (pane.mode == .normal) p.tagNormalKey(pane, key) else p.tagInsertKey(pane, key);
+ if (pane.body.mode == .normal) p.tagNormalKey(pane, key) else p.tagInsertKey(pane, key);
const pn = p.panes[p.active] orelse return;
if (normal.selRegexArmed(pn)) |a| normal.applySelRegex(p, pn, a.pat, a.split);
return;
}
- if (pane.mode == .normal and (hit(key, config.look_key) or hit(key, config.exec_key))) {
+ if (pane.body.mode == .normal and (hit(key, config.look_key) or hit(key, config.exec_key))) {
const cmd = if (hit(key, config.look_key)) config.look_cmd else config.exec_cmd;
- edit.pinPaneCursor(p, pane);
+ edit.pinPaneCursor(p, &pane.body);
const explicit = (p.native_images and pane.hasPdfSelection()) or
- (pane.vsel.active and pane.vsel.explicit) or pane.msel.active;
+ (pane.body.vsel.active and pane.body.vsel.explicit) or pane.body.msel.active;
if (explicit) {
if (exec.chordEachSel(p, pane, cmd)) return;
if (edit.currentSelText(p, pane)) |txt| {
- pane.vsel.active = false;
- pane.msel.active = false;
- pane.select = false;
+ pane.body.vsel.active = false;
+ pane.body.msel.active = false;
+ pane.body.select = false;
exec.runBuiltin(p, cmd, p.active, "", txt);
return;
}
@@ -5433,14 +5434,14 @@ pub const Pardes = struct {
exec.runBuiltin(p, cmd, p.active, "", word);
return;
}
- if (pane.mode == .normal and pane.hasPdf()) return normal.handlePdfNormal(p, pane, key);
- switch (pane.mode) {
+ if (pane.body.mode == .normal and pane.hasPdf()) return normal.handlePdfNormal(p, pane, key);
+ switch (pane.body.mode) {
.normal => {
- normal.handleNormal(p, pane, key);
+ normal.handleNormal(p, &pane.body, key);
},
.insert => {
- if (hit(key, config.escape)) return edit.exitInsert(p, pane);
- edit.handleInsert(p, pane, key);
+ if (hit(key, config.escape)) return edit.exitInsert(p, &pane.body);
+ edit.handleInsert(p, &pane.body, key);
},
.tty => panes.Terminal.forwardKey(p, p.active, key),
}
@@ -5529,8 +5530,8 @@ pub const Pardes = struct {
};
pane.tag_edit = true;
pane.tag_sel = false;
- pane.mode = .insert;
- pane.normal.clear();
+ pane.body.mode = .insert;
+ pane.body.normal.clear();
pane.tag_col = @intCast(prefix_len + pane.tag_tail_len);
}
@@ -5551,8 +5552,8 @@ pub const Pardes = struct {
if (!zig_buf and std.mem.indexOfAny(u8, arg, " \t\r\n\"\\") != null) return;
}
const off = if (pane.file) |f| modal.offsetAt(f.content, .{
- .row = @intCast(@max(0, pane.cur_row)),
- .col = @intCast(@max(0, pane.cur_col)),
+ .row = @intCast(@max(0, pane.body.cur_row)),
+ .col = @intCast(@max(0, pane.body.cur_col)),
}) else 0;
p.lsp_seq +%= 1;
p.lsp_wait = .{
@@ -5562,8 +5563,8 @@ pub const Pardes = struct {
.serial = pane.serial,
.revision = if (pane.file) |f| f.revision else 0,
.arg = .from(arg),
- .row = pane.cur_row,
- .col = pane.cur_col,
+ .row = pane.body.cur_row,
+ .col = pane.body.cur_col,
};
p.emit(.{ .lsp = .{
.id = p.lsp_seq,
@@ -5666,8 +5667,8 @@ pub const Pardes = struct {
const replacement = p.gpa.alloc(u8, final_len) catch return false;
const old_cursor = modal.offsetAt(f.content, .{
- .row = @intCast(@max(0, pane.cur_row)),
- .col = @intCast(@max(0, pane.cur_col)),
+ .row = @intCast(@max(0, pane.body.cur_row)),
+ .col = @intCast(@max(0, pane.body.cur_col)),
});
const mapped_cursor = mapLspEditOffset(edits, old_cursor);
var read_at: usize = 0;
@@ -5681,15 +5682,15 @@ pub const Pardes = struct {
}
@memcpy(replacement[write_at..], f.content[read_at..]);
- edit.pushUndo(p, pane);
+ edit.pushUndo(p, &pane.body);
panes.File.setContent(p, f, replacement);
const cursor = modal.positionAt(f.content, mapped_cursor);
- pane.cur_row = @intCast(cursor.row);
- pane.cur_col = @intCast(cursor.col);
- pane.vsel.active = false;
- pane.msel.active = false;
- pane.select = false;
- pane.sticky_col = -1;
+ pane.body.cur_row = @intCast(cursor.row);
+ pane.body.cur_col = @intCast(cursor.col);
+ pane.body.vsel.active = false;
+ pane.body.msel.active = false;
+ pane.body.select = false;
+ pane.body.sticky_col = -1;
pane.ensureCursorVisible();
return true;
}
@@ -5718,8 +5719,8 @@ pub const Pardes = struct {
} else return;
}
if (rows.len == 0) {
- if (w.kind == .completion and pane.mode == .insert and pane.nsel == 0 and
- pane.cur_row == w.row and pane.cur_col == w.col) edit.insertTab(p, pane);
+ if (w.kind == .completion and pane.body.mode == .insert and pane.body.nsel == 0 and
+ pane.body.cur_row == w.row and pane.body.cur_col == w.col) edit.insertTab(p, &pane.body);
return;
}
@@ -5789,7 +5790,7 @@ pub const Pardes = struct {
errdefer p.gpa.destroy(history);
const pane = try p.newDocPane(id);
pane.file = .{ .path = path, .content = content, .history = history };
- pane.cur_pinned = true;
+ pane.body.cur_pinned = true;
return pane;
}
@@ -5806,7 +5807,7 @@ pub const Pardes = struct {
p.panes[0] = null;
pane.file = .{ .path = path, .content = copy, .history = history };
p.installPane(0, pane);
- pane.cur_pinned = true;
+ pane.body.cur_pinned = true;
p.active = 0;
p.sync();
return pane;
@@ -6015,8 +6016,8 @@ pub const Pardes = struct {
const now: Loc = .{
.pane = @intCast(p.active),
.serial = pane.serial,
- .line = if (pane.pdfPage()) |page| @intCast(page + 1) else if (pane.cur_pinned) @intCast(@max(0, pane.cur_row) + 1) else 0,
- .col = if (pane.pdfPage() != null) 0 else if (pane.cur_pinned) @intCast(@max(0, pane.cur_col) + 1) else 0,
+ .line = if (pane.pdfPage()) |page| @intCast(page + 1) else if (pane.body.cur_pinned) @intCast(@max(0, pane.body.cur_row) + 1) else 0,
+ .col = if (pane.pdfPage() != null) 0 else if (pane.body.cur_pinned) @intCast(@max(0, pane.body.cur_col) + 1) else 0,
};
if (p.njumps > 0 and p.samePlace(p.jumps[p.jcur], now)) {
p.jumps[p.jcur] = now; // same visit; the entry IS where you are
@@ -6289,7 +6290,7 @@ pub const Pardes = struct {
if (prompt_col < printed.dropped) continue;
const caret = printed.left + (prompt_col - printed.dropped);
if (caret < tx + tw)
- s.cursor = .{ .x = @intCast(caret), .y = row, .bar = pane.mode == .insert };
+ s.cursor = .{ .x = @intCast(caret), .y = row, .bar = pane.body.mode == .insert };
}
}
@@ -6717,7 +6718,7 @@ pub const Pardes = struct {
const typed = panes.File.displayWidth(text[0..@min(pane.tag_col - prompt0, text.len)]);
const dropped = shown - panes.File.displayWidth(kept);
if (typed < dropped) continue;
- p.surface.tag_layers[layer_index].cursor = .{ .col = @intCast(pad + typed - dropped), .bar = pane.mode == .insert };
+ p.surface.tag_layers[layer_index].cursor = .{ .col = @intCast(pad + typed - dropped), .bar = pane.body.mode == .insert };
}
}
if (p.columnBarHeight() > 0) for (0..p.ncol) |column| {
@@ -6820,7 +6821,7 @@ pub const Pardes = struct {
.font_role = .tagline,
};
s.fill(r.x, tag_y, config.GUTTER, BOX_H, box_style);
- const box_mode = if (pane.tag_edit) pane.tag_mode else pane.mode;
+ const box_mode = if (pane.tag_edit) pane.tag_mode else pane.body.mode;
s.set(r.x, tag_y, switch (box_mode) {
.normal => config.tag_normal,
.insert => config.tag_insert,
@@ -6929,7 +6930,7 @@ pub const Pardes = struct {
if (active and pane.tag_edit) {
// bar while typing, block for `:` normal mode (same rule as a body)
const col = panes.File.rawDisplayCol(tag, pane.tag_col) -| pane.tag_scroll;
- if (col < tw) s.cursor = .{ .x = tx + @as(u16, @intCast(col)), .y = tag_y, .bar = pane.mode == .insert };
+ if (col < tw) s.cursor = .{ .x = tx + @as(u16, @intCast(col)), .y = tag_y, .bar = pane.body.mode == .insert };
}
for (pane.sel, 0..) |selection, button| {
@@ -7039,7 +7040,7 @@ test "raw terminal cursor obeys visibility without hiding modal and tag cursors"
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
- pane.mode = .tty;
+ pane.body.mode = .tty;
p.update(.{ .output = .{ .pane = 0, .bytes = "abc" } });
var frame = std.heap.ArenaAllocator.init(gpa);
defer frame.deinit();
@@ -7051,10 +7052,10 @@ test "raw terminal cursor obeys visibility without hiding modal and tag cursors"
p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[?25l" } });
try std.testing.expect((try p.render(frame.allocator())).cursor == null);
- pane.mode = .normal;
- pane.cur_pinned = true;
- pane.cur_row = 0;
- pane.cur_col = 1;
+ pane.body.mode = .normal;
+ pane.body.cur_pinned = true;
+ pane.body.cur_row = 0;
+ pane.body.cur_col = 1;
const modal_cursor = (try p.render(frame.allocator())).cursor orelse return error.MissingCursor;
try std.testing.expectEqual(rect.x + config.GUTTER + 1, modal_cursor.x);
try std.testing.expectEqual(body_y, modal_cursor.y);
@@ -7062,7 +7063,7 @@ test "raw terminal cursor obeys visibility without hiding modal and tag cursors"
const tag_cursor = (try p.render(frame.allocator())).cursor orelse return error.MissingCursor;
try std.testing.expectEqual(if (p.settings.tag_bottom) rect.y + rect.h - BOX_H else rect.y, tag_cursor.y);
Pardes.exitTagEdit(pane);
- pane.mode = .tty;
+ pane.body.mode = .tty;
try std.testing.expect((try p.render(frame.allocator())).cursor == null);
p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[?25h\x1b[?1049h\x1b[2;5H" } });
@@ -7086,7 +7087,7 @@ test "raw terminal cursor follows its active row only while that row is visible"
while (p.nextEffect()) |_| {}
p.settings.tag_bottom = tag_bottom;
const pane = p.panes[0].?;
- pane.mode = .tty;
+ pane.body.mode = .tty;
for (0..60) |_| p.update(.{ .output = .{ .pane = 0, .bytes = "row\r\n" } });
p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[3;4H" } });
var frame = std.heap.ArenaAllocator.init(gpa);
@@ -7129,7 +7130,7 @@ test "Esc back into a tty leaves its view at the prompt" {
try std.testing.expectEqual(shell, p.active);
p.update(.{ .key = .{ .cp = Key.escape, .shift = true } });
- try std.testing.expectEqual(Pane.Mode.tty, sp.mode);
+ try std.testing.expectEqual(Text.Mode.tty, sp.body.mode);
// tty mode follows output to the bottom, so a screenful and a half of it
// rides the view down and leaves that pin far up in the scrollback.
@@ -7368,7 +7369,7 @@ test "the bare tty startup opens a text pane under the shell, unfocused" {
const shell = p.panes[p.col_panes[0][0]].?;
const scratch = p.panes[p.col_panes[0][1]].?;
try std.testing.expect(shell.isTerminal());
- try std.testing.expectEqual(Pane.Mode.tty, shell.mode);
+ try std.testing.expectEqual(Text.Mode.tty, shell.body.mode);
try std.testing.expect(!scratch.isTerminal());
try std.testing.expectEqualStrings("", scratch.file.?.content);
@@ -7391,7 +7392,7 @@ test "tty output follows only from the bottom" {
const shell = p.active;
const sp = p.panes[shell].?;
p.update(.{ .key = .{ .cp = Key.escape, .shift = true } });
- try std.testing.expectEqual(Pane.Mode.tty, sp.mode);
+ try std.testing.expectEqual(Text.Mode.tty, sp.body.mode);
for (0..60) |i| {
var buf: [32]u8 = undefined;
@@ -7445,7 +7446,7 @@ test "Esc back into a file leaves its view where it was" {
for (0..20) |_| p.update(.{ .key = .{ .cp = 'j' } });
p.sync();
const view = dp.file.?.scroll;
- const row = dp.cur_row;
+ const row = dp.body.cur_row;
try std.testing.expect(view > 0);
p.update(.{ .key = .{ .cp = Key.escape } }); // out to the shell
@@ -7458,10 +7459,10 @@ test "Esc back into a file leaves its view where it was" {
// Nothing moved. The old landing recentred the line under the cursor, so
// coming back repainted the whole screen to show what was already on it.
try std.testing.expectEqual(view, dp.file.?.scroll);
- try std.testing.expectEqual(row, dp.cur_row);
+ try std.testing.expectEqual(row, dp.body.cur_row);
// ...and the cursor is still on screen, which is all `.nearest` promises.
- try std.testing.expect(dp.cur_row >= @as(i32, @intCast(view)));
- try std.testing.expect(dp.cur_row < @as(i32, @intCast(view)) + @as(i32, dp.rows));
+ try std.testing.expect(dp.body.cur_row >= @as(i32, @intCast(view)));
+ try std.testing.expect(dp.body.cur_row < @as(i32, @intCast(view)) + @as(i32, dp.rows));
// The other arm still centres: a look target, a `:NN`, a search hit.
look.focusPaneLine(p, doc, .{ .line = @intCast(row + 1), .col = 1 }, .center);
@@ -7488,7 +7489,7 @@ test "raw tty Escape only leaves at a shell prompt" {
p.update(.{ .key = .{ .cp = Key.escape, .shift = true } });
try std.testing.expectEqual(@as(usize, 0), p.active);
try std.testing.expectEqualStrings("", drainWrites(p, &buf));
- try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(Text.Mode.tty, pane.body.mode);
p.update(.{ .key = .{ .cp = Key.escape } }); // back into the shell
try std.testing.expectEqual(shell, p.active);
@@ -7497,7 +7498,7 @@ test "raw tty Escape only leaves at a shell prompt" {
p.update(.{ .key = .{ .cp = Key.escape } }); // bare Escape leaves at a prompt
try std.testing.expectEqual(@as(usize, 0), p.active);
try std.testing.expectEqualStrings("", drainWrites(p, &buf));
- try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(Text.Mode.tty, pane.body.mode);
}
test "raw tty Ctrl-B switches to editor mode without sending child input" {
@@ -7511,7 +7512,7 @@ test "raw tty Ctrl-B switches to editor mode without sending child input" {
_ = drainWrites(p, &buf);
p.update(.{ .key = .{ .cp = 'b', .ctrl = true } });
try std.testing.expectEqual(shell, p.active);
- try std.testing.expectEqual(Pane.Mode.normal, p.panes[shell].?.mode);
+ try std.testing.expectEqual(Text.Mode.normal, p.panes[shell].?.body.mode);
try std.testing.expectEqualStrings("", drainWrites(p, &buf));
}
@@ -7599,7 +7600,7 @@ test "raw tty forwards Ctrl letters and former global shortcuts to the child" {
};
try std.testing.expectEqualStrings(encoded, drainWrites(p, &buf));
try std.testing.expectEqual(@as(usize, 0), p.active);
- try std.testing.expectEqual(Pane.Mode.tty, p.panes[0].?.mode);
+ try std.testing.expectEqual(Text.Mode.tty, p.panes[0].?.body.mode);
try std.testing.expect(!p.ctrl_w_pending and p.clip_pending == null);
}
// ...and the two paste chords are the exception: Ctrl-V types the register
@@ -7745,13 +7746,13 @@ test "leaving tty hides the prompt and keeps the command typed at it" {
// The BODY is what you look at, and it follows the mode: in tty the pane
// is the program's own screen, so the prompt is there.
- sp.mode = .tty;
+ sp.body.mode = .tty;
try std.testing.expectEqualStrings(
"user@box ~/src $ grep -rn TODO src/",
bodyRowOf(p, sp, "grep") orelse return error.MissingPromptRow,
);
- sp.mode = .normal;
+ sp.body.mode = .normal;
try std.testing.expectEqualStrings(
"grep -rn TODO src/",
bodyRowOf(p, sp, "grep") orelse return error.MissingPromptRow,
@@ -7788,7 +7789,7 @@ test "entering tty walks the shell cursor to the column clicked past the prompt"
.bytes = "\x1b]133;A;cl=line\x1b\\prompt> \x1b]133;B\x1b\\0123456789",
} });
p.sync();
- sp.mode = .normal;
+ sp.body.mode = .normal;
p.shell_rows.stale = true;
// The command shows LEFT-HUGGED, so its column 3 is the '3'...
@@ -7802,9 +7803,9 @@ test "entering tty walks the shell cursor to the column clicked past the prompt"
// ...but the shell's own cursor lives on the real grid, eight cells
// further right, behind the prompt this pane is not showing.
- sp.cur_row = row;
- sp.cur_col = 3;
- sp.cur_pinned = true;
+ sp.body.cur_row = row;
+ sp.body.cur_col = 3;
+ sp.body.cur_pinned = true;
while (p.nextEffect()) |_| {}
panes.Terminal.enterTty(p, shell);
@@ -7897,8 +7898,8 @@ test "LSP failure clears only its matching wait without completion indentation"
const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
defer p.deinit();
const pane = try p.setTestFile("x");
- pane.mode = .insert;
- pane.cur_col = 1;
+ pane.body.mode = .insert;
+ pane.body.cur_col = 1;
p.lspRequest(p.active, .completion, "");
const old_id = p.lsp_wait.?.id;
@@ -7909,13 +7910,13 @@ test "LSP failure clears only its matching wait without completion indentation"
p.update(.{ .lsp_resp = .{ .id = current_id, .rows = null } });
try std.testing.expect(p.lsp_wait == null);
try std.testing.expectEqualStrings("x", pane.file.?.content);
- try std.testing.expectEqual(@as(i32, 1), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, 1), pane.body.cur_col);
p.lspRequest(p.active, .completion, "");
p.update(.{ .lsp_resp = .{ .id = p.lsp_wait.?.id, .rows = "" } });
try std.testing.expect(p.lsp_wait == null);
try std.testing.expectEqualStrings("x ", pane.file.?.content);
- try std.testing.expectEqual(@as(i32, 4), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, 4), pane.body.cur_col);
}
test "board heap: every allocation failure during boot is a clean OutOfMemory" {
@@ -7935,25 +7936,25 @@ test "jump history clears selections and lands at the recorded cursor" {
p.jumps[0] = .{ .pane = 0, .serial = pane.serial, .line = 3, .col = 8 };
p.jumps[1] = .{ .pane = 0, .serial = pane.serial, .line = 1, .col = 1 };
for ([_]u21{ 'o', 'i' }, 0..) |key, index| {
- pane.setRange(pane.file.?.content, 0, .{ .anchor = 1, .head = 5 }, true);
+ pane.body.setRange(pane.file.?.content, 0, .{ .anchor = 1, .head = 5 }, true);
pane.sel[0] = .{ .state = .done, .c0 = 2, .c1 = 5, .r0 = 1, .r1 = 1 };
try edit.capturePointerSelection(p, pane, 0);
- pane.select = true;
+ pane.body.select = true;
p.update(.{ .key = .{ .cp = key, .ctrl = true } });
try std.testing.expectEqual(index, p.jcur);
try std.testing.expectEqual(@as(usize, 2), p.njumps);
try std.testing.expectEqual(@as(u32, 3), p.jumps[0].line);
- try std.testing.expect(!pane.vsel.active and !pane.msel.active and !pane.select);
- try std.testing.expectEqual(@as(u8, 0), pane.nsel);
+ try std.testing.expect(!pane.body.vsel.active and !pane.body.msel.active and !pane.body.select);
+ try std.testing.expectEqual(@as(u8, 0), pane.body.nsel);
try std.testing.expectEqual(.none, pane.sel[0].state);
try std.testing.expect(pane.pointer_selections[0] == null);
- try std.testing.expectEqual(@as(i32, if (index == 0) 2 else 0), pane.cur_row);
- try std.testing.expectEqual(@as(i32, if (index == 0) 7 else 0), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, if (index == 0) 2 else 0), pane.body.cur_row);
+ try std.testing.expectEqual(@as(i32, if (index == 0) 7 else 0), pane.body.cur_col);
}
- pane.setRange(pane.file.?.content, 0, .{ .anchor = 1, .head = 5 }, true);
- const selected = pane.primaryRange(pane.file.?.content, 0);
+ pane.body.setRange(pane.file.?.content, 0, .{ .anchor = 1, .head = 5 }, true);
+ const selected = pane.body.primaryRange(pane.file.?.content, 0);
p.jumpBy(1); // No forward entry: selection stays untouched.
- try std.testing.expectEqualDeep(selected, pane.primaryRange(pane.file.?.content, 0));
+ try std.testing.expectEqualDeep(selected, pane.body.primaryRange(pane.file.?.content, 0));
for ([_]Loc{
.{ .pane = 15, .serial = pane.serial, .line = 1, .col = 1 },
.{ .pane = 0, .serial = pane.serial + 1, .line = 1, .col = 1 },
@@ -7961,7 +7962,7 @@ test "jump history clears selections and lands at the recorded cursor" {
p.jumps[0] = missing;
p.jumpBy(-1);
try std.testing.expectEqual(@as(usize, 1), p.jcur);
- try std.testing.expectEqualDeep(selected, pane.primaryRange(pane.file.?.content, 0));
+ try std.testing.expectEqualDeep(selected, pane.body.primaryRange(pane.file.?.content, 0));
}
}