summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pardes.zig22
-rw-r--r--test/snapshots/exec-bigdrag.golden61
-rw-r--r--test/snapshots/exec-bigdrag.snap40
3 files changed, 115 insertions, 8 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index c4893b25..d617e552 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -628,9 +628,11 @@ pub const Pardes = struct {
/// press during an active middle select-drag; consumed on middle release
chord_arg: ?[]u8 = null,
- effects: [64]Effect = undefined,
+ /// pending effects, drained by the shell after each update. Growable: one
+ /// update can emit unbounded writes (a big selection executed is chunked
+ /// into 64-byte write effects) — a fixed ring overflows and panics.
+ effects: std.ArrayList(Effect) = .empty,
effects_head: usize = 0,
- effects_tail: usize = 0,
/// modal yank register (gpa-owned); a yank also mirrors out to the system
/// clipboard via the set_clipboard effect.
@@ -678,6 +680,7 @@ pub const Pardes = struct {
if (p.yank) |y| gpa.free(y);
if (p.dump_out) |d| gpa.free(d);
if (p.chord_arg) |a| gpa.free(a);
+ p.effects.deinit(gpa);
p.scratch.deinit();
gpa.free(p.surface.cells);
gpa.destroy(p);
@@ -717,6 +720,7 @@ pub const Pardes = struct {
fn newShell(p: *Pardes, id: usize, cwd: []const u8) !*Pane {
std.debug.assert(p.panes[id] == null);
+ if (cwd.len > 256) return error.PathTooLong; // spawn effect cwd is a Buf(256)
const pane = try p.gpa.create(Pane);
pane.* = .{
.vt = try ghostty_vt.Terminal.init(p.gpa, .{
@@ -780,14 +784,16 @@ pub const Pardes = struct {
}
fn emit(p: *Pardes, e: Effect) void {
- std.debug.assert(p.effects_tail - p.effects_head < p.effects.len);
- p.effects[p.effects_tail % p.effects.len] = e;
- p.effects_tail += 1;
+ p.effects.append(p.gpa, e) catch {};
}
pub fn nextEffect(p: *Pardes) ?Effect {
- if (p.effects_head == p.effects_tail) return null;
- const e = p.effects[p.effects_head % p.effects.len];
+ if (p.effects_head == p.effects.items.len) {
+ p.effects.clearRetainingCapacity();
+ p.effects_head = 0;
+ return null;
+ }
+ const e = p.effects.items[p.effects_head];
p.effects_head += 1;
return e;
}
@@ -2607,7 +2613,7 @@ pub const Pardes = struct {
};
switch (look.resolve(txt, cwd, &realbuf)) {
.none => {},
- .url => |u| p.emit(.{ .open_link = .from(u) }),
+ .url => |u| if (u.len <= 256) p.emit(.{ .open_link = .from(u) }),
.dir => |dir| {
// focus an existing terminal on this dir, else fork one below
for (p.panes, 0..) |slot, i| {
diff --git a/test/snapshots/exec-bigdrag.golden b/test/snapshots/exec-bigdrag.golden
new file mode 100644
index 00000000..613bb342
--- /dev/null
+++ b/test/snapshots/exec-bigdrag.golden
@@ -0,0 +1,61 @@
+== snap alive grid=200x60 cursor=104,37
+|Kill Newcol Tutor Debug Colors NextColor Dump
+| nm /tmp/pardes-snap/exec-bigdrag/cwd Del nm /tmp/pardes-snap/exec-bigdrag/cwd Del
+| bash: line: command not found
+| big.txt
+| bash: 4line: command not found
+|
+| bash: 15line: command not found
+|
+| bash: 726line: command not found
+|
+| bash: 2737line: command not found
+|
+| bash: 2748line: command not found
+|
+| bash: e: command not found
+|
+| bash: ne: command not found
+|
+| bash: ine: command not found
+|
+| bash: line: command not found
+|
+| bash: 2line: command not found
+|
+| bash: 13line: command not found
+|
+| bash: 824line: command not found
+|
+| bash: 2835line: command not found
+|
+| bash: 2846line: command not found
+| nm /tmp/pardes-snap/exec-bigdrag/cwd Del
+| bash: e: command not found
+| big.txt
+| bash: ne: command not found
+|
+| bash: ine: command not found
+| echo alive-o''k
+| bash: line: command not found
+|
+| bash: 0line: command not found
+|
+| bash: 11line: command not found
+|
+| bash: 922line: command not found
+|
+| bash: 2933line: command not found
+|
+| bash: 2944line: command not found
+|
+| bash: e: command not found
+|
+| bash: ne: command not found
+|
+| bash: ine: command not found
+|
+| bash: line: command not found
+|
+| alive-ok
+|
diff --git a/test/snapshots/exec-bigdrag.snap b/test/snapshots/exec-bigdrag.snap
new file mode 100644
index 00000000..dae92205
--- /dev/null
+++ b/test/snapshots/exec-bigdrag.snap
@@ -0,0 +1,40 @@
+# a giant accidental middle-drag: the whole selection is executed, chunked
+# into 64-byte write effects in ONE update — this used to burst the fixed
+# 64-slot effect ring and panic the core (assert in emit). Needs a big grid:
+# the selection must exceed 64*64 bytes, more than any 30x100 pane can hold.
+lines big.txt 3000
+start 60 200
+wait 8000 big.txt
+stable 500 20000
+press left 105 8
+release left 105 8
+stable 300 5000
+key i
+text tr -d '\n' < big.txt
+key esc
+settle 400
+press middle 105 8
+drag middle 126 8
+release middle 126 8
+stable 800 30000
+# the accidental sweep over the full-height right pane, then release
+press middle 105 4
+drag middle 150 30
+drag middle 198 58
+release middle 198 58
+settle 500
+stable 800 30000
+# still alive: type and execute a marker command
+press left 105 40
+release left 105 40
+stable 300 5000
+key i
+text echo alive-o''k
+key esc
+settle 300
+press middle 105 40
+drag middle 119 40
+release middle 119 40
+wait 10000 alive-ok
+stable 800 20000
+snap alive