feat: render home screen based on current input mode
This commit is contained in:
parent
c827972e98
commit
f8dff2a7bb
5 changed files with 132 additions and 83 deletions
|
@ -145,6 +145,16 @@ pub fn get_id_cache(name: []const u8, id: *?ID) ?ID {
|
|||
return null;
|
||||
}
|
||||
|
||||
pub fn get_description(id: ID) ?[]const u8 {
|
||||
if (id >= commands.items.len) return null;
|
||||
return (commands.items[id] orelse return null).meta.description;
|
||||
}
|
||||
|
||||
pub fn get_arguments(id: ID) ?[]const ArgumentType {
|
||||
if (id >= commands.items.len) return null;
|
||||
return (commands.items[id] orelse return null).meta.arguments;
|
||||
}
|
||||
|
||||
const suppressed_errors = .{
|
||||
"enable_fast_scroll",
|
||||
"disable_fast_scroll",
|
||||
|
|
|
@ -155,6 +155,15 @@
|
|||
"home": {
|
||||
"on_match_failure": "ignore",
|
||||
"press": [
|
||||
["h", "open_help"],
|
||||
["o", "open_file"],
|
||||
["e", "open_recent"],
|
||||
["r", "open_recent_project"],
|
||||
["p", "open_command_palette"],
|
||||
["c", "open_config"],
|
||||
["k", "open_keybind_config"],
|
||||
["t", "change_theme"],
|
||||
["q", "quit"],
|
||||
["ctrl+f>ctrl+f>ctrl+f>ctrl+f>ctrl+f", "home_sheeran"],
|
||||
["ctrl+j", "toggle_panel"],
|
||||
["ctrl+q", "quit"],
|
||||
|
@ -175,15 +184,6 @@
|
|||
["alt+l", "toggle_panel"],
|
||||
["alt+i", "toggle_inputview"],
|
||||
["alt+x", "open_command_palette"],
|
||||
["h", "open_help"],
|
||||
["o", "open_file"],
|
||||
["e", "open_recent"],
|
||||
["r", "open_recent_project"],
|
||||
["p", "open_command_palette"],
|
||||
["c", "open_config"],
|
||||
["k", "open_keybind_config"],
|
||||
["t", "change_theme"],
|
||||
["q", "quit"],
|
||||
["f1", "open_help"],
|
||||
["f2", "toggle_input_mode"],
|
||||
["ctrl+f2", "insert_command_name"],
|
||||
|
|
|
@ -88,5 +88,17 @@
|
|||
["<BS>", "delete_backward"],
|
||||
["<CR>", "insert_line_after"]
|
||||
]
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"syntax": "vim",
|
||||
"on_match_failure": "ignore",
|
||||
"press": [
|
||||
[";", "open_command_palette"],
|
||||
["<S-;>", "open_command_palette"],
|
||||
["b", "open_keybind_config"],
|
||||
["j", "home_menu_down"],
|
||||
["k", "home_menu_up"],
|
||||
["<Space>", "home_menu_activate"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
105
src/tui/home.zig
105
src/tui/home.zig
|
@ -18,14 +18,31 @@ parent: Plane,
|
|||
fire: ?Fire = null,
|
||||
commands: Commands = undefined,
|
||||
menu: *Menu.State(*Self),
|
||||
menu_w: usize = 0,
|
||||
max_desc_len: usize = 0,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
const menu_commands = &[_][]const u8{
|
||||
"open_help",
|
||||
"open_file",
|
||||
"open_recent",
|
||||
"open_recent_project",
|
||||
"open_command_palette",
|
||||
"open_config",
|
||||
"open_keybind_config",
|
||||
"change_theme",
|
||||
"quit",
|
||||
};
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*);
|
||||
errdefer n.deinit();
|
||||
|
||||
command.executeName("enter_mode", command.Context.fmt(.{"home"})) catch {};
|
||||
const keybind_mode = tui.get_keybind_mode() orelse @panic("no active keybind mode");
|
||||
|
||||
const w = Widget.to(self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
|
@ -34,17 +51,9 @@ pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget {
|
|||
.menu = try Menu.create(*Self, allocator, w, .{ .ctx = self, .on_render = menu_on_render }),
|
||||
};
|
||||
try self.commands.init(self);
|
||||
try self.menu.add_item_with_handler("Help ······················· :h", menu_action_help);
|
||||
try self.menu.add_item_with_handler("Open file ·················· :o", menu_action_open_file);
|
||||
try self.menu.add_item_with_handler("Open recent file ··········· :e", menu_action_open_recent_file);
|
||||
try self.menu.add_item_with_handler("Open recent project ········ :r", menu_action_open_recent_project);
|
||||
try self.menu.add_item_with_handler("Show/Run commands ·········· :p", menu_action_show_commands);
|
||||
try self.menu.add_item_with_handler("Open config file ··········· :c", menu_action_open_config);
|
||||
try self.menu.add_item_with_handler("Open key bindings file ····· :k", menu_action_open_keybind_config);
|
||||
try self.menu.add_item_with_handler("Change theme ··············· :t", menu_action_change_theme);
|
||||
try self.menu.add_item_with_handler("Quit/Close ················· :q", menu_action_quit);
|
||||
self.menu.resize(.{ .y = 15, .x = 9, .w = 32 });
|
||||
command.executeName("enter_mode", command.Context.fmt(.{"home"})) catch {};
|
||||
self.get_max_desc_len(keybind_mode.keybind_hints);
|
||||
inline for (menu_commands) |command_name| try self.add_menu_command(command_name, self.menu, keybind_mode.keybind_hints);
|
||||
self.menu.resize(.{ .y = 15, .x = 9, .w = self.menu_w });
|
||||
return w;
|
||||
}
|
||||
|
||||
|
@ -56,6 +65,34 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
fn get_max_desc_len(self: *Self, hints_map: anytype) void {
|
||||
inline for (menu_commands) |command_name| {
|
||||
const id = command.get_id(command_name) orelse @panic(command_name ++ " is not defined");
|
||||
const description = command.get_description(id) orelse @panic(command_name ++ " has no description");
|
||||
var hints = std.mem.splitScalar(u8, hints_map.get(command_name) orelse "", ',');
|
||||
const hint = hints.first();
|
||||
self.max_desc_len = @max(self.max_desc_len, description.len + hint.len + 5);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_menu_command(self: *Self, comptime command_name: []const u8, menu: anytype, hints_map: anytype) !void {
|
||||
const id = command.get_id(command_name) orelse @panic(command_name ++ " is not defined");
|
||||
const description = command.get_description(id) orelse @panic(command_name ++ " has no description");
|
||||
var hints = std.mem.splitScalar(u8, hints_map.get(command_name) orelse "", ',');
|
||||
const hint = hints.first();
|
||||
const label_len = description.len + hint.len;
|
||||
var buf: [64]u8 = undefined;
|
||||
var fis = std.io.fixedBufferStream(&buf);
|
||||
const writer = fis.writer();
|
||||
try writer.print("{s} ..", .{description});
|
||||
for (0..(self.max_desc_len - label_len - 5)) |_|
|
||||
try writer.print(".", .{});
|
||||
try writer.print(" :{s}", .{hint});
|
||||
const label = fis.getWritten();
|
||||
try menu.add_item_with_handler(label, menu_action(command_name));
|
||||
self.menu_w = @max(self.menu_w, label.len + 1);
|
||||
}
|
||||
|
||||
pub fn update(self: *Self) void {
|
||||
self.menu.update();
|
||||
}
|
||||
|
@ -102,40 +139,12 @@ fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *c
|
|||
return false;
|
||||
}
|
||||
|
||||
fn menu_action_help(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_help", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_file(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_file", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_recent_file(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_recent", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_recent_project(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_recent_project", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_show_commands(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_command_palette", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_config(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_config", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_keybind_config(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_keybind_config", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_change_theme(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("change_theme", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_quit(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("quit", .{}) catch {};
|
||||
fn menu_action(comptime command_name: []const u8) *const fn (_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
return struct {
|
||||
fn action(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName(command_name, .{}) catch {};
|
||||
}
|
||||
}.action;
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
|
@ -154,7 +163,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
self.plane.cursor_move_yx(10, 8) catch return false;
|
||||
fonts.print_string_medium(&self.plane, root.application_subtext, style_subtext) catch return false;
|
||||
|
||||
self.menu.resize(.{ .y = 15, .x = 10, .w = 32 });
|
||||
self.menu.resize(.{ .y = 15, .x = 10, .w = self.menu_w });
|
||||
} else if (self.plane.dim_x() > 55 and self.plane.dim_y() > 16) {
|
||||
self.plane.cursor_move_yx(2, 4) catch return false;
|
||||
fonts.print_string_medium(&self.plane, root.application_title, style_title) catch return false;
|
||||
|
@ -164,7 +173,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
_ = self.plane.print(root.application_subtext, .{}) catch {};
|
||||
self.plane.set_style(theme.editor);
|
||||
|
||||
self.menu.resize(.{ .y = 9, .x = 8, .w = 32 });
|
||||
self.menu.resize(.{ .y = 9, .x = 8, .w = self.menu_w });
|
||||
} else {
|
||||
self.plane.set_style_bg_transparent(style_title);
|
||||
self.plane.cursor_move_yx(1, 4) catch return false;
|
||||
|
@ -176,7 +185,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
self.plane.set_style(theme.editor);
|
||||
|
||||
const x = @min(self.plane.dim_x() -| 32, 8);
|
||||
self.menu.resize(.{ .y = 5, .x = x, .w = 32 });
|
||||
self.menu.resize(.{ .y = 5, .x = x, .w = self.menu_w });
|
||||
}
|
||||
const more = self.menu.render(theme);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ mainview: Widget,
|
|||
message_filters: MessageFilter.List,
|
||||
input_mode: ?Mode = null,
|
||||
delayed_init_done: bool = false,
|
||||
delayed_init_input_mode: ?[]const u8 = null,
|
||||
delayed_init_input_mode: ?Mode = null,
|
||||
input_mode_outer: ?Mode = null,
|
||||
input_listeners: EventHandler.List,
|
||||
keyboard_focus: ?Widget = null,
|
||||
|
@ -146,23 +146,30 @@ fn init(allocator: Allocator) !*Self {
|
|||
self.logger.print("session restored", .{});
|
||||
}
|
||||
need_render();
|
||||
try self.init_input_namespace();
|
||||
return self;
|
||||
}
|
||||
|
||||
fn init_input_namespace(self: *Self) !void {
|
||||
var mode_parts = std.mem.splitScalar(u8, self.config.input_mode, '/');
|
||||
const namespace_name = mode_parts.first();
|
||||
keybind.set_namespace(namespace_name) catch {
|
||||
self.logger.print_err("keybind", "unknown mode {s}", .{namespace_name});
|
||||
try keybind.set_namespace("flow");
|
||||
self.config.input_mode = "flow";
|
||||
try self.save_config();
|
||||
};
|
||||
}
|
||||
|
||||
fn init_delayed(self: *Self) !void {
|
||||
self.delayed_init_done = true;
|
||||
if (self.input_mode) |_| {} else {
|
||||
var mode_parts = std.mem.splitScalar(u8, self.config.input_mode, '/');
|
||||
const namespace_name = mode_parts.first();
|
||||
keybind.set_namespace(namespace_name) catch {
|
||||
self.logger.print_err("keybind", "unknown mode {s}", .{namespace_name});
|
||||
try keybind.set_namespace("flow");
|
||||
self.config.input_mode = "flow";
|
||||
try self.save_config();
|
||||
};
|
||||
return cmds.enter_mode(self, command.Context.fmt(.{
|
||||
self.delayed_init_input_mode orelse keybind.default_mode,
|
||||
}));
|
||||
if (self.delayed_init_input_mode) |delayed_init_input_mode| {
|
||||
try enter_input_mode(self, delayed_init_input_mode);
|
||||
self.delayed_init_input_mode = null;
|
||||
} else {
|
||||
try cmds.enter_mode(self, command.Context.fmt(.{keybind.default_mode}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +188,10 @@ fn deinit(self: *Self) void {
|
|||
m.deinit();
|
||||
self.input_mode = null;
|
||||
}
|
||||
if (self.delayed_init_input_mode) |mode| self.allocator.free(mode);
|
||||
if (self.delayed_init_input_mode) |*m| {
|
||||
m.deinit();
|
||||
self.delayed_init_input_mode = null;
|
||||
}
|
||||
self.commands.deinit();
|
||||
self.mainview.deinit(self.allocator);
|
||||
self.message_filters.deinit();
|
||||
|
@ -587,6 +597,16 @@ fn get_input_mode(self: *Self, mode_name: []const u8) !Mode {
|
|||
return keybind.mode(mode_name, self.allocator, .{});
|
||||
}
|
||||
|
||||
fn enter_input_mode(self: *Self, new_mode: Mode, mode_name: []const u8) command.Result {
|
||||
if (self.mini_mode) |_| try cmds.exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer) |_| try cmds.exit_overlay_mode(self, .{});
|
||||
if (self.input_mode) |*m| {
|
||||
m.deinit();
|
||||
self.input_mode = null;
|
||||
}
|
||||
self.input_mode = new_mode;
|
||||
}
|
||||
|
||||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
|
@ -679,10 +699,6 @@ const cmds = struct {
|
|||
var mode: []const u8 = undefined;
|
||||
if (!try ctx.args.match(.{tp.extract(&mode)}))
|
||||
return tp.exit_error(error.InvalidArgument, null);
|
||||
if (!self.delayed_init_done) {
|
||||
self.delayed_init_input_mode = try self.allocator.dupe(u8, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
var new_mode = self.get_input_mode(mode) catch ret: {
|
||||
self.logger.print("unknown mode {s}", .{mode});
|
||||
|
@ -690,14 +706,11 @@ const cmds = struct {
|
|||
};
|
||||
errdefer new_mode.deinit();
|
||||
|
||||
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 = null;
|
||||
if (!self.delayed_init_done) {
|
||||
self.delayed_init_input_mode = new_mode;
|
||||
return;
|
||||
}
|
||||
self.input_mode = new_mode;
|
||||
// self.logger.print("input mode: {s}", .{(self.input_mode orelse return).description});
|
||||
return self.enter_input_mode(new_mode);
|
||||
}
|
||||
pub const enter_mode_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
|
@ -709,7 +722,7 @@ const cmds = struct {
|
|||
pub fn open_command_palette(self: *Self, _: Ctx) Result {
|
||||
return self.enter_overlay_mode(@import("mode/overlay/command_palette.zig").Type);
|
||||
}
|
||||
pub const open_command_palette_meta = .{};
|
||||
pub const open_command_palette_meta = .{ .description = "Show/Run commands" };
|
||||
|
||||
pub fn insert_command_name(self: *Self, _: Ctx) Result {
|
||||
return self.enter_overlay_mode(@import("mode/overlay/list_all_commands_palette.zig").Type);
|
||||
|
@ -888,6 +901,11 @@ pub fn get_mode() []const u8 {
|
|||
"INI";
|
||||
}
|
||||
|
||||
pub fn get_keybind_mode() ?Mode {
|
||||
const self = current();
|
||||
return self.input_mode orelse self.delayed_init_input_mode;
|
||||
}
|
||||
|
||||
pub fn reset_drag_context() void {
|
||||
const self = current();
|
||||
self.drag_source = null;
|
||||
|
|
Loading…
Add table
Reference in a new issue