summaryrefslogtreecommitdiff
path: root/src/ninep/pane.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/pane.zig')
-rw-r--r--src/ninep/pane.zig34
1 files changed, 29 insertions, 5 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index 0a511118..d2b2a791 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -194,6 +194,20 @@ pub fn spliceBody(p: *Pardes, pane: *Pane, q0: usize, q1: usize, bytes: []const
return take;
}
+test "a terminal's body stats as long as it reads" {
+ const gpa = testing.allocator;
+ const p = try pardes.Pardes.init(gpa, .{ .tty_only = true, .cols = 80, .rows = 24 });
+ defer p.deinit();
+ while (p.nextEffect()) |_| {}
+ const pane = p.panes[0].?;
+ try testing.expect(pane.isTerminal());
+ p.update(.{ .output = .{ .pane = 0, .bytes = "$ ls\r\nalpha beta\r\n$ " } });
+ const body = Node.of(pane.serial, .body);
+ const whole = rd(p, body, 0, 1 << 16);
+ try testing.expect(whole.bytes.len > 0);
+ try testing.expectEqual(@as(u64, whole.bytes.len), call(p, .{ .tag = 1, .op = .getattr, .node = body }).reply.attr.size);
+}
+
// ---- what stat reports ----
/// A range file's text: acme's addr format, two right-aligned offsets, so
@@ -204,7 +218,9 @@ pub fn fileSize(p: *Pardes, id: usize, f: PaneFile) u64 {
const pane = p.panes[id] orelse return 0;
const pf = &pane.fs;
return switch (f) {
- .body, .data, .xdata => bodyOf(pane).len,
+ // A terminal's body reads its screen and history, as text.
+ .body => if (pane.file == null and pane.isTerminal()) panes.Terminal.screenTextLen(pane) else bodyOf(pane).len,
+ .data, .xdata => bodyOf(pane).len,
.tag => tagOf(p, pane).len,
.name => nameOf(pane).len + 1,
.ctl => ctl: {
@@ -453,16 +469,22 @@ pub const e_addr_failed = "no address: the last one written to addr failed";
/// A range file takes an address expression, or that pair of offsets. One
/// that does not evaluate says why: `bad address syntax`, `no match for
-/// regexp`, `address out of range`, `bad regular expression`.
+/// regexp`, `address out of range`, `bad regular expression`, `addresses
+/// out of order`.
fn writeRange(req: Req, pane: *Pane, file: PaneFile) Reply {
const pf = &pane.fs;
const text = bodyOf(pane);
clampAddr(pf, text.len);
const expr = std.mem.trimEnd(u8, req.data, "\n");
var a: addressing.Addr = .{ .text = text, .lim = pf.limit, .expr = expr };
- const r = if (pairOf(expr)) |pair|
+ var r = if (pairOf(expr)) |pair|
State.Range{ .q0 = @min(pair.q0, clip(text.len)), .q1 = @min(pair.q1, clip(text.len)) }
else if (a.address(pf.addr)) |found| (if (a.i < expr.len) null else found) else null;
+ // sam's check, which acme leaves out: `#100,#50` names no range.
+ if (r) |found| if (found.q0 > found.q1) {
+ a.err = addressing.e_order;
+ r = null;
+ };
const range = r orelse {
if (file == .addr) pf.addr_failed = true;
return tree.failText(req.tag, E.INVAL, a.err);
@@ -485,7 +507,7 @@ fn writeRange(req: Req, pane: *Pane, file: PaneFile) Reply {
fn writeFlag(p: *Pardes, req: Req, pane: *Pane, file: PaneFile) Reply {
const word = std.mem.trim(u8, req.data, " \t\r\n");
- if (!std.mem.eql(u8, word, "1") and !std.mem.eql(u8, word, "0")) return Reply.fail(req.tag, E.INVAL);
+ if (!std.mem.eql(u8, word, "1") and !std.mem.eql(u8, word, "0")) return tree.failText(req.tag, E.INVAL, "takes 1 or 0");
const on = word[0] == '1';
const pf = &pane.fs;
switch (file) {
@@ -851,8 +873,10 @@ test "the flag files read and write the state acme kept behind ctl verbs" {
for ([_]u64{ dirty, mark, scroll }) |node| {
try testing.expectEqual(@as(u64, 2), call(p, .{ .tag = 1, .op = .getattr, .node = node }).reply.attr.size);
- for ([_][]const u8{ "", "yes", "2", "0 1", "true" }) |bad|
+ for ([_][]const u8{ "", "yes", "2", "0 1", "true" }) |bad| {
try testing.expectEqual(E.INVAL, wr(p, node, bad).errno());
+ try testing.expectEqualStrings("takes 1 or 0", wr(p, node, bad).reply.ename);
+ }
}
try testing.expectEqualStrings("0\n", rd(p, dirty, 0, 8).bytes);