diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index 4520b39..79e5094 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -326,13 +326,14 @@ const Namespace = struct { if (parsed.value.deinit_command) |cmd| self.deinit_command = try Command.load(allocator, cmd); } - fn load_mode(self: *@This(), allocator: std.mem.Allocator, mode_name: []const u8, mode_value: std.json.Value) !void { + fn load_mode(self: *@This(), allocator: std.mem.Allocator, mode_name_: []const u8, mode_value: std.json.Value) !void { + const mode_name = try allocator.dupe(u8, mode_name_); const fallback_mode = if (self.fallback) |fallback| fallback.get_mode(mode_name) orelse fallback.get_mode(default_mode) else null; - try self.modes.put(allocator, try allocator.dupe(u8, mode_name), try BindingSet.load(allocator, self.name, mode_value, fallback_mode, self)); + try self.modes.put(allocator, mode_name, try BindingSet.load(allocator, self.name, mode_name, mode_value, fallback_mode, self)); } fn copy_mode(self: *@This(), allocator: std.mem.Allocator, mode_name: []const u8, fallback_mode: *const BindingSet) !void { - try self.modes.put(allocator, mode_name, try BindingSet.copy(allocator, fallback_mode)); + try self.modes.put(allocator, mode_name, try BindingSet.copy(allocator, mode_name, fallback_mode)); } fn get_mode(self: *const @This(), mode_name: []const u8) ?*BindingSet { @@ -472,6 +473,7 @@ const BindingSet = struct { syntax: KeySyntax = .flow, on_match_failure: OnMatchFailure = .ignore, name: []const u8, + config_section: []const u8, line_numbers: LineNumbers = .inherit, cursor_shape: ?CursorShape = null, selection_style: SelectionStyle, @@ -483,8 +485,8 @@ const BindingSet = struct { const KeySyntax = enum { flow, vim }; const OnMatchFailure = enum { insert, ignore }; - fn load(allocator: std.mem.Allocator, namespace_name: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, namespace: *Namespace) (error{ OutOfMemory, WriteFailed } || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { - var self: @This() = .{ .name = undefined, .selection_style = undefined }; + fn load(allocator: std.mem.Allocator, namespace_name: []const u8, config_section: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, namespace: *Namespace) (error{ OutOfMemory, WriteFailed } || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { + var self: @This() = .{ .name = undefined, .config_section = config_section, .selection_style = undefined }; const JsonConfig = struct { press: []const []const std.json.Value = &[_][]std.json.Value{}, @@ -590,8 +592,8 @@ const BindingSet = struct { } } - fn copy(allocator: std.mem.Allocator, fallback: *const BindingSet) error{OutOfMemory}!@This() { - var self: @This() = .{ .name = fallback.name, .selection_style = fallback.selection_style }; + fn copy(allocator: std.mem.Allocator, config_section: []const u8, fallback: *const BindingSet) error{OutOfMemory}!@This() { + var self: @This() = .{ .name = fallback.name, .config_section = config_section, .selection_style = fallback.selection_style }; self.on_match_failure = fallback.on_match_failure; for (fallback.press.items) |binding| try self.press.append(allocator, binding); for (fallback.release.items) |binding| try self.release.append(allocator, binding); diff --git a/src/tui/WidgetStyle.zig b/src/tui/WidgetStyle.zig index f80599d..4d010ac 100644 --- a/src/tui/WidgetStyle.zig +++ b/src/tui/WidgetStyle.zig @@ -46,18 +46,23 @@ pub const Border = struct { sw: []const u8, w: []const u8, - const blank: Border = .{ .nw = " ", .n = " ", .ne = " ", .e = " ", .se = " ", .s = " ", .sw = " ", .w = " " }; - const box: Border = .{ .nw = "┌", .n = "─", .ne = "┐", .e = "│", .se = "┘", .s = "─", .sw = "└", .w = "│" }; - const @"rounded box": Border = .{ .nw = "╭", .n = "─", .ne = "╮", .e = "│", .se = "╯", .s = "─", .sw = "╰", .w = "│" }; - const @"double box": Border = .{ .nw = "╔", .n = "═", .ne = "╗", .e = "║", .se = "╝", .s = "═", .sw = "╚", .w = "║" }; - const @"single/double box (top/bottom)": Border = .{ .nw = "╓", .n = "─", .ne = "╖", .e = "║", .se = "╜", .s = "─", .sw = "╙", .w = "║" }; - const @"single/double box (left/right)": Border = .{ .nw = "╒", .n = "═", .ne = "╕", .e = "│", .se = "╛", .s = "═", .sw = "╘", .w = "│" }; - const @"dotted box (braille)": Border = .{ .nw = "⡏", .n = "⠉", .ne = "⢹", .e = "⢸", .se = "⣸", .s = "⣀", .sw = "⣇", .w = "⡇" }; - const @"thick box (half)": Border = .{ .nw = "▛", .n = "▀", .ne = "▜", .e = "▐", .se = "▟", .s = "▄", .sw = "▙", .w = "▌" }; - const @"thick box (sextant)": Border = .{ .nw = "🬕", .n = "🬂", .ne = "🬨", .e = "▐", .se = "🬷", .s = "🬭", .sw = "🬲", .w = "▌" }; - const @"thick box (octant)": Border = .{ .nw = "𜵊", .n = "🮂", .ne = "𜶘", .e = "▐", .se = "𜷕", .s = "▂", .sw = "𜷀", .w = "▌" }; - const @"extra thick box": Border = .{ .nw = "█", .n = "▀", .ne = "█", .e = "█", .se = "█", .s = "▄", .sw = "█", .w = "█" }; - const @"round thick box": Border = .{ .nw = "█", .n = "▀", .ne = "█", .e = "█", .se = "█", .s = "▄", .sw = "█", .w = "█" }; + nib: []const u8, // north insert begin + nie: []const u8, // north insert end + sib: []const u8, // south insert begin + sie: []const u8, // south insert end + + const blank: Border = .{ .nw = " ", .n = " ", .ne = " ", .e = " ", .se = " ", .s = " ", .sw = " ", .w = " ", .nib = " ", .nie = " ", .sib = " ", .sie = " " }; + const box: Border = .{ .nw = "┌", .n = "─", .ne = "┐", .e = "│", .se = "┘", .s = "─", .sw = "└", .w = "│", .nib = "┤", .nie = "├", .sib = "┤", .sie = "├" }; + const @"rounded box": Border = .{ .nw = "╭", .n = "─", .ne = "╮", .e = "│", .se = "╯", .s = "─", .sw = "╰", .w = "│", .nib = "┤", .nie = "├", .sib = "┤", .sie = "├" }; + const @"double box": Border = .{ .nw = "╔", .n = "═", .ne = "╗", .e = "║", .se = "╝", .s = "═", .sw = "╚", .w = "║", .nib = "╡", .nie = "╞", .sib = "╡", .sie = "╞" }; + const @"single/double box (top/bottom)": Border = .{ .nw = "╓", .n = "─", .ne = "╖", .e = "║", .se = "╜", .s = "─", .sw = "╙", .w = "║", .nib = "┤", .nie = "├", .sib = "┤", .sie = "├" }; + const @"single/double box (left/right)": Border = .{ .nw = "╒", .n = "═", .ne = "╕", .e = "│", .se = "╛", .s = "═", .sw = "╘", .w = "│", .nib = "╡", .nie = "╞", .sib = "╡", .sie = "╞" }; + const @"dotted box (braille)": Border = .{ .nw = "⡏", .n = "⠉", .ne = "⢹", .e = "⢸", .se = "⣸", .s = "⣀", .sw = "⣇", .w = "⡇", .nib = "⢹", .nie = "⡏", .sib = "⣸", .sie = "⣇" }; + const @"thick box (half)": Border = .{ .nw = "▛", .n = "▀", .ne = "▜", .e = "▐", .se = "▟", .s = "▄", .sw = "▙", .w = "▌", .nib = "▌", .nie = "▐", .sib = "▌", .sie = "▐" }; + const @"thick box (sextant)": Border = .{ .nw = "🬕", .n = "🬂", .ne = "🬨", .e = "▐", .se = "🬷", .s = "🬭", .sw = "🬲", .w = "▌", .nib = "▌", .nie = "▐", .sib = "▌", .sie = "▐" }; + const @"thick box (octant)": Border = .{ .nw = "𜵊", .n = "🮂", .ne = "𜶘", .e = "▐", .se = "𜷕", .s = "▂", .sw = "𜷀", .w = "▌", .nib = "▌", .nie = "▐", .sib = "▌", .sie = "▐" }; + const @"extra thick box": Border = .{ .nw = "█", .n = "▀", .ne = "█", .e = "█", .se = "█", .s = "▄", .sw = "█", .w = "█", .nib = "▌", .nie = "▐", .sib = "▌", .sie = "▐" }; + const @"round thick box": Border = .{ .nw = "█", .n = "▀", .ne = "█", .e = "█", .se = "█", .s = "▄", .sw = "█", .w = "█", .nib = "▌", .nie = "▐", .sib = "▌", .sie = "▐" }; }; const compact: @This() = .{}; diff --git a/src/tui/keyhints.zig b/src/tui/keyhints.zig index efa8fd1..577831f 100644 --- a/src/tui/keyhints.zig +++ b/src/tui/keyhints.zig @@ -17,14 +17,14 @@ pub fn render_current_input_mode(allocator: std.mem.Allocator, select_mode: keyb break :blk if (b.len > 0) b else mode.current_bindings(allocator, select_mode) catch return; }; defer allocator.free(bindings); - return render(bindings, theme, .full); + return render(mode, bindings, theme, .full); } pub fn render_current_key_event_sequence(allocator: std.mem.Allocator, select_mode: keybind.SelectMode, theme: *const Widget.Theme) void { const mode = tui.input_mode() orelse return; const bindings = mode.current_key_event_sequence_bindings(allocator, select_mode) catch return; defer allocator.free(bindings); - return render(bindings, theme, .no_key_event_prefix); + return render(mode, bindings, theme, .no_key_event_prefix); } pub fn scroll() void { @@ -33,13 +33,13 @@ pub fn scroll() void { const RenderMode = enum { full, no_key_event_prefix }; -fn render(bindings: []const keybind.Binding, theme: *const Widget.Theme, mode: RenderMode) void { +fn render(mode: *keybind.Mode, bindings: []const keybind.Binding, theme: *const Widget.Theme, render_mode: RenderMode) void { // return if something is already rendering to the top layer if (tui.have_top_layer()) return; if (bindings.len == 0) return; var key_events_buf: [256]u8 = undefined; - const key_events = switch (mode) { + const key_events = switch (render_mode) { .no_key_event_prefix => blk: { var writer = std.Io.Writer.fixed(&key_events_buf); writer.print("{f}", .{keybind.current_key_event_sequence_fmt()}) catch {}; @@ -63,7 +63,7 @@ fn render(bindings: []const keybind.Binding, theme: *const Widget.Theme, mode: R } var box: Widget.Box = .{ .h = max_items, - .w = max_len, + .w = max_len + widget_style.padding.left -| widget_style.padding.right, .x = scr.w -| max_len -| 2 -| widget_style.padding.left -| widget_style.padding.right, .y = scr.h -| max_items -| 1 -| widget_style.padding.top -| widget_style.padding.bottom, }; @@ -73,9 +73,29 @@ fn render(bindings: []const keybind.Binding, theme: *const Widget.Theme, mode: R widget_style.render_decoration(deco_box, widget_type, top_layer_, theme); if (bindings.len > max_items) { - top_layer_.cursor_move_yx(@intCast(top_layer_.window.height -| 1), @intCast(4)) catch return; - _ = top_layer_.print("[{d}/{d}](C-A-? for more)", .{ top, bindings.len }) catch {}; - top_layer_.cursor_move_yx(@intCast(top_layer_.window.height -| 1), @intCast(max_len - 5)) catch return; + if (widget_style.padding.bottom > 0) { + top_layer_.cursor_move_yx(@intCast(top_layer_.window.height -| 1), @intCast(max_len -| 13)) catch return; + _ = top_layer_.print("{s} {d}/{d} {s}", .{ + widget_style.border.sib, + top, + bindings.len, + widget_style.border.sie, + }) catch {}; + top_layer_.cursor_move_yx(@intCast(top_layer_.window.height -| 1), @intCast(4)) catch return; + _ = top_layer_.print("{s} C-A-? for more {s}", .{ + widget_style.border.sib, + widget_style.border.sie, + }) catch {}; + } + } + if (widget_style.padding.top > 0) { + top_layer_.cursor_move_yx(@intCast(0), @intCast(3)) catch return; + _ = top_layer_.print("{s} {s}/{s} {s}", .{ + widget_style.border.nib, + keybind.get_namespace(), + mode.bindings.config_section, + widget_style.border.nie, + }) catch {}; } // workaround vaxis.Layer issue