Compare commits

...

14 commits

Author SHA1 Message Date
35563822ba
feat: display info box for hover content in hover_info_mode box mode 2026-02-05 21:42:42 +01:00
4a1b206d2b
feat: add Editor.set_hover_content info_box function 2026-02-05 21:42:12 +01:00
ebe59eb0f7
refactor: toggle info_box style instead of panel style if no panel is open 2026-02-05 21:41:22 +01:00
269815dd21
feat: add toggle_hover_info_mode command 2026-02-05 21:41:10 +01:00
bc3f431dee
fix: remove trailing blank lines from info view 2026-02-05 21:40:20 +01:00
f0bf122f22
feat: add hover_info_mode and info_box_style config options 2026-02-05 21:40:09 +01:00
aed77322f3
refactor: add spacious bar widget styles 2026-02-05 21:39:50 +01:00
fd798e5775
feat: add toggle_auto_highlight_references and toggle_auto_hover commands 2026-02-05 17:41:58 +01:00
d3b2577338
refactor: drop late filter errors 2026-02-05 17:41:35 +01:00
fa58e09a18
feat: add info box mode support to completion_dropdown 2026-02-05 16:49:34 +01:00
1c2e1ae494
feat: add toggle_completion_info_mode command and keybindings 2026-02-05 16:48:23 +01:00
c1ae1fe25f
feat: add completion_info_mode config option 2026-02-05 16:46:48 +01:00
6280d7d0b4
refactor: add info_box widget style 2026-02-05 16:46:12 +01:00
69f5448f03
refactor: remove unused dropdown.on_render_menu
We always replace this method anyway, so this is all dead code.
2026-02-05 14:56:20 +01:00
9 changed files with 277 additions and 51 deletions

View file

