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
|
@ -5,6 +5,7 @@ const log = @import("log");
|
|||
const tracy = @import("tracy");
|
||||
const FileType = @import("syntax").FileType;
|
||||
const root = @import("root");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Project = @import("Project.zig");
|
||||
|
||||
|
@ -14,12 +15,25 @@ const Self = @This();
|
|||
const module_name = @typeName(Self);
|
||||
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);
|
||||
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();
|
||||
defer pid.deinit();
|
||||
tp.env.get().proc_set(module_name, pid.ref());
|
||||
|
@ -35,142 +49,142 @@ pub fn shutdown() void {
|
|||
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;
|
||||
const project_directory = std.fs.cwd().realpath(rel_project_directory, &path_buf) catch "(none)";
|
||||
var dir = try std.fs.openDirAbsolute(project_directory, .{});
|
||||
try dir.setAsCwd();
|
||||
dir.close();
|
||||
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");
|
||||
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 });
|
||||
defer allocator.free(rsp.buf);
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "request_recent_files", project, max });
|
||||
return error.NoProject;
|
||||
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");
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "query_recent_files", project, max, query });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "request_path_files", project, max, path });
|
||||
return error.NoProject;
|
||||
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");
|
||||
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;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "did_change", project, file_path, version, root_dst, root_src });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "did_save", project, file_path });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "did_close", project, file_path });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "goto_definition", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "goto_declaration", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "goto_implementation", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "goto_type_definition", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "references", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "completion", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "hover", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "update_mru", project, file_path, row, col });
|
||||
return error.NoProject;
|
||||
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");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "get_mru_position", project, file_path });
|
||||
return error.NoProject;
|
||||
return send(.{ "get_mru_position", project, file_path });
|
||||
}
|
||||
|
||||
const Process = struct {
|
||||
|
@ -181,6 +195,9 @@ const Process = struct {
|
|||
projects: ProjectsMap,
|
||||
walker: ?tp.pid = null,
|
||||
|
||||
const InvalidArgumentError = error{InvalidArgument};
|
||||
const UnsupportedError = error{Unsupported};
|
||||
|
||||
const Receiver = tp.Receiver(*Process);
|
||||
const ProjectsMap = std.StringHashMap(*Project);
|
||||
const RecentProject = struct {
|
||||
|
@ -188,7 +205,7 @@ const Process = struct {
|
|||
last_used: i128,
|
||||
};
|
||||
|
||||
fn create() !tp.pid {
|
||||
fn create() SpawnError!tp.pid {
|
||||
const allocator = std.heap.c_allocator;
|
||||
const self = try allocator.create(Process);
|
||||
self.* = .{
|
||||
|
@ -221,14 +238,17 @@ const Process = struct {
|
|||
|
||||
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
||||
errdefer self.deinit();
|
||||
self.receive_safe(from, m) catch |e| {
|
||||
if (std.mem.eql(u8, "normal", tp.error_text()))
|
||||
return e;
|
||||
self.logger.err("receive", tp.exit_error(e, @errorReturnTrace()));
|
||||
return self.receive_safe(from, m) catch |e| switch (e) {
|
||||
error.ExitNormal => tp.exit_normal(),
|
||||
else => blk: {
|
||||
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 path: []const u8 = undefined;
|
||||
var query: []const u8 = undefined;
|
||||
|
@ -249,77 +269,77 @@ const Process = struct {
|
|||
var root_dst: 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));
|
||||
if (self.projects.get(project_directory)) |project|
|
||||
project.add_pending_file(
|
||||
path,
|
||||
mtime,
|
||||
) 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();
|
||||
self.walker = null;
|
||||
self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
|
||||
self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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);
|
||||
} 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);
|
||||
} 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});
|
||||
} else if (try m.match(.{ "open", tp.extract(&project_directory) })) {
|
||||
self.open(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "request_most_recent_file", tp.extract(&project_directory) })) {
|
||||
self.request_most_recent_file(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "request_recent_projects", tp.extract(&project_directory) })) {
|
||||
self.request_recent_projects(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} 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, .{ "open", tp.extract(&project_directory) })) {
|
||||
self.open(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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 "";
|
||||
self.did_open(project_directory, path, file_type, language_server, version, text) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} 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) })) {
|
||||
self.did_change(project_directory, path, version, root_dst, root_src) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "did_save", tp.extract(&project_directory), tp.extract(&path) })) {
|
||||
self.did_save(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "did_close", tp.extract(&project_directory), tp.extract(&path) })) {
|
||||
self.did_close(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{ "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());
|
||||
} else if (try m.match(.{"shutdown"})) {
|
||||
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 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} 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()) catch error.SendFailed;
|
||||
} else if (try cbor.match(m.buf, .{"shutdown"})) {
|
||||
if (self.walker) |pid| pid.send(.{"stop"}) catch {};
|
||||
self.persist_projects();
|
||||
try from.send(.{ "project_manager", "shutdown" });
|
||||
return tp.exit_normal();
|
||||
} else if (try m.match(.{ "exit", "normal" })) {
|
||||
from.send(.{ "project_manager", "shutdown" }) catch return error.SendFailed;
|
||||
return error.ExitNormal;
|
||||
} else if (try cbor.match(m.buf, .{ "exit", "normal" })) {
|
||||
return;
|
||||
} else if (try m.match(.{ "exit", "DEADSEND", tp.more })) {
|
||||
} else if (try cbor.match(m.buf, .{ "exit", "DEADSEND", tp.more })) {
|
||||
return;
|
||||
} else {
|
||||
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) {
|
||||
self.logger.print("opening: {s}", .{project_directory});
|
||||
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;
|
||||
try project.merge_pending_files();
|
||||
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 {
|
||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
||||
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 error.NoProject;
|
||||
project.sort_files_by_mtime();
|
||||
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 {
|
||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
||||
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 error.NoProject;
|
||||
project.sort_files_by_mtime();
|
||||
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);
|
||||
defer recent_projects.deinit();
|
||||
self.load_recent_projects(&recent_projects, project_directory) catch {};
|
||||
|
@ -365,11 +385,11 @@ const Process = struct {
|
|||
try cbor.writeArrayHeader(writer, recent_projects.items.len);
|
||||
for (recent_projects.items) |project|
|
||||
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 {
|
||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
||||
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 error.NoProject;
|
||||
const start_time = std.time.milliTimestamp();
|
||||
const matched = try project.query_recent_files(from, max, query);
|
||||
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 });
|
||||
}
|
||||
|
||||
fn request_path_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, path: []const u8) error{ OutOfMemory, Exit }!void {
|
||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
||||
request_path_files_async(self.allocator, from, project, max, path) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
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 error.NoProject;
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
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" });
|
||||
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);
|
||||
}
|
||||
|
||||
fn update_mru(self: *Process, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
|
||||
const project = self.projects.get(project_directory) orelse return tp.exit("No project");
|
||||
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 error.NoProject;
|
||||
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;
|
||||
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"))
|
||||
project.publish_diagnostics(self.parent.ref(), params_cb)
|
||||
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;
|
||||
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"))
|
||||
project.register_capability(from, id, params_cb)
|
||||
else blk: {
|
||||
const params = try cbor.toJsonAlloc(self.allocator, params_cb);
|
||||
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 {
|
||||
allocator: std.mem.Allocator,
|
||||
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 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);
|
||||
self.* = .{
|
||||
.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_);
|
||||
}
|
||||
|
||||
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 {
|
||||
allocator: std.mem.Allocator,
|
||||
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 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);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
|
@ -775,7 +796,7 @@ const FilteredWalker = struct {
|
|||
dirname_len: usize,
|
||||
};
|
||||
|
||||
pub fn next(self: *FilteredWalker) error{OutOfMemory}!?Path {
|
||||
pub fn next(self: *FilteredWalker) OutOfMemoryError!?Path {
|
||||
while (self.stack.items.len != 0) {
|
||||
var top = &self.stack.items[self.stack.items.len - 1];
|
||||
var containing = top;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue