Compare commits

...

6 commits

4 changed files with 125 additions and 7 deletions

View file

@ -7,6 +7,7 @@
["ctrl+e", "find_file"],
["ctrl+shift+n", "create_new_file"],
["ctrl+r", "open_recent_project"],
["ctrl+,", "last_palette"],
["f1", "open_help"],
["ctrl+\\", "add_split"],
["ctrl+k w", "close_split"],

View file

@ -240,7 +240,7 @@
["space s", "show_symbols"],
["space d", "show_diagnostics"],
["space a", "code_action"],
["space '", "last_picker"],
["space '", "last_palette"],
["space y", "copy"],
["space p", "system_paste_after"],
["space /", "find_in_files"],
@ -526,10 +526,10 @@
["space f", "find_file"],
["space b", "switch_buffers"],
["space j", "jumplist_picker"],
["space s", "symbol_picker"],
["space s", "show_symbols"],
["space d", "show_diagnostics"],
["space a", "code_action"],
["space '", "last_picker"],
["space '", "last_palette"],
["space y", "copy"],
["space p", "system_paste_after"],
["space /", "find_in_files"],

View file

@ -40,12 +40,18 @@ buffer_manager: ?*BufferManager,
split: enum { none, vertical } = .none,
total_items: usize = 0,
total_files_in_project: usize = 0,
quick_activate_enabled: bool = true,
restore_info: std.ArrayList([]const u8) = .empty,
const inputbox_label = "Search files by name";
const MenuType = Menu.Options(*Self).MenuType;
const ButtonType = MenuType.ButtonType;
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
return create_with_args(allocator, .{});
}
pub fn create_with_args(allocator: std.mem.Allocator, ctx: command.Context) !tui.Mode {
const mv = tui.mainview() orelse return error.NotFound;
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
@ -70,8 +76,15 @@ pub fn create(allocator: std.mem.Allocator) !tui.Mode {
};
try self.commands.init(self);
try tui.message_filters().add(MessageFilter.bind(self, receive_project_manager));
self.query_pending = true;
try project_manager.request_recent_files(max_recent_files);
if (ctx.args.buf.len != 0) {
try self.restore(ctx);
self.quick_activate_enabled = false;
} else {
self.query_pending = true;
try project_manager.request_recent_files(max_recent_files);
}
self.do_resize();
try mv.floating_views.add(self.modal.widget());
try mv.floating_views.add(self.menu.container_widget);
@ -84,6 +97,8 @@ pub fn create(allocator: std.mem.Allocator) !tui.Mode {
}
pub fn deinit(self: *Self) void {
self.save();
self.clear_restore_info();
self.commands.deinit();
tui.message_filters().remove_ptr(self);
if (tui.mainview()) |mv| {
@ -94,6 +109,60 @@ pub fn deinit(self: *Self) void {
self.allocator.destroy(self);
}
fn clear_restore_info(self: *Self) void {
for (self.restore_info.items) |item| self.allocator.free(item);
self.restore_info.clearRetainingCapacity();
}
fn save(self: *Self) void {
var data: std.Io.Writer.Allocating = .init(self.allocator);
defer data.deinit();
const writer = &data.writer;
cbor.writeArrayHeader(writer, 4) catch return;
cbor.writeValue(writer, self.inputbox.text.items) catch return;
cbor.writeValue(writer, self.longest) catch return;
cbor.writeValue(writer, self.menu.selected) catch return;
cbor.writeArrayHeader(writer, self.restore_info.items.len) catch return;
for (self.restore_info.items) |item| cbor.writeValue(writer, item) catch return;
tui.set_last_palette(.open_recent, .{ .args = .{ .buf = data.written() } });
}
fn restore(self: *Self, ctx: command.Context) !void {
var iter = ctx.args.buf;
if ((cbor.decodeArrayHeader(&iter) catch 0) != 4) return;
var input_: []const u8 = undefined;
if (!(cbor.matchString(&iter, &input_) catch return)) return;
self.inputbox.text.shrinkRetainingCapacity(0);
try self.inputbox.text.appendSlice(self.inputbox.allocator, input_);
self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8);
if (!(cbor.matchValue(&iter, cbor.extract(&self.longest)) catch return)) return;
var selected: ?usize = null;
if (!(cbor.matchValue(&iter, cbor.extract(&selected)) catch return)) return;
var len = cbor.decodeArrayHeader(&iter) catch 0;
while (len > 0) : (len -= 0) {
var item: []const u8 = undefined;
if (!(cbor.matchString(&iter, &item) catch break)) break;
const data = try self.allocator.dupe(u8, item);
errdefer self.allocator.free(data);
try self.restore_item(data);
}
self.do_resize();
if (selected) |idx| {
var i = idx + 1;
while (i > 0) : (i -= 1) self.menu.select_down();
}
}
inline fn menu_width(self: *Self) usize {
return @max(@min(self.longest + 3, max_menu_width()) + 5, inputbox_label.len + 2);
}
@ -129,6 +198,7 @@ fn do_resize(self: *Self) void {
}
fn menu_action_open_file(menu: **MenuType, button: *ButtonType, _: Widget.Pos) void {
menu.*.opts.ctx.save();
var file_path: []const u8 = undefined;
var iter = button.opts.label;
if (!(cbor.matchString(&iter, &file_path) catch false)) return;
@ -148,7 +218,6 @@ fn add_item(
indicator: []const u8,
matches: ?[]const u8,
) !void {
self.total_items += 1;
var label: std.Io.Writer.Allocating = .init(self.allocator);
defer label.deinit();
const writer = &label.writer;
@ -157,7 +226,18 @@ fn add_item(
try cbor.writeValue(writer, file_color);
try cbor.writeValue(writer, indicator);
if (matches) |cb| _ = try writer.write(cb) else try cbor.writeValue(writer, &[_]usize{});
try self.menu.add_item_with_handler(label.written(), menu_action_open_file);
const data = try label.toOwnedSlice();
errdefer self.allocator.free(data);
try self.restore_item(data);
}
fn restore_item(
self: *Self,
label: []const u8,
) error{OutOfMemory}!void {
self.total_items += 1;
try self.menu.add_item_with_handler(label, menu_action_open_file);
(try self.restore_info.addOne(self.allocator)).* = label;
}
fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
@ -253,6 +333,7 @@ fn start_query(self: *Self) MessageFilter.Error!void {
self.total_items = 0;
if (self.query_pending) return;
self.query_pending = true;
self.clear_restore_info();
try project_manager.query_recent_files(max_recent_files, self.inputbox.text.items);
}
@ -370,11 +451,14 @@ const cmds = struct {
pub const palette_menu_activate_alternate_meta: Meta = .{};
pub fn palette_menu_activate_quick(self: *Self, _: Ctx) Result {
if (!self.quick_activate_enabled) return;
if (self.menu.selected orelse 0 > 0) self.menu.activate_selected();
self.quick_activate_enabled = false;
}
pub const palette_menu_activate_quick_meta: Meta = .{};
pub fn palette_menu_cancel(self: *Self, _: Ctx) Result {
self.save();
try self.cmd("exit_overlay_mode", .{});
}
pub const palette_menu_cancel_meta: Meta = .{};

View file

@ -85,9 +85,19 @@ clipboard_current_group_number: usize = 0,
color_scheme: enum { dark, light } = .dark,
color_scheme_locked: bool = false,
hint_mode: HintMode = .prefix,
last_palette: ?LastPalette = null,
const HintMode = enum { none, prefix, all };
const LastPalette = struct {
type_: PaletteType,
ctx: command.Context,
};
pub const PaletteType = enum {
open_recent,
};
pub const ClipboardEntry = struct {
text: []const u8 = &.{},
group: usize = 0,
@ -1177,6 +1187,17 @@ const cmds = struct {
}
pub const open_recent_meta: Meta = .{ .description = "Open recent" };
pub fn last_palette(self: *Self, _: Ctx) Result {
const palette = self.last_palette orelse {
self.logger.print("no previously used palette", .{});
return;
};
switch (palette.type_) {
.open_recent => return self.enter_overlay_mode_with_args(@import("mode/overlay/open_recent.zig"), palette.ctx),
}
}
pub const last_palette_meta: Meta = .{ .description = "Open last used palette" };
pub fn show_vcs_status(self: *Self, _: Ctx) Result {
return self.enter_overlay_mode(@import("mode/overlay/vcs_status.zig"));
}
@ -2234,3 +2255,15 @@ fn clipboard_send_to_system_internal(self: *Self, text: []const u8) void {
self.rdr_.copy_to_system_clipboard(text);
}
}
pub fn set_last_palette(type_: PaletteType, ctx: command.Context) void {
const self = current();
if (self.last_palette) |old| {
self.allocator.free(old.ctx.args.buf);
self.last_palette = null;
}
self.last_palette = .{
.type_ = type_,
.ctx = .{ .args = ctx.args.clone(self.allocator) catch return },
};
}