diff options
Diffstat (limited to 'src/ninep/ctl.zig')
| -rw-r--r-- | src/ninep/ctl.zig | 62 |
1 files changed, 58 insertions, 4 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 1f0195d0..307921b9 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -563,9 +563,8 @@ fn summaryOf(word: []const u8, buf: []u8) []const u8 { if (w.buffered().len > 0) w.writeByte(' ') catch break; w.writeAll(text) catch break; } - const all = w.buffered(); - // The first sentence, whole: to a `.` that ends one, or the whole cut - // between words. + const all = stripCitations(w.buffered()); + // The first sentence, whole: to a `.` that ends one. var i: usize = 0; while (std.mem.indexOfScalarPos(u8, all, i, '.')) |dot| : (i = dot + 1) { if (dot + 1 == all.len or all[dot + 1] == ' ') return all[0 .. dot + 1]; @@ -573,6 +572,29 @@ fn summaryOf(word: []const u8, buf: []u8) []const u8 { return all; } +/// Drops a parenthesis that cites source (`(editors/acme/exec.c:892)`, +/// `(exec.c, \`kill\`; acme.c's WKill)`): a reader of /commands wants what +/// the word does, not where acme has it. In place; answers the rest. +fn stripCitations(text: []u8) []u8 { + var out: usize = 0; + var i: usize = 0; + while (i < text.len) { + if (text[i] == '(') if (std.mem.indexOfScalarPos(u8, text, i, ')')) |close| { + const inside = text[i + 1 .. close]; + if (std.mem.indexOf(u8, inside, ".c") != null or std.mem.indexOf(u8, inside, ".zig") != null) { + // With the space before it, and a colon after it kept. + if (out > 0 and text[out - 1] == ' ') out -= 1; + i = close + 1; + continue; + } + }; + text[out] = text[i]; + out += 1; + i += 1; + } + return text[0..out]; +} + fn writeCommands(w: *std.Io.Writer) !void { for (std.enums.values(Builtin)) |b| { // Edit is a pane's word the root's ctl takes too, at the active pane. @@ -593,7 +615,11 @@ fn writeCommands(w: *std.Io.Writer) !void { // Then ` -- ` and what it does, when its source says. var summary_buf: [2048]u8 = undefined; const summary = summaryOf(@tagName(b), &summary_buf); - if (summary.len > 0) try w.print(" -- {s}", .{@import("../Messages.zig").clip(summary, 160)}); + if (summary.len > 0) { + // The sentence whole unless it is long, then cut between words. + const kept = @import("../Messages.zig").clip(summary, 240); + try w.print(" -- {s}{s}", .{ kept, if (kept.len < summary.len) "…" else "" }); + } try w.writeByte('\n'); } } @@ -1667,3 +1693,31 @@ test "a looked word is found in its own pane, next place after the dot, wrapping for (p.panes) |slot| after += @intFromBool(slot != null); try testing.expect(after > count); } + +test "each word's /commands description is its own doc comment's first sentence, no citation" { + const p = try withFile(testing.allocator, "x\n"); + defer p.deinit(); + const listed = rd(p, @intFromEnum(tree.TopFile.commands), 0, 1 << 16).bytes; + for ([_][]const u8{ + "\nRepl arg pane -- Binds this terminal as a language's REPL", + "\nJoincol root -- Fold the active pane's column into the one on its right, keeping its panes.\n", + "\nExit root -- acme's Exit: quit, once warnModified has nothing to say.\n", + "\nKill arg root -- acme's Kill: stop the commands pardes started", + }) |row| try testing.expect(std.mem.indexOf(u8, listed, row) != null); + try testing.expect(std.mem.indexOf(u8, listed, ".c:") == null); + // Every description is the first sentence of the doc comment just + // above its word's declaration in builtins.zig. + const source = @embedFile("../builtins.zig"); + var it = std.mem.tokenizeScalar(u8, listed, '\n'); + while (it.next()) |line| { + const dashes = std.mem.indexOf(u8, line, " -- ") orelse continue; + const word = line[0 .. std.mem.indexOfScalar(u8, line, ' ').?]; + var needle: [64]u8 = undefined; + const at = std.mem.indexOf(u8, source, try std.fmt.bufPrint(&needle, "\npub const {s} = struct", .{word})).?; + const said = std.mem.trimEnd(u8, line[dashes + 4 ..], "…"); + // Its opening words are in the comment block right above. + const head = said[0..@min(said.len, 10)]; + const block_start = std.mem.lastIndexOf(u8, source[0..at], "\n\n") orelse 0; + try testing.expect(std.mem.indexOf(u8, source[block_start..at], head) != null); + } +} |
