refactor: improve handling and reporting of project manager and lsp errors
This commit is contained in:
parent
da1ed11a22
commit
dc25a0ea14
5 changed files with 172 additions and 150 deletions
11
src/LSP.zig
11
src/LSP.zig
|
@ -22,12 +22,12 @@ pub fn open(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message)
|
||||||
return .{ .allocator = allocator, .pid = try Process.create(allocator, project, cmd) };
|
return .{ .allocator = allocator, .pid = try Process.create(allocator, project, cmd) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: Self) void {
|
||||||
self.pid.send(.{"close"}) catch {};
|
self.pid.send(.{"close"}) catch {};
|
||||||
self.pid.deinit();
|
self.pid.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn term(self: *Self) void {
|
pub fn term(self: Self) void {
|
||||||
self.pid.send(.{"term"}) catch {};
|
self.pid.send(.{"term"}) catch {};
|
||||||
self.pid.deinit();
|
self.pid.deinit();
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,7 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Error = (cbor.Error || cbor.JsonDecodeError || OutOfMemoryError || SendError || error{
|
const Error = (cbor.Error || cbor.JsonDecodeError || OutOfMemoryError || SendError || error{
|
||||||
|
FileNotFound,
|
||||||
InvalidSyntax,
|
InvalidSyntax,
|
||||||
InvalidMessageField,
|
InvalidMessageField,
|
||||||
InvalidMessage,
|
InvalidMessage,
|
||||||
|
@ -197,6 +198,12 @@ const Process = struct {
|
||||||
self.write_log("{s}\n", .{bytes});
|
self.write_log("{s}\n", .{bytes});
|
||||||
} else if (try cbor.match(m.buf, .{ "exit", "normal" })) {
|
} else if (try cbor.match(m.buf, .{ "exit", "normal" })) {
|
||||||
// self.write_log("### exit normal ###\n", .{});
|
// self.write_log("### exit normal ###\n", .{});
|
||||||
|
} else if (try cbor.match(m.buf, .{ "exit", "error.FileNotFound" })) {
|
||||||
|
self.write_log("### LSP not found ###\n", .{});
|
||||||
|
const logger = log.logger("LSP");
|
||||||
|
var buf: [1024]u8 = undefined;
|
||||||
|
logger.print_err("init", "executable not found: {s}", .{self.cmd.to_json(&buf) catch "{command too large}"});
|
||||||
|
return error.FileNotFound;
|
||||||
} else {
|
} else {
|
||||||
tp.unexpected(m) catch {};
|
tp.unexpected(m) catch {};
|
||||||
self.write_log("{s}\n", .{tp.error_text()});
|
self.write_log("{s}\n", .{tp.error_text()});
|
||||||
|
|
172
src/Project.zig
172
src/Project.zig
|
@ -22,10 +22,13 @@ file_language_server: std.StringHashMap(LSP),
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
const OutOfMemoryError = error{OutOfMemory};
|
const OutOfMemoryError = error{OutOfMemory};
|
||||||
const SendError = error{SendFailed};
|
|
||||||
const CallError = tp.CallError;
|
const CallError = tp.CallError;
|
||||||
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
||||||
pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI };
|
pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI };
|
||||||
|
pub const StartLspError = (error{ ThespianSpawnFailed, Timeout, InvalidArgument } || LspError || OutOfMemoryError || cbor.Error);
|
||||||
|
pub const LspError = (error{ NoLsp, LspFailed } || OutOfMemoryError);
|
||||||
|
pub const ClientError = (error{ClientFailed} || OutOfMemoryError);
|
||||||
|
pub const LspOrClientError = (LspError || ClientError);
|
||||||
|
|
||||||
const File = struct {
|
const File = struct {
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
|
@ -102,39 +105,48 @@ pub fn restore_state(self: *Self, data: []const u8) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const GetLspError = (error{ ThespianSpawnFailed, Timeout, InvalidArgument } || OutOfMemoryError || SendError || cbor.Error);
|
fn get_language_server_instance(self: *Self, language_server: []const u8) StartLspError!LSP {
|
||||||
|
if (self.language_servers.get(language_server)) |lsp| {
|
||||||
fn get_lsp(self: *Self, language_server: []const u8) GetLspError!LSP {
|
if (!lsp.pid.expired()) return lsp;
|
||||||
if (self.language_servers.get(language_server)) |lsp| return lsp;
|
lsp.deinit();
|
||||||
const logger = log.logger("lsp");
|
_ = self.language_servers.remove(language_server);
|
||||||
errdefer |e| logger.print_err("get_lsp", "failed to initialize LSP: {s} -> {any}", .{ fmt_lsp_name_func(language_server), e });
|
}
|
||||||
const lsp = try LSP.open(self.allocator, self.name, .{ .buf = language_server });
|
const lsp = try LSP.open(self.allocator, self.name, .{ .buf = language_server });
|
||||||
try self.language_servers.put(try self.allocator.dupe(u8, language_server), lsp);
|
errdefer lsp.deinit();
|
||||||
const uri = try self.make_URI(null);
|
const uri = try self.make_URI(null);
|
||||||
defer self.allocator.free(uri);
|
defer self.allocator.free(uri);
|
||||||
const basename_begin = std.mem.lastIndexOfScalar(u8, self.name, std.fs.path.sep);
|
const basename_begin = std.mem.lastIndexOfScalar(u8, self.name, std.fs.path.sep);
|
||||||
const basename = if (basename_begin) |begin| self.name[begin + 1 ..] else self.name;
|
const basename = if (basename_begin) |begin| self.name[begin + 1 ..] else self.name;
|
||||||
const response = try self.send_lsp_init_request(lsp, self.name, basename, uri);
|
const response = try self.send_lsp_init_request(lsp, self.name, basename, uri);
|
||||||
defer self.allocator.free(response.buf);
|
defer self.allocator.free(response.buf);
|
||||||
try lsp.send_notification("initialized", .{});
|
lsp.send_notification("initialized", .{}) catch return error.LspFailed;
|
||||||
logger.print("initialized LSP: {s}", .{fmt_lsp_name_func(language_server)});
|
if (lsp.pid.expired()) return error.LspFailed;
|
||||||
|
log.logger("lsp").print("initialized LSP: {s}", .{fmt_lsp_name_func(language_server)});
|
||||||
|
try self.language_servers.put(try self.allocator.dupe(u8, language_server), lsp);
|
||||||
return lsp;
|
return lsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const GetFileLspError = (GetLspError || error{NoLsp});
|
fn get_or_start_language_server(self: *Self, file_path: []const u8, language_server: []const u8) StartLspError!LSP {
|
||||||
|
const lsp = self.file_language_server.get(file_path) orelse blk: {
|
||||||
|
const new_lsp = try self.get_language_server_instance(language_server);
|
||||||
|
const key = try self.allocator.dupe(u8, file_path);
|
||||||
|
try self.file_language_server.put(key, new_lsp);
|
||||||
|
break :blk new_lsp;
|
||||||
|
};
|
||||||
|
return lsp;
|
||||||
|
}
|
||||||
|
|
||||||
fn get_file_lsp(self: *Self, file_path: []const u8) GetFileLspError!LSP {
|
fn get_language_server(self: *Self, file_path: []const u8) LspError!LSP {
|
||||||
const logger = log.logger("lsp");
|
|
||||||
errdefer logger.print_err("get_file_lsp", "no LSP found for file: {s} ({s})", .{
|
|
||||||
std.fmt.fmtSliceEscapeLower(file_path),
|
|
||||||
self.name,
|
|
||||||
});
|
|
||||||
const lsp = self.file_language_server.get(file_path) orelse return error.NoLsp;
|
const lsp = self.file_language_server.get(file_path) orelse return error.NoLsp;
|
||||||
if (lsp.pid.expired()) return error.NoLsp;
|
if (lsp.pid.expired()) {
|
||||||
|
if (self.file_language_server.fetchRemove(file_path)) |kv|
|
||||||
|
self.allocator.free(kv.key);
|
||||||
|
return error.LspFailed;
|
||||||
|
}
|
||||||
return lsp;
|
return lsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_URI(self: *Self, file_path: ?[]const u8) ![]const u8 {
|
fn make_URI(self: *Self, file_path: ?[]const u8) LspError![]const u8 {
|
||||||
var buf = std.ArrayList(u8).init(self.allocator);
|
var buf = std.ArrayList(u8).init(self.allocator);
|
||||||
if (file_path) |path| {
|
if (file_path) |path| {
|
||||||
if (std.fs.path.isAbsolute(path)) {
|
if (std.fs.path.isAbsolute(path)) {
|
||||||
|
@ -155,20 +167,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) SendError!void {
|
pub fn request_most_recent_file(self: *Self, from: tp.pid_ref) ClientError!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;
|
||||||
from.send(.{file_path}) catch return error.SendFailed;
|
from.send(.{file_path}) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) SendError!void {
|
pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) ClientError!void {
|
||||||
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, "" }) 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| {
|
||||||
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path }) catch return error.SendFailed;
|
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path }) catch return error.ClientFailed;
|
||||||
if (i >= max) return;
|
if (i >= max) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) (OutOfMemoryError || SendError)!usize {
|
fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!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| {
|
||||||
|
@ -178,7 +190,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;
|
||||||
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, matches }) catch return error.SendFailed;
|
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, matches }) catch return error.ClientFailed;
|
||||||
i += 1;
|
i += 1;
|
||||||
if (i >= max) return i;
|
if (i >= max) return i;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +198,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) (OutOfMemoryError || SendError)!usize {
|
pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!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 {};
|
||||||
|
@ -226,7 +238,7 @@ 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|
|
||||||
from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.matches }) catch return error.SendFailed;
|
from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.matches }) catch return error.ClientFailed;
|
||||||
return @min(max, matches.items.len);
|
return @min(max, matches.items.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,31 +291,27 @@ 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) SendError!void {
|
pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) ClientError!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)
|
||||||
from.send(.{ "cmd", "goto_line_and_column", .{ file.row + 1, file.col + 1 } }) catch return error.SendFailed;
|
from.send(.{ "cmd", "goto_line_and_column", .{ file.row + 1, file.col + 1 } }) catch return error.ClientFailed;
|
||||||
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) GetLspError!void {
|
pub fn did_open(self: *Self, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) StartLspError!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_or_start_language_server(file_path, language_server);
|
||||||
if (!self.file_language_server.contains(file_path)) {
|
|
||||||
const key = try self.allocator.dupe(u8, file_path);
|
|
||||||
try self.file_language_server.put(key, lsp);
|
|
||||||
}
|
|
||||||
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);
|
||||||
try lsp.send_notification("textDocument/didOpen", .{
|
lsp.send_notification("textDocument/didOpen", .{
|
||||||
.textDocument = .{ .uri = uri, .languageId = file_type, .version = version, .text = text },
|
.textDocument = .{ .uri = uri, .languageId = file_type, .version = version, .text = text },
|
||||||
});
|
}) catch return error.LspFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_change(self: *Self, file_path: []const u8, version: usize, root_dst_addr: usize, root_src_addr: usize, eol_mode: Buffer.EolMode) GetFileLspError!void {
|
pub fn did_change(self: *Self, file_path: []const u8, version: usize, root_dst_addr: usize, root_src_addr: usize, eol_mode: Buffer.EolMode) LspError!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_language_server(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);
|
||||||
|
|
||||||
|
@ -381,7 +389,7 @@ pub fn did_change(self: *Self, file_path: []const u8, version: usize, root_dst_a
|
||||||
try cbor.writeArrayHeader(msg_writer, edits_count);
|
try cbor.writeArrayHeader(msg_writer, edits_count);
|
||||||
_ = try msg_writer.write(edits_cb.items);
|
_ = try msg_writer.write(edits_cb.items);
|
||||||
|
|
||||||
try lsp.send_notification_raw("textDocument/didChange", msg.items);
|
lsp.send_notification_raw("textDocument/didChange", msg.items) catch return error.LspFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_char(chars: []const u8, lines: *usize, char: u8, last_offset: ?*usize) void {
|
fn scan_char(chars: []const u8, lines: *usize, char: u8, last_offset: ?*usize) void {
|
||||||
|
@ -396,22 +404,22 @@ fn scan_char(chars: []const u8, lines: *usize, char: u8, last_offset: ?*usize) v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_save(self: *Self, file_path: []const u8) !void {
|
pub fn did_save(self: *Self, file_path: []const u8) LspError!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_language_server(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);
|
||||||
try lsp.send_notification("textDocument/didSave", .{
|
lsp.send_notification("textDocument/didSave", .{
|
||||||
.textDocument = .{ .uri = uri },
|
.textDocument = .{ .uri = uri },
|
||||||
});
|
}) catch return error.LspFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_close(self: *Self, file_path: []const u8) !void {
|
pub fn did_close(self: *Self, file_path: []const u8) LspError!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_language_server(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);
|
||||||
try lsp.send_notification("textDocument/didClose", .{
|
lsp.send_notification("textDocument/didClose", .{
|
||||||
.textDocument = .{ .uri = uri },
|
.textDocument = .{ .uri = uri },
|
||||||
});
|
}) catch return error.LspFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void {
|
pub fn goto_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void {
|
||||||
|
@ -430,16 +438,16 @@ pub fn goto_type_definition(self: *Self, from: tp.pid_ref, file_path: []const u8
|
||||||
return self.send_goto_request(from, file_path, row, col, "textDocument/typeDefinition");
|
return self.send_goto_request(from, file_path, row, col, "textDocument/typeDefinition");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SendGotoRequestError = (SendError || InvalidMessageError || GetFileLspError || GetLineOfFileError || cbor.Error);
|
pub const SendGotoRequestError = (LspError || ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error);
|
||||||
|
|
||||||
fn send_goto_request(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize, method: []const u8) SendGotoRequestError!void {
|
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_language_server(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);
|
||||||
const response = try lsp.send_request(self.allocator, method, .{
|
const response = lsp.send_request(self.allocator, method, .{
|
||||||
.textDocument = .{ .uri = uri },
|
.textDocument = .{ .uri = uri },
|
||||||
.position = .{ .line = row, .character = col },
|
.position = .{ .line = row, .character = col },
|
||||||
});
|
}) catch return error.LspFailed;
|
||||||
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;
|
||||||
|
@ -456,7 +464,7 @@ fn send_goto_request(self: *Self, from: tp.pid_ref, file_path: []const u8, row:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const u8) (SendError || InvalidMessageError || cbor.Error)!void {
|
fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const u8) (ClientError || 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;
|
||||||
|
@ -502,7 +510,7 @@ 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;
|
} }) catch return error.ClientFailed;
|
||||||
} else {
|
} else {
|
||||||
from.send(.{ "cmd", "navigate", .{
|
from.send(.{ "cmd", "navigate", .{
|
||||||
.file = file_path,
|
.file = file_path,
|
||||||
|
@ -510,21 +518,21 @@ fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const
|
||||||
targetRange.?.start.line + 1,
|
targetRange.?.start.line + 1,
|
||||||
targetRange.?.start.character + 1,
|
targetRange.?.start.character + 1,
|
||||||
},
|
},
|
||||||
} }) catch return error.SendFailed;
|
} }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!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_language_server(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);
|
||||||
log.logger("lsp").print("finding references...", .{});
|
log.logger("lsp").print("finding references...", .{});
|
||||||
|
|
||||||
const response = try lsp.send_request(self.allocator, "textDocument/references", .{
|
const response = lsp.send_request(self.allocator, "textDocument/references", .{
|
||||||
.textDocument = .{ .uri = uri },
|
.textDocument = .{ .uri = uri },
|
||||||
.position = .{ .line = row, .character = col },
|
.position = .{ .line = row, .character = col },
|
||||||
.context = .{ .includeDeclaration = true },
|
.context = .{ .includeDeclaration = true },
|
||||||
});
|
}) catch return error.LspFailed;
|
||||||
defer self.allocator.free(response.buf);
|
defer self.allocator.free(response.buf);
|
||||||
var locations: []const u8 = undefined;
|
var locations: []const u8 = undefined;
|
||||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||||
|
@ -534,7 +542,7 @@ pub fn references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8) (InvalidMessageError || SendError || GetLineOfFileError || cbor.Error)!void {
|
fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8) (ClientError || InvalidMessageError || 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);
|
||||||
|
@ -548,7 +556,7 @@ fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8) (Inva
|
||||||
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) (InvalidMessageError || SendError || GetLineOfFileError || cbor.Error)!void {
|
fn send_reference(self: *Self, to: tp.pid_ref, location: []const u8) (ClientError || InvalidMessageError || 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;
|
||||||
|
@ -597,30 +605,30 @@ fn send_reference(self: *Self, to: tp.pid_ref, location: []const u8) (InvalidMes
|
||||||
targetRange.?.end.line + 1,
|
targetRange.?.end.line + 1,
|
||||||
targetRange.?.end.character,
|
targetRange.?.end.character,
|
||||||
line,
|
line,
|
||||||
}) catch return error.SendFailed;
|
}) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (SendError || GetFileLspError)!void {
|
pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize, col: usize) LspOrClientError!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_language_server(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);
|
||||||
const response = try lsp.send_request(self.allocator, "textDocument/completion", .{
|
const response = lsp.send_request(self.allocator, "textDocument/completion", .{
|
||||||
.textDocument = .{ .uri = uri },
|
.textDocument = .{ .uri = uri },
|
||||||
.position = .{ .line = row, .character = col },
|
.position = .{ .line = row, .character = col },
|
||||||
});
|
}) catch return error.LspFailed;
|
||||||
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) (SendError || InvalidMessageError || GetFileLspError || cbor.Error)!void {
|
pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) (LspOrClientError || InvalidMessageError || cbor.Error)!void {
|
||||||
const lsp = try self.get_file_lsp(file_path);
|
const lsp = try self.get_language_server(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);
|
||||||
// log.logger("lsp").print("fetching hover information...", .{});
|
// log.logger("lsp").print("fetching hover information...", .{});
|
||||||
|
|
||||||
const response = try lsp.send_request(self.allocator, "textDocument/hover", .{
|
const response = lsp.send_request(self.allocator, "textDocument/hover", .{
|
||||||
.textDocument = .{ .uri = uri },
|
.textDocument = .{ .uri = uri },
|
||||||
.position = .{ .line = row, .character = col },
|
.position = .{ .line = row, .character = col },
|
||||||
});
|
}) catch return error.LspFailed;
|
||||||
defer self.allocator.free(response.buf);
|
defer self.allocator.free(response.buf);
|
||||||
var result: []const u8 = undefined;
|
var result: []const u8 = undefined;
|
||||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||||
|
@ -630,7 +638,7 @@ pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
fn send_hover(self: *Self, to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (ClientError || 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 = "";
|
||||||
|
@ -710,19 +718,19 @@ fn send_content_msg(
|
||||||
kind: []const u8,
|
kind: []const u8,
|
||||||
content: []const u8,
|
content: []const u8,
|
||||||
range: ?Range,
|
range: ?Range,
|
||||||
) SendError!void {
|
) ClientError!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 },
|
||||||
};
|
};
|
||||||
to.send(.{ tag, file_path, kind, content, r.start.line, r.start.character, r.end.line, r.end.character }) catch return error.SendFailed;
|
to.send(.{ tag, file_path, kind, content, r.start.line, r.start.character, r.end.line, r.end.character }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_content_msg_empty(to: tp.pid_ref, tag: []const u8, file_path: []const u8, row: usize, col: usize) SendError!void {
|
fn send_content_msg_empty(to: tp.pid_ref, tag: []const u8, file_path: []const u8, row: usize, col: usize) ClientError!void {
|
||||||
return send_content_msg(to, tag, file_path, row, col, "plaintext", "", null);
|
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) (InvalidMessageError || SendError || cbor.Error)!void {
|
pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||||
var uri: ?[]const u8 = null;
|
var uri: ?[]const u8 = null;
|
||||||
var diagnostics: []const u8 = &.{};
|
var diagnostics: []const u8 = &.{};
|
||||||
var iter = params_cb;
|
var iter = params_cb;
|
||||||
|
@ -756,7 +764,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) (InvalidMessageError || SendError || cbor.Error)!void {
|
fn send_diagnostic(_: *Self, to: tp.pid_ref, file_path: []const u8, diagnostic: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||||
var source: []const u8 = "unknown";
|
var source: []const u8 = "unknown";
|
||||||
var code: []const u8 = "none";
|
var code: []const u8 = "none";
|
||||||
var message: []const u8 = "empty";
|
var message: []const u8 = "empty";
|
||||||
|
@ -794,11 +802,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;
|
} }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_clear_diagnostics(_: *Self, to: tp.pid_ref, file_path: []const u8) SendError!void {
|
fn send_clear_diagnostics(_: *Self, to: tp.pid_ref, file_path: []const u8) ClientError!void {
|
||||||
to.send(.{ "cmd", "clear_diagnostics", .{file_path} }) catch return error.SendFailed;
|
to.send(.{ "cmd", "clear_diagnostics", .{file_path} }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Range = struct { start: Position, end: Position };
|
const Range = struct { start: Position, end: Position };
|
||||||
|
@ -872,19 +880,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) (OutOfMemoryError || SendError)!void {
|
pub fn register_capability(self: *Self, from: tp.pid_ref, id: i32, params_cb: []const u8) ClientError!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) (OutOfMemoryError || SendError)!void {
|
pub fn send_lsp_response(self: *Self, from: tp.pid_ref, id: i32, result: anytype) ClientError!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);
|
||||||
from.send(.{ "RSP", id, cb.items }) catch return error.SendFailed;
|
from.send(.{ "RSP", id, cb.items }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8) (OutOfMemoryError || SpawnError || CallError)!tp.message {
|
fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8) CallError!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,
|
||||||
|
|
|
@ -20,18 +20,18 @@ pub const ProjectError = error{NoProject};
|
||||||
|
|
||||||
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
||||||
const OutOfMemoryError = error{OutOfMemory};
|
const OutOfMemoryError = error{OutOfMemory};
|
||||||
const SendError = (SpawnError || error{SendFailed});
|
|
||||||
const FileSystemError = error{FileSystem};
|
const FileSystemError = error{FileSystem};
|
||||||
const SetCwdError = if (builtin.os.tag == .windows) error{UnrecognizedVolume} else error{};
|
const SetCwdError = if (builtin.os.tag == .windows) error{UnrecognizedVolume} else error{};
|
||||||
const CallError = tp.CallError;
|
const CallError = tp.CallError;
|
||||||
|
const ProjectManagerError = (SpawnError || error{ProjectManagerFailed});
|
||||||
|
|
||||||
pub fn get() SpawnError!Self {
|
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 send(message: anytype) SendError!void {
|
fn send(message: anytype) ProjectManagerError!void {
|
||||||
return (try get()).pid.send(message) catch error.SendFailed;
|
return (try get()).pid.send(message) catch error.ProjectManagerFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create() SpawnError!Self {
|
fn create() SpawnError!Self {
|
||||||
|
@ -50,7 +50,7 @@ pub fn shutdown() void {
|
||||||
pid.send(.{"shutdown"}) catch {};
|
pid.send(.{"shutdown"}) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(rel_project_directory: []const u8) (SpawnError || FileSystemError || SendError || std.fs.File.OpenError || SetCwdError)!void {
|
pub fn open(rel_project_directory: []const u8) (ProjectManagerError || FileSystemError || 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, .{});
|
||||||
|
@ -70,7 +70,7 @@ pub fn request_most_recent_file(allocator: std.mem.Allocator) (CallError || Proj
|
||||||
return if (try cbor.match(rsp.buf, .{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) (ProjectError || SendError)!void {
|
pub fn request_recent_files(max: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
|
@ -82,21 +82,21 @@ pub fn request_recent_projects(allocator: std.mem.Allocator) (ProjectError || Ca
|
||||||
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) (ProjectError || SendError)!void {
|
pub fn query_recent_files(max: usize, query: []const u8) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn request_path_files(max: usize, path: []const u8) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn did_open(file_path: []const u8, file_type: *const FileType, version: usize, text: []const u8) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
|
@ -104,84 +104,84 @@ pub fn did_open(file_path: []const u8, file_type: *const FileType, version: usiz
|
||||||
return 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, eol_mode: Buffer.EolMode) (ProjectError || SendError)!void {
|
pub fn did_change(file_path: []const u8, version: usize, root_dst: usize, root_src: usize, eol_mode: Buffer.EolMode) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return send(.{ "did_change", project, file_path, version, root_dst, root_src, @intFromEnum(eol_mode) });
|
return send(.{ "did_change", project, file_path, version, root_dst, root_src, @intFromEnum(eol_mode) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_save(file_path: []const u8) (ProjectError || SendError)!void {
|
pub fn did_save(file_path: []const u8) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return send(.{ "did_save", project, file_path });
|
return send(.{ "did_save", project, file_path });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_close(file_path: []const u8) (ProjectError || SendError)!void {
|
pub fn did_close(file_path: []const u8) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn goto_definition(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn goto_declaration(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn goto_implementation(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn goto_type_definition(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn references(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn completion(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn hover(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn update_mru(file_path: []const u8, row: usize, col: usize) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
return 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) (ProjectError || SendError)!void {
|
pub fn get_mru_position(file_path: []const u8) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
return error.NoProject;
|
return error.NoProject;
|
||||||
|
@ -241,15 +241,19 @@ const Process = struct {
|
||||||
errdefer self.deinit();
|
errdefer self.deinit();
|
||||||
return self.receive_safe(from, m) catch |e| switch (e) {
|
return self.receive_safe(from, m) catch |e| switch (e) {
|
||||||
error.ExitNormal => tp.exit_normal(),
|
error.ExitNormal => tp.exit_normal(),
|
||||||
else => blk: {
|
error.ClientFailed => {
|
||||||
|
const err = tp.exit_error(e, @errorReturnTrace());
|
||||||
|
self.logger.err("receive", err);
|
||||||
|
return err;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
const err = tp.exit_error(e, @errorReturnTrace());
|
const err = tp.exit_error(e, @errorReturnTrace());
|
||||||
self.logger.err("receive", err);
|
self.logger.err("receive", err);
|
||||||
break :blk err;
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) (error{ExitNormal} || SendError || cbor.Error)!void {
|
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) (error{ ExitNormal, ClientFailed } || 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;
|
||||||
|
@ -281,9 +285,9 @@ const Process = struct {
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} 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) })) {
|
} 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 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) })) {
|
} 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) })) {
|
||||||
|
@ -291,51 +295,53 @@ const Process = struct {
|
||||||
} else if (try cbor.match(m.buf, .{ "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 cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.open(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.request_most_recent_file(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.request_recent_projects(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.request_path_files(from, project_directory, max, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} 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) })) {
|
} 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()) catch error.SendFailed;
|
self.did_open(project_directory, path, file_type, language_server, version, text) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} 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), tp.extract(&eol_mode) })) {
|
} 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), tp.extract(&eol_mode) })) {
|
||||||
self.did_change(project_directory, path, version, root_dst, root_src, @enumFromInt(eol_mode)) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.SendFailed;
|
self.did_change(project_directory, path, version, root_dst, root_src, @enumFromInt(eol_mode)) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.did_save(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.did_close(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.goto_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.goto_declaration(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.goto_implementation(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.goto_type_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.references(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.completion(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.hover(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "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()) catch error.SendFailed;
|
self.get_mru_position(from, project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{"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();
|
||||||
from.send(.{ "project_manager", "shutdown" }) catch return error.SendFailed;
|
from.send(.{ "project_manager", "shutdown" }) catch return error.ClientFailed;
|
||||||
return error.ExitNormal;
|
return error.ExitNormal;
|
||||||
} else if (try cbor.match(m.buf, .{ "exit", "normal" })) {
|
} else if (try cbor.match(m.buf, .{ "exit", "normal" })) {
|
||||||
return;
|
return;
|
||||||
} else if (try cbor.match(m.buf, .{ "exit", "DEADSEND", tp.more })) {
|
} else if (try cbor.match(m.buf, .{ "exit", "DEADSEND", tp.more })) {
|
||||||
return;
|
return;
|
||||||
|
} else if (try cbor.match(m.buf, .{ "exit", "error.FileNotFound", tp.more })) {
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
self.logger.err("receive", tp.unexpected(m));
|
self.logger.err("receive", tp.unexpected(m));
|
||||||
}
|
}
|
||||||
|
@ -365,19 +371,19 @@ const Process = struct {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_most_recent_file(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || SendError)!void {
|
fn request_most_recent_file(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
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) (ProjectError || SendError)!void {
|
fn request_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || Project.ClientError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
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) (ProjectError || SendError)!void {
|
fn request_recent_projects(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!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 {};
|
||||||
|
@ -387,10 +393,10 @@ 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);
|
||||||
from.send_raw(.{ .buf = message.items }) catch return error.SendFailed;
|
from.send_raw(.{ .buf = message.items }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || SendError)!void {
|
fn query_recent_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || Project.ClientError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
const 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);
|
||||||
|
@ -404,28 +410,28 @@ const Process = struct {
|
||||||
try request_path_files_async(self.allocator, from, project, max, path);
|
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) (ProjectError || InvalidArgumentError || SendError || CallError || cbor.Error)!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 || Project.StartLspError || 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 error.NoProject;
|
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, eol_mode: Buffer.EolMode) (ProjectError || Project.GetFileLspError)!void {
|
fn did_change(self: *Process, project_directory: []const u8, file_path: []const u8, version: usize, root_dst: usize, root_src: usize, eol_mode: Buffer.EolMode) (ProjectError || Project.LspError)!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 error.NoProject;
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
return project.did_change(file_path, version, root_dst, root_src, eol_mode);
|
return project.did_change(file_path, version, root_dst, root_src, eol_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn did_save(self: *Process, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.GetFileLspError)!void {
|
fn did_save(self: *Process, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.LspError)!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 error.NoProject;
|
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) (ProjectError || Project.GetFileLspError)!void {
|
fn did_close(self: *Process, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.LspError)!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 error.NoProject;
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
|
@ -467,21 +473,21 @@ const Process = struct {
|
||||||
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) (ProjectError || SendError || Project.GetFileLspError)!void {
|
fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.LspOrClientError)!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 error.NoProject;
|
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) (ProjectError || SendError || Project.InvalidMessageError || Project.GetFileLspError || cbor.Error)!void {
|
fn hover(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) (ProjectError || Project.InvalidMessageError || Project.LspOrClientError || cbor.Error)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".hover" });
|
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".hover" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
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) (ProjectError || SendError)!void {
|
fn get_mru_position(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) (ProjectError || Project.ClientError)!void {
|
||||||
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".get_mru_position" });
|
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 error.NoProject;
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
|
@ -493,7 +499,7 @@ const Process = struct {
|
||||||
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) (ProjectError || Project.InvalidMessageError || SendError || cbor.Error || cbor.JsonEncodeError)!void {
|
fn dispatch_notify(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, params_cb: []const u8) (ProjectError || Project.ClientError || Project.InvalidMessageError || cbor.Error || cbor.JsonEncodeError)!void {
|
||||||
_ = language_server;
|
_ = language_server;
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
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"))
|
||||||
|
@ -509,7 +515,7 @@ 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) (ProjectError || SendError || cbor.Error || cbor.JsonEncodeError || UnsupportedError)!void {
|
fn dispatch_request(self: *Process, from: tp.pid_ref, project_directory: []const u8, language_server: []const u8, method: []const u8, id: i32, params_cb: []const u8) (ProjectError || Project.ClientError || cbor.Error || cbor.JsonEncodeError || UnsupportedError)!void {
|
||||||
_ = language_server;
|
_ = language_server;
|
||||||
const project = if (self.projects.get(project_directory)) |p| p else return error.NoProject;
|
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"))
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub const Error = (cbor.Error || cbor.JsonEncodeError || error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
ThespianSpawnFailed,
|
ThespianSpawnFailed,
|
||||||
NoProject,
|
NoProject,
|
||||||
|
ProjectManagerFailed,
|
||||||
SendFailed,
|
SendFailed,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -307,14 +307,14 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
||||||
if (try self.send_widgets(from, m))
|
if (try self.send_widgets(from, m))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (try m.match(.{ "exit", "normal" }))
|
if (try m.match(.{ "exit", tp.more })) {
|
||||||
return;
|
if (try m.match(.{ tp.string, "normal" }) or
|
||||||
|
try m.match(.{ tp.string, "timeout_error", 125, "Operation aborted." }) or
|
||||||
if (try m.match(.{ "exit", "timeout_error", 125, "Operation aborted." }))
|
try m.match(.{ tp.string, "DEADSEND", tp.more }) or
|
||||||
return;
|
try m.match(.{ tp.string, "error.LspFailed", tp.more }) or
|
||||||
|
try m.match(.{ tp.string, "error.NoLsp", tp.more }))
|
||||||
if (try m.match(.{ "exit", "DEADSEND", tp.more }))
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var msg: []const u8 = undefined;
|
var msg: []const u8 = undefined;
|
||||||
if (try m.match(.{ "exit", tp.extract(&msg) }) or try m.match(.{ "exit", tp.extract(&msg), tp.more })) {
|
if (try m.match(.{ "exit", tp.extract(&msg) }) or try m.match(.{ "exit", tp.extract(&msg), tp.more })) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue