refactor: lots and lots of writergate changes
This commit is contained in:
parent
96e8100373
commit
e6b39c274c
19 changed files with 437 additions and 382 deletions
|
|
@ -30,8 +30,8 @@
|
||||||
.hash = "fuzzig-0.1.1-Ji0xivxIAQBD0g8O_NV_0foqoPf3elsg9Sc3pNfdVH4D",
|
.hash = "fuzzig-0.1.1-Ji0xivxIAQBD0g8O_NV_0foqoPf3elsg9Sc3pNfdVH4D",
|
||||||
},
|
},
|
||||||
.vaxis = .{
|
.vaxis = .{
|
||||||
.url = "git+https://github.com/neurocyte/libvaxis?ref=zig-0.15#db66bacf4799945c9d99704bf150112df2d688cf",
|
.url = "git+https://github.com/neurocyte/libvaxis?ref=main#35c384757b713c206d11efd76448eaea429f587e",
|
||||||
.hash = "vaxis-0.5.1-BWNV_J0eCQD_x1nEGocK1PgaTZU9L81qc9Vf3IIGx7W2",
|
.hash = "vaxis-0.5.1-BWNV_GQeCQBDaH91XVg4ql_F5RBv__F_Y-_eQ2nCuyNk",
|
||||||
},
|
},
|
||||||
.zeit = .{
|
.zeit = .{
|
||||||
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
|
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
|
||||||
|
|
|
||||||
155
src/LSP.zig
155
src/LSP.zig
|
|
@ -48,18 +48,18 @@ pub fn send_request(
|
||||||
method: []const u8,
|
method: []const u8,
|
||||||
m: anytype,
|
m: anytype,
|
||||||
ctx: anytype,
|
ctx: anytype,
|
||||||
) (OutOfMemoryError || SpawnError)!void {
|
) (OutOfMemoryError || SpawnError || std.Io.Writer.Error)!void {
|
||||||
var cb = std.ArrayList(u8).init(self.allocator);
|
var cb: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
try cbor.writeValue(cb.writer(), m);
|
try cbor.writeValue(&cb.writer, m);
|
||||||
return RequestContext(@TypeOf(ctx)).send(allocator, self.pid.ref(), ctx, tp.message.fmt(.{ "REQ", method, cb.items }));
|
return RequestContext(@TypeOf(ctx)).send(allocator, self.pid.ref(), ctx, tp.message.fmt(.{ "REQ", method, cb.written() }));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_notification(self: *const Self, method: []const u8, m: anytype) (OutOfMemoryError || SendError)!void {
|
pub fn send_notification(self: *const Self, method: []const u8, m: anytype) (OutOfMemoryError || SendError || std.Io.Writer.Error)!void {
|
||||||
var cb = std.ArrayList(u8).init(self.allocator);
|
var cb: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
try cbor.writeValue(cb.writer(), m);
|
try cbor.writeValue(&cb.writer, m);
|
||||||
return self.send_notification_raw(method, cb.items);
|
return self.send_notification_raw(method, cb.written());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_notification_raw(self: *const 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 {
|
||||||
|
|
@ -82,27 +82,27 @@ pub const ErrorCode = enum(i32) {
|
||||||
RequestCancelled = -32800,
|
RequestCancelled = -32800,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn send_response(allocator: std.mem.Allocator, to: tp.pid_ref, cbor_id: []const u8, result: anytype) (SendError || OutOfMemoryError)!void {
|
pub fn send_response(allocator: std.mem.Allocator, to: tp.pid_ref, cbor_id: []const u8, result: anytype) (SendError || OutOfMemoryError || std.Io.Writer.Error)!void {
|
||||||
var cb = std.ArrayList(u8).init(allocator);
|
var cb: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
const writer = cb.writer();
|
const writer = &cb.writer;
|
||||||
try cbor.writeArrayHeader(writer, 3);
|
try cbor.writeArrayHeader(writer, 3);
|
||||||
try cbor.writeValue(writer, "RSP");
|
try cbor.writeValue(writer, "RSP");
|
||||||
try writer.writeAll(cbor_id);
|
try writer.writeAll(cbor_id);
|
||||||
try cbor.writeValue(cb.writer(), result);
|
try cbor.writeValue(writer, result);
|
||||||
to.send_raw(.{ .buf = cb.items }) catch return error.SendFailed;
|
to.send_raw(.{ .buf = cb.written() }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_error_response(allocator: std.mem.Allocator, to: tp.pid_ref, cbor_id: []const u8, code: ErrorCode, message: []const u8) (SendError || OutOfMemoryError)!void {
|
pub fn send_error_response(allocator: std.mem.Allocator, to: tp.pid_ref, cbor_id: []const u8, code: ErrorCode, message: []const u8) (SendError || OutOfMemoryError || std.Io.Writer.Error)!void {
|
||||||
var cb = std.ArrayList(u8).init(allocator);
|
var cb: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer cb.deinit();
|
defer cb.deinit();
|
||||||
const writer = cb.writer();
|
const writer = &cb.writer;
|
||||||
try cbor.writeArrayHeader(writer, 4);
|
try cbor.writeArrayHeader(writer, 4);
|
||||||
try cbor.writeValue(writer, "ERR");
|
try cbor.writeValue(writer, "ERR");
|
||||||
try writer.writeAll(cbor_id);
|
try writer.writeAll(cbor_id);
|
||||||
try cbor.writeValue(cb.writer(), code);
|
try cbor.writeValue(writer, code);
|
||||||
try cbor.writeValue(cb.writer(), message);
|
try cbor.writeValue(writer, message);
|
||||||
to.send_raw(.{ .buf = cb.items }) catch return error.SendFailed;
|
to.send_raw(.{ .buf = cb.written() }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self: *Self) void {
|
pub fn close(self: *Self) void {
|
||||||
|
|
@ -172,6 +172,8 @@ const Process = struct {
|
||||||
sp_tag: [:0]const u8,
|
sp_tag: [:0]const u8,
|
||||||
log_file: ?std.fs.File = null,
|
log_file: ?std.fs.File = null,
|
||||||
log_file_path: ?[]const u8 = null,
|
log_file_path: ?[]const u8 = null,
|
||||||
|
log_file_writer: ?std.fs.File.Writer = null,
|
||||||
|
log_file_writer_buf: [1024]u8 = undefined,
|
||||||
next_id: i32 = 0,
|
next_id: i32 = 0,
|
||||||
requests: std.StringHashMap(tp.pid),
|
requests: std.StringHashMap(tp.pid),
|
||||||
state: enum { init, running } = .init,
|
state: enum { init, running } = .init,
|
||||||
|
|
@ -181,7 +183,7 @@ const Process = struct {
|
||||||
|
|
||||||
const Receiver = tp.Receiver(*Process);
|
const Receiver = tp.Receiver(*Process);
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) (error{ ThespianSpawnFailed, InvalidLspCommand } || OutOfMemoryError || cbor.Error)!tp.pid {
|
pub fn create(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) (error{ ThespianSpawnFailed, InvalidLspCommand } || OutOfMemoryError || cbor.Error || std.Io.Writer.Error)!tp.pid {
|
||||||
var tag: []const u8 = undefined;
|
var tag: []const u8 = undefined;
|
||||||
if (try cbor.match(cmd.buf, .{tp.extract(&tag)})) {
|
if (try cbor.match(cmd.buf, .{tp.extract(&tag)})) {
|
||||||
//
|
//
|
||||||
|
|
@ -194,15 +196,15 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
const self = try allocator.create(Process);
|
const self = try allocator.create(Process);
|
||||||
errdefer allocator.destroy(self);
|
errdefer allocator.destroy(self);
|
||||||
var sp_tag_ = std.ArrayList(u8).init(allocator);
|
var sp_tag_: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer sp_tag_.deinit();
|
defer sp_tag_.deinit();
|
||||||
try sp_tag_.appendSlice(tag);
|
try sp_tag_.writer.writeAll(tag);
|
||||||
try sp_tag_.appendSlice("-" ++ sp_tag);
|
try sp_tag_.writer.writeAll("-" ++ sp_tag);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.cmd = try cmd.clone(allocator),
|
.cmd = try cmd.clone(allocator),
|
||||||
.receiver = Receiver.init(receive, self),
|
.receiver = Receiver.init(receive, self),
|
||||||
.recv_buf = std.ArrayList(u8).init(allocator),
|
.recv_buf = .empty,
|
||||||
.parent = tp.self_pid().clone(),
|
.parent = tp.self_pid().clone(),
|
||||||
.tag = try allocator.dupeZ(u8, tag),
|
.tag = try allocator.dupeZ(u8, tag),
|
||||||
.project = try allocator.dupeZ(u8, project),
|
.project = try allocator.dupeZ(u8, project),
|
||||||
|
|
@ -220,11 +222,14 @@ const Process = struct {
|
||||||
req.value_ptr.deinit();
|
req.value_ptr.deinit();
|
||||||
}
|
}
|
||||||
self.allocator.free(self.sp_tag);
|
self.allocator.free(self.sp_tag);
|
||||||
self.recv_buf.deinit();
|
self.recv_buf.deinit(self.allocator);
|
||||||
self.allocator.free(self.cmd.buf);
|
self.allocator.free(self.cmd.buf);
|
||||||
self.close() catch {};
|
self.close() catch {};
|
||||||
self.write_log("### terminated LSP process ###\n", .{});
|
self.write_log("### terminated LSP process ###\n", .{});
|
||||||
if (self.log_file) |file| file.close();
|
if (self.log_file) |file| {
|
||||||
|
if (self.log_file_writer) |*writer| writer.interface.flush() catch {};
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
if (self.log_file_path) |file_path| self.allocator.free(file_path);
|
if (self.log_file_path) |file_path| self.allocator.free(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,12 +270,13 @@ const Process = struct {
|
||||||
self.sp = tp.subprocess.init(self.allocator, self.cmd, self.sp_tag, .Pipe) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
self.sp = tp.subprocess.init(self.allocator, self.cmd, self.sp_tag, .Pipe) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
tp.receive(&self.receiver);
|
tp.receive(&self.receiver);
|
||||||
|
|
||||||
var log_file_path = std.ArrayList(u8).init(self.allocator);
|
var log_file_path: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer log_file_path.deinit();
|
defer log_file_path.deinit();
|
||||||
const state_dir = root.get_state_dir() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
const state_dir = root.get_state_dir() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
log_file_path.writer().print("{s}{c}lsp-{s}.log", .{ state_dir, std.fs.path.sep, self.tag }) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
log_file_path.writer.print("{s}{c}lsp-{s}.log", .{ state_dir, std.fs.path.sep, self.tag }) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
self.log_file = std.fs.createFileAbsolute(log_file_path.items, .{ .truncate = true }) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
self.log_file = std.fs.createFileAbsolute(log_file_path.written(), .{ .truncate = true }) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
self.log_file_path = log_file_path.toOwnedSlice() catch null;
|
self.log_file_path = log_file_path.toOwnedSlice() catch null;
|
||||||
|
if (self.log_file) |log_file| self.log_file_writer = log_file.writer(&self.log_file_writer_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
||||||
|
|
@ -441,7 +447,7 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_output(self: *Process, bytes: []const u8) Error!void {
|
fn handle_output(self: *Process, bytes: []const u8) Error!void {
|
||||||
try self.recv_buf.appendSlice(bytes);
|
try self.recv_buf.appendSlice(self.allocator, bytes);
|
||||||
self.write_log("### RECV:\n{s}\n###\n", .{bytes});
|
self.write_log("### RECV:\n{s}\n###\n", .{bytes});
|
||||||
self.frame_message_recv() catch |e| {
|
self.frame_message_recv() catch |e| {
|
||||||
self.write_log("### RECV error: {any}\n", .{e});
|
self.write_log("### RECV error: {any}\n", .{e});
|
||||||
|
|
@ -473,9 +479,9 @@ const Process = struct {
|
||||||
const id = self.next_id;
|
const id = self.next_id;
|
||||||
self.next_id += 1;
|
self.next_id += 1;
|
||||||
|
|
||||||
var request = std.ArrayList(u8).init(self.allocator);
|
var request: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer request.deinit();
|
defer request.deinit();
|
||||||
const msg_writer = request.writer();
|
const msg_writer = &request.writer;
|
||||||
try cbor.writeMapHeader(msg_writer, 4);
|
try cbor.writeMapHeader(msg_writer, 4);
|
||||||
try cbor.writeValue(msg_writer, "jsonrpc");
|
try cbor.writeValue(msg_writer, "jsonrpc");
|
||||||
try cbor.writeValue(msg_writer, "2.0");
|
try cbor.writeValue(msg_writer, "2.0");
|
||||||
|
|
@ -486,32 +492,32 @@ const Process = struct {
|
||||||
try cbor.writeValue(msg_writer, "params");
|
try cbor.writeValue(msg_writer, "params");
|
||||||
_ = try msg_writer.write(params_cb);
|
_ = try msg_writer.write(params_cb);
|
||||||
|
|
||||||
const json = try cbor.toJsonAlloc(self.allocator, request.items);
|
const json = try cbor.toJsonAlloc(self.allocator, request.written());
|
||||||
defer self.allocator.free(json);
|
defer self.allocator.free(json);
|
||||||
var output = std.ArrayList(u8).init(self.allocator);
|
var output: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer output.deinit();
|
defer output.deinit();
|
||||||
const writer = output.writer();
|
const writer = &output.writer;
|
||||||
const terminator = "\r\n";
|
const terminator = "\r\n";
|
||||||
const content_length = json.len + terminator.len;
|
const content_length = json.len + terminator.len;
|
||||||
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
||||||
_ = try writer.write(json);
|
_ = try writer.write(json);
|
||||||
_ = try writer.write(terminator);
|
_ = try writer.write(terminator);
|
||||||
|
|
||||||
sp.send(output.items) catch return error.SendFailed;
|
sp.send(output.written()) catch return error.SendFailed;
|
||||||
self.write_log("### SEND request:\n{s}\n###\n", .{output.items});
|
self.write_log("### SEND request:\n{s}\n###\n", .{output.written()});
|
||||||
|
|
||||||
var cbor_id = std.ArrayList(u8).init(self.allocator);
|
var cbor_id: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer cbor_id.deinit();
|
defer cbor_id.deinit();
|
||||||
try cbor.writeValue(cbor_id.writer(), id);
|
try cbor.writeValue(&cbor_id.writer, id);
|
||||||
try self.requests.put(try cbor_id.toOwnedSlice(), from.clone());
|
try self.requests.put(try cbor_id.toOwnedSlice(), from.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_response(self: *Process, cbor_id: []const u8, result_cb: []const u8) (error{Closed} || SendError || cbor.Error || cbor.JsonEncodeError)!void {
|
fn send_response(self: *Process, cbor_id: []const u8, result_cb: []const u8) (error{Closed} || SendError || cbor.Error || cbor.JsonEncodeError)!void {
|
||||||
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
||||||
|
|
||||||
var response = std.ArrayList(u8).init(self.allocator);
|
var response: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer response.deinit();
|
defer response.deinit();
|
||||||
const msg_writer = response.writer();
|
const msg_writer = &response.writer;
|
||||||
try cbor.writeMapHeader(msg_writer, 3);
|
try cbor.writeMapHeader(msg_writer, 3);
|
||||||
try cbor.writeValue(msg_writer, "jsonrpc");
|
try cbor.writeValue(msg_writer, "jsonrpc");
|
||||||
try cbor.writeValue(msg_writer, "2.0");
|
try cbor.writeValue(msg_writer, "2.0");
|
||||||
|
|
@ -520,27 +526,28 @@ const Process = struct {
|
||||||
try cbor.writeValue(msg_writer, "result");
|
try cbor.writeValue(msg_writer, "result");
|
||||||
_ = try msg_writer.write(result_cb);
|
_ = try msg_writer.write(result_cb);
|
||||||
|
|
||||||
const json = try cbor.toJsonAlloc(self.allocator, response.items);
|
const json = try cbor.toJsonAlloc(self.allocator, response.written());
|
||||||
defer self.allocator.free(json);
|
defer self.allocator.free(json);
|
||||||
var output = std.ArrayList(u8).init(self.allocator);
|
|
||||||
|
var output: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer output.deinit();
|
defer output.deinit();
|
||||||
const writer = output.writer();
|
const writer = &output.writer;
|
||||||
const terminator = "\r\n";
|
const terminator = "\r\n";
|
||||||
const content_length = json.len + terminator.len;
|
const content_length = json.len + terminator.len;
|
||||||
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
||||||
_ = try writer.write(json);
|
_ = try writer.write(json);
|
||||||
_ = try writer.write(terminator);
|
_ = try writer.write(terminator);
|
||||||
|
|
||||||
sp.send(output.items) catch return error.SendFailed;
|
sp.send(output.written()) catch return error.SendFailed;
|
||||||
self.write_log("### SEND response:\n{s}\n###\n", .{output.items});
|
self.write_log("### SEND response:\n{s}\n###\n", .{output.written()});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_error_response(self: *Process, cbor_id: []const u8, error_code: ErrorCode, message: []const u8) (error{Closed} || SendError || cbor.Error || cbor.JsonEncodeError)!void {
|
fn send_error_response(self: *Process, cbor_id: []const u8, error_code: ErrorCode, message: []const u8) (error{Closed} || SendError || cbor.Error || cbor.JsonEncodeError)!void {
|
||||||
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
const sp = if (self.sp) |*sp| sp else return error.Closed;
|
||||||
|
|
||||||
var response = std.ArrayList(u8).init(self.allocator);
|
var response: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer response.deinit();
|
defer response.deinit();
|
||||||
const msg_writer = response.writer();
|
const msg_writer = &response.writer;
|
||||||
try cbor.writeMapHeader(msg_writer, 3);
|
try cbor.writeMapHeader(msg_writer, 3);
|
||||||
try cbor.writeValue(msg_writer, "jsonrpc");
|
try cbor.writeValue(msg_writer, "jsonrpc");
|
||||||
try cbor.writeValue(msg_writer, "2.0");
|
try cbor.writeValue(msg_writer, "2.0");
|
||||||
|
|
@ -553,19 +560,20 @@ const Process = struct {
|
||||||
try cbor.writeValue(msg_writer, "message");
|
try cbor.writeValue(msg_writer, "message");
|
||||||
try cbor.writeValue(msg_writer, message);
|
try cbor.writeValue(msg_writer, message);
|
||||||
|
|
||||||
const json = try cbor.toJsonAlloc(self.allocator, response.items);
|
const json = try cbor.toJsonAlloc(self.allocator, response.written());
|
||||||
defer self.allocator.free(json);
|
defer self.allocator.free(json);
|
||||||
var output = std.ArrayList(u8).init(self.allocator);
|
|
||||||
|
var output: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer output.deinit();
|
defer output.deinit();
|
||||||
const writer = output.writer();
|
const writer = &output.writer;
|
||||||
const terminator = "\r\n";
|
const terminator = "\r\n";
|
||||||
const content_length = json.len + terminator.len;
|
const content_length = json.len + terminator.len;
|
||||||
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
||||||
_ = try writer.write(json);
|
_ = try writer.write(json);
|
||||||
_ = try writer.write(terminator);
|
_ = try writer.write(terminator);
|
||||||
|
|
||||||
sp.send(output.items) catch return error.SendFailed;
|
sp.send(output.written()) catch return error.SendFailed;
|
||||||
self.write_log("### SEND error response:\n{s}\n###\n", .{output.items});
|
self.write_log("### SEND error response:\n{s}\n###\n", .{output.written()});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_notification(self: *Process, method: []const u8, params_cb: []const u8) Error!void {
|
fn send_notification(self: *Process, method: []const u8, params_cb: []const u8) Error!void {
|
||||||
|
|
@ -573,9 +581,9 @@ const Process = struct {
|
||||||
|
|
||||||
const have_params = !(cbor.match(params_cb, cbor.null_) catch false);
|
const have_params = !(cbor.match(params_cb, cbor.null_) catch false);
|
||||||
|
|
||||||
var notification = std.ArrayList(u8).init(self.allocator);
|
var notification: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer notification.deinit();
|
defer notification.deinit();
|
||||||
const msg_writer = notification.writer();
|
const msg_writer = ¬ification.writer;
|
||||||
try cbor.writeMapHeader(msg_writer, 3);
|
try cbor.writeMapHeader(msg_writer, 3);
|
||||||
try cbor.writeValue(msg_writer, "jsonrpc");
|
try cbor.writeValue(msg_writer, "jsonrpc");
|
||||||
try cbor.writeValue(msg_writer, "2.0");
|
try cbor.writeValue(msg_writer, "2.0");
|
||||||
|
|
@ -588,19 +596,20 @@ const Process = struct {
|
||||||
try cbor.writeMapHeader(msg_writer, 0);
|
try cbor.writeMapHeader(msg_writer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = try cbor.toJsonAlloc(self.allocator, notification.items);
|
const json = try cbor.toJsonAlloc(self.allocator, notification.written());
|
||||||
defer self.allocator.free(json);
|
defer self.allocator.free(json);
|
||||||
var output = std.ArrayList(u8).init(self.allocator);
|
|
||||||
|
var output: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer output.deinit();
|
defer output.deinit();
|
||||||
const writer = output.writer();
|
const writer = &output.writer;
|
||||||
const terminator = "\r\n";
|
const terminator = "\r\n";
|
||||||
const content_length = json.len + terminator.len;
|
const content_length = json.len + terminator.len;
|
||||||
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
try writer.print("Content-Length: {d}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n", .{content_length});
|
||||||
_ = try writer.write(json);
|
_ = try writer.write(json);
|
||||||
_ = try writer.write(terminator);
|
_ = try writer.write(terminator);
|
||||||
|
|
||||||
sp.send(output.items) catch return error.SendFailed;
|
sp.send(output.written()) catch return error.SendFailed;
|
||||||
self.write_log("### SEND notification:\n{s}\n###\n", .{output.items});
|
self.write_log("### SEND notification:\n{s}\n###\n", .{output.written()});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_message_recv(self: *Process) Error!void {
|
fn frame_message_recv(self: *Process) Error!void {
|
||||||
|
|
@ -609,11 +618,11 @@ const Process = struct {
|
||||||
const headers_data = self.recv_buf.items[0..headers_end];
|
const headers_data = self.recv_buf.items[0..headers_end];
|
||||||
const headers = try Headers.parse(headers_data);
|
const headers = try Headers.parse(headers_data);
|
||||||
if (self.recv_buf.items.len - (headers_end + sep.len) < headers.content_length) return;
|
if (self.recv_buf.items.len - (headers_end + sep.len) < headers.content_length) return;
|
||||||
const buf = try self.recv_buf.toOwnedSlice();
|
const buf = try self.recv_buf.toOwnedSlice(self.allocator);
|
||||||
const data = buf[headers_end + sep.len .. headers_end + sep.len + headers.content_length];
|
const data = buf[headers_end + sep.len .. headers_end + sep.len + headers.content_length];
|
||||||
const rest = buf[headers_end + sep.len + headers.content_length ..];
|
const rest = buf[headers_end + sep.len + headers.content_length ..];
|
||||||
defer self.allocator.free(buf);
|
defer self.allocator.free(buf);
|
||||||
if (rest.len > 0) try self.recv_buf.appendSlice(rest);
|
if (rest.len > 0) try self.recv_buf.appendSlice(self.allocator, rest);
|
||||||
const message = .{ .body = data[0..headers.content_length] };
|
const message = .{ .body = data[0..headers.content_length] };
|
||||||
const cb = try cbor.fromJsonAlloc(self.allocator, message.body);
|
const cb = try cbor.fromJsonAlloc(self.allocator, message.body);
|
||||||
defer self.allocator.free(cb);
|
defer self.allocator.free(cb);
|
||||||
|
|
@ -627,9 +636,9 @@ const Process = struct {
|
||||||
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
||||||
defer if (json) |p| self.allocator.free(p);
|
defer if (json) |p| self.allocator.free(p);
|
||||||
self.write_log("### RECV req: {s}\nmethod: {s}\n{s}\n###\n", .{ json_id, method, json orelse "no params" });
|
self.write_log("### RECV req: {s}\nmethod: {s}\n{s}\n###\n", .{ json_id, method, json orelse "no params" });
|
||||||
var request = std.ArrayList(u8).init(self.allocator);
|
var request: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer request.deinit();
|
defer request.deinit();
|
||||||
const writer = request.writer();
|
const writer = &request.writer;
|
||||||
try cbor.writeArrayHeader(writer, 7);
|
try cbor.writeArrayHeader(writer, 7);
|
||||||
try cbor.writeValue(writer, sp_tag);
|
try cbor.writeValue(writer, sp_tag);
|
||||||
try cbor.writeValue(writer, self.project);
|
try cbor.writeValue(writer, self.project);
|
||||||
|
|
@ -638,7 +647,7 @@ const Process = struct {
|
||||||
try cbor.writeValue(writer, method);
|
try cbor.writeValue(writer, method);
|
||||||
try writer.writeAll(cbor_id);
|
try writer.writeAll(cbor_id);
|
||||||
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
||||||
self.parent.send_raw(.{ .buf = request.items }) catch return error.SendFailed;
|
self.parent.send_raw(.{ .buf = request.written() }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_lsp_response(self: *Process, cbor_id: []const u8, result: ?[]const u8, err: ?[]const u8) Error!void {
|
fn receive_lsp_response(self: *Process, cbor_id: []const u8, result: ?[]const u8, err: ?[]const u8) Error!void {
|
||||||
|
|
@ -650,9 +659,9 @@ const Process = struct {
|
||||||
defer if (json_err) |p| self.allocator.free(p);
|
defer if (json_err) |p| self.allocator.free(p);
|
||||||
self.write_log("### RECV rsp: {s} {s}\n{s}\n###\n", .{ json_id, if (json_err) |_| "error" else "response", json_err orelse json orelse "no result" });
|
self.write_log("### RECV rsp: {s} {s}\n{s}\n###\n", .{ json_id, if (json_err) |_| "error" else "response", json_err orelse json orelse "no result" });
|
||||||
const from = self.requests.get(cbor_id) orelse return;
|
const from = self.requests.get(cbor_id) orelse return;
|
||||||
var response = std.ArrayList(u8).init(self.allocator);
|
var response: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer response.deinit();
|
defer response.deinit();
|
||||||
const writer = response.writer();
|
const writer = &response.writer;
|
||||||
try cbor.writeArrayHeader(writer, 4);
|
try cbor.writeArrayHeader(writer, 4);
|
||||||
try cbor.writeValue(writer, sp_tag);
|
try cbor.writeValue(writer, sp_tag);
|
||||||
try cbor.writeValue(writer, self.tag);
|
try cbor.writeValue(writer, self.tag);
|
||||||
|
|
@ -663,16 +672,16 @@ const Process = struct {
|
||||||
try cbor.writeValue(writer, "result");
|
try cbor.writeValue(writer, "result");
|
||||||
_ = try writer.write(result_);
|
_ = try writer.write(result_);
|
||||||
}
|
}
|
||||||
from.send_raw(.{ .buf = response.items }) catch return error.SendFailed;
|
from.send_raw(.{ .buf = response.written() }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_lsp_notification(self: *Process, method: []const u8, params: ?[]const u8) Error!void {
|
fn receive_lsp_notification(self: *Process, method: []const u8, params: ?[]const u8) Error!void {
|
||||||
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
const json = if (params) |p| try cbor.toJsonPrettyAlloc(self.allocator, p) else null;
|
||||||
defer if (json) |p| self.allocator.free(p);
|
defer if (json) |p| self.allocator.free(p);
|
||||||
self.write_log("### RECV notify:\nmethod: {s}\n{s}\n###\n", .{ method, json orelse "no params" });
|
self.write_log("### RECV notify:\nmethod: {s}\n{s}\n###\n", .{ method, json orelse "no params" });
|
||||||
var notification = std.ArrayList(u8).init(self.allocator);
|
var notification: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer notification.deinit();
|
defer notification.deinit();
|
||||||
const writer = notification.writer();
|
const writer = ¬ification.writer;
|
||||||
try cbor.writeArrayHeader(writer, 6);
|
try cbor.writeArrayHeader(writer, 6);
|
||||||
try cbor.writeValue(writer, sp_tag);
|
try cbor.writeValue(writer, sp_tag);
|
||||||
try cbor.writeValue(writer, self.project);
|
try cbor.writeValue(writer, self.project);
|
||||||
|
|
@ -680,13 +689,13 @@ const Process = struct {
|
||||||
try cbor.writeValue(writer, "notify");
|
try cbor.writeValue(writer, "notify");
|
||||||
try cbor.writeValue(writer, method);
|
try cbor.writeValue(writer, method);
|
||||||
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
if (params) |p| _ = try writer.write(p) else try cbor.writeValue(writer, null);
|
||||||
self.parent.send_raw(.{ .buf = notification.items }) catch return error.SendFailed;
|
self.parent.send_raw(.{ .buf = notification.written() }) catch return error.SendFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_log(self: *Process, comptime format: []const u8, args: anytype) void {
|
fn write_log(self: *Process, comptime format: []const u8, args: anytype) void {
|
||||||
if (!debug_lsp) return;
|
if (!debug_lsp) return;
|
||||||
const file = self.log_file orelse return;
|
const file_writer = if (self.log_file_writer) |*writer| writer else return;
|
||||||
file.writer().print(format, args) catch {};
|
file_writer.interface.print(format, args) catch {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ const OutOfMemoryError = error{OutOfMemory};
|
||||||
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
||||||
pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI, InvalidMapType };
|
pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI, InvalidMapType };
|
||||||
pub const StartLspError = (error{ ThespianSpawnFailed, Timeout, InvalidLspCommand } || LspError || OutOfMemoryError || cbor.Error);
|
pub const StartLspError = (error{ ThespianSpawnFailed, Timeout, InvalidLspCommand } || LspError || OutOfMemoryError || cbor.Error);
|
||||||
pub const LspError = (error{ NoLsp, LspFailed } || OutOfMemoryError);
|
pub const LspError = (error{ NoLsp, LspFailed } || OutOfMemoryError || std.Io.Writer.Error);
|
||||||
pub const ClientError = (error{ClientFailed} || OutOfMemoryError);
|
pub const ClientError = (error{ClientFailed} || OutOfMemoryError || std.Io.Writer.Error);
|
||||||
pub const LspOrClientError = (LspError || ClientError);
|
pub const LspOrClientError = (LspError || ClientError);
|
||||||
|
|
||||||
const File = struct {
|
const File = struct {
|
||||||
|
|
@ -80,7 +80,7 @@ pub fn init(allocator: std.mem.Allocator, name: []const u8) OutOfMemoryError!Sel
|
||||||
.open_time = std.time.milliTimestamp(),
|
.open_time = std.time.milliTimestamp(),
|
||||||
.language_servers = std.StringHashMap(*const LSP).init(allocator),
|
.language_servers = std.StringHashMap(*const LSP).init(allocator),
|
||||||
.file_language_server = std.StringHashMap(*const LSP).init(allocator),
|
.file_language_server = std.StringHashMap(*const LSP).init(allocator),
|
||||||
.tasks = std.ArrayList(Task).init(allocator),
|
.tasks = .empty,
|
||||||
.logger = log.logger("project"),
|
.logger = log.logger("project"),
|
||||||
.logger_lsp = log.logger("lsp"),
|
.logger_lsp = log.logger("lsp"),
|
||||||
.logger_git = log.logger("git"),
|
.logger_git = log.logger("git"),
|
||||||
|
|
@ -104,7 +104,7 @@ pub fn deinit(self: *Self) void {
|
||||||
self.files.deinit(self.allocator);
|
self.files.deinit(self.allocator);
|
||||||
self.pending.deinit(self.allocator);
|
self.pending.deinit(self.allocator);
|
||||||
for (self.tasks.items) |task| self.allocator.free(task.command);
|
for (self.tasks.items) |task| self.allocator.free(task.command);
|
||||||
self.tasks.deinit();
|
self.tasks.deinit(self.allocator);
|
||||||
self.logger_lsp.deinit();
|
self.logger_lsp.deinit();
|
||||||
self.logger_git.deinit();
|
self.logger_git.deinit();
|
||||||
self.logger.deinit();
|
self.logger.deinit();
|
||||||
|
|
@ -216,7 +216,7 @@ pub fn restore_state_v1(self: *Self, data: []const u8) !void {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tp.trace(tp.channel.debug, .{ "restore_state_v1", "task", command, mtime });
|
tp.trace(tp.channel.debug, .{ "restore_state_v1", "task", command, mtime });
|
||||||
(try self.tasks.addOne()).* = .{
|
(try self.tasks.addOne(self.allocator)).* = .{
|
||||||
.command = try self.allocator.dupe(u8, command),
|
.command = try self.allocator.dupe(u8, command),
|
||||||
.mtime = mtime,
|
.mtime = mtime,
|
||||||
};
|
};
|
||||||
|
|
@ -237,6 +237,7 @@ pub fn restore_state_v0(self: *Self, data: []const u8) error{
|
||||||
BadArrayAllocExtract,
|
BadArrayAllocExtract,
|
||||||
InvalidMapType,
|
InvalidMapType,
|
||||||
InvalidUnion,
|
InvalidUnion,
|
||||||
|
WriteFailed,
|
||||||
}!void {
|
}!void {
|
||||||
tp.trace(tp.channel.debug, .{"restore_state_v0"});
|
tp.trace(tp.channel.debug, .{"restore_state_v0"});
|
||||||
defer self.sort_files_by_mtime();
|
defer self.sort_files_by_mtime();
|
||||||
|
|
@ -309,14 +310,16 @@ fn get_language_server(self: *Self, file_path: []const u8) LspError!*const LSP {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_URI(self: *Self, file_path: ?[]const u8) LspError![]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.Io.Writer.Allocating = .init(self.allocator);
|
||||||
|
defer buf.deinit();
|
||||||
|
const writer = &buf.writer;
|
||||||
if (file_path) |path| {
|
if (file_path) |path| {
|
||||||
if (std.fs.path.isAbsolute(path)) {
|
if (std.fs.path.isAbsolute(path)) {
|
||||||
try buf.writer().print("file://{s}", .{path});
|
try writer.print("file://{s}", .{path});
|
||||||
} else {
|
} else {
|
||||||
try buf.writer().print("file://{s}{c}{s}", .{ self.name, std.fs.path.sep, path });
|
try writer.print("file://{s}{c}{s}", .{ self.name, std.fs.path.sep, path });
|
||||||
}
|
}
|
||||||
} else try buf.writer().print("file://{s}", .{self.name});
|
} else try writer.print("file://{s}", .{self.name});
|
||||||
return buf.toOwnedSlice();
|
return buf.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,12 +392,12 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []co
|
||||||
score: i32,
|
score: i32,
|
||||||
matches: []const usize,
|
matches: []const usize,
|
||||||
};
|
};
|
||||||
var matches = std.ArrayList(Match).init(self.allocator);
|
var matches: std.ArrayList(Match) = .empty;
|
||||||
|
|
||||||
for (self.files.items) |file| {
|
for (self.files.items) |file| {
|
||||||
const match = searcher.scoreMatches(file.path, query);
|
const match = searcher.scoreMatches(file.path, query);
|
||||||
if (match.score) |score| {
|
if (match.score) |score| {
|
||||||
(try matches.addOne()).* = .{
|
(try matches.addOne(self.allocator)).* = .{
|
||||||
.path = file.path,
|
.path = file.path,
|
||||||
.type = file.type,
|
.type = file.type,
|
||||||
.icon = file.icon,
|
.icon = file.icon,
|
||||||
|
|
@ -551,12 +554,13 @@ pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) Cl
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_tasks(self: *Self, from: tp.pid_ref) ClientError!void {
|
pub fn request_tasks(self: *Self, from: tp.pid_ref) ClientError!void {
|
||||||
var message = std.ArrayList(u8).init(self.allocator);
|
var message: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
const writer = message.writer();
|
defer message.deinit();
|
||||||
|
const writer = &message.writer;
|
||||||
try cbor.writeArrayHeader(writer, self.tasks.items.len);
|
try cbor.writeArrayHeader(writer, self.tasks.items.len);
|
||||||
for (self.tasks.items) |task|
|
for (self.tasks.items) |task|
|
||||||
try cbor.writeValue(writer, task.command);
|
try cbor.writeValue(writer, task.command);
|
||||||
from.send_raw(.{ .buf = message.items }) catch return error.ClientFailed;
|
from.send_raw(.{ .buf = message.written() }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_task(self: *Self, command: []const u8) OutOfMemoryError!void {
|
pub fn add_task(self: *Self, command: []const u8) OutOfMemoryError!void {
|
||||||
|
|
@ -569,7 +573,7 @@ pub fn add_task(self: *Self, command: []const u8) OutOfMemoryError!void {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
tp.trace(tp.channel.debug, .{ "project", self.name, "add_task", command, mtime });
|
tp.trace(tp.channel.debug, .{ "project", self.name, "add_task", command, mtime });
|
||||||
(try self.tasks.addOne()).* = .{
|
(try self.tasks.addOne(self.allocator)).* = .{
|
||||||
.command = try self.allocator.dupe(u8, command),
|
.command = try self.allocator.dupe(u8, command),
|
||||||
.mtime = mtime,
|
.mtime = mtime,
|
||||||
};
|
};
|
||||||
|
|
@ -615,8 +619,8 @@ pub fn did_change(self: *Self, file_path: []const u8, version: usize, text_dst:
|
||||||
}
|
}
|
||||||
|
|
||||||
var dizzy_edits = std.ArrayListUnmanaged(dizzy.Edit){};
|
var dizzy_edits = std.ArrayListUnmanaged(dizzy.Edit){};
|
||||||
var edits_cb = std.ArrayList(u8).init(arena);
|
var edits_cb: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
const writer = edits_cb.writer();
|
const writer = &edits_cb.writer;
|
||||||
|
|
||||||
const scratch_len = 4 * (text_dst.len + text_src.len) + 2;
|
const scratch_len = 4 * (text_dst.len + text_src.len) + 2;
|
||||||
const scratch = blk: {
|
const scratch = blk: {
|
||||||
|
|
@ -674,16 +678,17 @@ pub fn did_change(self: *Self, file_path: []const u8, version: usize, text_dst:
|
||||||
{
|
{
|
||||||
const frame = tracy.initZone(@src(), .{ .name = "send" });
|
const frame = tracy.initZone(@src(), .{ .name = "send" });
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
var msg = std.ArrayList(u8).init(arena);
|
var msg: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
const msg_writer = msg.writer();
|
defer msg.deinit();
|
||||||
|
const msg_writer = &msg.writer;
|
||||||
try cbor.writeMapHeader(msg_writer, 2);
|
try cbor.writeMapHeader(msg_writer, 2);
|
||||||
try cbor.writeValue(msg_writer, "textDocument");
|
try cbor.writeValue(msg_writer, "textDocument");
|
||||||
try cbor.writeValue(msg_writer, .{ .uri = uri, .version = version });
|
try cbor.writeValue(msg_writer, .{ .uri = uri, .version = version });
|
||||||
try cbor.writeValue(msg_writer, "contentChanges");
|
try cbor.writeValue(msg_writer, "contentChanges");
|
||||||
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.written());
|
||||||
|
|
||||||
lsp.send_notification_raw("textDocument/didChange", msg.items) catch return error.LspFailed;
|
lsp.send_notification_raw("textDocument/didChange", msg.written()) catch return error.LspFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1146,16 +1151,16 @@ pub fn rename_symbol(self: *Self, from: tp.pid_ref, file_path: []const u8, row:
|
||||||
const allocator = std.heap.c_allocator;
|
const allocator = std.heap.c_allocator;
|
||||||
var result: []const u8 = undefined;
|
var result: []const u8 = undefined;
|
||||||
// buffer the renames in order to send as a single, atomic message
|
// buffer the renames in order to send as a single, atomic message
|
||||||
var renames = std.ArrayList(Rename).init(allocator);
|
var renames = std.array_list.Managed(Rename).init(allocator);
|
||||||
defer renames.deinit();
|
defer renames.deinit();
|
||||||
|
|
||||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.map })) {
|
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.map })) {
|
||||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) })) {
|
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) })) {
|
||||||
try decode_rename_symbol_map(result, &renames);
|
try decode_rename_symbol_map(result, &renames);
|
||||||
// write the renames message manually since there doesn't appear to be an array helper
|
// write the renames message manually since there doesn't appear to be an array helper
|
||||||
var msg_buf = std.ArrayList(u8).init(allocator);
|
var msg_buf: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer msg_buf.deinit();
|
defer msg_buf.deinit();
|
||||||
const w = msg_buf.writer();
|
const w = &msg_buf.writer;
|
||||||
try cbor.writeArrayHeader(w, 3);
|
try cbor.writeArrayHeader(w, 3);
|
||||||
try cbor.writeValue(w, "cmd");
|
try cbor.writeValue(w, "cmd");
|
||||||
try cbor.writeValue(w, "rename_symbol_item");
|
try cbor.writeValue(w, "rename_symbol_item");
|
||||||
|
|
@ -1181,7 +1186,7 @@ pub fn rename_symbol(self: *Self, from: tp.pid_ref, file_path: []const u8, row:
|
||||||
line,
|
line,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self_.from.send_raw(.{ .buf = msg_buf.items }) catch return error.ClientFailed;
|
self_.from.send_raw(.{ .buf = msg_buf.written() }) catch return error.ClientFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1199,7 +1204,7 @@ pub fn rename_symbol(self: *Self, from: tp.pid_ref, file_path: []const u8, row:
|
||||||
|
|
||||||
// decode a WorkspaceEdit record which may have shape {"changes": {}} or {"documentChanges": []}
|
// decode a WorkspaceEdit record which may have shape {"changes": {}} or {"documentChanges": []}
|
||||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit
|
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit
|
||||||
fn decode_rename_symbol_map(result: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
fn decode_rename_symbol_map(result: []const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||||
var iter = result;
|
var iter = result;
|
||||||
var len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage;
|
var len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage;
|
||||||
var changes: []const u8 = "";
|
var changes: []const u8 = "";
|
||||||
|
|
@ -1221,7 +1226,7 @@ fn decode_rename_symbol_map(result: []const u8, renames: *std.ArrayList(Rename))
|
||||||
return error.ClientFailed;
|
return error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_rename_symbol_changes(changes: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
fn decode_rename_symbol_changes(changes: []const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||||
var iter = changes;
|
var iter = changes;
|
||||||
var files_len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage;
|
var files_len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage;
|
||||||
while (files_len > 0) : (files_len -= 1) {
|
while (files_len > 0) : (files_len -= 1) {
|
||||||
|
|
@ -1231,7 +1236,7 @@ fn decode_rename_symbol_changes(changes: []const u8, renames: *std.ArrayList(Ren
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||||
var iter = changes;
|
var iter = changes;
|
||||||
var changes_len = cbor.decodeArrayHeader(&iter) catch return error.InvalidMessage;
|
var changes_len = cbor.decodeArrayHeader(&iter) catch return error.InvalidMessage;
|
||||||
while (changes_len > 0) : (changes_len -= 1) {
|
while (changes_len > 0) : (changes_len -= 1) {
|
||||||
|
|
@ -1258,7 +1263,7 @@ fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.ArrayList
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEdit
|
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEdit
|
||||||
fn decode_rename_symbol_item(file_uri: []const u8, iter: *[]const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
fn decode_rename_symbol_item(file_uri: []const u8, iter: *[]const u8, renames: *std.array_list.Managed(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||||
var text_edits_len = cbor.decodeArrayHeader(iter) catch return error.InvalidMessage;
|
var text_edits_len = cbor.decodeArrayHeader(iter) catch return error.InvalidMessage;
|
||||||
while (text_edits_len > 0) : (text_edits_len -= 1) {
|
while (text_edits_len > 0) : (text_edits_len -= 1) {
|
||||||
var m_range: ?Range = null;
|
var m_range: ?Range = null;
|
||||||
|
|
@ -1366,15 +1371,15 @@ fn send_contents(
|
||||||
};
|
};
|
||||||
|
|
||||||
if (is_list) {
|
if (is_list) {
|
||||||
var content = std.ArrayList(u8).init(std.heap.c_allocator);
|
var content: std.Io.Writer.Allocating = .init(std.heap.c_allocator);
|
||||||
defer content.deinit();
|
defer content.deinit();
|
||||||
while (len > 0) : (len -= 1) {
|
while (len > 0) : (len -= 1) {
|
||||||
if (try cbor.matchValue(&iter, cbor.extract(&value))) {
|
if (try cbor.matchValue(&iter, cbor.extract(&value))) {
|
||||||
try content.appendSlice(value);
|
try content.writer.writeAll(value);
|
||||||
if (len > 1) try content.appendSlice("\n");
|
if (len > 1) try content.writer.writeAll("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return send_content_msg(to, tag, file_path, row, col, kind, content.items, range);
|
return send_content_msg(to, tag, file_path, row, col, kind, content.written(), range);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len > 0) : (len -= 1) {
|
while (len > 0) : (len -= 1) {
|
||||||
|
|
@ -1604,7 +1609,7 @@ fn send_lsp_init_request(self: *Self, lsp: *const LSP, project_path: []const u8,
|
||||||
pub fn receive(self_: @This(), _: tp.message) !void {
|
pub fn receive(self_: @This(), _: tp.message) !void {
|
||||||
self_.lsp.send_notification("initialized", .{}) catch return error.LspFailed;
|
self_.lsp.send_notification("initialized", .{}) catch return error.LspFailed;
|
||||||
if (self_.lsp.pid.expired()) return error.LspFailed;
|
if (self_.lsp.pid.expired()) return error.LspFailed;
|
||||||
self_.project.logger_lsp.print("initialized LSP: {s}", .{fmt_lsp_name_func(self_.language_server)});
|
self_.project.logger_lsp.print("initialized LSP: {f}", .{fmt_lsp_name_func(self_.language_server)});
|
||||||
}
|
}
|
||||||
} = .{
|
} = .{
|
||||||
.language_server = try std.heap.c_allocator.dupe(u8, language_server),
|
.language_server = try std.heap.c_allocator.dupe(u8, language_server),
|
||||||
|
|
@ -1916,18 +1921,14 @@ fn send_lsp_init_request(self: *Self, lsp: *const LSP, project_path: []const u8,
|
||||||
}, handler);
|
}, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_lsp_name_func(bytes: []const u8) std.fmt.Formatter(format_lsp_name_func) {
|
fn fmt_lsp_name_func(bytes: []const u8) std.fmt.Formatter([]const u8, format_lsp_name_func) {
|
||||||
return .{ .data = bytes };
|
return .{ .data = bytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_lsp_name_func(
|
fn format_lsp_name_func(
|
||||||
bytes: []const u8,
|
bytes: []const u8,
|
||||||
comptime fmt: []const u8,
|
writer: *std.Io.Writer,
|
||||||
options: std.fmt.FormatOptions,
|
) std.Io.Writer.Error!void {
|
||||||
writer: anytype,
|
|
||||||
) !void {
|
|
||||||
_ = fmt;
|
|
||||||
_ = options;
|
|
||||||
var iter: []const u8 = bytes;
|
var iter: []const u8 = bytes;
|
||||||
var len = cbor.decodeArrayHeader(&iter) catch return;
|
var len = cbor.decodeArrayHeader(&iter) catch return;
|
||||||
var first: bool = true;
|
var first: bool = true;
|
||||||
|
|
@ -1942,7 +1943,7 @@ fn format_lsp_name_func(
|
||||||
|
|
||||||
const eol = '\n';
|
const eol = '\n';
|
||||||
|
|
||||||
pub const GetLineOfFileError = (OutOfMemoryError || std.fs.File.OpenError || std.fs.File.Reader.Error);
|
pub const GetLineOfFileError = (OutOfMemoryError || std.fs.File.OpenError || std.fs.File.ReadError);
|
||||||
|
|
||||||
fn get_line_of_file(allocator: std.mem.Allocator, file_path: []const u8, line_: usize) GetLineOfFileError![]const u8 {
|
fn get_line_of_file(allocator: std.mem.Allocator, file_path: []const u8, line_: usize) GetLineOfFileError![]const u8 {
|
||||||
const line = line_ + 1;
|
const line = line_ + 1;
|
||||||
|
|
@ -1951,7 +1952,7 @@ fn get_line_of_file(allocator: std.mem.Allocator, file_path: []const u8, line_:
|
||||||
const stat = try file.stat();
|
const stat = try file.stat();
|
||||||
var buf = try allocator.alloc(u8, @intCast(stat.size));
|
var buf = try allocator.alloc(u8, @intCast(stat.size));
|
||||||
defer allocator.free(buf);
|
defer allocator.free(buf);
|
||||||
const read_size = try file.reader().readAll(buf);
|
const read_size = try file.readAll(buf);
|
||||||
if (read_size != @as(@TypeOf(read_size), @intCast(stat.size)))
|
if (read_size != @as(@TypeOf(read_size), @intCast(stat.size)))
|
||||||
@panic("get_line_of_file: buffer underrun");
|
@panic("get_line_of_file: buffer underrun");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,33 +224,33 @@ pub const Leaf = struct {
|
||||||
} else error.BufferUnderrun;
|
} else error.BufferUnderrun;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn dump(self: *const Leaf, l: *ArrayList(u8), abs_col: usize, metrics: Metrics) !void {
|
inline fn dump(self: *const Leaf, l: *std.Io.Writer, abs_col: usize, metrics: Metrics) !void {
|
||||||
var buf: [16]u8 = undefined;
|
var buf: [16]u8 = undefined;
|
||||||
const wcwidth = try std.fmt.bufPrint(&buf, "{d}", .{self.width(abs_col, metrics)});
|
const wcwidth = try std.fmt.bufPrint(&buf, "{d}", .{self.width(abs_col, metrics)});
|
||||||
if (self.bol)
|
if (self.bol)
|
||||||
try l.appendSlice("BOL ");
|
try l.writeAll("BOL ");
|
||||||
try l.appendSlice(wcwidth);
|
try l.writeAll(wcwidth);
|
||||||
try l.append('"');
|
try l.writeAll("\"");
|
||||||
try debug_render_chunk(self.buf, l, metrics);
|
try debug_render_chunk(self.buf, l, metrics);
|
||||||
try l.appendSlice("\" ");
|
try l.writeAll("\" ");
|
||||||
if (self.eol)
|
if (self.eol)
|
||||||
try l.appendSlice("EOL ");
|
try l.writeAll("EOL ");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_render_chunk(chunk: []const u8, l: *ArrayList(u8), metrics: Metrics) !void {
|
fn debug_render_chunk(chunk: []const u8, l: *std.Io.Writer, metrics: Metrics) !void {
|
||||||
var cols: c_int = 0;
|
var cols: c_int = 0;
|
||||||
var buf = chunk;
|
var buf = chunk;
|
||||||
while (buf.len > 0) {
|
while (buf.len > 0) {
|
||||||
switch (buf[0]) {
|
switch (buf[0]) {
|
||||||
'\x00'...(' ' - 1) => {
|
'\x00'...(' ' - 1) => {
|
||||||
const control = unicode.control_code_to_unicode(buf[0]);
|
const control = unicode.control_code_to_unicode(buf[0]);
|
||||||
try l.appendSlice(control);
|
try l.writeAll(control);
|
||||||
buf = buf[1..];
|
buf = buf[1..];
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
const bytes = metrics.egc_length(metrics, buf, &cols, 0);
|
const bytes = metrics.egc_length(metrics, buf, &cols, 0);
|
||||||
var buf_: [4096]u8 = undefined;
|
var buf_: [4096]u8 = undefined;
|
||||||
try l.appendSlice(try std.fmt.bufPrint(&buf_, "{s}", .{std.fmt.fmtSliceEscapeLower(buf[0..bytes])}));
|
try l.writeAll(try std.fmt.bufPrint(&buf_, "{f}", .{std.ascii.hexEscape(buf[0..bytes], .lower)}));
|
||||||
buf = buf[bytes..];
|
buf = buf[bytes..];
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -477,21 +477,21 @@ const Node = union(enum) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_render_tree(self: *const Node, l: *ArrayList(u8), d: usize) void {
|
fn debug_render_tree(self: *const Node, l: *std.Io.Writer, d: usize) void {
|
||||||
switch (self.*) {
|
switch (self.*) {
|
||||||
.node => |*node| {
|
.node => |*node| {
|
||||||
l.append('(') catch {};
|
l.writeAll("(") catch {};
|
||||||
node.left.debug_render_tree(l, d + 1);
|
node.left.debug_render_tree(l, d + 1);
|
||||||
l.append(' ') catch {};
|
l.writeAll(" ") catch {};
|
||||||
node.right.debug_render_tree(l, d + 1);
|
node.right.debug_render_tree(l, d + 1);
|
||||||
l.append(')') catch {};
|
l.writeAll(")") catch {};
|
||||||
},
|
},
|
||||||
.leaf => |*leaf| {
|
.leaf => |*leaf| {
|
||||||
l.append('"') catch {};
|
l.writeAll("\"") catch {};
|
||||||
l.appendSlice(leaf.buf) catch {};
|
l.writeAll(leaf.buf) catch {};
|
||||||
if (leaf.eol)
|
if (leaf.eol)
|
||||||
l.appendSlice("\\n") catch {};
|
l.writeAll("\\n") catch {};
|
||||||
l.append('"') catch {};
|
l.writeAll("\"") catch {};
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -554,22 +554,23 @@ const Node = union(enum) {
|
||||||
return pred(egc);
|
return pred(egc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_line_width_map(self: *const Node, line: usize, map: *ArrayList(usize), metrics: Metrics) error{ Stop, NoSpaceLeft }!void {
|
pub fn get_line_width_map(self: *const Node, line: usize, map: *ArrayList(usize), allocator: Allocator, metrics: Metrics) error{ Stop, NoSpaceLeft }!void {
|
||||||
const Ctx = struct {
|
const Ctx = struct {
|
||||||
|
allocator: Allocator,
|
||||||
map: *ArrayList(usize),
|
map: *ArrayList(usize),
|
||||||
wcwidth: usize = 0,
|
wcwidth: usize = 0,
|
||||||
fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrics) Walker {
|
fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrics) Walker {
|
||||||
const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_)));
|
const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_)));
|
||||||
var n = egc.len;
|
var n = egc.len;
|
||||||
while (n > 0) : (n -= 1) {
|
while (n > 0) : (n -= 1) {
|
||||||
const p = ctx.map.addOne() catch |e| return .{ .err = e };
|
const p = ctx.map.addOne(ctx.allocator) catch |e| return .{ .err = e };
|
||||||
p.* = ctx.wcwidth;
|
p.* = ctx.wcwidth;
|
||||||
}
|
}
|
||||||
ctx.wcwidth += wcwidth;
|
ctx.wcwidth += wcwidth;
|
||||||
return if (egc[0] == '\n') Walker.stop else Walker.keep_walking;
|
return if (egc[0] == '\n') Walker.stop else Walker.keep_walking;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var ctx: Ctx = .{ .map = map };
|
var ctx: Ctx = .{ .allocator = allocator, .map = map };
|
||||||
self.walk_egc_forward(line, Ctx.walker, &ctx, metrics) catch |e| return switch (e) {
|
self.walk_egc_forward(line, Ctx.walker, &ctx, metrics) catch |e| return switch (e) {
|
||||||
error.NoSpaceLeft => error.NoSpaceLeft,
|
error.NoSpaceLeft => error.NoSpaceLeft,
|
||||||
else => error.Stop,
|
else => error.Stop,
|
||||||
|
|
@ -926,7 +927,7 @@ const Node = union(enum) {
|
||||||
return .{ line, col, self };
|
return .{ line, col, self };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store(self: *const Node, writer: anytype, eol_mode: EolMode) !void {
|
pub fn store(self: *const Node, writer: *std.Io.Writer, eol_mode: EolMode) !void {
|
||||||
switch (self.*) {
|
switch (self.*) {
|
||||||
.node => |*node| {
|
.node => |*node| {
|
||||||
try node.left.store(writer, eol_mode);
|
try node.left.store(writer, eol_mode);
|
||||||
|
|
@ -943,7 +944,7 @@ const Node = union(enum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const FindAllCallback = fn (data: *anyopaque, begin_row: usize, begin_col: usize, end_row: usize, end_col: usize) error{Stop}!void;
|
pub const FindAllCallback = fn (data: *anyopaque, begin_row: usize, begin_col: usize, end_row: usize, end_col: usize) error{Stop}!void;
|
||||||
pub fn find_all_ranges(self: *const Node, pattern: []const u8, data: *anyopaque, callback: *const FindAllCallback, allocator: Allocator) !void {
|
pub fn find_all_ranges(self: *const Node, pattern: []const u8, data: *anyopaque, callback: *const FindAllCallback, allocator: Allocator) error{ OutOfMemory, Stop }!void {
|
||||||
const Ctx = struct {
|
const Ctx = struct {
|
||||||
pattern: []const u8,
|
pattern: []const u8,
|
||||||
data: *anyopaque,
|
data: *anyopaque,
|
||||||
|
|
@ -952,9 +953,27 @@ const Node = union(enum) {
|
||||||
pos: usize = 0,
|
pos: usize = 0,
|
||||||
buf: []u8,
|
buf: []u8,
|
||||||
rest: []u8 = "",
|
rest: []u8 = "",
|
||||||
|
writer: std.Io.Writer,
|
||||||
|
|
||||||
const Ctx = @This();
|
const Ctx = @This();
|
||||||
const Writer = std.io.Writer(*Ctx, error{Stop}, write);
|
fn drain(w: *std.Io.Writer, data_: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
|
||||||
fn write(ctx: *Ctx, bytes: []const u8) error{Stop}!usize {
|
const ctx: *Ctx = @alignCast(@fieldParentPtr("writer", w));
|
||||||
|
std.debug.assert(splat == 0);
|
||||||
|
if (data_.len == 0) return 0;
|
||||||
|
var written: usize = 0;
|
||||||
|
for (data_[0 .. data_.len - 1]) |bytes| {
|
||||||
|
written += try ctx.write(bytes);
|
||||||
|
}
|
||||||
|
const pattern_ = data_[data_.len - 1];
|
||||||
|
switch (pattern_.len) {
|
||||||
|
0 => return written,
|
||||||
|
else => for (0..splat) |_| {
|
||||||
|
written += try ctx.write(pattern_);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
fn write(ctx: *Ctx, bytes: []const u8) std.Io.Writer.Error!usize {
|
||||||
var input = bytes;
|
var input = bytes;
|
||||||
while (true) {
|
while (true) {
|
||||||
const input_consume_size = @min(ctx.buf.len - ctx.rest.len, input.len);
|
const input_consume_size = @min(ctx.buf.len - ctx.rest.len, input.len);
|
||||||
|
|
@ -975,7 +994,7 @@ const Node = union(enum) {
|
||||||
ctx.skip(&i, ctx.pattern.len);
|
ctx.skip(&i, ctx.pattern.len);
|
||||||
const end_row = ctx.line + 1;
|
const end_row = ctx.line + 1;
|
||||||
const end_pos = ctx.pos;
|
const end_pos = ctx.pos;
|
||||||
try ctx.callback(ctx.data, begin_row, begin_pos, end_row, end_pos);
|
ctx.callback(ctx.data, begin_row, begin_pos, end_row, end_pos) catch return error.WriteFailed;
|
||||||
} else {
|
} else {
|
||||||
ctx.skip(&i, 1);
|
ctx.skip(&i, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -1001,18 +1020,25 @@ const Node = union(enum) {
|
||||||
i.* += 1;
|
i.* += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn writer(ctx: *Ctx) Writer {
|
|
||||||
return .{ .context = ctx };
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
var ctx: Ctx = .{
|
var ctx: Ctx = .{
|
||||||
.pattern = pattern,
|
.pattern = pattern,
|
||||||
.data = data,
|
.data = data,
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.buf = try allocator.alloc(u8, pattern.len * 2),
|
.buf = try allocator.alloc(u8, pattern.len * 2),
|
||||||
|
.writer = .{
|
||||||
|
.vtable = &.{
|
||||||
|
.drain = Ctx.drain,
|
||||||
|
.flush = std.Io.Writer.noopFlush,
|
||||||
|
.rebase = std.Io.Writer.failingRebase,
|
||||||
|
},
|
||||||
|
.buffer = &.{},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
defer allocator.free(ctx.buf);
|
defer allocator.free(ctx.buf);
|
||||||
return self.store(ctx.writer(), .lf);
|
return self.store(&ctx.writer, .lf) catch |e| switch (e) {
|
||||||
|
error.WriteFailed => error.Stop,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_byte_pos(self: *const Node, pos_: Cursor, metrics_: Metrics, eol_mode: EolMode) !usize {
|
pub fn get_byte_pos(self: *const Node, pos_: Cursor, metrics_: Metrics, eol_mode: EolMode) !usize {
|
||||||
|
|
@ -1065,10 +1091,10 @@ const Node = union(enum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_render_chunks(self: *const Node, allocator: std.mem.Allocator, line: usize, metrics_: Metrics) ![]const u8 {
|
pub fn debug_render_chunks(self: *const Node, allocator: std.mem.Allocator, line: usize, metrics_: Metrics) ![]const u8 {
|
||||||
var output = std.ArrayList(u8).init(allocator);
|
var output: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer output.deinit();
|
defer output.deinit();
|
||||||
const ctx_ = struct {
|
const ctx_ = struct {
|
||||||
l: *ArrayList(u8),
|
l: *std.Io.Writer,
|
||||||
wcwidth: usize = 0,
|
wcwidth: usize = 0,
|
||||||
fn walker(ctx_: *anyopaque, leaf: *const Leaf, metrics: Metrics) Walker {
|
fn walker(ctx_: *anyopaque, leaf: *const Leaf, metrics: Metrics) Walker {
|
||||||
const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_)));
|
const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_)));
|
||||||
|
|
@ -1077,21 +1103,21 @@ const Node = union(enum) {
|
||||||
return if (!leaf.eol) Walker.keep_walking else Walker.stop;
|
return if (!leaf.eol) Walker.keep_walking else Walker.stop;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var ctx: ctx_ = .{ .l = &output };
|
var ctx: ctx_ = .{ .l = &output.writer };
|
||||||
const found = self.walk_from_line_begin_const(line, ctx_.walker, &ctx, metrics_) catch true;
|
const found = self.walk_from_line_begin_const(line, ctx_.walker, &ctx, metrics_) catch true;
|
||||||
if (!found) return error.NotFound;
|
if (!found) return error.NotFound;
|
||||||
|
|
||||||
var buf: [16]u8 = undefined;
|
var buf: [16]u8 = undefined;
|
||||||
const wcwidth = try std.fmt.bufPrint(&buf, "{d}", .{ctx.wcwidth});
|
const wcwidth = try std.fmt.bufPrint(&buf, "{d}", .{ctx.wcwidth});
|
||||||
try output.appendSlice(wcwidth);
|
try output.writer.writeAll(wcwidth);
|
||||||
return output.toOwnedSlice();
|
return output.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_line_render_tree(self: *const Node, allocator: std.mem.Allocator, line: usize) ![]const u8 {
|
pub fn debug_line_render_tree(self: *const Node, allocator: std.mem.Allocator, line: usize) ![]const u8 {
|
||||||
return if (self.find_line_node(line)) |n| blk: {
|
return if (self.find_line_node(line)) |n| blk: {
|
||||||
var l = std.ArrayList(u8).init(allocator);
|
var l: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer l.deinit();
|
defer l.deinit();
|
||||||
n.debug_render_tree(&l, 0);
|
n.debug_render_tree(&l.writer, 0);
|
||||||
break :blk l.toOwnedSlice();
|
break :blk l.toOwnedSlice();
|
||||||
} else error.NotFound;
|
} else error.NotFound;
|
||||||
}
|
}
|
||||||
|
|
@ -1152,28 +1178,24 @@ fn new_file(self: *const Self, file_exists: *bool) error{OutOfMemory}!Root {
|
||||||
return Leaf.new(self.allocator, "", true, false);
|
return Leaf.new(self.allocator, "", true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn LoadError(comptime reader_error: anytype) type {
|
pub const LoadError =
|
||||||
return error{
|
error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
BufferUnderrun,
|
BufferUnderrun,
|
||||||
DanglingSurrogateHalf,
|
DanglingSurrogateHalf,
|
||||||
ExpectedSecondSurrogateHalf,
|
ExpectedSecondSurrogateHalf,
|
||||||
UnexpectedSecondSurrogateHalf,
|
UnexpectedSecondSurrogateHalf,
|
||||||
Unexpected,
|
Unexpected,
|
||||||
} || reader_error;
|
} || std.Io.Reader.Error;
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(self: *const Self, reader: anytype, size: usize, eol_mode: *EolMode, utf8_sanitized: *bool) LoadError(@TypeOf(reader).Error)!Root {
|
pub fn load(self: *const Self, reader: *std.Io.Reader, eol_mode: *EolMode, utf8_sanitized: *bool) LoadError!Root {
|
||||||
const lf = '\n';
|
const lf = '\n';
|
||||||
const cr = '\r';
|
const cr = '\r';
|
||||||
var buf = try self.external_allocator.alloc(u8, size);
|
|
||||||
const self_ = @constCast(self);
|
const self_ = @constCast(self);
|
||||||
const read_size = try reader.readAll(buf);
|
var read_buffer: ArrayList(u8) = .empty;
|
||||||
if (read_size != size)
|
defer read_buffer.deinit(self.external_allocator);
|
||||||
return error.BufferUnderrun;
|
try reader.appendRemainingUnlimited(self.external_allocator, &read_buffer);
|
||||||
const final_read = try reader.read(buf);
|
var buf = try read_buffer.toOwnedSlice(self.external_allocator);
|
||||||
if (final_read != 0)
|
|
||||||
@panic("unexpected data in final read");
|
|
||||||
|
|
||||||
if (!std.unicode.utf8ValidateSlice(buf)) {
|
if (!std.unicode.utf8ValidateSlice(buf)) {
|
||||||
const converted = try unicode.utf8_sanitize(self.external_allocator, buf);
|
const converted = try unicode.utf8_sanitize(self.external_allocator, buf);
|
||||||
|
|
@ -1213,14 +1235,12 @@ pub fn load(self: *const Self, reader: anytype, size: usize, eol_mode: *EolMode,
|
||||||
return Node.merge_in_place(leaves, self.allocator);
|
return Node.merge_in_place(leaves, self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LoadFromStringError = LoadError(error{});
|
pub fn load_from_string(self: *const Self, s: []const u8, eol_mode: *EolMode, utf8_sanitized: *bool) LoadError!Root {
|
||||||
|
var reader = std.Io.Reader.fixed(s);
|
||||||
pub fn load_from_string(self: *const Self, s: []const u8, eol_mode: *EolMode, utf8_sanitized: *bool) LoadFromStringError!Root {
|
return self.load(&reader, eol_mode, utf8_sanitized);
|
||||||
var stream = std.io.fixedBufferStream(s);
|
|
||||||
return self.load(stream.reader(), s.len, eol_mode, utf8_sanitized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_string_and_update(self: *Self, file_path: []const u8, s: []const u8) LoadFromStringError!void {
|
pub fn load_from_string_and_update(self: *Self, file_path: []const u8, s: []const u8) LoadError!void {
|
||||||
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
|
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
|
||||||
self.set_file_path(file_path);
|
self.set_file_path(file_path);
|
||||||
self.last_save = self.root;
|
self.last_save = self.root;
|
||||||
|
|
@ -1229,7 +1249,7 @@ pub fn load_from_string_and_update(self: *Self, file_path: []const u8, s: []cons
|
||||||
self.mtime = std.time.milliTimestamp();
|
self.mtime = std.time.milliTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_from_string_and_update(self: *Self, s: []const u8) LoadFromStringError!void {
|
pub fn reset_from_string_and_update(self: *Self, s: []const u8) LoadError!void {
|
||||||
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
|
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
|
||||||
self.last_save = self.root;
|
self.last_save = self.root;
|
||||||
self.last_save_eol_mode = self.file_eol_mode;
|
self.last_save_eol_mode = self.file_eol_mode;
|
||||||
|
|
@ -1278,7 +1298,7 @@ pub const LoadFromFileError = error{
|
||||||
ProcessNotFound,
|
ProcessNotFound,
|
||||||
Canceled,
|
Canceled,
|
||||||
PermissionDenied,
|
PermissionDenied,
|
||||||
};
|
} || LoadError;
|
||||||
|
|
||||||
pub fn load_from_file(
|
pub fn load_from_file(
|
||||||
self: *const Self,
|
self: *const Self,
|
||||||
|
|
@ -1294,8 +1314,9 @@ pub fn load_from_file(
|
||||||
|
|
||||||
file_exists.* = true;
|
file_exists.* = true;
|
||||||
defer file.close();
|
defer file.close();
|
||||||
const stat = try file.stat();
|
var read_buf: [4096]u8 = undefined;
|
||||||
return self.load(file.reader(), @intCast(stat.size), eol_mode, utf8_sanitized);
|
var file_reader = file.reader(&read_buf);
|
||||||
|
return self.load(&file_reader.interface, eol_mode, utf8_sanitized);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_file_and_update(self: *Self, file_path: []const u8) LoadFromFileError!void {
|
pub fn load_from_file_and_update(self: *Self, file_path: []const u8) LoadFromFileError!void {
|
||||||
|
|
@ -1332,16 +1353,9 @@ pub fn store_to_string(self: *const Self, allocator: Allocator, eol_mode: EolMod
|
||||||
return s.toOwnedSlice();
|
return s.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_to_file_const(self: *const Self, file: anytype) StoreToFileError!void {
|
fn store_to_file_const(self: *const Self, writer: *std.Io.Writer) StoreToFileError!void {
|
||||||
const buffer_size = 4096 * 16; // 64KB
|
try self.root.store(writer, self.file_eol_mode);
|
||||||
const BufferedWriter = std.io.BufferedWriter(buffer_size, std.fs.File.Writer);
|
try writer.flush();
|
||||||
const Writer = std.io.Writer(*BufferedWriter, BufferedWriter.Error, BufferedWriter.write);
|
|
||||||
|
|
||||||
const file_writer: std.fs.File.Writer = file.writer();
|
|
||||||
var buffered_writer: BufferedWriter = .{ .unbuffered_writer = file_writer };
|
|
||||||
|
|
||||||
try self.root.store(Writer{ .context = &buffered_writer }, self.file_eol_mode);
|
|
||||||
try buffered_writer.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const StoreToFileError = error{
|
pub const StoreToFileError = error{
|
||||||
|
|
@ -1385,13 +1399,15 @@ pub const StoreToFileError = error{
|
||||||
WouldBlock,
|
WouldBlock,
|
||||||
PermissionDenied,
|
PermissionDenied,
|
||||||
MessageTooBig,
|
MessageTooBig,
|
||||||
|
WriteFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn store_to_existing_file_const(self: *const Self, file_path: []const u8) StoreToFileError!void {
|
pub fn store_to_existing_file_const(self: *const Self, file_path: []const u8) StoreToFileError!void {
|
||||||
const stat = try cwd().statFile(file_path);
|
const stat = try cwd().statFile(file_path);
|
||||||
var atomic = try cwd().atomicFile(file_path, .{ .mode = stat.mode });
|
var write_buffer: [4096]u8 = undefined;
|
||||||
|
var atomic = try cwd().atomicFile(file_path, .{ .mode = stat.mode, .write_buffer = &write_buffer });
|
||||||
defer atomic.deinit();
|
defer atomic.deinit();
|
||||||
try self.store_to_file_const(atomic.file);
|
try self.store_to_file_const(&atomic.file_writer.interface);
|
||||||
try atomic.finish();
|
try atomic.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1400,7 +1416,9 @@ pub fn store_to_new_file_const(self: *const Self, file_path: []const u8) StoreTo
|
||||||
try cwd().makePath(dir_name);
|
try cwd().makePath(dir_name);
|
||||||
const file = try cwd().createFile(file_path, .{ .read = true, .truncate = true });
|
const file = try cwd().createFile(file_path, .{ .read = true, .truncate = true });
|
||||||
defer file.close();
|
defer file.close();
|
||||||
try self.store_to_file_const(file);
|
var write_buffer: [4096]u8 = undefined;
|
||||||
|
var writer = file.writer(&write_buffer);
|
||||||
|
try self.store_to_file_const(&writer.interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_to_file_and_clean(self: *Self, file_path: []const u8) StoreToFileError!void {
|
pub fn store_to_file_and_clean(self: *Self, file_path: []const u8) StoreToFileError!void {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ pub fn open_file(self: *Self, file_path: []const u8) Buffer.LoadFromFileError!*B
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_scratch(self: *Self, file_path: []const u8, content: []const u8) Buffer.LoadFromStringError!*Buffer {
|
pub fn open_scratch(self: *Self, file_path: []const u8, content: []const u8) Buffer.LoadError!*Buffer {
|
||||||
const buffer = if (self.buffers.get(file_path)) |buffer| buffer else blk: {
|
const buffer = if (self.buffers.get(file_path)) |buffer| buffer else blk: {
|
||||||
var buffer = try Buffer.create(self.allocator);
|
var buffer = try Buffer.create(self.allocator);
|
||||||
errdefer buffer.deinit();
|
errdefer buffer.deinit();
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,13 @@ pub const Context = struct {
|
||||||
|
|
||||||
pub fn fmt(value: anytype) Context {
|
pub fn fmt(value: anytype) Context {
|
||||||
context_buffer.clearRetainingCapacity();
|
context_buffer.clearRetainingCapacity();
|
||||||
cbor.writeValue(context_buffer.writer(), value) catch @panic("command.Context.fmt failed");
|
cbor.writeValue(&context_buffer.writer, value) catch @panic("command.Context.fmt failed");
|
||||||
return .{ .args = .{ .buf = context_buffer.items } };
|
return .{ .args = .{ .buf = context_buffer.written() } };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const context_buffer_allocator = std.heap.c_allocator;
|
const context_buffer_allocator = std.heap.c_allocator;
|
||||||
threadlocal var context_buffer: std.ArrayList(u8) = std.ArrayList(u8).init(context_buffer_allocator);
|
threadlocal var context_buffer: std.Io.Writer.Allocating = .init(context_buffer_allocator);
|
||||||
pub const fmt = Context.fmt;
|
pub const fmt = Context.fmt;
|
||||||
|
|
||||||
const Vtable = struct {
|
const Vtable = struct {
|
||||||
|
|
@ -96,12 +96,12 @@ pub fn Closure(comptime T: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CommandTable = std.ArrayList(?*Vtable);
|
const CommandTable = std.ArrayList(?*Vtable);
|
||||||
pub var commands: CommandTable = CommandTable.init(command_table_allocator);
|
pub var commands: CommandTable = .empty;
|
||||||
var command_names: std.StringHashMap(ID) = std.StringHashMap(ID).init(command_table_allocator);
|
var command_names: std.StringHashMap(ID) = std.StringHashMap(ID).init(command_table_allocator);
|
||||||
const command_table_allocator = std.heap.c_allocator;
|
const command_table_allocator = std.heap.c_allocator;
|
||||||
|
|
||||||
fn addCommand(cmd: *Vtable) !ID {
|
fn addCommand(cmd: *Vtable) !ID {
|
||||||
try commands.append(cmd);
|
try commands.append(command_table_allocator, cmd);
|
||||||
return commands.items.len - 1;
|
return commands.items.len - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,9 +121,9 @@ pub fn execute(id: ID, ctx: Context) tp.result {
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
tp.trace(tp.channel.debug, .{ "command", "execute", id, get_name(id) });
|
tp.trace(tp.channel.debug, .{ "command", "execute", id, get_name(id) });
|
||||||
} else {
|
} else {
|
||||||
var msg_cb = std.ArrayList(u8).init(command_table_allocator);
|
var msg_cb: std.Io.Writer.Allocating = .init(command_table_allocator);
|
||||||
defer msg_cb.deinit();
|
defer msg_cb.deinit();
|
||||||
const writer = msg_cb.writer();
|
const writer = &msg_cb.writer;
|
||||||
cbor.writeArrayHeader(writer, 4 + len) catch break :trace;
|
cbor.writeArrayHeader(writer, 4 + len) catch break :trace;
|
||||||
cbor.writeValue(writer, "command") catch break :trace;
|
cbor.writeValue(writer, "command") catch break :trace;
|
||||||
cbor.writeValue(writer, "execute") catch break :trace;
|
cbor.writeValue(writer, "execute") catch break :trace;
|
||||||
|
|
@ -132,9 +132,9 @@ pub fn execute(id: ID, ctx: Context) tp.result {
|
||||||
while (len > 0) : (len -= 1) {
|
while (len > 0) : (len -= 1) {
|
||||||
var arg: []const u8 = undefined;
|
var arg: []const u8 = undefined;
|
||||||
if (cbor.matchValue(&iter, cbor.extract_cbor(&arg)) catch break :trace)
|
if (cbor.matchValue(&iter, cbor.extract_cbor(&arg)) catch break :trace)
|
||||||
msg_cb.appendSlice(arg) catch break :trace;
|
writer.writeAll(arg) catch break :trace;
|
||||||
}
|
}
|
||||||
const msg: tp.message = .{ .buf = msg_cb.items };
|
const msg: tp.message = .{ .buf = msg_cb.written() };
|
||||||
tp.trace(tp.channel.debug, msg);
|
tp.trace(tp.channel.debug, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
src/diff.zig
11
src/diff.zig
|
|
@ -122,7 +122,8 @@ pub fn diff(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) ![]D
|
||||||
|
|
||||||
var dizzy_edits = std.ArrayListUnmanaged(dizzy.Edit){};
|
var dizzy_edits = std.ArrayListUnmanaged(dizzy.Edit){};
|
||||||
var scratch = std.ArrayListUnmanaged(u32){};
|
var scratch = std.ArrayListUnmanaged(u32){};
|
||||||
var diffs = std.ArrayList(Diff).init(allocator);
|
var diffs: std.ArrayList(Diff) = .empty;
|
||||||
|
errdefer diffs.deinit(allocator);
|
||||||
|
|
||||||
const scratch_len = 4 * (dst.len + src.len) + 2;
|
const scratch_len = 4 * (dst.len + src.len) + 2;
|
||||||
try scratch.ensureTotalCapacity(arena, scratch_len);
|
try scratch.ensureTotalCapacity(arena, scratch_len);
|
||||||
|
|
@ -131,7 +132,7 @@ pub fn diff(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) ![]D
|
||||||
try dizzy.PrimitiveSliceDiffer(u8).diff(arena, &dizzy_edits, src, dst, scratch.items);
|
try dizzy.PrimitiveSliceDiffer(u8).diff(arena, &dizzy_edits, src, dst, scratch.items);
|
||||||
|
|
||||||
if (dizzy_edits.items.len > 2)
|
if (dizzy_edits.items.len > 2)
|
||||||
try diffs.ensureTotalCapacity((dizzy_edits.items.len - 1) / 2);
|
try diffs.ensureTotalCapacity(allocator, (dizzy_edits.items.len - 1) / 2);
|
||||||
|
|
||||||
var lines_dst: usize = 0;
|
var lines_dst: usize = 0;
|
||||||
var pos_src: usize = 0;
|
var pos_src: usize = 0;
|
||||||
|
|
@ -152,7 +153,7 @@ pub fn diff(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) ![]D
|
||||||
pos_dst += dist;
|
pos_dst += dist;
|
||||||
const line_start_dst: usize = lines_dst;
|
const line_start_dst: usize = lines_dst;
|
||||||
scan_char(dst[dizzy_edit.range.start..dizzy_edit.range.end], &lines_dst, '\n', null);
|
scan_char(dst[dizzy_edit.range.start..dizzy_edit.range.end], &lines_dst, '\n', null);
|
||||||
(try diffs.addOne()).* = .{
|
(try diffs.addOne(allocator)).* = .{
|
||||||
.kind = .insert,
|
.kind = .insert,
|
||||||
.line = line_start_dst,
|
.line = line_start_dst,
|
||||||
.offset = last_offset,
|
.offset = last_offset,
|
||||||
|
|
@ -165,7 +166,7 @@ pub fn diff(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) ![]D
|
||||||
const dist = dizzy_edit.range.end - dizzy_edit.range.start;
|
const dist = dizzy_edit.range.end - dizzy_edit.range.start;
|
||||||
pos_src += dist;
|
pos_src += dist;
|
||||||
pos_dst += 0;
|
pos_dst += 0;
|
||||||
(try diffs.addOne()).* = .{
|
(try diffs.addOne(allocator)).* = .{
|
||||||
.kind = .delete,
|
.kind = .delete,
|
||||||
.line = lines_dst,
|
.line = lines_dst,
|
||||||
.offset = last_offset,
|
.offset = last_offset,
|
||||||
|
|
@ -176,7 +177,7 @@ pub fn diff(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) ![]D
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return diffs.toOwnedSlice();
|
return diffs.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_edits(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) ![]Edit {
|
pub fn get_edits(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) ![]Edit {
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,10 @@ fn from_file_type(file_type: syntax.FileType) @This() {
|
||||||
pub fn get_default(allocator: std.mem.Allocator, file_type_name: []const u8) ![]const u8 {
|
pub fn get_default(allocator: std.mem.Allocator, file_type_name: []const u8) ![]const u8 {
|
||||||
const file_type = syntax.FileType.get_by_name_static(file_type_name) orelse return error.UnknownFileType;
|
const file_type = syntax.FileType.get_by_name_static(file_type_name) orelse return error.UnknownFileType;
|
||||||
const config = from_file_type(file_type);
|
const config = from_file_type(file_type);
|
||||||
var content = std.ArrayListUnmanaged(u8).empty;
|
var content: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer content.deinit(allocator);
|
defer content.deinit();
|
||||||
root.write_config_to_writer(@This(), config, content.writer(allocator)) catch {};
|
root.write_config_to_writer(@This(), config, &content.writer) catch {};
|
||||||
return content.toOwnedSlice(allocator);
|
return content.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_all_names() []const []const u8 {
|
pub fn get_all_names() []const []const u8 {
|
||||||
|
|
@ -93,21 +93,23 @@ pub fn get(file_type_name: []const u8) !?@This() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_config_file_path(allocator: std.mem.Allocator, file_type: []const u8) ![]u8 {
|
pub fn get_config_file_path(allocator: std.mem.Allocator, file_type: []const u8) ![]u8 {
|
||||||
var stream = std.ArrayList(u8).fromOwnedSlice(allocator, try get_config_dir_path(allocator));
|
var stream: std.Io.Writer.Allocating = .initOwnedSlice(allocator, try get_config_dir_path(allocator));
|
||||||
const writer = stream.writer();
|
defer stream.deinit();
|
||||||
|
const writer = &stream.writer;
|
||||||
_ = try writer.writeAll(file_type);
|
_ = try writer.writeAll(file_type);
|
||||||
_ = try writer.writeAll(".conf");
|
_ = try writer.writeAll(".conf");
|
||||||
return stream.toOwnedSlice();
|
return stream.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config_dir_path(allocator: std.mem.Allocator) ![]u8 {
|
fn get_config_dir_path(allocator: std.mem.Allocator) ![]u8 {
|
||||||
var stream = std.ArrayList(u8).init(allocator);
|
var stream: std.Io.Writer.Allocating = .init(allocator);
|
||||||
const writer = stream.writer();
|
defer stream.deinit();
|
||||||
|
const writer = &stream.writer;
|
||||||
_ = try writer.writeAll(try root.get_config_dir());
|
_ = try writer.writeAll(try root.get_config_dir());
|
||||||
_ = try writer.writeByte(std.fs.path.sep);
|
_ = try writer.writeByte(std.fs.path.sep);
|
||||||
_ = try writer.writeAll("file_type");
|
_ = try writer.writeAll("file_type");
|
||||||
_ = try writer.writeByte(std.fs.path.sep);
|
_ = try writer.writeByte(std.fs.path.sep);
|
||||||
std.fs.makeDirAbsolute(stream.items) catch |e| switch (e) {
|
std.fs.makeDirAbsolute(stream.written()) catch |e| switch (e) {
|
||||||
error.PathAlreadyExists => {},
|
error.PathAlreadyExists => {},
|
||||||
else => return e,
|
else => return e,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ const tp = @import("thespian");
|
||||||
const shell = @import("shell");
|
const shell = @import("shell");
|
||||||
const bin_path = @import("bin_path");
|
const bin_path = @import("bin_path");
|
||||||
|
|
||||||
pub const Error = error{ OutOfMemory, GitNotFound, GitCallFailed };
|
pub const Error = error{ OutOfMemory, GitNotFound, GitCallFailed, WriteFailed };
|
||||||
|
|
||||||
const log_execute = false;
|
const log_execute = false;
|
||||||
|
|
||||||
|
|
@ -208,15 +208,16 @@ fn git_err(
|
||||||
) Error!void {
|
) Error!void {
|
||||||
const cbor = @import("cbor");
|
const cbor = @import("cbor");
|
||||||
const git_binary = get_git() orelse return error.GitNotFound;
|
const git_binary = get_git() orelse return error.GitNotFound;
|
||||||
var buf: std.ArrayListUnmanaged(u8) = .empty;
|
var buf: std.Io.Writer.Allocating = .init(allocator);
|
||||||
const writer = buf.writer(allocator);
|
defer buf.deinit();
|
||||||
|
const writer = &buf.writer;
|
||||||
switch (@typeInfo(@TypeOf(cmd))) {
|
switch (@typeInfo(@TypeOf(cmd))) {
|
||||||
.@"struct" => |info| if (info.is_tuple) {
|
.@"struct" => |info| if (info.is_tuple) {
|
||||||
try cbor.writeArrayHeader(writer, info.fields.len + 1);
|
try cbor.writeArrayHeader(writer, info.fields.len + 1);
|
||||||
try cbor.writeValue(writer, git_binary);
|
try cbor.writeValue(writer, git_binary);
|
||||||
inline for (info.fields) |f|
|
inline for (info.fields) |f|
|
||||||
try cbor.writeValue(writer, @field(cmd, f.name));
|
try cbor.writeValue(writer, @field(cmd, f.name));
|
||||||
return shell.execute(allocator, .{ .buf = buf.items }, .{
|
return shell.execute(allocator, .{ .buf = buf.written() }, .{
|
||||||
.context = context,
|
.context = context,
|
||||||
.out = to_shell_output_handler(out),
|
.out = to_shell_output_handler(out),
|
||||||
.err = to_shell_output_handler(err),
|
.err = to_shell_output_handler(err),
|
||||||
|
|
|
||||||
|
|
@ -137,11 +137,11 @@ pub fn get_namespaces(allocator: std.mem.Allocator) ![]const []const u8 {
|
||||||
for (namespaces) |namespace| allocator.free(namespace);
|
for (namespaces) |namespace| allocator.free(namespace);
|
||||||
allocator.free(namespaces);
|
allocator.free(namespaces);
|
||||||
}
|
}
|
||||||
var result = std.ArrayList([]const u8).init(allocator);
|
var result: std.ArrayList([]const u8) = .empty;
|
||||||
try result.append(try allocator.dupe(u8, "flow"));
|
try result.append(allocator, try allocator.dupe(u8, "flow"));
|
||||||
try result.append(try allocator.dupe(u8, "emacs"));
|
try result.append(allocator, try allocator.dupe(u8, "emacs"));
|
||||||
try result.append(try allocator.dupe(u8, "vim"));
|
try result.append(allocator, try allocator.dupe(u8, "vim"));
|
||||||
try result.append(try allocator.dupe(u8, "helix"));
|
try result.append(allocator, try allocator.dupe(u8, "helix"));
|
||||||
for (namespaces) |namespace| {
|
for (namespaces) |namespace| {
|
||||||
var exists = false;
|
var exists = false;
|
||||||
for (result.items) |existing|
|
for (result.items) |existing|
|
||||||
|
|
@ -150,9 +150,9 @@ pub fn get_namespaces(allocator: std.mem.Allocator) ![]const []const u8 {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (!exists)
|
if (!exists)
|
||||||
try result.append(try allocator.dupe(u8, namespace));
|
try result.append(allocator, try allocator.dupe(u8, namespace));
|
||||||
}
|
}
|
||||||
return result.toOwnedSlice();
|
return result.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_namespace() []const u8 {
|
pub fn get_namespace() []const u8 {
|
||||||
|
|
@ -198,7 +198,7 @@ fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadE
|
||||||
return binding_set;
|
return binding_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LoadError = (error{ NotFound, NotAnObject } || std.json.ParseError(std.json.Scanner) || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError);
|
pub const LoadError = (error{ NotFound, NotAnObject, WriteFailed } || std.json.ParseError(std.json.Scanner) || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError);
|
||||||
|
|
||||||
///A collection of modes that represent a switchable editor emulation
|
///A collection of modes that represent a switchable editor emulation
|
||||||
const Namespace = struct {
|
const Namespace = struct {
|
||||||
|
|
@ -320,7 +320,7 @@ const Command = struct {
|
||||||
return args.len == 1 and args[0] == .integer;
|
return args.len == 1 and args[0] == .integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(allocator: std.mem.Allocator, tokens: []const std.json.Value) (parse_flow.ParseError || parse_vim.ParseError)!Command {
|
fn load(allocator: std.mem.Allocator, tokens: []const std.json.Value) (error{WriteFailed} || parse_flow.ParseError || parse_vim.ParseError)!Command {
|
||||||
if (tokens.len == 0) return error.InvalidFormat;
|
if (tokens.len == 0) return error.InvalidFormat;
|
||||||
var state: enum { command, args } = .command;
|
var state: enum { command, args } = .command;
|
||||||
var args = std.ArrayListUnmanaged(std.json.Value){};
|
var args = std.ArrayListUnmanaged(std.json.Value){};
|
||||||
|
|
@ -343,11 +343,10 @@ const Command = struct {
|
||||||
switch (token) {
|
switch (token) {
|
||||||
.string, .integer, .float, .bool => {},
|
.string, .integer, .float, .bool => {},
|
||||||
else => {
|
else => {
|
||||||
var json = std.ArrayList(u8).init(allocator);
|
const json = try std.json.Stringify.valueAlloc(allocator, token, .{});
|
||||||
defer json.deinit();
|
defer allocator.free(json);
|
||||||
std.json.stringify(token, .{}, json.writer()) catch {};
|
|
||||||
const logger = log.logger("keybind");
|
const logger = log.logger("keybind");
|
||||||
logger.print_err("keybind.load", "ERROR: invalid command argument '{s}'", .{json.items});
|
logger.print_err("keybind.load", "ERROR: invalid command argument '{s}'", .{json});
|
||||||
logger.deinit();
|
logger.deinit();
|
||||||
return error.InvalidFormat;
|
return error.InvalidFormat;
|
||||||
},
|
},
|
||||||
|
|
@ -357,14 +356,14 @@ const Command = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var args_cbor = std.ArrayListUnmanaged(u8){};
|
var args_cbor: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer args_cbor.deinit(allocator);
|
defer args_cbor.deinit();
|
||||||
const writer = args_cbor.writer(allocator);
|
const writer = &args_cbor.writer;
|
||||||
try cbor.writeArrayHeader(writer, args.items.len);
|
try cbor.writeArrayHeader(writer, args.items.len);
|
||||||
for (args.items) |arg| try cbor.writeJsonValue(writer, arg);
|
for (args.items) |arg| try cbor.writeJsonValue(writer, arg);
|
||||||
return .{
|
return .{
|
||||||
.command = command_,
|
.command = command_,
|
||||||
.args = try args_cbor.toOwnedSlice(allocator),
|
.args = try args_cbor.toOwnedSlice(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -426,7 +425,7 @@ const BindingSet = struct {
|
||||||
const KeySyntax = enum { flow, vim };
|
const KeySyntax = enum { flow, vim };
|
||||||
const OnMatchFailure = enum { insert, ignore };
|
const OnMatchFailure = enum { insert, ignore };
|
||||||
|
|
||||||
fn load(allocator: std.mem.Allocator, namespace_name: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, namespace: *Namespace) (error{OutOfMemory} || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() {
|
fn load(allocator: std.mem.Allocator, namespace_name: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, namespace: *Namespace) (error{ OutOfMemory, WriteFailed } || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() {
|
||||||
var self: @This() = .{ .name = undefined, .selection_style = undefined };
|
var self: @This() = .{ .name = undefined, .selection_style = undefined };
|
||||||
|
|
||||||
const JsonConfig = struct {
|
const JsonConfig = struct {
|
||||||
|
|
@ -475,7 +474,7 @@ const BindingSet = struct {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_event(self: *BindingSet, allocator: std.mem.Allocator, dest: *std.ArrayListUnmanaged(Binding), event: input.Event, bindings: []const []const std.json.Value) (parse_flow.ParseError || parse_vim.ParseError)!void {
|
fn load_event(self: *BindingSet, allocator: std.mem.Allocator, dest: *std.ArrayListUnmanaged(Binding), event: input.Event, bindings: []const []const std.json.Value) (error{WriteFailed} || parse_flow.ParseError || parse_vim.ParseError)!void {
|
||||||
_ = event;
|
_ = event;
|
||||||
bindings: for (bindings) |entry| {
|
bindings: for (bindings) |entry| {
|
||||||
if (entry.len < 2) {
|
if (entry.len < 2) {
|
||||||
|
|
@ -509,27 +508,26 @@ const BindingSet = struct {
|
||||||
errdefer allocator.free(key_events);
|
errdefer allocator.free(key_events);
|
||||||
|
|
||||||
const cmd = entry[1];
|
const cmd = entry[1];
|
||||||
var cmds = std.ArrayList(Command).init(allocator);
|
var cmds: std.ArrayList(Command) = .empty;
|
||||||
defer cmds.deinit();
|
defer cmds.deinit(allocator);
|
||||||
if (cmd == .string) {
|
if (cmd == .string) {
|
||||||
try cmds.append(try Command.load(allocator, entry[1..]));
|
try cmds.append(allocator, try Command.load(allocator, entry[1..]));
|
||||||
} else {
|
} else {
|
||||||
for (entry[1..]) |cmd_entry| {
|
for (entry[1..]) |cmd_entry| {
|
||||||
if (cmd_entry != .array) {
|
if (cmd_entry != .array) {
|
||||||
var json = std.ArrayList(u8).init(allocator);
|
const json = try std.json.Stringify.valueAlloc(allocator, cmd_entry, .{});
|
||||||
defer json.deinit();
|
defer allocator.free(json);
|
||||||
std.json.stringify(cmd_entry, .{}, json.writer()) catch {};
|
|
||||||
const logger = log.logger("keybind");
|
const logger = log.logger("keybind");
|
||||||
logger.print_err("keybind.load", "ERROR: invalid command definition {s}", .{json.items});
|
logger.print_err("keybind.load", "ERROR: invalid command definition {s}", .{json});
|
||||||
logger.deinit();
|
logger.deinit();
|
||||||
continue :bindings;
|
continue :bindings;
|
||||||
}
|
}
|
||||||
try cmds.append(try Command.load(allocator, cmd_entry.array.items));
|
try cmds.append(allocator, try Command.load(allocator, cmd_entry.array.items));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try dest.append(allocator, .{
|
try dest.append(allocator, .{
|
||||||
.key_events = key_events,
|
.key_events = key_events,
|
||||||
.commands = try cmds.toOwnedSlice(),
|
.commands = try cmds.toOwnedSlice(allocator),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -564,13 +562,13 @@ const BindingSet = struct {
|
||||||
|
|
||||||
for (self.press.items) |binding| {
|
for (self.press.items) |binding| {
|
||||||
const cmd = binding.commands[0].command;
|
const cmd = binding.commands[0].command;
|
||||||
var hint = if (hints_map.get(cmd)) |previous|
|
var hint: std.Io.Writer.Allocating = if (hints_map.get(cmd)) |previous|
|
||||||
std.ArrayList(u8).fromOwnedSlice(allocator, previous)
|
.initOwnedSlice(allocator, previous)
|
||||||
else
|
else
|
||||||
std.ArrayList(u8).init(allocator);
|
.init(allocator);
|
||||||
defer hint.deinit();
|
defer hint.deinit();
|
||||||
const writer = hint.writer();
|
const writer = &hint.writer;
|
||||||
if (hint.items.len > 0) try writer.writeAll(", ");
|
if (hint.written().len > 0) try writer.writeAll(", ");
|
||||||
const count = binding.key_events.len;
|
const count = binding.key_events.len;
|
||||||
for (binding.key_events, 0..) |key_, n| {
|
for (binding.key_events, 0..) |key_, n| {
|
||||||
var key = key_;
|
var key = key_;
|
||||||
|
|
@ -578,7 +576,7 @@ const BindingSet = struct {
|
||||||
switch (self.syntax) {
|
switch (self.syntax) {
|
||||||
// .flow => {
|
// .flow => {
|
||||||
else => {
|
else => {
|
||||||
try writer.print("{}", .{key});
|
try writer.print("{f}", .{key});
|
||||||
if (n < count - 1)
|
if (n < count - 1)
|
||||||
try writer.writeAll(" ");
|
try writer.writeAll(" ");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ fn parse_error(comptime format: anytype, args: anytype) ParseError {
|
||||||
pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseError![]input.KeyEvent {
|
pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseError![]input.KeyEvent {
|
||||||
parse_error_reset();
|
parse_error_reset();
|
||||||
if (str.len == 0) return parse_error("empty", .{});
|
if (str.len == 0) return parse_error("empty", .{});
|
||||||
var result_events = std.ArrayList(input.KeyEvent).init(allocator);
|
var result_events: std.ArrayList(input.KeyEvent) = .empty;
|
||||||
var iter_sequence = std.mem.tokenizeScalar(u8, str, ' ');
|
var iter_sequence = std.mem.tokenizeScalar(u8, str, ' ');
|
||||||
while (iter_sequence.next()) |item| {
|
while (iter_sequence.next()) |item| {
|
||||||
var key: ?input.Key = null;
|
var key: ?input.Key = null;
|
||||||
|
|
@ -65,11 +65,11 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
if (key == null) return parse_error("unknown key '{s}' in '{s}'", .{ part, str });
|
if (key == null) return parse_error("unknown key '{s}' in '{s}'", .{ part, str });
|
||||||
}
|
}
|
||||||
if (key) |k|
|
if (key) |k|
|
||||||
try result_events.append(input.KeyEvent.from_key_modset(k, mods))
|
try result_events.append(allocator, input.KeyEvent.from_key_modset(k, mods))
|
||||||
else
|
else
|
||||||
return parse_error("no key defined in '{s}'", .{str});
|
return parse_error("no key defined in '{s}'", .{str});
|
||||||
}
|
}
|
||||||
return result_events.toOwnedSlice();
|
return result_events.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const name_map = blk: {
|
pub const name_map = blk: {
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,8 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
var state: State = .base;
|
var state: State = .base;
|
||||||
var function_key_number: u8 = 0;
|
var function_key_number: u8 = 0;
|
||||||
var modifiers: input.Mods = 0;
|
var modifiers: input.Mods = 0;
|
||||||
var result = std.ArrayList(input.KeyEvent).init(allocator);
|
var result: std.ArrayList(input.KeyEvent) = .empty;
|
||||||
defer result.deinit();
|
defer result.deinit(allocator);
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < str.len) {
|
while (i < str.len) {
|
||||||
|
|
@ -100,7 +100,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
'0'...'9',
|
'0'...'9',
|
||||||
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
|
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
|
||||||
'`', '~', '-', '_', '=', '+', '[', ']', '{', '}', '\\', '|', ':', ';', '\'', '"', ',', '.', '/', '?', => {
|
'`', '~', '-', '_', '=', '+', '[', ']', '{', '}', '\\', '|', ':', ';', '\'', '"', ',', '.', '/', '?', => {
|
||||||
try result.append(from_key(str[i]));
|
try result.append(allocator, from_key(str[i]));
|
||||||
i += 1;
|
i += 1;
|
||||||
},
|
},
|
||||||
else => return parse_error(error.InvalidInitialCharacter, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }),
|
else => return parse_error(error.InvalidInitialCharacter, "str: {s}, i: {} c: {c}", .{ str, i, str[i] }),
|
||||||
|
|
@ -216,7 +216,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.insert => {
|
.insert => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Insert") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Insert") == 0) {
|
||||||
try result.append(from_key_mods(input.key.insert, modifiers));
|
try result.append(allocator, from_key_mods(input.key.insert, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 4;
|
i += 4;
|
||||||
|
|
@ -224,7 +224,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.end => {
|
.end => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "End") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "End") == 0) {
|
||||||
try result.append(from_key_mods(input.key.end, modifiers));
|
try result.append(allocator, from_key_mods(input.key.end, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
|
@ -232,7 +232,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.home => {
|
.home => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Home") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Home") == 0) {
|
||||||
try result.append(from_key_mods(input.key.home, modifiers));
|
try result.append(allocator, from_key_mods(input.key.home, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 4;
|
i += 4;
|
||||||
|
|
@ -240,7 +240,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.bs => {
|
.bs => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "BS") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "BS") == 0) {
|
||||||
try result.append(from_key_mods(input.key.backspace, modifiers));
|
try result.append(allocator, from_key_mods(input.key.backspace, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
@ -248,7 +248,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.cr => {
|
.cr => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "CR") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "CR") == 0) {
|
||||||
try result.append(from_key_mods(input.key.enter, modifiers));
|
try result.append(allocator, from_key_mods(input.key.enter, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
@ -256,7 +256,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.space => {
|
.space => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Space") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Space") == 0) {
|
||||||
try result.append(from_key_mods(input.key.space, modifiers));
|
try result.append(allocator, from_key_mods(input.key.space, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 5;
|
i += 5;
|
||||||
|
|
@ -264,7 +264,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.del => {
|
.del => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Del") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Del") == 0) {
|
||||||
try result.append(from_key_mods(input.key.delete, modifiers));
|
try result.append(allocator, from_key_mods(input.key.delete, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
|
@ -272,7 +272,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.tab => {
|
.tab => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Tab") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Tab") == 0) {
|
||||||
try result.append(from_key_mods(input.key.tab, modifiers));
|
try result.append(allocator, from_key_mods(input.key.tab, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
|
@ -280,7 +280,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.up => {
|
.up => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Up") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Up") == 0) {
|
||||||
try result.append(from_key_mods(input.key.up, modifiers));
|
try result.append(allocator, from_key_mods(input.key.up, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
@ -288,7 +288,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.esc => {
|
.esc => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Esc") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Esc") == 0) {
|
||||||
try result.append(from_key_mods(input.key.escape, modifiers));
|
try result.append(allocator, from_key_mods(input.key.escape, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
|
@ -296,7 +296,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.down => {
|
.down => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Down") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Down") == 0) {
|
||||||
try result.append(from_key_mods(input.key.down, modifiers));
|
try result.append(allocator, from_key_mods(input.key.down, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 4;
|
i += 4;
|
||||||
|
|
@ -304,7 +304,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.left => {
|
.left => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Left") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Left") == 0) {
|
||||||
try result.append(from_key_mods(input.key.left, modifiers));
|
try result.append(allocator, from_key_mods(input.key.left, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 4;
|
i += 4;
|
||||||
|
|
@ -312,7 +312,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.right => {
|
.right => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "Right") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "Right") == 0) {
|
||||||
try result.append(from_key_mods(input.key.right, modifiers));
|
try result.append(allocator, from_key_mods(input.key.right, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 5;
|
i += 5;
|
||||||
|
|
@ -320,7 +320,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.less_than => {
|
.less_than => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "LT") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "LT") == 0) {
|
||||||
try result.append(from_key_mods('<', modifiers));
|
try result.append(allocator, from_key_mods('<', modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
@ -328,7 +328,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
.greater_than => {
|
.greater_than => {
|
||||||
if (std.mem.indexOf(u8, str[i..], "GT") == 0) {
|
if (std.mem.indexOf(u8, str[i..], "GT") == 0) {
|
||||||
try result.append(from_key_mods('>', modifiers));
|
try result.append(allocator, from_key_mods('>', modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
@ -345,7 +345,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
'>' => {
|
'>' => {
|
||||||
const function_key = input.key.f1 - 1 + function_key_number;
|
const function_key = input.key.f1 - 1 + function_key_number;
|
||||||
try result.append(from_key_mods(function_key, modifiers));
|
try result.append(allocator, from_key_mods(function_key, modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
function_key_number = 0;
|
function_key_number = 0;
|
||||||
state = .base;
|
state = .base;
|
||||||
|
|
@ -371,7 +371,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
'0'...'9',
|
'0'...'9',
|
||||||
'`', '-', '=', '[', ']', '\\', ':', ';', '\'', ',', '.', '/',
|
'`', '-', '=', '[', ']', '\\', ':', ';', '\'', ',', '.', '/',
|
||||||
=> {
|
=> {
|
||||||
try result.append(from_key_mods(str[i], modifiers));
|
try result.append(allocator, from_key_mods(str[i], modifiers));
|
||||||
modifiers = 0;
|
modifiers = 0;
|
||||||
state = .escape_sequence_end;
|
state = .escape_sequence_end;
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
@ -405,5 +405,5 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.toOwnedSlice();
|
return result.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ const Process = struct {
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.arena = std.heap.ArenaAllocator.init(outer_a),
|
.arena = std.heap.ArenaAllocator.init(outer_a),
|
||||||
.allocator = self.arena.allocator(),
|
.allocator = self.arena.allocator(),
|
||||||
.backwards = std.ArrayList(Entry).init(self.allocator),
|
.backwards = .empty,
|
||||||
.forwards = std.ArrayList(Entry).init(self.allocator),
|
.forwards = .empty,
|
||||||
.receiver = Receiver.init(Process.receive, self),
|
.receiver = Receiver.init(Process.receive, self),
|
||||||
};
|
};
|
||||||
return tp.spawn_link(self.allocator, self, Process.start, module_name);
|
return tp.spawn_link(self.allocator, self, Process.start, module_name);
|
||||||
|
|
@ -65,8 +65,8 @@ const Process = struct {
|
||||||
fn deinit(self: *Process) void {
|
fn deinit(self: *Process) void {
|
||||||
self.clear_backwards();
|
self.clear_backwards();
|
||||||
self.clear_forwards();
|
self.clear_forwards();
|
||||||
self.backwards.deinit();
|
self.backwards.deinit(self.allocator);
|
||||||
self.forwards.deinit();
|
self.forwards.deinit(self.allocator);
|
||||||
if (self.current) |entry| self.allocator.free(entry.file_path);
|
if (self.current) |entry| self.allocator.free(entry.file_path);
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
outer_a.destroy(self);
|
outer_a.destroy(self);
|
||||||
|
|
@ -82,7 +82,7 @@ const Process = struct {
|
||||||
|
|
||||||
fn clear_table(self: *Process, table: *std.ArrayList(Entry)) void {
|
fn clear_table(self: *Process, table: *std.ArrayList(Entry)) void {
|
||||||
for (table.items) |entry| self.allocator.free(entry.file_path);
|
for (table.items) |entry| self.allocator.free(entry.file_path);
|
||||||
table.clearAndFree();
|
table.clearAndFree(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
||||||
|
|
@ -122,17 +122,17 @@ const Process = struct {
|
||||||
return self.allocator.free(self.current.?.file_path);
|
return self.allocator.free(self.current.?.file_path);
|
||||||
|
|
||||||
if (isdupe(self.backwards.getLastOrNull(), entry)) {
|
if (isdupe(self.backwards.getLastOrNull(), entry)) {
|
||||||
if (self.current) |current| self.forwards.append(current) catch {};
|
if (self.current) |current| self.forwards.append(self.allocator, current) catch {};
|
||||||
if (self.backwards.pop()) |top|
|
if (self.backwards.pop()) |top|
|
||||||
self.allocator.free(top.file_path);
|
self.allocator.free(top.file_path);
|
||||||
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "back", entry.file_path, entry.cursor.row, entry.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "back", entry.file_path, entry.cursor.row, entry.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
||||||
} else if (isdupe(self.forwards.getLastOrNull(), entry)) {
|
} else if (isdupe(self.forwards.getLastOrNull(), entry)) {
|
||||||
if (self.current) |current| self.backwards.append(current) catch {};
|
if (self.current) |current| self.backwards.append(self.allocator, current) catch {};
|
||||||
if (self.forwards.pop()) |top|
|
if (self.forwards.pop()) |top|
|
||||||
self.allocator.free(top.file_path);
|
self.allocator.free(top.file_path);
|
||||||
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "forward", entry.file_path, entry.cursor.row, entry.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "forward", entry.file_path, entry.cursor.row, entry.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
||||||
} else if (self.current) |current| {
|
} else if (self.current) |current| {
|
||||||
try self.backwards.append(current);
|
try self.backwards.append(self.allocator, current);
|
||||||
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "new", current.file_path, current.cursor.row, current.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "new", current.file_path, current.cursor.row, current.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
||||||
self.clear_forwards();
|
self.clear_forwards();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
src/log.zig
24
src/log.zig
|
|
@ -94,16 +94,24 @@ fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
|
||||||
} else {
|
} else {
|
||||||
self.store(m);
|
self.store(m);
|
||||||
}
|
}
|
||||||
if (!self.no_stderr)
|
if (!self.no_stderr) {
|
||||||
std.io.getStdErr().writer().print("{s}\n", .{output}) catch {};
|
var stderr_buffer: [1024]u8 = undefined;
|
||||||
|
var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
|
||||||
|
stderr_writer.interface.print("{s}\n", .{output}) catch {};
|
||||||
|
stderr_writer.interface.flush() catch {};
|
||||||
|
}
|
||||||
} else if (try m.match(.{ "log", tp.string, tp.extract(&output) })) {
|
} else if (try m.match(.{ "log", tp.string, tp.extract(&output) })) {
|
||||||
if (self.subscriber) |subscriber| {
|
if (self.subscriber) |subscriber| {
|
||||||
subscriber.send_raw(m) catch {};
|
subscriber.send_raw(m) catch {};
|
||||||
} else {
|
} else {
|
||||||
self.store(m);
|
self.store(m);
|
||||||
}
|
}
|
||||||
if (!self.no_stdout)
|
if (!self.no_stdout) {
|
||||||
std.io.getStdOut().writer().print("{s}\n", .{output}) catch {};
|
var stdout_buffer: [1024]u8 = undefined;
|
||||||
|
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
||||||
|
stdout_writer.interface.print("{s}\n", .{output}) catch {};
|
||||||
|
stdout_writer.interface.flush() catch {};
|
||||||
|
}
|
||||||
} else if (try m.match(.{"subscribe"})) {
|
} else if (try m.match(.{"subscribe"})) {
|
||||||
// log("subscribed");
|
// log("subscribed");
|
||||||
if (self.subscriber) |*s| s.deinit();
|
if (self.subscriber) |*s| s.deinit();
|
||||||
|
|
@ -152,8 +160,8 @@ pub const Logger = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn err(self: Logger, context: []const u8, e: anyerror) void {
|
pub fn err(self: Logger, context: []const u8, e: anyerror) void {
|
||||||
var msg_fmt = std.ArrayList(u8).init(std.heap.c_allocator);
|
var msg_fmt: std.ArrayList(u8) = .empty;
|
||||||
defer msg_fmt.deinit();
|
defer msg_fmt.deinit(std.heap.c_allocator);
|
||||||
defer tp.reset_error();
|
defer tp.reset_error();
|
||||||
var buf: [max_log_message]u8 = undefined;
|
var buf: [max_log_message]u8 = undefined;
|
||||||
var msg: []const u8 = "UNKNOWN";
|
var msg: []const u8 = "UNKNOWN";
|
||||||
|
|
@ -168,12 +176,12 @@ pub const Logger = struct {
|
||||||
//
|
//
|
||||||
} else {
|
} else {
|
||||||
var failed = false;
|
var failed = false;
|
||||||
msg_fmt.writer().print("{}", .{msg_}) catch {
|
msg_fmt.writer(std.heap.c_allocator).print("{f}", .{msg_}) catch {
|
||||||
failed = true;
|
failed = true;
|
||||||
};
|
};
|
||||||
if (failed) {
|
if (failed) {
|
||||||
msg_fmt.clearRetainingCapacity();
|
msg_fmt.clearRetainingCapacity();
|
||||||
msg_fmt.writer().print("{s}", .{std.fmt.fmtSliceEscapeLower(msg_.buf)}) catch {};
|
msg_fmt.writer(std.heap.c_allocator).print("{f}", .{std.ascii.hexEscape(msg_.buf, .lower)}) catch {};
|
||||||
}
|
}
|
||||||
msg__ = msg_fmt.items;
|
msg__ = msg_fmt.items;
|
||||||
tp.trace(tp.channel.debug, .{ "log_err_fmt", msg__.len, msg__[0..@min(msg__.len, 128)] });
|
tp.trace(tp.channel.debug, .{ "log_err_fmt", msg__.len, msg__[0..@min(msg__.len, 128)] });
|
||||||
|
|
|
||||||
70
src/main.zig
70
src/main.zig
|
|
@ -251,12 +251,12 @@ pub fn main() anyerror!void {
|
||||||
const tui_proc = try tui.spawn(a, &ctx, &eh, &env);
|
const tui_proc = try tui.spawn(a, &ctx, &eh, &env);
|
||||||
defer tui_proc.deinit();
|
defer tui_proc.deinit();
|
||||||
|
|
||||||
var links = std.ArrayList(file_link.Dest).init(a);
|
var links: std.ArrayList(file_link.Dest) = .empty;
|
||||||
defer links.deinit();
|
defer links.deinit(a);
|
||||||
var prev: ?*file_link.Dest = null;
|
var prev: ?*file_link.Dest = null;
|
||||||
var line_next: ?usize = null;
|
var line_next: ?usize = null;
|
||||||
var offset_next: ?usize = null;
|
var offset_next: ?usize = null;
|
||||||
for (args.positional.trailing.items) |arg| {
|
for (args.positional.trailing) |arg| {
|
||||||
if (arg.len == 0) continue;
|
if (arg.len == 0) continue;
|
||||||
|
|
||||||
if (!args.literal and arg[0] == '+') {
|
if (!args.literal and arg[0] == '+') {
|
||||||
|
|
@ -286,7 +286,7 @@ pub fn main() anyerror!void {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const curr = try links.addOne();
|
const curr = try links.addOne(a);
|
||||||
curr.* = if (!args.literal) try file_link.parse(arg) else .{ .file = .{ .path = arg } };
|
curr.* = if (!args.literal) try file_link.parse(arg) else .{ .file = .{ .path = arg } };
|
||||||
prev = curr;
|
prev = curr;
|
||||||
|
|
||||||
|
|
@ -354,9 +354,9 @@ pub fn main() anyerror!void {
|
||||||
while (count_args_.next()) |_| count += 1;
|
while (count_args_.next()) |_| count += 1;
|
||||||
if (count == 0) break;
|
if (count == 0) break;
|
||||||
|
|
||||||
var msg = std.ArrayList(u8).init(a);
|
var msg: std.Io.Writer.Allocating = .init(a);
|
||||||
defer msg.deinit();
|
defer msg.deinit();
|
||||||
const writer = msg.writer();
|
const writer = &msg.writer;
|
||||||
|
|
||||||
var cmd_args = std.mem.splitScalar(u8, cmd, ':');
|
var cmd_args = std.mem.splitScalar(u8, cmd, ':');
|
||||||
const cmd_ = cmd_args.next();
|
const cmd_ = cmd_args.next();
|
||||||
|
|
@ -372,7 +372,7 @@ pub fn main() anyerror!void {
|
||||||
try cbor.writeValue(writer, arg);
|
try cbor.writeValue(writer, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
try tui_proc.send_raw(.{ .buf = msg.items });
|
try tui_proc.send_raw(.{ .buf = msg.written() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,7 +391,10 @@ pub fn print_exit_status(_: void, msg: []const u8) void {
|
||||||
} else if (std.mem.eql(u8, msg, "restart")) {
|
} else if (std.mem.eql(u8, msg, "restart")) {
|
||||||
want_restart = true;
|
want_restart = true;
|
||||||
} else {
|
} else {
|
||||||
std.io.getStdErr().writer().print("\n" ++ application_name ++ " ERROR: {s}\n", .{msg}) catch {};
|
var stderr_buffer: [1024]u8 = undefined;
|
||||||
|
var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
|
||||||
|
stderr_writer.interface.print("\n" ++ application_name ++ " ERROR: {s}\n", .{msg}) catch {};
|
||||||
|
stderr_writer.interface.flush() catch {};
|
||||||
final_exit_status = 1;
|
final_exit_status = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -434,31 +437,31 @@ fn trace_to_file(m: thespian.message.c_buffer_type) callconv(.c) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const a = std.heap.c_allocator;
|
||||||
var state: *State = &(State.state orelse init: {
|
var state: *State = &(State.state orelse init: {
|
||||||
const a = std.heap.c_allocator;
|
var path: std.Io.Writer.Allocating = .init(a);
|
||||||
var path = std.ArrayList(u8).init(a);
|
|
||||||
defer path.deinit();
|
defer path.deinit();
|
||||||
path.writer().print("{s}{c}trace.log", .{ get_state_dir() catch return, sep }) catch return;
|
path.writer.print("{s}{c}trace.log", .{ get_state_dir() catch return, sep }) catch return;
|
||||||
const file = std.fs.createFileAbsolute(path.items, .{ .truncate = true }) catch return;
|
const file = std.fs.createFileAbsolute(path.written(), .{ .truncate = true }) catch return;
|
||||||
State.state = .{
|
State.state = .{
|
||||||
.file = file,
|
.file = file,
|
||||||
.last_time = std.time.microTimestamp(),
|
.last_time = std.time.microTimestamp(),
|
||||||
};
|
};
|
||||||
break :init State.state.?;
|
break :init State.state.?;
|
||||||
});
|
});
|
||||||
const file_writer = state.file.writer();
|
var buffer: [4096]u8 = undefined;
|
||||||
var buffer = std.io.bufferedWriter(file_writer);
|
var file_writer = state.file.writer(&buffer);
|
||||||
const writer = buffer.writer();
|
const writer = &file_writer.interface;
|
||||||
|
|
||||||
const ts = std.time.microTimestamp();
|
const ts = std.time.microTimestamp();
|
||||||
State.write_tdiff(writer, ts - state.last_time) catch {};
|
State.write_tdiff(writer, ts - state.last_time) catch {};
|
||||||
state.last_time = ts;
|
state.last_time = ts;
|
||||||
|
|
||||||
var stream = std.json.writeStream(writer, .{});
|
var stream: std.json.Stringify = .{ .writer = writer };
|
||||||
var iter: []const u8 = m.base[0..m.len];
|
var iter: []const u8 = m.base[0..m.len];
|
||||||
cbor.JsonStream(@TypeOf(buffer)).jsonWriteValue(&stream, &iter) catch {};
|
cbor.JsonWriter.jsonWriteValue(&stream, &iter) catch {};
|
||||||
_ = writer.write("\n") catch {};
|
_ = writer.write("\n") catch {};
|
||||||
buffer.flush() catch {};
|
writer.flush() catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(status: u8) noreturn {
|
pub fn exit(status: u8) noreturn {
|
||||||
|
|
@ -533,9 +536,9 @@ fn read_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8, content: []const u8) !void {
|
pub fn parse_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8, content: []const u8) !void {
|
||||||
var cbor_buf = std.ArrayList(u8).init(allocator);
|
var cbor_buf: std.Io.Writer.Allocating = .init(allocator);
|
||||||
defer cbor_buf.deinit();
|
defer cbor_buf.deinit();
|
||||||
const writer = cbor_buf.writer();
|
const writer = &cbor_buf.writer;
|
||||||
var it = std.mem.splitScalar(u8, content, '\n');
|
var it = std.mem.splitScalar(u8, content, '\n');
|
||||||
var lineno: u32 = 0;
|
var lineno: u32 = 0;
|
||||||
while (it.next()) |line| {
|
while (it.next()) |line| {
|
||||||
|
|
@ -554,7 +557,7 @@ pub fn parse_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, b
|
||||||
};
|
};
|
||||||
defer allocator.free(cb);
|
defer allocator.free(cb);
|
||||||
try cbor.writeValue(writer, name);
|
try cbor.writeValue(writer, name);
|
||||||
try cbor_buf.appendSlice(cb);
|
try writer.writeAll(cb);
|
||||||
}
|
}
|
||||||
const cb = try cbor_buf.toOwnedSlice();
|
const cb = try cbor_buf.toOwnedSlice();
|
||||||
var bufs = std.ArrayListUnmanaged([]const u8).fromOwnedSlice(bufs_.*);
|
var bufs = std.ArrayListUnmanaged([]const u8).fromOwnedSlice(bufs_.*);
|
||||||
|
|
@ -650,7 +653,7 @@ fn read_nested_include_files(T: type, allocator: std.mem.Allocator, conf: *T, bu
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ConfigWriteError = error{ CreateConfigFileFailed, WriteConfigFileFailed };
|
pub const ConfigWriteError = error{ CreateConfigFileFailed, WriteConfigFileFailed, WriteFailed };
|
||||||
|
|
||||||
pub fn write_config(conf: anytype, allocator: std.mem.Allocator) (ConfigDirError || ConfigWriteError)!void {
|
pub fn write_config(conf: anytype, allocator: std.mem.Allocator) (ConfigDirError || ConfigWriteError)!void {
|
||||||
config_mutex.lock();
|
config_mutex.lock();
|
||||||
|
|
@ -667,14 +670,16 @@ fn write_text_config_file(comptime T: type, data: T, file_name: []const u8) Conf
|
||||||
return error.CreateConfigFileFailed;
|
return error.CreateConfigFileFailed;
|
||||||
};
|
};
|
||||||
defer file.close();
|
defer file.close();
|
||||||
const writer = file.writer();
|
var buf: [4096]u8 = undefined;
|
||||||
write_config_to_writer(T, data, writer) catch |e| {
|
var writer = file.writer(&buf);
|
||||||
|
write_config_to_writer(T, data, &writer.interface) catch |e| {
|
||||||
std.log.err("write file failed with {any} for: {s}", .{ e, file_name });
|
std.log.err("write file failed with {any} for: {s}", .{ e, file_name });
|
||||||
return error.WriteConfigFileFailed;
|
return error.WriteConfigFileFailed;
|
||||||
};
|
};
|
||||||
|
try writer.interface.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_config_to_writer(comptime T: type, data: T, writer: anytype) @TypeOf(writer).Error!void {
|
pub fn write_config_to_writer(comptime T: type, data: T, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||||
const default: T = .{};
|
const default: T = .{};
|
||||||
inline for (@typeInfo(T).@"struct".fields) |field_info| {
|
inline for (@typeInfo(T).@"struct".fields) |field_info| {
|
||||||
if (config_eql(
|
if (config_eql(
|
||||||
|
|
@ -693,7 +698,7 @@ pub fn write_config_to_writer(comptime T: type, data: T, writer: anytype) @TypeO
|
||||||
else
|
else
|
||||||
try writer.writeAll("null"),
|
try writer.writeAll("null"),
|
||||||
else => {
|
else => {
|
||||||
var s = std.json.writeStream(writer, .{ .whitespace = .minified });
|
var s: std.json.Stringify = .{ .writer = writer, .options = .{ .whitespace = .minified } };
|
||||||
try s.write(@field(data, field_info.name));
|
try s.write(@field(data, field_info.name));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -701,7 +706,7 @@ pub fn write_config_to_writer(comptime T: type, data: T, writer: anytype) @TypeO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_color_value(value: u24, writer: anytype) @TypeOf(writer).Error!void {
|
fn write_color_value(value: u24, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||||
var hex: [7]u8 = undefined;
|
var hex: [7]u8 = undefined;
|
||||||
try writer.writeByte('"');
|
try writer.writeByte('"');
|
||||||
try writer.writeAll(color.RGB.to_string(color.RGB.from_u24(value), &hex));
|
try writer.writeAll(color.RGB.to_string(color.RGB.from_u24(value), &hex));
|
||||||
|
|
@ -770,15 +775,15 @@ pub fn write_keybind_namespace(namespace_name: []const u8, content: []const u8)
|
||||||
pub fn list_keybind_namespaces(allocator: std.mem.Allocator) ![]const []const u8 {
|
pub fn list_keybind_namespaces(allocator: std.mem.Allocator) ![]const []const u8 {
|
||||||
var dir = try std.fs.openDirAbsolute(try get_keybind_namespaces_directory(), .{ .iterate = true });
|
var dir = try std.fs.openDirAbsolute(try get_keybind_namespaces_directory(), .{ .iterate = true });
|
||||||
defer dir.close();
|
defer dir.close();
|
||||||
var result = std.ArrayList([]const u8).init(allocator);
|
var result: std.ArrayList([]const u8) = .empty;
|
||||||
var iter = dir.iterateAssumeFirstIteration();
|
var iter = dir.iterateAssumeFirstIteration();
|
||||||
while (try iter.next()) |entry| {
|
while (try iter.next()) |entry| {
|
||||||
switch (entry.kind) {
|
switch (entry.kind) {
|
||||||
.file, .sym_link => try result.append(try allocator.dupe(u8, std.fs.path.stem(entry.name))),
|
.file, .sym_link => try result.append(allocator, try allocator.dupe(u8, std.fs.path.stem(entry.name))),
|
||||||
else => continue,
|
else => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.toOwnedSlice();
|
return result.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_theme(allocator: std.mem.Allocator, theme_name: []const u8) ?[]const u8 {
|
pub fn read_theme(allocator: std.mem.Allocator, theme_name: []const u8) ?[]const u8 {
|
||||||
|
|
@ -1052,7 +1057,10 @@ fn restart() noreturn {
|
||||||
null,
|
null,
|
||||||
};
|
};
|
||||||
const ret = std.c.execve(executable, @ptrCast(&argv), @ptrCast(std.os.environ));
|
const ret = std.c.execve(executable, @ptrCast(&argv), @ptrCast(std.os.environ));
|
||||||
std.io.getStdErr().writer().print("\nrestart failed: {d}", .{ret}) catch {};
|
var stderr_buffer: [1024]u8 = undefined;
|
||||||
|
var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
|
||||||
|
stderr_writer.interface.print("\nrestart failed: {d}", .{ret}) catch {};
|
||||||
|
stderr_writer.interface.flush() catch {};
|
||||||
exit(234);
|
exit(234);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -463,12 +463,13 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_recent_projects(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!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) = .empty;
|
||||||
defer recent_projects.deinit();
|
defer recent_projects.deinit(self.allocator);
|
||||||
self.load_recent_projects(&recent_projects, project_directory) catch {};
|
self.load_recent_projects(&recent_projects, project_directory) catch {};
|
||||||
self.sort_projects_by_last_used(&recent_projects);
|
self.sort_projects_by_last_used(&recent_projects);
|
||||||
var message = std.ArrayList(u8).init(self.allocator);
|
var message: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
const writer = message.writer();
|
defer message.deinit();
|
||||||
|
const writer = &message.writer;
|
||||||
try cbor.writeArrayHeader(writer, 3);
|
try cbor.writeArrayHeader(writer, 3);
|
||||||
try cbor.writeValue(writer, "PRJ");
|
try cbor.writeValue(writer, "PRJ");
|
||||||
try cbor.writeValue(writer, "recent_projects");
|
try cbor.writeValue(writer, "recent_projects");
|
||||||
|
|
@ -478,7 +479,7 @@ const Process = struct {
|
||||||
try cbor.writeValue(writer, project.name);
|
try cbor.writeValue(writer, project.name);
|
||||||
try cbor.writeValue(writer, if (self.projects.get(project.name)) |_| true else false);
|
try cbor.writeValue(writer, if (self.projects.get(project.name)) |_| true else false);
|
||||||
}
|
}
|
||||||
from.send_raw(.{ .buf = message.items }) catch return error.ClientFailed;
|
from.send_raw(.{ .buf = message.written() }) catch return error.ClientFailed;
|
||||||
self.logger.print("{d} projects found", .{recent_projects.items.len});
|
self.logger.print("{d} projects found", .{recent_projects.items.len});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,9 +494,9 @@ const Process = struct {
|
||||||
|
|
||||||
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 {
|
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;
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
var buf = std.ArrayList(u8).init(self.allocator);
|
var buf: std.ArrayList(u8) = .empty;
|
||||||
defer buf.deinit();
|
defer buf.deinit(self.allocator);
|
||||||
try request_path_files_async(self.allocator, from, project, max, expand_home(&buf, path));
|
try request_path_files_async(self.allocator, from, project, max, expand_home(self.allocator, &buf, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_tasks(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void {
|
fn request_tasks(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void {
|
||||||
|
|
@ -651,9 +652,10 @@ const Process = struct {
|
||||||
defer self.allocator.free(file_name);
|
defer self.allocator.free(file_name);
|
||||||
var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true });
|
var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true });
|
||||||
defer file.close();
|
defer file.close();
|
||||||
var buffer = std.io.bufferedWriter(file.writer());
|
var buffer: [4096]u8 = undefined;
|
||||||
defer buffer.flush() catch {};
|
var writer = file.writer(&buffer);
|
||||||
try project.write_state(buffer.writer());
|
defer writer.interface.flush() catch {};
|
||||||
|
try project.write_state(&writer.interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_project(self: *Process, project: *Project) !void {
|
fn restore_project(self: *Process, project: *Project) !void {
|
||||||
|
|
@ -674,13 +676,14 @@ const Process = struct {
|
||||||
|
|
||||||
fn get_project_state_file_path(allocator: std.mem.Allocator, project: *Project) ![]const u8 {
|
fn get_project_state_file_path(allocator: std.mem.Allocator, project: *Project) ![]const u8 {
|
||||||
const path = project.name;
|
const path = project.name;
|
||||||
var stream = std.ArrayList(u8).init(allocator);
|
var stream: std.Io.Writer.Allocating = .init(allocator);
|
||||||
const writer = stream.writer();
|
defer stream.deinit();
|
||||||
|
const writer = &stream.writer;
|
||||||
_ = try writer.write(try root.get_state_dir());
|
_ = try writer.write(try root.get_state_dir());
|
||||||
_ = try writer.writeByte(std.fs.path.sep);
|
_ = try writer.writeByte(std.fs.path.sep);
|
||||||
_ = try writer.write("projects");
|
_ = try writer.write("projects");
|
||||||
_ = try writer.writeByte(std.fs.path.sep);
|
_ = try writer.writeByte(std.fs.path.sep);
|
||||||
std.fs.makeDirAbsolute(stream.items) catch |e| switch (e) {
|
std.fs.makeDirAbsolute(stream.written()) catch |e| switch (e) {
|
||||||
error.PathAlreadyExists => {},
|
error.PathAlreadyExists => {},
|
||||||
else => return e,
|
else => return e,
|
||||||
};
|
};
|
||||||
|
|
@ -696,19 +699,19 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_recent_projects(self: *Process, recent_projects: *std.ArrayList(RecentProject), project_directory: []const u8) !void {
|
fn load_recent_projects(self: *Process, recent_projects: *std.ArrayList(RecentProject), project_directory: []const u8) !void {
|
||||||
var path = std.ArrayList(u8).init(self.allocator);
|
var path: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer path.deinit();
|
defer path.deinit();
|
||||||
const writer = path.writer();
|
const writer = &path.writer;
|
||||||
_ = try writer.write(try root.get_state_dir());
|
_ = try writer.write(try root.get_state_dir());
|
||||||
_ = try writer.writeByte(std.fs.path.sep);
|
_ = try writer.writeByte(std.fs.path.sep);
|
||||||
_ = try writer.write("projects");
|
_ = try writer.write("projects");
|
||||||
|
|
||||||
var dir = try std.fs.cwd().openDir(path.items, .{ .iterate = true });
|
var dir = try std.fs.cwd().openDir(path.written(), .{ .iterate = true });
|
||||||
defer dir.close();
|
defer dir.close();
|
||||||
var iter = dir.iterate();
|
var iter = dir.iterate();
|
||||||
while (try iter.next()) |entry| {
|
while (try iter.next()) |entry| {
|
||||||
if (entry.kind != .file) continue;
|
if (entry.kind != .file) continue;
|
||||||
try self.read_project_name(path.items, entry.name, recent_projects, project_directory);
|
try self.read_project_name(path.written(), entry.name, recent_projects, project_directory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -719,14 +722,14 @@ const Process = struct {
|
||||||
recent_projects: *std.ArrayList(RecentProject),
|
recent_projects: *std.ArrayList(RecentProject),
|
||||||
project_directory: []const u8,
|
project_directory: []const u8,
|
||||||
) !void {
|
) !void {
|
||||||
var path = std.ArrayList(u8).init(self.allocator);
|
var path: std.Io.Writer.Allocating = .init(self.allocator);
|
||||||
defer path.deinit();
|
defer path.deinit();
|
||||||
const writer = path.writer();
|
const writer = &path.writer;
|
||||||
_ = try writer.write(state_dir);
|
_ = try writer.write(state_dir);
|
||||||
_ = try writer.writeByte(std.fs.path.sep);
|
_ = try writer.writeByte(std.fs.path.sep);
|
||||||
_ = try writer.write(file_path);
|
_ = try writer.write(file_path);
|
||||||
|
|
||||||
var file = try std.fs.openFileAbsolute(path.items, .{ .mode = .read_only });
|
var file = try std.fs.openFileAbsolute(path.written(), .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer file.close();
|
||||||
const stat = try file.stat();
|
const stat = try file.stat();
|
||||||
const buffer = try self.allocator.alloc(u8, @intCast(stat.size));
|
const buffer = try self.allocator.alloc(u8, @intCast(stat.size));
|
||||||
|
|
@ -737,7 +740,7 @@ const Process = struct {
|
||||||
var name: []const u8 = undefined;
|
var name: []const u8 = undefined;
|
||||||
if (cbor.matchValue(&iter, tp.extract(&name)) catch return) {
|
if (cbor.matchValue(&iter, tp.extract(&name)) catch return) {
|
||||||
const last_used = if (std.mem.eql(u8, project_directory, name)) std.math.maxInt(@TypeOf(stat.mtime)) else stat.mtime;
|
const last_used = if (std.mem.eql(u8, project_directory, name)) std.math.maxInt(@TypeOf(stat.mtime)) else stat.mtime;
|
||||||
(try recent_projects.addOne()).* = .{ .name = try self.allocator.dupe(u8, name), .last_used = last_used };
|
(try recent_projects.addOne(self.allocator)).* = .{ .name = try self.allocator.dupe(u8, name), .last_used = last_used };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -851,14 +854,14 @@ pub fn abbreviate_home(buf: []u8, path: []const u8) []const u8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_home(buf: *std.ArrayList(u8), file_path: []const u8) []const u8 {
|
pub fn expand_home(allocator: std.mem.Allocator, buf: *std.ArrayList(u8), file_path: []const u8) []const u8 {
|
||||||
if (builtin.os.tag == .windows) return file_path;
|
if (builtin.os.tag == .windows) return file_path;
|
||||||
if (file_path.len > 0 and file_path[0] == '~') {
|
if (file_path.len > 0 and file_path[0] == '~') {
|
||||||
if (file_path.len > 1 and file_path[1] != std.fs.path.sep) return file_path;
|
if (file_path.len > 1 and file_path[1] != std.fs.path.sep) return file_path;
|
||||||
const homedir = std.posix.getenv("HOME") orelse return file_path;
|
const homedir = std.posix.getenv("HOME") orelse return file_path;
|
||||||
buf.appendSlice(homedir) catch return file_path;
|
buf.appendSlice(allocator, homedir) catch return file_path;
|
||||||
buf.append(std.fs.path.sep) catch return file_path;
|
buf.append(allocator, std.fs.path.sep) catch return file_path;
|
||||||
buf.appendSlice(file_path[2..]) catch return file_path;
|
buf.appendSlice(allocator, file_path[2..]) catch return file_path;
|
||||||
return buf.items;
|
return buf.items;
|
||||||
} else return file_path;
|
} else return file_path;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ pub fn putstr(self: *Plane, text: []const u8) !usize {
|
||||||
var result: usize = 0;
|
var result: usize = 0;
|
||||||
const height = self.window.height;
|
const height = self.window.height;
|
||||||
const width = self.window.width;
|
const width = self.window.width;
|
||||||
var iter = self.window.screen.unicode.graphemeIterator(text);
|
var iter = self.window.unicode.graphemeIterator(text);
|
||||||
while (iter.next()) |grapheme| {
|
while (iter.next()) |grapheme| {
|
||||||
const s = grapheme.bytes(text);
|
const s = grapheme.bytes(text);
|
||||||
if (std.mem.eql(u8, s, "\n")) {
|
if (std.mem.eql(u8, s, "\n")) {
|
||||||
|
|
@ -443,7 +443,7 @@ pub fn egc_length(self: *const Plane, egcs: []const u8, colcount: *c_int, abs_co
|
||||||
colcount.* = @intCast(tab_width - (abs_col % tab_width));
|
colcount.* = @intCast(tab_width - (abs_col % tab_width));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
var iter = self.window.screen.unicode.graphemeIterator(egcs);
|
var iter = self.window.unicode.graphemeIterator(egcs);
|
||||||
const grapheme = iter.next() orelse {
|
const grapheme = iter.next() orelse {
|
||||||
colcount.* = 1;
|
colcount.* = 1;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -470,7 +470,7 @@ pub fn egc_chunk_width(self: *const Plane, chunk_: []const u8, abs_col_: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn egc_last(self: *const Plane, egcs: []const u8) []const u8 {
|
pub fn egc_last(self: *const Plane, egcs: []const u8) []const u8 {
|
||||||
var iter = self.window.screen.unicode.graphemeIterator(egcs);
|
var iter = self.window.unicode.graphemeIterator(egcs);
|
||||||
var last: []const u8 = egcs[0..0];
|
var last: []const u8 = egcs[0..0];
|
||||||
while (iter.next()) |grapheme| last = grapheme.bytes(egcs);
|
while (iter.next()) |grapheme| last = grapheme.bytes(egcs);
|
||||||
return last;
|
return last;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
const vaxis = @import("vaxis");
|
const vaxis = @import("vaxis");
|
||||||
|
|
||||||
|
const Io = @import("std").Io;
|
||||||
const meta = @import("std").meta;
|
const meta = @import("std").meta;
|
||||||
const unicode = @import("std").unicode;
|
const unicode = @import("std").unicode;
|
||||||
const FormatOptions = @import("std").fmt.FormatOptions;
|
const FormatOptions = @import("std").fmt.FormatOptions;
|
||||||
|
|
@ -88,12 +89,12 @@ pub const KeyEvent = struct {
|
||||||
return self.modifiers & ~mod.caps_lock;
|
return self.modifiers & ~mod.caps_lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) !void {
|
||||||
const mods = self.mods_no_shifts();
|
const mods = self.mods_no_shifts();
|
||||||
return if (self.event > 0)
|
return if (self.event > 0)
|
||||||
writer.print("{}:{}{}", .{ event_fmt(self.event), mod_fmt(mods), key_fmt(self.key) })
|
writer.print("{f}:{f}{f}", .{ event_fmt(self.event), mod_fmt(mods), key_fmt(self.key) })
|
||||||
else
|
else
|
||||||
writer.print("{}{}", .{ mod_fmt(mods), key_fmt(self.key) });
|
writer.print("{f}{f}", .{ mod_fmt(mods), key_fmt(self.key) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_key(keypress: Key) @This() {
|
pub fn from_key(keypress: Key) @This() {
|
||||||
|
|
@ -335,8 +336,8 @@ pub const utils = struct {
|
||||||
|
|
||||||
pub fn key_event_short_fmt(ke: KeyEvent) struct {
|
pub fn key_event_short_fmt(ke: KeyEvent) struct {
|
||||||
ke: KeyEvent,
|
ke: KeyEvent,
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) Io.Writer.Error!void {
|
||||||
return writer.print("{}{}", .{ mod_short_fmt(self.ke.modifiers), key_short_fmt(self.ke.key) });
|
return writer.print("{f}{f}", .{ mod_short_fmt(self.ke.modifiers), key_short_fmt(self.ke.key) });
|
||||||
}
|
}
|
||||||
} {
|
} {
|
||||||
return .{ .ke = ke };
|
return .{ .ke = ke };
|
||||||
|
|
@ -344,7 +345,7 @@ pub fn key_event_short_fmt(ke: KeyEvent) struct {
|
||||||
|
|
||||||
pub fn event_fmt(evt: Event) struct {
|
pub fn event_fmt(evt: Event) struct {
|
||||||
event: Event,
|
event: Event,
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) Io.Writer.Error!void {
|
||||||
return switch (self.event) {
|
return switch (self.event) {
|
||||||
event.press => writer.writeAll("press"),
|
event.press => writer.writeAll("press"),
|
||||||
event.repeat => writer.writeAll("repeat"),
|
event.repeat => writer.writeAll("repeat"),
|
||||||
|
|
@ -358,7 +359,7 @@ pub fn event_fmt(evt: Event) struct {
|
||||||
|
|
||||||
pub fn event_short_fmt(evt: Event) struct {
|
pub fn event_short_fmt(evt: Event) struct {
|
||||||
event: Event,
|
event: Event,
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) Io.Writer.Error!void {
|
||||||
return switch (self.event) {
|
return switch (self.event) {
|
||||||
event.press => writer.writeAll("P"),
|
event.press => writer.writeAll("P"),
|
||||||
event.repeat => writer.writeAll("RP"),
|
event.repeat => writer.writeAll("RP"),
|
||||||
|
|
@ -372,11 +373,11 @@ pub fn event_short_fmt(evt: Event) struct {
|
||||||
|
|
||||||
pub fn key_fmt(key_: Key) struct {
|
pub fn key_fmt(key_: Key) struct {
|
||||||
key: Key,
|
key: Key,
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) Io.Writer.Error!void {
|
||||||
var key_string = utils.key_id_string(self.key);
|
var key_string = utils.key_id_string(self.key);
|
||||||
var buf: [6]u8 = undefined;
|
var buf: [6]u8 = undefined;
|
||||||
if (key_string.len == 0) {
|
if (key_string.len == 0) {
|
||||||
const bytes = try ucs32_to_utf8(&[_]u32{self.key}, &buf);
|
const bytes = ucs32_to_utf8(&[_]u32{self.key}, &buf) catch return error.WriteFailed;
|
||||||
key_string = buf[0..bytes];
|
key_string = buf[0..bytes];
|
||||||
}
|
}
|
||||||
try writer.writeAll(key_string);
|
try writer.writeAll(key_string);
|
||||||
|
|
@ -387,7 +388,7 @@ pub fn key_fmt(key_: Key) struct {
|
||||||
|
|
||||||
pub fn key_short_fmt(key_: Key) struct {
|
pub fn key_short_fmt(key_: Key) struct {
|
||||||
key: Key,
|
key: Key,
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) Io.Writer.Error!void {
|
||||||
var key_string = utils.key_id_string_short(self.key);
|
var key_string = utils.key_id_string_short(self.key);
|
||||||
var buf: [6]u8 = undefined;
|
var buf: [6]u8 = undefined;
|
||||||
if (key_string.len == 0) {
|
if (key_string.len == 0) {
|
||||||
|
|
@ -402,7 +403,7 @@ pub fn key_short_fmt(key_: Key) struct {
|
||||||
|
|
||||||
pub fn mod_fmt(mods: Mods) struct {
|
pub fn mod_fmt(mods: Mods) struct {
|
||||||
modifiers: Mods,
|
modifiers: Mods,
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) Io.Writer.Error!void {
|
||||||
const modset: ModSet = @bitCast(self.modifiers);
|
const modset: ModSet = @bitCast(self.modifiers);
|
||||||
if (modset.super) try writer.writeAll("super+");
|
if (modset.super) try writer.writeAll("super+");
|
||||||
if (modset.ctrl) try writer.writeAll("ctrl+");
|
if (modset.ctrl) try writer.writeAll("ctrl+");
|
||||||
|
|
@ -415,7 +416,7 @@ pub fn mod_fmt(mods: Mods) struct {
|
||||||
|
|
||||||
pub fn mod_short_fmt(mods: Mods) struct {
|
pub fn mod_short_fmt(mods: Mods) struct {
|
||||||
modifiers: Mods,
|
modifiers: Mods,
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), writer: anytype) Io.Writer.Error!void {
|
||||||
const modset: ModSet = @bitCast(self.modifiers);
|
const modset: ModSet = @bitCast(self.modifiers);
|
||||||
if (modset.super) try writer.writeAll("Super-");
|
if (modset.super) try writer.writeAll("Super-");
|
||||||
if (modset.ctrl) try writer.writeAll("C-");
|
if (modset.ctrl) try writer.writeAll("C-");
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,16 @@ allocator: std.mem.Allocator,
|
||||||
|
|
||||||
tty: vaxis.Tty,
|
tty: vaxis.Tty,
|
||||||
vx: vaxis.Vaxis,
|
vx: vaxis.Vaxis,
|
||||||
|
tty_buffer: []u8,
|
||||||
|
|
||||||
no_alternate: bool,
|
no_alternate: bool,
|
||||||
event_buffer: std.ArrayList(u8),
|
event_buffer: std.Io.Writer.Allocating,
|
||||||
input_buffer: std.ArrayList(u8),
|
input_buffer: std.Io.Writer.Allocating,
|
||||||
mods: vaxis.Key.Modifiers = .{},
|
mods: vaxis.Key.Modifiers = .{},
|
||||||
queries_done: bool,
|
queries_done: bool,
|
||||||
|
|
||||||
bracketed_paste: bool = false,
|
bracketed_paste: bool = false,
|
||||||
bracketed_paste_buffer: std.ArrayList(u8),
|
bracketed_paste_buffer: std.Io.Writer.Allocating,
|
||||||
|
|
||||||
handler_ctx: *anyopaque,
|
handler_ctx: *anyopaque,
|
||||||
dispatch_input: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,
|
dispatch_input: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,
|
||||||
|
|
@ -61,6 +62,7 @@ pub const Error = error{
|
||||||
BadArrayAllocExtract,
|
BadArrayAllocExtract,
|
||||||
InvalidMapType,
|
InvalidMapType,
|
||||||
InvalidUnion,
|
InvalidUnion,
|
||||||
|
WriteFailed,
|
||||||
} || std.Thread.SpawnError;
|
} || std.Thread.SpawnError;
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool, _: *const fn (ctx: *anyopaque) void) Error!Self {
|
pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool, _: *const fn (ctx: *anyopaque) void) Error!Self {
|
||||||
|
|
@ -74,13 +76,15 @@ pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate:
|
||||||
},
|
},
|
||||||
.system_clipboard_allocator = allocator,
|
.system_clipboard_allocator = allocator,
|
||||||
};
|
};
|
||||||
|
const tty_buffer = try allocator.alloc(u8, 4096);
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.tty = vaxis.Tty.init() catch return error.TtyInitError,
|
.tty = vaxis.Tty.init(tty_buffer) catch return error.TtyInitError,
|
||||||
|
.tty_buffer = tty_buffer,
|
||||||
.vx = try vaxis.init(allocator, opts),
|
.vx = try vaxis.init(allocator, opts),
|
||||||
.no_alternate = no_alternate,
|
.no_alternate = no_alternate,
|
||||||
.event_buffer = std.ArrayList(u8).init(allocator),
|
.event_buffer = .init(allocator),
|
||||||
.input_buffer = std.ArrayList(u8).init(allocator),
|
.input_buffer = .init(allocator),
|
||||||
.bracketed_paste_buffer = std.ArrayList(u8).init(allocator),
|
.bracketed_paste_buffer = std.ArrayList(u8).init(allocator),
|
||||||
.handler_ctx = handler_ctx,
|
.handler_ctx = handler_ctx,
|
||||||
.logger = log.logger(log_name),
|
.logger = log.logger(log_name),
|
||||||
|
|
@ -94,6 +98,7 @@ pub fn deinit(self: *Self) void {
|
||||||
self.loop.stop();
|
self.loop.stop();
|
||||||
self.vx.deinit(self.allocator, self.tty.anyWriter());
|
self.vx.deinit(self.allocator, self.tty.anyWriter());
|
||||||
self.tty.deinit();
|
self.tty.deinit();
|
||||||
|
self.allocator.free(self.tty_buffer);
|
||||||
self.bracketed_paste_buffer.deinit();
|
self.bracketed_paste_buffer.deinit();
|
||||||
self.input_buffer.deinit();
|
self.input_buffer.deinit();
|
||||||
self.event_buffer.deinit();
|
self.event_buffer.deinit();
|
||||||
|
|
@ -204,9 +209,8 @@ pub fn run(self: *Self) Error!void {
|
||||||
|
|
||||||
pub fn render(self: *Self) !void {
|
pub fn render(self: *Self) !void {
|
||||||
if (in_panic.load(.acquire)) return;
|
if (in_panic.load(.acquire)) return;
|
||||||
var bufferedWriter = self.tty.bufferedWriter();
|
try self.vx.render(&self.tty.writer.interface);
|
||||||
try self.vx.render(bufferedWriter.writer().any());
|
try self.tty.writer.interface.flush();
|
||||||
try bufferedWriter.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sigwinch(self: *Self) !void {
|
pub fn sigwinch(self: *Self) !void {
|
||||||
|
|
@ -214,7 +218,7 @@ pub fn sigwinch(self: *Self) !void {
|
||||||
try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking()));
|
try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize(self: *Self, ws: vaxis.Winsize) error{ TtyWriteError, OutOfMemory }!void {
|
fn resize(self: *Self, ws: vaxis.Winsize) error{ TtyWriteError, OutOfMemory, WriteFailed }!void {
|
||||||
self.vx.resize(self.allocator, self.tty.anyWriter(), ws) catch return error.TtyWriteError;
|
self.vx.resize(self.allocator, self.tty.anyWriter(), ws) catch return error.TtyWriteError;
|
||||||
self.vx.queueRefresh();
|
self.vx.queueRefresh();
|
||||||
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"resize"}));
|
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"resize"}));
|
||||||
|
|
@ -394,25 +398,26 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmtmsg(self: *Self, value: anytype) std.ArrayList(u8).Writer.Error![]const u8 {
|
fn fmtmsg(self: *Self, value: anytype) std.Io.Writer.Error![]const u8 {
|
||||||
self.event_buffer.clearRetainingCapacity();
|
self.event_buffer.clearRetainingCapacity();
|
||||||
try cbor.writeValue(self.event_buffer.writer(), value);
|
try cbor.writeValue(&self.event_buffer.writer, value);
|
||||||
return self.event_buffer.items;
|
return self.event_buffer.written();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_bracketed_paste_input(self: *Self, cbor_msg: []const u8) !bool {
|
fn handle_bracketed_paste_input(self: *Self, cbor_msg: []const u8) !bool {
|
||||||
var keypress: input.Key = undefined;
|
var keypress: input.Key = undefined;
|
||||||
var egc_: input.Key = undefined;
|
var egc_: input.Key = undefined;
|
||||||
var mods: usize = undefined;
|
var mods: usize = undefined;
|
||||||
|
const writer = &self.bracketed_paste_buffer.writer;
|
||||||
if (try cbor.match(cbor_msg, .{ "I", cbor.number, cbor.extract(&keypress), cbor.extract(&egc_), cbor.string, cbor.extract(&mods) })) {
|
if (try cbor.match(cbor_msg, .{ "I", cbor.number, cbor.extract(&keypress), cbor.extract(&egc_), cbor.string, cbor.extract(&mods) })) {
|
||||||
switch (keypress) {
|
switch (keypress) {
|
||||||
106 => if (mods == 4) try self.bracketed_paste_buffer.appendSlice("\n") else try self.bracketed_paste_buffer.appendSlice("j"),
|
106 => if (mods == 4) try writer.writeAll("\n") else try writer.writeAll("j"),
|
||||||
input.key.enter => try self.bracketed_paste_buffer.appendSlice("\n"),
|
input.key.enter => try writer.writeAll("\n"),
|
||||||
input.key.tab => try self.bracketed_paste_buffer.appendSlice("\t"),
|
input.key.tab => try writer.writeAll("\t"),
|
||||||
else => if (!input.is_non_input_key(keypress)) {
|
else => if (!input.is_non_input_key(keypress)) {
|
||||||
var buf: [6]u8 = undefined;
|
var buf: [6]u8 = undefined;
|
||||||
const bytes = try input.ucs32_to_utf8(&[_]u32{egc_}, &buf);
|
const bytes = try input.ucs32_to_utf8(&[_]u32{egc_}, &buf);
|
||||||
try self.bracketed_paste_buffer.appendSlice(buf[0..bytes]);
|
try writer.writeAll(buf[0..bytes]);
|
||||||
} else {
|
} else {
|
||||||
var buf: [6]u8 = undefined;
|
var buf: [6]u8 = undefined;
|
||||||
const bytes = try input.ucs32_to_utf8(&[_]u32{egc_}, &buf);
|
const bytes = try input.ucs32_to_utf8(&[_]u32{egc_}, &buf);
|
||||||
|
|
@ -431,16 +436,16 @@ fn handle_bracketed_paste_start(self: *Self) !void {
|
||||||
|
|
||||||
fn handle_bracketed_paste_end(self: *Self) !void {
|
fn handle_bracketed_paste_end(self: *Self) !void {
|
||||||
defer {
|
defer {
|
||||||
self.bracketed_paste_buffer.clearAndFree();
|
self.bracketed_paste_buffer.clearRetainingCapacity();
|
||||||
self.bracketed_paste = false;
|
self.bracketed_paste = false;
|
||||||
}
|
}
|
||||||
if (!self.bracketed_paste) return;
|
if (!self.bracketed_paste) return;
|
||||||
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", self.bracketed_paste_buffer.items }));
|
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", self.bracketed_paste_buffer.written() }));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_bracketed_paste_error(self: *Self, e: Error) !void {
|
fn handle_bracketed_paste_error(self: *Self, e: Error) !void {
|
||||||
self.logger.err("bracketed paste", e);
|
self.logger.err("bracketed paste", e);
|
||||||
self.bracketed_paste_buffer.clearAndFree();
|
self.bracketed_paste_buffer.clearRetainingCapacity();
|
||||||
self.bracketed_paste = false;
|
self.bracketed_paste = false;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue