Compare commits

...

2 commits

13 changed files with 119 additions and 53 deletions

View file

@ -167,7 +167,7 @@ fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadE
return binding_set;
}
const LoadError = (error{ NotFound, NotAnObject } || std.json.ParseError(std.json.Scanner) || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError);
pub const LoadError = (error{ NotFound, NotAnObject } || std.json.ParseError(std.json.Scanner) || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError);
///A collection of modes that represent a switchable editor emulation
const Namespace = struct {

View file

@ -16,7 +16,7 @@ pub const Selection = struct {
end: Cursor = Cursor{},
};
pub fn create() !Self {
pub fn create() error{ OutOfMemory, ThespianSpawnFailed }!Self {
return .{ .pid = try Process.create() };
}
@ -45,7 +45,7 @@ const Process = struct {
selection: ?Selection = null,
};
pub fn create() !tp.pid {
pub fn create() error{ OutOfMemory, ThespianSpawnFailed }!tp.pid {
const self = try outer_a.create(Process);
self.* = .{
.arena = std.heap.ArenaAllocator.init(outer_a),

View file

@ -551,7 +551,9 @@ fn read_nested_include_files(T: type, allocator: std.mem.Allocator, conf: *T, bu
};
}
pub fn write_config(conf: anytype, allocator: std.mem.Allocator) !void {
pub const ConfigWriteError = error{ CreateConfigFileFailed, WriteConfigFileFailed };
pub fn write_config(conf: anytype, allocator: std.mem.Allocator) (ConfigDirError || ConfigWriteError)!void {
config_mutex.lock();
defer config_mutex.unlock();
_ = allocator;
@ -560,14 +562,20 @@ pub fn write_config(conf: anytype, allocator: std.mem.Allocator) !void {
// return write_json_file(@TypeOf(conf), conf, allocator, try get_app_config_file_name(application_name, @typeName(@TypeOf(conf))));
}
fn write_text_config_file(comptime T: type, data: T, file_name: []const u8) !void {
var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true });
fn write_text_config_file(comptime T: type, data: T, file_name: []const u8) ConfigWriteError!void {
var file = std.fs.createFileAbsolute(file_name, .{ .truncate = true }) catch |e| {
std.log.err("createFileAbsolute failed with {any} for: {s}", .{ e, file_name });
return error.CreateConfigFileFailed;
};
defer file.close();
const writer = file.writer();
return write_config_to_writer(T, data, writer);
write_config_to_writer(T, data, writer) catch |e| {
std.log.err("write file failed with {any} for: {s}", .{ e, file_name });
return error.WriteConfigFileFailed;
};
}
pub fn write_config_to_writer(comptime T: type, data: T, writer: anytype) !void {
pub fn write_config_to_writer(comptime T: type, data: T, writer: anytype) @TypeOf(writer).Error!void {
const default: T = .{};
inline for (@typeInfo(T).@"struct".fields) |field_info| {
if (config_eql(
@ -650,7 +658,15 @@ pub fn get_config_dir() ![]const u8 {
return get_app_config_dir(application_name);
}
fn get_app_config_dir(appname: []const u8) ![]const u8 {
pub const ConfigDirError = error{
NoSpaceLeft,
MakeConfigDirFailed,
MakeHomeConfigDirFailed,
MakeAppConfigDirFailed,
AppConfigDirUnavailable,
};
fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
const a = std.heap.c_allocator;
const local = struct {
var config_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
@ -666,7 +682,7 @@ fn get_app_config_dir(appname: []const u8) ![]const u8 {
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config", .{home});
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
error.PathAlreadyExists => {},
else => return e,
else => return error.MakeHomeConfigDirFailed,
};
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config/{s}", .{ home, appname });
} else if (builtin.os.tag == .windows) ret: {
@ -675,7 +691,7 @@ fn get_app_config_dir(appname: []const u8) ![]const u8 {
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ appdata, appname });
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
error.PathAlreadyExists => {},
else => return e,
else => return error.MakeAppConfigDirFailed,
};
break :ret dir;
} else return error.AppConfigDirUnavailable;
@ -684,7 +700,7 @@ fn get_app_config_dir(appname: []const u8) ![]const u8 {
local.config_dir = config_dir;
std.fs.makeDirAbsolute(config_dir) catch |e| switch (e) {
error.PathAlreadyExists => {},
else => return e,
else => return error.MakeConfigDirFailed,
};
var keybind_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
@ -784,11 +800,11 @@ fn get_app_state_dir(appname: []const u8) ![]const u8 {
return state_dir;
}
fn get_app_config_file_name(appname: []const u8, comptime base_name: []const u8) ![]const u8 {
fn get_app_config_file_name(appname: []const u8, comptime base_name: []const u8) ConfigDirError![]const u8 {
return get_app_config_dir_file_name(appname, base_name ++ ".json");
}
fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name: []const u8) ![]const u8 {
fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name: []const u8) ConfigDirError![]const u8 {
const local = struct {
var config_file_buffer: [std.posix.PATH_MAX]u8 = undefined;
};

View file

@ -41,7 +41,20 @@ logger: log.Logger,
loop: Loop,
pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool, _: *const fn (ctx: *anyopaque) void) !Self {
pub const Error = error{
UnexpectedRendererEvent,
OutOfMemory,
IntegerTooLarge,
IntegerTooSmall,
InvalidType,
TooShort,
Utf8CannotEncodeSurrogateHalf,
CodepointTooLarge,
TtyInitError,
TtyWriteError,
} || std.Thread.SpawnError;
pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool, _: *const fn (ctx: *anyopaque) void) Error!Self {
const opts: vaxis.Vaxis.Options = .{
.kitty_keyboard_flags = .{
.disambiguate = true,
@ -54,7 +67,7 @@ pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate:
};
return .{
.allocator = allocator,
.tty = try vaxis.Tty.init(),
.tty = vaxis.Tty.init() catch return error.TtyInitError,
.vx = try vaxis.init(allocator, opts),
.no_alternate = no_alternate,
.event_buffer = std.ArrayList(u8).init(allocator),
@ -93,19 +106,19 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_
return std.debug.defaultPanic(msg, ret_addr orelse @returnAddress());
}
pub fn run(self: *Self) !void {
pub fn run(self: *Self) Error!void {
self.vx.sgr = .legacy;
self.vx.conpty_hacks = true;
panic_cleanup = .{ .allocator = self.allocator, .tty = &self.tty, .vx = &self.vx };
if (!self.no_alternate) try self.vx.enterAltScreen(self.tty.anyWriter());
if (!self.no_alternate) self.vx.enterAltScreen(self.tty.anyWriter()) catch return error.TtyWriteError;
if (builtin.os.tag == .windows) {
try self.resize(.{ .rows = 25, .cols = 80, .x_pixel = 0, .y_pixel = 0 }); // dummy resize to fully init vaxis
} else {
try self.sigwinch();
self.sigwinch() catch return error.TtyWriteError;
}
try self.vx.setBracketedPaste(self.tty.anyWriter(), true);
try self.vx.queryTerminalSend(self.tty.anyWriter());
self.vx.setBracketedPaste(self.tty.anyWriter(), true) catch return error.TtyWriteError;
self.vx.queryTerminalSend(self.tty.anyWriter()) catch return error.TtyWriteError;
self.loop = Loop.init(&self.tty, &self.vx);
try self.loop.start();
@ -122,8 +135,8 @@ pub fn sigwinch(self: *Self) !void {
try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking()));
}
fn resize(self: *Self, ws: vaxis.Winsize) !void {
try self.vx.resize(self.allocator, self.tty.anyWriter(), ws);
fn resize(self: *Self, ws: vaxis.Winsize) error{ TtyWriteError, OutOfMemory }!void {
self.vx.resize(self.allocator, self.tty.anyWriter(), ws) catch return error.TtyWriteError;
self.vx.queueRefresh();
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"resize"}));
}
@ -147,7 +160,7 @@ pub fn input_fd_blocking(self: Self) i32 {
return self.tty.fd;
}
pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
var input_: []const u8 = undefined;
var text_: []const u8 = undefined;
if (!try cbor.match(msg, .{ "RDR", cbor.extract(&input_), cbor.extract(&text_) }))
@ -268,7 +281,7 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
.cap_da1 => {
self.queries_done = true;
self.vx.enableDetectedFeatures(self.tty.anyWriter()) catch |e| self.logger.err("enable features", e);
try self.vx.setMouseMode(self.tty.anyWriter(), true);
self.vx.setMouseMode(self.tty.anyWriter(), true) catch return error.TtyWriteError;
},
.cap_kitty_keyboard => {
self.logger.print("kitty keyboard capability detected", .{});
@ -287,7 +300,7 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
}
}
fn fmtmsg(self: *Self, value: anytype) ![]const u8 {
fn fmtmsg(self: *Self, value: anytype) std.ArrayList(u8).Writer.Error![]const u8 {
self.event_buffer.clearRetainingCapacity();
try cbor.writeValue(self.event_buffer.writer(), value);
return self.event_buffer.items;
@ -329,7 +342,7 @@ fn handle_bracketed_paste_end(self: *Self) !void {
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", self.bracketed_paste_buffer.items }));
}
fn handle_bracketed_paste_error(self: *Self, e: anytype) !void {
fn handle_bracketed_paste_error(self: *Self, e: Error) !void {
self.logger.err("bracketed paste", e);
self.bracketed_paste_buffer.clearAndFree();
self.bracketed_paste = false;
@ -508,7 +521,7 @@ const Loop = struct {
}
/// spawns the input thread to read input from the tty
pub fn start(self: *Loop) !void {
pub fn start(self: *Loop) std.Thread.SpawnError!void {
if (self.thread) |_| return;
self.thread = try std.Thread.spawn(.{}, Loop.ttyRun, .{self});
}

View file

@ -20,6 +20,18 @@ const DropWriter = gui.DropWriter;
pub const style = StyleBits;
pub const styles = @import("tuirenderer").styles;
pub const Error = error{
UnexpectedRendererEvent,
OutOfMemory,
IntegerTooLarge,
IntegerTooSmall,
InvalidType,
TooShort,
Utf8CannotEncodeSurrogateHalf,
CodepointTooLarge,
VaxisResizeError,
} || std.Thread.SpawnError;
pub const panic = messageBoxThenPanic(.{ .title = "Flow Panic" });
threadlocal var thread_is_panicing = false;
@ -80,7 +92,7 @@ pub fn init(
handler_ctx: *anyopaque,
no_alternate: bool,
dispatch_initialized: *const fn (ctx: *anyopaque) void,
) !Self {
) Error!Self {
std.debug.assert(!global.init_called);
global.init_called = true;
@ -116,16 +128,16 @@ pub fn deinit(self: *Self) void {
self.title_buf.deinit();
}
pub fn run(self: *Self) !void {
pub fn run(self: *Self) Error!void {
if (self.thread) |_| return;
// dummy resize to fully init vaxis
const drop_writer = DropWriter{};
try self.vx.resize(
self.vx.resize(
self.allocator,
drop_writer.writer().any(),
.{ .rows = 25, .cols = 80, .x_pixel = 0, .y_pixel = 0 },
);
) catch return error.VaxisResizeError;
self.thread = try gui.start();
}
@ -164,7 +176,7 @@ pub fn stdplane(self: *Self) Plane {
return plane;
}
pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
const Input = struct {
kind: u8,
codepoint: u21,

View file

@ -43,7 +43,7 @@ pub fn main() anyerror!void {
try cbor.writeValue(writer, "highlights");
try cbor.writeValue(writer, highlights_cb);
std.log.info("file_type {s} highlights {d} bytes", .{ file_type.name, highlights_cb.len });
// std.log.info("file_type {s} highlights {d} bytes", .{ file_type.name, highlights_cb.len });
if (file_type.injections) |injections| {
const injections_in = try treez.Query.create(lang, injections);
@ -54,12 +54,12 @@ pub fn main() anyerror!void {
try cbor.writeValue(writer, "injections");
try cbor.writeValue(writer, injections_cb);
std.log.info("file_type {s} injections {d} bytes", .{ file_type.name, injections_cb.len });
// std.log.info("file_type {s} injections {d} bytes", .{ file_type.name, injections_cb.len });
}
}
try output_file.writeAll(output.items);
std.log.info("file_types total {d} bytes", .{output.items.len});
// std.log.info("file_types total {d} bytes", .{output.items.len});
}
fn fatal(comptime format: []const u8, args: anytype) noreturn {

View file

@ -31,7 +31,7 @@ on_render: *const fn (ctx: ?*anyopaque, theme: *const Widget.Theme) void = on_re
after_render: *const fn (ctx: ?*anyopaque, theme: *const Widget.Theme) void = on_render_default,
on_resize: *const fn (ctx: ?*anyopaque, self: *Self, pos_: Widget.Box) void = on_resize_default,
pub fn createH(allocator: Allocator, parent: Plane, name: [:0]const u8, layout_: Layout) !*Self {
pub fn createH(allocator: Allocator, parent: Plane, name: [:0]const u8, layout_: Layout) error{OutOfMemory}!*Self {
const self: *Self = try allocator.create(Self);
self.* = try init(allocator, parent, name, .horizontal, layout_, Box{});
self.plane.hide();

View file

@ -60,7 +60,9 @@ const FileListType = enum {
find_in_files,
};
pub fn create(allocator: std.mem.Allocator) !Widget {
pub const CreateError = error{ OutOfMemory, ThespianSpawnFailed };
pub fn create(allocator: std.mem.Allocator) CreateError!Widget {
const self = try allocator.create(Self);
self.* = .{
.allocator = allocator,

View file

@ -8,13 +8,17 @@ const Plane = @import("renderer").Plane;
pub const Style = enum { none, grip };
pub fn create(allocator: std.mem.Allocator, parent: Plane, config: []const u8, style: Style, event_handler: ?EventHandler) !Widget {
pub fn create(allocator: std.mem.Allocator, parent: Plane, config: []const u8, style: Style, event_handler: ?EventHandler) error{OutOfMemory}!Widget {
var w = try WidgetList.createH(allocator, parent, "statusbar", .{ .static = 1 });
if (style == .grip) w.after_render = render_grip;
w.ctx = w;
var it = std.mem.splitScalar(u8, config, ' ');
while (it.next()) |widget_name|
try w.add(try status_widget.create(widget_name, allocator, w.plane, event_handler) orelse continue);
while (it.next()) |widget_name| {
try w.add(status_widget.create(widget_name, allocator, w.plane, event_handler) catch |e| switch (e) {
error.OutOfMemory => return error.OutOfMemory,
error.WidgetInitFailed => null,
} orelse continue);
}
return w.widget();
}

View file

@ -19,14 +19,20 @@ tz: zeit.timezone.TimeZone,
const Self = @This();
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
var env = std.process.getEnvMap(allocator) catch |e| return tp.exit_error(e, @errorReturnTrace());
var env = std.process.getEnvMap(allocator) catch |e| {
std.log.err("clock: std.process.getEnvMap failed with {any}", .{e});
return error.WidgetInitFailed;
};
defer env.deinit();
const self: *Self = try allocator.create(Self);
self.* = .{
.allocator = allocator,
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
.on_event = event_handler,
.tz = zeit.local(allocator, &env) catch |e| return tp.exit_error(e, @errorReturnTrace()),
.tz = zeit.local(allocator, &env) catch |e| {
std.log.err("clock: zeit.local failed with {any}", .{e});
return error.WidgetInitFailed;
},
};
try tui.message_filters().add(MessageFilter.bind(self, receive_tick));
self.update_tick_timer(.init);

View file

@ -35,7 +35,7 @@ pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?Event
};
logview.init(allocator);
try tui.message_filters().add(MessageFilter.bind(self, receive_log));
try log.subscribe();
log.subscribe() catch return error.WidgetInitFailed;
return Widget.to(self);
}

View file

@ -20,7 +20,7 @@ const widgets = std.static_string_map.StaticStringMap(CreateFunction).initCompti
.{ "keybind", @import("keybindstate.zig").create },
.{ "tabs", @import("tabs.zig").create },
});
pub const CreateError = error{ OutOfMemory, Exit };
pub const CreateError = error{ OutOfMemory, WidgetInitFailed };
pub const CreateFunction = *const fn (allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!Widget;
pub fn create(name: []const u8, allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!?Widget {

View file

@ -84,11 +84,24 @@ fn start(args: StartArgs) tp.result {
tp.receive(&self.receiver);
}
fn init(allocator: Allocator) !*Self {
const InitError = error{
OutOfMemory,
UnknownTheme,
ThespianMetronomeInitFailed,
ThespianMetronomeStartFailed,
ThespianTimeoutInitFailed,
ThespianSignalInitFailed,
ThespianSpawnFailed,
} || renderer.Error ||
root.ConfigDirError ||
root.ConfigWriteError ||
keybind.LoadError;
fn init(allocator: Allocator) InitError!*Self {
var conf, const conf_bufs = root.read_config(@import("config"), allocator);
defer root.free_config(allocator, conf_bufs);
const theme_ = get_theme_by_name(conf.theme) orelse get_theme_by_name("dark_modern") orelse return tp.exit("unknown theme");
const theme_ = get_theme_by_name(conf.theme) orelse get_theme_by_name("dark_modern") orelse return error.UnknownTheme;
conf.theme = theme_.name;
conf.whitespace_mode = try allocator.dupe(u8, conf.whitespace_mode);
conf.input_mode = try allocator.dupe(u8, conf.input_mode);
@ -161,7 +174,7 @@ fn init(allocator: Allocator) !*Self {
return self;
}
fn init_input_namespace(self: *Self) !void {
fn init_input_namespace(self: *Self) InitError!void {
var mode_parts = std.mem.splitScalar(u8, self.config_.input_mode, '/');
const namespace_name = mode_parts.first();
keybind.set_namespace(namespace_name) catch {
@ -172,7 +185,7 @@ fn init_input_namespace(self: *Self) !void {
};
}
fn init_delayed(self: *Self) !void {
fn init_delayed(self: *Self) command.Result {
self.delayed_init_done = true;
if (self.input_mode_) |_| {} else {
if (self.delayed_init_input_mode) |delayed_init_input_mode| {
@ -218,9 +231,9 @@ fn deinit(self: *Self) void {
self.allocator.destroy(self);
}
fn listen_sigwinch(self: *Self) tp.result {
fn listen_sigwinch(self: *Self) error{ThespianSignalInitFailed}!void {
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, @errorReturnTrace());
self.sigwinch_signal = try tp.signal.init(std.posix.SIG.WINCH, tp.message.fmt(.{"sigwinch"}));
}
fn update_mouse_idle_timer(self: *Self) void {
@ -465,7 +478,7 @@ fn active_event_handler(self: *Self) ?EventHandler {
return mode.event_handler orelse mode.input_handler;
}
fn dispatch_flush_input_event(self: *Self) !void {
fn dispatch_flush_input_event(self: *Self) error{ Exit, NoSpaceLeft }!void {
var buf: [32]u8 = undefined;
const mode = self.input_mode_ orelse return;
try mode.input_handler.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"}));
@ -627,7 +640,7 @@ pub fn refresh_hover() void {
_ = self.update_hover(self.last_hover_y, self.last_hover_x) catch {};
}
pub fn save_config() !void {
pub fn save_config() (root.ConfigDirError || root.ConfigWriteError)!void {
const self = current();
try root.write_config(self.config_, self.allocator);
}