summaryrefslogtreecommitdiff
path: root/src/output_pane.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/output_pane.zig')
-rw-r--r--src/output_pane.zig57
1 files changed, 46 insertions, 11 deletions
diff --git a/src/output_pane.zig b/src/output_pane.zig
index 9021e479..1850fa92 100644
--- a/src/output_pane.zig
+++ b/src/output_pane.zig
@@ -106,14 +106,22 @@ pub fn traits(o: Origin) Traits {
.hover => .{ .name = config.hover_buffer },
// prose: an action list, a diff, a report about the backend
.code_action, .format, .status, .explain => .{ .name = config.lsp_buffer },
- // Rename responses are edits consumed before an output can open;
- // the exhaustive table still records the otherwise-unused trait.
- .rename => .{ .name = config.lsp_buffer },
+ // Rename usually resolves to edit records the core consumes before
+ // any buffer opens; what RENDERS is the multi-file PREVIEW — one
+ // location row per would-be edit — which n/N step like any list.
+ .rename => .{ .name = config.search_buffer, .steps = true },
.definition, .declaration, .type_definition, .implementation, .references => .{
.name = config.search_buffer,
.steps = true,
.jumps = true,
},
+ // The hierarchy kinds behave like references: a list of places,
+ // and a lone answer (one caller, one subtype) is a jump.
+ .incoming_calls, .outgoing_calls, .supertypes, .subtypes => .{
+ .name = config.search_buffer,
+ .steps = true,
+ .jumps = true,
+ },
// completion lists WHAT COULD GO HERE, one row per candidate's
// definition. It does not jump on a single row where the gotos do:
// a goto answers a question whose answer is a place, so landing
@@ -397,8 +405,25 @@ fn openStepped(p: *Pardes, id: usize, from: Origin, content: []u8) !void {
fn helpContent(gpa: std.mem.Allocator, prefix: []const u8) ![]u8 {
const full_header = "pardes builtins, and how to run each:\nSPC and its keys, a chord, a button, the\ntopbar - or the name, executed anywhere.\n\n";
const group_header = "pardes builtins under SPC";
+ // The LANGUAGE KEYS are the one part of the keymap Help would otherwise
+ // never show: they are motions and modes, not words, so no builtin row
+ // carries them — yet they are the keys a reader comes looking for. Full
+ // listing only; a mid-chord `SPC l` view stays a pure filter.
+ const language_footer =
+ "\nlanguage keys (motions, not words):\n" ++
+ "gd gD gy gi gr goto: definition,\n" ++
+ " declaration, type-def,\n" ++
+ " implementation, refs\n" ++
+ "]d [d ]D [D diagnostics: next,\n" ++
+ " prev, last, first\n" ++
+ "= format (applies, one\n" ++
+ " undo step)\n" ++
+ "Tab after a . completion, in insert\n" ++
+ "C-left-click definition, by mouse\n" ++
+ "SPC l ... hover, rename, symbols,\n" ++
+ " calls, types: above\n";
var len: usize = if (prefix.len == 0)
- full_header.len
+ full_header.len + language_footer.len
else
group_header.len + prefix.len * 2 + 2;
for (pardes.builtin_rows) |row| {
@@ -431,6 +456,10 @@ fn helpContent(gpa: std.mem.Allocator, prefix: []const u8) ![]u8 {
content[at] = '\n';
at += 1;
}
+ if (prefix.len == 0) {
+ @memcpy(content[at..][0..language_footer.len], language_footer);
+ at += language_footer.len;
+ }
std.debug.assert(at == content.len);
return content;
}
@@ -442,22 +471,28 @@ pub fn openHelp(p: *Pardes, id: usize, prefix: []const u8) !void {
return openRead(p, id, .{ .cmd = .Help }, prefix, content);
}
-test "full Help renders every enabled builtin row" {
+test "full Help renders every builtin row, then the language keys" {
const content = try helpContent(std.testing.allocator, "");
defer std.testing.allocator.free(content);
- const body = content[(std.mem.lastIndexOf(u8, content, "\n\n") orelse
+ // FIRST blank line: the end of the header (the footer opens with one too)
+ const body = content[(std.mem.indexOf(u8, content, "\n\n") orelse
return error.MissingHelpHeader) + 2 ..];
var lines = std.mem.splitScalar(u8, body, '\n');
for (pardes.builtin_rows) |row|
try std.testing.expectEqualStrings(row.line, lines.next() orelse
return error.MissingBuiltinHelpRow);
- // The renderer terminates every row with a newline, so only split's empty
- // trailing field may remain. Any extra non-empty field is an unregistered
- // Help row and any missing row already failed in the loop above.
+ // ...and after the last row, the language-keys section: the one part of
+ // the keymap no builtin row can carry, closing the page.
try std.testing.expectEqualStrings("", lines.next() orelse
- return error.MissingHelpTerminator);
- try std.testing.expect(lines.next() == null);
+ return error.MissingLanguageKeys);
+ try std.testing.expectEqualStrings("language keys (motions, not words):", lines.next() orelse
+ return error.MissingLanguageKeys);
+ try std.testing.expect(std.mem.indexOf(u8, body, "\ngd gD gy gi gr goto: definition,\n") != null);
+ // the group view stays a pure filter: no footer under a prefix
+ const group = try helpContent(std.testing.allocator, "l");
+ defer std.testing.allocator.free(group);
+ try std.testing.expect(std.mem.indexOf(u8, group, "language keys") == null);
}
/// The complete live Config report: the generated settings and the host facts