diff --git a/src/main.zig b/src/main.zig index 52506e0..7155a5c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -587,3 +587,14 @@ pub fn is_directory(rel_path: []const u8) !bool { dir.close(); return true; } + +pub fn shorten_path(buf: []u8, path: []const u8, removed_prefix: *usize, max_len: usize) []const u8 { + removed_prefix.* = 0; + if (path.len <= max_len) return path; + const ellipsis = "…"; + const prefix = path.len - max_len; + defer removed_prefix.* = prefix - 1; + @memcpy(buf[0..ellipsis.len], ellipsis); + @memcpy(buf[ellipsis.len .. max_len + ellipsis.len], path[prefix..]); + return buf[0 .. max_len + ellipsis.len]; +} diff --git a/src/tui/filelist_view.zig b/src/tui/filelist_view.zig index 27d6493..6cb01e5 100644 --- a/src/tui/filelist_view.zig +++ b/src/tui/filelist_view.zig @@ -12,6 +12,7 @@ const tp = @import("thespian"); const log = @import("log"); const key = @import("renderer").input.key; const event_type = @import("renderer").input.event_type; +const root = @import("root"); const command = @import("command.zig"); const tui = @import("tui.zig"); @@ -37,9 +38,12 @@ commands: Commands = undefined, items: usize = 0, view_pos: usize = 0, view_rows: usize = 0, +view_cols: usize = 0, entries: std.ArrayList(Entry) = undefined, selected: ?usize = null, +const path_column_ratio = 4; + const Entry = struct { path: []const u8, begin_line: usize, @@ -79,6 +83,7 @@ pub fn handle_resize(self: *Self, pos: Widget.Box) void { self.plane.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return; self.menu.container_widget.resize(pos); self.view_rows = pos.h; + self.view_cols = pos.w; self.update_scrollbar(); } @@ -121,7 +126,9 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool { fn handle_render_menu(self: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme, selected: bool) bool { const style_base = if (button.active) theme.editor_cursor else if (button.hover or selected) theme.editor_selection else theme.panel; - // const style_keybind = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else style_base; + const style_info: Widget.Theme.Style = .{ .fg = theme.editor_information.fg, .fs = theme.editor_information.fs, .bg = style_base.bg }; + const style_separator: Widget.Theme.Style = .{ .fg = theme.editor_selection.bg, .bg = style_base.bg }; + // const style_error: Widget.Theme.Style = .{ .fg = theme.editor_error.fg, .fs = theme.editor_error.fs, .bg = style_base.bg }; button.plane.set_base_style(" ", style_base); button.plane.erase(); button.plane.home(); @@ -140,8 +147,16 @@ fn handle_render_menu(self: *Self, button: *Button.State(*Menu.State(*Self)), th const entry = &self.entries.items[idx]; const pointer = if (selected) "⏵" else " "; _ = button.plane.print("{s} ", .{pointer}) catch {}; + var buf: [std.fs.max_path_bytes]u8 = undefined; + var removed_prefix: usize = 0; + const max_len = self.view_cols / path_column_ratio; button.plane.set_style(style_base); - _ = button.plane.print("{s}:{d} {s}", .{ entry.path, entry.begin_line + 1, entry.lines }) catch {}; + _ = button.plane.print("{s}:{d}", .{ root.shorten_path(&buf, entry.path, &removed_prefix, max_len - 6), entry.begin_line + 1 }) catch {}; + button.plane.cursor_move_yx(0, @intCast(max_len)) catch return false; + button.plane.set_style(style_separator); + _ = button.plane.print(" ▏", .{}) catch {}; + button.plane.set_style(style_info); + _ = button.plane.print("{s}", .{entry.lines}) catch {}; return false; } diff --git a/src/tui/mode/overlay/open_recent.zig b/src/tui/mode/overlay/open_recent.zig index ba5e875..51aea07 100644 --- a/src/tui/mode/overlay/open_recent.zig +++ b/src/tui/mode/overlay/open_recent.zig @@ -2,6 +2,7 @@ const std = @import("std"); const tp = @import("thespian"); const log = @import("log"); const cbor = @import("cbor"); +const root = @import("root"); const Plane = @import("renderer").Plane; const planeutils = @import("renderer").planeutils; @@ -88,7 +89,7 @@ inline fn max_menu_width() usize { return @max(15, width - (width / 5)); } -fn on_render_menu(self: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme, selected: bool) bool { +fn on_render_menu(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme, selected: bool) bool { const style_base = if (button.active) theme.editor_cursor else if (button.hover or selected) theme.editor_selection else theme.editor_widget; const style_keybind = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else style_base; button.plane.set_base_style(" ", style_base); @@ -103,9 +104,10 @@ fn on_render_menu(self: *Self, button: *Button.State(*Menu.State(*Self)), theme: _ = button.plane.print("{s}", .{ pointer }) catch {}; var buf: [std.fs.max_path_bytes]u8 = undefined; var removed_prefix: usize = 0; + const max_len = max_menu_width() - 2; button.plane.set_style(style_base); _ = button.plane.print("{s} ", .{ - if (file_path.len > max_menu_width() - 2) self.shorten_path(&buf, file_path, &removed_prefix) else file_path, + if (file_path.len > max_len) root.shorten_path(&buf, file_path, &removed_prefix, max_len) else file_path, }) catch {}; var index: usize = 0; var len = cbor.decodeArrayHeader(&iter) catch return false; @@ -138,18 +140,6 @@ fn menu_action_open_file(menu: **Menu.State(*Self), button: *Button.State(*Menu. tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch |e| menu.*.opts.ctx.logger.err("navigate", e); } -fn shorten_path(_: *Self, buf: []u8, path: []const u8, removed_prefix: *usize) []const u8 { - const max_len = max_menu_width() - 2; - removed_prefix.* = 0; - if (path.len <= max_len) return path; - const ellipsis = "…"; - const prefix = path.len - max_len; - defer removed_prefix.* = prefix - 1; - @memcpy(buf[0..ellipsis.len], ellipsis); - @memcpy(buf[ellipsis.len .. max_len + ellipsis.len], path[prefix..]); - return buf[0 .. max_len + ellipsis.len]; -} - fn add_item(self: *Self, file_name: []const u8, matches: ?[]const u8) !void { var label = std.ArrayList(u8).init(self.a); defer label.deinit();