@ -24,6 +24,7 @@ inline_vcs_blame_alignment: Alignment = .right,
animation_min_lag: usize = 0, //milliseconds
animation_max_lag: usize = 50, //milliseconds
hover_time_ms: usize = 500, //milliseconds
hover_info_mode: HoverInfoMode = .box,
input_idle_time_ms: usize = 100, //milliseconds
idle_actions: []const IdleAction = &default_actions,
idle_commands: ?[]const []const u8 = null, // a list of simple commands
@ -64,6 +65,7 @@ start_debugger_on_crash: bool = false,
completion_trigger: CompletionTrigger = .automatic,
completion_style: CompletionStyle = .dropdown,
completion_insert_mode: CompletionInsertMode = .insert,
completion_info_mode: CompletionInfoMode = .box,
widget_style: WidgetStyle = .compact,
palette_style: WidgetStyle = .bars_top_bottom,
@ -74,6 +76,7 @@ pane_left_style: WidgetStyle = .bar_right,
pane_right_style: WidgetStyle = .bar_left,
pane_style: PaneStyle = .panel,
hint_window_style: WidgetStyle = .thick_boxed,
info_box_style: WidgetStyle = .bar_left_spacious,
centered_view: bool = false,
centered_view_width: usize = 145,
@ -119,6 +122,7 @@ pub const WidgetType = enum {
pane_left,
pane_right,
hint_window,
info_box,
dropdown,
};
@ -135,6 +139,8 @@ pub const WidgetStyle = enum {
single_double_top_bottom_boxed,
single_double_left_right_boxed,
boxed,
bar_left_spacious,
bar_right_spacious,
spacious,
compact,
};
@ -204,6 +210,17 @@ pub const CompletionInsertMode = enum {
replace,
};
pub const CompletionInfoMode = enum {
none,
box,
panel,
};
pub const HoverInfoMode = enum {
box,
panel,
};
pub const Alignment = enum {
left,
right,

View file

@ -396,7 +396,9 @@
"overlay/dropdown-noninvasive": {
"inherit": "normal",
"press": [
["ctrl+space", "toggle_completion_info_mode"],
["alt+f9", "dropdown_next_widget_style"],
["shift+alt+f9", "info_box_next_widget_style"],
["ctrl+p", "palette_menu_up"],
["ctrl+n", "palette_menu_down"],
["escape", "palette_menu_cancel"],
@ -409,7 +411,9 @@
"overlay/dropdown": {
"inherit": "normal",
"press": [
["ctrl+space", "toggle_completion_info_mode"],
["alt+f9", "dropdown_next_widget_style"],
["shift+alt+f9", "info_box_next_widget_style"],
["ctrl+p", "palette_menu_up"],
["ctrl+n", "palette_menu_down"],
["escape", "palette_menu_cancel"],

View file

@ -61,6 +61,8 @@ pub const Border = struct {
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 @"thick bar left (octant)": Border = .{ .nw = "", .n = " ", .ne = " ", .e = " ", .se = " ", .s = " ", .sw = "", .w = "", .nib = " ", .nie = " ", .sib = " ", .sie = " " };
const @"thick bar right (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 = "" };
};
@ -132,6 +134,16 @@ const bar_right: @This() = .{
.border = Border.@"thick box (octant)",
};
const bar_left_spacious: @This() = .{
.padding = Margin.@"1/2",
.border = Border.@"thick bar left (octant)",
};
const bar_right_spacious: @This() = .{
.padding = Margin.@"1/2",
.border = Border.@"thick bar right (octant)",
};
pub fn from_tag(tag: WidgetStyle) *const @This() {
return switch (tag) {
.compact => &compact,
@ -148,6 +160,8 @@ pub fn from_tag(tag: WidgetStyle) *const @This() {
.bars_left_right => &bars_left_right,
.bar_left => &bar_left,
.bar_right => &bar_right,
.bar_left_spacious => &bar_left_spacious,
.bar_right_spacious => &bar_right_spacious,
};
}
@ -169,6 +183,7 @@ pub fn theme_style_from_type(style_type: WidgetType, theme: *const Theme) Theme.
.editor => .{ .fg = theme.editor_widget.bg, .bg = theme.editor.bg },
},
.hint_window => .{ .fg = theme.editor_widget_border.fg, .bg = theme.editor_widget.bg },
.info_box => .{ .fg = theme.editor_widget_border.fg, .bg = theme.editor_widget.bg },
};
}

View file

@ -28,6 +28,7 @@ const WidgetList = @import("WidgetList.zig");
const tui = @import("tui.zig");
const IndentMode = @import("config").IndentMode;
const WhitespaceMode = @import("config").WhitespaceMode;
const info_view = @import("info_view.zig");
pub const Cursor = Buffer.Cursor;
pub const View = Buffer.View;
@ -414,6 +415,7 @@ pub const Editor = struct {
diag_warnings: usize = 0,
diag_info: usize = 0,
diag_hints: usize = 0,
info_box: ?Widget = null,
completions: CompletionState = .empty,
completions_request: ?CompletionState = .done,
@ -643,6 +645,7 @@ pub const Editor = struct {
var meta: std.Io.Writer.Allocating = .init(self.allocator);
defer meta.deinit();
if (self.buffer) |_| self.write_state(&meta.writer) catch {};
if (self.info_box) |*w| w.deinit(self.allocator);
for (self.diagnostics.items) |*d| d.deinit(self.allocator);
self.diagnostics.deinit(self.allocator);
self.completions.deinit(self.allocator);
@ -1294,6 +1297,7 @@ pub const Editor = struct {
self.render_blame(theme, hl_row, ctx_.cell_map) catch {};
self.render_column_highlights() catch {};
self.render_cursors(theme, ctx_.cell_map, focused) catch {};
if (self.info_box) |w| _ = w.render(theme);
}
fn render_cursors(self: *Self, theme: *const Widget.Theme, cell_map: CellMap, focused: bool) !void {
@ -1919,8 +1923,10 @@ pub const Editor = struct {
self.last.cursels = self.cursels.items.len;
}
if (lines != self.last.lines or !primary.cursor.eql(self.last.primary.cursor))
if (lines != self.last.lines or !primary.cursor.eql(self.last.primary.cursor)) {
self.clear_info_box();
try self.send_editor_pos(lines, &primary.cursor);
}
if (primary.selection) |primary_selection_| {
var primary_selection = primary_selection_;
@ -1934,8 +1940,10 @@ pub const Editor = struct {
} else if (self.last.primary.selection) |_|
try self.send_editor_selection_removed();
if (lines != self.last.lines or !self.view.eql(self.last.view))
if (lines != self.last.lines or !self.view.eql(self.last.view)) {
self.clear_info_box();
try self.send_editor_view(lines, self.view);
}
self.last.view = self.view;
self.last.lines = lines;
@ -2044,6 +2052,56 @@ pub const Editor = struct {
_ = try self.handlers.msg(.{ "E", "eol_mode", eol_mode, utf8_sanitized, indent_mode });
}
fn clear_info_box(self: *Self) void {
if (self.info_box) |*w| {
w.deinit(self.allocator);
self.info_box = null;
self.clear_matches();
}
}
const info_box_widget_type: Widget.Type = .info_box;
fn show_info_box(self: *Self) !*info_view {
const w = self.info_box orelse blk: {
self.info_box = try info_view.create_widget_type(self.allocator, self.plane, info_box_widget_type);
break :blk self.info_box.?;
};
const info_ = if (w.get(@typeName(info_view))) |w_| w_.dynamic_cast(info_view) orelse null else null;
const info = info_ orelse @panic("Editor.show_info_box");
return info;
}
fn place_info_box(self: *Self, cursor: Cursor) void {
const w = self.info_box orelse return;
const info = self.show_info_box() catch return;
const padding = tui.get_widget_style(info_box_widget_type).padding;
const dim = info.content_size();
const pos = self.screen_cursor(&cursor) orelse {
self.clear_info_box();
return;
};
const y, const x = self.plane.rel_yx_to_abs(@intCast(pos.row), @intCast(pos.col));
w.resize(.{
.h = dim.rows + padding.top + padding.bottom,
.w = dim.cols + padding.left + padding.right + 3,
.y = @intCast(y + 1),
.x = @intCast(x + 1),
});
}
pub fn set_hover_content(self: *Self, range: Match, content: []const u8) !void {
self.add_hover_highlight(range);
if (content.len == 0) {
self.clear_info_box();
return;
}
const info = try self.show_info_box();
info.clear();
try info.append_content(content);
self.place_info_box(range.begin);
}
fn clamp_abs_offset(self: *Self, abs: bool, offset: usize) void {
var dest: View = self.view;
dest.clamp_offset(&self.get_primary().cursor, abs, offset);
@ -4464,6 +4522,7 @@ pub const Editor = struct {
pub const move_buffer_end_meta: Meta = .{ .description = "Move cursor to end of file" };
pub fn cancel(self: *Self, _: Context) Result {
self.clear_info_box();
self.cancel_all_tabstops();
self.cancel_all_selections();
self.cancel_all_matches();

View file

@ -14,9 +14,13 @@ plane: Plane,
view_rows: usize = 0,
lines: std.ArrayList([]const u8),
const widget_type: Widget.Type = .panel;
const default_widget_type: Widget.Type = .panel;
pub fn create(allocator: Allocator, parent: Plane) !Widget {
return create_widget_type(allocator, parent, default_widget_type);
}
pub fn create_widget_type(allocator: Allocator, parent: Plane, widget_type: Widget.Type) !Widget {
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
const container = try WidgetList.createHStyled(allocator, parent, "panel_frame", .dynamic, widget_type);
@ -51,8 +55,9 @@ pub fn handle_resize(self: *Self, pos: Widget.Box) void {
pub fn append_content(self: *Self, content: []const u8) !void {
var iter = std.mem.splitScalar(u8, content, '\n');
while (iter.next()) |line|
while (iter.next()) |line| if (line.len > 0) {
(try self.lines.addOne(self.allocator)).* = try self.allocator.dupe(u8, line);
};
}
pub fn set_content(self: *Self, content: []const u8) !void {
@ -60,6 +65,12 @@ pub fn set_content(self: *Self, content: []const u8) !void {
return self.append_content(content);
}
pub fn content_size(self: *Self) struct { rows: usize, cols: usize } {
var cols: usize = 0;
for (self.lines.items) |line| cols = @max(cols, line.len);
return .{ .rows = self.lines.items.len, .cols = cols };
}
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
self.plane.set_base_style(theme.panel);
self.plane.erase();

View file

@ -175,12 +175,14 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
if (self.get_editor_for_file(path)) |editor| editor.done_highlight_reference();
return true;
} else if (try m.match(.{ "hover", tp.extract(&path), tp.string, tp.extract(&lines), tp.extract(&begin_line), tp.extract(&begin_pos), tp.extract(&end_line), tp.extract(&end_pos) })) {
try self.set_info_content(lines, .replace);
if (self.get_editor_for_file(path)) |editor|
editor.add_hover_highlight(.{
.begin = .{ .row = begin_line, .col = begin_pos },
.end = .{ .row = end_line, .col = end_pos },
});
switch (tui.config().hover_info_mode) {
.panel => self.set_info_content(lines, .replace) catch {},
.box => if (self.get_editor_for_file(path)) |editor|
editor.set_hover_content(.{
.begin = .{ .row = begin_line, .col = begin_pos },
.end = .{ .row = end_line, .col = end_pos },
}, lines) catch |e| return tp.exit_error(e, @errorReturnTrace()),
}
return true;
} else if (try m.match(.{ "navigate_complete", tp.extract(&path), tp.extract(&goto_args), tp.extract(&line), tp.extract(&column) })) {
cmds.navigate_complete(self, null, path, goto_args, line, column, null) catch |e| return tp.exit_error(e, @errorReturnTrace());
@ -339,6 +341,10 @@ fn close_all_panel_views(self: *Self) void {
tui.resize();
}
pub fn hide_info_view_panel(self: *Self) void {
self.toggle_panel_view(info_view, .disable) catch {};
}
fn check_all_not_dirty(self: *const Self) command.Result {
if (self.buffer_manager.is_dirty())
return tp.exit("unsaved changes");

View file

@ -13,6 +13,7 @@ pub const Type = @import("dropdown.zig").Create(@This());
const ed = @import("../../editor.zig");
const module_name = @typeName(@This());
const Widget = @import("../../Widget.zig");
const info_view = @import("../../info_view.zig");
pub const label = "Select completion";
pub const name = "completion";
@ -24,6 +25,8 @@ pub const widget_type: Widget.Type = .dropdown;
pub var detail_limit: usize = 40;
pub var description_limit: usize = 25;
const info_box_widget_type: Widget.Type = .info_box;
pub const Entry = struct {
label: []const u8,
sort_text: []const u8,
@ -38,6 +41,7 @@ pub const ValueType = struct {
last_query: ?[]const u8 = null,
commands: command.Collection(cmds) = undefined,
data: []const u8 = &.{},
info_box: ?Widget = null,
};
pub const defaultValue: ValueType = .{};
@ -97,6 +101,7 @@ pub fn load_entries(self: *Type) !usize {
pub fn deinit(self: *Type) void {
self.allocator.free(self.value.data);
if (self.value.last_query) |p| self.allocator.free(p);
if (self.value.info_box) |w| w.deinit(self.allocator);
self.value.commands.deinit();
}
@ -199,6 +204,9 @@ pub fn on_render_menu(self: *Type, button: *Type.ButtonType, theme: *const Widge
tui.rdr().cursor_enable(@intCast(cursor.row), @intCast(cursor.col), tui.get_cursor_shape()) catch {};
}
defer if (selected) if (self.value.info_box) |w| {
_ = w.render(theme);
};
return tui.render_symbol(
&button.plane,
values.label,
@ -217,6 +225,13 @@ pub fn on_render_menu(self: *Type, button: *Type.ButtonType, theme: *const Widge
);
}
pub fn after_resize(self: *Type) void {
if (self.value.info_box) |w| {
w.deinit(self.allocator);
self.value.info_box = null;
}
}
pub const Values = struct {
label: []const u8,
sort_text: []const u8,
@ -351,8 +366,18 @@ fn select(menu: **Type.MenuType, button: *Type.ButtonType, _: Type.Pos) void {
pub fn updated(self: *Type, button_: ?*Type.ButtonType) !void {
const button = button_ orelse return cancel(self);
const values = get_values(button.opts.label);
const mv = tui.mainview() orelse return;
const values = get_values(button.opts.label);
switch (tui.config().completion_info_mode) {
.none => {},
.box => try show_info_box(self, button, values),
.panel => try show_info_panel(mv, values),
}
if (mv.get_active_editor()) |editor|
self.value.view = editor.view;
}
fn show_info_panel(mv: anytype, values: Values) !void {
try mv.set_info_content(values.label, .replace);
try mv.set_info_content(" ", .append); // blank line
try mv.set_info_content(values.detail, .append);
@ -364,8 +389,41 @@ pub fn updated(self: *Type, button_: ?*Type.ButtonType) !void {
}
try mv.set_info_content(" ", .append); // blank line
try mv.set_info_content(values.documentation, .append);
if (mv.get_active_editor()) |editor|
self.value.view = editor.view;
}
fn show_info_box(self: *Type, button: *Type.ButtonType, values: Values) !void {
const w = self.value.info_box orelse blk: {
self.value.info_box = try info_view.create_widget_type(self.allocator, self.menu.container.plane, info_box_widget_type);
break :blk self.value.info_box.?;
};
const info_ = if (w.get(@typeName(info_view))) |w_| w_.dynamic_cast(info_view) orelse null else null;
const info = info_ orelse @panic("show_info_box");
try info.set_content(values.label);
if (values.detail.len > 0) {
try info.append_content(" "); // blank line
try info.append_content(values.detail);
}
if (builtin.mode == .Debug) {
try info.append_content("newText:"); // blank line
try info.append_content(values.textEdit_newText);
try info.append_content("insertText:"); // blank line
try info.append_content(values.insertText);
}
if (values.documentation.len > 0) {
try info.append_content(" "); // blank line
try info.append_content(values.documentation);
}
const padding = tui.get_widget_style(info_box_widget_type).padding;
const btn_box = Widget.Box.from(button.plane);
const dim = info.content_size();
w.resize(.{
.h = dim.rows + padding.top + padding.bottom,
.w = dim.cols + padding.left + padding.right + 3,
.y = btn_box.y,
.x = btn_box.x + btn_box.w + 1,
});
}
pub fn cancel(_: *Type) !void {

View file

@ -71,7 +71,7 @@ pub fn Create(options: type) type {
.menu = try Menu.create(*Self, allocator, tui.plane(), .{
.ctx = self,
.style = widget_type,
.on_render = if (@hasDecl(options, "on_render_menu")) options.on_render_menu else on_render_menu,
.on_render = options.on_render_menu,
.prepare_resize = prepare_resize_menu,
.after_resize = after_resize_menu,
.on_scroll = EventHandler.bind(self, Self.on_scroll),
@ -145,41 +145,6 @@ pub fn Create(options: type) type {
.{ .fg = theme.scrollbar.fg, .bg = theme.editor_widget.bg };
}
fn on_render_menu(_: *Self, button: *ButtonType, theme: *const Widget.Theme, selected: bool) bool {
const style_base = theme.editor_widget;
const style_label = if (button.active) theme.editor_cursor else if (button.hover or selected) theme.editor_selection else theme.editor_widget;
const style_hint = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else style_label;
button.plane.set_base_style(style_base);
button.plane.erase();
button.plane.home();
button.plane.set_style(style_label);
if (button.active or button.hover or selected) {
button.plane.fill(" ");
button.plane.home();
}
var label: []const u8 = undefined;
var hint: []const u8 = undefined;
var iter = button.opts.label; // label contains cbor, first the file name, then multiple match indexes
if (!(cbor.matchString(&iter, &label) catch false))
label = "#ERROR#";
if (!(cbor.matchString(&iter, &hint) catch false))
hint = "";
button.plane.set_style(style_hint);
tui.render_pointer(&button.plane, selected);
button.plane.set_style(style_label);
_ = button.plane.print("{s} ", .{label}) catch {};
button.plane.set_style(style_hint);
_ = button.plane.print_aligned_right(0, "{s} ", .{hint}) catch {};
var index: usize = 0;
var len = cbor.decodeArrayHeader(&iter) catch return false;
while (len > 0) : (len -= 1) {
if (cbor.matchValue(&iter, cbor.extract(&index)) catch break) {
tui.render_match_cell(&button.plane, 0, index + 2, theme) catch break;
} else break;
}
return false;
}
fn prepare_resize_menu(self: *Self, menu: *Menu.State(*Self), _: Widget.Box) Widget.Box {
const padding = tui.get_widget_style(menu.opts.style).padding;
return self.prepare_resize(padding) orelse .{};
@ -217,6 +182,8 @@ pub fn Create(options: type) type {
fn after_resize(self: *Self) void {
self.update_scrollbar();
// self.start_query(0) catch {};
if (@hasDecl(options, "after_resize"))
options.after_resize(self);
}
fn do_resize(self: *Self, padding: Widget.Style.Margin) void {

View file

@ -19,6 +19,7 @@ const syntax = @import("syntax");
const Widget = @import("Widget.zig");
const MessageFilter = @import("MessageFilter.zig");
const MainView = @import("mainview.zig");
const IdleAction = @import("config").IdleAction;
// exports for unittesting
pub const exports = struct {
@ -86,6 +87,7 @@ color_scheme: enum { dark, light } = .dark,
color_scheme_locked: bool = false,
hint_mode: HintMode = .prefix,
last_palette: ?LastPalette = null,
idle_actions_: std.ArrayList(IdleAction) = .empty,
fast_scroll_: bool = false,
alt_scroll_: bool = false,
@ -296,6 +298,7 @@ fn deinit(self: *Self) void {
m.deinit();
self.delayed_init_input_mode = null;
}
self.idle_actions_.deinit(self.allocator);
self.commands.deinit();
if (self.mainview_) |*mv| mv.deinit(self.allocator);
self.message_filters_.deinit();
@ -607,6 +610,9 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
return;
}
if (try m.match(.{ "filter", "term", "exited", tp.more })) // drop late filter errors
return;
if (try m.match(.{ "line_number_mode", tp.more })) // drop broadcast messages
return;
@ -1019,6 +1025,30 @@ fn current_theme(self: *const Self) *const Widget.Theme {
};
}
fn toggle_idle_action(self: *Self, action: IdleAction) !bool {
var enable: bool = true;
if (self.idle_actions_.items.len == 0)
try self.idle_actions_.appendSlice(self.allocator, self.config_.idle_actions);
for (self.idle_actions_.items) |item| if (item == action) {
enable = false;
};
if (enable) {
(try self.idle_actions_.addOne(self.allocator)).* = action;
} else {
for (self.idle_actions_.items, 0..) |item, idx| if (item == action) {
_ = self.idle_actions_.orderedRemove(idx);
break;
};
}
self.config_.idle_actions = self.idle_actions_.items;
try save_config();
return enable;
}
const cmds = struct {
pub const Target = Self;
const Ctx = command.Context;
@ -1178,6 +1208,35 @@ const cmds = struct {
}
pub const toggle_completion_insert_mode_meta: Meta = .{ .description = "Toggle completion insert mode" };
pub fn toggle_completion_info_mode(self: *Self, _: Ctx) Result {
self.config_.completion_info_mode = switch (self.config_.completion_info_mode) {
.none => .box,
.box => .panel,
.panel => blk: {
if (mainview()) |mv| mv.hide_info_view_panel();
break :blk .none;
},
};
defer self.logger.print("completion info mode {t}", .{self.config_.completion_info_mode});
try save_config();
resize();
}
pub const toggle_completion_info_mode_meta: Meta = .{ .description = "Toggle completion item info display" };
pub fn toggle_hover_info_mode(self: *Self, _: Ctx) Result {
self.config_.hover_info_mode = switch (self.config_.hover_info_mode) {
.box => .panel,
.panel => blk: {
if (mainview()) |mv| mv.hide_info_view_panel();
break :blk .box;
},
};
defer self.logger.print("hover info mode {t}", .{self.config_.hover_info_mode});
try save_config();
resize();
}
pub const toggle_hover_info_mode_meta: Meta = .{ .description = "Toggle hover info display" };
pub fn toggle_keybind_hints(self: *Self, _: Ctx) Result {
self.hint_mode = switch (self.hint_mode) {
.all => .prefix,
@ -1203,6 +1262,18 @@ const cmds = struct {
}
pub const toggle_auto_find_meta: Meta = .{ .description = "Toggle auto find mode" };
pub fn toggle_auto_highlight_references(self: *Self, _: Ctx) Result {
const enabled = try self.toggle_idle_action(.highlight_references);
self.logger.print("auto highlight references {s}", .{if (enabled) "enabled" else "disabled"});
}
pub const toggle_auto_highlight_references_meta: Meta = .{ .description = "Toggle auto highlight references" };
pub fn toggle_auto_hover(self: *Self, _: Ctx) Result {
const enabled = try self.toggle_idle_action(.hover);
self.logger.print("auto hover {s}", .{if (enabled) "enabled" else "disabled"});
}
pub const toggle_auto_hover_meta: Meta = .{ .description = "Toggle auto hover" };
pub fn force_color_scheme(self: *Self, ctx: Ctx) Result {
self.force_color_scheme(if (try ctx.args.match(.{"dark"}))
.dark
@ -1643,9 +1714,17 @@ const cmds = struct {
pub const shrink_centered_view_meta: Meta = .{ .description = "Shrink centered view" };
pub fn panel_next_widget_style(_: *Self, _: Ctx) Result {
set_next_style(.panel);
if (mainview()) |mv| if (mv.is_any_panel_view_showing()) {
set_next_style(.panel);
need_render(@src());
try save_config();
return;
};
set_next_style(.info_box);
need_render(@src());
try save_config();
tp.self_pid().send(.{ "cmd", "hover" }) catch {};
return;
}
pub const panel_next_widget_style_meta: Meta = .{};
@ -1663,6 +1742,13 @@ const cmds = struct {
}
pub const dropdown_next_widget_style_meta: Meta = .{};
pub fn info_box_next_widget_style(_: *Self, _: Ctx) Result {
set_next_style(.info_box);
need_render(@src());
try save_config();
}
pub const info_box_next_widget_style_meta: Meta = .{};
pub fn enable_fast_scroll(self: *Self, _: Ctx) Result {
self.fast_scroll_ = true;
}
@ -2355,6 +2441,7 @@ pub fn get_widget_style(widget_type: WidgetType) *const WidgetStyle {
.pane_left => WidgetStyle.from_tag(config_.pane_left_style),
.pane_right => WidgetStyle.from_tag(config_.pane_right_style),
.hint_window => WidgetStyle.from_tag(config_.hint_window_style),
.info_box => WidgetStyle.from_tag(config_.info_box_style),
};
}
@ -2368,7 +2455,8 @@ pub fn set_next_style(widget_type: WidgetType) void {
fn next_widget_style(tag: ConfigWidgetStyle) ConfigWidgetStyle {
const max_tag = comptime std.meta.tags(ConfigWidgetStyle).len;
const new_value = @intFromEnum(tag) + 1;
const value: usize = @intFromEnum(tag);
const new_value = value + 1;
return if (new_value >= max_tag) @enumFromInt(0) else @enumFromInt(new_value);
}
@ -2383,6 +2471,7 @@ fn widget_type_config_variable(widget_type: WidgetType) *ConfigWidgetStyle {
.pane_left => &config_.pane_left_style,
.pane_right => &config_.pane_right_style,
.hint_window => &config_.hint_window_style,
.info_box => &config_.info_box_style,
};
}