summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.agents/skills/pardes-9p/SKILL.md4
-rw-r--r--docs/fs.md4
-rw-r--r--src/builtins.zig17
3 files changed, 15 insertions, 10 deletions
diff --git a/.agents/skills/pardes-9p/SKILL.md b/.agents/skills/pardes-9p/SKILL.md
index e031f436..77acade3 100644
--- a/.agents/skills/pardes-9p/SKILL.md
+++ b/.agents/skills/pardes-9p/SKILL.md
@@ -59,7 +59,9 @@ $m/focus the serial of the pane with the keyboard (empty while a column/wor
echo a serial into it to move the keyboard (a folded pane stays folded)
$m/ctl the settings, one a line as a write takes them; write a setting or a session builtin
(Newcol, Dump, Theme x; Exit QUITS the editor, Kill [word...] stops the
- commands pardes typed into terminals); a pane's builtins (Del, Save f,
+ commands pardes typed into terminals; Exit and Restore refuse once per
+ unsaved pane, `<name>: Modified (Exit again to discard)`, and the same
+ word again DISCARDS that text -- not a retry, unlike lock's `file in use`); a pane's builtins (Del, Save f,
and the column words Delcol, Collapse, which act on that pane's column) go to
$m/pane/<n>/ctl
$m/commands every builtin: `Word`, `Word arg`, then `root` or `pane` (which ctl takes it)
diff --git a/docs/fs.md b/docs/fs.md
index 2507ac93..c9b268b0 100644
--- a/docs/fs.md
+++ b/docs/fs.md
@@ -105,8 +105,8 @@ every setting is one, the rest act on a pane). `/ctl` takes the session's
builtins, one a line, at whichever pane has the keyboard as each runs --
`Newcol`, `Dump`, `Mount name dial`, `Theme ink`, `Verbose off`; `Exit`,
which quits the editor as acme's does (it refuses once, naming each pane with
-unsaved text, `<name>: Modified`, and a second `Exit` with nothing edited
-since quits; a scratch under 100 bytes is not asked about; `Restore`, which
+unsaved text, `<name>: Modified (Exit again to discard)`, and a second
+`Exit` with nothing edited since quits, throwing that text away; a scratch under 100 bytes is not asked about; `Restore`, which
replaces every pane, asks the same first); and `Kill`, which
does not quit but stops commands, as acme's does: bare, every command pardes
started, and `Kill make ls`, those whose line begins with one of the words. A
diff --git a/src/builtins.zig b/src/builtins.zig
index 88c65704..6bfc9b26 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -220,7 +220,7 @@ test "Exit asks once about unsaved text, and quits when asked again" {
pane.file.?.saved_revision = pane.file.?.revision -% 1; // modified
try std.testing.expect(p.executeBuiltinLine(p.active, "Exit"));
try std.testing.expect(!p.quit);
- try std.testing.expect(std.mem.endsWith(u8, pane.msg[0..pane.msg_len], ": Modified"));
+ try std.testing.expect(std.mem.endsWith(u8, pane.msg[0..pane.msg_len], ": Modified (Exit again to discard)"));
// Told once, and nothing edited since: the second Exit quits.
try std.testing.expect(p.executeBuiltinLine(p.active, "Exit"));
try std.testing.expect(p.quit);
@@ -233,7 +233,7 @@ test "Restore asks about unsaved text as Exit does, and restores when asked agai
pane.file.?.saved_revision = pane.file.?.revision -% 1; // modified
try std.testing.expect(p.executeBuiltinLine(p.active, "Restore /tmp/some.dump.zon"));
try std.testing.expect(p.restore_req == null);
- try std.testing.expect(std.mem.endsWith(u8, pane.msg[0..pane.msg_len], ": Modified"));
+ try std.testing.expect(std.mem.endsWith(u8, pane.msg[0..pane.msg_len], ": Modified (Restore again to discard)"));
try std.testing.expect(p.executeBuiltinLine(p.active, "Restore /tmp/some.dump.zon"));
try std.testing.expectEqualStrings("/tmp/some.dump.zon", p.restore_req.?);
}
@@ -354,11 +354,13 @@ pub const Exec = struct {
/// acme's rowclean (editors/acme/wind.c:511-529, winclean), asked before
/// what would throw unsaved text away: each pane holding some nobody has
-/// been told about says so, `<name>: Modified`, and is then clean for the
+/// been told about says so, `<name>: Modified (Exit again to discard)`,
+/// naming the word asking, since repeating it throws the text away, and is
+/// then clean for the
/// asking, as winclean clears `dirty`; so the same word again, with
/// nothing edited since, goes ahead. A scratch of under 100 bytes is no
/// loss worth the question, as winclean does not ask for one.
-fn warnModified(c: Ctx) bool {
+fn warnModified(c: Ctx, asking: []const u8) bool {
var modified = false;
for (c.p.panes, 0..) |slot, id| {
const pane = slot orelse continue;
@@ -367,7 +369,8 @@ fn warnModified(c: Ctx) bool {
if (f.output != null and f.content.len < 100) continue;
if (pane.discard_warned == f.revision) continue;
pane.discard_warned = f.revision;
- c.p.reportError(id, f.path, error.Modified);
+ var buf: [limits.host_path_cap + 48]u8 = undefined;
+ c.p.reportFailure(id, std.fmt.bufPrint(&buf, "{s}: Modified ({s} again to discard)", .{ f.path, asking }) catch f.path);
modified = true;
}
return modified;
@@ -378,7 +381,7 @@ fn warnModified(c: Ctx) bool {
pub const Exit = struct {
pub const scope: Scope = .session;
pub fn run(c: Ctx) void {
- if (warnModified(c)) return;
+ if (warnModified(c, "Exit")) return;
c.p.quit = true;
c.p.emit(.quit);
}
@@ -433,7 +436,7 @@ pub const Restore = struct {
if (path.len > c.p.restore_buf.len) return;
// acme's Load adds a dump's windows to the ones there; a Restore
// replaces them all, so it asks what Exit asks first.
- if (warnModified(c)) return;
+ if (warnModified(c, "Restore")) return;
@memcpy(c.p.restore_buf[0..path.len], path);
c.p.restore_req = c.p.restore_buf[0..path.len];
}