refactor: improve capsulation and safety of tui module public api
This commit is contained in:
parent
4145460012
commit
1d947ab499
28 changed files with 239 additions and 198 deletions
|
@ -125,7 +125,7 @@ pub fn State(ctx_type: type) type {
|
|||
tui.need_render();
|
||||
return true;
|
||||
} else if (try m.match(.{ "H", tp.extract(&self.hover) })) {
|
||||
tui.current().rdr.request_mouse_cursor_pointer(self.hover);
|
||||
tui.rdr().request_mouse_cursor_pointer(self.hover);
|
||||
tui.need_render();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -36,10 +36,9 @@ pub fn Options(context: type) type {
|
|||
}
|
||||
if (self.cursor) |cursor| {
|
||||
const pos: c_int = @intCast(cursor);
|
||||
const tui_ = tui.current();
|
||||
if (tui_.config.enable_terminal_cursor) {
|
||||
if (tui.config().enable_terminal_cursor) {
|
||||
const y, const x = self.plane.rel_yx_to_abs(0, pos + 1);
|
||||
tui_.rdr.cursor_enable(y, x, tui_.get_cursor_shape()) catch {};
|
||||
tui.rdr().cursor_enable(y, x, tui.get_cursor_shape()) catch {};
|
||||
} else {
|
||||
self.plane.cursor_move_yx(0, pos + 1) catch return false;
|
||||
var cell = self.plane.cell_init();
|
||||
|
@ -119,7 +118,7 @@ pub fn State(ctx_type: type) type {
|
|||
tui.need_render();
|
||||
return true;
|
||||
} else if (try m.match(.{ "H", tp.extract(&self.hover) })) {
|
||||
tui.current().rdr.request_mouse_cursor_pointer(self.hover);
|
||||
tui.rdr().request_mouse_cursor_pointer(self.hover);
|
||||
tui.need_render();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ pub fn create(ctx_type: type, allocator: std.mem.Allocator, parent: Widget, opts
|
|||
.allocator = allocator,
|
||||
.plane = parent.plane.*,
|
||||
.opts = opts,
|
||||
.fade_time_ms = tui.current().config.animation_max_lag,
|
||||
.fade_time_ms = tui.config().animation_max_lag,
|
||||
.frame_rate = @intCast(tp.env.get().num("frame-rate")),
|
||||
};
|
||||
return self;
|
||||
|
@ -106,7 +106,7 @@ pub fn State(ctx_type: type) type {
|
|||
self.call_click_handler(@enumFromInt(btn));
|
||||
return true;
|
||||
} else if (try m.match(.{ "H", tp.extract(&self.hover) })) {
|
||||
tui.current().rdr.request_mouse_cursor_default(self.hover);
|
||||
tui.rdr().request_mouse_cursor_default(self.hover);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -98,7 +98,7 @@ pub const CurSel = struct {
|
|||
}
|
||||
|
||||
fn enable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection {
|
||||
return switch (tui.current().get_selection_style()) {
|
||||
return switch (tui.get_selection_style()) {
|
||||
.normal => self.enable_selection_normal(),
|
||||
.inclusive => try self.enable_selection_inclusive(root, metrics),
|
||||
};
|
||||
|
@ -131,7 +131,7 @@ pub const CurSel = struct {
|
|||
}
|
||||
|
||||
fn disable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
|
||||
switch (tui.current().get_selection_style()) {
|
||||
switch (tui.get_selection_style()) {
|
||||
.normal => self.disable_selection_normal(),
|
||||
.inclusive => self.disable_selection_inclusive(root, metrics),
|
||||
}
|
||||
|
@ -404,8 +404,8 @@ pub const Editor = struct {
|
|||
fn init(self: *Self, allocator: Allocator, n: Plane, buffer_manager: *Buffer.Manager) void {
|
||||
const logger = log.logger("editor");
|
||||
const frame_rate = tp.env.get().num("frame-rate");
|
||||
const indent_size = tui.current().config.indent_size;
|
||||
const tab_width = tui.current().config.tab_width;
|
||||
const indent_size = tui.config().indent_size;
|
||||
const tab_width = tui.config().tab_width;
|
||||
self.* = Self{
|
||||
.allocator = allocator,
|
||||
.plane = n,
|
||||
|
@ -423,8 +423,8 @@ pub const Editor = struct {
|
|||
.cursels = CurSel.List.init(allocator),
|
||||
.cursels_saved = CurSel.List.init(allocator),
|
||||
.matches = Match.List.init(allocator),
|
||||
.enable_terminal_cursor = tui.current().config.enable_terminal_cursor,
|
||||
.render_whitespace = from_whitespace_mode(tui.current().config.whitespace_mode),
|
||||
.enable_terminal_cursor = tui.config().enable_terminal_cursor,
|
||||
.render_whitespace = from_whitespace_mode(tui.config().whitespace_mode),
|
||||
.diagnostics = std.ArrayList(Diagnostic).init(allocator),
|
||||
};
|
||||
}
|
||||
|
@ -555,7 +555,7 @@ pub const Editor = struct {
|
|||
self.buffer = null;
|
||||
self.plane.erase();
|
||||
self.plane.home();
|
||||
tui.current().rdr.cursor_disable();
|
||||
tui.rdr().cursor_disable();
|
||||
_ = try self.handlers.msg(.{ "E", "close" });
|
||||
if (self.syntax) |_| if (self.file_path) |file_path|
|
||||
project_manager.did_close(file_path) catch {};
|
||||
|
@ -933,7 +933,7 @@ pub const Editor = struct {
|
|||
return Buffer.Walker.keep_walking;
|
||||
}
|
||||
};
|
||||
const hl_row: ?usize = if (tui.current().config.highlight_current_line) blk: {
|
||||
const hl_row: ?usize = if (tui.config().highlight_current_line) blk: {
|
||||
if (self.get_primary().selection) |_|
|
||||
if (theme.editor_selection.bg) |sel_bg|
|
||||
if (theme.editor_line_highlight.bg) |hl_bg|
|
||||
|
@ -969,7 +969,7 @@ pub const Editor = struct {
|
|||
}
|
||||
|
||||
fn render_cursors(self: *Self, theme: *const Widget.Theme, cell_map: CellMap) !void {
|
||||
const style = tui.current().get_selection_style();
|
||||
const style = tui.get_selection_style();
|
||||
const frame = tracy.initZone(@src(), .{ .name = "editor render cursors" });
|
||||
defer frame.deinit();
|
||||
for (self.cursels.items[0 .. self.cursels.items.len - 1]) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
|
@ -988,19 +988,18 @@ pub const Editor = struct {
|
|||
}
|
||||
|
||||
fn render_cursor_primary(self: *Self, cursor: *const Cursor, theme: *const Widget.Theme, cell_map: CellMap) !void {
|
||||
const tui_ = tui.current();
|
||||
if (!tui_.is_mainview_focused() or !self.enable_terminal_cursor) {
|
||||
if (!tui.is_mainview_focused() or !self.enable_terminal_cursor) {
|
||||
if (self.screen_cursor(cursor)) |pos| {
|
||||
set_cell_map_cursor(cell_map, pos.row, pos.col);
|
||||
self.plane.cursor_move_yx(@intCast(pos.row), @intCast(pos.col)) catch return;
|
||||
const style = if (tui_.is_mainview_focused()) theme.editor_cursor else theme.editor_cursor_secondary;
|
||||
const style = if (tui.is_mainview_focused()) theme.editor_cursor else theme.editor_cursor_secondary;
|
||||
self.render_cursor_cell(style);
|
||||
}
|
||||
} else {
|
||||
if (self.screen_cursor(cursor)) |pos| {
|
||||
set_cell_map_cursor(cell_map, pos.row, pos.col);
|
||||
const y, const x = self.plane.rel_yx_to_abs(@intCast(pos.row), @intCast(pos.col));
|
||||
const configured_shape = tui_.get_cursor_shape();
|
||||
const configured_shape = tui.get_cursor_shape();
|
||||
const cursor_shape = if (self.cursels.items.len > 1) switch (configured_shape) {
|
||||
.beam => .block,
|
||||
.beam_blink => .block_blink,
|
||||
|
@ -1008,9 +1007,9 @@ pub const Editor = struct {
|
|||
.underline_blink => .block_blink,
|
||||
else => configured_shape,
|
||||
} else configured_shape;
|
||||
tui_.rdr.cursor_enable(y, x, cursor_shape) catch {};
|
||||
tui.rdr().cursor_enable(y, x, cursor_shape) catch {};
|
||||
} else {
|
||||
tui_.rdr.cursor_disable();
|
||||
tui.rdr().cursor_disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2112,12 +2111,12 @@ pub const Editor = struct {
|
|||
}
|
||||
|
||||
fn get_animation_min_lag() f64 {
|
||||
const ms: f64 = @floatFromInt(tui.current().config.animation_min_lag);
|
||||
const ms: f64 = @floatFromInt(tui.config().animation_min_lag);
|
||||
return @max(ms * 0.001, 0.001); // to seconds
|
||||
}
|
||||
|
||||
fn get_animation_max_lag() f64 {
|
||||
const ms: f64 = @floatFromInt(tui.current().config.animation_max_lag);
|
||||
const ms: f64 = @floatFromInt(tui.config().animation_max_lag);
|
||||
return @max(ms * 0.001, 0.001); // to seconds
|
||||
}
|
||||
|
||||
|
@ -2249,7 +2248,7 @@ pub const Editor = struct {
|
|||
@import("renderer").copy_to_windows_clipboard(text) catch |e|
|
||||
self.logger.print_err("clipboard", "failed to set clipboard: {any}", .{e});
|
||||
} else {
|
||||
tui.current().rdr.copy_to_system_clipboard(text);
|
||||
tui.rdr().copy_to_system_clipboard(text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3566,13 +3565,13 @@ pub const Editor = struct {
|
|||
|
||||
pub fn enable_jump_mode(self: *Self, _: Context) Result {
|
||||
self.jump_mode = true;
|
||||
tui.current().rdr.request_mouse_cursor_pointer(true);
|
||||
tui.rdr().request_mouse_cursor_pointer(true);
|
||||
}
|
||||
pub const enable_jump_mode_meta = .{ .description = "Enable jump/hover mode" };
|
||||
|
||||
pub fn disable_jump_mode(self: *Self, _: Context) Result {
|
||||
self.jump_mode = false;
|
||||
tui.current().rdr.request_mouse_cursor_text(true);
|
||||
tui.rdr().request_mouse_cursor_text(true);
|
||||
}
|
||||
pub const disable_jump_mode_meta = .{};
|
||||
|
||||
|
@ -3762,7 +3761,7 @@ pub const Editor = struct {
|
|||
if (ctx.args.match(.{ "then", .{ tp.extract(&cmd), tp.extract_cbor(&args) } }) catch false) {
|
||||
then = true;
|
||||
}
|
||||
if (tui.current().config.enable_format_on_save) if (self.get_formatter()) |_| {
|
||||
if (tui.config().enable_format_on_save) if (self.get_formatter()) |_| {
|
||||
self.need_save_after_filter = .{ .then = if (then) .{ .cmd = cmd, .args = args } else null };
|
||||
const primary = self.get_primary();
|
||||
const sel = primary.selection;
|
||||
|
@ -4888,10 +4887,10 @@ pub const EditorWidget = struct {
|
|||
} else if (try m.match(.{ "H", tp.extract(&self.hover) })) {
|
||||
if (self.editor.jump_mode) {
|
||||
self.update_hover_timer(.init);
|
||||
tui.current().rdr.request_mouse_cursor_pointer(self.hover);
|
||||
tui.rdr().request_mouse_cursor_pointer(self.hover);
|
||||
} else {
|
||||
self.update_hover_timer(.cancel);
|
||||
tui.current().rdr.request_mouse_cursor_text(self.hover);
|
||||
tui.rdr().request_mouse_cursor_text(self.hover);
|
||||
}
|
||||
} else if (try m.match(.{"HOVER"})) {
|
||||
self.update_hover_timer(.fired);
|
||||
|
@ -4947,7 +4946,7 @@ pub const EditorWidget = struct {
|
|||
}
|
||||
|
||||
fn mouse_pos_abs(self: *Self, y: c_int, x: c_int, xoffset: c_int) struct { c_int, c_int } {
|
||||
return if (tui.current().is_cursor_beam())
|
||||
return if (tui.is_cursor_beam())
|
||||
self.editor.plane.abs_yx_to_rel_nearest_x(y, x, xoffset)
|
||||
else
|
||||
self.editor.plane.abs_yx_to_rel(y, x);
|
||||
|
|
|
@ -45,15 +45,15 @@ pub fn create(allocator: Allocator, parent: Widget, event_source: Widget, editor
|
|||
.allocator = allocator,
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent.plane.*),
|
||||
.parent = parent,
|
||||
.linenum = tui.current().config.gutter_line_numbers,
|
||||
.relative = tui.current().config.gutter_line_numbers_relative,
|
||||
.highlight = tui.current().config.highlight_current_line_gutter,
|
||||
.symbols = tui.current().config.gutter_symbols,
|
||||
.linenum = tui.config().gutter_line_numbers,
|
||||
.relative = tui.config().gutter_line_numbers_relative,
|
||||
.highlight = tui.config().highlight_current_line_gutter,
|
||||
.symbols = tui.config().gutter_symbols,
|
||||
.editor = editor,
|
||||
.diff = try diff.create(),
|
||||
.diff_symbols = std.ArrayList(Symbol).init(allocator),
|
||||
};
|
||||
try tui.current().message_filters.add(MessageFilter.bind(self, filter_receive));
|
||||
try tui.message_filters().add(MessageFilter.bind(self, filter_receive));
|
||||
try event_source.subscribe(EventHandler.bind(self, handle_event));
|
||||
return self.widget();
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ pub fn widget(self: *Self) Widget {
|
|||
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||
self.diff_symbols_clear();
|
||||
self.diff_symbols.deinit();
|
||||
tui.current().message_filters.remove_ptr(self);
|
||||
tui.message_filters().remove_ptr(self);
|
||||
self.plane.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
self.plane.set_style(theme.editor_gutter);
|
||||
_ = self.plane.fill(" ");
|
||||
if (self.linenum) {
|
||||
const relative = self.relative or if (tui.current().input_mode) |mode| mode.line_numbers == .relative else false;
|
||||
const relative = self.relative or if (tui.input_mode()) |mode| mode.line_numbers == .relative else false;
|
||||
if (relative)
|
||||
self.render_relative(theme)
|
||||
else
|
||||
|
|
|
@ -126,7 +126,7 @@ pub fn walk(self: *Self, walk_ctx: *anyopaque, f: Widget.WalkFn, w: *Widget) boo
|
|||
pub fn receive(_: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||
var hover: bool = false;
|
||||
if (try m.match(.{ "H", tp.extract(&hover) })) {
|
||||
tui.current().rdr.request_mouse_cursor_default(hover);
|
||||
tui.rdr().request_mouse_cursor_default(hover);
|
||||
tui.need_render();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -39,12 +39,12 @@ pub fn create(allocator: Allocator, parent: Plane) !Widget {
|
|||
.plane = n,
|
||||
.buffer = Buffer.init(allocator),
|
||||
};
|
||||
try tui.current().input_listeners.add(EventHandler.bind(self, listen));
|
||||
try tui.input_listeners().add(EventHandler.bind(self, listen));
|
||||
return Widget.to(self);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||
tui.current().input_listeners.remove_ptr(self);
|
||||
tui.input_listeners().remove_ptr(self);
|
||||
for (self.buffer.items) |item|
|
||||
self.buffer.allocator.free(item.json);
|
||||
self.buffer.deinit();
|
||||
|
|
|
@ -37,7 +37,7 @@ pub fn create(allocator: Allocator, parent: Plane) !Widget {
|
|||
|
||||
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||
self.editor.handlers.remove_ptr(self);
|
||||
tui.current().message_filters.remove_ptr(self);
|
||||
tui.message_filters().remove_ptr(self);
|
||||
self.plane.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
|
|
@ -80,8 +80,8 @@ pub fn create(allocator: std.mem.Allocator) !Widget {
|
|||
const widgets = try WidgetList.createV(allocator, self.plane, @typeName(Self), .dynamic);
|
||||
self.widgets = widgets;
|
||||
self.widgets_widget = widgets.widget();
|
||||
if (tui.current().config.top_bar.len > 0)
|
||||
self.top_bar = try widgets.addP(try @import("status/bar.zig").create(allocator, self.plane, tui.current().config.top_bar, .none, null));
|
||||
if (tui.config().top_bar.len > 0)
|
||||
self.top_bar = try widgets.addP(try @import("status/bar.zig").create(allocator, self.plane, tui.config().top_bar, .none, null));
|
||||
|
||||
const views = try WidgetList.createH(allocator, self.plane, @typeName(Self), .dynamic);
|
||||
self.views = views;
|
||||
|
@ -90,8 +90,8 @@ pub fn create(allocator: std.mem.Allocator) !Widget {
|
|||
|
||||
try widgets.add(self.views_widget);
|
||||
|
||||
if (tui.current().config.bottom_bar.len > 0) {
|
||||
self.bottom_bar = try widgets.addP(try @import("status/bar.zig").create(allocator, self.plane, tui.current().config.bottom_bar, .grip, EventHandler.bind(self, handle_bottom_bar_event)));
|
||||
if (tui.config().bottom_bar.len > 0) {
|
||||
self.bottom_bar = try widgets.addP(try @import("status/bar.zig").create(allocator, self.plane, tui.config().bottom_bar, .grip, EventHandler.bind(self, handle_bottom_bar_event)));
|
||||
}
|
||||
if (tp.env.get().is("show-input"))
|
||||
self.toggle_inputview_async();
|
||||
|
@ -142,9 +142,6 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
.end = .{ .row = end_line, .col = end_pos },
|
||||
});
|
||||
return true;
|
||||
} else if (try m.match(.{"write_restore_info"})) {
|
||||
self.write_restore_info();
|
||||
return true;
|
||||
}
|
||||
return if (try self.floating_views.send(from_, m)) true else self.widgets.send(from_, m);
|
||||
}
|
||||
|
@ -212,7 +209,7 @@ fn toggle_panel_view(self: *Self, view: anytype, enable_only: bool) !void {
|
|||
try panels.add(try view.create(self.allocator, self.widgets.plane));
|
||||
self.panels = panels;
|
||||
}
|
||||
tui.current().resize();
|
||||
tui.resize();
|
||||
}
|
||||
|
||||
fn get_panel_view(self: *Self, comptime view: type) ?*view {
|
||||
|
@ -228,7 +225,7 @@ fn close_all_panel_views(self: *Self) void {
|
|||
self.widgets.remove(panels.widget());
|
||||
self.panels = null;
|
||||
}
|
||||
tui.current().resize();
|
||||
tui.resize();
|
||||
}
|
||||
|
||||
fn toggle_view(self: *Self, view: anytype) !void {
|
||||
|
@ -237,7 +234,7 @@ fn toggle_view(self: *Self, view: anytype) !void {
|
|||
} else {
|
||||
try self.widgets.add(try view.create(self.allocator, self.plane));
|
||||
}
|
||||
tui.current().resize();
|
||||
tui.resize();
|
||||
}
|
||||
|
||||
fn check_all_not_dirty(self: *const Self) command.Result {
|
||||
|
@ -274,7 +271,7 @@ const cmds = struct {
|
|||
return;
|
||||
try project_manager.open(project_dir);
|
||||
const project = tp.env.get().str("project");
|
||||
tui.current().rdr.set_terminal_working_directory(project);
|
||||
tui.rdr().set_terminal_working_directory(project);
|
||||
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
}
|
||||
|
@ -297,7 +294,7 @@ const cmds = struct {
|
|||
self.buffer_manager = BufferManager.init(self.allocator);
|
||||
try project_manager.open(project_dir);
|
||||
const project = tp.env.get().str("project");
|
||||
tui.current().rdr.set_terminal_working_directory(project);
|
||||
tui.rdr().set_terminal_working_directory(project);
|
||||
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
if (try project_manager.request_most_recent_file(self.allocator)) |file_path|
|
||||
|
@ -487,9 +484,9 @@ const cmds = struct {
|
|||
pub const add_split_meta = .{};
|
||||
|
||||
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;
|
||||
const config = tui.config_mut();
|
||||
var ln = config.gutter_line_numbers;
|
||||
var lnr = config.gutter_line_numbers_relative;
|
||||
if (ln and !lnr) {
|
||||
ln = true;
|
||||
lnr = true;
|
||||
|
@ -500,9 +497,9 @@ const cmds = struct {
|
|||
ln = true;
|
||||
lnr = false;
|
||||
}
|
||||
tui_.config.gutter_line_numbers = ln;
|
||||
tui_.config.gutter_line_numbers_relative = lnr;
|
||||
try tui_.save_config();
|
||||
config.gutter_line_numbers = ln;
|
||||
config.gutter_line_numbers_relative = lnr;
|
||||
try tui.save_config();
|
||||
if (self.widgets.get("editor_gutter")) |gutter_widget| {
|
||||
const gutter = gutter_widget.dynamic_cast(@import("editor_gutter.zig")) orelse return;
|
||||
gutter.linenum = ln;
|
||||
|
@ -658,7 +655,7 @@ const cmds = struct {
|
|||
defer self.allocator.free(text);
|
||||
return command.executeName("paste", command.fmt(.{text})) catch {};
|
||||
}
|
||||
tui.current().rdr.request_system_clipboard();
|
||||
tui.rdr().request_system_clipboard();
|
||||
}
|
||||
pub const system_paste_meta = .{ .description = "Paste from system clipboard" };
|
||||
|
||||
|
@ -719,7 +716,7 @@ const cmds = struct {
|
|||
if (!try ctx.args.match(.{tp.extract(&amount)}))
|
||||
return error.InvalidArgument;
|
||||
if (build_options.gui)
|
||||
tui.current().rdr.adjust_fontsize(amount);
|
||||
tui.rdr().adjust_fontsize(amount);
|
||||
}
|
||||
pub const adjust_fontsize_meta = .{ .arguments = &.{.float} };
|
||||
|
||||
|
@ -728,13 +725,13 @@ const cmds = struct {
|
|||
if (!try ctx.args.match(.{tp.extract(&fontsize)}))
|
||||
return error.InvalidArgument;
|
||||
if (build_options.gui)
|
||||
tui.current().rdr.set_fontsize(fontsize);
|
||||
tui.rdr().set_fontsize(fontsize);
|
||||
}
|
||||
pub const set_fontsize_meta = .{ .arguments = &.{.float} };
|
||||
|
||||
pub fn reset_fontsize(_: *Self, _: Ctx) Result {
|
||||
if (build_options.gui)
|
||||
tui.current().rdr.reset_fontsize();
|
||||
tui.rdr().reset_fontsize();
|
||||
}
|
||||
pub const reset_fontsize_meta = .{ .description = "Reset font to configured size" };
|
||||
|
||||
|
@ -743,13 +740,13 @@ const cmds = struct {
|
|||
if (!try ctx.args.match(.{tp.extract(&fontface)}))
|
||||
return error.InvalidArgument;
|
||||
if (build_options.gui)
|
||||
tui.current().rdr.set_fontface(fontface);
|
||||
tui.rdr().set_fontface(fontface);
|
||||
}
|
||||
pub const set_fontface_meta = .{ .arguments = &.{.float} };
|
||||
|
||||
pub fn reset_fontface(_: *Self, _: Ctx) Result {
|
||||
if (build_options.gui)
|
||||
tui.current().rdr.reset_fontface();
|
||||
tui.rdr().reset_fontface();
|
||||
}
|
||||
pub const reset_fontface_meta = .{ .description = "Reset font to configured face" };
|
||||
};
|
||||
|
@ -888,7 +885,7 @@ fn create_editor(self: *Self) !void {
|
|||
try self.replace_active_view(editor_widget);
|
||||
if (editor.dynamic_cast(ed.EditorWidget)) |p|
|
||||
try self.add_editor(&p.editor);
|
||||
tui.current().resize();
|
||||
tui.resize();
|
||||
}
|
||||
|
||||
fn toggle_logview_async(_: *Self) void {
|
||||
|
@ -913,16 +910,16 @@ fn create_home(self: *Self) !void {
|
|||
if (self.active_editor) |_| return;
|
||||
try self.delete_active_view();
|
||||
try self.replace_active_view(try home.create(self.allocator, Widget.to(self)));
|
||||
tui.current().resize();
|
||||
tui.resize();
|
||||
}
|
||||
|
||||
fn create_home_split(self: *Self) !void {
|
||||
tui.reset_drag_context();
|
||||
try self.add_view(try home.create(self.allocator, Widget.to(self)));
|
||||
tui.current().resize();
|
||||
tui.resize();
|
||||
}
|
||||
|
||||
fn write_restore_info(self: *Self) void {
|
||||
pub fn write_restore_info(self: *Self) void {
|
||||
const editor = self.get_active_editor() orelse return;
|
||||
var sfa = std.heap.stackFallback(512, self.allocator);
|
||||
const a = sfa.get();
|
||||
|
|
|
@ -5,7 +5,6 @@ const command = @import("command");
|
|||
const cmd = command.executeName;
|
||||
|
||||
const tui = @import("../tui.zig");
|
||||
const mainview = @import("../mainview.zig");
|
||||
|
||||
var commands: Commands = undefined;
|
||||
|
||||
|
@ -59,7 +58,7 @@ const cmds_ = struct {
|
|||
const logger = log.logger("helix-mode");
|
||||
defer logger.deinit();
|
||||
logger.print("saved location", .{});
|
||||
const mv = tui.current().mainview.dynamic_cast(mainview) orelse return;
|
||||
const mv = tui.mainview() orelse return;
|
||||
const file_path = mv.get_active_file_path() orelse return;
|
||||
const primary = (mv.get_active_editor() orelse return).get_primary();
|
||||
const sel: ?location_history.Selection = if (primary.selection) |sel| .{
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn Create(options: type) type {
|
|||
.entries = std.ArrayList(Entry).init(allocator),
|
||||
};
|
||||
try self.commands.init(self);
|
||||
try tui.current().message_filters.add(MessageFilter.bind(self, receive_path_entry));
|
||||
try tui.message_filters().add(MessageFilter.bind(self, receive_path_entry));
|
||||
try options.load_entries(self);
|
||||
if (@hasDecl(options, "restore_state"))
|
||||
options.restore_state(self) catch {};
|
||||
|
@ -57,7 +57,7 @@ pub fn Create(options: type) type {
|
|||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.commands.deinit();
|
||||
tui.current().message_filters.remove_ptr(self);
|
||||
tui.message_filters().remove_ptr(self);
|
||||
self.clear_entries();
|
||||
self.entries.deinit();
|
||||
self.match.deinit();
|
||||
|
@ -113,7 +113,7 @@ pub fn Create(options: type) type {
|
|||
} else {
|
||||
try self.file_path.appendSlice(self.query.items);
|
||||
}
|
||||
if (tui.current().mini_mode) |*mini_mode| {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.file_path.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.file_path.items, 0, 8);
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ pub fn Create(options: type) type {
|
|||
|
||||
fn process_project_manager(self: *Self, m: tp.message) MessageFilter.Error!void {
|
||||
defer {
|
||||
if (tui.current().mini_mode) |*mini_mode| {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.file_path.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.file_path.items, 0, 8);
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ pub fn Create(options: type) type {
|
|||
}
|
||||
|
||||
fn update_mini_mode_text(self: *Self) void {
|
||||
if (tui.current().mini_mode) |*mini_mode| {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.file_path.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.file_path.items, 0, 8);
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ fn load_history(self: *Self, pos: usize) void {
|
|||
}
|
||||
|
||||
fn update_mini_mode_text(self: *Self) void {
|
||||
if (tui.current().mini_mode) |*mini_mode| {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.input.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.input.items, 0, 8);
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ fn start_query(self: *Self) !void {
|
|||
}
|
||||
|
||||
fn update_mini_mode_text(self: *Self) void {
|
||||
if (tui.current().mini_mode) |*mini_mode| {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.input;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.input, 0, 8);
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ pub fn receive(self: *Self, _: tp.pid_ref, _: tp.message) error{Exit}!bool {
|
|||
}
|
||||
|
||||
fn update_mini_mode_text(self: *Self) void {
|
||||
if (tui.current().mini_mode) |*mini_mode| {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = if (self.input) |linenum|
|
||||
(fmt.bufPrint(&self.buf, "{d}", .{linenum}) catch "")
|
||||
else
|
||||
|
|
|
@ -4,7 +4,6 @@ const root = @import("root");
|
|||
const command = @import("command");
|
||||
|
||||
const tui = @import("../../tui.zig");
|
||||
const mainview = @import("../../mainview.zig");
|
||||
|
||||
pub const Type = @import("file_browser.zig").Create(@This());
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ pub const Entry = struct {
|
|||
};
|
||||
|
||||
pub fn load_entries(palette: *Type) !usize {
|
||||
const hints = if (tui.current().input_mode) |m| m.keybind_hints else @panic("no keybind hints");
|
||||
const hints = if (tui.input_mode()) |m| m.keybind_hints else @panic("no keybind hints");
|
||||
var longest_hint: usize = 0;
|
||||
for (command.commands.items) |cmd_| if (cmd_) |p| {
|
||||
if (p.meta.description.len > 0) {
|
||||
|
|
|
@ -33,10 +33,10 @@ pub fn deinit(palette: *Type) void {
|
|||
|
||||
pub fn load_entries(palette: *Type) !usize {
|
||||
var idx: usize = 0;
|
||||
previous_fontface = try palette.allocator.dupe(u8, tui.current().fontface);
|
||||
const fontfaces = tui.current().fontfaces orelse return 0;
|
||||
tui.current().fontfaces = null;
|
||||
for (fontfaces.items) |fontface| {
|
||||
previous_fontface = try palette.allocator.dupe(u8, tui.fontface());
|
||||
const fontfaces = try tui.fontfaces(palette.allocator);
|
||||
defer palette.allocator.free(fontfaces);
|
||||
for (fontfaces) |fontface| {
|
||||
idx += 1;
|
||||
(try palette.entries.addOne()).* = .{ .label = fontface };
|
||||
if (previous_fontface) |previous_fontface_| if (std.mem.eql(u8, fontface, previous_fontface_)) {
|
||||
|
|
|
@ -23,7 +23,7 @@ pub fn deinit(palette: *Type) void {
|
|||
}
|
||||
|
||||
pub fn load_entries(palette: *Type) !usize {
|
||||
const hints = if (tui.current().input_mode) |m| m.keybind_hints else @panic("no keybind hints");
|
||||
const hints = if (tui.input_mode()) |m| m.keybind_hints else @panic("no keybind hints");
|
||||
var longest_hint: usize = 0;
|
||||
for (command.commands.items) |cmd_| if (cmd_) |p| {
|
||||
var label_ = std.ArrayList(u8).init(palette.allocator);
|
||||
|
|
|
@ -18,7 +18,6 @@ const Button = @import("../../Button.zig");
|
|||
const InputBox = @import("../../InputBox.zig");
|
||||
const Menu = @import("../../Menu.zig");
|
||||
const Widget = @import("../../Widget.zig");
|
||||
const mainview = @import("../../mainview.zig");
|
||||
const ModalBackground = @import("../../ModalBackground.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
@ -38,11 +37,11 @@ commands: Commands = undefined,
|
|||
buffer_manager: ?*BufferManager,
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
||||
const mv = tui.current().mainview.dynamic_cast(mainview) orelse return error.NotFound;
|
||||
const mv = tui.mainview() orelse return error.NotFound;
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.modal = try ModalBackground.create(*Self, allocator, tui.current().mainview, .{ .ctx = self }),
|
||||
.modal = try ModalBackground.create(*Self, allocator, tui.mainview_widget(), .{ .ctx = self }),
|
||||
.menu = try Menu.create(*Self, allocator, tui.plane(), .{
|
||||
.ctx = self,
|
||||
.on_render = on_render_menu,
|
||||
|
@ -56,7 +55,7 @@ pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
|||
.buffer_manager = tui.get_buffer_manager(),
|
||||
};
|
||||
try self.commands.init(self);
|
||||
try tui.current().message_filters.add(MessageFilter.bind(self, receive_project_manager));
|
||||
try tui.message_filters().add(MessageFilter.bind(self, receive_project_manager));
|
||||
self.query_pending = true;
|
||||
try project_manager.request_recent_files(max_recent_files);
|
||||
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = max_menu_width() + 2 });
|
||||
|
@ -72,8 +71,8 @@ pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
|||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.commands.deinit();
|
||||
tui.current().message_filters.remove_ptr(self);
|
||||
if (tui.current().mainview.dynamic_cast(mainview)) |mv| {
|
||||
tui.message_filters().remove_ptr(self);
|
||||
if (tui.mainview()) |mv| {
|
||||
mv.floating_views.remove(self.menu.container_widget);
|
||||
mv.floating_views.remove(self.modal.widget());
|
||||
}
|
||||
|
@ -86,13 +85,13 @@ inline fn menu_width(self: *Self) usize {
|
|||
}
|
||||
|
||||
inline fn menu_pos_x(self: *Self) usize {
|
||||
const screen_width = tui.current().screen().w;
|
||||
const screen_width = tui.screen().w;
|
||||
const width = self.menu_width();
|
||||
return if (screen_width <= width) 0 else (screen_width - width) / 2;
|
||||
}
|
||||
|
||||
inline fn max_menu_width() usize {
|
||||
const width = tui.current().screen().w;
|
||||
const width = tui.screen().w;
|
||||
return @max(15, width - (width / 5));
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ const tui = @import("../../tui.zig");
|
|||
const Button = @import("../../Button.zig");
|
||||
const InputBox = @import("../../InputBox.zig");
|
||||
const Widget = @import("../../Widget.zig");
|
||||
const mainview = @import("../../mainview.zig");
|
||||
const scrollbar_v = @import("../../scrollbar_v.zig");
|
||||
const ModalBackground = @import("../../ModalBackground.zig");
|
||||
|
||||
|
@ -47,11 +46,11 @@ pub fn Create(options: type) type {
|
|||
pub const ButtonState = Button.State(*Menu.State(*Self));
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
||||
const mv = tui.current().mainview.dynamic_cast(mainview) orelse return error.NotFound;
|
||||
const mv = tui.mainview() orelse return error.NotFound;
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.modal = try ModalBackground.create(*Self, allocator, tui.current().mainview, .{
|
||||
.modal = try ModalBackground.create(*Self, allocator, tui.mainview_widget(), .{
|
||||
.ctx = self,
|
||||
.on_click = mouse_palette_menu_cancel,
|
||||
}),
|
||||
|
@ -68,7 +67,7 @@ pub fn Create(options: type) type {
|
|||
.ctx = self,
|
||||
.label = options.label,
|
||||
}))).dynamic_cast(InputBox.State(*Self)) orelse unreachable,
|
||||
.view_rows = get_view_rows(tui.current().screen()),
|
||||
.view_rows = get_view_rows(tui.screen()),
|
||||
.entries = std.ArrayList(Entry).init(allocator),
|
||||
};
|
||||
self.menu.scrollbar.?.style_factory = scrollbar_style;
|
||||
|
@ -92,8 +91,8 @@ pub fn Create(options: type) type {
|
|||
if (@hasDecl(options, "deinit"))
|
||||
options.deinit(self);
|
||||
self.entries.deinit();
|
||||
tui.current().message_filters.remove_ptr(self);
|
||||
if (tui.current().mainview.dynamic_cast(mainview)) |mv| {
|
||||
tui.message_filters().remove_ptr(self);
|
||||
if (tui.mainview()) |mv| {
|
||||
mv.floating_views.remove(self.menu.container_widget);
|
||||
mv.floating_views.remove(self.modal.widget());
|
||||
}
|
||||
|
@ -160,7 +159,7 @@ pub fn Create(options: type) type {
|
|||
}
|
||||
|
||||
fn do_resize(self: *Self) void {
|
||||
const screen = tui.current().screen();
|
||||
const screen = tui.screen();
|
||||
const w = @min(self.longest, max_menu_width) + 2 + 1 + self.longest_hint;
|
||||
const x = if (screen.w > w) (screen.w - w) / 2 else 0;
|
||||
self.view_rows = get_view_rows(screen);
|
||||
|
@ -246,7 +245,7 @@ pub fn Create(options: type) type {
|
|||
while (i > 0) : (i -= 1)
|
||||
self.menu.select_down();
|
||||
self.do_resize();
|
||||
tui.current().refresh_hover();
|
||||
tui.refresh_hover();
|
||||
self.selection_updated();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ var previous_theme: ?[]const u8 = null;
|
|||
pub fn load_entries(palette: *Type) !usize {
|
||||
var longest_hint: usize = 0;
|
||||
var idx: usize = 0;
|
||||
previous_theme = tui.current().theme.name;
|
||||
previous_theme = tui.theme().name;
|
||||
for (Widget.themes) |theme| {
|
||||
idx += 1;
|
||||
(try palette.entries.addOne()).* = .{
|
||||
|
@ -76,7 +76,7 @@ pub fn updated(palette: *Type, button_: ?*Type.ButtonState) !void {
|
|||
}
|
||||
|
||||
pub fn cancel(palette: *Type) !void {
|
||||
if (previous_theme) |name_| if (!std.mem.eql(u8, name_, tui.current().theme.name)) {
|
||||
if (previous_theme) |name_| if (!std.mem.eql(u8, name_, tui.theme().name)) {
|
||||
previous_theme = null;
|
||||
tp.self_pid().send(.{ "cmd", "set_theme", .{name_} }) catch |e| palette.logger.err("theme_palette cancel", e);
|
||||
};
|
||||
|
|
|
@ -28,13 +28,13 @@ pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?Event
|
|||
.on_event = event_handler,
|
||||
.tz = zeit.local(allocator, &env) catch |e| return tp.exit_error(e, @errorReturnTrace()),
|
||||
};
|
||||
try tui.current().message_filters.add(MessageFilter.bind(self, receive_tick));
|
||||
try tui.message_filters().add(MessageFilter.bind(self, receive_tick));
|
||||
self.update_tick_timer(.init);
|
||||
return Widget.to(self);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||
tui.current().message_filters.remove_ptr(self);
|
||||
tui.message_filters().remove_ptr(self);
|
||||
if (self.tick_timer) |*t| {
|
||||
t.cancel() catch {};
|
||||
t.deinit();
|
||||
|
|
|
@ -90,7 +90,7 @@ pub fn render(self: *Self, btn: *Button.State(Self), theme: *const Widget.Theme)
|
|||
btn.plane.fill(" ");
|
||||
btn.plane.home();
|
||||
}
|
||||
if (tui.current().mini_mode) |_|
|
||||
if (tui.mini_mode()) |_|
|
||||
render_mini_mode(&btn.plane, theme)
|
||||
else if (self.detailed)
|
||||
self.render_detailed(&btn.plane, theme)
|
||||
|
@ -102,14 +102,13 @@ pub fn render(self: *Self, btn: *Button.State(Self), theme: *const Widget.Theme)
|
|||
|
||||
fn render_mini_mode(plane: *Plane, theme: *const Widget.Theme) void {
|
||||
plane.off_styles(style.italic);
|
||||
const tui_ = tui.current();
|
||||
const mini_mode = tui_.mini_mode orelse return;
|
||||
const mini_mode = tui.mini_mode() orelse return;
|
||||
_ = plane.print(" {s}", .{mini_mode.text}) catch {};
|
||||
if (mini_mode.cursor) |cursor| {
|
||||
const pos: c_int = @intCast(cursor);
|
||||
if (tui_.config.enable_terminal_cursor) {
|
||||
if (tui.config().enable_terminal_cursor) {
|
||||
const y, const x = plane.rel_yx_to_abs(0, pos + 1);
|
||||
tui_.rdr.cursor_enable(y, x, tui_.get_cursor_shape()) catch {};
|
||||
tui.rdr().cursor_enable(y, x, tui.get_cursor_shape()) catch {};
|
||||
} else {
|
||||
plane.cursor_move_yx(0, pos + 1) catch return;
|
||||
var cell = plane.cell_init();
|
||||
|
@ -189,7 +188,7 @@ fn render_terminal_title(self: *Self) void {
|
|||
if (std.mem.eql(u8, self.previous_title, new_title)) return;
|
||||
@memcpy(self.previous_title_buf[0..new_title.len], new_title);
|
||||
self.previous_title = self.previous_title_buf[0..new_title.len];
|
||||
tui.current().rdr.set_terminal_title(new_title);
|
||||
tui.rdr().set_terminal_title(new_title);
|
||||
}
|
||||
|
||||
pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||
|
|
|
@ -36,7 +36,7 @@ pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler) @import("wi
|
|||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
.wipe_after_frames = @divTrunc(frame_rate, 2),
|
||||
};
|
||||
try tui.current().input_listeners.add(EventHandler.bind(self, listen));
|
||||
try tui.input_listeners().add(EventHandler.bind(self, listen));
|
||||
return self.widget();
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ pub fn widget(self: *Self) Widget {
|
|||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||
tui.current().input_listeners.remove_ptr(self);
|
||||
tui.input_listeners().remove_ptr(self);
|
||||
self.plane.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
return true;
|
||||
}
|
||||
if (try m.match(.{ "H", tp.extract(&self.hover) })) {
|
||||
tui.current().rdr.request_mouse_cursor_pointer(self.hover);
|
||||
tui.rdr().request_mouse_cursor_pointer(self.hover);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?Event
|
|||
.on_event = event_handler,
|
||||
};
|
||||
logview.init(allocator);
|
||||
try tui.current().message_filters.add(MessageFilter.bind(self, receive_log));
|
||||
try tui.message_filters().add(MessageFilter.bind(self, receive_log));
|
||||
try log.subscribe();
|
||||
return Widget.to(self);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||
}
|
||||
self.msg.deinit();
|
||||
log.unsubscribe() catch {};
|
||||
tui.current().message_filters.remove_ptr(self);
|
||||
tui.message_filters().remove_ptr(self);
|
||||
self.plane.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ pub fn layout(_: *void, btn: *Button.State(void)) Widget.Layout {
|
|||
}
|
||||
|
||||
fn is_mini_mode() bool {
|
||||
return tui.current().mini_mode != null;
|
||||
return tui.mini_mode() != null;
|
||||
}
|
||||
|
||||
fn is_overlay_mode() bool {
|
||||
return tui.current().input_mode_outer != null;
|
||||
return tui.input_mode_outer() != null;
|
||||
}
|
||||
|
||||
pub fn render(_: *void, self: *Button.State(void), theme: *const Widget.Theme) bool {
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler) @import("wi
|
|||
self.* = .{
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
};
|
||||
try tui.current().input_listeners.add(EventHandler.bind(self, listen));
|
||||
try tui.input_listeners().add(EventHandler.bind(self, listen));
|
||||
return self.widget();
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ pub fn widget(self: *Self) Widget {
|
|||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||
tui.current().input_listeners.remove_ptr(self);
|
||||
tui.input_listeners().remove_ptr(self);
|
||||
self.plane.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
|
203
src/tui/tui.zig
203
src/tui/tui.zig
|
@ -3,7 +3,6 @@ const build_options = @import("build_options");
|
|||
const tp = @import("thespian");
|
||||
const cbor = @import("cbor");
|
||||
const log = @import("log");
|
||||
const config = @import("config");
|
||||
const project_manager = @import("project_manager");
|
||||
const root = @import("root");
|
||||
const tracy = @import("tracy");
|
||||
|
@ -16,19 +15,19 @@ const keybind = @import("keybind");
|
|||
|
||||
const Widget = @import("Widget.zig");
|
||||
const MessageFilter = @import("MessageFilter.zig");
|
||||
const mainview = @import("mainview.zig");
|
||||
const MainView = @import("mainview.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
allocator: Allocator,
|
||||
rdr: renderer,
|
||||
config: config,
|
||||
config: @import("config"),
|
||||
frame_time: usize, // in microseconds
|
||||
frame_clock: tp.metronome,
|
||||
frame_clock_running: bool = false,
|
||||
frame_last_time: i64 = 0,
|
||||
receiver: Receiver,
|
||||
mainview: Widget,
|
||||
mainview: ?Widget = null,
|
||||
message_filters: MessageFilter.List,
|
||||
input_mode: ?Mode = null,
|
||||
delayed_init_done: bool = false,
|
||||
|
@ -55,7 +54,7 @@ keepalive_timer: ?tp.Cancellable = null,
|
|||
mouse_idle_timer: ?tp.Cancellable = null,
|
||||
default_cursor: keybind.CursorShape = .default,
|
||||
fontface: []const u8 = "",
|
||||
fontfaces: ?std.ArrayList([]const u8) = null,
|
||||
fontfaces: std.ArrayListUnmanaged([]const u8) = .{},
|
||||
enable_mouse_idle_timer: bool = false,
|
||||
|
||||
const keepalive = std.time.us_per_day * 365; // one year
|
||||
|
@ -84,13 +83,11 @@ fn start(args: StartArgs) tp.result {
|
|||
}
|
||||
|
||||
fn init(allocator: Allocator) !*Self {
|
||||
var self = try allocator.create(Self);
|
||||
|
||||
var conf, const conf_bufs = root.read_config(config, allocator);
|
||||
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");
|
||||
conf.theme = theme.name;
|
||||
const theme_ = get_theme_by_name(conf.theme) orelse get_theme_by_name("dark_modern") orelse return tp.exit("unknown theme");
|
||||
conf.theme = theme_.name;
|
||||
conf.whitespace_mode = try allocator.dupe(u8, conf.whitespace_mode);
|
||||
conf.input_mode = try allocator.dupe(u8, conf.input_mode);
|
||||
conf.top_bar = try allocator.dupe(u8, conf.top_bar);
|
||||
|
@ -106,6 +103,7 @@ fn init(allocator: Allocator) !*Self {
|
|||
const frame_time = std.time.us_per_s / conf.frame_rate;
|
||||
const frame_clock = try tp.metronome.init(frame_time);
|
||||
|
||||
var self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.config = conf,
|
||||
|
@ -114,14 +112,13 @@ fn init(allocator: Allocator) !*Self {
|
|||
.frame_clock = frame_clock,
|
||||
.frame_clock_running = true,
|
||||
.receiver = Receiver.init(receive, self),
|
||||
.mainview = undefined,
|
||||
.message_filters = MessageFilter.List.init(allocator),
|
||||
.input_listeners = EventHandler.List.init(allocator),
|
||||
.logger = log.logger("tui"),
|
||||
.init_timer = if (build_options.gui) null else try tp.timeout.init_ms(init_delay, tp.message.fmt(
|
||||
.{"init"},
|
||||
)),
|
||||
.theme = theme,
|
||||
.theme = theme_,
|
||||
.no_sleep = tp.env.get().is("no-sleep"),
|
||||
};
|
||||
instance_ = self;
|
||||
|
@ -147,11 +144,11 @@ fn init(allocator: Allocator) !*Self {
|
|||
try self.listen_sigwinch();
|
||||
},
|
||||
}
|
||||
self.mainview = try mainview.create(allocator);
|
||||
self.resize();
|
||||
self.mainview = try MainView.create(allocator);
|
||||
resize();
|
||||
self.set_terminal_style();
|
||||
try self.rdr.render();
|
||||
try self.save_config();
|
||||
try save_config();
|
||||
try self.init_input_namespace();
|
||||
if (tp.env.get().is("restore-session")) {
|
||||
command.executeName("restore_session", .{}) catch |e| self.logger.err("restore_session", e);
|
||||
|
@ -168,7 +165,7 @@ fn init_input_namespace(self: *Self) !void {
|
|||
self.logger.print_err("keybind", "unknown mode {s}", .{namespace_name});
|
||||
try keybind.set_namespace("flow");
|
||||
self.config.input_mode = "flow";
|
||||
try self.save_config();
|
||||
try save_config();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -204,7 +201,7 @@ fn deinit(self: *Self) void {
|
|||
self.delayed_init_input_mode = null;
|
||||
}
|
||||
self.commands.deinit();
|
||||
self.mainview.deinit(self.allocator);
|
||||
if (self.mainview) |*mv| mv.deinit(self.allocator);
|
||||
self.message_filters.deinit();
|
||||
self.input_listeners.deinit();
|
||||
if (self.frame_clock_running)
|
||||
|
@ -296,7 +293,7 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
|||
}
|
||||
|
||||
if (try m.match(.{"restart"})) {
|
||||
_ = try self.mainview.msg(.{"write_restore_info"});
|
||||
if (mainview()) |mv| mv.write_restore_info();
|
||||
project_manager.shutdown();
|
||||
self.final_exit = "restart";
|
||||
return;
|
||||
|
@ -310,8 +307,8 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
|||
};
|
||||
|
||||
if (try m.match(.{"resize"})) {
|
||||
self.resize();
|
||||
const box = self.screen();
|
||||
resize();
|
||||
const box = screen();
|
||||
message("{d}x{d}", .{ box.w, box.h });
|
||||
return;
|
||||
}
|
||||
|
@ -391,20 +388,16 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
|||
return self.enter_overlay_mode(@import("mode/overlay/fontface_palette.zig").Type);
|
||||
}
|
||||
|
||||
var fontface: []const u8 = undefined;
|
||||
if (try m.match(.{ "fontface", "current", tp.extract(&fontface) })) {
|
||||
var fontface_: []const u8 = undefined;
|
||||
if (try m.match(.{ "fontface", "current", tp.extract(&fontface_) })) {
|
||||
if (self.fontface.len > 0) self.allocator.free(self.fontface);
|
||||
self.fontface = "";
|
||||
self.fontface = try self.allocator.dupe(u8, fontface);
|
||||
self.fontface = try self.allocator.dupe(u8, fontface_);
|
||||
return;
|
||||
}
|
||||
|
||||
if (try m.match(.{ "fontface", tp.extract(&fontface) })) {
|
||||
var fontfaces = if (self.fontfaces) |*p| p else blk: {
|
||||
self.fontfaces = std.ArrayList([]const u8).init(self.allocator);
|
||||
break :blk &self.fontfaces.?;
|
||||
};
|
||||
try fontfaces.append(try self.allocator.dupe(u8, fontface));
|
||||
if (try m.match(.{ "fontface", tp.extract(&fontface_) })) {
|
||||
try self.fontfaces.append(self.allocator, try self.allocator.dupe(u8, fontface_));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -427,14 +420,14 @@ fn render(self: *Self) void {
|
|||
{
|
||||
const frame = tracy.initZone(@src(), .{ .name = "tui update" });
|
||||
defer frame.deinit();
|
||||
self.mainview.update();
|
||||
if (self.mainview) |mv| mv.update();
|
||||
}
|
||||
|
||||
const more = ret: {
|
||||
const frame = tracy.initZone(@src(), .{ .name = "tui render" });
|
||||
defer frame.deinit();
|
||||
self.rdr.stdplane().erase();
|
||||
break :ret self.mainview.render(&self.theme);
|
||||
break :ret if (self.mainview) |mv| mv.render(&self.theme) else false;
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -543,7 +536,7 @@ fn find_coord_widget(self: *Self, y: usize, x: usize) ?*Widget {
|
|||
}
|
||||
};
|
||||
var ctx: Ctx = .{ .y = y, .x = x };
|
||||
_ = self.mainview.walk(&ctx, Ctx.find);
|
||||
if (self.mainview) |*mv| _ = mv.walk(&ctx, Ctx.find);
|
||||
return ctx.widget;
|
||||
}
|
||||
|
||||
|
@ -560,7 +553,7 @@ fn is_live_widget_ptr(self: *Self, w_: *Widget) bool {
|
|||
}
|
||||
};
|
||||
var ctx: Ctx = .{ .w = w_ };
|
||||
return self.mainview.walk(&ctx, Ctx.find);
|
||||
return if (self.mainview) |*mv| mv.walk(&ctx, Ctx.find) else false;
|
||||
}
|
||||
|
||||
fn send_widgets(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||
|
@ -569,8 +562,10 @@ fn send_widgets(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
tp.trace(tp.channel.widget, m);
|
||||
return if (self.keyboard_focus) |w|
|
||||
w.send(from, m)
|
||||
else if (self.mainview) |mv|
|
||||
mv.send(from, m)
|
||||
else
|
||||
self.mainview.send(from, m);
|
||||
false;
|
||||
}
|
||||
|
||||
fn send_mouse(self: *Self, y: c_int, x: c_int, from: tp.pid_ref, m: tp.message) tp.result {
|
||||
|
@ -623,16 +618,19 @@ fn clear_hover_focus(self: *Self) tp.result {
|
|||
self.hover_focus = null;
|
||||
}
|
||||
|
||||
pub fn refresh_hover(self: *Self) void {
|
||||
pub fn refresh_hover() void {
|
||||
const self = current();
|
||||
self.clear_hover_focus() catch return;
|
||||
_ = self.update_hover(self.last_hover_y, self.last_hover_x) catch {};
|
||||
}
|
||||
|
||||
pub fn save_config(self: *const Self) !void {
|
||||
pub fn save_config() !void {
|
||||
const self = current();
|
||||
try root.write_config(self.config, self.allocator);
|
||||
}
|
||||
|
||||
pub fn is_mainview_focused(self: *const Self) bool {
|
||||
pub fn is_mainview_focused() bool {
|
||||
const self = current();
|
||||
return self.mini_mode == null and self.input_mode_outer == null;
|
||||
}
|
||||
|
||||
|
@ -643,7 +641,7 @@ fn enter_overlay_mode(self: *Self, mode: type) command.Result {
|
|||
if (self.input_mode_outer) |_| try cmds.exit_overlay_mode(self, .{});
|
||||
self.input_mode_outer = self.input_mode;
|
||||
self.input_mode = try mode.create(self.allocator);
|
||||
self.refresh_hover();
|
||||
refresh_hover();
|
||||
}
|
||||
|
||||
fn get_input_mode(self: *Self, mode_name: []const u8) !Mode {
|
||||
|
@ -703,7 +701,7 @@ const cmds = struct {
|
|||
self.config.theme = self.theme.name;
|
||||
self.set_terminal_style();
|
||||
self.logger.print("theme: {s}", .{self.theme.description});
|
||||
try self.save_config();
|
||||
try save_config();
|
||||
}
|
||||
pub const set_theme_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
|
@ -712,7 +710,7 @@ const cmds = struct {
|
|||
self.config.theme = self.theme.name;
|
||||
self.set_terminal_style();
|
||||
self.logger.print("theme: {s}", .{self.theme.description});
|
||||
try self.save_config();
|
||||
try save_config();
|
||||
}
|
||||
pub const theme_next_meta = .{ .description = "Switch to next color theme" };
|
||||
|
||||
|
@ -721,7 +719,7 @@ const cmds = struct {
|
|||
self.config.theme = self.theme.name;
|
||||
self.set_terminal_style();
|
||||
self.logger.print("theme: {s}", .{self.theme.description});
|
||||
try self.save_config();
|
||||
try save_config();
|
||||
}
|
||||
pub const theme_prev_meta = .{ .description = "Switch to previous color theme" };
|
||||
|
||||
|
@ -740,7 +738,7 @@ const cmds = struct {
|
|||
"full"
|
||||
else
|
||||
"none";
|
||||
try self.save_config();
|
||||
try save_config();
|
||||
var buf: [32]u8 = undefined;
|
||||
const m = try tp.message.fmtbuf(&buf, .{ "whitespace_mode", self.config.whitespace_mode });
|
||||
_ = try self.send_widgets(tp.self_pid(), m);
|
||||
|
@ -764,7 +762,7 @@ const cmds = struct {
|
|||
found = true;
|
||||
} else try self.allocator.dupe(u8, namespaces[0]);
|
||||
|
||||
try self.save_config();
|
||||
try save_config();
|
||||
self.logger.print("input mode {s}", .{self.config.input_mode});
|
||||
try keybind.set_namespace(self.config.input_mode);
|
||||
return self.refresh_input_mode();
|
||||
|
@ -842,7 +840,7 @@ const cmds = struct {
|
|||
if (self.input_mode) |*mode| mode.deinit();
|
||||
self.input_mode = self.input_mode_outer;
|
||||
self.input_mode_outer = null;
|
||||
self.refresh_hover();
|
||||
refresh_hover();
|
||||
}
|
||||
pub const exit_overlay_mode_meta = .{};
|
||||
|
||||
|
@ -879,13 +877,13 @@ const cmds = struct {
|
|||
fn enter_mini_mode(self: *Self, comptime mode: anytype, ctx: Ctx) !void {
|
||||
command.executeName("disable_fast_scroll", .{}) catch {};
|
||||
command.executeName("disable_jump_mode", .{}) catch {};
|
||||
const input_mode, const mini_mode = try mode.create(self.allocator, ctx);
|
||||
const input_mode_, const mini_mode_ = try mode.create(self.allocator, ctx);
|
||||
if (self.mini_mode) |_| try exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{});
|
||||
if (self.input_mode_outer != null) @panic("exit_overlay_mode failed");
|
||||
self.input_mode_outer = self.input_mode;
|
||||
self.input_mode = input_mode;
|
||||
self.mini_mode = mini_mode;
|
||||
self.input_mode = input_mode_;
|
||||
self.mini_mode = mini_mode_;
|
||||
}
|
||||
|
||||
pub fn exit_mini_mode(self: *Self, _: Ctx) Result {
|
||||
|
@ -980,12 +978,52 @@ pub const KeybindHints = keybind.KeybindHints;
|
|||
|
||||
threadlocal var instance_: ?*Self = null;
|
||||
|
||||
pub fn current() *Self {
|
||||
fn current() *Self {
|
||||
return instance_ orelse @panic("tui call out of context");
|
||||
}
|
||||
|
||||
pub fn rdr() *renderer {
|
||||
return ¤t().rdr;
|
||||
}
|
||||
|
||||
pub fn message_filters() *MessageFilter.List {
|
||||
return ¤t().message_filters;
|
||||
}
|
||||
|
||||
pub fn input_listeners() *EventHandler.List {
|
||||
return ¤t().input_listeners;
|
||||
}
|
||||
|
||||
pub fn input_mode() ?*Mode {
|
||||
return if (current().input_mode) |*p| p else null;
|
||||
}
|
||||
|
||||
pub fn input_mode_outer() ?*Mode {
|
||||
return if (current().input_mode_outer) |*p| p else null;
|
||||
}
|
||||
|
||||
pub fn mini_mode() ?*MiniMode {
|
||||
return if (current().mini_mode) |*p| p else null;
|
||||
}
|
||||
|
||||
pub fn config() *const @import("config") {
|
||||
return ¤t().config;
|
||||
}
|
||||
|
||||
pub fn config_mut() *@import("config") {
|
||||
return ¤t().config;
|
||||
}
|
||||
|
||||
pub fn mainview() ?*MainView {
|
||||
return if (current().mainview) |*mv| mv.dynamic_cast(MainView) else null;
|
||||
}
|
||||
|
||||
pub fn mainview_widget() Widget {
|
||||
return current().mainview orelse @panic("tui main view not found");
|
||||
}
|
||||
|
||||
pub fn get_active_editor() ?*@import("editor.zig").Editor {
|
||||
if (current().mainview.dynamic_cast(mainview)) |mv_| if (mv_.get_active_editor()) |editor|
|
||||
if (mainview()) |mv_| if (mv_.get_active_editor()) |editor|
|
||||
return editor;
|
||||
return null;
|
||||
}
|
||||
|
@ -997,7 +1035,7 @@ pub fn get_active_selection(allocator: std.mem.Allocator) ?[]u8 {
|
|||
}
|
||||
|
||||
pub fn get_buffer_manager() ?*@import("Buffer").Manager {
|
||||
return if (current().mainview.dynamic_cast(mainview)) |mv_| &mv_.buffer_manager else null;
|
||||
return if (mainview()) |mv| &mv.buffer_manager else null;
|
||||
}
|
||||
|
||||
fn context_check() void {
|
||||
|
@ -1031,9 +1069,9 @@ pub fn need_render() void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resize(self: *Self) void {
|
||||
self.mainview.resize(self.screen());
|
||||
self.refresh_hover();
|
||||
pub fn resize() void {
|
||||
mainview_widget().resize(screen());
|
||||
refresh_hover();
|
||||
need_render();
|
||||
}
|
||||
|
||||
|
@ -1053,24 +1091,36 @@ pub fn egc_last(egcs: []const u8) []const u8 {
|
|||
return plane().egc_last(egcs);
|
||||
}
|
||||
|
||||
pub fn screen(self: *Self) Widget.Box {
|
||||
return Widget.Box.from(self.rdr.stdplane());
|
||||
pub fn screen() Widget.Box {
|
||||
return Widget.Box.from(plane());
|
||||
}
|
||||
|
||||
pub fn fontface() []const u8 {
|
||||
return current().fontface;
|
||||
}
|
||||
|
||||
pub fn fontfaces(allocator: std.mem.Allocator) error{OutOfMemory}![][]const u8 {
|
||||
return current().fontfaces.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
pub fn theme() *const Widget.Theme {
|
||||
return ¤t().theme;
|
||||
}
|
||||
|
||||
pub fn get_theme_by_name(name: []const u8) ?Widget.Theme {
|
||||
for (Widget.themes) |theme| {
|
||||
if (std.mem.eql(u8, theme.name, name))
|
||||
return theme;
|
||||
for (Widget.themes) |theme_| {
|
||||
if (std.mem.eql(u8, theme_.name, name))
|
||||
return theme_;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn get_next_theme_by_name(name: []const u8) Widget.Theme {
|
||||
var next = false;
|
||||
for (Widget.themes) |theme| {
|
||||
for (Widget.themes) |theme_| {
|
||||
if (next)
|
||||
return theme;
|
||||
if (std.mem.eql(u8, theme.name, name))
|
||||
return theme_;
|
||||
if (std.mem.eql(u8, theme_.name, name))
|
||||
next = true;
|
||||
}
|
||||
return Widget.themes[0];
|
||||
|
@ -1078,24 +1128,24 @@ pub fn get_next_theme_by_name(name: []const u8) Widget.Theme {
|
|||
|
||||
pub fn get_prev_theme_by_name(name: []const u8) Widget.Theme {
|
||||
var prev: ?Widget.Theme = null;
|
||||
for (Widget.themes) |theme| {
|
||||
if (std.mem.eql(u8, theme.name, name))
|
||||
for (Widget.themes) |theme_| {
|
||||
if (std.mem.eql(u8, theme_.name, name))
|
||||
return prev orelse Widget.themes[Widget.themes.len - 1];
|
||||
prev = theme;
|
||||
prev = theme_;
|
||||
}
|
||||
return Widget.themes[Widget.themes.len - 1];
|
||||
}
|
||||
|
||||
pub fn find_scope_style(theme: *const Widget.Theme, scope: []const u8) ?Widget.Theme.Token {
|
||||
pub fn find_scope_style(theme_: *const Widget.Theme, scope: []const u8) ?Widget.Theme.Token {
|
||||
return if (find_scope_fallback(scope)) |tm_scope|
|
||||
scope_to_theme_token(theme, tm_scope) orelse
|
||||
scope_to_theme_token(theme, scope)
|
||||
scope_to_theme_token(theme_, tm_scope) orelse
|
||||
scope_to_theme_token(theme_, scope)
|
||||
else
|
||||
scope_to_theme_token(theme, scope);
|
||||
scope_to_theme_token(theme_, scope);
|
||||
}
|
||||
|
||||
fn scope_to_theme_token(theme: *const Widget.Theme, document_scope: []const u8) ?Widget.Theme.Token {
|
||||
var idx = theme.tokens.len - 1;
|
||||
fn scope_to_theme_token(theme_: *const Widget.Theme, document_scope: []const u8) ?Widget.Theme.Token {
|
||||
var idx = theme_.tokens.len - 1;
|
||||
var matched: ?Widget.Theme.Token = null;
|
||||
var done = false;
|
||||
while (!done) : (if (idx == 0) {
|
||||
|
@ -1103,7 +1153,7 @@ fn scope_to_theme_token(theme: *const Widget.Theme, document_scope: []const u8)
|
|||
} else {
|
||||
idx -= 1;
|
||||
}) {
|
||||
const token = theme.tokens[idx];
|
||||
const token = theme_.tokens[idx];
|
||||
const theme_scope = Widget.scopes[token.id];
|
||||
const last_matched_scope = if (matched) |tok| Widget.scopes[tok.id] else "";
|
||||
if (theme_scope.len < last_matched_scope.len) continue;
|
||||
|
@ -1178,7 +1228,8 @@ fn set_terminal_style(self: *Self) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor_shape(self: *Self) renderer.CursorShape {
|
||||
pub fn get_cursor_shape() renderer.CursorShape {
|
||||
const self = current();
|
||||
const shape = if (self.input_mode) |mode| mode.cursor_shape orelse self.default_cursor else self.default_cursor;
|
||||
return switch (shape) {
|
||||
.default => .default,
|
||||
|
@ -1191,15 +1242,15 @@ pub fn get_cursor_shape(self: *Self) renderer.CursorShape {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn is_cursor_beam(self: *Self) bool {
|
||||
return switch (self.get_cursor_shape()) {
|
||||
pub fn is_cursor_beam() bool {
|
||||
return switch (get_cursor_shape()) {
|
||||
.beam, .beam_blink => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_selection_style(self: *Self) @import("Buffer").Selection.Style {
|
||||
return if (self.input_mode) |mode| mode.selection_style else .normal;
|
||||
pub fn get_selection_style() @import("Buffer").Selection.Style {
|
||||
return if (current().input_mode) |mode| mode.selection_style else .normal;
|
||||
}
|
||||
|
||||
pub fn message(comptime fmt: anytype, args: anytype) void {
|
||||
|
|
Loading…
Add table
Reference in a new issue