summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/body_layer.zig13
-rw-r--r--src/edit.zig72
-rw-r--r--src/mouse.zig12
-rw-r--r--src/panes.zig13
-rw-r--r--test/panes.zig60
-rw-r--r--test/snapshots/exec-bigdrag.golden94
6 files changed, 160 insertions, 104 deletions
diff --git a/src/body_layer.zig b/src/body_layer.zig
index a0195fb8..413ab7de 100644
--- a/src/body_layer.zig
+++ b/src/body_layer.zig
@@ -72,7 +72,7 @@ fn paintTerminalSelection(p: *Pardes, s: *Surface, pane: *Pane, r: Rect, rows: [
hi = @min(hi, line.len);
if (lo >= hi) continue;
var col = panes.File.rawDisplayCol(line, lo);
- const end = panes.File.rawDisplayCol(line, hi);
+ const end = if (row.to_edge and hi == line.len) width else panes.File.rawDisplayCol(line, hi);
while (col < end and col < width) : (col += 1) {
const cell = s.at(tx + @as(u16, @intCast(col)), body_y + @as(u16, @intCast(visible)));
cell.default = false;
@@ -103,7 +103,7 @@ fn paintSourceSelection(p: *Pardes, s: *Surface, pane: *Pane, r: Rect, rows: []c
const hi = @min(end, row.hi);
if (lo >= hi) continue;
var col = prefix + @as(i32, @intCast(panes.File.rawDisplayCol(line[start..], lo - start)));
- const last = prefix + @as(i32, @intCast(panes.File.rawDisplayCol(line[start..], hi - start)));
+ const last = if (row.to_edge and hi == end) @as(i32, width) else prefix + @as(i32, @intCast(panes.File.rawDisplayCol(line[start..], hi - start)));
while (col < last and col < width) : (col += 1) {
const cell = s.at(tx + @as(u16, @intCast(col)), body_y + @as(u16, @intCast(visible)));
cell.default = false;
@@ -130,13 +130,12 @@ pub fn paintPointerSelection(
fg: ?[3]u8,
) void {
if (pane.pointerSelection(sl)) |rows| return paintSourceSelection(p, s, pane, r, rows, bg, fg);
- const r0 = @min(sl.r0, sl.r1);
- const r1 = @max(sl.r0, sl.r1);
- const c0 = @max(0, @min(sl.c0, sl.c1));
- const c1 = @max(0, @max(sl.c0, sl.c1));
var row: u16 = 0;
while (row < r.h) : (row += 1) {
- if (@as(i32, row) < r0 or @as(i32, row) > r1 or row < from_row) continue;
+ if (row < from_row) continue;
+ const cols = edit.sweepCols(sl, row) orelse continue;
+ const c0: i32 = if (cols.first) cols.lo else 0;
+ const c1: i32 = cols.hi orelse std.math.maxInt(i16);
const sy = if (row < pane.tag_rows) tag_y + row else body_y + row - pane.tag_rows;
// File line numbers occupy a gutter only in the body. The tag is
// row zero in Sel space and starts at its real first text cell.
diff --git a/src/edit.zig b/src/edit.zig
index 84bbb292..3dfe2f20 100644
--- a/src/edit.zig
+++ b/src/edit.zig
@@ -234,10 +234,13 @@ pub fn capturePointerSelection(p: *Pardes, pane: *Pane, slot: usize) !void {
errdefer p.gpa.free(rows);
const raw_text = if (raw) try p.gpa.dupe(u8, try selectionText(p, pane, gesture)) else null;
const prefix: i32 = if (pane.file != null) panes.File.gutterWidth(pane) else 0;
- const left = @max(0, @min(gesture.c0, gesture.c1));
- const right = @max(0, @max(gesture.c0, gesture.c1));
for (rows, 0..) |*row, index| {
const visible = first + @as(i32, @intCast(index));
+ // A stream: only the first row starts where the press was; the
+ // others start after the line numbers, and all but the last run on.
+ const cols = sweepCols(gesture, visible + @as(i32, pane.tag_rows)).?;
+ const left: i32 = if (cols.first) cols.lo else prefix;
+ const right: i32 = cols.hi orelse std.math.maxInt(i32) / 2;
var source = pane.wrapAt(visible);
if (raw) source = .{ .line = panes.Terminal.gridOffset(pane) + visible, .at = 0 };
const line = if (raw) modal.lineSlice(body, @intCast(visible)) else pointerSourceLine(pane, terminal_lines, source.line);
@@ -250,7 +253,8 @@ pub fn capturePointerSelection(p: *Pardes, pane: *Pane, slot: usize) !void {
row.* = .{
.row = source.line,
.lo = lo,
- .hi = if (right < prefix) lo else @min(end, modal.nextGrapheme(line, at)),
+ .hi = if (right < prefix) lo else if (cols.hi == null) end else @min(end, modal.nextGrapheme(line, at)),
+ .to_edge = cols.hi == null,
.raw_terminal = raw,
.prompt_bytes = if (raw) panes.Terminal.promptPrefixBytes(pane, source.line, line) else 0,
};
@@ -294,40 +298,48 @@ pub fn selectionText(p: *Pardes, pane: *Pane, sl: Pane.Sel) ![]const u8 {
}
return result;
}
- const r0 = @min(sl.r0, sl.r1);
- const r1 = @max(sl.r0, sl.r1);
- const c0: usize = @intCast(@max(0, @min(sl.c0, sl.c1)));
- const c1: usize = @intCast(@max(0, @max(sl.c0, sl.c1)));
const text = try paneText(p, pane);
- var total: usize = 0;
- var selected: usize = 0;
- var count_it = std.mem.splitAny(u8, text, "\n");
- var count_row: i32 = 0;
- while (count_it.next()) |line| : (count_row += 1) {
- if (count_row < r0 or count_row > r1) continue;
- const b0 = @min(panes.File.renderedLineByteCol(pane, count_row, line, c0), line.len);
- const b1 = modal.nextGrapheme(line, @min(panes.File.renderedLineByteCol(pane, count_row, line, c1), line.len));
- total += b1 - b0 + @intFromBool(selected > 0);
- selected += 1;
- }
- const out = try arena.alloc(u8, total);
- var at: usize = 0;
+ var out: std.ArrayList(u8) = .empty;
var it = std.mem.splitAny(u8, text, "\n");
var v: i32 = 0;
var first = true;
while (it.next()) |line| : (v += 1) {
- if (v < r0 or v > r1) continue;
- if (!first) {
- out[at] = '\n';
- at += 1;
- }
+ const cols = sweepCols(sl, v) orelse continue;
+ if (!first) try out.append(arena, '\n');
first = false;
- const b0 = @min(panes.File.renderedLineByteCol(pane, v, line, c0), line.len);
- const b1 = modal.nextGrapheme(line, @min(panes.File.renderedLineByteCol(pane, v, line, c1), line.len));
- @memcpy(out[at..][0 .. b1 - b0], line[b0..b1]);
- at += b1 - b0;
+ // Past the first row a body row starts after its line numbers.
+ const gutter: i32 = if (pane.file != null and v >= pane.tag_rows) panes.File.gutterWidth(pane) else 0;
+ const lo: usize = @intCast(if (cols.first) cols.lo else gutter);
+ const b0 = @min(panes.File.renderedLineByteCol(pane, v, line, lo), line.len);
+ const b1 = if (cols.hi) |hi|
+ @max(b0, modal.nextGrapheme(line, @min(panes.File.renderedLineByteCol(pane, v, line, @intCast(hi)), line.len)))
+ else
+ line.len;
+ try out.appendSlice(arena, line[b0..b1]);
}
- return out;
+ return out.items;
+}
+
+/// A sweep's columns on `row`, in its Sel space: acme's stream, not a
+/// rectangle (libframe/frselect.c:115-140, frselectpaint): the first row
+/// from the press to its end, the rows between whole, the last from its
+/// start to the release. `hi` null runs to the end of the row.
+pub const SweepCols = struct { lo: i32, hi: ?i32, first: bool };
+
+pub fn sweepCols(sl: Pane.Sel, row: i32) ?SweepCols {
+ const start, const end = sweepEnds(sl);
+ if (row < start[0] or row > end[0]) return null;
+ return .{
+ .lo = if (row == start[0]) @max(0, start[1]) else 0,
+ .hi = if (row == end[0]) @max(0, end[1]) else null,
+ .first = row == start[0],
+ };
+}
+
+/// The sweep's two ends in reading order, each (row, col).
+pub fn sweepEnds(sl: Pane.Sel) struct { [2]i32, [2]i32 } {
+ const fwd = sl.r0 < sl.r1 or (sl.r0 == sl.r1 and sl.c0 <= sl.c1);
+ return if (fwd) .{ .{ sl.r0, sl.c0 }, .{ sl.r1, sl.c1 } } else .{ .{ sl.r1, sl.c1 }, .{ sl.r0, sl.c0 } };
}
pub fn spanHas(r: i32, c: i32, ar: i32, ac: i32, br: i32, bc: i32) bool {
diff --git a/src/mouse.zig b/src/mouse.zig
index 22eb3270..2dcd80ed 100644
--- a/src/mouse.zig
+++ b/src/mouse.zig
@@ -691,12 +691,13 @@ fn gestureRange(p: *Pardes, id: usize, text: []const u8, on_tag: bool, operand:
const start: ?modal.Cursor = if (operand.file_word) |w|
.{ .row = @intCast(@max(0, w.row)), .col = @intCast(@max(0, w.lo)) }
else if (operand.expanded orelse operand.preview) |sel| lead: {
- // A selection's leading corner in reading order, converted the way
+ // A selection's start in reading order, converted the way
// `pointerOperand` converts the click itself.
- const top = @min(sel.r0, sel.r1) - @as(i32, pane.tag_rows);
+ const lead = edit.sweepEnds(sel)[0];
+ const top = lead[0] - @as(i32, pane.tag_rows);
if (top < 0) break :lead null;
const w = pane.wrapAt(top);
- const col = edit.paneByteAtDisplay(p, &pane.body, w.line, w.at, @min(sel.c0, sel.c1) - panes.File.gutterWidth(pane));
+ const col = edit.paneByteAtDisplay(p, &pane.body, w.line, w.at, lead[1] - panes.File.gutterWidth(pane));
break :lead .{
.row = @intCast(@max(0, w.line)),
.col = @intCast(@max(0, col)),
@@ -730,10 +731,11 @@ fn mirrorTtySelection(p: *Pardes, pane: *Pane) void {
const rows = pane.pointerSelection(gesture) orelse return;
const text = pane.rawPointerText(gesture) orelse return;
if (rows.len == 0) return;
- const endpoint = rows[if (gesture.r1 >= gesture.r0) rows.len - 1 else 0];
+ const forward = gesture.r1 > gesture.r0 or (gesture.r1 == gesture.r0 and gesture.c1 >= gesture.c0);
+ const endpoint = rows[if (forward) rows.len - 1 else 0];
const body = body_layer.bodyText(p, p.scratch.allocator(), pane) catch return;
const line = modal.lineSlice(body, @intCast(@max(0, endpoint.row - panes.Terminal.gridOffset(pane))));
- const byte = if (gesture.c1 >= gesture.c0) modal.prevGrapheme(line, @min(endpoint.hi, line.len)) else endpoint.lo;
+ const byte = if (forward) modal.prevGrapheme(line, @min(endpoint.hi, line.len)) else endpoint.lo;
pane.body.cur_row = pane.surfRow(endpoint.row);
var shown = std.mem.trimEnd(u8, line[@min(endpoint.prompt_bytes, line.len)..], " \t");
if (pane.ovl) |overlay| {
diff --git a/src/panes.zig b/src/panes.zig
index a7e5c668..e4621311 100644
--- a/src/panes.zig
+++ b/src/panes.zig
@@ -27,8 +27,10 @@ pub const Pane = struct {
/// The words that throw unsaved text away (builtins.zig warnModified).
pub const Discarding = enum { Exit, Restore, get };
- /// One mouse selection (block-shaped), per button. c/r are text-area relative;
- /// r counts from the tag's first row (the body starts at Pane.tag_rows).
+ /// One mouse sweep, per button: the press (c0, r0) and where it is now
+ /// (c1, r1), a stream between them as acme's (edit.sweepCols). c/r are
+ /// text-area relative; r counts from the tag's first row (the body
+ /// starts at Pane.tag_rows).
pub const Sel = struct {
state: enum { none, dragging, done } = .none,
source_id: u64 = 0,
@@ -38,12 +40,15 @@ pub const Pane = struct {
r1: i32 = 0,
};
- /// A rectangle keeps one source span per rendered row. Wrapped segments
- /// remain separate rows when copied, even when they share a source line.
+ /// A captured sweep keeps one source span per rendered row. Wrapped
+ /// segments remain separate rows when copied, even when they share a
+ /// source line.
pub const PointerRow = struct {
row: i32,
lo: usize,
hi: usize,
+ /// Not the sweep's last row: its highlight runs to the right edge.
+ to_edge: bool = false,
prefix: [32]u8 = @splat(0),
prefix_len: u8 = 0,
raw_terminal: bool = false,
diff --git a/test/panes.zig b/test/panes.zig
index 40b4b6ba..96819728 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -595,7 +595,8 @@ const BodyHitTests = struct {
p.update(.{ .mouse = mouse(layer, last - 1, prefix + 11, .press) });
// Release at a different source row without an intermediate drag event.
p.update(.{ .mouse = mouse(layer, last, prefix + 14, .release) });
- try std.testing.expectEqualStrings("body\nbody", pardes.test_api.heldSelection(p, 0).?);
+ // A stream: the last row from its start, indentation and all.
+ try std.testing.expect(std.mem.endsWith(u8, pardes.test_api.heldSelection(p, 0).?, "// body") and std.mem.startsWith(u8, pardes.test_api.heldSelection(p, 0).?, "body\n"));
p.update(.{ .mouse = mouse(layer, last, 10, .press) });
p.update(.{ .mouse = mouse(layer, last, 10, .release) });
try std.testing.expectEqual(expected, pane.body.cur_row);
@@ -873,7 +874,7 @@ const TtySelectionTests = struct {
try noChildInput(p);
}
- test "tty selection preserves exact rectangle through yank clipboard and mode changes" {
+ test "tty selection preserves its exact stream through yank clipboard and mode changes" {
if (comptime !panes.Terminal.enabled) return error.SkipZigTest;
for ([_]bool{ false, true }) |prompt| {
const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 40, .rows = 12 });
@@ -894,7 +895,7 @@ const TtySelectionTests = struct {
const x = rect.x + config.GUTTER;
const y = p.bodyTop(pane, rect);
JumpSelectionTests.drag(p, x + @as(u16, if (prompt) 0 else 1), y, x + 3, y + @as(u16, if (prompt) 0 else 1));
- const expected = if (prompt) "$ ab" else "lph\nrav";
+ const expected = if (prompt) "$ ab" else "lpha\nbrav";
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.registers.text(p.gpa, '"') orelse return error.MissingAutomaticTtyYank);
@@ -907,9 +908,13 @@ const TtySelectionTests = struct {
try std.testing.expectEqual(panes.Text.Mode.normal, pane.body.mode);
const normal = try p.render(frame.allocator());
if (!prompt) {
- const selection_bg: pardes.Color = .{ .rgb = p.theme().sel_bg };
- try std.testing.expect(!std.meta.eql(selection_bg, normal.at(x + 4, y).style.bg));
- try std.testing.expect(!std.meta.eql(selection_bg, normal.at(x, y + 1).style.bg));
+ // A stream: the first row to its edge, the last from its
+ // start; (x + 1, y) is surely in it, whatever its tint.
+ const selected = normal.at(x + 1, y).style.bg;
+ try std.testing.expect(std.meta.eql(selected, normal.at(x + 4, y).style.bg));
+ try std.testing.expect(std.meta.eql(selected, normal.at(x, y + 1).style.bg));
+ try std.testing.expect(!std.meta.eql(selected, normal.at(x + 4, y + 1).style.bg));
+ try std.testing.expect(!std.meta.eql(selected, normal.at(x, y).style.bg));
}
try std.testing.expectEqualStrings(expected, pardes.test_api.heldSelection(p, 0).?);
p.update(.{ .key = .{ .cp = 'y' } });
@@ -956,7 +961,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.registers.text(p.gpa, '"') orelse return error.MissingAutomaticTtyYank);
+ try std.testing.expectEqualStrings("lpha\nbrav", p.registers.text(p.gpa, '"') orelse return error.MissingAutomaticTtyYank);
try noChildInput(p);
const target = p.rects[1];
@@ -976,13 +981,13 @@ const TtySelectionTests = struct {
}
const expected = try std.fmt.allocPrint(p.gpa, "{s}{s}", .{
if (reports_mouse) "\x1b[<0;3;1M\x1b[<0;3;1m" else "",
- if (bracketed) "\x1b[200~lph\nrav\x1b[201~" else "lph\rrav",
+ if (bracketed) "\x1b[200~lpha\nbrav\x1b[201~" else "lpha\rbrav",
});
defer p.gpa.free(expected);
try std.testing.expectEqualStrings(expected, written.written());
try std.testing.expectEqual(panes.Text.Mode.tty, p.panes[0].?.body.mode);
try std.testing.expectEqual(panes.Text.Mode.tty, p.panes[1].?.body.mode);
- try std.testing.expectEqualStrings("lph\nrav", pardes.test_api.heldSelection(p, 0).?);
+ try std.testing.expectEqualStrings("lpha\nbrav", pardes.test_api.heldSelection(p, 0).?);
}
}
}
@@ -1253,9 +1258,42 @@ const JumpSelectionTests = struct {
try std.testing.expectEqual(@as(i32, 0), pane.body.cur_col);
}
- test "jump selection clears copied rectangles in both history directions" {
+ test "a B1 sweep over several lines is a stream, as acme's, in a body and a tag" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 60, .rows = 12 });
+ defer p.deinit();
+ const pane = try p.setTestFile("alpha\nbravo\ncharlie\n");
+ var frame = std.heap.ArenaAllocator.init(p.gpa);
+ defer frame.deinit();
+ _ = try p.render(frame.allocator());
+ const rect = p.rects[0];
+ const x = rect.x + config.GUTTER + panes.File.gutterWidth(pane);
+ const y = p.bodyTop(pane, rect);
+ // From the press to the end of its line, the line between whole, the
+ // last from its start: no line numbers, no rectangle.
+ drag(p, x + 2, y, x + 1, y + 2);
+ try std.testing.expectEqualStrings("pha\nbravo\nch", pardes.test_api.heldSelection(p, 0).?);
+ // Upward, the same text.
+ drag(p, x + 1, y + 2, x + 2, y);
+ try std.testing.expectEqualStrings("pha\nbravo\nch", pardes.test_api.heldSelection(p, 0).?);
+ // A tag of several rows sweeps the same way.
+ if (pane.tag.own) |own| p.gpa.free(own);
+ pane.tag.own = try p.gpa.dupe(u8, "Save Del\nLook Edit");
+ p.sync();
+ _ = try p.render(frame.allocator());
+ p.sync();
+ try std.testing.expectEqual(@as(u16, 2), pane.tag_rows);
+ const sl: panes.Pane.Sel = .{ .state = .done, .r0 = 0, .c0 = 3, .r1 = 1, .c1 = 1 };
+ const text = try pardes.edit.paneText(p, pane);
+ const swept = try pardes.edit.selectionText(p, pane, sl);
+ const first_line = text[0 .. std.mem.indexOfScalar(u8, text, '\n') orelse text.len];
+ const second = std.mem.sliceTo(text[first_line.len + 1 ..], '\n');
+ const want = try std.fmt.allocPrint(frame.allocator(), "{s}\n{s}", .{ first_line[3..], second[0..@min(2, second.len)] });
+ try std.testing.expectEqualStrings(want, swept);
+ }
+
+ test "jump selection clears copied sweeps in both history directions" {
for ([_]bool{ false, true }) |reverse|
- try exercise("alpha\nbravo\n", false, reverse, 1, 3, "lph\nrav");
+ try exercise("alpha\nbravo\n", false, reverse, 1, 3, "lpha\nbrav");
}
test "jump selection clears wrapped Unicode and tab rectangles" {
diff --git a/test/snapshots/exec-bigdrag.golden b/test/snapshots/exec-bigdrag.golden
index 87d3b9bb..c74fd8f9 100644
--- a/test/snapshots/exec-bigdrag.golden
+++ b/test/snapshots/exec-bigdrag.golden
@@ -2,60 +2,60 @@
|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Exit
| New Tty Find Grep Joincol Delcol New Tty Find Grep Joincol Delcol
| /tmp/pardes-snap/exec-bigdrag/cwd Tty+bash Save Mode Filter Collapse Del /tmp/pardes-snap/exec-bigdrag/cwd Tty+bash Save Mode Filter Collapse Del
-| ls bash: line: command not found
-| big.txt 4line 2705line 2706line 2707line 2708line 2709line 2710line 2711line 2712line 2713line 2714lin
-| bash: 4line: command not found
-| 15line 2716line 2717line 2718line 2719line 2720line 2721line 2722line 2723line 2724line 2725li
-| bash: 15line: command not found
-| 726line 2727line 2728line 2729line 2730line 2731line 2732line 2733line 2734line 2735line 2736l
-| bash: 726line: command not found
-| 2737line 2738line 2739line 2740line 2741line 2742line 2743line 2744line 2745line 2746line 2747
-| bash: 2737line: command not found
-| 2748line 2749line 2750line 2751line 2752line 2753line 2754line 2755line 2756line 2757line 275
-| bash: 2748line: command not found
-| e 2759line 2760line 2761line 2762line 2763line 2764line 2765line 2766line 2767line 2768line 27
+| ls 2
+| big.txt bash: 91line: command not found
+| 802line 2803line 2804line 2805line 2806line 2807line 2808line 2809line 2810line 2811line 2812lin
+| e
+| bash: 802line: command not found
+| 2813line 2814line 2815line 2816line 2817line 2818line 2819line 2820line 2821line 2822line 2823li
+| ne
+| bash: 2813line: command not found
+| 2824line 2825line 2826line 2827line 2828line 2829line 2830line 2831line 2832line 2833line 2834l
+| in
+| bash: 2824line: command not found
+| e 2835line 2836line 2837line 2838line 2839line 2840line 2841line 2842line 2843line 2844line 2845
+| li
| bash: e: command not found
-| ne 2770line 2771line 2772line 2773line 2774line 2775line 2776line 2777line 2778line 2779line 2
+| ne 2846line 2847line 2848line 2849line 2850line 2851line 2852line 2853line 2854line 2855line 285
+| 6l
| bash: ne: command not found
-| ine 2781line 2782line 2783line 2784line 2785line 2786line 2787line 2788line 2789line 2790line
+| ine 2857line 2858line 2859line 2860line 2861line 2862line 2863line 2864line 2865line 2866line 28
+| 67
| bash: ine: command not found
-| line 2792line 2793line 2794line 2795line 2796line 2797line 2798line 2799line 2800line 2801line
+| line 2868line 2869line 2870line 2871line 2872line 2873line 2874line 2875line 2876line 2877line 2
+| 87
| bash: line: command not found
-| 2line 2803line 2804line 2805line 2806line 2807line 2808line 2809line 2810line 2811line 2812lin
-| bash: 2line: command not found
-| 13line 2814line 2815line 2816line 2817line 2818line 2819line 2820line 2821line 2822line 2823li
-| bash: 13line: command not found
-| 824line 2825line 2826line 2827line 2828line 2829line 2830line 2831line 2832line 2833line 2834l
-| bash: 824line: command not found
-| 2835line 2836line 2837line 2838line 2839line 2840line 2841line 2842line 2843line 2844line 2845
-| bash: 2835line: command not found
-| 2846line 2847line 2848line 2849line 2850line 2851line 2852line 2853line 2854line 2855line 285
-| bash: 2846line: command not found
-| /tmp/pardes-snap/exec-bigdrag/cwd Tty+bash Save Mode Filter Collapse Del e 2857line 2858line 2859line 2860line 2861line 2862line 2863line 2864line 2865line 2866line 28
-| ls bash: e: command not found
-| big.txt ne 2868line 2869line 2870line 2871line 2872line 2873line 2874line 2875line 2876line 2877line 2
-| bash: ne: command not found
-| ine 2879line 2880line 2881line 2882line 2883line 2884line 2885line 2886line 2887line 2888line
-| bash: ine: command not found
-| liecho alive-o''kne 2890line 2891line 2892line 2893line 2894line 2895line 2896line 2897line 2898li
-| bash: line: command not found
-| 0line 2901line 2902line 2903line 2904line 2905line 2906line 2907line 2908line 2909line 2910lin
-| bash: 0line: command not found
-| 11line 2912line 2913line 2914line 2915line 2916line 2917line 2918line 2919line 2920line 2921li
-| bash: 11line: command not found
-| 922line 2923line 2924line 2925line 2926line 2927line 2928line 2929line 2930line 2931line 2932l
-| bash: 922line: command not found
-| 2933line 2934line 2935line 2936line 2937line 2938line 2939line 2940line 2941line 2942line 2943
-| bash: 2933line: command not found
-| 2944line 2945line 2946line 2947line 2948line 2949line 2950line 2951line 2952line 2953line 295
-| bash: 2944line: command not found
-| e 2955line 2956line 2957line 2958line 2959line 2960line 2961line 2962line 2963line 2964line 29
+| 8line 2879line 2880line 2881line 2882line 2883line 2884line 2885line 2886line 2887line 2888line
+| 28
+| bash: 8line: command not found
+| 89line 2890line 2891line 2892line 2893line 2894line 2895line 2896line 2897line 2898line 2899line
+| 2
+| bash: 89line: command not found
+| /tmp/pardes-snap/exec-bigdrag/cwd Tty+bash Save Mode Filter Collapse Del 900line 2901line 2902line 2903line 2904line 2905line 2906line 2907line 2908line 2909line 2910lin
+| ls e
+| big.txt bash: 900line: command not found
+| 2911line 2912line 2913line 2914line 2915line 2916line 2917line 2918line 2919line 2920line 2921li
+| ne
+| bash: 2911line: command not found
+| 2echo alive-o''k922line 2923line 2924line 2925line 2926line 2927line 2928line 2929line 2930line 2
+| in
+| bash: 2922line: command not found
+| e 2933line 2934line 2935line 2936line 2937line 2938line 2939line 2940line 2941line 2942line 2943
+| li
| bash: e: command not found
-| ne 2966line 2967line 2968line 2969line 2970line 2971line 2972line 2973line 2974line 2975line 2
+| ne 2944line 2945line 2946line 2947line 2948line 2949line 2950line 2951line 2952line 2953line 295
+| 4l
| bash: ne: command not found
-| ine 2977line 2978line 2979line 2980line 2981line 2982line 2983line 2984line 2985line 2986line
+| ine 2955line 2956line 2957line 2958line 2959line 2960line 2961line 2962line 2963line 2964line 29
+| 65
| bash: ine: command not found
-| line 2988line 2989line 2990line 2991line 2992line 2993line 2994line 2995line 2996line 2997line
+| line 2966line 2967line 2968line 2969line 2970line 2971line 2972line 2973line 2974line 2975line 2
+| 97
| bash: line: command not found
+| 6line 2977line 2978line 2979line 2980line 2981line 2982line 2983line 2984line 2985line 2986line
+| 29
+| bash: 6line: command not found
+| 87line 2988line 2989line 2990line 2991line 2992line 2993line 2994line 2995line 2996line 2997line
+| bash: 87line: command not found
| echo alive-o''k
| alive-ok