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;
|
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 = .{
|
const suppressed_errors = .{
|
||||||
"enable_fast_scroll",
|
"enable_fast_scroll",
|
||||||
"disable_fast_scroll",
|
"disable_fast_scroll",
|
||||||
|
|
|
@ -155,6 +155,15 @@
|
||||||
"home": {
|
"home": {
|
||||||
"on_match_failure": "ignore",
|
"on_match_failure": "ignore",
|
||||||
"press": [
|
"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+f>ctrl+f>ctrl+f>ctrl+f>ctrl+f", "home_sheeran"],
|
||||||
["ctrl+j", "toggle_panel"],
|
["ctrl+j", "toggle_panel"],
|
||||||
["ctrl+q", "quit"],
|
["ctrl+q", "quit"],
|
||||||
|
@ -175,15 +184,6 @@
|
||||||
["alt+l", "toggle_panel"],
|
["alt+l", "toggle_panel"],
|
||||||
["alt+i", "toggle_inputview"],
|
["alt+i", "toggle_inputview"],
|
||||||
["alt+x", "open_command_palette"],
|
["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"],
|
["f1", "open_help"],
|
||||||
["f2", "toggle_input_mode"],
|
["f2", "toggle_input_mode"],
|
||||||
["ctrl+f2", "insert_command_name"],
|
["ctrl+f2", "insert_command_name"],
|
||||||
|
|
|
@ -88,5 +88,17 @@
|
||||||
["<BS>", "delete_backward"],
|
["<BS>", "delete_backward"],
|
||||||
["<CR>", "insert_line_after"]
|
["<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,
|
fire: ?Fire = null,
|
||||||
commands: Commands = undefined,
|
commands: Commands = undefined,
|
||||||
menu: *Menu.State(*Self),
|
menu: *Menu.State(*Self),
|
||||||
|
menu_w: usize = 0,
|
||||||
|
max_desc_len: usize = 0,
|
||||||
|
|
||||||
const Self = @This();
|
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 {
|
pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget {
|
||||||
const self: *Self = try allocator.create(Self);
|
const self: *Self = try allocator.create(Self);
|
||||||
var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*);
|
var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*);
|
||||||
errdefer n.deinit();
|
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);
|
const w = Widget.to(self);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.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 }),
|
.menu = try Menu.create(*Self, allocator, w, .{ .ctx = self, .on_render = menu_on_render }),
|
||||||
};
|
};
|
||||||
try self.commands.init(self);
|
try self.commands.init(self);
|
||||||
try self.menu.add_item_with_handler("Help ······················· :h", menu_action_help);
|
self.get_max_desc_len(keybind_mode.keybind_hints);
|
||||||
try self.menu.add_item_with_handler("Open file ·················· :o", menu_action_open_file);
|
inline for (menu_commands) |command_name| try self.add_menu_command(command_name, self.menu, keybind_mode.keybind_hints);
|
||||||
try self.menu.add_item_with_handler("Open recent file ··········· :e", menu_action_open_recent_file);
|
self.menu.resize(.{ .y = 15, .x = 9, .w = self.menu_w });
|
||||||
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 {};
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +65,34 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||||
allocator.destroy(self);
|
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 {
|
pub fn update(self: *Self) void {
|
||||||
self.menu.update();
|
self.menu.update();
|
||||||
}
|
}
|
||||||
|
@ -102,40 +139,12 @@ fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *c
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn menu_action_help(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
fn menu_action(comptime command_name: []const u8) *const fn (_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||||
command.executeName("open_help", .{}) catch {};
|
return struct {
|
||||||
}
|
fn action(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||||
|
command.executeName(command_name, .{}) catch {};
|
||||||
fn menu_action_open_file(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
}
|
||||||
command.executeName("open_file", .{}) catch {};
|
}.action;
|
||||||
}
|
|
||||||
|
|
||||||
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 {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
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;
|
self.plane.cursor_move_yx(10, 8) catch return false;
|
||||||
fonts.print_string_medium(&self.plane, root.application_subtext, style_subtext) 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) {
|
} else if (self.plane.dim_x() > 55 and self.plane.dim_y() > 16) {
|
||||||
self.plane.cursor_move_yx(2, 4) catch return false;
|
self.plane.cursor_move_yx(2, 4) catch return false;
|
||||||
fonts.print_string_medium(&self.plane, root.application_title, style_title) 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.print(root.application_subtext, .{}) catch {};
|
||||||
self.plane.set_style(theme.editor);
|
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 {
|
} else {
|
||||||
self.plane.set_style_bg_transparent(style_title);
|
self.plane.set_style_bg_transparent(style_title);
|
||||||
self.plane.cursor_move_yx(1, 4) catch return false;
|
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);
|
self.plane.set_style(theme.editor);
|
||||||
|
|
||||||
const x = @min(self.plane.dim_x() -| 32, 8);
|
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);
|
const more = self.menu.render(theme);
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ mainview: Widget,
|
||||||
message_filters: MessageFilter.List,
|
message_filters: MessageFilter.List,
|
||||||
input_mode: ?Mode = null,
|
input_mode: ?Mode = null,
|
||||||
delayed_init_done: bool = false,
|
delayed_init_done: bool = false,
|
||||||
delayed_init_input_mode: ?[]const u8 = null,
|
delayed_init_input_mode: ?Mode = null,
|
||||||
input_mode_outer: ?Mode = null,
|
input_mode_outer: ?Mode = null,
|
||||||
input_listeners: EventHandler.List,
|
input_listeners: EventHandler.List,
|
||||||
keyboard_focus: ?Widget = null,
|
keyboard_focus: ?Widget = null,
|
||||||
|
@ -146,23 +146,30 @@ fn init(allocator: Allocator) !*Self {
|
||||||
self.logger.print("session restored", .{});
|
self.logger.print("session restored", .{});
|
||||||
}
|
}
|
||||||
need_render();
|
need_render();
|
||||||
|
try self.init_input_namespace();
|
||||||
return self;
|
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 {
|
fn init_delayed(self: *Self) !void {
|
||||||
self.delayed_init_done = true;
|
self.delayed_init_done = true;
|
||||||
if (self.input_mode) |_| {} else {
|
if (self.input_mode) |_| {} else {
|
||||||
var mode_parts = std.mem.splitScalar(u8, self.config.input_mode, '/');
|
if (self.delayed_init_input_mode) |delayed_init_input_mode| {
|
||||||
const namespace_name = mode_parts.first();
|
try enter_input_mode(self, delayed_init_input_mode);
|
||||||
keybind.set_namespace(namespace_name) catch {
|
self.delayed_init_input_mode = null;
|
||||||
self.logger.print_err("keybind", "unknown mode {s}", .{namespace_name});
|
} else {
|
||||||
try keybind.set_namespace("flow");
|
try cmds.enter_mode(self, command.Context.fmt(.{keybind.default_mode}));
|
||||||
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,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +188,10 @@ fn deinit(self: *Self) void {
|
||||||
m.deinit();
|
m.deinit();
|
||||||
self.input_mode = null;
|
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.commands.deinit();
|
||||||
self.mainview.deinit(self.allocator);
|
self.mainview.deinit(self.allocator);
|
||||||
self.message_filters.deinit();
|
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, .{});
|
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 {
|
const cmds = struct {
|
||||||
pub const Target = Self;
|
pub const Target = Self;
|
||||||
const Ctx = command.Context;
|
const Ctx = command.Context;
|
||||||
|
@ -679,10 +699,6 @@ const cmds = struct {
|
||||||
var mode: []const u8 = undefined;
|
var mode: []const u8 = undefined;
|
||||||
if (!try ctx.args.match(.{tp.extract(&mode)}))
|
if (!try ctx.args.match(.{tp.extract(&mode)}))
|
||||||
return tp.exit_error(error.InvalidArgument, null);
|
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: {
|
var new_mode = self.get_input_mode(mode) catch ret: {
|
||||||
self.logger.print("unknown mode {s}", .{mode});
|
self.logger.print("unknown mode {s}", .{mode});
|
||||||
|
@ -690,14 +706,11 @@ const cmds = struct {
|
||||||
};
|
};
|
||||||
errdefer new_mode.deinit();
|
errdefer new_mode.deinit();
|
||||||
|
|
||||||
if (self.mini_mode) |_| try exit_mini_mode(self, .{});
|
if (!self.delayed_init_done) {
|
||||||
if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{});
|
self.delayed_init_input_mode = new_mode;
|
||||||
if (self.input_mode) |*m| {
|
return;
|
||||||
m.deinit();
|
|
||||||
self.input_mode = null;
|
|
||||||
}
|
}
|
||||||
self.input_mode = new_mode;
|
return self.enter_input_mode(new_mode);
|
||||||
// self.logger.print("input mode: {s}", .{(self.input_mode orelse return).description});
|
|
||||||
}
|
}
|
||||||
pub const enter_mode_meta = .{ .arguments = &.{.string} };
|
pub const enter_mode_meta = .{ .arguments = &.{.string} };
|
||||||
|
|
||||||
|
@ -709,7 +722,7 @@ const cmds = struct {
|
||||||
pub fn open_command_palette(self: *Self, _: Ctx) Result {
|
pub fn open_command_palette(self: *Self, _: Ctx) Result {
|
||||||
return self.enter_overlay_mode(@import("mode/overlay/command_palette.zig").Type);
|
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 {
|
pub fn insert_command_name(self: *Self, _: Ctx) Result {
|
||||||
return self.enter_overlay_mode(@import("mode/overlay/list_all_commands_palette.zig").Type);
|
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";
|
"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 {
|
pub fn reset_drag_context() void {
|
||||||
const self = current();
|
const self = current();
|
||||||
self.drag_source = null;
|
self.drag_source = null;
|
||||||
|
|
Loading…
Add table
Reference in a new issue