Add LSP diagnostics panel
This commit is contained in:
+63
@@ -150,6 +150,8 @@ pub const Client = struct {
|
||||
if (std.mem.eql(u8, line, "terminal_exit")) return self.closeTerminalPanel();
|
||||
if (std.mem.startsWith(u8, line, "syntax_spans ")) return self.openSyntaxSpans(line[13..]);
|
||||
if (std.mem.startsWith(u8, line, "lsp_sync ")) return self.openLspSync(line[9..]);
|
||||
if (std.mem.startsWith(u8, line, "lsp_diagnostics ")) return self.openLspDiagnostics(line[16..]);
|
||||
if (std.mem.eql(u8, line, "lsp_diagnostics_open_selected")) return self.openSelectedLspDiagnostic();
|
||||
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);
|
||||
@@ -439,6 +441,25 @@ pub const Client = struct {
|
||||
self.message = null;
|
||||
}
|
||||
|
||||
fn openLspDiagnostics(self: *Client, payload: []const u8) !void {
|
||||
const rows = lsp_mod.diagnosticRowsAlloc(self.allocator, payload) catch return Error.ProtocolRejected;
|
||||
defer freeOwnedRows(self.allocator, rows);
|
||||
try self.session.openListPanel("lsp-diagnostics", rows);
|
||||
self.message = null;
|
||||
}
|
||||
|
||||
fn openSelectedLspDiagnostic(self: *Client) !void {
|
||||
const selected = self.session.selectListPanel() catch return Error.ProtocolRejected;
|
||||
const location = lsp_mod.diagnosticLocationFromRow(selected) catch return Error.ProtocolRejected;
|
||||
const snap = try self.session.snapshot();
|
||||
const bytes = try self.allocator.dupe(u8, snap.bytes);
|
||||
defer self.allocator.free(bytes);
|
||||
const offset = lsp_mod.byteOffsetForLineColumn(bytes, location.line, location.character) catch return Error.ProtocolRejected;
|
||||
try self.session.openFixtureAt(bytes, offset);
|
||||
try self.session.closePanel();
|
||||
self.message = null;
|
||||
}
|
||||
|
||||
fn openStaticJobRow(self: *Client, title: []const u8, row: []const u8) !void {
|
||||
try self.session.openListPanel(title, &.{row});
|
||||
self.message = null;
|
||||
@@ -1590,3 +1611,45 @@ test "adversarial: lsp sync rejection does not corrupt current buffer" {
|
||||
const snap = try client.session.snapshot();
|
||||
try std.testing.expectEqualStrings("safe", snap.bytes);
|
||||
}
|
||||
|
||||
test "regular: lsp diagnostics panel renders rows and jumps to diagnostic" {
|
||||
var client = try Client.init(std.testing.allocator, .{ .width = 96, .height = 7 });
|
||||
defer client.deinit();
|
||||
|
||||
try client.handleTraceLine("open one\\nabcdTARGET");
|
||||
const payload =
|
||||
\\{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///tmp/main.zig","diagnostics":[{"range":{"start":{"line":0,"character":4},"end":{"line":1,"character":5}},"severity":1,"message":"expected semicolon"}]}}
|
||||
;
|
||||
const command = try std.fmt.allocPrint(std.testing.allocator, "lsp_diagnostics {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-diagnostics") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp:diagnostics:count_1") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, frame, "lsp:diag:error:1:5:file_///tmp/main.zig:expected_semicolon") != null);
|
||||
}
|
||||
|
||||
try client.handleTraceLine("list_down");
|
||||
try client.handleTraceLine("lsp_diagnostics_open_selected");
|
||||
const snap = try client.session.snapshot();
|
||||
try std.testing.expectEqual(@as(usize, 4), snap.cursor_byte);
|
||||
}
|
||||
|
||||
test "adversarial: malformed diagnostics and unselected summary row do not corrupt buffer" {
|
||||
var client = try Client.init(std.testing.allocator, .{ .width = 72, .height = 5 });
|
||||
defer client.deinit();
|
||||
|
||||
try client.handleTraceLine("open safe");
|
||||
try std.testing.expectError(Error.ProtocolRejected, client.handleTraceLine("lsp_diagnostics not-json"));
|
||||
const payload =
|
||||
\\{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///tmp/main.zig","diagnostics":[{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":1}},"severity":2,"message":"warn"}]}}
|
||||
;
|
||||
const command = try std.fmt.allocPrint(std.testing.allocator, "lsp_diagnostics {s}", .{payload});
|
||||
defer std.testing.allocator.free(command);
|
||||
try client.handleTraceLine(command);
|
||||
try std.testing.expectError(Error.ProtocolRejected, client.handleTraceLine("lsp_diagnostics_open_selected"));
|
||||
const snap = try client.session.snapshot();
|
||||
try std.testing.expectEqualStrings("safe", snap.bytes);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user