diff --git a/src/LSP.zig b/src/LSP.zig index 4fe9952..2afae60 100644 --- a/src/LSP.zig +++ b/src/LSP.zig @@ -17,22 +17,34 @@ const OutOfMemoryError = error{OutOfMemory}; const SendError = error{SendFailed}; const SpawnError = error{ThespianSpawnFailed}; -pub fn open(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) (error{ ThespianSpawnFailed, InvalidLspCommand } || cbor.Error)!Self { - return .{ .allocator = allocator, .pid = try Process.create(allocator, project, cmd) }; +pub fn open( + allocator: std.mem.Allocator, + project: []const u8, + cmd: tp.message, +) (error{ ThespianSpawnFailed, InvalidLspCommand } || cbor.Error)!*const Self { + const self = try allocator.create(Self); + errdefer allocator.destroy(self); + self.* = .{ + .allocator = allocator, + .pid = try Process.create(allocator, project, cmd), + }; + return self; } -pub fn deinit(self: Self) void { +pub fn deinit(self: *const Self) void { self.pid.send(.{"close"}) catch {}; self.pid.deinit(); + self.allocator.destroy(self); } -pub fn term(self: Self) void { +pub fn term(self: *const Self) void { self.pid.send(.{"term"}) catch {}; self.pid.deinit(); + self.allocator.destroy(self); } pub fn send_request( - self: Self, + self: *const Self, allocator: std.mem.Allocator, method: []const u8, m: anytype, @@ -44,14 +56,14 @@ pub fn send_request( return RequestContext(@TypeOf(ctx)).send(allocator, self.pid.ref(), ctx, tp.message.fmt(.{ "REQ", method, cb.items })); } -pub fn send_notification(self: Self, method: []const u8, m: anytype) (OutOfMemoryError || SendError)!void { +pub fn send_notification(self: *const Self, method: []const u8, m: anytype) (OutOfMemoryError || SendError)!void { var cb = std.ArrayList(u8).init(self.allocator); defer cb.deinit(); try cbor.writeValue(cb.writer(), m); return self.send_notification_raw(method, cb.items); } -pub fn send_notification_raw(self: Self, method: []const u8, cb: []const u8) SendError!void { +pub fn send_notification_raw(self: *const Self, method: []const u8, cb: []const u8) SendError!void { self.pid.send(.{ "NTFY", method, cb }) catch return error.SendFailed; } diff --git a/src/Project.zig b/src/Project.zig index 19e4399..2306d78 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -19,8 +19,8 @@ files: std.ArrayListUnmanaged(File) = .empty, pending: std.ArrayListUnmanaged(File) = .empty, longest_file_path: usize = 0, open_time: i64, -language_servers: std.StringHashMap(LSP), -file_language_server: std.StringHashMap(LSP), +language_servers: std.StringHashMap(*const LSP), +file_language_server: std.StringHashMap(*const LSP), tasks: std.ArrayList(Task), persistent: bool = false, logger: log.Logger, @@ -74,8 +74,8 @@ pub fn init(allocator: std.mem.Allocator, name: []const u8) OutOfMemoryError!Sel .allocator = allocator, .name = try allocator.dupe(u8, name), .open_time = std.time.milliTimestamp(), - .language_servers = std.StringHashMap(LSP).init(allocator), - .file_language_server = std.StringHashMap(LSP).init(allocator), + .language_servers = std.StringHashMap(*const LSP).init(allocator), + .file_language_server = std.StringHashMap(*const LSP).init(allocator), .tasks = std.ArrayList(Task).init(allocator), .logger = log.logger("project"), .logger_lsp = log.logger("lsp"), @@ -261,11 +261,14 @@ pub fn restore_state_v0(self: *Self, data: []const u8) error{ } } -fn get_language_server_instance(self: *Self, language_server: []const u8) StartLspError!LSP { +fn get_language_server_instance(self: *Self, language_server: []const u8) StartLspError!*const LSP { if (self.language_servers.get(language_server)) |lsp| { - if (!lsp.pid.expired()) return lsp; - lsp.deinit(); - _ = self.language_servers.remove(language_server); + if (lsp.pid.expired()) { + _ = self.language_servers.remove(language_server); + lsp.deinit(); + } else { + return lsp; + } } const lsp = try LSP.open(self.allocator, self.name, .{ .buf = language_server }); errdefer lsp.deinit(); @@ -279,7 +282,7 @@ fn get_language_server_instance(self: *Self, language_server: []const u8) StartL return lsp; } -fn get_or_start_language_server(self: *Self, file_path: []const u8, language_server: []const u8) StartLspError!LSP { +fn get_or_start_language_server(self: *Self, file_path: []const u8, language_server: []const u8) StartLspError!*const 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); @@ -289,7 +292,7 @@ fn get_or_start_language_server(self: *Self, file_path: []const u8, language_ser return lsp; } -fn get_language_server(self: *Self, file_path: []const u8) LspError!LSP { +fn get_language_server(self: *Self, file_path: []const u8) LspError!*const LSP { const lsp = self.file_language_server.get(file_path) orelse return error.NoLsp; if (lsp.pid.expired()) { if (self.file_language_server.fetchRemove(file_path)) |kv| @@ -1510,7 +1513,7 @@ pub fn send_lsp_response(self: *Self, from: tp.pid_ref, cbor_id: []const u8, res from.send_raw(.{ .buf = 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, language_server: []const u8) !void { +fn send_lsp_init_request(self: *Self, lsp: *const LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8, language_server: []const u8) !void { const handler: struct { language_server: []const u8, lsp: LSP,