refactor: rework error handling to simplifiy command implementation and provide better back traces

This commit is contained in:
CJ van den Berg 2024-06-26 23:29:39 +02:00
parent 21b604f4d6
commit 032982c1e8
26 changed files with 821 additions and 785 deletions

View file

@ -16,8 +16,8 @@
.hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362", .hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362",
}, },
.thespian = .{ .thespian = .{
.url = "https://github.com/neurocyte/thespian/archive/3ace3163087a0260b30e2c420de76235dd82451f.tar.gz", .url = "https://github.com/neurocyte/thespian/archive/f1a89bdf9d9fac2cd7d6c1479e5bc99c8dd4c904.tar.gz",
.hash = "1220ffbfff37c24b68424a3c9223cf57daed5debdbb6b7751a36b9dca318825cff4c", .hash = "1220f1f69aaad041ca96e5a06fb14ff510c3775d809a37a83b8651e7f0f71be8deaf",
}, },
.themes = .{ .themes = .{
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-15e8cad1619429bf2547a6819b5b999510d5c1e5/flow-themes.tar.gz", .url = "https://github.com/neurocyte/flow-themes/releases/download/master-15e8cad1619429bf2547a6819b5b999510d5c1e5/flow-themes.tar.gz",

View file

@ -11,9 +11,8 @@ const Self = @This();
const module_name = @typeName(Self); const module_name = @typeName(Self);
const sp_tag = "child"; const sp_tag = "child";
const debug_lsp = true; const debug_lsp = true;
pub const Error = error{ OutOfMemory, Exit };
pub fn open(a: std.mem.Allocator, project: []const u8, cmd: tp.message) Error!Self { pub fn open(a: std.mem.Allocator, project: []const u8, cmd: tp.message) !Self {
return .{ .a = a, .pid = try Process.create(a, project, cmd) }; return .{ .a = a, .pid = try Process.create(a, project, cmd) };
} }
@ -27,23 +26,23 @@ pub fn term(self: *Self) void {
self.pid.deinit(); self.pid.deinit();
} }
pub fn send_request(self: Self, a: std.mem.Allocator, method: []const u8, m: anytype) error{Exit}!tp.message { pub fn send_request(self: Self, a: std.mem.Allocator, method: []const u8, m: anytype) !tp.message {
// const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".send_request" }); // const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".send_request" });
// defer frame.deinit(); // defer frame.deinit();
var cb = std.ArrayList(u8).init(self.a); var cb = std.ArrayList(u8).init(self.a);
defer cb.deinit(); defer cb.deinit();
cbor.writeValue(cb.writer(), m) catch |e| return tp.exit_error(e); try cbor.writeValue(cb.writer(), m);
return self.pid.call(a, std.time.ns_per_s / 2, .{ "REQ", method, cb.items }) catch |e| return tp.exit_error(e); return self.pid.call(a, std.time.ns_per_s / 2, .{ "REQ", method, cb.items });
} }
pub fn send_notification(self: Self, method: []const u8, m: anytype) tp.result { pub fn send_notification(self: Self, method: []const u8, m: anytype) !void {
var cb = std.ArrayList(u8).init(self.a); var cb = std.ArrayList(u8).init(self.a);
defer cb.deinit(); defer cb.deinit();
cbor.writeValue(cb.writer(), m) catch |e| return tp.exit_error(e); try cbor.writeValue(cb.writer(), m);
return self.send_notification_raw(method, cb.items); return self.send_notification_raw(method, cb.items);
} }
pub fn send_notification_raw(self: Self, method: []const u8, cb: []const u8) tp.result { pub fn send_notification_raw(self: Self, method: []const u8, cb: []const u8) !void {
return self.pid.send(.{ "NTFY", method, cb }); return self.pid.send(.{ "NTFY", method, cb });
} }
@ -67,7 +66,7 @@ const Process = struct {
const Receiver = tp.Receiver(*Process); const Receiver = tp.Receiver(*Process);
pub fn create(a: std.mem.Allocator, project: []const u8, cmd: tp.message) Error!tp.pid { pub fn create(a: std.mem.Allocator, project: []const u8, cmd: tp.message) !tp.pid {
var tag: []const u8 = undefined; var tag: []const u8 = undefined;
if (try cmd.match(.{tp.extract(&tag)})) { if (try cmd.match(.{tp.extract(&tag)})) {
// //
@ -92,7 +91,7 @@ const Process = struct {
.requests = std.AutoHashMap(i32, tp.pid).init(a), .requests = std.AutoHashMap(i32, tp.pid).init(a),
.sp_tag = try sp_tag_.toOwnedSliceSentinel(0), .sp_tag = try sp_tag_.toOwnedSliceSentinel(0),
}; };
return tp.spawn_link(self.a, self, Process.start, self.tag) catch |e| tp.exit_error(e); return tp.spawn_link(self.a, self, Process.start, self.tag);
} }
fn deinit(self: *Process) void { fn deinit(self: *Process) void {
@ -126,17 +125,21 @@ const Process = struct {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ " start" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ " start" });
defer frame.deinit(); defer frame.deinit();
_ = tp.set_trap(true); _ = tp.set_trap(true);
self.sp = tp.subprocess.init(self.a, self.cmd, self.sp_tag, .Pipe) catch |e| return tp.exit_error(e); self.sp = tp.subprocess.init(self.a, 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.a); var log_file_path = std.ArrayList(u8).init(self.a);
defer log_file_path.deinit(); defer log_file_path.deinit();
const state_dir = root.get_state_dir() catch |e| return tp.exit_error(e); const state_dir = root.get_state_dir() catch |e| return tp.exit_error(e, @errorReturnTrace());
log_file_path.writer().print("{s}/lsp-{s}.log", .{ state_dir, self.tag }) catch |e| return tp.exit_error(e); log_file_path.writer().print("{s}/lsp-{s}.log", .{ state_dir, 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); self.log_file = std.fs.createFileAbsolute(log_file_path.items, .{ .truncate = true }) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result { fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
return self.receive_safe(from, m) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name }); const frame = tracy.initZone(@src(), .{ .name = module_name });
defer frame.deinit(); defer frame.deinit();
errdefer self.deinit(); errdefer self.deinit();
@ -146,9 +149,9 @@ const Process = struct {
var code: u32 = 0; var code: u32 = 0;
if (try m.match(.{ "REQ", tp.extract(&method), tp.extract(&bytes) })) { if (try m.match(.{ "REQ", tp.extract(&method), tp.extract(&bytes) })) {
self.send_request(from, method, bytes) catch |e| return tp.exit_error(e); try self.send_request(from, method, bytes);
} else if (try m.match(.{ "NTFY", tp.extract(&method), tp.extract(&bytes) })) { } else if (try m.match(.{ "NTFY", tp.extract(&method), tp.extract(&bytes) })) {
self.send_notification(method, bytes) catch |e| return tp.exit_error(e); try self.send_notification(method, bytes);
} else if (try m.match(.{"close"})) { } else if (try m.match(.{"close"})) {
self.write_log("### LSP close ###\n", .{}); self.write_log("### LSP close ###\n", .{});
try self.close(); try self.close();
@ -156,9 +159,9 @@ const Process = struct {
self.write_log("### LSP terminated ###\n", .{}); self.write_log("### LSP terminated ###\n", .{});
try self.term(); try self.term();
} else if (try m.match(.{ self.sp_tag, "stdout", tp.extract(&bytes) })) { } else if (try m.match(.{ self.sp_tag, "stdout", tp.extract(&bytes) })) {
self.handle_output(bytes) catch |e| return tp.exit_error(e); try self.handle_output(bytes);
} else if (try m.match(.{ self.sp_tag, "term", tp.extract(&err), tp.extract(&code) })) { } else if (try m.match(.{ self.sp_tag, "term", tp.extract(&err), tp.extract(&code) })) {
self.handle_terminated(err, code) catch |e| return tp.exit_error(e); try self.handle_terminated(err, code);
} else if (try m.match(.{ self.sp_tag, "stderr", tp.extract(&bytes) })) { } else if (try m.match(.{ self.sp_tag, "stderr", tp.extract(&bytes) })) {
self.write_log("{s}\n", .{bytes}); self.write_log("{s}\n", .{bytes});
} else if (try m.match(.{ "exit", "normal" })) { } else if (try m.match(.{ "exit", "normal" })) {

View file

@ -132,7 +132,7 @@ pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) error{ Ou
} }
} }
fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) error{ OutOfMemory, Exit }!usize { fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) error{Exit}!usize {
var i: usize = 0; var i: usize = 0;
defer from.send(.{ "PRJ", "recent_done", query }) catch {}; defer from.send(.{ "PRJ", "recent_done", query }) catch {};
for (self.files.items) |file| { for (self.files.items) |file| {
@ -155,12 +155,15 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []co
return self.simple_query_recent_files(from, max, query); return self.simple_query_recent_files(from, max, query);
defer from.send(.{ "PRJ", "recent_done", query }) catch {}; defer from.send(.{ "PRJ", "recent_done", query }) catch {};
var searcher = try fuzzig.Ascii.init( var searcher = fuzzig.Ascii.init(
self.a, self.a,
std.fs.max_path_bytes, // haystack max size std.fs.max_path_bytes, // haystack max size
std.fs.max_path_bytes, // needle max size std.fs.max_path_bytes, // needle max size
.{ .case_sensitive = false }, .{ .case_sensitive = false },
); ) catch |e| switch (e) {
error.OutOfMemory => @panic("OOM in fussiz.Ascii.init"),
else => |e_| return e_,
};
defer searcher.deinit(); defer searcher.deinit();
const Match = struct { const Match = struct {
@ -251,14 +254,14 @@ pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) !v
} }
} }
pub fn did_open(self: *Self, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) tp.result { pub fn did_open(self: *Self, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) !void {
self.update_mru(file_path, 0, 0) catch {}; self.update_mru(file_path, 0, 0) catch {};
const lsp = self.get_lsp(language_server) catch |e| return tp.exit_error(e); const lsp = try self.get_lsp(language_server);
if (!self.file_language_server.contains(file_path)) { if (!self.file_language_server.contains(file_path)) {
const key = self.a.dupe(u8, file_path) catch |e| return tp.exit_error(e); const key = try self.a.dupe(u8, file_path);
self.file_language_server.put(key, lsp) catch |e| return tp.exit_error(e); try self.file_language_server.put(key, lsp);
} }
const uri = self.make_URI(file_path) catch |e| return tp.exit_error(e); const uri = try self.make_URI(file_path);
defer self.a.free(uri); defer self.a.free(uri);
try lsp.send_notification("textDocument/didOpen", .{ try lsp.send_notification("textDocument/didOpen", .{
.textDocument = .{ .uri = uri, .languageId = file_type, .version = version, .text = text }, .textDocument = .{ .uri = uri, .languageId = file_type, .version = version, .text = text },
@ -267,7 +270,7 @@ pub fn did_open(self: *Self, file_path: []const u8, file_type: []const u8, langu
pub fn did_change(self: *Self, file_path: []const u8, version: usize, root_dst_addr: usize, root_src_addr: usize) !void { pub fn did_change(self: *Self, file_path: []const u8, version: usize, root_dst_addr: usize, root_src_addr: usize) !void {
const lsp = try self.get_file_lsp(file_path); const lsp = try self.get_file_lsp(file_path);
const uri = self.make_URI(file_path) catch |e| return tp.exit_error(e); const uri = try self.make_URI(file_path);
defer self.a.free(uri); defer self.a.free(uri);
const root_dst: Buffer.Root = if (root_dst_addr == 0) return else @ptrFromInt(root_dst_addr); const root_dst: Buffer.Root = if (root_dst_addr == 0) return else @ptrFromInt(root_dst_addr);
@ -359,18 +362,18 @@ fn scan_char(chars: []const u8, lines: *usize, char: u8, last_offset: ?*usize) v
} }
} }
pub fn did_save(self: *Self, file_path: []const u8) tp.result { pub fn did_save(self: *Self, file_path: []const u8) !void {
const lsp = try self.get_file_lsp(file_path); const lsp = try self.get_file_lsp(file_path);
const uri = self.make_URI(file_path) catch |e| return tp.exit_error(e); const uri = try self.make_URI(file_path);
defer self.a.free(uri); defer self.a.free(uri);
try lsp.send_notification("textDocument/didSave", .{ try lsp.send_notification("textDocument/didSave", .{
.textDocument = .{ .uri = uri }, .textDocument = .{ .uri = uri },
}); });
} }
pub fn did_close(self: *Self, file_path: []const u8) tp.result { pub fn did_close(self: *Self, file_path: []const u8) !void {
const lsp = try self.get_file_lsp(file_path); const lsp = try self.get_file_lsp(file_path);
const uri = self.make_URI(file_path) catch |e| return tp.exit_error(e); const uri = try self.make_URI(file_path);
defer self.a.free(uri); defer self.a.free(uri);
try lsp.send_notification("textDocument/didClose", .{ try lsp.send_notification("textDocument/didClose", .{
.textDocument = .{ .uri = uri }, .textDocument = .{ .uri = uri },
@ -379,7 +382,7 @@ pub fn did_close(self: *Self, file_path: []const u8) tp.result {
pub fn goto_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void { pub fn goto_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
const lsp = try self.get_file_lsp(file_path); const lsp = try self.get_file_lsp(file_path);
const uri = self.make_URI(file_path) catch |e| return tp.exit_error(e); const uri = try self.make_URI(file_path);
defer self.a.free(uri); defer self.a.free(uri);
const response = try lsp.send_request(self.a, "textDocument/definition", .{ const response = try lsp.send_request(self.a, "textDocument/definition", .{
.textDocument = .{ .uri = uri }, .textDocument = .{ .uri = uri },
@ -454,7 +457,7 @@ fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const
pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void { pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void {
const lsp = try self.get_file_lsp(file_path); const lsp = try self.get_file_lsp(file_path);
const uri = self.make_URI(file_path) catch |e| return tp.exit_error(e); const uri = try self.make_URI(file_path);
defer self.a.free(uri); defer self.a.free(uri);
const response = try lsp.send_request(self.a, "textDocument/completion", .{ const response = try lsp.send_request(self.a, "textDocument/completion", .{
.textDocument = .{ .uri = uri }, .textDocument = .{ .uri = uri },
@ -613,7 +616,7 @@ pub fn show_message(_: *Self, _: tp.pid_ref, params_cb: []const u8) !void {
logger.print("{s}", .{msg}); logger.print("{s}", .{msg});
} }
fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8) error{Exit}!tp.message { fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8) !tp.message {
return lsp.send_request(self.a, "initialize", .{ return lsp.send_request(self.a, "initialize", .{
.processId = if (builtin.os.tag == .linux) std.os.linux.getpid() else null, .processId = if (builtin.os.tag == .linux) std.os.linux.getpid() else null,
.rootPath = project_path, .rootPath = project_path,

View file

@ -7,7 +7,6 @@ const cbor = @import("cbor");
const Self = @This(); const Self = @This();
const module_name = @typeName(Self); const module_name = @typeName(Self);
pub const Error = error{ OutOfMemory, Exit };
pub const Kind = enum { insert, delete }; pub const Kind = enum { insert, delete };
pub const Edit = struct { pub const Edit = struct {
@ -19,7 +18,7 @@ pub const Edit = struct {
pid: ?tp.pid, pid: ?tp.pid,
pub fn create() Error!Self { pub fn create() !Self {
return .{ .pid = try Process.create() }; return .{ .pid = try Process.create() };
} }
@ -39,14 +38,14 @@ const Process = struct {
const Receiver = tp.Receiver(*Process); const Receiver = tp.Receiver(*Process);
const outer_a = std.heap.page_allocator; const outer_a = std.heap.page_allocator;
pub fn create() Error!tp.pid { pub fn create() !tp.pid {
const self = try outer_a.create(Process); const self = try outer_a.create(Process);
self.* = .{ self.* = .{
.arena = std.heap.ArenaAllocator.init(outer_a), .arena = std.heap.ArenaAllocator.init(outer_a),
.a = self.arena.allocator(), .a = self.arena.allocator(),
.receiver = Receiver.init(Process.receive, self), .receiver = Receiver.init(Process.receive, self),
}; };
return tp.spawn_link(self.a, self, Process.start, module_name) catch |e| tp.exit_error(e); return tp.spawn_link(self.a, self, Process.start, module_name);
} }
fn start(self: *Process) tp.result { fn start(self: *Process) tp.result {
@ -67,7 +66,7 @@ const Process = struct {
var root_src: usize = 0; var root_src: usize = 0;
return if (try m.match(.{ "D", tp.extract(&cb), tp.extract(&root_dst), tp.extract(&root_src) })) return if (try m.match(.{ "D", tp.extract(&cb), tp.extract(&root_dst), tp.extract(&root_src) }))
self.diff(from, cb, root_dst, root_src) catch |e| tp.exit_error(e) self.diff(from, cb, root_dst, root_src) catch |e| tp.exit_error(e, @errorReturnTrace())
else if (try m.match(.{"shutdown"})) else if (try m.match(.{"shutdown"}))
tp.exit_normal(); tp.exit_normal();
} }

View file

@ -3,7 +3,6 @@ const tp = @import("thespian");
const Self = @This(); const Self = @This();
const module_name = @typeName(Self); const module_name = @typeName(Self);
pub const Error = error{ OutOfMemory, Exit };
pid: ?tp.pid, pid: ?tp.pid,
@ -17,7 +16,7 @@ pub const Selection = struct {
end: Cursor = Cursor{}, end: Cursor = Cursor{},
}; };
pub fn create() Error!Self { pub fn create() !Self {
return .{ .pid = try Process.create() }; return .{ .pid = try Process.create() };
} }
@ -46,7 +45,7 @@ const Process = struct {
selection: ?Selection = null, selection: ?Selection = null,
}; };
pub fn create() Error!tp.pid { pub fn create() !tp.pid {
const self = try outer_a.create(Process); const self = try outer_a.create(Process);
self.* = .{ self.* = .{
.arena = std.heap.ArenaAllocator.init(outer_a), .arena = std.heap.ArenaAllocator.init(outer_a),
@ -55,7 +54,7 @@ const Process = struct {
.forwards = std.ArrayList(Entry).init(self.a), .forwards = std.ArrayList(Entry).init(self.a),
.receiver = Receiver.init(Process.receive, self), .receiver = Receiver.init(Process.receive, self),
}; };
return tp.spawn_link(self.a, self, Process.start, module_name) catch |e| tp.exit_error(e); return tp.spawn_link(self.a, self, Process.start, module_name);
} }
fn start(self: *Process) tp.result { fn start(self: *Process) tp.result {
@ -87,6 +86,10 @@ const Process = struct {
} }
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result { fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
self.receive_safe(from, m) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) !void {
errdefer self.deinit(); errdefer self.deinit();
var c: Cursor = .{}; var c: Cursor = .{};
@ -106,9 +109,9 @@ const Process = struct {
tp.exit_normal(); tp.exit_normal();
} }
fn update(self: *Process, entry_: Entry) tp.result { fn update(self: *Process, entry_: Entry) !void {
const entry: Entry = .{ const entry: Entry = .{
.file_path = self.a.dupe(u8, entry_.file_path) catch |e| return tp.exit_error(e), .file_path = try self.a.dupe(u8, entry_.file_path),
.cursor = entry_.cursor, .cursor = entry_.cursor,
.selection = entry_.selection, .selection = entry_.selection,
}; };
@ -129,7 +132,7 @@ const Process = struct {
self.a.free(top.file_path); self.a.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| {
self.backwards.append(current) catch |e| return tp.exit_error(e); try self.backwards.append(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();
} }

View file

@ -28,7 +28,7 @@ pub fn spawn(ctx: *tp.context, a: std.mem.Allocator, env: ?*const tp.env) !tp.pi
fn start(args: StartArgs) tp.result { fn start(args: StartArgs) tp.result {
_ = tp.set_trap(true); _ = tp.set_trap(true);
var this = Self.init(args) catch |e| return tp.exit_error(e); var this = Self.init(args) catch |e| return tp.exit_error(e, @errorReturnTrace());
errdefer this.deinit(); errdefer this.deinit();
tp.receive(&this.receiver); tp.receive(&this.receiver);
} }
@ -135,15 +135,27 @@ pub const Logger = struct {
error.Exit => { error.Exit => {
const msg_: tp.message = .{ .buf = tp.error_message() }; const msg_: tp.message = .{ .buf = tp.error_message() };
var msg__: []const u8 = undefined; var msg__: []const u8 = undefined;
if (!(msg_.match(.{ "exit", tp.extract(&msg__) }) catch false)) var trace__: []const u8 = "";
if (msg_.match(.{ "exit", tp.extract(&msg__) }) catch false) {
//
} else if (msg_.match(.{ "exit", tp.extract(&msg__), tp.extract(&trace__) }) catch false) {
//
} else {
msg__ = msg_.buf; msg__ = msg_.buf;
}
if (msg__.len > buf.len) { if (msg__.len > buf.len) {
self.proc.send(.{ "log", "error", self.tag, context, "->", "MESSAGE TOO LARGE" }) catch {}; self.proc.send(.{ "log", "error", self.tag, context, "->", "MESSAGE TOO LARGE" }) catch {};
return; return;
} }
const msg___ = buf[0..msg__.len]; const msg___ = buf[0..msg__.len];
@memcpy(msg___, msg__); @memcpy(msg___, msg__);
msg = msg___; if (buf.len - msg___.len > trace__.len) {
const msg____ = buf[0 .. msg__.len + trace__.len];
@memcpy(msg____[msg__.len..], trace__);
msg = msg____;
} else {
msg = msg___;
}
}, },
else => { else => {
msg = @errorName(e); msg = @errorName(e);

View file

@ -13,13 +13,13 @@ pid: tp.pid_ref,
const Self = @This(); const Self = @This();
const module_name = @typeName(Self); const module_name = @typeName(Self);
pub fn get() error{Exit}!Self { pub fn get() !Self {
const pid = tp.env.get().proc(module_name); const pid = tp.env.get().proc(module_name);
return if (pid.expired()) create() else .{ .pid = pid }; return if (pid.expired()) create() else .{ .pid = pid };
} }
fn create() error{Exit}!Self { fn create() !Self {
const pid = Process.create() catch |e| return tp.exit_error(e); const pid = try Process.create();
defer pid.deinit(); defer pid.deinit();
tp.env.get().proc_set(module_name, pid.ref()); tp.env.get().proc_set(module_name, pid.ref());
return .{ .pid = tp.env.get().proc(module_name) }; return .{ .pid = tp.env.get().proc(module_name) };
@ -34,35 +34,35 @@ pub fn shutdown() void {
pid.send(.{"shutdown"}) catch {}; pid.send(.{"shutdown"}) catch {};
} }
pub fn open_cwd() tp.result { pub fn open_cwd() !void {
return open("."); return open(".");
} }
pub fn open(rel_project_directory: []const u8) tp.result { pub fn open(rel_project_directory: []const u8) !void {
var path_buf: [std.fs.max_path_bytes]u8 = undefined; var path_buf: [std.fs.max_path_bytes]u8 = undefined;
const project_directory = std.fs.cwd().realpath(rel_project_directory, &path_buf) catch "(none)"; const project_directory = std.fs.cwd().realpath(rel_project_directory, &path_buf) catch "(none)";
var dir = std.fs.openDirAbsolute(project_directory, .{}) catch |e| return tp.exit_error(e); var dir = try std.fs.openDirAbsolute(project_directory, .{});
dir.setAsCwd() catch |e| return tp.exit_error(e); try dir.setAsCwd();
dir.close(); dir.close();
tp.env.get().str_set("project", project_directory); tp.env.get().str_set("project", project_directory);
return (try get()).pid.send(.{ "open", project_directory }); return (try get()).pid.send(.{ "open", project_directory });
} }
pub fn request_recent_files(max: usize) tp.result { pub fn request_recent_files(max: usize) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "request_recent_files", project, max }); return (try get()).pid.send(.{ "request_recent_files", project, max });
} }
pub fn query_recent_files(max: usize, query: []const u8) tp.result { pub fn query_recent_files(max: usize, query: []const u8) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "query_recent_files", project, max, query }); return (try get()).pid.send(.{ "query_recent_files", project, max, query });
} }
pub fn did_open(file_path: []const u8, file_type: *const FileType, version: usize, text: []const u8) tp.result { pub fn did_open(file_path: []const u8, file_type: *const FileType, version: usize, text: []const u8) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
@ -70,49 +70,49 @@ pub fn did_open(file_path: []const u8, file_type: *const FileType, version: usiz
return (try get()).pid.send(.{ "did_open", project, file_path, file_type.name, file_type.language_server, version, text_ptr, text.len }); return (try get()).pid.send(.{ "did_open", project, file_path, file_type.name, file_type.language_server, version, text_ptr, text.len });
} }
pub fn did_change(file_path: []const u8, version: usize, root_dst: usize, root_src: usize) tp.result { pub fn did_change(file_path: []const u8, version: usize, root_dst: usize, root_src: usize) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "did_change", project, file_path, version, root_dst, root_src }); return (try get()).pid.send(.{ "did_change", project, file_path, version, root_dst, root_src });
} }
pub fn did_save(file_path: []const u8) tp.result { pub fn did_save(file_path: []const u8) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "did_save", project, file_path }); return (try get()).pid.send(.{ "did_save", project, file_path });
} }
pub fn did_close(file_path: []const u8) tp.result { pub fn did_close(file_path: []const u8) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "did_close", project, file_path }); return (try get()).pid.send(.{ "did_close", project, file_path });
} }
pub fn goto_definition(file_path: []const u8, row: usize, col: usize) tp.result { pub fn goto_definition(file_path: []const u8, row: usize, col: usize) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "goto_definition", project, file_path, row, col }); return (try get()).pid.send(.{ "goto_definition", project, file_path, row, col });
} }
pub fn completion(file_path: []const u8, row: usize, col: usize) tp.result { pub fn completion(file_path: []const u8, row: usize, col: usize) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "completion", project, file_path, row, col }); return (try get()).pid.send(.{ "completion", project, file_path, row, col });
} }
pub fn update_mru(file_path: []const u8, row: usize, col: usize) tp.result { pub fn update_mru(file_path: []const u8, row: usize, col: usize) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
return (try get()).pid.send(.{ "update_mru", project, file_path, row, col }); return (try get()).pid.send(.{ "update_mru", project, file_path, row, col });
} }
pub fn get_mru_position(file_path: []const u8) tp.result { pub fn get_mru_position(file_path: []const u8) !void {
const project = tp.env.get().str("project"); const project = tp.env.get().str("project");
if (project.len == 0) if (project.len == 0)
return tp.exit("No project"); return tp.exit("No project");
@ -140,7 +140,7 @@ const Process = struct {
.receiver = Receiver.init(Process.receive, self), .receiver = Receiver.init(Process.receive, self),
.projects = ProjectsMap.init(a), .projects = ProjectsMap.init(a),
}; };
return tp.spawn_link(self.a, self, Process.start, module_name) catch |e| tp.exit_error(e); return tp.spawn_link(self.a, self, Process.start, module_name);
} }
fn deinit(self: *Process) void { fn deinit(self: *Process) void {
@ -166,11 +166,11 @@ const Process = struct {
self.receive_safe(from, m) catch |e| { self.receive_safe(from, m) catch |e| {
if (std.mem.eql(u8, "normal", tp.error_text())) if (std.mem.eql(u8, "normal", tp.error_text()))
return e; return e;
self.logger.err("receive", e); self.logger.err("receive", tp.exit_error(e, @errorReturnTrace()));
}; };
} }
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) tp.result { fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) !void {
var project_directory: []const u8 = undefined; var project_directory: []const u8 = undefined;
var path: []const u8 = undefined; var path: []const u8 = undefined;
var query: []const u8 = undefined; var query: []const u8 = undefined;
@ -201,9 +201,9 @@ const Process = struct {
} else if (try m.match(.{ "walk_tree_done", tp.extract(&project_directory) })) { } else if (try m.match(.{ "walk_tree_done", tp.extract(&project_directory) })) {
if (self.walker) |pid| pid.deinit(); if (self.walker) |pid| pid.deinit();
self.walker = null; self.walker = null;
self.loaded(project_directory) catch |e| return from.forward_error(e); self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) { } else if (try m.match(.{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e); self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(&params_cb) })) { } else if (try m.match(.{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(&params_cb) })) {
self.dispatch_notify(project_directory, language_server, method, params_cb) catch |e| return self.logger.err("lsp-handling", e); self.dispatch_notify(project_directory, language_server, method, params_cb) catch |e| return self.logger.err("lsp-handling", e);
} else if (try m.match(.{ "child", tp.extract(&project_directory), tp.extract(&language_server), "request", tp.extract(&method), tp.extract(&id), tp.extract_cbor(&params_cb) })) { } else if (try m.match(.{ "child", tp.extract(&project_directory), tp.extract(&language_server), "request", tp.extract(&method), tp.extract(&id), tp.extract_cbor(&params_cb) })) {
@ -211,26 +211,26 @@ const Process = struct {
} else if (try m.match(.{ "child", tp.extract(&path), "done" })) { } else if (try m.match(.{ "child", tp.extract(&path), "done" })) {
self.logger.print_err("lsp-handling", "child '{s}' terminated", .{path}); self.logger.print_err("lsp-handling", "child '{s}' terminated", .{path});
} else if (try m.match(.{ "open", tp.extract(&project_directory) })) { } else if (try m.match(.{ "open", tp.extract(&project_directory) })) {
self.open(project_directory) catch |e| return from.forward_error(e); self.open(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "request_recent_files", tp.extract(&project_directory), tp.extract(&max) })) { } else if (try m.match(.{ "request_recent_files", tp.extract(&project_directory), tp.extract(&max) })) {
self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e); self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) { } else if (try m.match(.{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) {
self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e); self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "did_open", tp.extract(&project_directory), tp.extract(&path), tp.extract(&file_type), tp.extract_cbor(&language_server), tp.extract(&version), tp.extract(&text_ptr), tp.extract(&text_len) })) { } else if (try m.match(.{ "did_open", tp.extract(&project_directory), tp.extract(&path), tp.extract(&file_type), tp.extract_cbor(&language_server), tp.extract(&version), tp.extract(&text_ptr), tp.extract(&text_len) })) {
const text = if (text_len > 0) @as([*]const u8, @ptrFromInt(text_ptr))[0..text_len] else ""; const text = if (text_len > 0) @as([*]const u8, @ptrFromInt(text_ptr))[0..text_len] else "";
self.did_open(project_directory, path, file_type, language_server, version, text) catch |e| return from.forward_error(e); self.did_open(project_directory, path, file_type, language_server, version, text) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "did_change", tp.extract(&project_directory), tp.extract(&path), tp.extract(&version), tp.extract(&root_dst), tp.extract(&root_src) })) { } else if (try m.match(.{ "did_change", tp.extract(&project_directory), tp.extract(&path), tp.extract(&version), tp.extract(&root_dst), tp.extract(&root_src) })) {
self.did_change(project_directory, path, version, root_dst, root_src) catch |e| return from.forward_error(e); self.did_change(project_directory, path, version, root_dst, root_src) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "did_save", tp.extract(&project_directory), tp.extract(&path) })) { } else if (try m.match(.{ "did_save", tp.extract(&project_directory), tp.extract(&path) })) {
self.did_save(project_directory, path) catch |e| return from.forward_error(e); self.did_save(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "did_close", tp.extract(&project_directory), tp.extract(&path) })) { } else if (try m.match(.{ "did_close", tp.extract(&project_directory), tp.extract(&path) })) {
self.did_close(project_directory, path) catch |e| return from.forward_error(e); self.did_close(project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "goto_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) { } else if (try m.match(.{ "goto_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
self.goto_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e); self.goto_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "completion", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) { } else if (try m.match(.{ "completion", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
self.completion(from, project_directory, path, row, col) catch |e| return from.forward_error(e); self.completion(from, project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{ "get_mru_position", tp.extract(&project_directory), tp.extract(&path) })) { } else if (try m.match(.{ "get_mru_position", tp.extract(&project_directory), tp.extract(&path) })) {
self.get_mru_position(from, project_directory, path) catch |e| return from.forward_error(e); self.get_mru_position(from, project_directory, path) catch |e| return from.forward_error(e, @errorReturnTrace());
} else if (try m.match(.{"shutdown"})) { } else if (try m.match(.{"shutdown"})) {
if (self.walker) |pid| pid.send(.{"stop"}) catch {}; if (self.walker) |pid| pid.send(.{"stop"}) catch {};
self.persist_projects(); self.persist_projects();
@ -245,7 +245,7 @@ const Process = struct {
} }
} }
fn open(self: *Process, project_directory: []const u8) error{ OutOfMemory, Exit }!void { fn open(self: *Process, project_directory: []const u8) !void {
if (self.projects.get(project_directory) == null) { if (self.projects.get(project_directory) == null) {
self.logger.print("opening: {s}", .{project_directory}); self.logger.print("opening: {s}", .{project_directory});
const project = try self.a.create(Project); const project = try self.a.create(Project);
@ -282,72 +282,72 @@ const Process = struct {
self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time }); self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time });
} }
fn did_open(self: *Process, project_directory: []const u8, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) tp.result { fn did_open(self: *Process, project_directory: []const u8, file_path: []const u8, file_type: []const u8, language_server: []const u8, version: usize, text: []const u8) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_open" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_open" });
defer frame.deinit(); defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.did_open(file_path, file_type, language_server, version, text); return project.did_open(file_path, file_type, language_server, version, text);
} }
fn did_change(self: *Process, project_directory: []const u8, file_path: []const u8, version: usize, root_dst: usize, root_src: usize) tp.result { fn did_change(self: *Process, project_directory: []const u8, file_path: []const u8, version: usize, root_dst: usize, root_src: usize) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_change" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_change" });
defer frame.deinit(); defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.did_change(file_path, version, root_dst, root_src) catch |e| tp.exit_error(e); return project.did_change(file_path, version, root_dst, root_src);
} }
fn did_save(self: *Process, project_directory: []const u8, file_path: []const u8) tp.result { fn did_save(self: *Process, project_directory: []const u8, file_path: []const u8) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_save" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_save" });
defer frame.deinit(); defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.did_save(file_path); return project.did_save(file_path);
} }
fn did_close(self: *Process, project_directory: []const u8, file_path: []const u8) tp.result { fn did_close(self: *Process, project_directory: []const u8, file_path: []const u8) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_close" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".did_close" });
defer frame.deinit(); defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.did_close(file_path); return project.did_close(file_path);
} }
fn goto_definition(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) tp.result { fn goto_definition(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_definition" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".goto_definition" });
defer frame.deinit(); defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.goto_definition(from, file_path, row, col) catch |e| tp.exit_error(e); return project.goto_definition(from, file_path, row, col);
} }
fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) tp.result { fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".completion" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".completion" });
defer frame.deinit(); defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.completion(from, file_path, row, col) catch |e| tp.exit_error(e); return project.completion(from, file_path, row, col);
} }
fn get_mru_position(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) tp.result { fn get_mru_position(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) !void {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".get_mru_position" }); const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".get_mru_position" });
defer frame.deinit(); defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.get_mru_position(from, file_path) catch |e| tp.exit_error(e); return project.get_mru_position(from, file_path);
} }
fn update_mru(self: *Process, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) tp.result { fn update_mru(self: *Process, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) !void {
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return project.update_mru(file_path, row, col) catch |e| tp.exit_error(e); return project.update_mru(file_path, row, col);
} }
fn dispatch_notify(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, params_cb: []const u8) tp.result { fn dispatch_notify(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, params_cb: []const u8) !void {
_ = language_server; _ = language_server;
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
return if (std.mem.eql(u8, method, "textDocument/publishDiagnostics")) return if (std.mem.eql(u8, method, "textDocument/publishDiagnostics"))
project.publish_diagnostics(self.parent.ref(), params_cb) catch |e| tp.exit_error(e) project.publish_diagnostics(self.parent.ref(), params_cb)
else if (std.mem.eql(u8, method, "window/showMessage")) else if (std.mem.eql(u8, method, "window/showMessage"))
project.show_message(self.parent.ref(), params_cb) catch |e| tp.exit_error(e) project.show_message(self.parent.ref(), params_cb)
else else
tp.exit_fmt("unsupported LSP notification: {s}", .{method}); tp.exit_fmt("unsupported LSP notification: {s}", .{method});
} }
fn dispatch_request(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, id: i32, params_cb: []const u8) tp.result { fn dispatch_request(self: *Process, project_directory: []const u8, language_server: []const u8, method: []const u8, id: i32, params_cb: []const u8) !void {
_ = self; _ = self;
_ = project_directory; _ = project_directory;
_ = language_server; _ = language_server;
@ -410,7 +410,7 @@ const Process = struct {
} }
}; };
fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) error{Exit}!tp.pid { fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) !tp.pid {
return struct { return struct {
a: std.mem.Allocator, a: std.mem.Allocator,
root_path: []const u8, root_path: []const u8,
@ -422,17 +422,17 @@ fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) error{Exit}!tp
const tree_walker = @This(); const tree_walker = @This();
const Receiver = tp.Receiver(*tree_walker); const Receiver = tp.Receiver(*tree_walker);
fn spawn_link(a: std.mem.Allocator, root_path: []const u8) error{Exit}!tp.pid { fn spawn_link(a: std.mem.Allocator, root_path: []const u8) !tp.pid {
const self = a.create(tree_walker) catch |e| return tp.exit_error(e); const self = try a.create(tree_walker);
self.* = .{ self.* = .{
.a = a, .a = a,
.root_path = a.dupe(u8, root_path) catch |e| return tp.exit_error(e), .root_path = try a.dupe(u8, root_path),
.parent = tp.self_pid().clone(), .parent = tp.self_pid().clone(),
.receiver = Receiver.init(tree_walker.receive, self), .receiver = Receiver.init(tree_walker.receive, self),
.dir = std.fs.cwd().openDir(self.root_path, .{ .iterate = true }) catch |e| return tp.exit_error(e), .dir = try std.fs.cwd().openDir(self.root_path, .{ .iterate = true }),
.walker = walk_filtered(self.dir, self.a) catch |e| return tp.exit_error(e), .walker = try walk_filtered(self.dir, self.a),
}; };
return tp.spawn_link(a, self, tree_walker.start, module_name ++ ".tree_walker") catch |e| return tp.exit_error(e); return tp.spawn_link(a, self, tree_walker.start, module_name ++ ".tree_walker");
} }
fn start(self: *tree_walker) tp.result { fn start(self: *tree_walker) tp.result {
@ -440,7 +440,7 @@ fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) error{Exit}!tp
const frame = tracy.initZone(@src(), .{ .name = "project scan" }); const frame = tracy.initZone(@src(), .{ .name = "project scan" });
defer frame.deinit(); defer frame.deinit();
tp.receive(&self.receiver); tp.receive(&self.receiver);
self.next() catch |e| return tp.exit_error(e); self.next() catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
fn deinit(self: *tree_walker) void { fn deinit(self: *tree_walker) void {
@ -456,7 +456,7 @@ fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) error{Exit}!tp
defer frame.deinit(); defer frame.deinit();
if (try m.match(.{"next"})) { if (try m.match(.{"next"})) {
self.next() catch |e| return tp.exit_error(e); self.next() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{"stop"})) { } else if (try m.match(.{"stop"})) {
return tp.exit_normal(); return tp.exit_normal();
} else { } else {

View file

@ -11,9 +11,9 @@ stdin_behavior: std.process.Child.StdIo,
const Self = @This(); const Self = @This();
const module_name = @typeName(Self); const module_name = @typeName(Self);
pub const max_chunk_size = tp.subprocess.max_chunk_size; pub const max_chunk_size = tp.subprocess.max_chunk_size;
pub const Writer = std.io.Writer(*Self, error{Exit}, write); pub const Writer = std.io.Writer(*Self, Error, write);
pub const BufferedWriter = std.io.BufferedWriter(max_chunk_size, Writer); pub const BufferedWriter = std.io.BufferedWriter(max_chunk_size, Writer);
pub const Error = error{ OutOfMemory, Exit }; pub const Error = error{ OutOfMemory, Exit, ThespianSpawnFailed, Closed };
pub const FindF = fn (a: std.mem.Allocator, query: []const u8, tag: [:0]const u8) Error!Self; pub const FindF = fn (a: std.mem.Allocator, query: []const u8, tag: [:0]const u8) Error!Self;
@ -21,11 +21,11 @@ pub fn find_in_stdin(a: std.mem.Allocator, query: []const u8, tag: [:0]const u8)
return create(a, query, tag, .Pipe); return create(a, query, tag, .Pipe);
} }
pub fn find_in_files(a: std.mem.Allocator, query: []const u8, tag: [:0]const u8) Error!Self { pub fn find_in_files(a: std.mem.Allocator, query: []const u8, tag: [:0]const u8) !Self {
return create(a, query, tag, .Close); return create(a, query, tag, .Close);
} }
fn create(a: std.mem.Allocator, query: []const u8, tag: [:0]const u8, stdin_behavior: std.process.Child.StdIo) Error!Self { fn create(a: std.mem.Allocator, query: []const u8, tag: [:0]const u8, stdin_behavior: std.process.Child.StdIo) !Self {
return .{ .pid = try Process.create(a, query, tag, stdin_behavior), .stdin_behavior = stdin_behavior }; return .{ .pid = try Process.create(a, query, tag, stdin_behavior), .stdin_behavior = stdin_behavior };
} }
@ -38,13 +38,13 @@ pub fn deinit(self: *Self) void {
} }
} }
pub fn write(self: *Self, bytes: []const u8) error{Exit}!usize { pub fn write(self: *Self, bytes: []const u8) !usize {
try self.input(bytes); try self.input(bytes);
return bytes.len; return bytes.len;
} }
pub fn input(self: *const Self, bytes: []const u8) tp.result { pub fn input(self: *const Self, bytes: []const u8) !void {
const pid = if (self.pid) |pid| pid else return tp.exit_error(error.Closed); const pid = if (self.pid) |pid| pid else return error.Closed;
var remaining = bytes; var remaining = bytes;
while (remaining.len > 0) while (remaining.len > 0)
remaining = loop: { remaining = loop: {
@ -83,7 +83,7 @@ const Process = struct {
const Receiver = tp.Receiver(*Process); const Receiver = tp.Receiver(*Process);
pub fn create(a: std.mem.Allocator, query: []const u8, tag: [:0]const u8, stdin_behavior: std.process.Child.StdIo) Error!tp.pid { pub fn create(a: std.mem.Allocator, query: []const u8, tag: [:0]const u8, stdin_behavior: std.process.Child.StdIo) !tp.pid {
const self = try a.create(Process); const self = try a.create(Process);
self.* = .{ self.* = .{
.a = a, .a = a,
@ -95,7 +95,7 @@ const Process = struct {
.logger = log.logger(@typeName(Self)), .logger = log.logger(@typeName(Self)),
.stdin_behavior = stdin_behavior, .stdin_behavior = stdin_behavior,
}; };
return tp.spawn_link(self.a, self, Process.start, tag) catch |e| tp.exit_error(e); return tp.spawn_link(self.a, self, Process.start, tag);
} }
fn deinit(self: *Process) void { fn deinit(self: *Process) void {
@ -121,7 +121,7 @@ const Process = struct {
"--json", "--json",
self.query, self.query,
}); });
self.sp = tp.subprocess.init(self.a, args, module_name, self.stdin_behavior) catch |e| return tp.exit_error(e); self.sp = tp.subprocess.init(self.a, args, module_name, self.stdin_behavior) catch |e| return tp.exit_error(e, @errorReturnTrace());
tp.receive(&self.receiver); tp.receive(&self.receiver);
} }
@ -130,14 +130,14 @@ const Process = struct {
var bytes: []u8 = ""; var bytes: []u8 = "";
if (try m.match(.{ "input", tp.extract(&bytes) })) { if (try m.match(.{ "input", tp.extract(&bytes) })) {
const sp = if (self.sp) |sp| sp else return tp.exit_error(error.Closed); const sp = if (self.sp) |sp| sp else return tp.exit_error(error.Closed, null);
try sp.send(bytes); try sp.send(bytes);
} else if (try m.match(.{"close"})) { } else if (try m.match(.{"close"})) {
try self.close(); try self.close();
} else if (try m.match(.{ module_name, "stdout", tp.extract(&bytes) })) { } else if (try m.match(.{ module_name, "stdout", tp.extract(&bytes) })) {
self.handle_output(bytes) catch |e| return tp.exit_error(e); self.handle_output(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ module_name, "term", tp.more })) { } else if (try m.match(.{ module_name, "term", tp.more })) {
self.handle_terminated() catch |e| return tp.exit_error(e); self.handle_terminated() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ module_name, "stderr", tp.extract(&bytes) })) { } else if (try m.match(.{ module_name, "stderr", tp.extract(&bytes) })) {
self.logger.print("ERR: {s}", .{bytes}); self.logger.print("ERR: {s}", .{bytes});
} else if (try m.match(.{ "exit", "normal" })) { } else if (try m.match(.{ "exit", "normal" })) {

View file

@ -123,7 +123,7 @@ pub const List = struct {
pub fn filter(self: *const List, from: tp.pid_ref, m: tp.message) error{Exit}!bool { pub fn filter(self: *const List, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
var sfa = std.heap.stackFallback(4096, self.a); var sfa = std.heap.stackFallback(4096, self.a);
const a = sfa.get(); const a = sfa.get();
const buf = a.alloc(u8, m.buf.len) catch |e| return tp.exit_error(e); const buf = a.alloc(u8, m.buf.len) catch |e| return tp.exit_error(e, @errorReturnTrace());
defer a.free(buf); defer a.free(buf);
@memcpy(buf[0..m.buf.len], m.buf); @memcpy(buf[0..m.buf.len], m.buf);
const m_: tp.message = .{ .buf = buf[0..m.buf.len] }; const m_: tp.message = .{ .buf = buf[0..m.buf.len] };

View file

@ -7,6 +7,7 @@ const tui = @import("tui.zig");
pub const ID = usize; pub const ID = usize;
pub const ID_unknown = std.math.maxInt(ID); pub const ID_unknown = std.math.maxInt(ID);
pub const Result = anyerror!void;
pub const Context = struct { pub const Context = struct {
args: tp.message = .{}, args: tp.message = .{},
@ -29,7 +30,7 @@ pub fn Closure(comptime T: type) type {
f: FunT, f: FunT,
data: T, data: T,
const FunT: type = *const fn (T, ctx: Context) tp.result; const FunT: type = *const fn (T, ctx: Context) Result;
const Self = @This(); const Self = @This();
pub fn init(f: FunT, data: T, name: []const u8) Self { pub fn init(f: FunT, data: T, name: []const u8) Self {
@ -61,7 +62,7 @@ pub fn Closure(comptime T: type) type {
fn run(vtbl: *Vtable, ctx: Context) tp.result { fn run(vtbl: *Vtable, ctx: Context) tp.result {
const self: *Self = fromVtable(vtbl); const self: *Self = fromVtable(vtbl);
return self.f(self.data, ctx); return self.f(self.data, ctx) catch |e| tp.exit_error(e, @errorReturnTrace());
} }
fn fromVtable(vtbl: *Vtable) *Self { fn fromVtable(vtbl: *Vtable) *Self {
@ -96,7 +97,7 @@ pub fn execute(id: ID, ctx: Context) tp.result {
const cmd = commands.items[id]; const cmd = commands.items[id];
if (cmd) |p| { if (cmd) |p| {
// var buf: [tp.max_message_size]u8 = undefined; // var buf: [tp.max_message_size]u8 = undefined;
// log.print("cmd", "execute({s}) {s}", .{ p.name, ctx.args.to_json(&buf) catch "" }) catch |e| return tp.exit_error(e); // log.print("cmd", "execute({s}) {s}", .{ p.name, ctx.args.to_json(&buf) catch "" }) catch |e| return tp.exit_error(e, @errorReturnTrace());
return p.run(p, ctx); return p.run(p, ctx);
} else { } else {
return tp.exit_fmt("CommandNotAvailable: {d}", .{id}); return tp.exit_fmt("CommandNotAvailable: {d}", .{id});
@ -129,7 +130,7 @@ pub fn executeName(name: []const u8, ctx: Context) tp.result {
fn CmdDef(comptime T: type) type { fn CmdDef(comptime T: type) type {
return struct { return struct {
const Fn = fn (T, Context) tp.result; const Fn = fn (T, Context) anyerror!void;
name: [:0]const u8, name: [:0]const u8,
f: *const Fn, f: *const Fn,
}; };

File diff suppressed because it is too large Load diff

View file

@ -76,7 +76,7 @@ fn diff_symbols_clear(self: *Self) void {
pub fn handle_event(self: *Self, _: tp.pid_ref, m: tp.message) tp.result { pub fn handle_event(self: *Self, _: tp.pid_ref, m: tp.message) tp.result {
if (try m.match(.{ "E", "update", tp.more })) if (try m.match(.{ "E", "update", tp.more }))
return self.diff_update() catch |e| return tp.exit_error(e); return self.diff_update() catch |e| return tp.exit_error(e, @errorReturnTrace());
if (try m.match(.{ "E", "view", tp.extract(&self.lines), tp.extract(&self.rows), tp.extract(&self.row) })) if (try m.match(.{ "E", "view", tp.extract(&self.lines), tp.extract(&self.rows), tp.extract(&self.row) }))
return self.update_width(); return self.update_width();
if (try m.match(.{ "E", "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.more })) if (try m.match(.{ "E", "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.more }))
@ -382,7 +382,7 @@ fn process_edit(self: *Self, kind: Kind, line: usize, offset: usize, bytes: []co
pub fn filter_receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { pub fn filter_receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var cb: []const u8 = undefined; var cb: []const u8 = undefined;
if (try m.match(.{ "DIFF", tp.extract_cbor(&cb) })) { if (try m.match(.{ "DIFF", tp.extract_cbor(&cb) })) {
self.process_diff(cb) catch |e| return tp.exit_error(e); self.process_diff(cb) catch |e| return tp.exit_error(e, @errorReturnTrace());
return true; return true;
} }
return false; return false;

View file

@ -189,24 +189,25 @@ const Commands = command.Collection(cmds);
const cmds = struct { const cmds = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn home_menu_down(self: *Self, _: Ctx) tp.result { pub fn home_menu_down(self: *Self, _: Ctx) Result {
self.menu.select_down(); self.menu.select_down();
} }
pub fn home_menu_up(self: *Self, _: Ctx) tp.result { pub fn home_menu_up(self: *Self, _: Ctx) Result {
self.menu.select_up(); self.menu.select_up();
} }
pub fn home_menu_activate(self: *Self, _: Ctx) tp.result { pub fn home_menu_activate(self: *Self, _: Ctx) Result {
self.menu.activate_selected(); self.menu.activate_selected();
} }
pub fn home_sheeran(self: *Self, _: Ctx) tp.result { pub fn home_sheeran(self: *Self, _: Ctx) Result {
self.fire = if (self.fire) |*fire| ret: { self.fire = if (self.fire) |*fire| ret: {
fire.deinit(); fire.deinit();
break :ret null; break :ret null;
} else Fire.init(self.a, self.plane) catch |e| return tp.exit_error(e); } else try Fire.init(self.a, self.plane);
} }
}; };

View file

@ -103,8 +103,8 @@ fn append(self: *Self, json: []const u8) !void {
pub fn listen(self: *Self, _: tp.pid_ref, m: tp.message) tp.result { pub fn listen(self: *Self, _: tp.pid_ref, m: tp.message) tp.result {
if (try m.match(.{ "M", tp.more })) return; if (try m.match(.{ "M", tp.more })) return;
var buf: [4096]u8 = undefined; var buf: [4096]u8 = undefined;
const json = m.to_json(&buf) catch |e| return tp.exit_error(e); const json = m.to_json(&buf) catch |e| return tp.exit_error(e, @errorReturnTrace());
self.append(json) catch |e| return tp.exit_error(e); self.append(json) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
pub fn receive(_: *Self, _: tp.pid_ref, _: tp.message) error{Exit}!bool { pub fn receive(_: *Self, _: tp.pid_ref, _: tp.message) error{Exit}!bool {

View file

@ -108,7 +108,7 @@ pub fn box(self: *const Self) Box {
return Box.from(self.plane); return Box.from(self.plane);
} }
fn toggle_panel_view(self: *Self, view: anytype, enable_only: bool) error{Exit}!bool { fn toggle_panel_view(self: *Self, view: anytype, enable_only: bool) !bool {
var enabled = true; var enabled = true;
if (self.panels) |panels| { if (self.panels) |panels| {
if (panels.get(@typeName(view))) |w| { if (panels.get(@typeName(view))) |w| {
@ -121,12 +121,12 @@ fn toggle_panel_view(self: *Self, view: anytype, enable_only: bool) error{Exit}!
enabled = false; enabled = false;
} }
} else { } else {
panels.add(view.create(self.a, self.widgets.plane) catch |e| return tp.exit_error(e)) catch |e| return tp.exit_error(e); try panels.add(try view.create(self.a, self.widgets.plane));
} }
} else { } else {
const panels = WidgetList.createH(self.a, self.widgets.widget(), "panel", .{ .static = self.box().h / 5 }) catch |e| return tp.exit_error(e); const panels = try WidgetList.createH(self.a, self.widgets.widget(), "panel", .{ .static = self.box().h / 5 });
self.widgets.add(panels.widget()) catch |e| return tp.exit_error(e); try self.widgets.add(panels.widget());
panels.add(view.create(self.a, self.widgets.plane) catch |e| return tp.exit_error(e)) catch |e| return tp.exit_error(e); try panels.add(try view.create(self.a, self.widgets.plane));
self.panels = panels; self.panels = panels;
} }
tui.current().resize(); tui.current().resize();
@ -141,11 +141,11 @@ fn close_all_panel_views(self: *Self) void {
tui.current().resize(); tui.current().resize();
} }
fn toggle_view(self: *Self, view: anytype) tp.result { fn toggle_view(self: *Self, view: anytype) !void {
if (self.widgets.get(@typeName(view))) |w| { if (self.widgets.get(@typeName(view))) |w| {
self.widgets.remove(w.*); self.widgets.remove(w.*);
} else { } else {
self.widgets.add(view.create(self.a, self.plane) catch |e| return tp.exit_error(e)) catch |e| return tp.exit_error(e); try self.widgets.add(try view.create(self.a, self.plane));
} }
tui.current().resize(); tui.current().resize();
} }
@ -153,23 +153,24 @@ fn toggle_view(self: *Self, view: anytype) tp.result {
const cmds = struct { const cmds = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn quit(self: *Self, _: Ctx) tp.result { pub fn quit(self: *Self, _: Ctx) Result {
if (self.editor) |editor| if (editor.is_dirty()) if (self.editor) |editor| if (editor.is_dirty())
return tp.exit("unsaved changes"); return tp.exit("unsaved changes");
try tp.self_pid().send("quit"); try tp.self_pid().send("quit");
} }
pub fn quit_without_saving(_: *Self, _: Ctx) tp.result { pub fn quit_without_saving(_: *Self, _: Ctx) Result {
try tp.self_pid().send("quit"); try tp.self_pid().send("quit");
} }
pub fn open_project_cwd(self: *Self, _: Ctx) tp.result { pub fn open_project_cwd(self: *Self, _: Ctx) Result {
try project_manager.open_cwd(); try project_manager.open_cwd();
_ = try self.statusbar.msg(.{ "PRJ", "open" }); _ = try self.statusbar.msg(.{ "PRJ", "open" });
} }
pub fn open_project_dir(self: *Self, ctx: Ctx) tp.result { pub fn open_project_dir(self: *Self, ctx: Ctx) Result {
var project_dir: []const u8 = undefined; var project_dir: []const u8 = undefined;
if (!try ctx.args.match(.{tp.extract(&project_dir)})) if (!try ctx.args.match(.{tp.extract(&project_dir)}))
return; return;
@ -177,7 +178,7 @@ const cmds = struct {
_ = try self.statusbar.msg(.{ "PRJ", "open" }); _ = try self.statusbar.msg(.{ "PRJ", "open" });
} }
pub fn navigate(self: *Self, ctx: Ctx) tp.result { pub fn navigate(self: *Self, ctx: Ctx) Result {
tui.reset_drag_context(); tui.reset_drag_context();
const frame = tracy.initZone(@src(), .{ .name = "navigate" }); const frame = tracy.initZone(@src(), .{ .name = "navigate" });
defer frame.deinit(); defer frame.deinit();
@ -192,27 +193,27 @@ const cmds = struct {
var len = len_; var len = len_;
while (len > 0) : (len -= 1) { while (len > 0) : (len -= 1) {
var field_name: []const u8 = undefined; var field_name: []const u8 = undefined;
if (!(cbor.matchString(&iter, &field_name) catch |e| return tp.exit_error(e))) if (!try cbor.matchString(&iter, &field_name))
return tp.exit_error(error.InvalidArgument); return error.InvalidArgument;
if (std.mem.eql(u8, field_name, "line")) { if (std.mem.eql(u8, field_name, "line")) {
if (!(cbor.matchValue(&iter, cbor.extract(&line)) catch |e| return tp.exit_error(e))) if (!try cbor.matchValue(&iter, cbor.extract(&line)))
return tp.exit_error(error.InvalidArgument); return error.InvalidArgument;
} else if (std.mem.eql(u8, field_name, "column")) { } else if (std.mem.eql(u8, field_name, "column")) {
if (!(cbor.matchValue(&iter, cbor.extract(&column)) catch |e| return tp.exit_error(e))) if (!try cbor.matchValue(&iter, cbor.extract(&column)))
return tp.exit_error(error.InvalidArgument); return error.InvalidArgument;
} else if (std.mem.eql(u8, field_name, "file")) { } else if (std.mem.eql(u8, field_name, "file")) {
if (!(cbor.matchValue(&iter, cbor.extract(&file)) catch |e| return tp.exit_error(e))) if (!try cbor.matchValue(&iter, cbor.extract(&file)))
return tp.exit_error(error.InvalidArgument); return error.InvalidArgument;
} else if (std.mem.eql(u8, field_name, "goto")) { } else if (std.mem.eql(u8, field_name, "goto")) {
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&goto_args)) catch |e| return tp.exit_error(e))) if (!try cbor.matchValue(&iter, cbor.extract_cbor(&goto_args)))
return tp.exit_error(error.InvalidArgument); return error.InvalidArgument;
} else { } else {
cbor.skipValue(&iter) catch |e| return tp.exit_error(e); try cbor.skipValue(&iter);
} }
} }
} else |_| if (ctx.args.match(tp.extract(&file_name)) catch false) { } else |_| if (ctx.args.match(tp.extract(&file_name)) catch false) {
file = file_name; file = file_name;
} else return tp.exit_error(error.InvalidArgument); } else return error.InvalidArgument;
if (tp.env.get().str("project").len == 0) { if (tp.env.get().str("project").len == 0) {
try open_project_cwd(self, .{}); try open_project_cwd(self, .{});
@ -247,57 +248,57 @@ const cmds = struct {
tui.need_render(); tui.need_render();
} }
pub fn open_help(self: *Self, _: Ctx) tp.result { pub fn open_help(self: *Self, _: Ctx) Result {
tui.reset_drag_context(); tui.reset_drag_context();
try self.create_editor(); try self.create_editor();
try command.executeName("open_scratch_buffer", command.fmt(.{ "help.md", @embedFile("help.md") })); try command.executeName("open_scratch_buffer", command.fmt(.{ "help.md", @embedFile("help.md") }));
tui.need_render(); tui.need_render();
} }
pub fn open_config(_: *Self, _: Ctx) tp.result { pub fn open_config(_: *Self, _: Ctx) Result {
const file_name = root.get_config_file_name() catch |e| return tp.exit_error(e); const file_name = try root.get_config_file_name();
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name } }); try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name } });
} }
pub fn restore_session(self: *Self, _: Ctx) tp.result { pub fn restore_session(self: *Self, _: Ctx) Result {
try self.create_editor(); try self.create_editor();
self.read_restore_info() catch |e| return tp.exit_error(e); try self.read_restore_info();
tui.need_render(); tui.need_render();
} }
pub fn toggle_logview(self: *Self, _: Ctx) tp.result { pub fn toggle_logview(self: *Self, _: Ctx) Result {
self.logview_enabled = try self.toggle_panel_view(@import("logview.zig"), false); self.logview_enabled = try self.toggle_panel_view(@import("logview.zig"), false);
} }
pub fn show_logview(self: *Self, _: Ctx) tp.result { pub fn show_logview(self: *Self, _: Ctx) Result {
self.logview_enabled = try self.toggle_panel_view(@import("logview.zig"), true); self.logview_enabled = try self.toggle_panel_view(@import("logview.zig"), true);
} }
pub fn toggle_inputview(self: *Self, _: Ctx) tp.result { pub fn toggle_inputview(self: *Self, _: Ctx) Result {
_ = try self.toggle_panel_view(@import("inputview.zig"), false); _ = try self.toggle_panel_view(@import("inputview.zig"), false);
} }
pub fn toggle_inspector_view(self: *Self, _: Ctx) tp.result { pub fn toggle_inspector_view(self: *Self, _: Ctx) Result {
_ = try self.toggle_panel_view(@import("inspector_view.zig"), false); _ = try self.toggle_panel_view(@import("inspector_view.zig"), false);
} }
pub fn show_inspector_view(self: *Self, _: Ctx) tp.result { pub fn show_inspector_view(self: *Self, _: Ctx) Result {
_ = try self.toggle_panel_view(@import("inspector_view.zig"), true); _ = try self.toggle_panel_view(@import("inspector_view.zig"), true);
} }
pub fn jump_back(self: *Self, _: Ctx) tp.result { pub fn jump_back(self: *Self, _: Ctx) Result {
try self.location_history.back(location_jump); try self.location_history.back(location_jump);
} }
pub fn jump_forward(self: *Self, _: Ctx) tp.result { pub fn jump_forward(self: *Self, _: Ctx) Result {
try self.location_history.forward(location_jump); try self.location_history.forward(location_jump);
} }
pub fn show_home(self: *Self, _: Ctx) tp.result { pub fn show_home(self: *Self, _: Ctx) Result {
return self.create_home(); return self.create_home();
} }
pub fn gutter_mode_next(self: *Self, _: Ctx) tp.result { pub fn gutter_mode_next(self: *Self, _: Ctx) Result {
const tui_ = tui.current(); const tui_ = tui.current();
var ln = tui_.config.gutter_line_numbers; var ln = tui_.config.gutter_line_numbers;
var lnr = tui_.config.gutter_line_numbers_relative; var lnr = tui_.config.gutter_line_numbers_relative;
@ -313,7 +314,7 @@ const cmds = struct {
} }
tui_.config.gutter_line_numbers = ln; tui_.config.gutter_line_numbers = ln;
tui_.config.gutter_line_numbers_relative = lnr; tui_.config.gutter_line_numbers_relative = lnr;
tui_.save_config() catch |e| return tp.exit_error(e); try tui_.save_config();
if (self.widgets.get("editor_gutter")) |gutter_widget| { if (self.widgets.get("editor_gutter")) |gutter_widget| {
const gutter = if (gutter_widget.dynamic_cast(@import("editor_gutter.zig"))) |p| p else return; const gutter = if (gutter_widget.dynamic_cast(@import("editor_gutter.zig"))) |p| p else return;
gutter.linenum = ln; gutter.linenum = ln;
@ -387,8 +388,8 @@ fn location_jump(from: tp.pid_ref, file_path: []const u8, cursor: location_histo
} }) catch return; } }) catch return;
} }
fn clear_auto_find(self: *Self, editor: *ed.Editor) !void { fn clear_auto_find(self: *Self, editor: *ed.Editor) void {
try editor.clear_matches(); editor.clear_matches();
self.store_last_match_text(null); self.store_last_match_text(null);
} }
@ -412,11 +413,11 @@ pub fn walk(self: *Self, ctx: *anyopaque, f: Widget.WalkFn, w: *Widget) bool {
return self.floating_views.walk(ctx, f) or self.widgets.walk(ctx, f, &self.widgets_widget) or f(ctx, w); return self.floating_views.walk(ctx, f) or self.widgets.walk(ctx, f, &self.widgets_widget) or f(ctx, w);
} }
fn create_editor(self: *Self) tp.result { fn create_editor(self: *Self) !void {
if (self.editor) |editor| if (editor.file_path) |file_path| self.push_file_stack(file_path) catch {}; if (self.editor) |editor| if (editor.file_path) |file_path| self.push_file_stack(file_path) catch {};
self.widgets.replace(0, Widget.empty(self.a, self.plane, .dynamic) catch |e| return tp.exit_error(e)); self.widgets.replace(0, try Widget.empty(self.a, self.plane, .dynamic));
command.executeName("enter_mode_default", .{}) catch {}; command.executeName("enter_mode_default", .{}) catch {};
var editor_widget = ed.create(self.a, Widget.to(self)) catch |e| return tp.exit_error(e); var editor_widget = try ed.create(self.a, Widget.to(self));
errdefer editor_widget.deinit(self.a); errdefer editor_widget.deinit(self.a);
if (editor_widget.get("editor")) |editor| { if (editor_widget.get("editor")) |editor| {
editor.subscribe(EventHandler.to_unowned(self.statusbar)) catch @panic("subscribe unsupported"); editor.subscribe(EventHandler.to_unowned(self.statusbar)) catch @panic("subscribe unsupported");
@ -443,10 +444,10 @@ fn show_home_async(_: *Self) void {
tp.self_pid().send(.{ "cmd", "show_home" }) catch return; tp.self_pid().send(.{ "cmd", "show_home" }) catch return;
} }
fn create_home(self: *Self) tp.result { fn create_home(self: *Self) !void {
tui.reset_drag_context(); tui.reset_drag_context();
if (self.editor) |_| return; if (self.editor) |_| return;
var home_widget = home.create(self.a, Widget.to(self)) catch |e| return tp.exit_error(e); var home_widget = try home.create(self.a, Widget.to(self));
errdefer home_widget.deinit(self.a); errdefer home_widget.deinit(self.a);
self.widgets.replace(0, home_widget); self.widgets.replace(0, home_widget);
tui.current().resize(); tui.current().resize();

View file

@ -50,18 +50,18 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var text: []const u8 = undefined; var text: []const u8 = undefined;
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{"F"})) { } else if (try m.match(.{"F"})) {
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.paste_bytes(text); self.paste_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
pub fn add_keybind() void {} pub fn add_keybind() void {}
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
return switch (evtype) { return switch (evtype) {
event_type.PRESS => self.mapPress(keypress, egc, modifiers), event_type.PRESS => self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => self.mapPress(keypress, egc, modifiers), event_type.REPEAT => self.mapPress(keypress, egc, modifiers),
@ -70,7 +70,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
}; };
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers); if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers);
switch (keypress) { switch (keypress) {
@ -225,7 +225,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapFollower(self: *Self, keypress: u32, _: u32, modifiers: u32) tp.result { fn mapFollower(self: *Self, keypress: u32, _: u32, modifiers: u32) !void {
defer self.leader = null; defer self.leader = null;
const ldr = if (self.leader) |leader| leader else return; const ldr = if (self.leader) |leader| leader else return;
return switch (ldr.modifiers) { return switch (ldr.modifiers) {
@ -245,7 +245,7 @@ fn mapFollower(self: *Self, keypress: u32, _: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}), key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}), key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}),
@ -253,32 +253,32 @@ fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result {
}; };
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
var buf: [6]u8 = undefined; var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e); try self.input.appendSlice(buf[0..bytes]);
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
self.input.appendSlice(bytes) catch |e| return tp.exit_error(e); try self.input.appendSlice(bytes);
} }
fn paste_bytes(self: *Self, bytes: []const u8) tp.result { fn paste_bytes(self: *Self, bytes: []const u8) !void {
try self.flush_input(); try self.flush_input();
try command.executeName("paste", command.fmt(.{bytes})); try command.executeName("paste", command.fmt(.{bytes}));
} }
var insert_chars_id: ?command.ID = null; var insert_chars_id: ?command.ID = null;
fn flush_input(self: *Self) tp.result { fn flush_input(self: *Self) !void {
if (self.input.items.len > 0) { if (self.input.items.len > 0) {
defer self.input.clearRetainingCapacity(); defer self.input.clearRetainingCapacity();
const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse { const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse {
return tp.exit_error(error.InputTargetNotFound); return tp.exit_error(error.InputTargetNotFound, null);
}; };
try command.execute(id, command.fmt(.{self.input.items})); try command.execute(id, command.fmt(.{self.input.items}));
self.last_cmd = "insert_chars"; self.last_cmd = "insert_chars";

View file

@ -53,20 +53,20 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var text: []const u8 = undefined; var text: []const u8 = undefined;
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{"F"})) { } else if (try m.match(.{"F"})) {
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
try self.insert_bytes(text); self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
pub fn add_keybind() void {} pub fn add_keybind() void {}
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
return switch (evtype) { return switch (evtype) {
event_type.PRESS => self.mapPress(keypress, egc, modifiers), event_type.PRESS => self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => self.mapPress(keypress, egc, modifiers), event_type.REPEAT => self.mapPress(keypress, egc, modifiers),
@ -75,7 +75,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
}; };
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers); if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers);
switch (keypress) { switch (keypress) {
@ -227,7 +227,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapFollower(self: *Self, keypress: u32, _: u32, modifiers: u32) tp.result { fn mapFollower(self: *Self, keypress: u32, _: u32, modifiers: u32) !void {
defer self.leader = null; defer self.leader = null;
const ldr = if (self.leader) |leader| leader else return; const ldr = if (self.leader) |leader| leader else return;
return switch (ldr.modifiers) { return switch (ldr.modifiers) {
@ -247,7 +247,7 @@ fn mapFollower(self: *Self, keypress: u32, _: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}), key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}), key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}),
@ -255,27 +255,27 @@ fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result {
}; };
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
var buf: [6]u8 = undefined; var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e); try self.input.appendSlice(buf[0..bytes]);
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
self.input.appendSlice(bytes) catch |e| return tp.exit_error(e); try self.input.appendSlice(bytes);
} }
var insert_chars_id: ?command.ID = null; var insert_chars_id: ?command.ID = null;
fn flush_input(self: *Self) tp.result { fn flush_input(self: *Self) !void {
if (self.input.items.len > 0) { if (self.input.items.len > 0) {
defer self.input.clearRetainingCapacity(); defer self.input.clearRetainingCapacity();
const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse { const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse {
return tp.exit_error(error.InputTargetNotFound); return tp.exit_error(error.InputTargetNotFound, null);
}; };
try command.execute(id, command.fmt(.{self.input.items})); try command.execute(id, command.fmt(.{self.input.items}));
self.last_cmd = "insert_chars"; self.last_cmd = "insert_chars";
@ -306,25 +306,26 @@ const Commands = command.Collection(cmds_);
const cmds_ = struct { const cmds_ = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn @"w"(self: *Self, _: Ctx) tp.result { pub fn w(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{}); try self.cmd("save_file", .{});
} }
pub fn @"q"(self: *Self, _: Ctx) tp.result { pub fn q(self: *Self, _: Ctx) Result {
try self.cmd("quit", .{}); try self.cmd("quit", .{});
} }
pub fn @"q!"(self: *Self, _: Ctx) tp.result { pub fn @"q!"(self: *Self, _: Ctx) Result {
try self.cmd("quit_without_saving", .{}); try self.cmd("quit_without_saving", .{});
} }
pub fn @"wq"(self: *Self, _: Ctx) tp.result { pub fn wq(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{}); try self.cmd("save_file", .{});
try self.cmd("quit", .{}); try self.cmd("quit", .{});
} }
pub fn @"wq!"(self: *Self, _: Ctx) tp.result { pub fn @"wq!"(self: *Self, _: Ctx) Result {
self.cmd("save_file", .{}) catch {}; self.cmd("save_file", .{}) catch {};
try self.cmd("quit_without_saving", .{}); try self.cmd("quit_without_saving", .{});
} }

View file

@ -55,20 +55,20 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var text: []const u8 = undefined; var text: []const u8 = undefined;
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{"F"})) { } else if (try m.match(.{"F"})) {
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
try self.insert_bytes(text); self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
pub fn add_keybind() void {} pub fn add_keybind() void {}
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
return switch (evtype) { return switch (evtype) {
event_type.PRESS => self.mapPress(keypress, egc, modifiers), event_type.PRESS => self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => self.mapPress(keypress, egc, modifiers), event_type.REPEAT => self.mapPress(keypress, egc, modifiers),
@ -77,7 +77,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
}; };
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
if (self.count > 0 and modifiers == 0 and '0' <= keypress and keypress <= '9') return self.add_count(keypress - '0'); if (self.count > 0 and modifiers == 0 and '0' <= keypress and keypress <= '9') return self.add_count(keypress - '0');
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers); if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers);
@ -290,7 +290,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapFollower(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapFollower(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
if (keypress == key.LCTRL or if (keypress == key.LCTRL or
keypress == key.RCTRL or keypress == key.RCTRL or
keypress == key.LALT or keypress == key.LALT or
@ -403,7 +403,7 @@ fn mapFollower(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}), key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}), key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}),
@ -416,27 +416,27 @@ fn add_count(self: *Self, value: usize) void {
self.count += value; self.count += value;
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
var buf: [6]u8 = undefined; var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e); try self.input.appendSlice(buf[0..bytes]);
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
self.input.appendSlice(bytes) catch |e| return tp.exit_error(e); try self.input.appendSlice(bytes);
} }
var insert_chars_id: ?command.ID = null; var insert_chars_id: ?command.ID = null;
fn flush_input(self: *Self) tp.result { fn flush_input(self: *Self) !void {
if (self.input.items.len > 0) { if (self.input.items.len > 0) {
defer self.input.clearRetainingCapacity(); defer self.input.clearRetainingCapacity();
const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse { const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse {
return tp.exit_error(error.InputTargetNotFound); return tp.exit_error(error.InputTargetNotFound, null);
}; };
try command.execute(id, command.fmt(.{self.input.items})); try command.execute(id, command.fmt(.{self.input.items}));
self.last_cmd = "insert_chars"; self.last_cmd = "insert_chars";
@ -610,25 +610,26 @@ const Commands = command.Collection(cmds_);
const cmds_ = struct { const cmds_ = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn @"w"(self: *Self, _: Ctx) tp.result { pub fn w(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{}); try self.cmd("save_file", .{});
} }
pub fn @"q"(self: *Self, _: Ctx) tp.result { pub fn q(self: *Self, _: Ctx) Result {
try self.cmd("quit", .{}); try self.cmd("quit", .{});
} }
pub fn @"q!"(self: *Self, _: Ctx) tp.result { pub fn @"q!"(self: *Self, _: Ctx) Result {
try self.cmd("quit_without_saving", .{}); try self.cmd("quit_without_saving", .{});
} }
pub fn @"wq"(self: *Self, _: Ctx) tp.result { pub fn wq(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{}); try self.cmd("save_file", .{});
try self.cmd("quit", .{}); try self.cmd("quit", .{});
} }
pub fn @"wq!"(self: *Self, _: Ctx) tp.result { pub fn @"wq!"(self: *Self, _: Ctx) Result {
self.cmd("save_file", .{}) catch {}; self.cmd("save_file", .{}) catch {};
try self.cmd("quit_without_saving", .{}); try self.cmd("quit_without_saving", .{});
} }

View file

@ -55,20 +55,20 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var text: []const u8 = undefined; var text: []const u8 = undefined;
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{"F"})) { } else if (try m.match(.{"F"})) {
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
try self.insert_bytes(text); self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
try self.flush_input(); self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
pub fn add_keybind() void {} pub fn add_keybind() void {}
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
return switch (evtype) { return switch (evtype) {
event_type.PRESS => self.mapPress(keypress, egc, modifiers), event_type.PRESS => self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => self.mapPress(keypress, egc, modifiers), event_type.REPEAT => self.mapPress(keypress, egc, modifiers),
@ -77,7 +77,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
}; };
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
if (self.count > 0 and modifiers == 0 and '0' <= keypress and keypress <= '9') return self.add_count(keypress - '0'); if (self.count > 0 and modifiers == 0 and '0' <= keypress and keypress <= '9') return self.add_count(keypress - '0');
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers); if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers);
@ -288,7 +288,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapFollower(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapFollower(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
if (keypress == key.LCTRL or if (keypress == key.LCTRL or
keypress == key.RCTRL or keypress == key.RCTRL or
keypress == key.LALT or keypress == key.LALT or
@ -363,7 +363,7 @@ fn mapFollower(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}), key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}), key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}),
@ -376,27 +376,27 @@ fn add_count(self: *Self, value: usize) void {
self.count += value; self.count += value;
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
var buf: [6]u8 = undefined; var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e); try self.input.appendSlice(buf[0..bytes]);
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
if (self.input.items.len + 4 > input_buffer_size) if (self.input.items.len + 4 > input_buffer_size)
try self.flush_input(); try self.flush_input();
self.input.appendSlice(bytes) catch |e| return tp.exit_error(e); try self.input.appendSlice(bytes);
} }
var insert_chars_id: ?command.ID = null; var insert_chars_id: ?command.ID = null;
fn flush_input(self: *Self) tp.result { fn flush_input(self: *Self) !void {
if (self.input.items.len > 0) { if (self.input.items.len > 0) {
defer self.input.clearRetainingCapacity(); defer self.input.clearRetainingCapacity();
const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse { const id = insert_chars_id orelse command.get_id_cache("insert_chars", &insert_chars_id) orelse {
return tp.exit_error(error.InputTargetNotFound); return tp.exit_error(error.InputTargetNotFound, null);
}; };
try command.execute(id, command.fmt(.{self.input.items})); try command.execute(id, command.fmt(.{self.input.items}));
self.last_cmd = "insert_chars"; self.last_cmd = "insert_chars";
@ -570,25 +570,26 @@ const Commands = command.Collection(cmds_);
const cmds_ = struct { const cmds_ = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn @"w"(self: *Self, _: Ctx) tp.result { pub fn @"w"(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{}); try self.cmd("save_file", .{});
} }
pub fn @"q"(self: *Self, _: Ctx) tp.result { pub fn @"q"(self: *Self, _: Ctx) Result {
try self.cmd("quit", .{}); try self.cmd("quit", .{});
} }
pub fn @"q!"(self: *Self, _: Ctx) tp.result { pub fn @"q!"(self: *Self, _: Ctx) Result {
try self.cmd("quit_without_saving", .{}); try self.cmd("quit_without_saving", .{});
} }
pub fn @"wq"(self: *Self, _: Ctx) tp.result { pub fn @"wq"(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{}); try self.cmd("save_file", .{});
try self.cmd("quit", .{}); try self.cmd("quit", .{});
} }
pub fn @"wq!"(self: *Self, _: Ctx) tp.result { pub fn @"wq!"(self: *Self, _: Ctx) Result {
self.cmd("save_file", .{}) catch {}; self.cmd("save_file", .{}) catch {};
try self.cmd("quit_without_saving", .{}); try self.cmd("quit_without_saving", .{});
} }

View file

@ -74,16 +74,16 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
} }
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{"F"})) { } else if (try m.match(.{"F"})) {
self.flush_input() catch |e| return e; self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.insert_bytes(text); self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
switch (evtype) { switch (evtype) {
event_type.PRESS => try self.mapPress(keypress, egc, modifiers), event_type.PRESS => try self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => try self.mapPress(keypress, egc, modifiers), event_type.REPEAT => try self.mapPress(keypress, egc, modifiers),
@ -92,7 +92,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
} }
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
return switch (modifiers) { return switch (modifiers) {
mod.CTRL => switch (keynormal) { mod.CTRL => switch (keynormal) {
@ -150,7 +150,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}), key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_fast_scroll", .{}), key.LALT, key.RALT => self.cmd("disable_fast_scroll", .{}),
@ -158,14 +158,14 @@ fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result {
}; };
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
if (self.input.len + 16 > self.buf.len) if (self.input.len + 16 > self.buf.len)
try self.flush_input(); try self.flush_input();
const bytes = ucs32_to_utf8(&[_]u32{c}, self.buf[self.input.len..]) catch |e| return tp.exit_error(e); const bytes = ucs32_to_utf8(&[_]u32{c}, self.buf[self.input.len..]) catch |e| return tp.exit_error(e, @errorReturnTrace());
self.input = self.buf[0 .. self.input.len + bytes]; self.input = self.buf[0 .. self.input.len + bytes];
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
if (self.input.len + 16 > self.buf.len) if (self.input.len + 16 > self.buf.len)
try self.flush_input(); try self.flush_input();
const newlen = self.input.len + bytes.len; const newlen = self.input.len + bytes.len;
@ -175,7 +175,7 @@ fn insert_bytes(self: *Self, bytes: []const u8) tp.result {
var find_cmd_id: ?command.ID = null; var find_cmd_id: ?command.ID = null;
fn flush_input(self: *Self) tp.result { fn flush_input(self: *Self) !void {
if (self.input.len > 0) { if (self.input.len > 0) {
if (eql(u8, self.input, self.last_input)) if (eql(u8, self.input, self.last_input))
return; return;

View file

@ -73,16 +73,16 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
} }
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{"F"})) { } else if (try m.match(.{"F"})) {
self.flush_input() catch |e| return e; self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.insert_bytes(text); self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
switch (evtype) { switch (evtype) {
event_type.PRESS => try self.mapPress(keypress, egc, modifiers), event_type.PRESS => try self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => try self.mapPress(keypress, egc, modifiers), event_type.REPEAT => try self.mapPress(keypress, egc, modifiers),
@ -91,7 +91,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
} }
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
return switch (modifiers) { return switch (modifiers) {
mod.CTRL => switch (keynormal) { mod.CTRL => switch (keynormal) {
@ -147,7 +147,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}), key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_fast_scroll", .{}), key.LALT, key.RALT => self.cmd("disable_fast_scroll", .{}),
@ -155,14 +155,14 @@ fn mapRelease(self: *Self, keypress: u32, _: u32, _: u32) tp.result {
}; };
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
if (self.input.len + 16 > self.buf.len) if (self.input.len + 16 > self.buf.len)
try self.flush_input(); try self.flush_input();
const bytes = ucs32_to_utf8(&[_]u32{c}, self.buf[self.input.len..]) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, self.buf[self.input.len..]);
self.input = self.buf[0 .. self.input.len + bytes]; self.input = self.buf[0 .. self.input.len + bytes];
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
if (self.input.len + 16 > self.buf.len) if (self.input.len + 16 > self.buf.len)
try self.flush_input(); try self.flush_input();
const newlen = self.input.len + bytes.len; const newlen = self.input.len + bytes.len;
@ -172,7 +172,7 @@ fn insert_bytes(self: *Self, bytes: []const u8) tp.result {
var find_cmd_id: ?command.ID = null; var find_cmd_id: ?command.ID = null;
fn flush_input(self: *Self) tp.result { fn flush_input(self: *Self) !void {
if (self.input.len > 0) { if (self.input.len > 0) {
if (eql(u8, self.input, self.last_input)) if (eql(u8, self.input, self.last_input))
return; return;

View file

@ -65,12 +65,12 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
} }
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
switch (evtype) { switch (evtype) {
event_type.PRESS => try self.mapPress(keypress, egc, modifiers), event_type.PRESS => try self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => try self.mapPress(keypress, egc, modifiers), event_type.REPEAT => try self.mapPress(keypress, egc, modifiers),
@ -79,7 +79,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
} }
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
return switch (modifiers) { return switch (modifiers) {
mod.CTRL => switch (keynormal) { mod.CTRL => switch (keynormal) {
@ -121,16 +121,16 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(_: *Self, _: u32, _: u32, _: u32) tp.result {} fn mapRelease(_: *Self, _: u32, _: u32, _: u32) !void {}
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
var buf: [32]u8 = undefined; var buf: [32]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
self.file_path.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e); try self.file_path.appendSlice(buf[0..bytes]);
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
self.file_path.appendSlice(bytes) catch |e| return tp.exit_error(e); try self.file_path.appendSlice(bytes);
} }
fn cmd(_: *Self, name_: []const u8, ctx: command.Context) tp.result { fn cmd(_: *Self, name_: []const u8, ctx: command.Context) tp.result {

View file

@ -170,7 +170,7 @@ fn menu_action_execute_command(menu: **Menu.State(*Self), button: *Button.State(
fn on_scroll(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!void { fn on_scroll(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!void {
if (try m.match(.{ "scroll_to", tp.extract(&self.view_pos) })) { if (try m.match(.{ "scroll_to", tp.extract(&self.view_pos) })) {
try self.start_query(); self.start_query() catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
} }
@ -186,14 +186,14 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var text: []const u8 = undefined; var text: []const u8 = undefined;
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.insert_bytes(text); self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
return switch (evtype) { return switch (evtype) {
event_type.PRESS => self.mapPress(keypress, egc, modifiers), event_type.PRESS => self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => self.mapPress(keypress, egc, modifiers), event_type.REPEAT => self.mapPress(keypress, egc, modifiers),
@ -202,7 +202,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
}; };
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
return switch (modifiers) { return switch (modifiers) {
mod.CTRL => switch (keynormal) { mod.CTRL => switch (keynormal) {
@ -267,14 +267,14 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => if (self.menu.selected orelse 0 > 0) return self.cmd("command_palette_menu_activate", .{}), key.LCTRL, key.RCTRL => if (self.menu.selected orelse 0 > 0) return self.cmd("command_palette_menu_activate", .{}),
else => {}, else => {},
}; };
} }
fn start_query(self: *Self) tp.result { fn start_query(self: *Self) !void {
self.items = 0; self.items = 0;
self.menu.reset_items(); self.menu.reset_items();
self.menu.selected = null; self.menu.selected = null;
@ -289,10 +289,10 @@ fn start_query(self: *Self) tp.result {
defer pos += 1; defer pos += 1;
if (pos < self.view_pos) continue; if (pos < self.view_pos) continue;
if (self.items < self.view_rows) if (self.items < self.view_rows)
self.add_item(cmd_.name, cmd_.id, null) catch |e| return tp.exit_error(e); try self.add_item(cmd_.name, cmd_.id, null);
} }
} else { } else {
_ = self.query_commands(self.inputbox.text.items) catch |e| return tp.exit_error(e); _ = try self.query_commands(self.inputbox.text.items);
} }
self.menu.select_down(); self.menu.select_down();
self.do_resize(); self.do_resize();
@ -360,7 +360,7 @@ fn add_item(self: *Self, name: []const u8, id: command.ID, matches: ?[]const usi
self.items += 1; self.items += 1;
} }
fn delete_word(self: *Self) tp.result { fn delete_word(self: *Self) !void {
if (std.mem.lastIndexOfAny(u8, self.inputbox.text.items, "/\\. -_")) |pos| { if (std.mem.lastIndexOfAny(u8, self.inputbox.text.items, "/\\. -_")) |pos| {
self.inputbox.text.shrinkRetainingCapacity(pos); self.inputbox.text.shrinkRetainingCapacity(pos);
} else { } else {
@ -371,7 +371,7 @@ fn delete_word(self: *Self) tp.result {
return self.start_query(); return self.start_query();
} }
fn delete_code_point(self: *Self) tp.result { fn delete_code_point(self: *Self) !void {
if (self.inputbox.text.items.len > 0) { if (self.inputbox.text.items.len > 0) {
self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - 1); self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - 1);
self.inputbox.cursor = self.inputbox.text.items.len; self.inputbox.cursor = self.inputbox.text.items.len;
@ -380,17 +380,17 @@ fn delete_code_point(self: *Self) tp.result {
return self.start_query(); return self.start_query();
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
var buf: [6]u8 = undefined; var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
self.inputbox.text.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e); try self.inputbox.text.appendSlice(buf[0..bytes]);
self.inputbox.cursor = self.inputbox.text.items.len; self.inputbox.cursor = self.inputbox.text.items.len;
self.view_pos = 0; self.view_pos = 0;
return self.start_query(); return self.start_query();
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
self.inputbox.text.appendSlice(bytes) catch |e| return tp.exit_error(e); try self.inputbox.text.appendSlice(bytes);
self.inputbox.cursor = self.inputbox.text.items.len; self.inputbox.cursor = self.inputbox.text.items.len;
self.view_pos = 0; self.view_pos = 0;
return self.start_query(); return self.start_query();
@ -476,8 +476,9 @@ fn restore_state(self: *Self) !void {
const cmds = struct { const cmds = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn command_palette_menu_down(self: *Self, _: Ctx) tp.result { pub fn command_palette_menu_down(self: *Self, _: Ctx) Result {
if (self.menu.selected) |selected| { if (self.menu.selected) |selected| {
if (selected == self.view_rows - 1) { if (selected == self.view_rows - 1) {
self.view_pos += 1; self.view_pos += 1;
@ -489,7 +490,7 @@ const cmds = struct {
self.menu.select_down(); self.menu.select_down();
} }
pub fn command_palette_menu_up(self: *Self, _: Ctx) tp.result { pub fn command_palette_menu_up(self: *Self, _: Ctx) Result {
if (self.menu.selected) |selected| { if (self.menu.selected) |selected| {
if (selected == 0 and self.view_pos > 0) { if (selected == 0 and self.view_pos > 0) {
self.view_pos -= 1; self.view_pos -= 1;
@ -501,7 +502,7 @@ const cmds = struct {
self.menu.select_up(); self.menu.select_up();
} }
pub fn command_palette_menu_pagedown(self: *Self, _: Ctx) tp.result { pub fn command_palette_menu_pagedown(self: *Self, _: Ctx) Result {
if (self.total_items > self.view_rows) { if (self.total_items > self.view_rows) {
self.view_pos += self.view_rows; self.view_pos += self.view_rows;
if (self.view_pos > self.total_items - self.view_rows) if (self.view_pos > self.total_items - self.view_rows)
@ -511,14 +512,14 @@ const cmds = struct {
self.menu.select_last(); self.menu.select_last();
} }
pub fn command_palette_menu_pageup(self: *Self, _: Ctx) tp.result { pub fn command_palette_menu_pageup(self: *Self, _: Ctx) Result {
if (self.view_pos > self.view_rows) if (self.view_pos > self.view_rows)
self.view_pos -= self.view_rows; self.view_pos -= self.view_rows;
try self.start_query(); try self.start_query();
self.menu.select_first(); self.menu.select_first();
} }
pub fn command_palette_menu_activate(self: *Self, _: Ctx) tp.result { pub fn command_palette_menu_activate(self: *Self, _: Ctx) Result {
self.menu.activate_selected(); self.menu.activate_selected();
} }
}; };

View file

@ -150,20 +150,20 @@ fn add_item(self: *Self, file_name: []const u8, matches: ?[]const u8) !void {
fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
if (try m.match(.{ "PRJ", tp.more })) { if (try m.match(.{ "PRJ", tp.more })) {
try self.process_project_manager(m); self.process_project_manager(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
return true; return true;
} }
return false; return false;
} }
fn process_project_manager(self: *Self, m: tp.message) tp.result { fn process_project_manager(self: *Self, m: tp.message) !void {
var file_name: []const u8 = undefined; var file_name: []const u8 = undefined;
var matches: []const u8 = undefined; var matches: []const u8 = undefined;
var query: []const u8 = undefined; var query: []const u8 = undefined;
if (try m.match(.{ "PRJ", "recent", tp.extract(&file_name), tp.extract_cbor(&matches) })) { if (try m.match(.{ "PRJ", "recent", tp.extract(&file_name), tp.extract_cbor(&matches) })) {
if (self.need_reset) self.reset_results(); if (self.need_reset) self.reset_results();
self.longest = @max(self.longest, file_name.len); self.longest = @max(self.longest, file_name.len);
self.add_item(file_name, matches) catch |e| return tp.exit_error(e); try self.add_item(file_name, matches);
self.menu.resize(.{ .y = 0, .x = 25, .w = @min(self.longest, max_menu_width) + 2 }); self.menu.resize(.{ .y = 0, .x = 25, .w = @min(self.longest, max_menu_width) + 2 });
if (self.need_select_first) { if (self.need_select_first) {
self.menu.select_down(); self.menu.select_down();
@ -173,7 +173,7 @@ fn process_project_manager(self: *Self, m: tp.message) tp.result {
} else if (try m.match(.{ "PRJ", "recent", tp.extract(&file_name) })) { } else if (try m.match(.{ "PRJ", "recent", tp.extract(&file_name) })) {
if (self.need_reset) self.reset_results(); if (self.need_reset) self.reset_results();
self.longest = @max(self.longest, file_name.len); self.longest = @max(self.longest, file_name.len);
self.add_item(file_name, null) catch |e| return tp.exit_error(e); try self.add_item(file_name, null);
self.menu.resize(.{ .y = 0, .x = 25, .w = @min(self.longest, max_menu_width) + 2 }); self.menu.resize(.{ .y = 0, .x = 25, .w = @min(self.longest, max_menu_width) + 2 });
if (self.need_select_first) { if (self.need_select_first) {
self.menu.select_down(); self.menu.select_down();
@ -198,14 +198,14 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var text: []const u8 = undefined; var text: []const u8 = undefined;
if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) { if (try m.match(.{ "I", tp.extract(&evtype), tp.extract(&keypress), tp.extract(&egc), tp.string, tp.extract(&modifiers) })) {
try self.mapEvent(evtype, keypress, egc, modifiers); self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
} else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) { } else if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
try self.insert_bytes(text); self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
return false; return false;
} }
fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) !void {
return switch (evtype) { return switch (evtype) {
event_type.PRESS => self.mapPress(keypress, egc, modifiers), event_type.PRESS => self.mapPress(keypress, egc, modifiers),
event_type.REPEAT => self.mapPress(keypress, egc, modifiers), event_type.REPEAT => self.mapPress(keypress, egc, modifiers),
@ -214,7 +214,7 @@ fn mapEvent(self: *Self, evtype: u32, keypress: u32, egc: u32, modifiers: u32) t
}; };
} }
fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) !void {
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress; const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
return switch (modifiers) { return switch (modifiers) {
mod.CTRL => switch (keynormal) { mod.CTRL => switch (keynormal) {
@ -271,7 +271,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
}; };
} }
fn mapRelease(self: *Self, keypress: u32, _: u32) tp.result { fn mapRelease(self: *Self, keypress: u32, _: u32) !void {
return switch (keypress) { return switch (keypress) {
key.LCTRL, key.RCTRL => if (self.menu.selected orelse 0 > 0) return self.cmd("open_recent_menu_activate", .{}), key.LCTRL, key.RCTRL => if (self.menu.selected orelse 0 > 0) return self.cmd("open_recent_menu_activate", .{}),
else => {}, else => {},
@ -285,13 +285,13 @@ fn reset_results(self: *Self) void {
self.need_select_first = true; self.need_select_first = true;
} }
fn start_query(self: *Self) tp.result { fn start_query(self: *Self) !void {
if (self.query_pending) return; if (self.query_pending) return;
self.query_pending = true; self.query_pending = true;
try project_manager.query_recent_files(max_recent_files, self.inputbox.text.items); try project_manager.query_recent_files(max_recent_files, self.inputbox.text.items);
} }
fn delete_word(self: *Self) tp.result { fn delete_word(self: *Self) !void {
if (std.mem.lastIndexOfAny(u8, self.inputbox.text.items, "/\\. -_")) |pos| { if (std.mem.lastIndexOfAny(u8, self.inputbox.text.items, "/\\. -_")) |pos| {
self.inputbox.text.shrinkRetainingCapacity(pos); self.inputbox.text.shrinkRetainingCapacity(pos);
} else { } else {
@ -301,7 +301,7 @@ fn delete_word(self: *Self) tp.result {
return self.start_query(); return self.start_query();
} }
fn delete_code_point(self: *Self) tp.result { fn delete_code_point(self: *Self) !void {
if (self.inputbox.text.items.len > 0) { if (self.inputbox.text.items.len > 0) {
self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - 1); self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - 1);
self.inputbox.cursor = self.inputbox.text.items.len; self.inputbox.cursor = self.inputbox.text.items.len;
@ -309,16 +309,16 @@ fn delete_code_point(self: *Self) tp.result {
return self.start_query(); return self.start_query();
} }
fn insert_code_point(self: *Self, c: u32) tp.result { fn insert_code_point(self: *Self, c: u32) !void {
var buf: [6]u8 = undefined; var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e); const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
self.inputbox.text.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e); try self.inputbox.text.appendSlice(buf[0..bytes]);
self.inputbox.cursor = self.inputbox.text.items.len; self.inputbox.cursor = self.inputbox.text.items.len;
return self.start_query(); return self.start_query();
} }
fn insert_bytes(self: *Self, bytes: []const u8) tp.result { fn insert_bytes(self: *Self, bytes: []const u8) !void {
self.inputbox.text.appendSlice(bytes) catch |e| return tp.exit_error(e); try self.inputbox.text.appendSlice(bytes);
self.inputbox.cursor = self.inputbox.text.items.len; self.inputbox.cursor = self.inputbox.text.items.len;
return self.start_query(); return self.start_query();
} }
@ -339,16 +339,17 @@ const Commands = command.Collection(cmds);
const cmds = struct { const cmds = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn open_recent_menu_down(self: *Self, _: Ctx) tp.result { pub fn open_recent_menu_down(self: *Self, _: Ctx) Result {
self.menu.select_down(); self.menu.select_down();
} }
pub fn open_recent_menu_up(self: *Self, _: Ctx) tp.result { pub fn open_recent_menu_up(self: *Self, _: Ctx) Result {
self.menu.select_up(); self.menu.select_up();
} }
pub fn open_recent_menu_activate(self: *Self, _: Ctx) tp.result { pub fn open_recent_menu_activate(self: *Self, _: Ctx) Result {
self.menu.activate_selected(); self.menu.activate_selected();
} }
}; };

View file

@ -71,8 +71,8 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
fn receive_log(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { fn receive_log(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var clear_msg_num: usize = 0; var clear_msg_num: usize = 0;
if (try m.match(.{ "log", tp.more })) { if (try m.match(.{ "log", tp.more })) {
logview.process_log(m) catch |e| return tp.exit_error(e); logview.process_log(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
self.process_log(m) catch |e| return tp.exit_error(e); self.process_log(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
return true; return true;
} else if (try m.match(.{ "MINILOG", tp.extract(&clear_msg_num) })) { } else if (try m.match(.{ "MINILOG", tp.extract(&clear_msg_num) })) {
if (clear_msg_num == self.msg_counter) if (clear_msg_num == self.msg_counter)

View file

@ -72,7 +72,7 @@ pub fn spawn(a: Allocator, ctx: *tp.context, eh: anytype, env: ?*const tp.env) !
fn start(args: StartArgs) tp.result { fn start(args: StartArgs) tp.result {
_ = tp.set_trap(true); _ = tp.set_trap(true);
var self = init(args.a) catch |e| return tp.exit_error(e); var self = init(args.a) catch |e| return tp.exit_error(e, @errorReturnTrace());
errdefer self.deinit(); errdefer self.deinit();
tp.receive(&self.receiver); tp.receive(&self.receiver);
} }
@ -144,7 +144,7 @@ fn init(a: Allocator) !*Self {
return self; return self;
} }
fn init_delayed(self: *Self) tp.result { fn init_delayed(self: *Self) !void {
if (self.input_mode) |_| {} else return cmds.enter_mode(self, command.Context.fmt(.{self.config.input_mode})); if (self.input_mode) |_| {} else return cmds.enter_mode(self, command.Context.fmt(.{self.config.input_mode}));
} }
@ -171,7 +171,7 @@ fn deinit(self: *Self) void {
fn listen_sigwinch(self: *Self) tp.result { fn listen_sigwinch(self: *Self) tp.result {
if (self.sigwinch_signal) |old| old.deinit(); if (self.sigwinch_signal) |old| old.deinit();
self.sigwinch_signal = tp.signal.init(std.posix.SIG.WINCH, tp.message.fmt(.{"sigwinch"})) catch |e| return tp.exit_error(e); self.sigwinch_signal = tp.signal.init(std.posix.SIG.WINCH, tp.message.fmt(.{"sigwinch"})) catch |e| return tp.exit_error(e, @errorReturnTrace());
} }
fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
@ -183,18 +183,18 @@ fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
self.receive_safe(from, m) catch |e| { self.receive_safe(from, m) catch |e| {
if (std.mem.eql(u8, "normal", tp.error_text())) if (std.mem.eql(u8, "normal", tp.error_text()))
return e; return error.Exit;
if (std.mem.eql(u8, "restart", tp.error_text())) if (std.mem.eql(u8, "restart", tp.error_text()))
return e; return error.Exit;
self.logger.err("UI", e); self.logger.err("UI", tp.exit_error(e, @errorReturnTrace()));
}; };
} }
fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) tp.result { fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
var input: []const u8 = undefined; var input: []const u8 = undefined;
var text: []const u8 = undefined; var text: []const u8 = undefined;
if (try m.match(.{ "VXS", tp.extract(&input), tp.extract(&text) })) { if (try m.match(.{ "VXS", tp.extract(&input), tp.extract(&text) })) {
self.rdr.process_input_event(input, if (text.len > 0) text else null) catch |e| return tp.exit_error(e); try self.rdr.process_input_event(input, if (text.len > 0) text else null);
try self.dispatch_flush_input_event(); try self.dispatch_flush_input_event();
if (self.unrendered_input_events_count > 0 and !self.frame_clock_running) if (self.unrendered_input_events_count > 0 and !self.frame_clock_running)
need_render(); need_render();
@ -355,10 +355,10 @@ fn render(self: *Self) void {
} }
} }
fn dispatch_flush_input_event(self: *Self) tp.result { fn dispatch_flush_input_event(self: *Self) !void {
var buf: [32]u8 = undefined; var buf: [32]u8 = undefined;
if (self.input_mode) |mode| if (self.input_mode) |mode|
try mode.handler.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{"F"}) catch |e| return tp.exit_error(e)); try mode.handler.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"}));
} }
fn dispatch_input(ctx: *anyopaque, cbor_msg: []const u8) void { fn dispatch_input(ctx: *anyopaque, cbor_msg: []const u8) void {
@ -383,10 +383,8 @@ fn dispatch_mouse(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) voi
const m: tp.message = .{ .buf = cbor_msg }; const m: tp.message = .{ .buf = cbor_msg };
const from = tp.self_pid(); const from = tp.self_pid();
self.unrendered_input_events_count += 1; self.unrendered_input_events_count += 1;
if (self.drag_source) |_| const send_func = if (self.drag_source) |_| &send_mouse_drag else &send_mouse;
self.send_mouse_drag(y, x, from, m) catch |e| self.logger.err("dispatch mouse", e) send_func(self, y, x, from, m) catch |e| self.logger.err("dispatch mouse", e);
else
self.send_mouse(y, x, from, m) catch |e| self.logger.err("dispatch mouse", e);
self.drag_source = null; self.drag_source = null;
} }
@ -462,16 +460,16 @@ fn send_mouse(self: *Self, y: c_int, x: c_int, from: tp.pid_ref, m: tp.message)
var buf: [256]u8 = undefined; var buf: [256]u8 = undefined;
if (self.hover_focus) |h| { if (self.hover_focus) |h| {
if (self.is_live_widget_ptr(h)) if (self.is_live_widget_ptr(h))
_ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e)); _ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
} }
self.hover_focus = w; self.hover_focus = w;
_ = try w.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", true }) catch |e| return tp.exit_error(e)); _ = try w.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", true }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
} }
_ = try w.send(from, m); _ = try w.send(from, m);
} else { } else {
if (self.hover_focus) |h| { if (self.hover_focus) |h| {
var buf: [256]u8 = undefined; var buf: [256]u8 = undefined;
_ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e)); _ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
} }
self.hover_focus = null; self.hover_focus = null;
} }
@ -488,15 +486,15 @@ fn send_mouse_drag(self: *Self, y: c_int, x: c_int, from: tp.pid_ref, m: tp.mess
var buf: [256]u8 = undefined; var buf: [256]u8 = undefined;
if (self.hover_focus) |h| { if (self.hover_focus) |h| {
if (self.is_live_widget_ptr(h)) if (self.is_live_widget_ptr(h))
_ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e)); _ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
} }
self.hover_focus = w; self.hover_focus = w;
_ = try w.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", true }) catch |e| return tp.exit_error(e)); _ = try w.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", true }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
} }
} else { } else {
if (self.hover_focus) |h| { if (self.hover_focus) |h| {
var buf: [256]u8 = undefined; var buf: [256]u8 = undefined;
_ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e)); _ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
} }
self.hover_focus = null; self.hover_focus = null;
} }
@ -510,83 +508,84 @@ pub fn save_config(self: *const Self) !void {
const cmds = struct { const cmds = struct {
pub const Target = Self; pub const Target = Self;
const Ctx = command.Context; const Ctx = command.Context;
const Result = command.Result;
pub fn restart(_: *Self, _: Ctx) tp.result { pub fn restart(_: *Self, _: Ctx) Result {
try tp.self_pid().send("restart"); try tp.self_pid().send("restart");
} }
pub fn theme_next(self: *Self, _: Ctx) tp.result { pub fn theme_next(self: *Self, _: Ctx) Result {
self.theme = get_next_theme_by_name(self.theme.name); self.theme = get_next_theme_by_name(self.theme.name);
self.config.theme = self.theme.name; self.config.theme = self.theme.name;
self.logger.print("theme: {s}", .{self.theme.description}); self.logger.print("theme: {s}", .{self.theme.description});
self.save_config() catch |e| return tp.exit_error(e); try self.save_config();
} }
pub fn theme_prev(self: *Self, _: Ctx) tp.result { pub fn theme_prev(self: *Self, _: Ctx) Result {
self.theme = get_prev_theme_by_name(self.theme.name); self.theme = get_prev_theme_by_name(self.theme.name);
self.config.theme = self.theme.name; self.config.theme = self.theme.name;
self.logger.print("theme: {s}", .{self.theme.description}); self.logger.print("theme: {s}", .{self.theme.description});
self.save_config() catch |e| return tp.exit_error(e); try self.save_config();
} }
pub fn toggle_whitespace(self: *Self, _: Ctx) tp.result { pub fn toggle_whitespace(self: *Self, _: Ctx) Result {
self.config.show_whitespace = !self.config.show_whitespace; self.config.show_whitespace = !self.config.show_whitespace;
self.logger.print("show_whitspace {s}", .{if (self.config.show_whitespace) "enabled" else "disabled"}); self.logger.print("show_whitspace {s}", .{if (self.config.show_whitespace) "enabled" else "disabled"});
self.save_config() catch |e| return tp.exit_error(e); try self.save_config();
var buf: [32]u8 = undefined; var buf: [32]u8 = undefined;
const m = tp.message.fmtbuf(&buf, .{ "show_whitespace", self.config.show_whitespace }) catch |e| return tp.exit_error(e); const m = try tp.message.fmtbuf(&buf, .{ "show_whitespace", self.config.show_whitespace });
_ = try self.send_widgets(tp.self_pid(), m); _ = try self.send_widgets(tp.self_pid(), m);
} }
pub fn toggle_input_mode(self: *Self, _: Ctx) tp.result { pub fn toggle_input_mode(self: *Self, _: Ctx) Result {
self.config.input_mode = if (std.mem.eql(u8, self.config.input_mode, "flow")) "vim/normal" else "flow"; self.config.input_mode = if (std.mem.eql(u8, self.config.input_mode, "flow")) "vim/normal" else "flow";
self.save_config() catch |e| return tp.exit_error(e); try self.save_config();
return enter_mode(self, Ctx.fmt(.{self.config.input_mode})); return enter_mode(self, Ctx.fmt(.{self.config.input_mode}));
} }
pub fn enter_mode(self: *Self, ctx: Ctx) tp.result { pub fn enter_mode(self: *Self, ctx: Ctx) Result {
var mode: []const u8 = undefined; var mode: []const u8 = undefined;
if (!try ctx.args.match(.{tp.extract(&mode)})) if (!try ctx.args.match(.{tp.extract(&mode)}))
return tp.exit_error(error.InvalidArgument); return tp.exit_error(error.InvalidArgument, null);
if (self.mini_mode) |_| try exit_mini_mode(self, .{}); if (self.mini_mode) |_| try exit_mini_mode(self, .{});
if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{}); if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{});
if (self.input_mode) |*m| m.deinit(); if (self.input_mode) |*m| m.deinit();
self.input_mode = if (std.mem.eql(u8, mode, "vim/normal")) self.input_mode = if (std.mem.eql(u8, mode, "vim/normal"))
@import("mode/input/vim/normal.zig").create(self.a) catch |e| return tp.exit_error(e) try @import("mode/input/vim/normal.zig").create(self.a)
else if (std.mem.eql(u8, mode, "vim/insert")) else if (std.mem.eql(u8, mode, "vim/insert"))
@import("mode/input/vim/insert.zig").create(self.a) catch |e| return tp.exit_error(e) try @import("mode/input/vim/insert.zig").create(self.a)
else if (std.mem.eql(u8, mode, "vim/visual")) else if (std.mem.eql(u8, mode, "vim/visual"))
@import("mode/input/vim/visual.zig").create(self.a) catch |e| return tp.exit_error(e) try @import("mode/input/vim/visual.zig").create(self.a)
else if (std.mem.eql(u8, mode, "flow")) else if (std.mem.eql(u8, mode, "flow"))
@import("mode/input/flow.zig").create(self.a) catch |e| return tp.exit_error(e) try @import("mode/input/flow.zig").create(self.a)
else if (std.mem.eql(u8, mode, "home")) else if (std.mem.eql(u8, mode, "home"))
@import("mode/input/home.zig").create(self.a) catch |e| return tp.exit_error(e) try @import("mode/input/home.zig").create(self.a)
else ret: { else ret: {
self.logger.print("unknown mode {s}", .{mode}); self.logger.print("unknown mode {s}", .{mode});
break :ret @import("mode/input/flow.zig").create(self.a) catch |e| return tp.exit_error(e); break :ret try @import("mode/input/flow.zig").create(self.a);
}; };
// self.logger.print("input mode: {s}", .{(self.input_mode orelse return).description}); // self.logger.print("input mode: {s}", .{(self.input_mode orelse return).description});
} }
pub fn enter_mode_default(self: *Self, _: Ctx) tp.result { pub fn enter_mode_default(self: *Self, _: Ctx) Result {
return enter_mode(self, Ctx.fmt(.{self.config.input_mode})); return enter_mode(self, Ctx.fmt(.{self.config.input_mode}));
} }
pub fn open_command_palette(self: *Self, _: Ctx) tp.result { pub fn open_command_palette(self: *Self, _: Ctx) Result {
if (self.mini_mode) |_| try exit_mini_mode(self, .{}); if (self.mini_mode) |_| try exit_mini_mode(self, .{});
if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{}); if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{});
self.input_mode_outer = self.input_mode; self.input_mode_outer = self.input_mode;
self.input_mode = @import("mode/overlay/command_palette.zig").create(self.a) catch |e| return tp.exit_error(e); self.input_mode = try @import("mode/overlay/command_palette.zig").create(self.a);
} }
pub fn open_recent(self: *Self, _: Ctx) tp.result { pub fn open_recent(self: *Self, _: Ctx) Result {
if (self.mini_mode) |_| try exit_mini_mode(self, .{}); if (self.mini_mode) |_| try exit_mini_mode(self, .{});
if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{}); if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{});
self.input_mode_outer = self.input_mode; self.input_mode_outer = self.input_mode;
self.input_mode = @import("mode/overlay/open_recent.zig").create(self.a) catch |e| return tp.exit_error(e); self.input_mode = try @import("mode/overlay/open_recent.zig").create(self.a);
} }
pub fn exit_overlay_mode(self: *Self, _: Ctx) tp.result { pub fn exit_overlay_mode(self: *Self, _: Ctx) Result {
if (self.input_mode_outer == null) return; if (self.input_mode_outer == null) return;
defer { defer {
self.input_mode = self.input_mode_outer; self.input_mode = self.input_mode_outer;
@ -595,29 +594,29 @@ const cmds = struct {
if (self.input_mode) |*mode| mode.deinit(); if (self.input_mode) |*mode| mode.deinit();
} }
pub fn enter_find_mode(self: *Self, ctx: Ctx) tp.result { pub fn enter_find_mode(self: *Self, ctx: Ctx) Result {
return enter_mini_mode(self, @import("mode/mini/find.zig"), ctx); return enter_mini_mode(self, @import("mode/mini/find.zig"), ctx);
} }
pub fn enter_find_in_files_mode(self: *Self, ctx: Ctx) tp.result { pub fn enter_find_in_files_mode(self: *Self, ctx: Ctx) Result {
return enter_mini_mode(self, @import("mode/mini/find_in_files.zig"), ctx); return enter_mini_mode(self, @import("mode/mini/find_in_files.zig"), ctx);
} }
pub fn enter_goto_mode(self: *Self, ctx: Ctx) tp.result { pub fn enter_goto_mode(self: *Self, ctx: Ctx) Result {
return enter_mini_mode(self, @import("mode/mini/goto.zig"), ctx); return enter_mini_mode(self, @import("mode/mini/goto.zig"), ctx);
} }
pub fn enter_move_to_char_mode(self: *Self, ctx: Ctx) tp.result { pub fn enter_move_to_char_mode(self: *Self, ctx: Ctx) Result {
return enter_mini_mode(self, @import("mode/mini/move_to_char.zig"), ctx); return enter_mini_mode(self, @import("mode/mini/move_to_char.zig"), ctx);
} }
pub fn enter_open_file_mode(self: *Self, ctx: Ctx) tp.result { pub fn enter_open_file_mode(self: *Self, ctx: Ctx) Result {
return enter_mini_mode(self, @import("mode/mini/open_file.zig"), ctx); return enter_mini_mode(self, @import("mode/mini/open_file.zig"), ctx);
} }
const MiniModeFactory = fn (Allocator, Ctx) error{ NotFound, OutOfMemory }!EventHandler; const MiniModeFactory = fn (Allocator, Ctx) error{ NotFound, OutOfMemory }!EventHandler;
fn enter_mini_mode(self: *Self, comptime mode: anytype, ctx: Ctx) tp.result { fn enter_mini_mode(self: *Self, comptime mode: anytype, ctx: Ctx) Result {
if (self.mini_mode) |_| try exit_mini_mode(self, .{}); if (self.mini_mode) |_| try exit_mini_mode(self, .{});
if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{}); if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{});
self.input_mode_outer = self.input_mode; self.input_mode_outer = self.input_mode;
@ -626,7 +625,7 @@ const cmds = struct {
self.input_mode_outer = null; self.input_mode_outer = null;
self.mini_mode = null; self.mini_mode = null;
} }
const mode_instance = mode.create(self.a, ctx) catch |e| return tp.exit_error(e); const mode_instance = try mode.create(self.a, ctx);
self.input_mode = .{ self.input_mode = .{
.handler = mode_instance.handler(), .handler = mode_instance.handler(),
.name = mode_instance.name(), .name = mode_instance.name(),
@ -635,7 +634,7 @@ const cmds = struct {
self.mini_mode = .{}; self.mini_mode = .{};
} }
pub fn exit_mini_mode(self: *Self, _: Ctx) tp.result { pub fn exit_mini_mode(self: *Self, _: Ctx) Result {
if (self.mini_mode) |_| {} else return; if (self.mini_mode) |_| {} else return;
defer { defer {
self.input_mode = self.input_mode_outer; self.input_mode = self.input_mode_outer;