WIP: feat: render whichkey
This commit is contained in:
parent
2881f531b3
commit
a129c97ddd
3 changed files with 95 additions and 26 deletions
|
|
@ -205,7 +205,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
fn on_render_default(_: ?*anyopaque, _: *const Widget.Theme) void {}
|
||||
|
||||
fn render_decoration_default(self: *Self, theme: *const Widget.Theme, widget_style: *const Widget.Style) void {
|
||||
return widget_style.render_decoration(self.deco_box, self.widget_type, &self.plane, theme);
|
||||
widget_style.render_decoration(self.deco_box, self.widget_type, &self.plane, theme);
|
||||
}
|
||||
|
||||
inline fn put_at_pos(plane: *Plane, y: usize, x: usize, egc: []const u8) void {
|
||||
|
|
|
|||
|
|
@ -297,30 +297,6 @@ fn handle_input_idle(self: *Self) void {
|
|||
var buf: [32]u8 = undefined;
|
||||
const m = tp.message.fmtbuf(&buf, .{"input_idle"}) catch return;
|
||||
_ = self.send_widgets(tp.self_pid(), m) catch return;
|
||||
if (self.input_mode_) |mode| {
|
||||
const bindings = mode.current_key_event_sequence_bindings(self.allocator) catch return;
|
||||
defer self.allocator.free(bindings);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_keybind_matches(self: *Self) void {
|
||||
var box = screen();
|
||||
// const anchor: Widget.Pos = .{};
|
||||
// box.y = @intCast(@max(pos.y, anchor.y) - anchor.y);
|
||||
// box.x = @intCast(@max(pos.x, anchor.x) - anchor.x);
|
||||
|
||||
// return if something is already rendering to the top layer
|
||||
const top_layer_ = top_layer(box.to_layer()) orelse return;
|
||||
const mode = self.input_mode_ orelse return;
|
||||
|
||||
const bindings = mode.current_key_event_sequence_bindings(self.allocator) catch return;
|
||||
defer self.allocator.free(bindings);
|
||||
|
||||
for (bindings) |binding|
|
||||
top_layer_.plane.print(" {f} => {s}", .{
|
||||
keybind.key_event_sequence_fmt(binding.key_events),
|
||||
binding.commands[0].command,
|
||||
});
|
||||
}
|
||||
|
||||
fn update_input_idle_timer(self: *Self) void {
|
||||
|
|
@ -583,7 +559,11 @@ fn render(self: *Self) void {
|
|||
const frame = tracy.initZone(@src(), .{ .name = "tui render" });
|
||||
defer frame.deinit();
|
||||
self.rdr_.stdplane().erase();
|
||||
break :ret if (self.mainview_) |mv| mv.render(self.current_theme()) else false;
|
||||
const continue_mainview = if (self.mainview_) |mv| mv.render(self.current_theme()) else false;
|
||||
|
||||
@import("whichkey.zig").render(self.allocator, self.current_theme());
|
||||
|
||||
break :ret continue_mainview;
|
||||
};
|
||||
|
||||
if (self.top_layer_) |top_layer_| {
|
||||
|
|
@ -1648,6 +1628,11 @@ pub fn top_layer(opts: renderer.Layer.Options) ?*renderer.Plane {
|
|||
return self.top_layer_.?.plane();
|
||||
}
|
||||
|
||||
pub fn have_top_layer() bool {
|
||||
const self = current();
|
||||
return self.top_layer_ != null;
|
||||
}
|
||||
|
||||
fn top_layer_reset(self: *Self) void {
|
||||
if (self.top_layer_) |top_layer_| {
|
||||
top_layer_.deinit();
|
||||
|
|
|
|||
84
src/tui/whichkey.zig
Normal file
84
src/tui/whichkey.zig
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
const std = @import("std");
|
||||
const keybind = @import("keybind");
|
||||
const command = @import("command");
|
||||
|
||||
const tui = @import("tui.zig");
|
||||
const Widget = @import("Widget.zig");
|
||||
|
||||
pub fn render(allocator: std.mem.Allocator, theme: *const Widget.Theme) void {
|
||||
// return if something is already rendering to the top layer
|
||||
if (tui.have_top_layer()) return;
|
||||
|
||||
const mode = tui.input_mode() orelse return;
|
||||
const bindings = mode.current_key_event_sequence_bindings(allocator) catch return;
|
||||
defer allocator.free(bindings);
|
||||
if (bindings.len == 0) return;
|
||||
|
||||
var key_events_buf: [256]u8 = undefined;
|
||||
const key_events = blk: {
|
||||
var writer = std.Io.Writer.fixed(&key_events_buf);
|
||||
writer.print("{f}", .{keybind.current_key_event_sequence_fmt()}) catch {};
|
||||
break :blk writer.buffered();
|
||||
};
|
||||
|
||||
const max_prefix_len = get_max_prefix_len(bindings) - key_events.len;
|
||||
const max_description_len = get_max_description_len(bindings);
|
||||
const max_len = max_prefix_len + max_description_len + 2;
|
||||
|
||||
const scr = tui.screen();
|
||||
var box: Widget.Box = .{
|
||||
.h = bindings.len,
|
||||
.w = max_len,
|
||||
.x = scr.w -| max_len -| 4,
|
||||
.y = scr.h -| bindings.len -| 2,
|
||||
};
|
||||
const widget_style = tui.get_widget_style(.panel);
|
||||
const deco_box = box.from_client_box(widget_style.padding);
|
||||
const top_layer_ = tui.top_layer(deco_box.to_layer()) orelse return;
|
||||
widget_style.render_decoration(deco_box, .panel, top_layer_, theme);
|
||||
|
||||
for (bindings, 0..) |binding, y| {
|
||||
var keybind_buf: [256]u8 = undefined;
|
||||
const keybind_txt = blk: {
|
||||
var writer = std.Io.Writer.fixed(&keybind_buf);
|
||||
writer.print("{f}", .{keybind.key_event_sequence_fmt(binding.key_events)}) catch break :blk "";
|
||||
break :blk writer.buffered();
|
||||
};
|
||||
const padding = max_prefix_len + 2;
|
||||
|
||||
const description = blk: {
|
||||
const id = binding.commands[0].command_id orelse
|
||||
command.get_id(binding.commands[0].command) orelse
|
||||
break :blk binding.commands[0].command;
|
||||
break :blk command.get_description(id) orelse break :blk "[n/a]";
|
||||
};
|
||||
|
||||
top_layer_.cursor_move_yx(@intCast(y), 0) catch break;
|
||||
_ = top_layer_.print("{s}", .{keybind_txt[key_events.len..]}) catch {};
|
||||
|
||||
top_layer_.cursor_move_yx(@intCast(y), @intCast(padding)) catch break;
|
||||
_ = top_layer_.print("{s}", .{if (description.len > 0) description else binding.commands[0].command}) catch {};
|
||||
}
|
||||
}
|
||||
|
||||
fn get_max_prefix_len(bindings: anytype) usize {
|
||||
var max: usize = 0;
|
||||
for (bindings) |binding| {
|
||||
var keybind_buf: [256]u8 = undefined;
|
||||
var writer = std.Io.Writer.fixed(&keybind_buf);
|
||||
writer.print("{f}", .{keybind.key_event_sequence_fmt(binding.key_events)}) catch continue;
|
||||
max = @max(max, writer.buffered().len);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
fn get_max_description_len(bindings: anytype) usize {
|
||||
var max: usize = 0;
|
||||
for (bindings) |binding| {
|
||||
const id = binding.commands[0].command_id orelse command.get_id(binding.commands[0].command) orelse continue;
|
||||
const description = command.get_description(id) orelse continue;
|
||||
const text = if (description.len > 0) description else binding.commands[0].command;
|
||||
max = @max(max, text.len);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue