summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/tags.md6
-rw-r--r--src/builtins.zig21
-rw-r--r--src/ninep/ctl.zig9
3 files changed, 32 insertions, 4 deletions
diff --git a/docs/tags.md b/docs/tags.md
index a113d86a..2cd3f16b 100644
--- a/docs/tags.md
+++ b/docs/tags.md
@@ -19,7 +19,11 @@ one, since other arguments (a dump's name) may contain `+`. A command pane's tag
and offers `Kill`. `Repl python` in a terminal's tag binds it as Python's
REPL, its id, `python-a`, beside the Tty word: a middle click or the execute
key on a `.py` body then types the text into it rather than running it, and
-several bound ask which. The tag's own words, `Exec <text>` by name and a
+several bound ask which. `Repl` takes any language a code fence names
+(`py`, `Python`, `sh`): ada, bash, c, c_sharp, clojure, cpp, css, elixir,
+erlang, fortran, go, haskell, html, java, javascript, json, kotlin, ocaml,
+markdown, pascal, php, powershell, python, ruby, rust, scala, typst, zig;
+an unknown one is refused, naming a few of these. The tag's own words, `Exec <text>` by name and a
command word @`cmd` still run as commands (docs/fs.md).
A tag word runs as acme's does, in the pane's directory with no file named:
`wc` alone waits on its stdin. pardes has no `$%` for the pane's file; name
diff --git a/src/builtins.zig b/src/builtins.zig
index 87a4d022..4490482d 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -1075,10 +1075,25 @@ pub const Repl = struct {
// Named as a code fence names it: `py`, `Python`, `sh`.
const named: ?u8 = if (manifest.byName(arg)) |i| if (grammars[i].exts.len > 0) @intCast(i) else null else null;
const lang: u8 = named orelse {
+ // A few, whole, and where the rest are: a list cut to fit the
+ // row would end mid-word.
var w = std.Io.Writer.fixed(&buf);
- w.print("Repl: no language \"{s}\"; - or one of:", .{@import("Messages.zig").clip(arg, 24)}) catch {};
- for (grammars) |g| if (g.exts.len > 0) w.print(" {s}", .{g.name}) catch break;
- return c.p.reportFailure(c.id, @import("Messages.zig").clip(w.buffered(), 256));
+ w.print("Repl: no language \"{s}\"; - or one like", .{@import("Messages.zig").clip(arg, 24)}) catch {};
+ // Those that start as the word does first, a misspelling's
+ // likeliest meaning (pithon: python).
+ var shown: usize = 0;
+ var known: usize = 0;
+ for ([2]bool{ true, false }) |alike| for (grammars) |g| if (g.exts.len > 0) {
+ const starts = arg.len > 0 and g.name[0] == std.ascii.toLower(arg[0]);
+ if (starts != alike) continue;
+ known += 1;
+ if (shown < 6) {
+ w.print(" {s}", .{g.name}) catch {};
+ shown += 1;
+ }
+ };
+ w.print(" ({d} more: docs/tags.md, Repl)", .{known - shown}) catch {};
+ return c.p.reportFailure(c.id, w.buffered());
};
if (pane.repl) |r| if (r.lang == lang)
return c.p.setMessage(c.id, std.fmt.bufPrint(&buf, "Repl: {s}", .{exec.replId(&idbuf, pane)}) catch "Repl");
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index dd382290..5921198e 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -1514,3 +1514,12 @@ test "size sets the screen of a session no frontend is attached to, and only of
try testing.expect(std.mem.indexOf(u8, wr(p, root_ctl, "size 80 8\n").reply.ename, "too small for the panes") != null);
try testing.expectEqual(@as(u16, 40), p.screen_h);
}
+
+test "Repl with no such language names a few whole, and where the rest are" {
+ const p = try th.withTerm(testing.allocator);
+ defer p.deinit();
+ const refused = wr(p, Node.of(serialOf(p), .ctl), "Repl zzlang\n");
+ try testing.expectEqual(Status.err, refused.reply.status);
+ try testing.expect(std.mem.indexOf(u8, refused.reply.ename, "Repl: no language \"zzlang\"; - or one like zig ada bash c c_sharp clojure (") != null);
+ try testing.expect(std.mem.indexOf(u8, refused.reply.ename, " more: docs/tags.md, Repl)") != null);
+}