so... jai :D
This commit is contained in:
75
src/lsp/transport.zig
Normal file
75
src/lsp/transport.zig
Normal file
@@ -0,0 +1,75 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const Transport = struct {
|
||||
in: *std.Io.Reader,
|
||||
out_file: std.Io.File,
|
||||
io: std.Io,
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, io: std.Io, in: *std.Io.Reader, out_file: std.Io.File) Transport {
|
||||
return .{
|
||||
.in = in,
|
||||
.out_file = out_file,
|
||||
.io = io,
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
/// Read one LSP message: parse Content-Length header, read body.
|
||||
pub fn readMessage(self: *Transport) ![]const u8 {
|
||||
var content_length: ?usize = null;
|
||||
|
||||
// Parse headers (terminated by \r\n\r\n)
|
||||
while (true) {
|
||||
const line = try self.readLine();
|
||||
if (line.len == 0) break; // empty line = end of headers
|
||||
|
||||
if (std.mem.startsWith(u8, line, "Content-Length: ")) {
|
||||
content_length = std.fmt.parseInt(usize, line["Content-Length: ".len..], 10) catch
|
||||
return error.InvalidContentLength;
|
||||
}
|
||||
}
|
||||
|
||||
const len = content_length orelse return error.MissingContentLength;
|
||||
|
||||
const body = try self.allocator.alloc(u8, len);
|
||||
try self.in.readSliceAll(body);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/// Write one LSP message: Content-Length header + body.
|
||||
pub fn writeMessage(self: *Transport, body: []const u8) !void {
|
||||
var buf: [32]u8 = undefined;
|
||||
const len_str = std.fmt.bufPrint(&buf, "{d}", .{body.len}) catch unreachable;
|
||||
|
||||
self.out_file.writeStreamingAll(self.io, "Content-Length: ") catch return error.WriteFailed;
|
||||
self.out_file.writeStreamingAll(self.io, len_str) catch return error.WriteFailed;
|
||||
self.out_file.writeStreamingAll(self.io, "\r\n\r\n") catch return error.WriteFailed;
|
||||
self.out_file.writeStreamingAll(self.io, body) catch return error.WriteFailed;
|
||||
}
|
||||
|
||||
/// Read a single line terminated by \r\n. Returns content without \r\n.
|
||||
fn readLine(self: *Transport) ![]const u8 {
|
||||
var buf = std.ArrayList(u8).empty;
|
||||
while (true) {
|
||||
const byte = self.in.takeByte() catch |err| switch (err) {
|
||||
error.EndOfStream => {
|
||||
if (buf.items.len == 0) return error.EndOfStream;
|
||||
return buf.items;
|
||||
},
|
||||
else => return error.ReadFailed,
|
||||
};
|
||||
|
||||
if (byte == '\n') {
|
||||
const line = buf.items;
|
||||
if (line.len > 0 and line[line.len - 1] == '\r') {
|
||||
return line[0 .. line.len - 1];
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
try buf.append(self.allocator, byte);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user