Add LSP hover and signature panels
This commit is contained in:
+96
@@ -160,6 +160,10 @@ pub const Client = struct {
|
||||
if (std.mem.startsWith(u8, line, "lsp_rename ")) return self.openLspWorkspaceEdit("rename", line[11..]);
|
||||
if (std.mem.startsWith(u8, line, "lsp_code_actions ")) return self.openLspCodeActions(line[17..]);
|
||||
if (std.mem.eql(u8, line, "lsp_edit_apply_selected")) return self.applySelectedLspEdit();
|
||||
if (std.mem.startsWith(u8, line, "lsp_hover ")) return self.openLspHover(line[10..]);
|
||||
if (std.mem.startsWith(u8, line, "lsp_signature ")) return self.openLspSignature(line[14..]);
|
||||
if (std.mem.eql(u8, line, "lsp_param_next")) return self.moveLspParameter(.next);
|
||||
if (std.mem.eql(u8, line, "lsp_param_previous")) return self.moveLspParameter(.previous);
|
||||
if (std.mem.startsWith(u8, line, "panel_open ")) return self.applyProtocolCommand(line);
|
||||
if (std.mem.startsWith(u8, line, "list_open ")) return self.applyProtocolCommand(line);
|
||||
if (std.mem.startsWith(u8, line, "list_filter ")) return self.applyProtocolCommand(line);
|
||||
@@ -508,6 +512,31 @@ pub const Client = struct {
|
||||
self.message = null;
|
||||
}
|
||||
|
||||
fn openLspHover(self: *Client, payload: []const u8) !void {
|
||||
const rows = lsp_mod.hoverRowsAlloc(self.allocator, payload, self.viewport.width) catch return Error.ProtocolRejected;
|
||||
defer freeOwnedRows(self.allocator, rows);
|
||||
try self.session.openListPanel("lsp-hover", rows);
|
||||
self.message = null;
|
||||
}
|
||||
|
||||
fn openLspSignature(self: *Client, payload: []const u8) !void {
|
||||
const rows = lsp_mod.signatureRowsAlloc(self.allocator, payload, self.viewport.width) catch return Error.ProtocolRejected;
|
||||
defer freeOwnedRows(self.allocator, rows);
|
||||
try self.session.openListPanel("lsp-signature", rows);
|
||||
self.message = null;
|
||||
}
|
||||
|
||||
fn moveLspParameter(self: *Client, direction: lsp_mod.ParameterDirection) !void {
|
||||
const snap = try self.session.snapshot();
|
||||
const moved = lsp_mod.parameterMoveRowsAlloc(self.allocator, snap.bytes, snap.cursor_byte, direction) catch return Error.ProtocolRejected;
|
||||
defer freeOwnedRows(self.allocator, moved.rows);
|
||||
const bytes = try self.allocator.dupe(u8, snap.bytes);
|
||||
defer self.allocator.free(bytes);
|
||||
try self.session.openFixtureAt(bytes, moved.cursor);
|
||||
try self.session.openListPanel("lsp-parameter", moved.rows);
|
||||
self.message = null;
|
||||
}
|
||||
|
||||
fn jumpCurrentBufferToLspLocation(self: *Client, location: lsp_mod.DiagnosticLocation) !void {
|
||||
const snap = try self.session.snapshot();
|
||||
const bytes = try self.allocator.dupe(u8, snap.bytes);
|
||||
@@ -1858,3 +1887,70 @@ test "adversarial: lsp edit failures do not corrupt current buffer" {
|
||||
const snap = try client.session.snapshot();
|
||||
try std.testing.expectEqualStrings("safe", snap.bytes);
|
||||
}
|
||||
|
||||
test "regular: lsp hover wraps inside narrow viewport" {
|
||||
var client = try Client.init(std.testing.allocator, .{ .width = 32, .height = 7 });
|
||||
defer client.deinit();
|
||||
|
||||
const payload =
|
||||
\\{"jsonrpc":"2.0","id":8,"result":{"contents":{"kind":"markdown","value":"pub fn add(lhs: i32, rhs: i32) i32"}}}
|
||||
;
|
||||
const command = try std.fmt.allocPrint(std.testing.allocator, "lsp_hover {s}", .{payload});
|
||||
defer std.testing.allocator.free(command);
|
||||
try client.handleTraceLine(command);
|
||||
const frame = try client.render(std.testing.allocator);
|
||||
defer std.testing.allocator.free(frame);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp-hover") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp:hover:") != null);
|
||||
try assertLinesFit(frame, 32);
|
||||
}
|
||||
|
||||
test "regular: lsp signature shows active parameter in shared panel" {
|
||||
var client = try Client.init(std.testing.allocator, .{ .width = 64, .height = 7 });
|
||||
defer client.deinit();
|
||||
|
||||
const payload =
|
||||
\\{"jsonrpc":"2.0","id":9,"result":{"activeSignature":0,"activeParameter":1,"signatures":[{"label":"add(lhs: i32, rhs: i32)","parameters":[{"label":"lhs: i32"},{"label":"rhs: i32"}]}]}}
|
||||
;
|
||||
const command = try std.fmt.allocPrint(std.testing.allocator, "lsp_signature {s}", .{payload});
|
||||
defer std.testing.allocator.free(command);
|
||||
try client.handleTraceLine(command);
|
||||
const frame = try client.render(std.testing.allocator);
|
||||
defer std.testing.allocator.free(frame);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp-signature") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp:signature:active_2") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp:signature:param_2:active") != null);
|
||||
}
|
||||
|
||||
test "regular: lsp parameter movement updates cursor and reports active parameter" {
|
||||
var client = try Client.init(std.testing.allocator, .{ .width = 72, .height = 6 });
|
||||
defer client.deinit();
|
||||
|
||||
try client.session.openFixtureAt("add(alpha, beta, gamma)", 5);
|
||||
try client.handleTraceLine("lsp_param_next");
|
||||
var snap = try client.session.snapshot();
|
||||
try std.testing.expectEqual(@as(usize, 11), snap.cursor_byte);
|
||||
{
|
||||
const frame = try client.render(std.testing.allocator);
|
||||
defer std.testing.allocator.free(frame);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp:param:active_2:11") != null);
|
||||
}
|
||||
try client.handleTraceLine("lsp_param_previous");
|
||||
snap = try client.session.snapshot();
|
||||
try std.testing.expectEqual(@as(usize, 4), snap.cursor_byte);
|
||||
}
|
||||
|
||||
test "adversarial: malformed hover signature and non-call parameter movement are safe" {
|
||||
var client = try Client.init(std.testing.allocator, .{ .width = 64, .height = 5 });
|
||||
defer client.deinit();
|
||||
|
||||
try client.handleTraceLine("open safe");
|
||||
try std.testing.expectError(Error.ProtocolRejected, client.handleTraceLine("lsp_hover not-json"));
|
||||
try std.testing.expectError(Error.ProtocolRejected, client.handleTraceLine("lsp_signature not-json"));
|
||||
try client.handleTraceLine("lsp_param_next");
|
||||
const snap = try client.session.snapshot();
|
||||
try std.testing.expectEqualStrings("safe", snap.bytes);
|
||||
const frame = try client.render(std.testing.allocator);
|
||||
defer std.testing.allocator.free(frame);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp:param:outside_call") != null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user