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.zig29
1 files changed, 26 insertions, 3 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index f90a83d8..9f85a75f 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -125,7 +125,8 @@ pub fn tagOf(p: *Pardes, pane: *Pane) []const u8 {
pub fn dirtyOf(pane: *const Pane) bool {
const f = if (pane.file) |*x| x else return false;
if (!panes.Output.fileTraits(f.output).saves) return false;
- return f.revision != f.saved_revision;
+ // Its file deleted on disk: the text is only here now, as acme counts it.
+ return f.revision != f.saved_revision or f.disk_gone;
}
/// The pane's name: its file, its document, or a terminal's directory.
@@ -280,6 +281,7 @@ pub fn fileSize(p: *Pardes, id: usize, f: PaneFile) u64 {
.pty_status => pty.status_len,
.pty_ctl => pty_ctl: {
var buf: [32]u8 = undefined;
+ // unreachable: two u16s and 9 bytes fit 32
break :pty_ctl (std.fmt.bufPrint(&buf, "winsize {d} {d}\n", .{ pane.cols, pane.rows }) catch unreachable).len;
},
.pty_data => if (pf.pty_out.peek()) |chunk| chunk.len else 0,
@@ -303,9 +305,11 @@ pub fn indexLen(p: *Pardes) u64 {
last = serial;
const pane = p.panes[p.paneBySerial(serial).?].?;
var digits: [16]u8 = undefined;
+ // unreachable: a u32 serial is at most 10 digits
n += (std.fmt.bufPrint(&digits, "{d}", .{serial}) catch unreachable).len;
var name_buf: [4 * 4096]u8 = undefined;
n += 1 + kindOf(pane).len + 3 + events.shown(nameOf(pane), &name_buf).len + 1;
+ // unreachable: a column index is under 16 digits
n += 1 + (std.fmt.bufPrint(&digits, "{d}", .{columnOf(p, p.paneBySerial(serial).?)}) catch unreachable).len;
}
return n;
@@ -665,7 +669,8 @@ fn nameFault(name: []const u8) ?[]const u8 {
while (std.mem.indexOfScalarPos(u8, name, i, 0xC2)) |at| : (i = at + 1)
if (at + 1 < name.len and name[at + 1] <= 0x9F) return e_name_char ++ ": a control character";
}
- if (name[0] == ' ' or name[name.len - 1] == ' ') return e_name_char ++ ": a blank at its end";
+ if (name[0] == ' ') return e_name_char ++ ": a blank at its start";
+ if (name[name.len - 1] == ' ') return e_name_char ++ ": a blank at its end";
return null;
}
@@ -1123,6 +1128,24 @@ test "after a failed address, one that goes from it says there is none" {
try testing.expectEqual(Status.ok, wr(p, addr, ".").reply.status);
}
+test "a write of two lines to name is refused EINVAL, on a held open or not" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const node = Node.of(serial, .name);
+ try testing.expectEqual(E.INVAL, wr(p, node, "/tmp/a\n/tmp/b\n").errno());
+ const h = call(p, .{ .tag = 1, .op = .open, .node = node, .omode = 1 }).reply.handle;
+ try testing.expectEqual(E.INVAL, call(p, .{ .tag = 2, .op = .write, .node = node, .handle = h, .data = "/tmp/a\n/tmp/b\n" }).errno());
+ _ = call(p, .{ .tag = 3, .op = .release, .node = node, .handle = h, .opened = true });
+ try testing.expectEqualStrings("/test.txt", nameOf(p.panes[p.paneBySerial(serial).?].?));
+ // Line by line, as bash writes it: the second line is refused.
+ const h2 = call(p, .{ .tag = 1, .op = .open, .node = node, .omode = 1 }).reply.handle;
+ try testing.expectEqual(Status.ok, call(p, .{ .tag = 2, .op = .write, .node = node, .handle = h2, .data = "/tmp/pardes-a\n" }).reply.status);
+ try testing.expectEqual(E.INVAL, call(p, .{ .tag = 2, .op = .write, .node = node, .handle = h2, .data = "/tmp/pardes-b\n" }).errno());
+ _ = call(p, .{ .tag = 3, .op = .release, .node = node, .handle = h2, .opened = true });
+ try testing.expectEqualStrings("/tmp/pardes-a", nameOf(p.panes[p.paneBySerial(serial).?].?));
+}
+
test "a name cut across writes is one name, applied once at its newline or its close" {
const p = try withFile(testing.allocator, "x\n");
defer p.deinit();
@@ -1252,7 +1275,7 @@ test "name reads the file name and writing it promotes a scratch without touchin
// off), a second line, a control byte, DEL, a C1 control, not UTF-8.
for ([_][2][]const u8{
.{ "trailing.zig \n", "a blank at its end" },
- .{ " leading.zig\n", "a blank at its end" },
+ .{ " leading.zig\n", "a blank at its start" },
.{ "tab\t.zig\n", "a control character" },
.{ "two\nlines\n", "a newline" },
.{ "del\x7f.zig\n", "a control character" },