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",
},
.thespian = .{
.url = "https://github.com/neurocyte/thespian/archive/3ace3163087a0260b30e2c420de76235dd82451f.tar.gz",
.hash = "1220ffbfff37c24b68424a3c9223cf57daed5debdbb6b7751a36b9dca318825cff4c",
.url = "https://github.com/neurocyte/thespian/archive/f1a89bdf9d9fac2cd7d6c1479e5bc99c8dd4c904.tar.gz",
.hash = "1220f1f69aaad041ca96e5a06fb14ff510c3775d809a37a83b8651e7f0f71be8deaf",
},
.themes = .{
.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 sp_tag = "child";
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) };
}
@ -27,23 +26,23 @@ pub fn term(self: *Self) void {
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" });
// defer frame.deinit();
var cb = std.ArrayList(u8).init(self.a);
defer cb.deinit();
cbor.writeValue(cb.writer(), m) catch |e| return tp.exit_error(e);
return self.pid.call(a, std.time.ns_per_s / 2, .{ "REQ", method, cb.items }) 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 });
}
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);
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);
}
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 });
}
@ -67,7 +66,7 @@ const Process = struct {
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;
if (try cmd.match(.{tp.extract(&tag)})) {
//
@ -92,7 +91,7 @@ const Process = struct {
.requests = std.AutoHashMap(i32, tp.pid).init(a),
.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 {
@ -126,17 +125,21 @@ const Process = struct {
const frame = tracy.initZone(@src(), .{ .name = module_name ++ " start" });
defer frame.deinit();
_ = 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);
var log_file_path = std.ArrayList(u8).init(self.a);
defer log_file_path.deinit();
const state_dir = root.get_state_dir() 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);
self.log_file = std.fs.createFileAbsolute(log_file_path.items, .{ .truncate = true }) 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, @errorReturnTrace());
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 {
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 });
defer frame.deinit();
errdefer self.deinit();
@ -146,9 +149,9 @@ const Process = struct {
var code: u32 = 0;
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) })) {
self.send_notification(method, bytes) catch |e| return tp.exit_error(e);
try self.send_notification(method, bytes);
} else if (try m.match(.{"close"})) {
self.write_log("### LSP close ###\n", .{});
try self.close();
@ -156,9 +159,9 @@ const Process = struct {
self.write_log("### LSP terminated ###\n", .{});
try self.term();
} 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) })) {
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) })) {
self.write_log("{s}\n", .{bytes});
} 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;
defer from.send(.{ "PRJ", "recent_done", query }) catch {};
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);
defer from.send(.{ "PRJ", "recent_done", query }) catch {};
var searcher = try fuzzig.Ascii.init(
var searcher = fuzzig.Ascii.init(
self.a,
std.fs.max_path_bytes, // haystack max size
std.fs.max_path_bytes, // needle max size
.{ .case_sensitive = false },
);
) catch |e| switch (e) {
error.OutOfMemory => @panic("OOM in fussiz.Ascii.init"),
else => |e_| return e_,
};
defer searcher.deinit();
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 {};
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)) {
const key = self.a.dupe(u8, file_path) catch |e| return tp.exit_error(e);
self.file_language_server.put(key, lsp) catch |e| return tp.exit_error(e);
const key = try self.a.dupe(u8, file_path);
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);
try lsp.send_notification("textDocument/didOpen", .{
.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 {
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);
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 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);
try lsp.send_notification("textDocument/didSave", .{
.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 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);
try lsp.send_notification("textDocument/didClose", .{
.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 {
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);
const response = try lsp.send_request(self.a, "textDocument/definition", .{
.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 {
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);
const response = try lsp.send_request(self.a, "textDocument/completion", .{
.textDocument = .{ .uri = uri },
@ -613,7 +616,7 @@ pub fn show_message(_: *Self, _: tp.pid_ref, params_cb: []const u8) !void {
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", .{
.processId = if (builtin.os.tag == .linux) std.os.linux.getpid() else null,
.rootPath = project_path,

View file

@ -7,7 +7,6 @@ const cbor = @import("cbor");
const Self = @This();
const module_name = @typeName(Self);
pub const Error = error{ OutOfMemory, Exit };
pub const Kind = enum { insert, delete };
pub const Edit = struct {
@ -19,7 +18,7 @@ pub const Edit = struct {
pid: ?tp.pid,
pub fn create() Error!Self {
pub fn create() !Self {
return .{ .pid = try Process.create() };
}
@ -39,14 +38,14 @@ const Process = struct {
const Receiver = tp.Receiver(*Process);
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);
self.* = .{
.arena = std.heap.ArenaAllocator.init(outer_a),
.a = self.arena.allocator(),
.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 {
@ -67,7 +66,7 @@ const Process = struct {
var root_src: usize = 0;
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"}))
tp.exit_normal();
}

View file

@ -3,7 +3,6 @@ const tp = @import("thespian");
const Self = @This();
const module_name = @typeName(Self);
pub const Error = error{ OutOfMemory, Exit };
pid: ?tp.pid,
@ -17,7 +16,7 @@ pub const Selection = struct {
end: Cursor = Cursor{},
};
pub fn create() Error!Self {
pub fn create() !Self {
return .{ .pid = try Process.create() };
}
@ -46,7 +45,7 @@ const Process = struct {
selection: ?Selection = null,
};
pub fn create() Error!tp.pid {
pub fn create() !tp.pid {
const self = try outer_a.create(Process);
self.* = .{
.arena = std.heap.ArenaAllocator.init(outer_a),
@ -55,7 +54,7 @@ const Process = struct {
.forwards = std.ArrayList(Entry).init(self.a),
.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 {
@ -87,6 +86,10 @@ const Process = struct {
}
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();
var c: Cursor = .{};
@ -106,9 +109,9 @@ const Process = struct {
tp.exit_normal();
}
fn update(self: *Process, entry_: Entry) tp.result {
fn update(self: *Process, entry_: Entry) !void {
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,
.selection = entry_.selection,
};
@ -129,7 +132,7 @@ const Process = struct {
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 }));
} 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 }));
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 {
_ = 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();
tp.receive(&this.receiver);
}
@ -135,15 +135,27 @@ pub const Logger = struct {
error.Exit => {
const msg_: tp.message = .{ .buf = tp.error_message() };
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;
}
if (msg__.len > buf.len) {
self.proc.send(.{ "log", "error", self.tag, context, "->", "MESSAGE TOO LARGE" }) catch {};
return;
}
const msg___ = buf[0..msg__.len];
@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 => {
msg = @errorName(e);

View file

@ -13,13 +13,13 @@ pid: tp.pid_ref,
const Self = @This();
const module_name = @typeName(Self);
pub fn get() error{Exit}!Self {
pub fn get() !Self {
const pid = tp.env.get().proc(module_name);
return if (pid.expired()) create() else .{ .pid = pid };
}
fn create() error{Exit}!Self {
const pid = Process.create() catch |e| return tp.exit_error(e);
fn create() !Self {
const pid = try Process.create();
defer pid.deinit();
tp.env.get().proc_set(module_name, pid.ref());
return .{ .pid = tp.env.get().proc(module_name) };
@ -34,35 +34,35 @@ pub fn shutdown() void {
pid.send(.{"shutdown"}) catch {};
}
pub fn open_cwd() tp.result {
pub fn open_cwd() !void {
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;
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);
dir.setAsCwd() catch |e| return tp.exit_error(e);
var dir = try std.fs.openDirAbsolute(project_directory, .{});
try dir.setAsCwd();
dir.close();
tp.env.get().str_set("project", project_directory);
return (try get()).pid.send(.{ "open", project_directory });
}
pub fn request_recent_files(max: usize) tp.result {
pub fn request_recent_files(max: usize) !void {
const project = tp.env.get().str("project");
if (project.len == 0)
return tp.exit("No project");
return (try get()).pid.send(.{ "request_recent_files", project, max });
}
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");
if (project.len == 0)
return tp.exit("No project");
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");
if (project.len == 0)
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 });
}
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");
if (project.len == 0)
return tp.exit("No project");
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");
if (project.len == 0)
return tp.exit("No project");
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");
if (project.len == 0)
return tp.exit("No project");
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");
if (project.len == 0)
return tp.exit("No project");
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");
if (project.len == 0)
return tp.exit("No project");
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");
if (project.len == 0)
return tp.exit("No project");
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");
if (project.len == 0)
return tp.exit("No project");
@ -140,7 +140,7 @@ const Process = struct {
.receiver = Receiver.init(Process.receive, self),
.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 {
@ -166,11 +166,11 @@ const Process = struct {
self.receive_safe(from, m) catch |e| {
if (std.mem.eql(u8, "normal", tp.error_text()))
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 path: []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) })) {
if (self.walker) |pid| pid.deinit();
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) })) {
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) })) {
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) })) {
@ -211,26 +211,26 @@ const Process = struct {
} else if (try m.match(.{ "child", tp.extract(&path), "done" })) {
self.logger.print_err("lsp-handling", "child '{s}' terminated", .{path});
} else if (try m.match(.{ "open", tp.extract(&project_directory) })) {
self.open(project_directory) catch |e| return from.forward_error(e);
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) })) {
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) })) {
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) })) {
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) })) {
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) })) {
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) })) {
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) })) {
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) })) {
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) })) {
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"})) {
if (self.walker) |pid| pid.send(.{"stop"}) catch {};
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) {
self.logger.print("opening: {s}", .{project_directory});
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 });
}
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" });
defer frame.deinit();
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);
}
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" });
defer frame.deinit();
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" });
defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
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" });
defer frame.deinit();
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
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" });
defer frame.deinit();
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" });
defer frame.deinit();
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" });
defer frame.deinit();
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");
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;
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"))
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"))
project.show_message(self.parent.ref(), params_cb) catch |e| tp.exit_error(e)
project.show_message(self.parent.ref(), params_cb)
else
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;
_ = project_directory;
_ = 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 {
a: std.mem.Allocator,
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 Receiver = tp.Receiver(*tree_walker);
fn spawn_link(a: std.mem.Allocator, root_path: []const u8) error{Exit}!tp.pid {
const self = a.create(tree_walker) catch |e| return tp.exit_error(e);
fn spawn_link(a: std.mem.Allocator, root_path: []const u8) !tp.pid {
const self = try a.create(tree_walker);
self.* = .{
.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(),
.receiver = Receiver.init(tree_walker.receive, self),
.dir = std.fs.cwd().openDir(self.root_path, .{ .iterate = true }) catch |e| return tp.exit_error(e),
.walker = walk_filtered(self.dir, self.a) catch |e| return tp.exit_error(e),
.dir = try std.fs.cwd().openDir(self.root_path, .{ .iterate = true }),
.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 {
@ -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" });
defer frame.deinit();
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 {
@ -456,7 +456,7 @@ fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) error{Exit}!tp
defer frame.deinit();
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"})) {
return tp.exit_normal();
} else {

View file

@ -11,9 +11,9 @@ stdin_behavior: std.process.Child.StdIo,
const Self = @This();
const module_name = @typeName(Self);
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 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;
@ -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);
}
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);
}
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 };
}
@ -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);
return bytes.len;
}
pub fn input(self: *const Self, bytes: []const u8) tp.result {
const pid = if (self.pid) |pid| pid else return tp.exit_error(error.Closed);
pub fn input(self: *const Self, bytes: []const u8) !void {
const pid = if (self.pid) |pid| pid else return error.Closed;
var remaining = bytes;
while (remaining.len > 0)
remaining = loop: {
@ -83,7 +83,7 @@ const Process = struct {
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);
self.* = .{
.a = a,
@ -95,7 +95,7 @@ const Process = struct {
.logger = log.logger(@typeName(Self)),
.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 {
@ -121,7 +121,7 @@ const Process = struct {
"--json",
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);
}
@ -130,14 +130,14 @@ const Process = struct {
var bytes: []u8 = "";
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);
} else if (try m.match(.{"close"})) {
try self.close();
} 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 })) {
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) })) {
self.logger.print("ERR: {s}", .{bytes});
} 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 {
var sfa = std.heap.stackFallback(4096, self.a);
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);
@memcpy(buf[0..m.buf.len], m.buf);
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_unknown = std.math.maxInt(ID);
pub const Result = anyerror!void;
pub const Context = struct {
args: tp.message = .{},
@ -29,7 +30,7 @@ pub fn Closure(comptime T: type) type {
f: FunT,
data: T,
const FunT: type = *const fn (T, ctx: Context) tp.result;
const FunT: type = *const fn (T, ctx: Context) Result;
const Self = @This();
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 {
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 {
@ -96,7 +97,7 @@ pub fn execute(id: ID, ctx: Context) tp.result {
const cmd = commands.items[id];
if (cmd) |p| {
// 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);
} else {
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 {
return struct {
const Fn = fn (T, Context) tp.result;
const Fn = fn (T, Context) anyerror!void;
name: [:0]const u8,
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 {
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) }))
return self.update_width();
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 {
var cb: []const u8 = undefined;
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 false;

View file

@ -189,24 +189,25 @@ const Commands = command.Collection(cmds);
const cmds = struct {
pub const Target = Self;
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();
}
pub fn home_menu_up(self: *Self, _: Ctx) tp.result {
pub fn home_menu_up(self: *Self, _: Ctx) Result {
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();
}
pub fn home_sheeran(self: *Self, _: Ctx) tp.result {
pub fn home_sheeran(self: *Self, _: Ctx) Result {
self.fire = if (self.fire) |*fire| ret: {
fire.deinit();
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 {
if (try m.match(.{ "M", tp.more })) return;
var buf: [4096]u8 = undefined;
const json = m.to_json(&buf) catch |e| return tp.exit_error(e);
self.append(json) 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, @errorReturnTrace());
}
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);
}
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;
if (self.panels) |panels| {
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;
}
} 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 {
const panels = WidgetList.createH(self.a, self.widgets.widget(), "panel", .{ .static = self.box().h / 5 }) catch |e| return tp.exit_error(e);
self.widgets.add(panels.widget()) catch |e| return tp.exit_error(e);
panels.add(view.create(self.a, self.widgets.plane) catch |e| return tp.exit_error(e)) catch |e| return tp.exit_error(e);
const panels = try WidgetList.createH(self.a, self.widgets.widget(), "panel", .{ .static = self.box().h / 5 });
try self.widgets.add(panels.widget());
try panels.add(try view.create(self.a, self.widgets.plane));
self.panels = panels;
}
tui.current().resize();
@ -141,11 +141,11 @@ fn close_all_panel_views(self: *Self) void {
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| {
self.widgets.remove(w.*);
} 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();
}
@ -153,23 +153,24 @@ fn toggle_view(self: *Self, view: anytype) tp.result {
const cmds = struct {
pub const Target = Self;
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())
return tp.exit("unsaved changes");
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");
}
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 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;
if (!try ctx.args.match(.{tp.extract(&project_dir)}))
return;
@ -177,7 +178,7 @@ const cmds = struct {
_ = 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();
const frame = tracy.initZone(@src(), .{ .name = "navigate" });
defer frame.deinit();
@ -192,27 +193,27 @@ const cmds = struct {
var len = len_;
while (len > 0) : (len -= 1) {
var field_name: []const u8 = undefined;
if (!(cbor.matchString(&iter, &field_name) catch |e| return tp.exit_error(e)))
return tp.exit_error(error.InvalidArgument);
if (!try cbor.matchString(&iter, &field_name))
return error.InvalidArgument;
if (std.mem.eql(u8, field_name, "line")) {
if (!(cbor.matchValue(&iter, cbor.extract(&line)) catch |e| return tp.exit_error(e)))
return tp.exit_error(error.InvalidArgument);
if (!try cbor.matchValue(&iter, cbor.extract(&line)))
return error.InvalidArgument;
} else if (std.mem.eql(u8, field_name, "column")) {
if (!(cbor.matchValue(&iter, cbor.extract(&column)) catch |e| return tp.exit_error(e)))
return tp.exit_error(error.InvalidArgument);
if (!try cbor.matchValue(&iter, cbor.extract(&column)))
return error.InvalidArgument;
} else if (std.mem.eql(u8, field_name, "file")) {
if (!(cbor.matchValue(&iter, cbor.extract(&file)) catch |e| return tp.exit_error(e)))
return tp.exit_error(error.InvalidArgument);
if (!try cbor.matchValue(&iter, cbor.extract(&file)))
return error.InvalidArgument;
} 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)))
return tp.exit_error(error.InvalidArgument);
if (!try cbor.matchValue(&iter, cbor.extract_cbor(&goto_args)))
return error.InvalidArgument;
} 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) {
file = file_name;
} else return tp.exit_error(error.InvalidArgument);
} else return error.InvalidArgument;
if (tp.env.get().str("project").len == 0) {
try open_project_cwd(self, .{});
@ -247,57 +248,57 @@ const cmds = struct {
tui.need_render();
}
pub fn open_help(self: *Self, _: Ctx) tp.result {
pub fn open_help(self: *Self, _: Ctx) Result {
tui.reset_drag_context();
try self.create_editor();
try command.executeName("open_scratch_buffer", command.fmt(.{ "help.md", @embedFile("help.md") }));
tui.need_render();
}
pub fn open_config(_: *Self, _: Ctx) tp.result {
const file_name = root.get_config_file_name() catch |e| return tp.exit_error(e);
pub fn open_config(_: *Self, _: Ctx) Result {
const file_name = try root.get_config_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();
self.read_restore_info() catch |e| return tp.exit_error(e);
try self.read_restore_info();
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);
}
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);
}
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);
}
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);
}
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);
}
pub fn jump_back(self: *Self, _: Ctx) tp.result {
pub fn jump_back(self: *Self, _: Ctx) Result {
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);
}
pub fn show_home(self: *Self, _: Ctx) tp.result {
pub fn show_home(self: *Self, _: Ctx) Result {
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();
var ln = tui_.config.gutter_line_numbers;
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_relative = lnr;
tui_.save_config() catch |e| return tp.exit_error(e);
try tui_.save_config();
if (self.widgets.get("editor_gutter")) |gutter_widget| {
const gutter = if (gutter_widget.dynamic_cast(@import("editor_gutter.zig"))) |p| p else return;
gutter.linenum = ln;
@ -387,8 +388,8 @@ fn location_jump(from: tp.pid_ref, file_path: []const u8, cursor: location_histo
} }) catch return;
}
fn clear_auto_find(self: *Self, editor: *ed.Editor) !void {
try editor.clear_matches();
fn clear_auto_find(self: *Self, editor: *ed.Editor) void {
editor.clear_matches();
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);
}
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 {};
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 {};
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);
if (editor_widget.get("editor")) |editor| {
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;
}
fn create_home(self: *Self) tp.result {
fn create_home(self: *Self) !void {
tui.reset_drag_context();
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);
self.widgets.replace(0, home_widget);
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;
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"})) {
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) })) {
try self.paste_bytes(text);
self.paste_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
return false;
}
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) {
event_type.PRESS => 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;
if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers);
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;
const ldr = if (self.leader) |leader| leader else return;
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) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
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)
try self.flush_input();
var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e);
const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
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)
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 command.executeName("paste", command.fmt(.{bytes}));
}
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) {
defer self.input.clearRetainingCapacity();
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}));
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;
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"})) {
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) })) {
try self.flush_input();
try self.insert_bytes(text);
try self.flush_input();
self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
}
return false;
}
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) {
event_type.PRESS => 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;
if (self.leader) |_| return self.mapFollower(keynormal, egc, modifiers);
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;
const ldr = if (self.leader) |leader| leader else return;
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) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
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)
try self.flush_input();
var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e);
const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
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)
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;
fn flush_input(self: *Self) tp.result {
fn flush_input(self: *Self) !void {
if (self.input.items.len > 0) {
defer self.input.clearRetainingCapacity();
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}));
self.last_cmd = "insert_chars";
@ -306,25 +306,26 @@ const Commands = command.Collection(cmds_);
const cmds_ = struct {
pub const Target = Self;
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", .{});
}
pub fn @"q"(self: *Self, _: Ctx) tp.result {
pub fn q(self: *Self, _: Ctx) Result {
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", .{});
}
pub fn @"wq"(self: *Self, _: Ctx) tp.result {
pub fn wq(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{});
try self.cmd("quit", .{});
}
pub fn @"wq!"(self: *Self, _: Ctx) tp.result {
pub fn @"wq!"(self: *Self, _: Ctx) Result {
self.cmd("save_file", .{}) catch {};
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;
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"})) {
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) })) {
try self.flush_input();
try self.insert_bytes(text);
try self.flush_input();
self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
}
return false;
}
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) {
event_type.PRESS => 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');
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
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
keypress == key.RCTRL 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) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}),
@ -416,27 +416,27 @@ fn add_count(self: *Self, value: usize) void {
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)
try self.flush_input();
var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e);
const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
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)
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;
fn flush_input(self: *Self) tp.result {
fn flush_input(self: *Self) !void {
if (self.input.items.len > 0) {
defer self.input.clearRetainingCapacity();
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}));
self.last_cmd = "insert_chars";
@ -610,25 +610,26 @@ const Commands = command.Collection(cmds_);
const cmds_ = struct {
pub const Target = Self;
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", .{});
}
pub fn @"q"(self: *Self, _: Ctx) tp.result {
pub fn q(self: *Self, _: Ctx) Result {
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", .{});
}
pub fn @"wq"(self: *Self, _: Ctx) tp.result {
pub fn wq(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{});
try self.cmd("quit", .{});
}
pub fn @"wq!"(self: *Self, _: Ctx) tp.result {
pub fn @"wq!"(self: *Self, _: Ctx) Result {
self.cmd("save_file", .{}) catch {};
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;
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"})) {
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) })) {
try self.flush_input();
try self.insert_bytes(text);
try self.flush_input();
self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
self.flush_input() catch |e| return tp.exit_error(e, @errorReturnTrace());
}
return false;
}
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) {
event_type.PRESS => 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');
const keynormal = if ('a' <= keypress and keypress <= 'z') keypress - ('a' - 'A') else keypress;
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
keypress == key.RCTRL 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) {
key.LCTRL, key.RCTRL => self.cmd("disable_fast_scroll", .{}),
key.LALT, key.RALT => self.cmd("disable_jump_mode", .{}),
@ -376,27 +376,27 @@ fn add_count(self: *Self, value: usize) void {
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)
try self.flush_input();
var buf: [6]u8 = undefined;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e);
self.input.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e);
const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
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)
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;
fn flush_input(self: *Self) tp.result {
fn flush_input(self: *Self) !void {
if (self.input.items.len > 0) {
defer self.input.clearRetainingCapacity();
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}));
self.last_cmd = "insert_chars";
@ -570,25 +570,26 @@ const Commands = command.Collection(cmds_);
const cmds_ = struct {
pub const Target = Self;
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", .{});
}
pub fn @"q"(self: *Self, _: Ctx) tp.result {
pub fn @"q"(self: *Self, _: Ctx) Result {
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", .{});
}
pub fn @"wq"(self: *Self, _: Ctx) tp.result {
pub fn @"wq"(self: *Self, _: Ctx) Result {
try self.cmd("save_file", .{});
try self.cmd("quit", .{});
}
pub fn @"wq!"(self: *Self, _: Ctx) tp.result {
pub fn @"wq!"(self: *Self, _: Ctx) Result {
self.cmd("save_file", .{}) catch {};
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) })) {
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"})) {
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) })) {
try self.insert_bytes(text);
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
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) {
event_type.PRESS => 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;
return switch (modifiers) {
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) {
key.LCTRL, key.RCTRL => 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)
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];
}
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)
try self.flush_input();
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;
fn flush_input(self: *Self) tp.result {
fn flush_input(self: *Self) !void {
if (self.input.len > 0) {
if (eql(u8, self.input, self.last_input))
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) })) {
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"})) {
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) })) {
try self.insert_bytes(text);
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
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) {
event_type.PRESS => 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;
return switch (modifiers) {
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) {
key.LCTRL, key.RCTRL => 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)
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];
}
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)
try self.flush_input();
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;
fn flush_input(self: *Self) tp.result {
fn flush_input(self: *Self) !void {
if (self.input.len > 0) {
if (eql(u8, self.input, self.last_input))
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) })) {
try self.mapEvent(evtype, keypress, egc, modifiers);
self.mapEvent(evtype, keypress, egc, modifiers) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
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) {
event_type.PRESS => 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;
return switch (modifiers) {
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;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e);
self.file_path.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e);
const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
try self.file_path.appendSlice(buf[0..bytes]);
}
fn insert_bytes(self: *Self, bytes: []const u8) tp.result {
self.file_path.appendSlice(bytes) catch |e| return tp.exit_error(e);
fn insert_bytes(self: *Self, bytes: []const u8) !void {
try self.file_path.appendSlice(bytes);
}
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 {
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;
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) })) {
try self.insert_bytes(text);
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
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) {
event_type.PRESS => 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;
return switch (modifiers) {
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) {
key.LCTRL, key.RCTRL => if (self.menu.selected orelse 0 > 0) return self.cmd("command_palette_menu_activate", .{}),
else => {},
};
}
fn start_query(self: *Self) tp.result {
fn start_query(self: *Self) !void {
self.items = 0;
self.menu.reset_items();
self.menu.selected = null;
@ -289,10 +289,10 @@ fn start_query(self: *Self) tp.result {
defer pos += 1;
if (pos < self.view_pos) continue;
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 {
_ = 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.do_resize();
@ -360,7 +360,7 @@ fn add_item(self: *Self, name: []const u8, id: command.ID, matches: ?[]const usi
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| {
self.inputbox.text.shrinkRetainingCapacity(pos);
} else {
@ -371,7 +371,7 @@ fn delete_word(self: *Self) tp.result {
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) {
self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - 1);
self.inputbox.cursor = self.inputbox.text.items.len;
@ -380,17 +380,17 @@ fn delete_code_point(self: *Self) tp.result {
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;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e);
self.inputbox.text.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e);
const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
try self.inputbox.text.appendSlice(buf[0..bytes]);
self.inputbox.cursor = self.inputbox.text.items.len;
self.view_pos = 0;
return self.start_query();
}
fn insert_bytes(self: *Self, bytes: []const u8) tp.result {
self.inputbox.text.appendSlice(bytes) catch |e| return tp.exit_error(e);
fn insert_bytes(self: *Self, bytes: []const u8) !void {
try self.inputbox.text.appendSlice(bytes);
self.inputbox.cursor = self.inputbox.text.items.len;
self.view_pos = 0;
return self.start_query();
@ -476,8 +476,9 @@ fn restore_state(self: *Self) !void {
const cmds = struct {
pub const Target = Self;
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 (selected == self.view_rows - 1) {
self.view_pos += 1;
@ -489,7 +490,7 @@ const cmds = struct {
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 (selected == 0 and self.view_pos > 0) {
self.view_pos -= 1;
@ -501,7 +502,7 @@ const cmds = struct {
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) {
self.view_pos += self.view_rows;
if (self.view_pos > self.total_items - self.view_rows)
@ -511,14 +512,14 @@ const cmds = struct {
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)
self.view_pos -= self.view_rows;
try self.start_query();
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();
}
};

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 {
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 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 matches: []const u8 = undefined;
var query: []const u8 = undefined;
if (try m.match(.{ "PRJ", "recent", tp.extract(&file_name), tp.extract_cbor(&matches) })) {
if (self.need_reset) self.reset_results();
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 });
if (self.need_select_first) {
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) })) {
if (self.need_reset) self.reset_results();
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 });
if (self.need_select_first) {
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;
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) })) {
try self.insert_bytes(text);
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
}
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) {
event_type.PRESS => 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;
return switch (modifiers) {
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) {
key.LCTRL, key.RCTRL => if (self.menu.selected orelse 0 > 0) return self.cmd("open_recent_menu_activate", .{}),
else => {},
@ -285,13 +285,13 @@ fn reset_results(self: *Self) void {
self.need_select_first = true;
}
fn start_query(self: *Self) tp.result {
fn start_query(self: *Self) !void {
if (self.query_pending) return;
self.query_pending = true;
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| {
self.inputbox.text.shrinkRetainingCapacity(pos);
} else {
@ -301,7 +301,7 @@ fn delete_word(self: *Self) tp.result {
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) {
self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - 1);
self.inputbox.cursor = self.inputbox.text.items.len;
@ -309,16 +309,16 @@ fn delete_code_point(self: *Self) tp.result {
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;
const bytes = ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e);
self.inputbox.text.appendSlice(buf[0..bytes]) catch |e| return tp.exit_error(e);
const bytes = try ucs32_to_utf8(&[_]u32{c}, &buf);
try self.inputbox.text.appendSlice(buf[0..bytes]);
self.inputbox.cursor = self.inputbox.text.items.len;
return self.start_query();
}
fn insert_bytes(self: *Self, bytes: []const u8) tp.result {
self.inputbox.text.appendSlice(bytes) catch |e| return tp.exit_error(e);
fn insert_bytes(self: *Self, bytes: []const u8) !void {
try self.inputbox.text.appendSlice(bytes);
self.inputbox.cursor = self.inputbox.text.items.len;
return self.start_query();
}
@ -339,16 +339,17 @@ const Commands = command.Collection(cmds);
const cmds = struct {
pub const Target = Self;
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();
}
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();
}
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();
}
};

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 {
var clear_msg_num: usize = 0;
if (try m.match(.{ "log", tp.more })) {
logview.process_log(m) catch |e| return tp.exit_error(e);
self.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, @errorReturnTrace());
return true;
} else if (try m.match(.{ "MINILOG", tp.extract(&clear_msg_num) })) {
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 {
_ = 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();
tp.receive(&self.receiver);
}
@ -144,7 +144,7 @@ fn init(a: Allocator) !*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}));
}
@ -171,7 +171,7 @@ fn deinit(self: *Self) void {
fn listen_sigwinch(self: *Self) tp.result {
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 {
@ -183,18 +183,18 @@ fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
self.receive_safe(from, m) catch |e| {
if (std.mem.eql(u8, "normal", tp.error_text()))
return e;
return error.Exit;
if (std.mem.eql(u8, "restart", tp.error_text()))
return e;
self.logger.err("UI", e);
return error.Exit;
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 text: []const u8 = undefined;
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();
if (self.unrendered_input_events_count > 0 and !self.frame_clock_running)
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;
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 {
@ -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 from = tp.self_pid();
self.unrendered_input_events_count += 1;
if (self.drag_source) |_|
self.send_mouse_drag(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);
const send_func = if (self.drag_source) |_| &send_mouse_drag else &send_mouse;
send_func(self, y, x, from, m) catch |e| self.logger.err("dispatch mouse", e);
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;
if (self.hover_focus) |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;
_ = 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);
} else {
if (self.hover_focus) |h| {
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;
}
@ -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;
if (self.hover_focus) |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;
_ = 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 {
if (self.hover_focus) |h| {
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;
}
@ -510,83 +508,84 @@ pub fn save_config(self: *const Self) !void {
const cmds = struct {
pub const Target = Self;
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");
}
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.config.theme = self.theme.name;
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.config.theme = self.theme.name;
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.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;
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);
}
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.save_config() catch |e| return tp.exit_error(e);
try self.save_config();
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;
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.input_mode_outer) |_| try exit_overlay_mode(self, .{});
if (self.input_mode) |*m| m.deinit();
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"))
@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"))
@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"))
@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"))
@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: {
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});
}
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}));
}
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.input_mode_outer) |_| try exit_overlay_mode(self, .{});
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.input_mode_outer) |_| try exit_overlay_mode(self, .{});
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;
defer {
self.input_mode = self.input_mode_outer;
@ -595,29 +594,29 @@ const cmds = struct {
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);
}
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);
}
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);
}
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);
}
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);
}
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.input_mode_outer) |_| try exit_overlay_mode(self, .{});
self.input_mode_outer = self.input_mode;
@ -626,7 +625,7 @@ const cmds = struct {
self.input_mode_outer = 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 = .{
.handler = mode_instance.handler(),
.name = mode_instance.name(),
@ -635,7 +634,7 @@ const cmds = struct {
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;
defer {
self.input_mode = self.input_mode_outer;