summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index b64b62d7..8c643be6 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -5841,6 +5841,17 @@ pub const Options = struct {
/// not consulted at all (it never was — the file arm always won).
file: ?[]const u8 = null,
file_line: usize = 0,
+ /// argv NAMED SOMETHING THAT IS NOT THERE — no file, no directory, nothing
+ /// `look.resolve` could make a target of. The word as the human typed it,
+ /// and it boots one `+Errors` pane saying so.
+ ///
+ /// A launch is not a failure worth refusing. `pardes nosuchfile` used to
+ /// return `BadArgs` out of `main`, which std prints as `error: BadArgs`
+ /// with a return trace under it — indistinguishable from a crash for a
+ /// typo, and it left the human with no editor at all. Outranked by `file`
+ /// for the same reason `file` outranks `shells`: only one of them can name
+ /// the boot layout, and they are never both set.
+ missing_path: ?[]const u8 = null,
tty_toggle: u21 = config.tty_toggle_default,
/// load a dump of another instance instead of spawning shells (acme -l)
load_path: ?[]const u8 = null,
@@ -6322,6 +6333,28 @@ pub const Pardes = struct {
p.ncol = 1;
p.col_n[0] = 1;
p.col_terms[0][0] = 0;
+ } else if (opts.missing_path) |word| {
+ // ARGV NAMED NOTHING. `+Errors` and not the message row, because a
+ // launch has no pane to put a message row on yet — and because
+ // this is exactly what acme's `+Errors` is: output from the
+ // program rather than from a word anybody clicked (output_pane
+ // `Origin.errors`). Filling the window with it makes the answer
+ // unmissable, which a one-line message under a shell prompt is
+ // not.
+ //
+ // The word AS TYPED, not a resolved path: there is nothing to
+ // resolve, and `pardes ~/notes/tdoo.md` wants to see its own typo
+ // back rather than an absolute path built around it.
+ const content = try std.fmt.allocPrint(
+ gpa,
+ "file or directory not found\n\n\t{s}\n",
+ .{word},
+ );
+ errdefer gpa.free(content);
+ _ = try output_pane.open(p, 0, "", .errors, "", content);
+ p.ncol = 1;
+ p.col_n[0] = 1;
+ p.col_terms[0][0] = 0;
} else if (comptime platform == .esp32p4) {
// BARE METAL BOOTS AN EMPTY OUTPUT BUFFER, and a shell is not a layout preference
// here but an impossibility: there is no operating system under this, so there is
@@ -16419,6 +16452,26 @@ test "Esc alternates between two panes of the SAME kind" {
}
}
+test "argv naming nothing boots an errors pane rather than failing the launch" {
+ const gpa = std.testing.allocator;
+ const p = try Pardes.init(gpa, .{ .cols = 80, .rows = 24, .missing_path = "notes/tdoo.md" });
+ defer p.deinit();
+ p.update(.{ .resize = .{ .cols = 80, .rows = 24 } });
+
+ // One pane, filling the window, and it is an OUTPUT pane rather than the
+ // shell a bare `pardes` boots: the answer is the whole screen.
+ try std.testing.expectEqual(@as(u8, 1), p.ncol);
+ try std.testing.expectEqual(@as(usize, 1), p.col_n[0]);
+ const pane = p.panes[0].?;
+ try std.testing.expect(!pane.isTerminal());
+ const f = pane.file.?;
+ try std.testing.expectEqual(output_pane.Origin.errors, f.output.?.from);
+ // ...and it says what happened AND what was asked for. The word as typed,
+ // which is the half a bare "not found" leaves out.
+ try std.testing.expect(std.mem.indexOf(u8, f.content, "not found") != null);
+ try std.testing.expect(std.mem.indexOf(u8, f.content, "notes/tdoo.md") != null);
+}
+
test "Esc back into a tty leaves its view at the prompt" {
if (platform == .web) return;
const gpa = std.testing.allocator;