refactor: use explicit error sets in MessageFilter and project_manager
This commit is contained in:
parent
6fac0b1cb4
commit
0542fdc680
12 changed files with 396 additions and 341 deletions
|
@ -18,8 +18,8 @@
|
||||||
.hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362",
|
.hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362",
|
||||||
},
|
},
|
||||||
.thespian = .{
|
.thespian = .{
|
||||||
.url = "https://github.com/neurocyte/thespian/archive/06ff2a148c1e33095d4838579461f31141565958.tar.gz",
|
.url = "https://github.com/neurocyte/thespian/archive/6e65fa623a45a4925875955aeb45e5cb0b5f7a68.tar.gz",
|
||||||
.hash = "122064ef6d9da7aa0352da12804ab46dbecdabb033e9d6c1b4208844f9dd3694e373",
|
.hash = "12206feb723c41340acfe574b16f98a90e3af1f2662850ee2904ec0facb9dc5f0eef",
|
||||||
},
|
},
|
||||||
.themes = .{
|
.themes = .{
|
||||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-803da089c5a0fc3b4513a7c34afe9bdaff83efdc/flow-themes.tar.gz",
|
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-803da089c5a0fc3b4513a7c34afe9bdaff83efdc/flow-themes.tar.gz",
|
||||||
|
|
122
src/LSP.zig
122
src/LSP.zig
|
@ -14,7 +14,11 @@ const sp_tag = "child";
|
||||||
const debug_lsp = true;
|
const debug_lsp = true;
|
||||||
const lsp_request_timeout = std.time.ns_per_s * 30;
|
const lsp_request_timeout = std.time.ns_per_s * 30;
|
||||||
|
|
||||||
pub fn open(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) !Self {
|
const OutOfMemoryError = error{OutOfMemory};
|
||||||
|
const SendError = error{SendFailed};
|
||||||
|
const CallError = tp.CallError;
|
||||||
|
|
||||||
|
pub fn open(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) (error{ ThespianSpawnFailed, InvalidArgument } || cbor.Error)!Self {
|
||||||
return .{ .allocator = allocator, .pid = try Process.create(allocator, project, cmd) };
|
return .{ .allocator = allocator, .pid = try Process.create(allocator, project, cmd) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,29 +32,29 @@ pub fn term(self: *Self) void {
|
||||||
self.pid.deinit();
|
self.pid.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_request(self: Self, allocator: std.mem.Allocator, method: []const u8, m: anytype) !tp.message {
|
pub fn send_request(self: Self, allocator: std.mem.Allocator, method: []const u8, m: anytype) CallError!tp.message {
|
||||||
var cb = std.ArrayList(u8).init(self.allocator);
|
var cb = std.ArrayList(u8).init(self.allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
try cbor.writeValue(cb.writer(), m);
|
try cbor.writeValue(cb.writer(), m);
|
||||||
return self.pid.call(allocator, lsp_request_timeout, .{ "REQ", method, cb.items });
|
return self.pid.call(allocator, lsp_request_timeout, .{ "REQ", method, cb.items });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_response(self: Self, id: i32, m: anytype) !tp.message {
|
pub fn send_response(self: Self, id: i32, m: anytype) SendError!tp.message {
|
||||||
var cb = std.ArrayList(u8).init(self.allocator);
|
var cb = std.ArrayList(u8).init(self.allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
try cbor.writeValue(cb.writer(), m);
|
try cbor.writeValue(cb.writer(), m);
|
||||||
return self.pid.send(.{ "RSP", id, cb.items });
|
return self.pid.send(.{ "RSP", id, cb.items });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_notification(self: Self, method: []const u8, m: anytype) !void {
|
pub fn send_notification(self: Self, method: []const u8, m: anytype) (OutOfMemoryError || SendError)!void {
|
||||||
var cb = std.ArrayList(u8).init(self.allocator);
|
var cb = std.ArrayList(u8).init(self.allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
try cbor.writeValue(cb.writer(), m);
|
try cbor.writeValue(cb.writer(), m);
|
||||||
return self.send_notification_raw(method, cb.items);
|
return self.send_notification_raw(method, cb.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_notification_raw(self: Self, method: []const u8, cb: []const u8) !void {
|
pub fn send_notification_raw(self: Self, method: []const u8, cb: []const u8) SendError!void {
|
||||||
return self.pid.send(.{ "NTFY", method, cb });
|
self.pid.send(.{ "NTFY", method, cb }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self: *Self) void {
|
pub fn close(self: *Self) void {
|
||||||
|
@ -73,14 +77,14 @@ const Process = struct {
|
||||||
|
|
||||||
const Receiver = tp.Receiver(*Process);
|
const Receiver = tp.Receiver(*Process);
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) !tp.pid {
|
pub fn create(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) (error{ ThespianSpawnFailed, InvalidArgument } || OutOfMemoryError || cbor.Error)!tp.pid {
|
||||||
var tag: []const u8 = undefined;
|
var tag: []const u8 = undefined;
|
||||||
if (try cmd.match(.{tp.extract(&tag)})) {
|
if (try cbor.match(cmd.buf, .{tp.extract(&tag)})) {
|
||||||
//
|
//
|
||||||
} else if (try cmd.match(.{ tp.extract(&tag), tp.more })) {
|
} else if (try cbor.match(cmd.buf, .{ tp.extract(&tag), tp.more })) {
|
||||||
//
|
//
|
||||||
} else {
|
} else {
|
||||||
return tp.exit("no LSP command");
|
return error.InvalidArgument;
|
||||||
}
|
}
|
||||||
const self = try allocator.create(Process);
|
const self = try allocator.create(Process);
|
||||||
var sp_tag_ = std.ArrayList(u8).init(allocator);
|
var sp_tag_ = std.ArrayList(u8).init(allocator);
|
||||||
|
@ -112,18 +116,18 @@ const Process = struct {
|
||||||
if (self.log_file) |file| file.close();
|
if (self.log_file) |file| file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(self: *Process) tp.result {
|
fn close(self: *Process) error{CloseFailed}!void {
|
||||||
if (self.sp) |*sp| {
|
if (self.sp) |*sp| {
|
||||||
defer self.sp = null;
|
defer self.sp = null;
|
||||||
try sp.close();
|
sp.close() catch return error.CloseFailed;
|
||||||
self.write_log("### closed ###\n", .{});
|
self.write_log("### closed ###\n", .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term(self: *Process) tp.result {
|
fn term(self: *Process) error{TerminateFailed}!void {
|
||||||
if (self.sp) |*sp| {
|
if (self.sp) |*sp| {
|
||||||
defer self.sp = null;
|
defer self.sp = null;
|
||||||
try sp.term();
|
sp.term() catch return error.TerminateFailed;
|
||||||
self.write_log("### terminated ###\n", .{});
|
self.write_log("### terminated ###\n", .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,29 +147,27 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
||||||
return self.receive_safe(from, m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
return self.receive_safe(from, m) catch |e| switch (e) {
|
||||||
|
error.ExitNormal => tp.exit_normal(),
|
||||||
|
error.ExitUnexpected => error.Exit,
|
||||||
|
else => tp.exit_error(e, @errorReturnTrace()),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReceiveError = error{
|
const Error = (cbor.Error || cbor.JsonDecodeError || OutOfMemoryError || SendError || error{
|
||||||
OutOfMemory,
|
|
||||||
NoSpaceLeft,
|
|
||||||
BufferUnderrun,
|
|
||||||
CborIntegerTooLarge,
|
|
||||||
CborIntegerTooSmall,
|
|
||||||
CborInvalidType,
|
|
||||||
CborTooShort,
|
|
||||||
CborUnsupportedType,
|
|
||||||
SyntaxError,
|
|
||||||
UnexpectedEndOfInput,
|
|
||||||
InvalidSyntax,
|
InvalidSyntax,
|
||||||
InvalidMessageField,
|
InvalidMessageField,
|
||||||
InvalidMessage,
|
InvalidMessage,
|
||||||
InvalidContentLength,
|
InvalidContentLength,
|
||||||
Closed,
|
Closed,
|
||||||
Exit,
|
CloseFailed,
|
||||||
};
|
TerminateFailed,
|
||||||
|
UnsupportedType,
|
||||||
|
ExitNormal,
|
||||||
|
ExitUnexpected,
|
||||||
|
});
|
||||||
|
|
||||||
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) ReceiveError!void {
|
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) Error!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name });
|
const frame = tracy.initZone(@src(), .{ .name = module_name });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
errdefer self.deinit();
|
errdefer self.deinit();
|
||||||
|
@ -175,34 +177,34 @@ const Process = struct {
|
||||||
var code: u32 = 0;
|
var code: u32 = 0;
|
||||||
var id: i32 = 0;
|
var id: i32 = 0;
|
||||||
|
|
||||||
if (try m.match(.{ "REQ", tp.extract(&method), tp.extract(&bytes) })) {
|
if (try cbor.match(m.buf, .{ "REQ", tp.extract(&method), tp.extract(&bytes) })) {
|
||||||
try self.send_request(from, method, bytes);
|
try self.send_request(from, method, bytes);
|
||||||
} else if (try m.match(.{ "RSP", tp.extract(&id), tp.extract(&bytes) })) {
|
} else if (try cbor.match(m.buf, .{ "RSP", tp.extract(&id), tp.extract(&bytes) })) {
|
||||||
try self.send_response(id, bytes);
|
try self.send_response(id, bytes);
|
||||||
} else if (try m.match(.{ "NTFY", tp.extract(&method), tp.extract(&bytes) })) {
|
} else if (try cbor.match(m.buf, .{ "NTFY", tp.extract(&method), tp.extract(&bytes) })) {
|
||||||
try self.send_notification(method, bytes);
|
try self.send_notification(method, bytes);
|
||||||
} else if (try m.match(.{"close"})) {
|
} else if (try cbor.match(m.buf, .{"close"})) {
|
||||||
self.write_log("### LSP close ###\n", .{});
|
self.write_log("### LSP close ###\n", .{});
|
||||||
try self.close();
|
try self.close();
|
||||||
} else if (try m.match(.{"term"})) {
|
} else if (try cbor.match(m.buf, .{"term"})) {
|
||||||
self.write_log("### LSP terminated ###\n", .{});
|
self.write_log("### LSP terminated ###\n", .{});
|
||||||
try self.term();
|
try self.term();
|
||||||
} else if (try m.match(.{ self.sp_tag, "stdout", tp.extract(&bytes) })) {
|
} else if (try cbor.match(m.buf, .{ self.sp_tag, "stdout", tp.extract(&bytes) })) {
|
||||||
try self.handle_output(bytes);
|
try self.handle_output(bytes);
|
||||||
} else if (try m.match(.{ self.sp_tag, "term", tp.extract(&err), tp.extract(&code) })) {
|
} else if (try cbor.match(m.buf, .{ self.sp_tag, "term", tp.extract(&err), tp.extract(&code) })) {
|
||||||
try self.handle_terminated(err, code);
|
try self.handle_terminated(err, code);
|
||||||
} else if (try m.match(.{ self.sp_tag, "stderr", tp.extract(&bytes) })) {
|
} else if (try cbor.match(m.buf, .{ self.sp_tag, "stderr", tp.extract(&bytes) })) {
|
||||||
self.write_log("{s}\n", .{bytes});
|
self.write_log("{s}\n", .{bytes});
|
||||||
} else if (try m.match(.{ "exit", "normal" })) {
|
} else if (try cbor.match(m.buf, .{ "exit", "normal" })) {
|
||||||
// self.write_log("### exit normal ###\n", .{});
|
// self.write_log("### exit normal ###\n", .{});
|
||||||
} else {
|
} else {
|
||||||
const e = tp.unexpected(m);
|
tp.unexpected(m) catch {};
|
||||||
self.write_log("{s}\n", .{tp.error_text()});
|
self.write_log("{s}\n", .{tp.error_text()});
|
||||||
return e;
|
return error.ExitUnexpected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_lsp_message(self: *Process, cb: []const u8) !void {
|
fn receive_lsp_message(self: *Process, cb: []const u8) Error!void {
|
||||||
var iter = cb;
|
var iter = cb;
|
||||||
|
|
||||||
const MsgMembers = struct {
|
const MsgMembers = struct {
|
||||||
|
@ -252,7 +254,7 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_output(self: *Process, bytes: []u8) ReceiveError!void {
|
fn handle_output(self: *Process, bytes: []u8) Error!void {
|
||||||
try self.recv_buf.appendSlice(bytes);
|
try self.recv_buf.appendSlice(bytes);
|
||||||
self.write_log("### RECV:\n{s}\n###\n", .{bytes});
|
self.write_log("### RECV:\n{s}\n###\n", .{bytes});
|
||||||
self.frame_message_recv() catch |e| {
|
self.frame_message_recv() catch |e| {
|
||||||
|
@ -261,15 +263,15 @@ const Process = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminated(self: *Process, err: []const u8, code: u32) tp.result {
|
fn handle_terminated(self: *Process, err: []const u8, code: u32) error{ExitNormal}!void {
|
||||||
const logger = log.logger("LSP");
|
const logger = log.logger("LSP");
|
||||||
logger.print("terminated: {s} {d}", .{ err, code });
|
logger.print("terminated: {s} {d}", .{ err, code });
|
||||||
self.write_log("### subprocess terminated {s} {d} ###\n", .{ err, code });
|
self.write_log("### subprocess terminated {s} {d} ###\n", .{ err, code });
|
||||||
try self.parent.send(.{ sp_tag, self.tag, "done" });
|
self.parent.send(.{ sp_tag, self.tag, "done" }) catch {};
|
||||||
return tp.exit_normal();
|
return error.ExitNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_request(self: *Process, from: tp.pid_ref, method: []const u8, params_cb: []const u8) ReceiveError!void {
|
fn send_request(self: *Process, from: tp.pid_ref, method: []const u8, params_cb: []const u8) Error!void {
|
||||||
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
||||||
|
|
||||||
const id = self.next_id;
|
const id = self.next_id;
|
||||||
|
@ -299,12 +301,12 @@ const Process = struct {
|
||||||
_ = try writer.write(json);
|
_ = try writer.write(json);
|
||||||
_ = try writer.write(terminator);
|
_ = try writer.write(terminator);
|
||||||
|
|
||||||
try sp.send(output.items);
|
sp.send(output.items) catch return error.SendFailed;
|
||||||
self.write_log("### SEND request:\n{s}\n###\n", .{output.items});
|
self.write_log("### SEND request:\n{s}\n###\n", .{output.items});
|
||||||
try self.requests.put(id, from.clone());
|
try self.requests.put(id, from.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_response(self: *Process, id: i32, result_cb: []const u8) !void {
|
fn send_response(self: *Process, id: i32, result_cb: []const u8) (error{Closed} || SendError || cbor.Error || cbor.JsonEncodeError)!void {
|
||||||
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
||||||
|
|
||||||
var msg = std.ArrayList(u8).init(self.allocator);
|
var msg = std.ArrayList(u8).init(self.allocator);
|
||||||
|
@ -329,11 +331,11 @@ const Process = struct {
|
||||||
_ = try writer.write(json);
|
_ = try writer.write(json);
|
||||||
_ = try writer.write(terminator);
|
_ = try writer.write(terminator);
|
||||||
|
|
||||||
try sp.send(output.items);
|
sp.send(output.items) catch return error.SendFailed;
|
||||||
self.write_log("### SEND response:\n{s}\n###\n", .{output.items});
|
self.write_log("### SEND response:\n{s}\n###\n", .{output.items});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_notification(self: *Process, method: []const u8, params_cb: []const u8) !void {
|
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;
|
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
||||||
|
|
||||||
const have_params = !(cbor.match(params_cb, cbor.null_) catch false);
|
const have_params = !(cbor.match(params_cb, cbor.null_) catch false);
|
||||||
|
@ -364,11 +366,11 @@ const Process = struct {
|
||||||
_ = try writer.write(json);
|
_ = try writer.write(json);
|
||||||
_ = try writer.write(terminator);
|
_ = try writer.write(terminator);
|
||||||
|
|
||||||
try sp.send(output.items);
|
sp.send(output.items) catch return error.SendFailed;
|
||||||
self.write_log("### SEND notification:\n{s}\n###\n", .{output.items});
|
self.write_log("### SEND notification:\n{s}\n###\n", .{output.items});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_message_recv(self: *Process) ReceiveError!void {
|
fn frame_message_recv(self: *Process) Error!void {
|
||||||
const sep = "\r\n\r\n";
|
const sep = "\r\n\r\n";
|
||||||
const headers_end = std.mem.indexOf(u8, self.recv_buf.items, sep) orelse return;
|
const headers_end = std.mem.indexOf(u8, self.recv_buf.items, sep) orelse return;
|
||||||
const headers_data = self.recv_buf.items[0..headers_end];
|
const headers_data = self.recv_buf.items[0..headers_end];
|
||||||
|
@ -386,7 +388,7 @@ const Process = struct {
|
||||||
if (rest.len > 0) return self.frame_message_recv();
|
if (rest.len > 0) return self.frame_message_recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_lsp_request(self: *Process, id: i32, method: []const u8, params: ?[]const u8) !void {
|
fn receive_lsp_request(self: *Process, id: i32, method: []const u8, params: ?[]const u8) Error!void {
|
||||||
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
||||||
defer if (json) |p| self.allocator.free(p);
|
defer if (json) |p| self.allocator.free(p);
|
||||||
self.write_log("### RECV req: {d}\nmethod: {s}\n{s}\n###\n", .{ id, method, json orelse "no params" });
|
self.write_log("### RECV req: {d}\nmethod: {s}\n{s}\n###\n", .{ id, method, json orelse "no params" });
|
||||||
|
@ -401,10 +403,10 @@ const Process = struct {
|
||||||
try cbor.writeValue(writer, method);
|
try cbor.writeValue(writer, method);
|
||||||
try cbor.writeValue(writer, id);
|
try cbor.writeValue(writer, id);
|
||||||
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
||||||
try self.parent.send_raw(.{ .buf = msg.items });
|
self.parent.send_raw(.{ .buf = msg.items }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_lsp_response(self: *Process, id: i32, result: ?[]const u8, err: ?[]const u8) !void {
|
fn receive_lsp_response(self: *Process, id: i32, result: ?[]const u8, err: ?[]const u8) Error!void {
|
||||||
const json = if (result) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
const json = if (result) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
||||||
defer if (json) |p| self.allocator.free(p);
|
defer if (json) |p| self.allocator.free(p);
|
||||||
const json_err = if (err) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
const json_err = if (err) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
||||||
|
@ -424,10 +426,10 @@ const Process = struct {
|
||||||
try cbor.writeValue(writer, "result");
|
try cbor.writeValue(writer, "result");
|
||||||
_ = try writer.write(result_);
|
_ = try writer.write(result_);
|
||||||
}
|
}
|
||||||
try from.send_raw(.{ .buf = msg.items });
|
from.send_raw(.{ .buf = msg.items }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_lsp_notification(self: *Process, method: []const u8, params: ?[]const u8) !void {
|
fn receive_lsp_notification(self: *Process, method: []const u8, params: ?[]const u8) Error!void {
|
||||||
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
||||||
defer if (json) |p| self.allocator.free(p);
|
defer if (json) |p| self.allocator.free(p);
|
||||||
self.write_log("### RECV notify:\nmethod: {s}\n{s}\n###\n", .{ method, json orelse "no params" });
|
self.write_log("### RECV notify:\nmethod: {s}\n{s}\n###\n", .{ method, json orelse "no params" });
|
||||||
|
@ -441,7 +443,7 @@ const Process = struct {
|
||||||
try cbor.writeValue(writer, "notify");
|
try cbor.writeValue(writer, "notify");
|
||||||
try cbor.writeValue(writer, method);
|
try cbor.writeValue(writer, method);
|
||||||
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
||||||
try self.parent.send_raw(.{ .buf = msg.items });
|
self.parent.send_raw(.{ .buf = msg.items }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_log(self: *Process, comptime format: []const u8, args: anytype) void {
|
fn write_log(self: *Process, comptime format: []const u8, args: anytype) void {
|
||||||
|
@ -455,7 +457,7 @@ const Headers = struct {
|
||||||
content_length: usize = 0,
|
content_length: usize = 0,
|
||||||
content_type: ?[]const u8 = null,
|
content_type: ?[]const u8 = null,
|
||||||
|
|
||||||
fn parse(buf_: []const u8) Process.ReceiveError!Headers {
|
fn parse(buf_: []const u8) Process.Error!Headers {
|
||||||
var buf = buf_;
|
var buf = buf_;
|
||||||
var ret: Headers = .{};
|
var ret: Headers = .{};
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -475,7 +477,7 @@ const Headers = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_one(self: *Headers, name: []const u8, value: []const u8) Process.ReceiveError!void {
|
fn parse_one(self: *Headers, name: []const u8, value: []const u8) Process.Error!void {
|
||||||
if (std.mem.eql(u8, "Content-Length", name)) {
|
if (std.mem.eql(u8, "Content-Length", name)) {
|
||||||
self.content_length = std.fmt.parseInt(@TypeOf(self.content_length), value, 10) catch |e| switch (e) {
|
self.content_length = std.fmt.parseInt(@TypeOf(self.content_length), value, 10) catch |e| switch (e) {
|
||||||
error.Overflow => return error.InvalidContentLength,
|
error.Overflow => return error.InvalidContentLength,
|
||||||
|
|
140
src/Project.zig
140
src/Project.zig
|
@ -29,7 +29,7 @@ const File = struct {
|
||||||
visited: bool = false,
|
visited: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, name: []const u8) error{OutOfMemory}!Self {
|
pub fn init(allocator: std.mem.Allocator, name: []const u8) OutOfMemoryError!Self {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.name = try allocator.dupe(u8, name),
|
.name = try allocator.dupe(u8, name),
|
||||||
|
@ -83,7 +83,7 @@ pub fn restore_state(self: *Self, data: []const u8) !void {
|
||||||
tp.extract(&row),
|
tp.extract(&row),
|
||||||
tp.extract(&col),
|
tp.extract(&col),
|
||||||
}) catch |e| switch (e) {
|
}) catch |e| switch (e) {
|
||||||
error.CborTooShort => return,
|
error.TooShort => return,
|
||||||
else => return e,
|
else => return e,
|
||||||
}) {
|
}) {
|
||||||
self.longest_file_path = @max(self.longest_file_path, path.len);
|
self.longest_file_path = @max(self.longest_file_path, path.len);
|
||||||
|
@ -96,7 +96,9 @@ pub fn restore_state(self: *Self, data: []const u8) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_lsp(self: *Self, language_server: []const u8) !LSP {
|
pub const GetLspError = (error{ ThespianSpawnFailed, Timeout, InvalidArgument } || OutOfMemoryError || SendError || cbor.Error);
|
||||||
|
|
||||||
|
fn get_lsp(self: *Self, language_server: []const u8) GetLspError!LSP {
|
||||||
if (self.language_servers.get(language_server)) |lsp| return lsp;
|
if (self.language_servers.get(language_server)) |lsp| return lsp;
|
||||||
const logger = log.logger("lsp");
|
const logger = log.logger("lsp");
|
||||||
errdefer |e| logger.print_err("get_lsp", "failed to initialize LSP: {s} -> {any}", .{ fmt_lsp_name_func(language_server), e });
|
errdefer |e| logger.print_err("get_lsp", "failed to initialize LSP: {s} -> {any}", .{ fmt_lsp_name_func(language_server), e });
|
||||||
|
@ -113,14 +115,16 @@ fn get_lsp(self: *Self, language_server: []const u8) !LSP {
|
||||||
return lsp;
|
return lsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_file_lsp(self: *Self, file_path: []const u8) !LSP {
|
pub const GetFileLspError = (GetLspError || error{NoLsp});
|
||||||
|
|
||||||
|
fn get_file_lsp(self: *Self, file_path: []const u8) GetFileLspError!LSP {
|
||||||
const logger = log.logger("lsp");
|
const logger = log.logger("lsp");
|
||||||
errdefer logger.print_err("get_file_lsp", "no LSP found for file: {s} ({s})", .{
|
errdefer logger.print_err("get_file_lsp", "no LSP found for file: {s} ({s})", .{
|
||||||
std.fmt.fmtSliceEscapeLower(file_path),
|
std.fmt.fmtSliceEscapeLower(file_path),
|
||||||
self.name,
|
self.name,
|
||||||
});
|
});
|
||||||
const lsp = self.file_language_server.get(file_path) orelse return tp.exit("no language server");
|
const lsp = self.file_language_server.get(file_path) orelse return error.NoLsp;
|
||||||
if (lsp.pid.expired()) return tp.exit("no language server");
|
if (lsp.pid.expired()) return error.NoLsp;
|
||||||
return lsp;
|
return lsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,20 +149,20 @@ pub fn sort_files_by_mtime(self: *Self) void {
|
||||||
std.mem.sort(File, self.files.items, {}, less_fn);
|
std.mem.sort(File, self.files.items, {}, less_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_most_recent_file(self: *Self, from: tp.pid_ref) error{ OutOfMemory, Exit }!void {
|
pub fn request_most_recent_file(self: *Self, from: tp.pid_ref) SendError!void {
|
||||||
const file_path = if (self.files.items.len > 0) self.files.items[0].path else null;
|
const file_path = if (self.files.items.len > 0) self.files.items[0].path else null;
|
||||||
try from.send(.{file_path});
|
from.send(.{file_path}) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) error{ OutOfMemory, Exit }!void {
|
pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) SendError!void {
|
||||||
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, "" }) catch {};
|
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, "" }) catch {};
|
||||||
for (self.files.items, 0..) |file, i| {
|
for (self.files.items, 0..) |file, i| {
|
||||||
try from.send(.{ "PRJ", "recent", self.longest_file_path, file.path });
|
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path }) catch return error.SendFailed;
|
||||||
if (i >= max) return;
|
if (i >= max) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) error{ OutOfMemory, Exit }!usize {
|
fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) (OutOfMemoryError || SendError)!usize {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query }) catch {};
|
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query }) catch {};
|
||||||
for (self.files.items) |file| {
|
for (self.files.items) |file| {
|
||||||
|
@ -168,7 +172,7 @@ fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: [
|
||||||
defer self.allocator.free(matches);
|
defer self.allocator.free(matches);
|
||||||
var n: usize = 0;
|
var n: usize = 0;
|
||||||
while (n < query.len) : (n += 1) matches[n] = idx + n;
|
while (n < query.len) : (n += 1) matches[n] = idx + n;
|
||||||
try from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, matches });
|
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, matches }) catch return error.SendFailed;
|
||||||
i += 1;
|
i += 1;
|
||||||
if (i >= max) return i;
|
if (i >= max) return i;
|
||||||
}
|
}
|
||||||
|
@ -176,7 +180,7 @@ fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: [
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) error{ OutOfMemory, Exit }!usize {
|
pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) (OutOfMemoryError || SendError)!usize {
|
||||||
if (query.len < 3)
|
if (query.len < 3)
|
||||||
return self.simple_query_recent_files(from, max, query);
|
return self.simple_query_recent_files(from, max, query);
|
||||||
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query }) catch {};
|
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query }) catch {};
|
||||||
|
@ -216,16 +220,16 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []co
|
||||||
std.mem.sort(Match, matches.items, {}, less_fn);
|
std.mem.sort(Match, matches.items, {}, less_fn);
|
||||||
|
|
||||||
for (matches.items[0..@min(max, matches.items.len)]) |match|
|
for (matches.items[0..@min(max, matches.items.len)]) |match|
|
||||||
try from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.matches });
|
from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.matches }) catch return error.SendFailed;
|
||||||
return @min(max, matches.items.len);
|
return @min(max, matches.items.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_pending_file(self: *Self, file_path: []const u8, mtime: i128) error{OutOfMemory}!void {
|
pub fn add_pending_file(self: *Self, file_path: []const u8, mtime: i128) OutOfMemoryError!void {
|
||||||
self.longest_file_path = @max(self.longest_file_path, file_path.len);
|
self.longest_file_path = @max(self.longest_file_path, file_path.len);
|
||||||
(try self.pending.addOne()).* = .{ .path = try self.allocator.dupe(u8, file_path), .mtime = mtime };
|
(try self.pending.addOne()).* = .{ .path = try self.allocator.dupe(u8, file_path), .mtime = mtime };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge_pending_files(self: *Self) error{OutOfMemory}!void {
|
pub fn merge_pending_files(self: *Self) OutOfMemoryError!void {
|
||||||
defer self.sort_files_by_mtime();
|
defer self.sort_files_by_mtime();
|
||||||
const existing = try self.files.toOwnedSlice();
|
const existing = try self.files.toOwnedSlice();
|
||||||
self.files = self.pending;
|
self.files = self.pending;
|
||||||
|
@ -237,12 +241,12 @@ pub fn merge_pending_files(self: *Self) error{OutOfMemory}!void {
|
||||||
self.allocator.free(existing);
|
self.allocator.free(existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_mru(self: *Self, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn update_mru(self: *Self, file_path: []const u8, row: usize, col: usize) OutOfMemoryError!void {
|
||||||
defer self.sort_files_by_mtime();
|
defer self.sort_files_by_mtime();
|
||||||
try self.update_mru_internal(file_path, std.time.nanoTimestamp(), row, col);
|
try self.update_mru_internal(file_path, std.time.nanoTimestamp(), row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usize, col: usize) !void {
|
fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usize, col: usize) OutOfMemoryError!void {
|
||||||
for (self.files.items) |*file| {
|
for (self.files.items) |*file| {
|
||||||
if (!std.mem.eql(u8, file.path, file_path)) continue;
|
if (!std.mem.eql(u8, file.path, file_path)) continue;
|
||||||
file.mtime = mtime;
|
file.mtime = mtime;
|
||||||
|
@ -269,16 +273,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) !void {
|
pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) SendError!void {
|
||||||
for (self.files.items) |*file| {
|
for (self.files.items) |*file| {
|
||||||
if (!std.mem.eql(u8, file.path, file_path)) continue;
|
if (!std.mem.eql(u8, file.path, file_path)) continue;
|
||||||
if (file.row != 0)
|
if (file.row != 0)
|
||||||
try from.send(.{ "cmd", "goto_line_and_column", .{ file.row + 1, file.col + 1 } });
|
from.send(.{ "cmd", "goto_line_and_column", .{ file.row + 1, file.col + 1 } }) catch return error.SendFailed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_open(self: *Self, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) !void {
|
pub fn did_open(self: *Self, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) GetLspError!void {
|
||||||
self.update_mru(file_path, 0, 0) catch {};
|
self.update_mru(file_path, 0, 0) catch {};
|
||||||
const lsp = try self.get_lsp(language_server);
|
const lsp = try self.get_lsp(language_server);
|
||||||
if (!self.file_language_server.contains(file_path)) {
|
if (!self.file_language_server.contains(file_path)) {
|
||||||
|
@ -292,7 +296,7 @@ pub fn did_open(self: *Self, file_path: []const u8, file_type: []const u8, langu
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_change(self: *Self, file_path: []const u8, version: usize, root_dst_addr: usize, root_src_addr: usize) !void {
|
pub fn did_change(self: *Self, file_path: []const u8, version: usize, root_dst_addr: usize, root_src_addr: usize) GetFileLspError!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_file_lsp(file_path);
|
||||||
const uri = try self.make_URI(file_path);
|
const uri = try self.make_URI(file_path);
|
||||||
defer self.allocator.free(uri);
|
defer self.allocator.free(uri);
|
||||||
|
@ -404,23 +408,25 @@ pub fn did_close(self: *Self, file_path: []const u8) !void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void {
|
||||||
return self.send_goto_request(from, file_path, row, col, "textDocument/definition");
|
return self.send_goto_request(from, file_path, row, col, "textDocument/definition");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_declaration(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_declaration(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void {
|
||||||
return self.send_goto_request(from, file_path, row, col, "textDocument/declaration");
|
return self.send_goto_request(from, file_path, row, col, "textDocument/declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_implementation(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_implementation(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void {
|
||||||
return self.send_goto_request(from, file_path, row, col, "textDocument/implementation");
|
return self.send_goto_request(from, file_path, row, col, "textDocument/implementation");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_type_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_type_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void {
|
||||||
return self.send_goto_request(from, file_path, row, col, "textDocument/typeDefinition");
|
return self.send_goto_request(from, file_path, row, col, "textDocument/typeDefinition");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_goto_request(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize, method: []const u8) !void {
|
pub const SendGotoRequestError = (SendError || InvalidMessageError || GetFileLspError || 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_file_lsp(file_path);
|
const lsp = try self.get_file_lsp(file_path);
|
||||||
const uri = try self.make_URI(file_path);
|
const uri = try self.make_URI(file_path);
|
||||||
defer self.allocator.free(uri);
|
defer self.allocator.free(uri);
|
||||||
|
@ -431,20 +437,24 @@ fn send_goto_request(self: *Self, from: tp.pid_ref, file_path: []const u8, row:
|
||||||
defer self.allocator.free(response.buf);
|
defer self.allocator.free(response.buf);
|
||||||
var link: []const u8 = undefined;
|
var link: []const u8 = undefined;
|
||||||
var locations: []const u8 = undefined;
|
var locations: []const u8 = undefined;
|
||||||
if (try response.match(.{ "child", tp.string, "result", tp.array })) {
|
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.array })) {
|
||||||
if (try response.match(.{ tp.any, tp.any, tp.any, .{tp.extract_cbor(&link)} })) {
|
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, .{tp.extract_cbor(&link)} })) {
|
||||||
try self.navigate_to_location_link(from, link);
|
try self.navigate_to_location_link(from, link);
|
||||||
} else if (try response.match(.{ tp.any, tp.any, tp.any, tp.extract_cbor(&locations) })) {
|
} else if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&locations) })) {
|
||||||
try self.send_reference_list(from, locations);
|
try self.send_reference_list(from, locations);
|
||||||
}
|
}
|
||||||
} else if (try response.match(.{ "child", tp.string, "result", tp.null_ })) {
|
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||||
return;
|
return;
|
||||||
} else if (try response.match(.{ "child", tp.string, "result", tp.extract_cbor(&link) })) {
|
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&link) })) {
|
||||||
try self.navigate_to_location_link(from, link);
|
try self.navigate_to_location_link(from, link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const u8) !void {
|
const OutOfMemoryError = error{OutOfMemory};
|
||||||
|
pub const SendError = error{SendFailed};
|
||||||
|
pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI };
|
||||||
|
|
||||||
|
fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const u8) (SendError || InvalidMessageError || cbor.Error)!void {
|
||||||
var iter = location_link;
|
var iter = location_link;
|
||||||
var targetUri: ?[]const u8 = null;
|
var targetUri: ?[]const u8 = null;
|
||||||
var targetRange: ?Range = null;
|
var targetRange: ?Range = null;
|
||||||
|
@ -480,7 +490,7 @@ fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (targetSelectionRange) |sel| {
|
if (targetSelectionRange) |sel| {
|
||||||
try from.send(.{ "cmd", "navigate", .{
|
from.send(.{ "cmd", "navigate", .{
|
||||||
.file = file_path,
|
.file = file_path,
|
||||||
.goto = .{
|
.goto = .{
|
||||||
targetRange.?.start.line + 1,
|
targetRange.?.start.line + 1,
|
||||||
|
@ -490,19 +500,19 @@ fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const
|
||||||
sel.end.line,
|
sel.end.line,
|
||||||
sel.end.character,
|
sel.end.character,
|
||||||
},
|
},
|
||||||
} });
|
} }) catch return error.SendFailed;
|
||||||
} else {
|
} else {
|
||||||
try from.send(.{ "cmd", "navigate", .{
|
from.send(.{ "cmd", "navigate", .{
|
||||||
.file = file_path,
|
.file = file_path,
|
||||||
.goto = .{
|
.goto = .{
|
||||||
targetRange.?.start.line + 1,
|
targetRange.?.start.line + 1,
|
||||||
targetRange.?.start.character + 1,
|
targetRange.?.start.character + 1,
|
||||||
},
|
},
|
||||||
} });
|
} }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_file_lsp(file_path);
|
||||||
const uri = try self.make_URI(file_path);
|
const uri = try self.make_URI(file_path);
|
||||||
defer self.allocator.free(uri);
|
defer self.allocator.free(uri);
|
||||||
|
@ -515,14 +525,14 @@ pub fn references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usi
|
||||||
});
|
});
|
||||||
defer self.allocator.free(response.buf);
|
defer self.allocator.free(response.buf);
|
||||||
var locations: []const u8 = undefined;
|
var locations: []const u8 = undefined;
|
||||||
if (try response.match(.{ "child", tp.string, "result", tp.null_ })) {
|
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||||
return;
|
return;
|
||||||
} else if (try response.match(.{ "child", tp.string, "result", tp.extract_cbor(&locations) })) {
|
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&locations) })) {
|
||||||
try self.send_reference_list(from, locations);
|
try self.send_reference_list(from, locations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8) !void {
|
fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8) (InvalidMessageError || SendError || GetLineOfFileError || cbor.Error)!void {
|
||||||
defer to.send(.{ "REF", "done" }) catch {};
|
defer to.send(.{ "REF", "done" }) catch {};
|
||||||
var iter = locations;
|
var iter = locations;
|
||||||
var len = try cbor.decodeArrayHeader(&iter);
|
var len = try cbor.decodeArrayHeader(&iter);
|
||||||
|
@ -536,7 +546,7 @@ fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8) !void
|
||||||
log.logger("lsp").print("found {d} references", .{count});
|
log.logger("lsp").print("found {d} references", .{count});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_reference(self: *Self, to: tp.pid_ref, location: []const u8) !void {
|
fn send_reference(self: *Self, to: tp.pid_ref, location: []const u8) (InvalidMessageError || SendError || GetLineOfFileError || cbor.Error)!void {
|
||||||
var iter = location;
|
var iter = location;
|
||||||
var targetUri: ?[]const u8 = null;
|
var targetUri: ?[]const u8 = null;
|
||||||
var targetRange: ?Range = null;
|
var targetRange: ?Range = null;
|
||||||
|
@ -577,7 +587,7 @@ fn send_reference(self: *Self, to: tp.pid_ref, location: []const u8) !void {
|
||||||
file_path[self.name.len + 1 ..]
|
file_path[self.name.len + 1 ..]
|
||||||
else
|
else
|
||||||
file_path;
|
file_path;
|
||||||
try to.send(.{
|
to.send(.{
|
||||||
"REF",
|
"REF",
|
||||||
file_path_,
|
file_path_,
|
||||||
targetRange.?.start.line + 1,
|
targetRange.?.start.line + 1,
|
||||||
|
@ -585,10 +595,10 @@ fn send_reference(self: *Self, to: tp.pid_ref, location: []const u8) !void {
|
||||||
targetRange.?.end.line + 1,
|
targetRange.?.end.line + 1,
|
||||||
targetRange.?.end.character,
|
targetRange.?.end.character,
|
||||||
line,
|
line,
|
||||||
});
|
}) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (SendError || GetFileLspError)!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_file_lsp(file_path);
|
||||||
const uri = try self.make_URI(file_path);
|
const uri = try self.make_URI(file_path);
|
||||||
defer self.allocator.free(uri);
|
defer self.allocator.free(uri);
|
||||||
|
@ -599,7 +609,7 @@ pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize,
|
||||||
defer self.allocator.free(response.buf);
|
defer self.allocator.free(response.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
|
pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (SendError || InvalidMessageError || GetFileLspError || cbor.Error)!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_file_lsp(file_path);
|
||||||
const uri = try self.make_URI(file_path);
|
const uri = try self.make_URI(file_path);
|
||||||
defer self.allocator.free(uri);
|
defer self.allocator.free(uri);
|
||||||
|
@ -611,14 +621,14 @@ pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, c
|
||||||
});
|
});
|
||||||
defer self.allocator.free(response.buf);
|
defer self.allocator.free(response.buf);
|
||||||
var result: []const u8 = undefined;
|
var result: []const u8 = undefined;
|
||||||
if (try response.match(.{ "child", tp.string, "result", tp.null_ })) {
|
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||||
try send_content_msg_empty(from, "hover", file_path, row, col);
|
try send_content_msg_empty(from, "hover", file_path, row, col);
|
||||||
} else if (try response.match(.{ "child", tp.string, "result", tp.extract_cbor(&result) })) {
|
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&result) })) {
|
||||||
try self.send_hover(from, file_path, row, col, result);
|
try self.send_hover(from, file_path, row, col, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_hover(self: *Self, to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) !void {
|
fn send_hover(self: *Self, to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (SendError || InvalidMessageError || cbor.Error)!void {
|
||||||
var iter = result;
|
var iter = result;
|
||||||
var len = cbor.decodeMapHeader(&iter) catch return;
|
var len = cbor.decodeMapHeader(&iter) catch return;
|
||||||
var contents: []const u8 = "";
|
var contents: []const u8 = "";
|
||||||
|
@ -698,19 +708,19 @@ fn send_content_msg(
|
||||||
kind: []const u8,
|
kind: []const u8,
|
||||||
content: []const u8,
|
content: []const u8,
|
||||||
range: ?Range,
|
range: ?Range,
|
||||||
) !void {
|
) SendError!void {
|
||||||
const r = range orelse Range{
|
const r = range orelse Range{
|
||||||
.start = .{ .line = row, .character = col },
|
.start = .{ .line = row, .character = col },
|
||||||
.end = .{ .line = row, .character = col },
|
.end = .{ .line = row, .character = col },
|
||||||
};
|
};
|
||||||
return try to.send(.{ tag, file_path, kind, content, r.start.line, r.start.character, r.end.line, r.end.character });
|
to.send(.{ tag, file_path, kind, content, r.start.line, r.start.character, r.end.line, r.end.character }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_content_msg_empty(to: tp.pid_ref, tag: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn send_content_msg_empty(to: tp.pid_ref, tag: []const u8, file_path: []const u8, row: usize, col: usize) SendError!void {
|
||||||
return send_content_msg(to, tag, file_path, row, col, "plaintext", "", null);
|
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) !void {
|
pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) (InvalidMessageError || SendError || cbor.Error)!void {
|
||||||
var uri: ?[]const u8 = null;
|
var uri: ?[]const u8 = null;
|
||||||
var diagnostics: []const u8 = &.{};
|
var diagnostics: []const u8 = &.{};
|
||||||
var iter = params_cb;
|
var iter = params_cb;
|
||||||
|
@ -728,7 +738,7 @@ pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) !
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri == null) return error.InvalidMessageField;
|
if (uri == null) return error.InvalidMessageField;
|
||||||
if (!std.mem.eql(u8, uri.?[0..7], "file://")) return error.InvalidURI;
|
if (!std.mem.eql(u8, uri.?[0..7], "file://")) return error.InvalidTargetURI;
|
||||||
var file_path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
var file_path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
const file_path = std.Uri.percentDecodeBackwards(&file_path_buf, uri.?[7..]);
|
const file_path = std.Uri.percentDecodeBackwards(&file_path_buf, uri.?[7..]);
|
||||||
|
|
||||||
|
@ -744,7 +754,7 @@ pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) !
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic: []const u8) !void {
|
fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic: []const u8) (InvalidMessageError || SendError || cbor.Error)!void {
|
||||||
var source: []const u8 = "unknown";
|
var source: []const u8 = "unknown";
|
||||||
var code: []const u8 = "none";
|
var code: []const u8 = "none";
|
||||||
var message: []const u8 = "empty";
|
var message: []const u8 = "empty";
|
||||||
|
@ -772,7 +782,7 @@ fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (range == null) return error.InvalidMessageField;
|
if (range == null) return error.InvalidMessageField;
|
||||||
try to.send(.{ "cmd", "add_diagnostic", .{
|
to.send(.{ "cmd", "add_diagnostic", .{
|
||||||
file_path,
|
file_path,
|
||||||
source,
|
source,
|
||||||
code,
|
code,
|
||||||
|
@ -782,11 +792,11 @@ fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic:
|
||||||
range.?.start.character,
|
range.?.start.character,
|
||||||
range.?.end.line,
|
range.?.end.line,
|
||||||
range.?.end.character,
|
range.?.end.character,
|
||||||
} });
|
} }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_clear_diagnostics(_: *Self, to: tp.pid_ref, file_path: []const u8) !void {
|
fn send_clear_diagnostics(_: *Self, to: tp.pid_ref, file_path: []const u8) SendError!void {
|
||||||
try to.send(.{ "cmd", "clear_diagnostics", .{file_path} });
|
to.send(.{ "cmd", "clear_diagnostics", .{file_path} }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Range = struct { start: Position, end: Position };
|
const Range = struct { start: Position, end: Position };
|
||||||
|
@ -860,19 +870,19 @@ pub fn show_message(_: *Self, _: tp.pid_ref, params_cb: []const u8) !void {
|
||||||
logger.print("{s}", .{msg});
|
logger.print("{s}", .{msg});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_capability(self: *Self, from: tp.pid_ref, id: i32, params_cb: []const u8) !void {
|
pub fn register_capability(self: *Self, from: tp.pid_ref, id: i32, params_cb: []const u8) (OutOfMemoryError || SendError)!void {
|
||||||
_ = params_cb;
|
_ = params_cb;
|
||||||
return self.send_lsp_response(from, id, null);
|
return self.send_lsp_response(from, id, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_lsp_response(self: *Self, from: tp.pid_ref, id: i32, result: anytype) !void {
|
pub fn send_lsp_response(self: *Self, from: tp.pid_ref, id: i32, result: anytype) (OutOfMemoryError || SendError)!void {
|
||||||
var cb = std.ArrayList(u8).init(self.allocator);
|
var cb = std.ArrayList(u8).init(self.allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
try cbor.writeValue(cb.writer(), result);
|
try cbor.writeValue(cb.writer(), result);
|
||||||
return from.send(.{ "RSP", id, cb.items });
|
from.send(.{ "RSP", id, cb.items }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8) !tp.message {
|
fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8) (OutOfMemoryError || SendError)!tp.message {
|
||||||
return lsp.send_request(self.allocator, "initialize", .{
|
return lsp.send_request(self.allocator, "initialize", .{
|
||||||
.processId = if (builtin.os.tag == .linux) std.os.linux.getpid() else null,
|
.processId = if (builtin.os.tag == .linux) std.os.linux.getpid() else null,
|
||||||
.rootPath = project_path,
|
.rootPath = project_path,
|
||||||
|
@ -1198,7 +1208,9 @@ fn format_lsp_name_func(
|
||||||
|
|
||||||
const eol = '\n';
|
const eol = '\n';
|
||||||
|
|
||||||
fn get_line_of_file(self: *Self, allocator: std.mem.Allocator, file_path: []const u8, line_: usize) ![]const u8 {
|
const GetLineOfFileError = (OutOfMemoryError || std.fs.File.OpenError || std.fs.File.Reader.Error);
|
||||||
|
|
||||||
|
fn get_line_of_file(self: *Self, allocator: std.mem.Allocator, file_path: []const u8, line_: usize) GetLineOfFileError![]const u8 {
|
||||||
const line = line_ + 1;
|
const line = line_ + 1;
|
||||||
const file = try std.fs.cwd().openFile(file_path, .{ .mode = .read_only });
|
const file = try std.fs.cwd().openFile(file_path, .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
|
@ -5,6 +5,7 @@ const log = @import("log");
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
const FileType = @import("syntax").FileType;
|
const FileType = @import("syntax").FileType;
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const Project = @import("Project.zig");
|
const Project = @import("Project.zig");
|
||||||
|
|
||||||
|
@ -14,12 +15,25 @@ const Self = @This();
|
||||||
const module_name = @typeName(Self);
|
const module_name = @typeName(Self);
|
||||||
const request_timeout = std.time.ns_per_s * 5;
|
const request_timeout = std.time.ns_per_s * 5;
|
||||||
|
|
||||||
pub fn get() !Self {
|
pub const ProjectError = error{NoProject};
|
||||||
|
|
||||||
|
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
||||||
|
const OutOfMemoryError = error{OutOfMemory};
|
||||||
|
const SendError = (SpawnError || error{SendFailed});
|
||||||
|
const FileSystemError = error{FileSystem};
|
||||||
|
const SetCwdError = if (builtin.os.tag == .windows) error{UnrecognizedVolume} else error{};
|
||||||
|
const CallError = tp.CallError;
|
||||||
|
|
||||||
|
pub fn get() SpawnError!Self {
|
||||||
const pid = tp.env.get().proc(module_name);
|
const pid = tp.env.get().proc(module_name);
|
||||||
return if (pid.expired()) create() else .{ .pid = pid };
|
return if (pid.expired()) create() else .{ .pid = pid };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create() !Self {
|
fn send(message: anytype) SendError!void {
|
||||||
|
return (try get()).pid.send(message) catch error.SendFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create() SpawnError!Self {
|
||||||
const pid = try Process.create();
|
const pid = try Process.create();
|
||||||
defer pid.deinit();
|
defer pid.deinit();
|
||||||
tp.env.get().proc_set(module_name, pid.ref());
|
tp.env.get().proc_set(module_name, pid.ref());
|
||||||
|
@ -35,142 +49,142 @@ pub fn shutdown() void {
|
||||||
pid.send(.{"shutdown"}) catch {};
|
pid.send(.{"shutdown"}) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(rel_project_directory: []const u8) !void {
|
pub fn open(rel_project_directory: []const u8) (SpawnError || FileSystemError || SendError || std.fs.File.OpenError || SetCwdError)!void {
|
||||||
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
const project_directory = std.fs.cwd().realpath(rel_project_directory, &path_buf) catch "(none)";
|
const project_directory = std.fs.cwd().realpath(rel_project_directory, &path_buf) catch "(none)";
|
||||||
var dir = try std.fs.openDirAbsolute(project_directory, .{});
|
var dir = try std.fs.openDirAbsolute(project_directory, .{});
|
||||||
try dir.setAsCwd();
|
try dir.setAsCwd();
|
||||||
dir.close();
|
dir.close();
|
||||||
tp.env.get().str_set("project", project_directory);
|
tp.env.get().str_set("project", project_directory);
|
||||||
return (try get()).pid.send(.{ "open", project_directory });
|
return send(.{ "open", project_directory });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_most_recent_file(allocator: std.mem.Allocator) !?[]const u8 {
|
pub fn request_most_recent_file(allocator: std.mem.Allocator) (CallError || ProjectError || cbor.Error)!?[]const u8 {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
const rsp = try (try get()).pid.call(allocator, request_timeout, .{ "request_most_recent_file", project });
|
const rsp = try (try get()).pid.call(allocator, request_timeout, .{ "request_most_recent_file", project });
|
||||||
defer allocator.free(rsp.buf);
|
defer allocator.free(rsp.buf);
|
||||||
var file_path: []const u8 = undefined;
|
var file_path: []const u8 = undefined;
|
||||||
return if (try rsp.match(.{tp.extract(&file_path)})) try allocator.dupe(u8, file_path) else null;
|
return if (try cbor.match(rsp.buf, .{tp.extract(&file_path)})) try allocator.dupe(u8, file_path) else null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_recent_files(max: usize) !void {
|
pub fn request_recent_files(max: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "request_recent_files", project, max });
|
return send(.{ "request_recent_files", project, max });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_recent_projects(allocator: std.mem.Allocator) !tp.message {
|
pub fn request_recent_projects(allocator: std.mem.Allocator) (ProjectError || CallError)!tp.message {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
return (try get()).pid.call(allocator, request_timeout, .{ "request_recent_projects", project });
|
return (try get()).pid.call(allocator, request_timeout, .{ "request_recent_projects", project });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_recent_files(max: usize, query: []const u8) !void {
|
pub fn query_recent_files(max: usize, query: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "query_recent_files", project, max, query });
|
return send(.{ "query_recent_files", project, max, query });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_path_files(max: usize, path: []const u8) !void {
|
pub fn request_path_files(max: usize, path: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "request_path_files", project, max, path });
|
return send(.{ "request_path_files", project, max, path });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_open(file_path: []const u8, file_type: *const FileType, version: usize, text: []const u8) !void {
|
pub fn did_open(file_path: []const u8, file_type: *const FileType, version: usize, text: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
const text_ptr: usize = if (text.len > 0) @intFromPtr(text.ptr) else 0;
|
const text_ptr: usize = if (text.len > 0) @intFromPtr(text.ptr) else 0;
|
||||||
return (try get()).pid.send(.{ "did_open", project, file_path, file_type.name, file_type.language_server, version, text_ptr, text.len });
|
return send(.{ "did_open", project, file_path, file_type.name, file_type.language_server, version, text_ptr, text.len });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_change(file_path: []const u8, version: usize, root_dst: usize, root_src: usize) !void {
|
pub fn did_change(file_path: []const u8, version: usize, root_dst: usize, root_src: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "did_change", project, file_path, version, root_dst, root_src });
|
return send(.{ "did_change", project, file_path, version, root_dst, root_src });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_save(file_path: []const u8) !void {
|
pub fn did_save(file_path: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "did_save", project, file_path });
|
return send(.{ "did_save", project, file_path });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_close(file_path: []const u8) !void {
|
pub fn did_close(file_path: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "did_close", project, file_path });
|
return send(.{ "did_close", project, file_path });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_definition(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_definition(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "goto_definition", project, file_path, row, col });
|
return send(.{ "goto_definition", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_declaration(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_declaration(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "goto_declaration", project, file_path, row, col });
|
return send(.{ "goto_declaration", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_implementation(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_implementation(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "goto_implementation", project, file_path, row, col });
|
return send(.{ "goto_implementation", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_type_definition(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn goto_type_definition(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "goto_type_definition", project, file_path, row, col });
|
return send(.{ "goto_type_definition", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn references(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn references(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "references", project, file_path, row, col });
|
return send(.{ "references", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn completion(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn completion(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "completion", project, file_path, row, col });
|
return send(.{ "completion", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hover(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn hover(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "hover", project, file_path, row, col });
|
return send(.{ "hover", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_mru(file_path: []const u8, row: usize, col: usize) !void {
|
pub fn update_mru(file_path: []const u8, row: usize, col: usize) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "update_mru", project, file_path, row, col });
|
return send(.{ "update_mru", project, file_path, row, col });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mru_position(file_path: []const u8) !void {
|
pub fn get_mru_position(file_path: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return tp.exit("No project");
|
return error.NoProject;
|
||||||
return (try get()).pid.send(.{ "get_mru_position", project, file_path });
|
return send(.{ "get_mru_position", project, file_path });
|
||||||
}
|
}
|
||||||
|
|
||||||
const Process = struct {
|
const Process = struct {
|
||||||
|
@ -181,6 +195,9 @@ const Process = struct {
|
||||||
projects: ProjectsMap,
|
projects: ProjectsMap,
|
||||||
walker: ?tp.pid = null,
|
walker: ?tp.pid = null,
|
||||||
|
|
||||||
|
const InvalidArgumentError = error{InvalidArgument};
|
||||||
|
const UnsupportedError = error{Unsupported};
|
||||||
|
|
||||||
const Receiver = tp.Receiver(*Process);
|
const Receiver = tp.Receiver(*Process);
|
||||||
const ProjectsMap = std.StringHashMap(*Project);
|
const ProjectsMap = std.StringHashMap(*Project);
|
||||||
const RecentProject = struct {
|
const RecentProject = struct {
|
||||||
|
@ -188,7 +205,7 @@ const Process = struct {
|
||||||
last_used: i128,
|
last_used: i128,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn create() !tp.pid {
|
fn create() SpawnError!tp.pid {
|
||||||
const allocator = std.heap.c_allocator;
|
const allocator = std.heap.c_allocator;
|
||||||
const self = try allocator.create(Process);
|
const self = try allocator.create(Process);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
|
@ -221,14 +238,17 @@ const Process = struct {
|
||||||
|
|
||||||
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
||||||
errdefer self.deinit();
|
errdefer self.deinit();
|
||||||
self.receive_safe(from, m) catch |e| {
|
return self.receive_safe(from, m) catch |e| switch (e) {
|
||||||
if (std.mem.eql(u8, "normal", tp.error_text()))
|
error.ExitNormal => tp.exit_normal(),
|
||||||
return e;
|
else => blk: {
|
||||||
self.logger.err("receive", tp.exit_error(e, @errorReturnTrace()));
|
const err = tp.exit_error(e, @errorReturnTrace());
|
||||||
|
self.logger.err("receive", err);
|
||||||
|
break :blk err;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) !void {
|
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) (error{ExitNormal} || SendError || cbor.Error)!void {
|
||||||
var project_directory: []const u8 = undefined;
|
var project_directory: []const u8 = undefined;
|
||||||
var path: []const u8 = undefined;
|
var path: []const u8 = undefined;
|
||||||
var query: []const u8 = undefined;
|
var query: []const u8 = undefined;
|
||||||
|
@ -249,77 +269,77 @@ const Process = struct {
|
||||||
var root_dst: usize = 0;
|
var root_dst: usize = 0;
|
||||||
var root_src: usize = 0;
|
var root_src: usize = 0;
|
||||||
|
|
||||||
if (try m.match(.{ "walk_tree_entry", tp.extract(&project_directory), tp.extract(&path), tp.extract(&high), tp.extract(&low) })) {
|
if (try cbor.match(m.buf, .{ "walk_tree_entry", tp.extract(&project_directory), tp.extract(&path), tp.extract(&high), tp.extract(&low) })) {
|
||||||
const mtime = (@as(i128, @intCast(high)) << 64) | @as(i128, @intCast(low));
|
const mtime = (@as(i128, @intCast(high)) << 64) | @as(i128, @intCast(low));
|
||||||
if (self.projects.get(project_directory)) |project|
|
if (self.projects.get(project_directory)) |project|
|
||||||
project.add_pending_file(
|
project.add_pending_file(
|
||||||
path,
|
path,
|
||||||
mtime,
|
mtime,
|
||||||
) catch |e| self.logger.err("walk_tree_entry", e);
|
) catch |e| self.logger.err("walk_tree_entry", e);
|
||||||
} else if (try m.match(.{ "walk_tree_done", tp.extract(&project_directory) })) {
|
} else if (try cbor.match(m.buf, .{ "walk_tree_done", tp.extract(&project_directory) })) {
|
||||||
if (self.walker) |pid| pid.deinit();
|
if (self.walker) |pid| pid.deinit();
|
||||||
self.walker = null;
|
self.walker = null;
|
||||||
self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
|
} else if (try cbor.match(m.buf, .{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
|
||||||
self.dispatch_notify(project_directory, language_server, method, params_cb) catch |e| return self.logger.err("lsp-handling", e);
|
self.dispatch_notify(project_directory, language_server, method, params_cb) catch |e| return self.logger.err("lsp-handling", e);
|
||||||
} else if (try m.match(.{ "child", tp.extract(&project_directory), tp.extract(&language_server), "request", tp.extract(&method), tp.extract(&id), tp.extract_cbor(¶ms_cb) })) {
|
} else if (try cbor.match(m.buf, .{ "child", tp.extract(&project_directory), tp.extract(&language_server), "request", tp.extract(&method), tp.extract(&id), tp.extract_cbor(¶ms_cb) })) {
|
||||||
self.dispatch_request(from, project_directory, language_server, method, id, params_cb) catch |e| return self.logger.err("lsp-handling", e);
|
self.dispatch_request(from, project_directory, language_server, method, id, params_cb) catch |e| return self.logger.err("lsp-handling", e);
|
||||||
} else if (try m.match(.{ "child", tp.extract(&path), "done" })) {
|
} else if (try cbor.match(m.buf, .{ "child", tp.extract(&path), "done" })) {
|
||||||
self.logger.print_err("lsp-handling", "child '{s}' terminated", .{path});
|
self.logger.print_err("lsp-handling", "child '{s}' terminated", .{path});
|
||||||
} else if (try m.match(.{ "open", tp.extract(&project_directory) })) {
|
} else if (try cbor.match(m.buf, .{ "open", tp.extract(&project_directory) })) {
|
||||||
self.open(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.open(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "request_most_recent_file", tp.extract(&project_directory) })) {
|
} else if (try cbor.match(m.buf, .{ "request_most_recent_file", tp.extract(&project_directory) })) {
|
||||||
self.request_most_recent_file(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.request_most_recent_file(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "request_recent_files", tp.extract(&project_directory), tp.extract(&max) })) {
|
} else if (try cbor.match(m.buf, .{ "request_recent_files", tp.extract(&project_directory), tp.extract(&max) })) {
|
||||||
self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "request_recent_projects", tp.extract(&project_directory) })) {
|
} else if (try cbor.match(m.buf, .{ "request_recent_projects", tp.extract(&project_directory) })) {
|
||||||
self.request_recent_projects(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.request_recent_projects(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) {
|
} else if (try cbor.match(m.buf, .{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) {
|
||||||
self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "request_path_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&path) })) {
|
} else if (try cbor.match(m.buf, .{ "request_path_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&path) })) {
|
||||||
self.request_path_files(from, project_directory, max, path) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.request_path_files(from, project_directory, max, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "did_open", tp.extract(&project_directory), tp.extract(&path), tp.extract(&file_type), tp.extract_cbor(&language_server), tp.extract(&version), tp.extract(&text_ptr), tp.extract(&text_len) })) {
|
} else if (try cbor.match(m.buf, .{ "did_open", tp.extract(&project_directory), tp.extract(&path), tp.extract(&file_type), tp.extract_cbor(&language_server), tp.extract(&version), tp.extract(&text_ptr), tp.extract(&text_len) })) {
|
||||||
const text = if (text_len > 0) @as([*]const u8, @ptrFromInt(text_ptr))[0..text_len] else "";
|
const text = if (text_len > 0) @as([*]const u8, @ptrFromInt(text_ptr))[0..text_len] else "";
|
||||||
self.did_open(project_directory, path, file_type, language_server, version, text) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.did_open(project_directory, path, file_type, language_server, version, text) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "did_change", tp.extract(&project_directory), tp.extract(&path), tp.extract(&version), tp.extract(&root_dst), tp.extract(&root_src) })) {
|
} else if (try cbor.match(m.buf, .{ "did_change", tp.extract(&project_directory), tp.extract(&path), tp.extract(&version), tp.extract(&root_dst), tp.extract(&root_src) })) {
|
||||||
self.did_change(project_directory, path, version, root_dst, root_src) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.did_change(project_directory, path, version, root_dst, root_src) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "did_save", tp.extract(&project_directory), tp.extract(&path) })) {
|
} else if (try cbor.match(m.buf, .{ "did_save", tp.extract(&project_directory), tp.extract(&path) })) {
|
||||||
self.did_save(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.did_save(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "did_close", tp.extract(&project_directory), tp.extract(&path) })) {
|
} else if (try cbor.match(m.buf, .{ "did_close", tp.extract(&project_directory), tp.extract(&path) })) {
|
||||||
self.did_close(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.did_close(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "goto_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "goto_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.goto_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.goto_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "goto_declaration", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "goto_declaration", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.goto_declaration(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.goto_declaration(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "goto_implementation", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "goto_implementation", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.goto_implementation(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.goto_implementation(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "goto_type_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "goto_type_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.goto_type_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.goto_type_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "references", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "references", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.references(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.references(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "completion", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "completion", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.completion(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.completion(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "hover", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "hover", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.hover(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.hover(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{ "get_mru_position", tp.extract(&project_directory), tp.extract(&path) })) {
|
} else if (try cbor.match(m.buf, .{ "get_mru_position", tp.extract(&project_directory), tp.extract(&path) })) {
|
||||||
self.get_mru_position(from, project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
|
self.get_mru_position(from, project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||||
} else if (try m.match(.{"shutdown"})) {
|
} else if (try cbor.match(m.buf, .{"shutdown"})) {
|
||||||
if (self.walker) |pid| pid.send(.{"stop"}) catch {};
|
if (self.walker) |pid| pid.send(.{"stop"}) catch {};
|
||||||
self.persist_projects();
|
self.persist_projects();
|
||||||
try from.send(.{ "project_manager", "shutdown" });
|
from.send(.{ "project_manager", "shutdown" }) catch return error.SendFailed;
|
||||||
return tp.exit_normal();
|
return error.ExitNormal;
|
||||||
} else if (try m.match(.{ "exit", "normal" })) {
|
} else if (try cbor.match(m.buf, .{ "exit", "normal" })) {
|
||||||
return;
|
return;
|
||||||
} else if (try m.match(.{ "exit", "DEADSEND", tp.more })) {
|
} else if (try cbor.match(m.buf, .{ "exit", "DEADSEND", tp.more })) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
self.logger.err("receive", tp.unexpected(m));
|
self.logger.err("receive", tp.unexpected(m));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(self: *Process, project_directory: []const u8) !void {
|
fn open(self: *Process, project_directory: []const u8) (SpawnError || std.fs.Dir.OpenError)!void {
|
||||||
if (self.projects.get(project_directory) == null) {
|
if (self.projects.get(project_directory) == null) {
|
||||||
self.logger.print("opening: {s}", .{project_directory});
|
self.logger.print("opening: {s}", .{project_directory});
|
||||||
const project = try self.allocator.create(Project);
|
const project = try self.allocator.create(Project);
|
||||||
|
@ -333,7 +353,7 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loaded(self: *Process, project_directory: []const u8) error{ OutOfMemory, Exit }!void {
|
fn loaded(self: *Process, project_directory: []const u8) OutOfMemoryError!void {
|
||||||
const project = self.projects.get(project_directory) orelse return;
|
const project = self.projects.get(project_directory) orelse return;
|
||||||
try project.merge_pending_files();
|
try project.merge_pending_files();
|
||||||
self.logger.print("opened: {s} with {d} files in {d} ms", .{
|
self.logger.print("opened: {s} with {d} files in {d} ms", .{
|
||||||
|
@ -343,19 +363,19 @@ const Process = struct {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_most_recent_file(self: *Process, from: tp.pid_ref, project_directory: []const u8) error{ OutOfMemory, Exit }!void {
|
fn request_most_recent_file(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
project.sort_files_by_mtime();
|
project.sort_files_by_mtime();
|
||||||
return project.request_most_recent_file(from);
|
return project.request_most_recent_file(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) error{ OutOfMemory, Exit }!void {
|
fn request_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || SendError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
project.sort_files_by_mtime();
|
project.sort_files_by_mtime();
|
||||||
return project.request_recent_files(from, max);
|
return project.request_recent_files(from, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_recent_projects(self: *Process, from: tp.pid_ref, project_directory: []const u8) error{ OutOfMemory, Exit }!void {
|
fn request_recent_projects(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || SendError)!void {
|
||||||
var recent_projects = std.ArrayList(RecentProject).init(self.allocator);
|
var recent_projects = std.ArrayList(RecentProject).init(self.allocator);
|
||||||
defer recent_projects.deinit();
|
defer recent_projects.deinit();
|
||||||
self.load_recent_projects(&recent_projects, project_directory) catch {};
|
self.load_recent_projects(&recent_projects, project_directory) catch {};
|
||||||
|
@ -365,11 +385,11 @@ const Process = struct {
|
||||||
try cbor.writeArrayHeader(writer, recent_projects.items.len);
|
try cbor.writeArrayHeader(writer, recent_projects.items.len);
|
||||||
for (recent_projects.items) |project|
|
for (recent_projects.items) |project|
|
||||||
try cbor.writeValue(writer, project.name);
|
try cbor.writeValue(writer, project.name);
|
||||||
try from.send_raw(.{ .buf = message.items });
|
from.send_raw(.{ .buf = message.items }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) error{ OutOfMemory, Exit }!void {
|
fn query_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || SendError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
const start_time = std.time.milliTimestamp();
|
const start_time = std.time.milliTimestamp();
|
||||||
const matched = try project.query_recent_files(from, max, query);
|
const matched = try project.query_recent_files(from, max, query);
|
||||||
const query_time = std.time.milliTimestamp() - start_time;
|
const query_time = std.time.milliTimestamp() - start_time;
|
||||||
|
@ -377,103 +397,103 @@ const Process = struct {
|
||||||
self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time });
|
self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_path_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, path: []const u8) error{ OutOfMemory, Exit }!void {
|
fn request_path_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, path: []const u8) (ProjectError || SpawnError || std.fs.Dir.OpenError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
request_path_files_async(self.allocator, from, project, max, path) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
try request_path_files_async(self.allocator, from, project, max, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn did_open(self: *Process, project_directory: []const u8, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) !void {
|
fn did_open(self: *Process, project_directory: []const u8, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) (ProjectError || InvalidArgumentError || SendError || CallError || cbor.Error)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_open" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_open" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.did_open(file_path, file_type, language_server, version, text);
|
return project.did_open(file_path, file_type, language_server, version, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn did_change(self: *Process, project_directory: []const u8, file_path: []const u8, version: usize, root_dst: usize, root_src: usize) !void {
|
fn did_change(self: *Process, project_directory: []const u8, file_path: []const u8, version: usize, root_dst: usize, root_src: usize) (ProjectError || Project.GetFileLspError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_change" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_change" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.did_change(file_path, version, root_dst, root_src);
|
return project.did_change(file_path, version, root_dst, root_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn did_save(self: *Process, project_directory: []const u8, file_path: []const u8) !void {
|
fn did_save(self: *Process, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.GetFileLspError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_save" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_save" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.did_save(file_path);
|
return project.did_save(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn did_close(self: *Process, project_directory: []const u8, file_path: []const u8) !void {
|
fn did_close(self: *Process, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.GetFileLspError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_close" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_close" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.did_close(file_path);
|
return project.did_close(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto_definition(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn goto_definition(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.SendGotoRequestError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_definition" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_definition" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.goto_definition(from, file_path, row, col);
|
return project.goto_definition(from, file_path, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto_declaration(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn goto_declaration(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.SendGotoRequestError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_declaration" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_declaration" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.goto_declaration(from, file_path, row, col);
|
return project.goto_declaration(from, file_path, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto_implementation(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn goto_implementation(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.SendGotoRequestError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_implementation" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_implementation" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.goto_implementation(from, file_path, row, col);
|
return project.goto_implementation(from, file_path, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto_type_definition(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn goto_type_definition(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.SendGotoRequestError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_type_definition" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_type_definition" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.goto_type_definition(from, file_path, row, col);
|
return project.goto_type_definition(from, file_path, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn references(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn references(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.SendGotoRequestError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".references" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".references" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.references(from, file_path, row, col);
|
return project.references(from, file_path, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.SendError || Project.GetFileLspError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".completion" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".completion" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.completion(from, file_path, row, col);
|
return project.completion(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) !void {
|
fn hover(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.SendError || Project.InvalidMessageError || Project.GetFileLspError || cbor.Error)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".hover" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".hover" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.hover(from, file_path, row, col);
|
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) !void {
|
fn get_mru_position(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.SendError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".get_mru_position" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".get_mru_position" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.get_mru_position(from, file_path);
|
return project.get_mru_position(from, file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_mru(self: *Process, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
fn update_mru(self: *Process, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || OutOfMemoryError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.update_mru(file_path, row, col);
|
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) !void {
|
fn dispatch_notify(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, params_cb: []const u8) (ProjectError || Project.InvalidMessageError || Project.SendError || cbor.Error || cbor.JsonEncodeError)!void {
|
||||||
_ = language_server;
|
_ = language_server;
|
||||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return if (std.mem.eql(u8, method, "textDocument/publishDiagnostics"))
|
return if (std.mem.eql(u8, method, "textDocument/publishDiagnostics"))
|
||||||
project.publish_diagnostics(self.parent.ref(), params_cb)
|
project.publish_diagnostics(self.parent.ref(), params_cb)
|
||||||
else if (std.mem.eql(u8, method, "window/showMessage"))
|
else if (std.mem.eql(u8, method, "window/showMessage"))
|
||||||
|
@ -487,15 +507,16 @@ const Process = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch_request(self: *Process, from: tp.pid_ref, project_directory: []const u8, language_server: []const u8, method: []const u8, id: i32, params_cb: []const u8) !void {
|
fn dispatch_request(self: *Process, from: tp.pid_ref, project_directory: []const u8, language_server: []const u8, method: []const u8, id: i32, params_cb: []const u8) (ProjectError || SendError || cbor.Error || cbor.JsonEncodeError || UnsupportedError)!void {
|
||||||
_ = language_server;
|
_ = language_server;
|
||||||
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
|
const project = if (self.projects.get(project_directory)) |p| p else return error.NoProject;
|
||||||
return if (std.mem.eql(u8, method, "client/registerCapability"))
|
return if (std.mem.eql(u8, method, "client/registerCapability"))
|
||||||
project.register_capability(from, id, params_cb)
|
project.register_capability(from, id, params_cb)
|
||||||
else blk: {
|
else blk: {
|
||||||
const params = try cbor.toJsonAlloc(self.allocator, params_cb);
|
const params = try cbor.toJsonAlloc(self.allocator, params_cb);
|
||||||
defer self.allocator.free(params);
|
defer self.allocator.free(params);
|
||||||
break :blk tp.exit_fmt("unsupported LSP request: {s} -> {s}", .{ method, params });
|
self.logger.print_err("lsp", "unsupported LSP request: {s} -> {s}", .{ method, params });
|
||||||
|
break :blk error.Unsupported;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,7 +630,7 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn request_path_files_async(a_: std.mem.Allocator, parent_: tp.pid_ref, project_: *Project, max_: usize, path_: []const u8) !void {
|
fn request_path_files_async(a_: std.mem.Allocator, parent_: tp.pid_ref, project_: *Project, max_: usize, path_: []const u8) (SpawnError || std.fs.Dir.OpenError)!void {
|
||||||
return struct {
|
return struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
project_name: []const u8,
|
project_name: []const u8,
|
||||||
|
@ -621,7 +642,7 @@ fn request_path_files_async(a_: std.mem.Allocator, parent_: tp.pid_ref, project_
|
||||||
const path_files = @This();
|
const path_files = @This();
|
||||||
const Receiver = tp.Receiver(*path_files);
|
const Receiver = tp.Receiver(*path_files);
|
||||||
|
|
||||||
fn spawn_link(allocator: std.mem.Allocator, parent: tp.pid_ref, project: *Project, max: usize, path: []const u8) !void {
|
fn spawn_link(allocator: std.mem.Allocator, parent: tp.pid_ref, project: *Project, max: usize, path: []const u8) (SpawnError || std.fs.Dir.OpenError)!void {
|
||||||
const self = try allocator.create(path_files);
|
const self = try allocator.create(path_files);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
@ -673,7 +694,7 @@ fn request_path_files_async(a_: std.mem.Allocator, parent_: tp.pid_ref, project_
|
||||||
}.spawn_link(a_, parent_, project_, max_, path_);
|
}.spawn_link(a_, parent_, project_, max_, path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) !tp.pid {
|
fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) (SpawnError || std.fs.Dir.OpenError)!tp.pid {
|
||||||
return struct {
|
return struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
root_path: []const u8,
|
root_path: []const u8,
|
||||||
|
@ -685,7 +706,7 @@ fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) !tp.pid {
|
||||||
const tree_walker = @This();
|
const tree_walker = @This();
|
||||||
const Receiver = tp.Receiver(*tree_walker);
|
const Receiver = tp.Receiver(*tree_walker);
|
||||||
|
|
||||||
fn spawn_link(allocator: std.mem.Allocator, root_path: []const u8) !tp.pid {
|
fn spawn_link(allocator: std.mem.Allocator, root_path: []const u8) (SpawnError || std.fs.Dir.OpenError)!tp.pid {
|
||||||
const self = try allocator.create(tree_walker);
|
const self = try allocator.create(tree_walker);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
@ -775,7 +796,7 @@ const FilteredWalker = struct {
|
||||||
dirname_len: usize,
|
dirname_len: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn next(self: *FilteredWalker) error{OutOfMemory}!?Path {
|
pub fn next(self: *FilteredWalker) OutOfMemoryError!?Path {
|
||||||
while (self.stack.items.len != 0) {
|
while (self.stack.items.len != 0) {
|
||||||
var top = &self.stack.items[self.stack.items.len - 1];
|
var top = &self.stack.items[self.stack.items.len - 1];
|
||||||
var containing = top;
|
var containing = top;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
|
const cbor = @import("cbor");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
@ -8,9 +9,16 @@ const MessageFilter = Self;
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
vtable: *const VTable,
|
vtable: *const VTable,
|
||||||
|
|
||||||
|
pub const Error = (cbor.Error || cbor.JsonEncodeError || error{
|
||||||
|
OutOfMemory,
|
||||||
|
ThespianSpawnFailed,
|
||||||
|
NoProject,
|
||||||
|
SendFailed,
|
||||||
|
});
|
||||||
|
|
||||||
pub const VTable = struct {
|
pub const VTable = struct {
|
||||||
deinit: *const fn (ctx: *anyopaque) void,
|
deinit: *const fn (ctx: *anyopaque) void,
|
||||||
filter: *const fn (ctx: *anyopaque, from: tp.pid_ref, m: tp.message) error{Exit}!bool,
|
filter: *const fn (ctx: *anyopaque, from: tp.pid_ref, m: tp.message) Error!bool,
|
||||||
type_name: []const u8,
|
type_name: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,7 +35,7 @@ pub fn to_owned(pimpl: anytype) Self {
|
||||||
}
|
}
|
||||||
}.deinit,
|
}.deinit,
|
||||||
.filter = struct {
|
.filter = struct {
|
||||||
pub fn filter(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
pub fn filter(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) Error!bool {
|
||||||
return child.filter(@as(*child, @ptrCast(@alignCast(ctx))), from_, m);
|
return child.filter(@as(*child, @ptrCast(@alignCast(ctx))), from_, m);
|
||||||
}
|
}
|
||||||
}.filter,
|
}.filter,
|
||||||
|
@ -46,7 +54,7 @@ pub fn to_unowned(pimpl: anytype) Self {
|
||||||
pub fn deinit(_: *anyopaque) void {}
|
pub fn deinit(_: *anyopaque) void {}
|
||||||
}.deinit,
|
}.deinit,
|
||||||
.filter = struct {
|
.filter = struct {
|
||||||
pub fn filter(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
pub fn filter(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) Error!bool {
|
||||||
return child.filter(@as(*child, @ptrCast(@alignCast(ctx))), from_, m);
|
return child.filter(@as(*child, @ptrCast(@alignCast(ctx))), from_, m);
|
||||||
}
|
}
|
||||||
}.filter,
|
}.filter,
|
||||||
|
@ -54,7 +62,7 @@ pub fn to_unowned(pimpl: anytype) Self {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(pimpl: anytype, comptime f: *const fn (ctx: @TypeOf(pimpl), from: tp.pid_ref, m: tp.message) error{Exit}!bool) Self {
|
pub fn bind(pimpl: anytype, comptime f: *const fn (ctx: @TypeOf(pimpl), from: tp.pid_ref, m: tp.message) Error!bool) Self {
|
||||||
const impl = @typeInfo(@TypeOf(pimpl));
|
const impl = @typeInfo(@TypeOf(pimpl));
|
||||||
const child: type = impl.Pointer.child;
|
const child: type = impl.Pointer.child;
|
||||||
return .{
|
return .{
|
||||||
|
@ -65,7 +73,7 @@ pub fn bind(pimpl: anytype, comptime f: *const fn (ctx: @TypeOf(pimpl), from: tp
|
||||||
pub fn deinit(_: *anyopaque) void {}
|
pub fn deinit(_: *anyopaque) void {}
|
||||||
}.deinit,
|
}.deinit,
|
||||||
.filter = struct {
|
.filter = struct {
|
||||||
pub fn filter(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
pub fn filter(ctx: *anyopaque, from_: tp.pid_ref, m: tp.message) Error!bool {
|
||||||
return @call(.auto, f, .{ @as(*child, @ptrCast(@alignCast(ctx))), from_, m });
|
return @call(.auto, f, .{ @as(*child, @ptrCast(@alignCast(ctx))), from_, m });
|
||||||
}
|
}
|
||||||
}.filter,
|
}.filter,
|
||||||
|
@ -84,7 +92,7 @@ pub fn dynamic_cast(self: Self, comptime T: type) ?*T {
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter(self: Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
pub fn filter(self: Self, from_: tp.pid_ref, m: tp.message) Error!bool {
|
||||||
return self.vtable.filter(self.ptr, from_, m);
|
return self.vtable.filter(self.ptr, from_, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,14 +128,14 @@ pub const List = struct {
|
||||||
self.list.orderedRemove(i).deinit();
|
self.list.orderedRemove(i).deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter(self: *const List, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
pub fn filter(self: *const List, from: tp.pid_ref, m: tp.message) Error!bool {
|
||||||
var sfa = std.heap.stackFallback(4096, self.allocator);
|
var sfa = std.heap.stackFallback(4096, self.allocator);
|
||||||
const a = sfa.get();
|
const a = sfa.get();
|
||||||
const buf = a.alloc(u8, m.buf.len) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
const buf = try a.alloc(u8, m.buf.len);
|
||||||
defer a.free(buf);
|
defer a.free(buf);
|
||||||
@memcpy(buf[0..m.buf.len], m.buf);
|
@memcpy(buf[0..m.buf.len], m.buf);
|
||||||
const m_: tp.message = .{ .buf = buf[0..m.buf.len] };
|
const m_: tp.message = .{ .buf = buf[0..m.buf.len] };
|
||||||
var e: ?error{Exit} = null;
|
var e: ?Error = null;
|
||||||
for (self.list.items) |*i| {
|
for (self.list.items) |*i| {
|
||||||
const consume = i.filter(from, m_) catch |e_| ret: {
|
const consume = i.filter(from, m_) catch |e_| ret: {
|
||||||
e = e_;
|
e = e_;
|
||||||
|
|
|
@ -333,7 +333,7 @@ fn diff_result_send(from: tp.pid_ref, edits: []diff.Edit) !void {
|
||||||
from.send_raw(tp.message{ .buf = stream.getWritten() }) catch return;
|
from.send_raw(tp.message{ .buf = stream.getWritten() }) catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_diff(self: *Self, cb: []const u8) !void {
|
pub fn process_diff(self: *Self, cb: []const u8) MessageFilter.Error!void {
|
||||||
var iter = cb;
|
var iter = cb;
|
||||||
self.diff_symbols_clear();
|
self.diff_symbols_clear();
|
||||||
var count = try cbor.decodeArrayHeader(&iter);
|
var count = try cbor.decodeArrayHeader(&iter);
|
||||||
|
@ -382,10 +382,10 @@ fn process_edit(self: *Self, kind: Kind, line: usize, offset: usize, bytes: []co
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter_receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
pub fn filter_receive(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
||||||
var cb: []const u8 = undefined;
|
var cb: []const u8 = undefined;
|
||||||
if (try m.match(.{ "DIFF", tp.extract_cbor(&cb) })) {
|
if (cbor.match(m.buf, .{ "DIFF", tp.extract_cbor(&cb) }) catch false) {
|
||||||
self.process_diff(cb) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
try self.process_diff(cb);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -5,10 +5,12 @@ const Allocator = @import("std").mem.Allocator;
|
||||||
const ArrayList = @import("std").ArrayList;
|
const ArrayList = @import("std").ArrayList;
|
||||||
|
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
|
const cbor = @import("cbor");
|
||||||
|
|
||||||
const Plane = @import("renderer").Plane;
|
const Plane = @import("renderer").Plane;
|
||||||
|
|
||||||
const Widget = @import("Widget.zig");
|
const Widget = @import("Widget.zig");
|
||||||
|
const MessageFilter = @import("MessageFilter.zig");
|
||||||
|
|
||||||
const escape = fmt.fmtSliceEscapeLower;
|
const escape = fmt.fmtSliceEscapeLower;
|
||||||
|
|
||||||
|
@ -82,21 +84,21 @@ fn output_tdiff(self: *Self, tdiff: i64) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_log(m: tp.message) !void {
|
pub fn process_log(m: tp.message) MessageFilter.Error!void {
|
||||||
var src: []const u8 = undefined;
|
var src: []const u8 = undefined;
|
||||||
var context: []const u8 = undefined;
|
var context: []const u8 = undefined;
|
||||||
var msg: []const u8 = undefined;
|
var msg: []const u8 = undefined;
|
||||||
const buffer = get_buffer();
|
const buffer = get_buffer();
|
||||||
if (try m.match(.{ "log", tp.extract(&src), tp.extract(&msg) })) {
|
if (try cbor.match(m.buf, .{ "log", tp.extract(&src), tp.extract(&msg) })) {
|
||||||
try append(buffer, src, msg, .info);
|
try append(buffer, src, msg, .info);
|
||||||
} else if (try m.match(.{ "log", "error", tp.extract(&src), tp.extract(&context), "->", tp.extract(&msg) })) {
|
} else if (try cbor.match(m.buf, .{ "log", "error", tp.extract(&src), tp.extract(&context), "->", tp.extract(&msg) })) {
|
||||||
const err_stop = "error.Stop";
|
const err_stop = "error.Stop";
|
||||||
if (eql(u8, msg, err_stop))
|
if (eql(u8, msg, err_stop))
|
||||||
return;
|
return;
|
||||||
if (msg.len >= err_stop.len + 1 and eql(u8, msg[0 .. err_stop.len + 1], err_stop ++ "\n"))
|
if (msg.len >= err_stop.len + 1 and eql(u8, msg[0 .. err_stop.len + 1], err_stop ++ "\n"))
|
||||||
return;
|
return;
|
||||||
try append_error(buffer, src, context, msg);
|
try append_error(buffer, src, context, msg);
|
||||||
} else if (try m.match(.{ "log", tp.extract(&src), tp.more })) {
|
} else if (try cbor.match(m.buf, .{ "log", tp.extract(&src), tp.more })) {
|
||||||
try append_json(buffer, src, m);
|
try append_json(buffer, src, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,16 +122,23 @@ fn append(buffer: *Buffer, src: []const u8, msg: []const u8, level: Level) !void
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_error(buffer: *Buffer, src: []const u8, context: []const u8, msg_: []const u8) !void {
|
fn append_error(buffer: *Buffer, src: []const u8, context: []const u8, msg_: []const u8) MessageFilter.Error!void {
|
||||||
var buf: [4096]u8 = undefined;
|
const std = @import("std");
|
||||||
const msg = try fmt.bufPrint(&buf, "error in {s}: {s}", .{ context, msg_ });
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
try append(buffer, src, msg, .err);
|
defer arena.deinit();
|
||||||
|
var sfa = std.heap.stackFallback(4096, arena.allocator());
|
||||||
|
var msg = std.ArrayList(u8).init(sfa.get());
|
||||||
|
try fmt.format(msg.writer(), "error in {s}: {s}", .{ context, msg_ });
|
||||||
|
try append(buffer, src, msg.items, .err);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_json(buffer: *Buffer, src: []const u8, m: tp.message) !void {
|
fn append_json(buffer: *Buffer, src: []const u8, m: tp.message) MessageFilter.Error!void {
|
||||||
var buf: [4096]u8 = undefined;
|
const std = @import("std");
|
||||||
const json = try m.to_json(&buf);
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
try append(buffer, src, json, .err);
|
defer arena.deinit();
|
||||||
|
var sfa = std.heap.stackFallback(4096, arena.allocator());
|
||||||
|
const msg = try cbor.toJsonAlloc(sfa.get(), m.buf);
|
||||||
|
try append(buffer, src, msg, .err);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_buffer() *Buffer {
|
fn get_buffer() *Buffer {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
|
const cbor = @import("cbor");
|
||||||
const log = @import("log");
|
const log = @import("log");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
|
|
||||||
|
@ -216,15 +217,15 @@ pub fn Create(options: type) type {
|
||||||
try self.do_complete();
|
try self.do_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_path_entry(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
fn receive_path_entry(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
||||||
if (try m.match(.{ "PRJ", tp.more })) {
|
if (try cbor.match(m.buf, .{ "PRJ", tp.more })) {
|
||||||
self.process_project_manager(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
try self.process_project_manager(m);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_project_manager(self: *Self, m: tp.message) !void {
|
fn process_project_manager(self: *Self, m: tp.message) MessageFilter.Error!void {
|
||||||
defer {
|
defer {
|
||||||
if (tui.current().mini_mode) |*mini_mode| {
|
if (tui.current().mini_mode) |*mini_mode| {
|
||||||
mini_mode.text = self.file_path.items;
|
mini_mode.text = self.file_path.items;
|
||||||
|
@ -232,23 +233,23 @@ pub fn Create(options: type) type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var count: usize = undefined;
|
var count: usize = undefined;
|
||||||
if (try m.match(.{ "PRJ", "path_entry", tp.more })) {
|
if (try cbor.match(m.buf, .{ "PRJ", "path_entry", tp.more })) {
|
||||||
return self.process_path_entry(m);
|
return self.process_path_entry(m);
|
||||||
} else if (try m.match(.{ "PRJ", "path_done", tp.any, tp.any, tp.extract(&count) })) {
|
} else if (try cbor.match(m.buf, .{ "PRJ", "path_done", tp.any, tp.any, tp.extract(&count) })) {
|
||||||
try self.do_complete();
|
try self.do_complete();
|
||||||
} else {
|
} else {
|
||||||
log.logger("file_browser").err("receive", tp.unexpected(m));
|
log.logger("file_browser").err("receive", tp.unexpected(m));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_path_entry(self: *Self, m: tp.message) !void {
|
fn process_path_entry(self: *Self, m: tp.message) MessageFilter.Error!void {
|
||||||
var path: []const u8 = undefined;
|
var path: []const u8 = undefined;
|
||||||
var file_name: []const u8 = undefined;
|
var file_name: []const u8 = undefined;
|
||||||
if (try m.match(.{ tp.any, tp.any, tp.any, tp.extract(&path), "DIR", tp.extract(&file_name) })) {
|
if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "DIR", tp.extract(&file_name) })) {
|
||||||
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .dir };
|
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .dir };
|
||||||
} else if (try m.match(.{ tp.any, tp.any, tp.any, tp.extract(&path), "LINK", tp.extract(&file_name) })) {
|
} else if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "LINK", tp.extract(&file_name) })) {
|
||||||
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .link };
|
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .link };
|
||||||
} else if (try m.match(.{ tp.any, tp.any, tp.any, tp.extract(&path), "FILE", tp.extract(&file_name) })) {
|
} else if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "FILE", tp.extract(&file_name) })) {
|
||||||
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .file };
|
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .file };
|
||||||
} else {
|
} else {
|
||||||
log.logger("file_browser").err("receive", tp.unexpected(m));
|
log.logger("file_browser").err("receive", tp.unexpected(m));
|
||||||
|
|
|
@ -118,7 +118,7 @@ pub fn restore_state(palette: *Type) !void {
|
||||||
tp.extract(&name_),
|
tp.extract(&name_),
|
||||||
tp.extract(&used_time),
|
tp.extract(&used_time),
|
||||||
}) catch |e| switch (e) {
|
}) catch |e| switch (e) {
|
||||||
error.CborTooShort => return,
|
error.TooShort => return,
|
||||||
else => return e,
|
else => return e,
|
||||||
}) {
|
}) {
|
||||||
const id = command.getId(name_) orelse continue;
|
const id = command.getId(name_) orelse continue;
|
||||||
|
|
|
@ -148,19 +148,19 @@ fn add_item(self: *Self, file_name: []const u8, matches: ?[]const u8) !void {
|
||||||
try self.menu.add_item_with_handler(label.items, menu_action_open_file);
|
try self.menu.add_item_with_handler(label.items, menu_action_open_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
||||||
if (try m.match(.{ "PRJ", tp.more })) {
|
if (cbor.match(m.buf, .{ "PRJ", tp.more }) catch false) {
|
||||||
self.process_project_manager(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
try self.process_project_manager(m);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_project_manager(self: *Self, m: tp.message) !void {
|
fn process_project_manager(self: *Self, m: tp.message) MessageFilter.Error!void {
|
||||||
var file_name: []const u8 = undefined;
|
var file_name: []const u8 = undefined;
|
||||||
var matches: []const u8 = undefined;
|
var matches: []const u8 = undefined;
|
||||||
var query: []const u8 = undefined;
|
var query: []const u8 = undefined;
|
||||||
if (try m.match(.{ "PRJ", "recent", tp.extract(&self.longest), tp.extract(&file_name), tp.extract_cbor(&matches) })) {
|
if (try cbor.match(m.buf, .{ "PRJ", "recent", tp.extract(&self.longest), tp.extract(&file_name), tp.extract_cbor(&matches) })) {
|
||||||
if (self.need_reset) self.reset_results();
|
if (self.need_reset) self.reset_results();
|
||||||
try self.add_item(file_name, matches);
|
try self.add_item(file_name, matches);
|
||||||
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = self.menu_width() });
|
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = self.menu_width() });
|
||||||
|
@ -169,7 +169,7 @@ fn process_project_manager(self: *Self, m: tp.message) !void {
|
||||||
self.need_select_first = false;
|
self.need_select_first = false;
|
||||||
}
|
}
|
||||||
tui.need_render();
|
tui.need_render();
|
||||||
} else if (try m.match(.{ "PRJ", "recent", tp.extract(&self.longest), tp.extract(&file_name) })) {
|
} else if (try cbor.match(m.buf, .{ "PRJ", "recent", tp.extract(&self.longest), tp.extract(&file_name) })) {
|
||||||
if (self.need_reset) self.reset_results();
|
if (self.need_reset) self.reset_results();
|
||||||
try self.add_item(file_name, null);
|
try self.add_item(file_name, null);
|
||||||
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = self.menu_width() });
|
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = self.menu_width() });
|
||||||
|
@ -178,7 +178,7 @@ fn process_project_manager(self: *Self, m: tp.message) !void {
|
||||||
self.need_select_first = false;
|
self.need_select_first = false;
|
||||||
}
|
}
|
||||||
tui.need_render();
|
tui.need_render();
|
||||||
} else if (try m.match(.{ "PRJ", "recent_done", tp.extract(&self.longest), tp.extract(&query) })) {
|
} else if (try cbor.match(m.buf, .{ "PRJ", "recent_done", tp.extract(&self.longest), tp.extract(&query) })) {
|
||||||
self.query_pending = false;
|
self.query_pending = false;
|
||||||
self.need_reset = true;
|
self.need_reset = true;
|
||||||
if (!std.mem.eql(u8, self.inputbox.text.items, query))
|
if (!std.mem.eql(u8, self.inputbox.text.items, query))
|
||||||
|
@ -283,7 +283,7 @@ fn reset_results(self: *Self) void {
|
||||||
self.need_select_first = true;
|
self.need_select_first = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_query(self: *Self) !void {
|
fn start_query(self: *Self) MessageFilter.Error!void {
|
||||||
if (self.query_pending) return;
|
if (self.query_pending) return;
|
||||||
self.query_pending = true;
|
self.query_pending = true;
|
||||||
try project_manager.query_recent_files(max_recent_files, self.inputbox.text.items);
|
try project_manager.query_recent_files(max_recent_files, self.inputbox.text.items);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
|
const cbor = @import("cbor");
|
||||||
const zeit = @import("zeit");
|
const zeit = @import("zeit");
|
||||||
|
|
||||||
const Plane = @import("renderer").Plane;
|
const Plane = @import("renderer").Plane;
|
||||||
|
@ -67,8 +68,8 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_tick(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
fn receive_tick(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
||||||
if (try m.match(.{"CLOCK"})) {
|
if (try cbor.match(m.buf, .{"CLOCK"})) {
|
||||||
tui.need_render();
|
tui.need_render();
|
||||||
self.update_tick_timer(.ticked);
|
self.update_tick_timer(.ticked);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
|
const cbor = @import("cbor");
|
||||||
const log = @import("log");
|
const log = @import("log");
|
||||||
|
|
||||||
const Plane = @import("renderer").Plane;
|
const Plane = @import("renderer").Plane;
|
||||||
|
@ -76,13 +77,13 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_log(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
fn receive_log(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
||||||
var clear_msg_num: usize = 0;
|
var clear_msg_num: usize = 0;
|
||||||
if (try m.match(.{ "log", tp.more })) {
|
if (try cbor.match(m.buf, .{ "log", tp.more })) {
|
||||||
logview.process_log(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
try logview.process_log(m);
|
||||||
self.process_log(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
try self.process_log(m);
|
||||||
return true;
|
return true;
|
||||||
} else if (try m.match(.{ "MINILOG", tp.extract(&clear_msg_num) })) {
|
} else if (try cbor.match(m.buf, .{ "MINILOG", tp.extract(&clear_msg_num) })) {
|
||||||
if (clear_msg_num == self.msg_counter)
|
if (clear_msg_num == self.msg_counter)
|
||||||
self.clear();
|
self.clear();
|
||||||
return true;
|
return true;
|
||||||
|
@ -90,20 +91,20 @@ fn receive_log(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_log(self: *Self, m: tp.message) !void {
|
fn process_log(self: *Self, m: tp.message) MessageFilter.Error!void {
|
||||||
var src: []const u8 = undefined;
|
var src: []const u8 = undefined;
|
||||||
var context: []const u8 = undefined;
|
var context: []const u8 = undefined;
|
||||||
var msg: []const u8 = undefined;
|
var msg: []const u8 = undefined;
|
||||||
if (try m.match(.{ "log", tp.extract(&src), tp.extract(&msg) })) {
|
if (try cbor.match(m.buf, .{ "log", tp.extract(&src), tp.extract(&msg) })) {
|
||||||
try self.set(msg, .info);
|
try self.set(msg, .info);
|
||||||
} else if (try m.match(.{ "log", "error", tp.extract(&src), tp.extract(&context), "->", tp.extract(&msg) })) {
|
} else if (try cbor.match(m.buf, .{ "log", "error", tp.extract(&src), tp.extract(&context), "->", tp.extract(&msg) })) {
|
||||||
const err_stop = "error.Stop";
|
const err_stop = "error.Stop";
|
||||||
if (std.mem.eql(u8, msg, err_stop))
|
if (std.mem.eql(u8, msg, err_stop))
|
||||||
return;
|
return;
|
||||||
if (msg.len >= err_stop.len + 1 and std.mem.eql(u8, msg[0 .. err_stop.len + 1], err_stop ++ "\n"))
|
if (msg.len >= err_stop.len + 1 and std.mem.eql(u8, msg[0 .. err_stop.len + 1], err_stop ++ "\n"))
|
||||||
return;
|
return;
|
||||||
try self.set(msg, .err);
|
try self.set(msg, .err);
|
||||||
} else if (try m.match(.{ "log", tp.extract(&src), tp.more })) {
|
} else if (try cbor.match(m.buf, .{ "log", tp.extract(&src), tp.more })) {
|
||||||
self.level = .err;
|
self.level = .err;
|
||||||
var s = std.json.writeStream(self.msg.writer(), .{});
|
var s = std.json.writeStream(self.msg.writer(), .{});
|
||||||
var iter: []const u8 = m.buf;
|
var iter: []const u8 = m.buf;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue