feat: add LSP client support for error responses to requests
This commit is contained in:
		
							parent
							
								
									5d256413da
								
							
						
					
					
						commit
						996ec70e42
					
				
					 1 changed files with 76 additions and 0 deletions
				
			
		
							
								
								
									
										76
									
								
								src/LSP.zig
									
										
									
									
									
								
							
							
						
						
									
										76
									
								
								src/LSP.zig
									
										
									
									
									
								
							|  | @ -67,6 +67,45 @@ pub fn send_notification_raw(self: *const Self, method: []const u8, cb: []const | |||
|     self.pid.send(.{ "NTFY", method, cb }) catch return error.SendFailed; | ||||
| } | ||||
| 
 | ||||
| pub const ErrorCode = enum(i32) { | ||||
| 
 | ||||
|     // Defined by JSON-RPC | ||||
|     ParseError = -32700, | ||||
|     InvalidRequest = -32600, | ||||
|     MethodNotFound = -32601, | ||||
|     InvalidParams = -32602, | ||||
|     InternalError = -32603, | ||||
| 
 | ||||
|     // Defined by LSP | ||||
|     RequestFailed = -32803, | ||||
|     ServerCancelled = -32802, | ||||
|     ContentModified = -32801, | ||||
|     RequestCancelled = -32800, | ||||
| }; | ||||
| 
 | ||||
| pub fn send_response(allocator: std.mem.Allocator, to: tp.pid_ref, cbor_id: []const u8, result: anytype) (SendError || OutOfMemoryError)!void { | ||||
|     var cb = std.ArrayList(u8).init(allocator); | ||||
|     defer cb.deinit(); | ||||
|     const writer = cb.writer(); | ||||
|     try cbor.writeArrayHeader(writer, 3); | ||||
|     try cbor.writeValue(writer, "RSP"); | ||||
|     try writer.writeAll(cbor_id); | ||||
|     try cbor.writeValue(cb.writer(), result); | ||||
|     to.send_raw(.{ .buf = cb.items }) catch return error.SendFailed; | ||||
| } | ||||
| 
 | ||||
| pub fn send_error_response(allocator: std.mem.Allocator, to: tp.pid_ref, cbor_id: []const u8, code: ErrorCode, message: []const u8) (SendError || OutOfMemoryError)!void { | ||||
|     var cb = std.ArrayList(u8).init(allocator); | ||||
|     defer cb.deinit(); | ||||
|     const writer = cb.writer(); | ||||
|     try cbor.writeArrayHeader(writer, 4); | ||||
|     try cbor.writeValue(writer, "ERR"); | ||||
|     try writer.writeAll(cbor_id); | ||||
|     try cbor.writeValue(cb.writer(), code); | ||||
|     try cbor.writeValue(cb.writer(), message); | ||||
|     to.send_raw(.{ .buf = cb.items }) catch return error.SendFailed; | ||||
| } | ||||
| 
 | ||||
| pub fn close(self: *Self) void { | ||||
|     self.deinit(); | ||||
| } | ||||
|  | @ -252,6 +291,8 @@ const Process = struct { | |||
|         var err: []const u8 = ""; | ||||
|         var code: u32 = 0; | ||||
|         var cbor_id: []const u8 = ""; | ||||
|         var error_code: ErrorCode = undefined; | ||||
|         var message: []const u8 = ""; | ||||
| 
 | ||||
|         if (try cbor.match(m.buf, .{ "REQ", "initialize", tp.extract(&bytes) })) { | ||||
|             try self.send_request(from, "initialize", bytes); | ||||
|  | @ -262,6 +303,8 @@ const Process = struct { | |||
|             } | ||||
|         } else if (try cbor.match(m.buf, .{ "RSP", tp.extract_cbor(&cbor_id), tp.extract_cbor(&bytes) })) { | ||||
|             try self.send_response(cbor_id, bytes); | ||||
|         } else if (try cbor.match(m.buf, .{ "ERR", tp.extract_cbor(&cbor_id), tp.extract(&error_code), tp.extract(&message) })) { | ||||
|             try self.send_error_response(cbor_id, error_code, message); | ||||
|         } else if (try cbor.match(m.buf, .{ "NTFY", "initialized", tp.extract(&bytes) })) { | ||||
|             self.state = .running; | ||||
|             try self.send_notification("initialized", bytes); | ||||
|  | @ -482,6 +525,39 @@ const Process = struct { | |||
|         self.write_log("### SEND response:\n{s}\n###\n", .{output.items}); | ||||
|     } | ||||
| 
 | ||||
|     fn send_error_response(self: *Process, cbor_id: []const u8, error_code: ErrorCode, message: []const u8) (error{Closed} || SendError || cbor.Error || cbor.JsonEncodeError)!void { | ||||
|         const sp = if (self.sp) |*sp| sp else return error.Closed; | ||||
| 
 | ||||
|         var msg = std.ArrayList(u8).init(self.allocator); | ||||
|         defer msg.deinit(); | ||||
|         const msg_writer = msg.writer(); | ||||
|         try cbor.writeMapHeader(msg_writer, 3); | ||||
|         try cbor.writeValue(msg_writer, "jsonrpc"); | ||||
|         try cbor.writeValue(msg_writer, "2.0"); | ||||
|         try cbor.writeValue(msg_writer, "id"); | ||||
|         try msg_writer.writeAll(cbor_id); | ||||
|         try cbor.writeValue(msg_writer, "error"); | ||||
|         try cbor.writeMapHeader(msg_writer, 2); | ||||
|         try cbor.writeValue(msg_writer, "code"); | ||||
|         try cbor.writeValue(msg_writer, @intFromEnum(error_code)); | ||||
|         try cbor.writeValue(msg_writer, "message"); | ||||
|         try cbor.writeValue(msg_writer, message); | ||||
| 
 | ||||
|         const json = try cbor.toJsonAlloc(self.allocator, msg.items); | ||||
|         defer self.allocator.free(json); | ||||
|         var output = std.ArrayList(u8).init(self.allocator); | ||||
|         defer output.deinit(); | ||||
|         const writer = output.writer(); | ||||
|         const terminator = "\r\n"; | ||||
|         const content_length = json.len + terminator.len; | ||||
|         try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length}); | ||||
|         _ = try writer.write(json); | ||||
|         _ = try writer.write(terminator); | ||||
| 
 | ||||
|         sp.send(output.items) catch return error.SendFailed; | ||||
|         self.write_log("### SEND error response:\n{s}\n###\n", .{output.items}); | ||||
|     } | ||||
| 
 | ||||
|     fn send_notification(self: *Process, method: []const u8, params_cb: []const u8) Error!void { | ||||
|         const sp = if (self.sp) |*sp| sp else return error.Closed; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue