diff options
| -rw-r--r-- | docs/tags.md | 6 | ||||
| -rw-r--r-- | src/builtins.zig | 21 | ||||
| -rw-r--r-- | src/ninep/ctl.zig | 9 |
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); +} |
