feat: start work on file list view
This commit is contained in:
parent
054400ce3b
commit
d22dcff571
2 changed files with 158 additions and 0 deletions
154
src/tui/filelist_view.zig
Normal file
154
src/tui/filelist_view.zig
Normal file
|
@ -0,0 +1,154 @@
|
|||
const std = @import("std");
|
||||
const eql = @import("std").mem.eql;
|
||||
const fmt = @import("std").fmt;
|
||||
const time = @import("std").time;
|
||||
const cbor = @import("cbor");
|
||||
const Allocator = @import("std").mem.Allocator;
|
||||
const Mutex = @import("std").Thread.Mutex;
|
||||
const ArrayList = @import("std").ArrayList;
|
||||
const Plane = @import("renderer").Plane;
|
||||
|
||||
const tp = @import("thespian");
|
||||
const log = @import("log");
|
||||
|
||||
const tui = @import("tui.zig");
|
||||
const Widget = @import("Widget.zig");
|
||||
const MessageFilter = @import("MessageFilter.zig");
|
||||
const Menu = @import("Menu.zig");
|
||||
const EventHandler = @import("EventHandler.zig");
|
||||
const Button = @import("Button.zig");
|
||||
|
||||
const escape = fmt.fmtSliceEscapeLower;
|
||||
|
||||
pub const name = @typeName(Self);
|
||||
|
||||
const Self = @This();
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
plane: Plane,
|
||||
menu: *Menu.State(*Self),
|
||||
logger: log.Logger,
|
||||
|
||||
items: usize = 0,
|
||||
view_pos: usize = 0,
|
||||
total_items: usize = 0,
|
||||
entries: std.ArrayList(Entry) = undefined,
|
||||
|
||||
const Entry = struct {
|
||||
path: []const u8,
|
||||
begin_line: usize,
|
||||
begin_pos: usize,
|
||||
end_line: usize,
|
||||
end_pos: usize,
|
||||
lines: []const u8,
|
||||
};
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane) !Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(name), parent),
|
||||
.logger = log.logger(@typeName(Self)),
|
||||
.entries = std.ArrayList(Entry).init(allocator),
|
||||
.menu = try Menu.create(*Self, allocator, tui.current().mainview, .{
|
||||
.ctx = self,
|
||||
.on_render = handle_render_menu,
|
||||
// .on_resize = on_resize_menu,
|
||||
.on_scroll = EventHandler.bind(self, Self.handle_scroll),
|
||||
}),
|
||||
};
|
||||
(try self.entries.addOne()).* = .{ .path = "file_path_1.zig", .begin_line = 1, .begin_pos = 1, .end_line = 1, .end_pos = 10, .lines = "matching text" };
|
||||
(try self.entries.addOne()).* = .{ .path = "file_path_2.zig", .begin_line = 1, .begin_pos = 1, .end_line = 1, .end_pos = 10, .lines = "matching text" };
|
||||
(try self.entries.addOne()).* = .{ .path = "file_path_3.zig", .begin_line = 1, .begin_pos = 1, .end_line = 1, .end_pos = 10, .lines = "matching text" };
|
||||
try self.add_item(0);
|
||||
try self.add_item(1);
|
||||
try self.add_item(2);
|
||||
return Widget.to(self);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, a: Allocator) void {
|
||||
self.plane.deinit();
|
||||
a.destroy(self);
|
||||
}
|
||||
|
||||
pub fn handle_resize(self: *Self, pos: Widget.Box) void {
|
||||
self.menu.resize(pos);
|
||||
}
|
||||
|
||||
fn add_item(self: *Self, idx: usize) !void {
|
||||
var label = std.ArrayList(u8).init(self.allocator);
|
||||
defer label.deinit();
|
||||
const writer = label.writer();
|
||||
try cbor.writeValue(writer, idx);
|
||||
try self.menu.add_item_with_handler(label.items, handle_menu_action);
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
return self.menu.render(theme);
|
||||
}
|
||||
|
||||
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.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);
|
||||
button.plane.erase();
|
||||
button.plane.home();
|
||||
var idx: usize = undefined;
|
||||
var iter = button.opts.label; // label contains cbor, just the index
|
||||
if (!(cbor.matchValue(&iter, cbor.extract(&idx)) catch false)) {
|
||||
const json = cbor.toJsonAlloc(self.allocator, iter) catch return false;
|
||||
defer self.allocator.free(json);
|
||||
self.logger.print_err(name, "invalid table entry: {s}", .{json});
|
||||
return false;
|
||||
}
|
||||
if (idx >= self.entries.items.len) {
|
||||
self.logger.print_err(name, "table entry index out of range: {d}/{d}", .{ idx, self.entries.items.len });
|
||||
return false;
|
||||
}
|
||||
const entry = &self.entries.items[idx];
|
||||
const pointer = if (selected) "⏵" else " ";
|
||||
_ = button.plane.print("{s} ", .{pointer}) catch {};
|
||||
button.plane.set_style(style_base);
|
||||
_ = button.plane.print("{s} ", .{entry.path}) catch {};
|
||||
return false;
|
||||
}
|
||||
|
||||
fn render_cell(plane: *Plane, y: usize, x: usize, style: Widget.Theme.Style) !void {
|
||||
plane.cursor_move_yx(@intCast(y), @intCast(x)) catch return;
|
||||
var cell = plane.cell_init();
|
||||
_ = plane.at_cursor_cell(&cell) catch return;
|
||||
cell.set_style(style);
|
||||
_ = plane.putc(&cell) catch {};
|
||||
}
|
||||
|
||||
fn handle_scroll(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!void {
|
||||
_ = try m.match(.{ "scroll_to", tp.extract(&self.view_pos) });
|
||||
}
|
||||
|
||||
fn handle_menu_action(menu: **Menu.State(*Self), button: *Button.State(*Menu.State(*Self))) void {
|
||||
const self = menu.*.opts.ctx;
|
||||
var idx: usize = undefined;
|
||||
var iter = button.opts.label;
|
||||
if (!(cbor.matchValue(&iter, cbor.extract(&idx)) catch return)) {
|
||||
const json = cbor.toJsonAlloc(self.allocator, button.opts.label) catch return;
|
||||
self.logger.print_err(name, "invalid table entry: {s}", .{json});
|
||||
return;
|
||||
}
|
||||
if (idx >= self.entries.items.len) {
|
||||
self.logger.print_err(name, "table entry index out of range: {d}/{d}", .{ idx, self.entries.items.len });
|
||||
return;
|
||||
}
|
||||
const entry = &self.entries.items[idx];
|
||||
|
||||
tp.self_pid().send(.{ "cmd", "navigate", .{
|
||||
.file = entry.path,
|
||||
.goto = .{
|
||||
entry.begin_line,
|
||||
entry.begin_pos,
|
||||
entry.begin_line,
|
||||
entry.begin_pos,
|
||||
entry.end_line,
|
||||
entry.end_pos,
|
||||
},
|
||||
} }) catch |e| self.logger.err("navigate", e);
|
||||
}
|
|
@ -285,6 +285,10 @@ const cmds = struct {
|
|||
_ = try self.toggle_panel_view(@import("inspector_view.zig"), true);
|
||||
}
|
||||
|
||||
pub fn toggle_filelist_view(self: *Self, _: Ctx) Result {
|
||||
_ = try self.toggle_panel_view(@import("filelist_view.zig"), false);
|
||||
}
|
||||
|
||||
pub fn jump_back(self: *Self, _: Ctx) Result {
|
||||
try self.location_history.back(location_jump);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue