diff --git a/src/Project.zig b/src/Project.zig index 085d45f..4f41772 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -55,9 +55,11 @@ const Self = @This(); const OutOfMemoryError = error{OutOfMemory}; const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed}); -pub const RequestError = error{InvalidRequest} || OutOfMemoryError || cbor.Error; +pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI, InvalidMapType }; pub const StartLspError = (error{ ThespianSpawnFailed, Timeout, InvalidLspCommand } || LspError || OutOfMemoryError || cbor.Error); pub const LspError = (error{ NoLsp, LspFailed } || OutOfMemoryError || std.Io.Writer.Error); +pub const ClientError = (error{ClientFailed} || OutOfMemoryError || std.Io.Writer.Error); +pub const LspOrClientError = (LspError || ClientError); pub const GitError = error{InvalidGitResponse}; pub const LspInfoError = error{ InvalidInfoMessage, InvalidTriggerCharacters }; @@ -374,25 +376,21 @@ inline fn sort_by_mtime(T: type, items: []T) void { }.cmp); } -pub fn request_n_most_recent_file(self: *Self, from: tp.pid_ref, n: usize) RequestError!void { - if (n >= self.files.items.len) return error.InvalidRequest; +pub fn request_n_most_recent_file(self: *Self, from: tp.pid_ref, n: usize) ClientError!void { + if (n >= self.files.items.len) return error.ClientFailed; const file_path = if (self.files.items.len > 0) self.files.items[n].path else null; - from.send(.{file_path}) catch |e| - std.log.err("send request_n_most_recent_file failed: {t}", .{e}); + from.send(.{file_path}) catch return error.ClientFailed; } -pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) RequestError!void { +pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) ClientError!void { defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, "", self.files.items.len }) catch {}; for (self.files.items, 0..) |file, i| { - from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, file.type, file.icon, file.color }) catch |e| { - std.log.err("send recent failed: {t}", .{e}); - return; - }; + from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, file.type, file.icon, file.color }) catch return error.ClientFailed; if (i >= max) return; } } -fn simple_query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) RequestError!usize { +fn simple_query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize { var i: usize = 0; defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_file_path, query }) catch {}; for (self.new_or_modified_files.items) |file| { @@ -402,10 +400,7 @@ fn simple_query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, defer self.allocator.free(matches); var n: usize = 0; while (n < query.len) : (n += 1) matches[n] = idx + n; - from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status, matches }) catch |e| { - std.log.err("send new_or_modified_files failed: {t}", .{e}); - return error.InvalidRequest; - }; + from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status, matches }) catch return error.ClientFailed; i += 1; if (i >= max) return i; } @@ -413,7 +408,7 @@ fn simple_query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, return i; } -pub fn query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) RequestError!usize { +pub fn query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize { if (query.len < 3) return self.simple_query_new_or_modified_files(from, max, query); defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_file_path, query }) catch {}; @@ -461,25 +456,19 @@ pub fn query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, qu std.mem.sort(Match, matches.items, {}, less_fn); for (matches.items[0..@min(max, matches.items.len)]) |match| - from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, match.path, match.type, match.icon, match.color, match.vcs_status, match.matches }) catch |e| { - std.log.err("send new_or_modified_files failed: {t}", .{e}); - return error.InvalidRequest; - }; + from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, match.path, match.type, match.icon, match.color, match.vcs_status, match.matches }) catch return error.ClientFailed; return @min(max, matches.items.len); } -pub fn request_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize) RequestError!void { +pub fn request_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize) ClientError!void { defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_new_or_modified_file_path, "" }) catch {}; for (self.new_or_modified_files.items, 0..) |file, i| { - from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status }) catch |e| { - std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; - }; + from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status }) catch return error.ClientFailed; if (i >= max) return; } } -fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) RequestError!usize { +fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize { var i: usize = 0; defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query, self.files.items.len }) catch {}; for (self.files.items) |file| { @@ -489,10 +478,7 @@ fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: [ defer self.allocator.free(matches); var n: usize = 0; while (n < query.len) : (n += 1) matches[n] = idx + n; - from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, file.type, file.icon, file.color, matches }) catch |e| { - std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; - }; + from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, file.type, file.icon, file.color, matches }) catch return error.ClientFailed; i += 1; if (i >= max) return i; } @@ -500,7 +486,7 @@ fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: [ return i; } -pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) RequestError!usize { +pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize { if (query.len < 3) return self.simple_query_recent_files(from, max, query); defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query, self.files.items.len }) catch {}; @@ -546,10 +532,7 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []co std.mem.sort(Match, matches.items, {}, less_fn); for (matches.items[0..@min(max, matches.items.len)]) |match| - from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.type, match.icon, match.color, match.matches }) catch |e| { - std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; - }; + from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.type, match.icon, match.color, match.matches }) catch return error.ClientFailed; return @min(max, matches.items.len); } @@ -701,16 +684,16 @@ fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usi } } -pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) RequestError!void { +pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) ClientError!void { for (self.files.items) |*file| { if (!std.mem.eql(u8, file.path, file_path)) continue; - from.send(.{ file.pos.row + 1, file.pos.col + 1 }) catch return error.InvalidRequest; + from.send(.{ file.pos.row + 1, file.pos.col + 1 }) catch return error.ClientFailed; return; } - from.send(.{"none"}) catch return error.InvalidRequest; + from.send(.{"none"}) catch return error.ClientFailed; } -pub fn request_vcs_status(self: *Self, from: tp.pid_ref) RequestError!void { +pub fn request_vcs_status(self: *Self, from: tp.pid_ref) ClientError!void { switch (self.state.status) { .failed => return, .none => switch (self.state.workspace_path) { @@ -718,7 +701,7 @@ pub fn request_vcs_status(self: *Self, from: tp.pid_ref) RequestError!void { if (self.status_request) |_| return; self.status_request = from.clone(); }, - else => return error.InvalidRequest, + else => return error.ClientFailed, }, .running => { if (self.status_request) |_| return; @@ -746,17 +729,14 @@ pub fn request_vcs_status(self: *Self, from: tp.pid_ref) RequestError!void { } } -pub fn request_tasks(self: *Self, from: tp.pid_ref) RequestError!void { +pub fn request_tasks(self: *Self, from: tp.pid_ref) ClientError!void { var message: std.Io.Writer.Allocating = .init(self.allocator); defer message.deinit(); const writer = &message.writer; try cbor.writeArrayHeader(writer, self.tasks.items.len); for (self.tasks.items) |task| try cbor.writeValue(writer, task.command); - from.send_raw(.{ .buf = message.written() }) catch |e| { - std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; - }; + from.send_raw(.{ .buf = message.written() }) catch return error.ClientFailed; } pub fn add_task(self: *Self, command: []const u8) OutOfMemoryError!void { @@ -934,7 +914,7 @@ pub fn goto_type_definition(self: *Self, from: tp.pid_ref, file_path: []const u8 return self.send_goto_request(from, file_path, row, col, "textDocument/typeDefinition"); } -pub const SendGotoRequestError = (error{} || LspError || GetLineOfFileError || cbor.Error); +pub const SendGotoRequestError = (LspError || ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error); fn send_goto_request(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize, method: []const u8) SendGotoRequestError!void { const lsp = try self.get_language_server(file_path); @@ -987,9 +967,9 @@ fn file_uri_to_path(uri: []const u8, file_path_buf: []u8) error{InvalidTargetURI return error.InvalidTargetURI); } -fn navigate_to_location_link(from: tp.pid_ref, location_link: []const u8) (error{InvalidTargetURI} || LocationLinkError)!void { +fn navigate_to_location_link(from: tp.pid_ref, location_link: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void { const location: LocationLink = try read_locationlink(location_link); - if (location.targetUri == null or location.targetRange == null) return error.InvalidLocationLink; + if (location.targetUri == null or location.targetRange == null) return error.InvalidMessageField; var file_path_buf: [std.fs.max_path_bytes]u8 = undefined; var file_path = try file_uri_to_path(location.targetUri.?, &file_path_buf); if (builtin.os.tag == .windows) { @@ -1009,10 +989,7 @@ fn navigate_to_location_link(from: tp.pid_ref, location_link: []const u8) (error sel.end.line, sel.end.character, }, - } }) catch |e| { - std.log.err("send navigate failed: {t}", .{e}); - return; - }; + } }) catch return error.ClientFailed; } else { from.send(.{ "cmd", "navigate", .{ .file = file_path, @@ -1020,10 +997,7 @@ fn navigate_to_location_link(from: tp.pid_ref, location_link: []const u8) (error location.targetRange.?.start.line + 1, location.targetRange.?.start.character + 1, }, - } }) catch |e| { - std.log.err("send navigate failed: {t}", .{e}); - return; - }; + } }) catch return error.ClientFailed; } } @@ -1101,10 +1075,7 @@ pub fn highlight_references(self: *Self, from: tp.pid_ref, file_path: []const u8 }, handler) catch return error.LspFailed; } -fn send_reference_list(tag: []const u8, to: tp.pid_ref, locations: []const u8, name: []const u8) (error{ - InvalidTargetURI, - InvalidReferenceList, -} || LocationLinkError || GetLineOfFileError || cbor.Error)!usize { +fn send_reference_list(tag: []const u8, to: tp.pid_ref, locations: []const u8, name: []const u8) (ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error)!usize { defer to.send(.{ tag, "done" }) catch {}; var iter = locations; var len = try cbor.decodeArrayHeader(&iter); @@ -1113,15 +1084,15 @@ fn send_reference_list(tag: []const u8, to: tp.pid_ref, locations: []const u8, n var location: []const u8 = undefined; if (try cbor.matchValue(&iter, cbor.extract_cbor(&location))) { try send_reference(tag, to, location, name); - } else return error.InvalidReferenceList; + } else return error.InvalidMessageField; } return count; } -fn send_reference(tag: []const u8, to: tp.pid_ref, location_: []const u8, name: []const u8) (error{InvalidTargetURI} || LocationLinkError || GetLineOfFileError || cbor.Error)!void { +fn send_reference(tag: []const u8, to: tp.pid_ref, location_: []const u8, name: []const u8) (ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error)!void { const allocator = std.heap.c_allocator; const location: LocationLink = try read_locationlink(location_); - if (location.targetUri == null or location.targetRange == null) return error.InvalidLocationLink; + if (location.targetUri == null or location.targetRange == null) return error.InvalidMessageField; var file_path_buf: [std.fs.max_path_bytes]u8 = undefined; var file_path = try file_uri_to_path(location.targetUri.?, &file_path_buf); if (builtin.os.tag == .windows) { @@ -1144,17 +1115,10 @@ fn send_reference(tag: []const u8, to: tp.pid_ref, location_: []const u8, name: location.targetRange.?.end.line + 1, location.targetRange.?.end.character, line, - }) catch |e| { - std.log.err("send {s} (in send_reference) failed: {t}", .{ tag, e }); - return; - }; + }) catch return error.ClientFailed; } -pub const CompletionError = error{ - InvalidTargetURI, -} || CompletionListError || CompletionItemError || TextEditError || cbor.Error; - -pub fn completion(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) LspError!void { +pub fn completion(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (LspOrClientError || InvalidMessageError || cbor.Error)!void { const lsp = try self.get_language_server(file_path); const uri = try self.make_URI(file_path); defer self.allocator.free(uri); @@ -1170,7 +1134,7 @@ pub fn completion(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usi self_.from.deinit(); } - pub fn receive(self_: @This(), response: tp.message) (CompletionError || cbor.Error)!void { + pub fn receive(self_: @This(), response: tp.message) !void { var result: []const u8 = undefined; if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) { try send_content_msg_empty(self_.from.ref(), "hover", self_.file_path, self_.row, self_.col); @@ -1195,7 +1159,7 @@ pub fn completion(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usi }, handler) catch return error.LspFailed; } -pub fn symbols(self: *Self, from: tp.pid_ref, file_path: []const u8) (LspError || SymbolInformationError)!void { +pub fn symbols(self: *Self, from: tp.pid_ref, file_path: []const u8) (LspOrClientError || InvalidMessageError || cbor.Error)!void { const lsp = try self.get_language_server(file_path); const uri = try self.make_URI(file_path); defer self.allocator.free(uri); @@ -1228,81 +1192,59 @@ pub fn symbols(self: *Self, from: tp.pid_ref, file_path: []const u8) (LspError | }, handler) catch return error.LspFailed; } -fn send_symbol_items(to: tp.pid_ref, file_path: []const u8, items: []const u8) (SymbolInformationError || cbor.Error)!void { +fn send_symbol_items(to: tp.pid_ref, file_path: []const u8, items: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void { var iter = items; var len = cbor.decodeArrayHeader(&iter) catch return; var item: []const u8 = ""; var node_count: usize = 0; while (len > 0) : (len -= 1) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&item)))) return error.InvalidSymbolInformation; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&item)))) return error.InvalidMessageField; node_count += try send_symbol_information(to, file_path, item, ""); } const logger = log.logger("lsp"); defer logger.deinit(); logger.print("LSP accounted {d} symbols", .{node_count}); - return to.send(.{ "cmd", "add_document_symbol_done", .{file_path} }) catch |e| { - std.log.err("send add_document_symbol_done failed: {t}", .{e}); - return; - }; + return to.send(.{ "cmd", "add_document_symbol_done", .{file_path} }) catch error.ClientFailed; } -pub const CompletionListError = error{ - InvalidCompletionListField, - InvalidCompletionListFieldName, -} || CompletionItemError || TextEditError || cbor.Error; -fn send_completion_list(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (CompletionListError || cbor.Error)!void { +fn send_completion_list(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void { var iter = result; var len = cbor.decodeMapHeader(&iter) catch return; var items: []const u8 = ""; - var is_incomplete: bool = true; + var is_incomplete: bool = false; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidCompletionListFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "items")) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&items)))) return error.InvalidCompletionListField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&items)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "isIncomplete")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&is_incomplete)))) return error.InvalidCompletionListField; + if (!(try cbor.matchValue(&iter, cbor.extract(&is_incomplete)))) return error.InvalidMessageField; } else { try cbor.skipValue(&iter); } } - return if (items.len > 0) - send_completion_items(to, file_path, row, col, items, is_incomplete) - else - to.send(.{ "cmd", "add_completion_done", .{ file_path, row, col } }) catch |e| { - std.log.err("send add_completion_done failed: {t}", .{e}); - }; + return send_completion_items(to, file_path, row, col, items, is_incomplete) catch error.ClientFailed; } -pub const CompletionItemError = error{ - InvalidCompletionItem, - InvalidCompletionItemField, - InvalidCompletionItemFieldName, -} || TextEditError || cbor.Error; -fn send_completion_items(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, items: []const u8, is_incomplete: bool) (CompletionItemError || cbor.Error)!void { +fn send_completion_items(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, items: []const u8, is_incomplete: bool) (ClientError || InvalidMessageError || cbor.Error)!void { var iter = items; var len = cbor.decodeArrayHeader(&iter) catch return; var item: []const u8 = ""; while (len > 0) : (len -= 1) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&item)))) return error.InvalidCompletionItem; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&item)))) return error.InvalidMessageField; try send_completion_item(to, file_path, row, col, item, if (len > 1) true else is_incomplete); } - return to.send(.{ "cmd", "add_completion_done", .{ file_path, row, col } }) catch |e| { - std.log.err("send add_completion_done failed: {t}", .{e}); - }; + return to.send(.{ "cmd", "add_completion_done", .{ file_path, row, col } }) catch error.ClientFailed; } -fn invalid_symbol_information_field(field: []const u8) error{InvalidSymbolInformationField} { - std.log.err("invalid symbol information field '{s}'", .{field}); - return error.InvalidSymbolInformationField; +fn invalid_field(field: []const u8) error{InvalidMessage} { + const logger = log.logger("lsp"); + defer logger.deinit(); + logger.print("invalid completion field '{s}'", .{field}); + return error.InvalidMessage; } -pub const SymbolInformationError = error{ - InvalidSymbolInformation, - InvalidSymbolInformationField, - InvalidTargetURI, -} || LocationLinkError || cbor.Error; -fn send_symbol_information(to: tp.pid_ref, file_path: []const u8, item: []const u8, parent_name: []const u8) SymbolInformationError!usize { +fn send_symbol_information(to: tp.pid_ref, file_path: []const u8, item: []const u8, parent_name: []const u8) (ClientError || InvalidMessageError || cbor.Error)!usize { var name: []const u8 = ""; var detail: ?[]const u8 = ""; var kind: usize = 0; @@ -1322,49 +1264,49 @@ fn send_symbol_information(to: tp.pid_ref, file_path: []const u8, item: []const tags[0] = 0; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidSymbolInformation; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "name")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&name)))) return invalid_symbol_information_field("name"); + if (!(try cbor.matchValue(&iter, cbor.extract(&name)))) return invalid_field("name"); } else if (std.mem.eql(u8, field_name, "detail")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&detail)))) return invalid_symbol_information_field("detail"); + if (!(try cbor.matchValue(&iter, cbor.extract(&detail)))) return invalid_field("detail"); } else if (std.mem.eql(u8, field_name, "kind")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&kind)))) return invalid_symbol_information_field("kind"); + if (!(try cbor.matchValue(&iter, cbor.extract(&kind)))) return invalid_field("kind"); } else if (std.mem.eql(u8, field_name, "tags")) { var len_ = cbor.decodeArrayHeader(&iter) catch return 0; var idx: usize = 0; var this_tag: usize = undefined; len_tags_ = len_; while (len_ > 0) : (len_ -= 1) { - if (!(try cbor.matchValue(&iter, cbor.extract(&this_tag)))) return invalid_symbol_information_field("tags"); + if (!(try cbor.matchValue(&iter, cbor.extract(&this_tag)))) return invalid_field("tags"); tags[idx] = this_tag; idx += 1; } try cbor.skipValue(&iter); } else if (std.mem.eql(u8, field_name, "deprecated")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&deprecated)))) return invalid_symbol_information_field("deprecated"); + if (!(try cbor.matchValue(&iter, cbor.extract(&deprecated)))) return invalid_field("deprecated"); } else if (std.mem.eql(u8, field_name, "range")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return invalid_symbol_information_field("range"); + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return invalid_field("range"); range = try read_range(range_); symbolKind = SymbolType.document_symbol; } else if (std.mem.eql(u8, field_name, "selectionRange")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return invalid_symbol_information_field("selectionRange"); + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return invalid_field("selectionRange"); selectionRange = try read_range(range_); } else if (std.mem.eql(u8, field_name, "children")) { var len_ = cbor.decodeArrayHeader(&iter) catch return 0; var descendant: []const u8 = ""; while (len_ > 0) : (len_ -= 1) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&descendant)))) return error.InvalidSymbolInformationField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&descendant)))) return error.InvalidMessageField; descendant_count += try send_symbol_information(to, file_path, descendant, name); } } else if (std.mem.eql(u8, field_name, "location")) {} else if (std.mem.eql(u8, field_name, "location")) { var location_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&location_)))) return invalid_symbol_information_field("selectionRange"); + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&location_)))) return invalid_field("selectionRange"); location = try read_locationlink(iter); symbolKind = SymbolType.document_symbol; } else if (std.mem.eql(u8, field_name, "containerName")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&containerName)))) return invalid_symbol_information_field("containerName"); + if (!(try cbor.matchValue(&iter, cbor.extract(&containerName)))) return invalid_field("containerName"); } else { try cbor.skipValue(&iter); } @@ -1388,16 +1330,13 @@ fn send_symbol_information(to: tp.pid_ref, file_path: []const u8, item: []const selectionRange.end.character, deprecated, detail, - } }) catch |e| { - std.log.err("send add_document_symbol failed: {t}", .{e}); - return 0; - }; + } }) catch return error.ClientFailed; return descendant_count + 1; }, SymbolType.symbol_information => { var fp = file_path; if (location) |location_| { - if (location_.targetUri == null or location_.targetRange == null) return error.InvalidSymbolInformationField; + if (location_.targetUri == null or location_.targetRange == null) return error.InvalidMessageField; var file_path_buf: [std.fs.max_path_bytes]u8 = undefined; var file_path_ = try file_uri_to_path(location_.targetUri.?, &file_path_buf); if (builtin.os.tag == .windows) { @@ -1407,24 +1346,16 @@ fn send_symbol_information(to: tp.pid_ref, file_path: []const u8, item: []const }; } fp = file_path_; - to.send(.{ "cmd", "add_symbol_information", .{ fp, name, parent_name, kind, location_.targetRange.?.start.line, location_.targetRange.?.start.character, location_.targetRange.?.end.line, location_.targetRange.?.end.character, tags[0..len_tags_], location_.targetSelectionRange.?.start.line, location_.targetSelectionRange.?.start.character, location_.targetSelectionRange.?.end.line, location_.targetSelectionRange.?.end.character, deprecated, location_.targetUri } }) catch |e| { - std.log.err("send add_symbol_information failed: {t}", .{e}); - return 0; - }; + to.send(.{ "cmd", "add_symbol_information", .{ fp, name, parent_name, kind, location_.targetRange.?.start.line, location_.targetRange.?.start.character, location_.targetRange.?.end.line, location_.targetRange.?.end.character, tags[0..len_tags_], location_.targetSelectionRange.?.start.line, location_.targetSelectionRange.?.start.character, location_.targetSelectionRange.?.end.line, location_.targetSelectionRange.?.end.character, deprecated, location_.targetUri } }) catch return error.ClientFailed; return 1; } else { - return error.InvalidSymbolInformationField; + return error.InvalidMessageField; } }, }; } -fn invalid_completion_item_field(field: []const u8) error{InvalidCompletionItemField} { - std.log.err("invalid completion item field '{s}'", .{field}); - return error.InvalidCompletionItemField; -} - -fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, item: []const u8, is_incomplete: bool) CompletionItemError!void { +fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, item: []const u8, is_incomplete: bool) (ClientError || InvalidMessageError || cbor.Error)!void { var label: []const u8 = ""; var label_detail: []const u8 = ""; var label_description: []const u8 = ""; @@ -1443,48 +1374,43 @@ fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col: var len = cbor.decodeMapHeader(&iter) catch return; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) { - const json = cbor.toJsonAlloc(std.heap.c_allocator, iter) catch "(error)"; - defer std.heap.c_allocator.free(json); - std.log.err("unexpected value in completion item field name: {s}", .{json}); - return error.InvalidCompletionItemFieldName; - } + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "label")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&label)))) return invalid_completion_item_field("label"); + if (!(try cbor.matchValue(&iter, cbor.extract(&label)))) return invalid_field("label"); } else if (std.mem.eql(u8, field_name, "labelDetails")) { var len_ = cbor.decodeMapHeader(&iter) catch return; while (len_ > 0) : (len_ -= 1) { - if (!(try cbor.matchString(&iter, &field_name))) return invalid_completion_item_field("labelDetails"); + if (!(try cbor.matchString(&iter, &field_name))) return invalid_field("labelDetails"); if (std.mem.eql(u8, field_name, "detail")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&label_detail)))) return invalid_completion_item_field("labelDetails.detail"); + if (!(try cbor.matchValue(&iter, cbor.extract(&label_detail)))) return invalid_field("labelDetails.detail"); } else if (std.mem.eql(u8, field_name, "description")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&label_description)))) return invalid_completion_item_field("labelDetails.description"); + if (!(try cbor.matchValue(&iter, cbor.extract(&label_description)))) return invalid_field("labelDetails.description"); } else { try cbor.skipValue(&iter); } } } else if (std.mem.eql(u8, field_name, "kind")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&kind)))) return invalid_completion_item_field("kind"); + if (!(try cbor.matchValue(&iter, cbor.extract(&kind)))) return invalid_field("kind"); } else if (std.mem.eql(u8, field_name, "detail")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&detail)))) return invalid_completion_item_field("detail"); + if (!(try cbor.matchValue(&iter, cbor.extract(&detail)))) return invalid_field("detail"); } else if (std.mem.eql(u8, field_name, "documentation")) { var len_ = cbor.decodeMapHeader(&iter) catch return; while (len_ > 0) : (len_ -= 1) { - if (!(try cbor.matchString(&iter, &field_name))) return invalid_completion_item_field("documentation"); + if (!(try cbor.matchString(&iter, &field_name))) return invalid_field("documentation"); if (std.mem.eql(u8, field_name, "kind")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&documentation_kind)))) return invalid_completion_item_field("documentation.kind"); + if (!(try cbor.matchValue(&iter, cbor.extract(&documentation_kind)))) return invalid_field("documentation.kind"); } else if (std.mem.eql(u8, field_name, "value")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&documentation)))) return invalid_completion_item_field("documentation.value"); + if (!(try cbor.matchValue(&iter, cbor.extract(&documentation)))) return invalid_field("documentation.value"); } else { try cbor.skipValue(&iter); } } } else if (std.mem.eql(u8, field_name, "insertText")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&insertText)))) return invalid_completion_item_field("insertText"); + if (!(try cbor.matchValue(&iter, cbor.extract(&insertText)))) return invalid_field("insertText"); } else if (std.mem.eql(u8, field_name, "sortText")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&sortText)))) return invalid_completion_item_field("sortText"); + if (!(try cbor.matchValue(&iter, cbor.extract(&sortText)))) return invalid_field("sortText"); } else if (std.mem.eql(u8, field_name, "insertTextFormat")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&insertTextFormat)))) return invalid_completion_item_field("insertTextFormat"); + if (!(try cbor.matchValue(&iter, cbor.extract(&insertTextFormat)))) return invalid_field("insertTextFormat"); } else if (std.mem.eql(u8, field_name, "textEdit")) { textEdit = try read_textEdit(&iter); } else if (std.mem.eql(u8, field_name, "additionalTextEdits")) { @@ -1495,6 +1421,7 @@ fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col: additionalTextEdits[idx] = try read_textEdit(&iter); idx += 1; } + try cbor.skipValue(&iter); } else { try cbor.skipValue(&iter); } @@ -1528,38 +1455,26 @@ fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col: replace.end.character, additionalTextEdits[0..additionalTextEdits_len], }, - }) catch |e| { - std.log.err("send add_completion failed: {t}", .{e}); - }; + }) catch error.ClientFailed; } -fn invalid_text_edit_field(field: []const u8) error{InvalidTextEditField} { - std.log.err("invalid text edit field '{s}'", .{field}); - return error.InvalidTextEditField; -} - -const TextEditError = error{ - InvalidTextEdit, - InvalidTextEditField, - InvalidTextEditFieldName, -} || RangeError || cbor.Error; -fn read_textEdit(iter: *[]const u8) TextEditError!TextEdit { +fn read_textEdit(iter: *[]const u8) !TextEdit { var field_name: []const u8 = undefined; var newText: []const u8 = ""; var insert: ?Range = null; var replace: ?Range = null; - var len_ = cbor.decodeMapHeader(iter) catch return invalid_text_edit_field("textEdit"); + var len_ = cbor.decodeMapHeader(iter) catch return invalid_field("textEdit"); while (len_ > 0) : (len_ -= 1) { - if (!(try cbor.matchString(iter, &field_name))) return invalid_text_edit_field("textEdit"); + if (!(try cbor.matchString(iter, &field_name))) return invalid_field("textEdit"); if (std.mem.eql(u8, field_name, "newText")) { - if (!(try cbor.matchValue(iter, cbor.extract(&newText)))) return invalid_text_edit_field("textEdit.newText"); + if (!(try cbor.matchValue(iter, cbor.extract(&newText)))) return invalid_field("textEdit.newText"); } else if (std.mem.eql(u8, field_name, "insert")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range_)))) return invalid_text_edit_field("textEdit.insert"); + if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range_)))) return invalid_field("textEdit.insert"); insert = try read_range(range_); } else if (std.mem.eql(u8, field_name, "replace") or std.mem.eql(u8, field_name, "range")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range_)))) return invalid_text_edit_field("textEdit.replace"); + if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range_)))) return invalid_field("textEdit.replace"); replace = try read_range(range_); } else { try cbor.skipValue(iter); @@ -1580,7 +1495,7 @@ const Rename = struct { range: Range, }; -pub fn rename_symbol(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (LspError || GetLineOfFileError)!void { +pub fn rename_symbol(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (LspOrClientError || GetLineOfFileError || InvalidMessageError || cbor.Error)!void { const lsp = try self.get_language_server(file_path); const uri = try self.make_URI(file_path); defer self.allocator.free(uri); @@ -1650,63 +1565,58 @@ pub fn rename_symbol(self: *Self, from: tp.pid_ref, file_path: []const u8, row: // decode a WorkspaceEdit record which may have shape {"changes": {}} or {"documentChanges": []} // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit -fn decode_rename_symbol_map(result: []const u8, renames: *std.array_list.Managed(Rename)) DocumentChangesError!void { +fn decode_rename_symbol_map(result: []const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void { var iter = result; - var len = cbor.decodeMapHeader(&iter) catch return error.InvalidDocumentChanges; + var len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage; var changes: []const u8 = ""; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidDocumentChangesFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "changes")) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&changes)))) return error.InvalidDocumentChangesField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&changes)))) return error.InvalidMessageField; try decode_rename_symbol_changes(changes, renames); return; } else if (std.mem.eql(u8, field_name, "documentChanges")) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&changes)))) return error.InvalidDocumentChangesField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&changes)))) return error.InvalidMessageField; try decode_rename_symbol_doc_changes(changes, renames); return; } else { try cbor.skipValue(&iter); } } - return error.InvalidDocumentChanges; + return error.ClientFailed; } -fn decode_rename_symbol_changes(changes: []const u8, renames: *std.array_list.Managed(Rename)) TextEditError!void { +fn decode_rename_symbol_changes(changes: []const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void { var iter = changes; - var files_len = cbor.decodeMapHeader(&iter) catch return error.InvalidTextEdit; + var files_len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage; while (files_len > 0) : (files_len -= 1) { var file_uri: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &file_uri))) return error.InvalidTextEdit; + if (!(try cbor.matchString(&iter, &file_uri))) return error.InvalidMessage; try decode_rename_symbol_item(file_uri, &iter, renames); } } -const DocumentChangesError = error{ - InvalidDocumentChanges, - InvalidDocumentChangesField, - InvalidDocumentChangesFieldName, -} || TextEditError || cbor.Error; -fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.array_list.Managed(Rename)) DocumentChangesError!void { +fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void { var iter = changes; - var changes_len = cbor.decodeArrayHeader(&iter) catch return error.InvalidDocumentChanges; + var changes_len = cbor.decodeArrayHeader(&iter) catch return error.InvalidMessage; while (changes_len > 0) : (changes_len -= 1) { - var dc_fields_len = cbor.decodeMapHeader(&iter) catch return error.InvalidDocumentChanges; + var dc_fields_len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage; var file_uri: []const u8 = ""; while (dc_fields_len > 0) : (dc_fields_len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidDocumentChangesFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "textDocument")) { - var td_fields_len = cbor.decodeMapHeader(&iter) catch return error.InvalidDocumentChangesField; + var td_fields_len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage; while (td_fields_len > 0) : (td_fields_len -= 1) { var td_field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &td_field_name))) return error.InvalidDocumentChangesField; + if (!(try cbor.matchString(&iter, &td_field_name))) return error.InvalidMessage; if (std.mem.eql(u8, td_field_name, "uri")) { - if (!(try cbor.matchString(&iter, &file_uri))) return error.InvalidDocumentChangesField; + if (!(try cbor.matchString(&iter, &file_uri))) return error.InvalidMessage; } else try cbor.skipValue(&iter); // skip "version": 1 } } else if (std.mem.eql(u8, field_name, "edits")) { - if (file_uri.len == 0) return error.InvalidDocumentChangesField; + if (file_uri.len == 0) return error.InvalidMessage; try decode_rename_symbol_item(file_uri, &iter, renames); } } @@ -1714,32 +1624,32 @@ fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.array_lis } // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEdit -fn decode_rename_symbol_item(file_uri: []const u8, iter: *[]const u8, renames: *std.array_list.Managed(Rename)) TextEditError!void { - var text_edits_len = cbor.decodeArrayHeader(iter) catch return error.InvalidTextEditField; +fn decode_rename_symbol_item(file_uri: []const u8, iter: *[]const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void { + var text_edits_len = cbor.decodeArrayHeader(iter) catch return error.InvalidMessage; while (text_edits_len > 0) : (text_edits_len -= 1) { var m_range: ?Range = null; var new_text: []const u8 = ""; - var edits_len = cbor.decodeMapHeader(iter) catch return error.InvalidTextEditField; + var edits_len = cbor.decodeMapHeader(iter) catch return error.InvalidMessage; while (edits_len > 0) : (edits_len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(iter, &field_name))) return error.InvalidTextEditField; + if (!(try cbor.matchString(iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "range")) { var range: []const u8 = undefined; - if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range)))) return error.InvalidTextEditField; + if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range)))) return error.InvalidMessageField; m_range = try read_range(range); } else if (std.mem.eql(u8, field_name, "newText")) { - if (!(try cbor.matchString(iter, &new_text))) return error.InvalidTextEditField; + if (!(try cbor.matchString(iter, &new_text))) return error.InvalidMessageField; } else { try cbor.skipValue(iter); } } - const range = m_range orelse return error.InvalidTextEditField; + const range = m_range orelse return error.InvalidMessageField; try renames.append(.{ .uri = file_uri, .range = range, .new_text = new_text }); } } -pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) LspError!void { +pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (LspOrClientError || InvalidMessageError || cbor.Error)!void { const lsp = try self.get_language_server(file_path); const uri = try self.make_URI(file_path); defer self.allocator.free(uri); @@ -1777,25 +1687,19 @@ pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, c }, handler) catch return error.LspFailed; } -const HoverError = error{ - InvalidHover, - InvalidHoverField, - InvalidHoverFieldName, -} || HoverContentsError || RangeError || cbor.Error; - -fn send_hover(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) HoverError!void { +fn send_hover(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void { var iter = result; var len = cbor.decodeMapHeader(&iter) catch return; var contents: []const u8 = ""; var range: ?Range = null; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidHoverFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "contents")) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&contents)))) return error.InvalidHoverField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&contents)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "range")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidHoverField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidMessageField; range = try read_range(range_); } else { try cbor.skipValue(&iter); @@ -1805,12 +1709,6 @@ fn send_hover(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, res return send_contents(to, "hover", file_path, row, col, contents, range); } -const HoverContentsError = error{ - InvalidHoverContents, - InvalidHoverContentsField, - InvalidHoverContentsFieldName, -} || cbor.Error; - fn send_contents( to: tp.pid_ref, tag: []const u8, @@ -1819,7 +1717,7 @@ fn send_contents( col: usize, result: []const u8, range: ?Range, -) HoverContentsError!void { +) !void { var iter = result; var kind: []const u8 = "plaintext"; var value: []const u8 = ""; @@ -1835,11 +1733,11 @@ fn send_contents( var len = cbor.decodeMapHeader(&iter) catch return; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidHoverContentsFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "kind")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&kind)))) return error.InvalidHoverContentsField; + if (!(try cbor.matchValue(&iter, cbor.extract(&kind)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "value")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&value)))) return error.InvalidHoverContentsField; + if (!(try cbor.matchValue(&iter, cbor.extract(&value)))) return error.InvalidMessageField; } else { try cbor.skipValue(&iter); } @@ -1857,42 +1755,40 @@ fn send_content_msg( kind: []const u8, content: []const u8, range: ?Range, -) error{}!void { +) ClientError!void { const r = range orelse Range{ .start = .{ .line = row, .character = col }, .end = .{ .line = row, .character = col }, }; - to.send(.{ tag, file_path, kind, content, r.start.line, r.start.character, r.end.line, r.end.character }) catch |e| { - std.log.err("send {s} (in send_content_msg) failed: {t}", .{ tag, e }); - }; + to.send(.{ tag, file_path, kind, content, r.start.line, r.start.character, r.end.line, r.end.character }) catch return error.ClientFailed; } -fn send_content_msg_empty(to: tp.pid_ref, tag: []const u8, file_path: []const u8, row: usize, col: usize) error{}!void { +fn send_content_msg_empty(to: tp.pid_ref, tag: []const u8, file_path: []const u8, row: usize, col: usize) ClientError!void { return send_content_msg(to, tag, file_path, row, col, "plaintext", "", null); } -pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) DiagnosticError!void { +pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void { var uri: ?[]const u8 = null; var diagnostics: []const u8 = &.{}; var iter = params_cb; var len = try cbor.decodeMapHeader(&iter); while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidDiagnostic; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "uri")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&uri)))) return error.InvalidDiagnosticField; + if (!(try cbor.matchValue(&iter, cbor.extract(&uri)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "diagnostics")) { - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&diagnostics)))) return error.InvalidDiagnosticField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&diagnostics)))) return error.InvalidMessageField; } else { try cbor.skipValue(&iter); } } - if (uri == null) return error.InvalidDiagnosticField; + if (uri == null) return error.InvalidMessageField; var file_path_buf: [std.fs.max_path_bytes]u8 = undefined; const file_path = try file_uri_to_path(uri.?, &file_path_buf); - self.send_clear_diagnostics(to, file_path); + try self.send_clear_diagnostics(to, file_path); iter = diagnostics; len = try cbor.decodeArrayHeader(&iter); @@ -1900,17 +1796,11 @@ pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) D var diagnostic: []const u8 = undefined; if (try cbor.matchValue(&iter, cbor.extract_cbor(&diagnostic))) { try self.send_diagnostic(to, file_path, diagnostic); - } else return error.InvalidDiagnosticField; + } else return error.InvalidMessageField; } } -pub const DiagnosticError = error{ - InvalidTargetURI, - InvalidDiagnostic, - InvalidDiagnosticFieldName, - InvalidDiagnosticField, -} || RangeError || cbor.Error; -fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic: []const u8) DiagnosticError!void { +fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void { var source: []const u8 = "unknown"; var code: []const u8 = "none"; var code_int: i64 = 0; @@ -1922,29 +1812,29 @@ fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic: var len = try cbor.decodeMapHeader(&iter); while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidDiagnosticFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "source") or std.mem.eql(u8, field_name, "uri")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&source)))) return error.InvalidDiagnosticField; + if (!(try cbor.matchValue(&iter, cbor.extract(&source)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "code")) { if (try cbor.matchValue(&iter, cbor.extract(&code_int))) { var writer = std.Io.Writer.fixed(&code_int_buf); try writer.print("{}", .{code_int}); code = writer.buffered(); } else if (!(try cbor.matchValue(&iter, cbor.extract(&code)))) - return error.InvalidDiagnosticField; + return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "message")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&message)))) return error.InvalidDiagnosticField; + if (!(try cbor.matchValue(&iter, cbor.extract(&message)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "severity")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&severity)))) return error.InvalidDiagnosticField; + if (!(try cbor.matchValue(&iter, cbor.extract(&severity)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "range")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidDiagnosticField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidMessageField; range = try read_range(range_); } else { try cbor.skipValue(&iter); } } - if (range == null) return error.InvalidDiagnostic; + if (range == null) return error.InvalidMessageField; to.send(.{ "cmd", "add_diagnostic", .{ file_path, source, @@ -1955,15 +1845,11 @@ fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic: range.?.start.character, range.?.end.line, range.?.end.character, - } }) catch |e| { - std.log.err("send add_diagnostic failed: {t}", .{e}); - }; + } }) catch return error.ClientFailed; } -fn send_clear_diagnostics(_: *Self, to: tp.pid_ref, file_path: []const u8) void { - to.send(.{ "cmd", "clear_diagnostics", .{file_path} }) catch |e| { - std.log.err("send clear_diagnostics failed: {t}", .{e}); - }; +fn send_clear_diagnostics(_: *Self, to: tp.pid_ref, file_path: []const u8) ClientError!void { + to.send(.{ "cmd", "clear_diagnostics", .{file_path} }) catch return error.ClientFailed; } const SymbolType = enum { document_symbol, symbol_information }; @@ -1988,12 +1874,7 @@ const LocationLink = struct { targetRange: ?Range = null, targetSelectionRange: ?Range = null, }; -const LocationLinkError = error{ - InvalidLocationLink, - InvalidLocationLinkFieldName, - InvalidLocationLinkField, -} || RangeError || cbor.Error; -fn read_locationlink(location_link: []const u8) LocationLinkError!LocationLink { +fn read_locationlink(location_link: []const u8) !LocationLink { var iter = location_link; var targetUri: ?[]const u8 = null; var targetRange: ?Range = null; @@ -2001,18 +1882,18 @@ fn read_locationlink(location_link: []const u8) LocationLinkError!LocationLink { var len = try cbor.decodeMapHeader(&iter); while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidLocationLinkFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "targetUri") or std.mem.eql(u8, field_name, "uri")) { var uri_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract(&uri_)))) return error.InvalidLocationLinkField; + if (!(try cbor.matchValue(&iter, cbor.extract(&uri_)))) return error.InvalidMessageField; targetUri = uri_; } else if (std.mem.eql(u8, field_name, "targetRange") or std.mem.eql(u8, field_name, "range")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidLocationLinkField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidMessageField; targetRange = try read_range(range_); } else if (std.mem.eql(u8, field_name, "targetSelectionRange")) { var range_: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidLocationLinkField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidMessageField; targetSelectionRange = try read_range(range_); } else { try cbor.skipValue(&iter); @@ -2022,58 +1903,48 @@ fn read_locationlink(location_link: []const u8) LocationLinkError!LocationLink { } const Range = struct { start: Position, end: Position }; -const RangeError = error{ - InvalidRange, - InvalidRangeFieldName, - InvalidRangeField, -} || PositionError || cbor.Error; -fn read_range(range: []const u8) RangeError!Range { +fn read_range(range: []const u8) !Range { var iter = range; var start: ?Position = null; var end: ?Position = null; var len = try cbor.decodeMapHeader(&iter); while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidRangeFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "start")) { var position: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&position)))) return error.InvalidRangeField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&position)))) return error.InvalidMessageField; start = try read_position(position); } else if (std.mem.eql(u8, field_name, "end")) { var position: []const u8 = undefined; - if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&position)))) return error.InvalidRangeField; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&position)))) return error.InvalidMessageField; end = try read_position(position); } else { try cbor.skipValue(&iter); } } - if (start == null or end == null) return error.InvalidRange; + if (start == null or end == null) return error.InvalidMessageField; return .{ .start = start.?, .end = end.? }; } const Position = struct { line: usize, character: usize }; -const PositionError = error{ - InvalidPosition, - InvalidPositionFieldName, - InvalidPositionField, -} || cbor.Error; -fn read_position(position: []const u8) PositionError!Position { +fn read_position(position: []const u8) !Position { var iter = position; var line: ?usize = 0; var character: ?usize = 0; var len = try cbor.decodeMapHeader(&iter); while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidPositionFieldName; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "line")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&line)))) return error.InvalidPositionField; + if (!(try cbor.matchValue(&iter, cbor.extract(&line)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "character")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&character)))) return error.InvalidPositionField; + if (!(try cbor.matchValue(&iter, cbor.extract(&character)))) return error.InvalidMessageField; } else { try cbor.skipValue(&iter); } } - if (line == null or character == null) return error.InvalidPosition; + if (line == null or character == null) return error.InvalidMessageField; return .{ .line = line.?, .character = character.? }; } @@ -2085,12 +1956,7 @@ pub fn log_message(self: *Self, params_cb: []const u8) !void { return self.show_or_log_message(.log, params_cb); } -pub const LogMessageError = error{ - InvalidLogMessage, - InvalidLogMessageField, - InvalidLogMessageFieldName, -} || cbor.Error; -fn show_or_log_message(self: *Self, operation: enum { show, log }, params_cb: []const u8) LogMessageError!void { +fn show_or_log_message(self: *Self, operation: enum { show, log }, params_cb: []const u8) !void { if (!tp.env.get().is("lsp_verbose")) return; var type_: i32 = 0; var message: ?[]const u8 = null; @@ -2098,11 +1964,11 @@ fn show_or_log_message(self: *Self, operation: enum { show, log }, params_cb: [] var len = try cbor.decodeMapHeader(&iter); while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; - if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidLogMessage; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage; if (std.mem.eql(u8, field_name, "type")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&type_)))) return error.InvalidLogMessageField; + if (!(try cbor.matchValue(&iter, cbor.extract(&type_)))) return error.InvalidMessageField; } else if (std.mem.eql(u8, field_name, "message")) { - if (!(try cbor.matchValue(&iter, cbor.extract(&message)))) return error.InvalidLogMessageField; + if (!(try cbor.matchValue(&iter, cbor.extract(&message)))) return error.InvalidMessageField; } else { try cbor.skipValue(&iter); } @@ -2121,18 +1987,18 @@ pub fn show_notification(self: *Self, method: []const u8, params_cb: []const u8) self.logger_lsp.print("LSP notification: {s} -> {s}", .{ method, params }); } -pub fn register_capability(self: *Self, from: tp.pid_ref, cbor_id: []const u8, params_cb: []const u8) LspError!void { +pub fn register_capability(self: *Self, from: tp.pid_ref, cbor_id: []const u8, params_cb: []const u8) ClientError!void { _ = params_cb; - return LSP.send_response(self.allocator, from, cbor_id, null) catch error.LspFailed; + return LSP.send_response(self.allocator, from, cbor_id, null) catch error.ClientFailed; } -pub fn workDoneProgress_create(self: *Self, from: tp.pid_ref, cbor_id: []const u8, params_cb: []const u8) LspError!void { +pub fn workDoneProgress_create(self: *Self, from: tp.pid_ref, cbor_id: []const u8, params_cb: []const u8) ClientError!void { _ = params_cb; - return LSP.send_response(self.allocator, from, cbor_id, null) catch error.LspFailed; + return LSP.send_response(self.allocator, from, cbor_id, null) catch error.ClientFailed; } -pub fn unsupported_lsp_request(self: *Self, from: tp.pid_ref, cbor_id: []const u8, method: []const u8) LspError!void { - return LSP.send_error_response(self.allocator, from, cbor_id, LSP.ErrorCode.MethodNotFound, method) catch error.LspFailed; +pub fn unsupported_lsp_request(self: *Self, from: tp.pid_ref, cbor_id: []const u8, method: []const u8) ClientError!void { + return LSP.send_error_response(self.allocator, from, cbor_id, LSP.ErrorCode.MethodNotFound, method) catch error.ClientFailed; } fn send_lsp_init_request(self: *Self, from: tp.pid_ref, lsp: *const LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8, language_server: []const u8, language_server_options: []const u8) !void { @@ -2496,7 +2362,7 @@ fn send_lsp_init_request(self: *Self, from: tp.pid_ref, lsp: *const LSP, project }, handler); } -fn send_lsp_init_response(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, result: []const u8) (LspInfoError || cbor.Error)!void { +fn send_lsp_init_response(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, result: []const u8) (ClientError || LspInfoError || cbor.Error)!void { var iter = result; var len = cbor.decodeMapHeader(&iter) catch return; while (len > 0) : (len -= 1) { @@ -2510,7 +2376,7 @@ fn send_lsp_init_response(to: tp.pid_ref, project_path: []const u8, language_ser } } -fn send_lsp_capabilities(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, iter: *[]const u8) (LspInfoError || cbor.Error)!void { +fn send_lsp_capabilities(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, iter: *[]const u8) (ClientError || LspInfoError || cbor.Error)!void { var len = cbor.decodeMapHeader(iter) catch return; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; @@ -2523,7 +2389,7 @@ fn send_lsp_capabilities(to: tp.pid_ref, project_path: []const u8, language_serv } } -fn send_lsp_completionProvider(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, iter: *[]const u8) (LspInfoError || cbor.Error)!void { +fn send_lsp_completionProvider(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, iter: *[]const u8) (ClientError || LspInfoError || cbor.Error)!void { var len = cbor.decodeMapHeader(iter) catch return; while (len > 0) : (len -= 1) { var field_name: []const u8 = undefined; @@ -2538,7 +2404,7 @@ fn send_lsp_completionProvider(to: tp.pid_ref, project_path: []const u8, languag } } -fn send_lsp_triggerCharacters(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, items: []const u8) (LspInfoError || cbor.Error)!void { +fn send_lsp_triggerCharacters(to: tp.pid_ref, project_path: []const u8, language_server: []const u8, items: []const u8) (ClientError || LspInfoError || cbor.Error)!void { var buf: [4096]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); const w = &writer; @@ -2548,10 +2414,7 @@ fn send_lsp_triggerCharacters(to: tp.pid_ref, project_path: []const u8, language try cbor.writeValue(w, project_path); try w.writeAll(language_server); try w.writeAll(items); - to.send_raw(.{ .buf = w.buffered() }) catch |e| { - std.log.err("send triggerCharacters failed: {t}", .{e}); - return; - }; + to.send_raw(.{ .buf = w.buffered() }) catch return error.ClientFailed; } fn fmt_lsp_name_func(bytes: []const u8) std.fmt.Formatter([]const u8, format_lsp_name_func) { diff --git a/src/project_manager.zig b/src/project_manager.zig index 0446698..b878219 100644 --- a/src/project_manager.zig +++ b/src/project_manager.zig @@ -552,27 +552,27 @@ const Process = struct { } } - fn request_n_most_recent_file(self: *Process, from: tp.pid_ref, project_directory: []const u8, n: usize) (ProjectError || Project.RequestError)!void { + fn request_n_most_recent_file(self: *Process, from: tp.pid_ref, project_directory: []const u8, n: usize) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; return project.request_n_most_recent_file(from, n); } - fn request_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || Project.RequestError)!void { + fn request_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; return project.request_recent_files(from, max); } - fn request_sync_with_vcs(self: *Process, _: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.RequestError)!void { + fn request_sync_with_vcs(self: *Process, _: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; return project.query_git(); } - fn request_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || Project.RequestError)!void { + fn request_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; return project.request_new_or_modified_files(from, max); } - fn request_recent_projects(self: *Process, from: tp.pid_ref, active_project: []const u8) (ProjectError || Project.RequestError || OutOfMemoryError || cbor.Error)!void { + fn request_recent_projects(self: *Process, from: tp.pid_ref, active_project: []const u8) (ProjectError || Project.ClientError)!void { var recent_projects: std.ArrayList(RecentProject) = .empty; defer recent_projects.deinit(self.allocator); self.load_recent_projects(&recent_projects) catch {}; @@ -615,14 +615,11 @@ const Process = struct { try cbor.writeValue(writer, if (self.projects.get(project.name)) |_| true else false); self.allocator.free(project.name); } - from.send_raw(.{ .buf = message.written() }) catch |e| { - std.log.err("send recent_projects failed: {t}", .{e}); - return; - }; + from.send_raw(.{ .buf = message.written() }) catch return error.ClientFailed; self.logger.print("{d} projects found", .{recent_projects.items.len}); } - fn query_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || Project.RequestError)!void { + fn query_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; const start_time = std.time.milliTimestamp(); const matched = try project.query_recent_files(from, max, query); @@ -631,7 +628,7 @@ const Process = struct { self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time }); } - fn query_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || Project.RequestError)!void { + fn query_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; const start_time = std.time.milliTimestamp(); const matched = try project.query_new_or_modified_files(from, max, query); @@ -647,32 +644,32 @@ const Process = struct { try request_path_files_async(self.allocator, from, project, max, expand_home(self.allocator, &buf, path)); } - fn request_tasks(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.RequestError)!void { + fn request_tasks(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; try project.request_tasks(from); } - fn add_task(self: *Process, project_directory: []const u8, task: []const u8) (ProjectError || Project.RequestError)!void { + fn add_task(self: *Process, project_directory: []const u8, task: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; try project.add_task(task); } - fn delete_task(self: *Process, project_directory: []const u8, task: []const u8) (ProjectError || Project.RequestError)!void { + fn delete_task(self: *Process, project_directory: []const u8, task: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; try project.delete_task(task); } - fn request_vcs_status(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.RequestError)!void { + fn request_vcs_status(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; try project.request_vcs_status(from); } - fn request_vcs_id(self: *Process, _: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.RequestError)!void { + fn request_vcs_id(self: *Process, _: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; try project.request_vcs_id(file_path); } - fn request_vcs_content(self: *Process, _: tp.pid_ref, project_directory: []const u8, file_path: []const u8, vcs_id: []const u8) (ProjectError || Project.RequestError)!void { + fn request_vcs_content(self: *Process, _: tp.pid_ref, project_directory: []const u8, file_path: []const u8, vcs_id: []const u8) (ProjectError || Project.ClientError)!void { const project = self.projects.get(project_directory) orelse return error.NoProject; try project.request_vcs_content(file_path, vcs_id); } @@ -747,35 +744,35 @@ const Process = struct { return project.highlight_references(from, file_path, row, col); } - fn symbols(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.SymbolInformationError || Project.LspError)!void { + fn symbols(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.InvalidMessageError || Project.LspOrClientError || cbor.Error)!void { const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".symbols" }); defer frame.deinit(); const project = self.projects.get(project_directory) orelse return error.NoProject; return project.symbols(from, file_path); } - fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.CompletionError || Project.LspError)!void { + fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.InvalidMessageError || Project.LspOrClientError || cbor.Error)!void { const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".completion" }); defer frame.deinit(); const project = self.projects.get(project_directory) orelse return error.NoProject; return project.completion(from, file_path, row, col); } - fn rename_symbol(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.GetLineOfFileError || Project.LspError)!void { + fn rename_symbol(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.InvalidMessageError || Project.LspOrClientError || Project.GetLineOfFileError || cbor.Error)!void { const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".rename_symbol" }); defer frame.deinit(); const project = self.projects.get(project_directory) orelse return error.NoProject; return project.rename_symbol(from, file_path, row, col); } - fn hover(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.LspError)!void { + fn hover(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.InvalidMessageError || Project.LspOrClientError || cbor.Error)!void { const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".hover" }); defer frame.deinit(); const project = self.projects.get(project_directory) orelse return error.NoProject; return project.hover(from, file_path, row, col); } - fn get_mru_position(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.RequestError)!void { + fn get_mru_position(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.ClientError)!void { const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".get_mru_position" }); defer frame.deinit(); const project = self.projects.get(project_directory) orelse return error.NoProject; @@ -787,7 +784,7 @@ const Process = struct { return project.update_mru(file_path, row, col); } - fn dispatch_notify(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, params_cb: []const u8) (ProjectError || Project.DiagnosticError || Project.LogMessageError || cbor.JsonEncodeError)!void { + fn dispatch_notify(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, params_cb: []const u8) (ProjectError || Project.ClientError || Project.InvalidMessageError || cbor.Error || cbor.JsonEncodeError)!void { _ = language_server; const project = self.projects.get(project_directory) orelse return error.NoProject; return if (std.mem.eql(u8, method, "textDocument/publishDiagnostics")) @@ -800,7 +797,7 @@ const Process = struct { project.show_notification(method, params_cb); } - fn dispatch_request(self: *Process, from: tp.pid_ref, project_directory: []const u8, language_server: []const u8, method: []const u8, cbor_id: []const u8, params_cb: []const u8) (ProjectError || Project.LspError || cbor.Error || cbor.JsonEncodeError || UnsupportedError)!void { + fn dispatch_request(self: *Process, from: tp.pid_ref, project_directory: []const u8, language_server: []const u8, method: []const u8, cbor_id: []const u8, params_cb: []const u8) (ProjectError || Project.ClientError || cbor.Error || cbor.JsonEncodeError || UnsupportedError)!void { _ = language_server; const project = if (self.projects.get(project_directory)) |p| p else return error.NoProject; return if (std.mem.eql(u8, method, "client/registerCapability"))