168 lines
5.9 KiB
Zig
168 lines
5.9 KiB
Zig
const std = @import("std");
|
|
const fmt = std.fmt;
|
|
const cbor = @import("cbor");
|
|
const tp = @import("thespian");
|
|
const root = @import("soft_root").root;
|
|
const text_manip = @import("text_manip");
|
|
const command = @import("command");
|
|
const Buffer = @import("Buffer");
|
|
const SymbolKind = @import("lsp_types").SymbolKind;
|
|
|
|
const tui = @import("../../tui.zig");
|
|
pub const Type = @import("palette.zig").Create(@This());
|
|
const ed = @import("../../editor.zig");
|
|
const module_name = @typeName(@This());
|
|
const Widget = @import("../../Widget.zig");
|
|
|
|
pub const label = "Go to Symbol";
|
|
pub const name = "Go to";
|
|
pub const description = "Symbols in scope";
|
|
pub const icon = " ";
|
|
pub const modal_dim = false;
|
|
pub const placement = .top_right;
|
|
|
|
pub const Entry = struct {
|
|
label: []const u8,
|
|
range: ed.Selection,
|
|
cbor: []const u8,
|
|
};
|
|
|
|
pub const ValueType = struct {
|
|
start: ed.CurSel = .{},
|
|
view: ed.View = .{},
|
|
};
|
|
pub const defaultValue: ValueType = .{};
|
|
|
|
pub fn load_entries(palette: *Type) !usize {
|
|
const mv = tui.mainview() orelse return 0;
|
|
const editor = tui.get_active_editor() orelse return error.NotFound;
|
|
var max_cols_len: u8 = 0;
|
|
var max_label_len: usize = 0;
|
|
|
|
palette.value.start = editor.get_primary().*;
|
|
palette.value.view = editor.view;
|
|
var iter: []const u8 = mv.symbols.items;
|
|
while (iter.len > 0) {
|
|
var cbor_item: []const u8 = undefined;
|
|
if (!try cbor.matchValue(&iter, cbor.extract_cbor(&cbor_item))) return error.BadCompletion;
|
|
const label_, _, _, const sel = get_values(cbor_item);
|
|
const label_len_ = tui.egc_chunk_width(label_, 0, 1);
|
|
(try palette.entries.addOne(palette.allocator)).* = .{ .cbor = cbor_item, .label = label_, .range = sel };
|
|
|
|
const label_len: u8 = @truncate(label_len_);
|
|
max_cols_len = @max(max_cols_len, label_len);
|
|
max_label_len = @max(max_label_len, label_len);
|
|
}
|
|
|
|
const less_fn = struct {
|
|
fn less_fn(_: void, lhs: Entry, rhs: Entry) bool {
|
|
return lhs.range.begin.row < rhs.range.begin.row;
|
|
}
|
|
}.less_fn;
|
|
std.mem.sort(Entry, palette.entries.items, {}, less_fn);
|
|
|
|
palette.initial_selected = find_closest(palette);
|
|
palette.quick_activate_enabled = false;
|
|
|
|
return 5 + max_label_len;
|
|
}
|
|
|
|
pub fn clear_entries(palette: *Type) void {
|
|
palette.entries.clearRetainingCapacity();
|
|
}
|
|
|
|
pub fn add_menu_entry(palette: *Type, entry: *Entry, matches: ?[]const usize) !void {
|
|
var value: std.Io.Writer.Allocating = .init(palette.allocator);
|
|
defer value.deinit();
|
|
const writer = &value.writer;
|
|
try writer.writeAll(entry.cbor);
|
|
try cbor.writeValue(writer, matches orelse &[_]usize{});
|
|
try palette.menu.add_item_with_handler(value.written(), select);
|
|
palette.items += 1;
|
|
}
|
|
|
|
pub fn on_render_menu(_: *Type, button: *Type.ButtonType, theme: *const Widget.Theme, selected: bool) bool {
|
|
var item_cbor: []const u8 = undefined;
|
|
var matches_cbor: []const u8 = undefined;
|
|
|
|
var iter = button.opts.label;
|
|
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&item_cbor)) catch false)) return false;
|
|
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) return false;
|
|
|
|
const label_, const container, const kind, _ = get_values(item_cbor);
|
|
const icon_: []const u8 = kind.icon();
|
|
const color: u24 = 0x0;
|
|
return tui.render_symbol(
|
|
&button.plane,
|
|
label_,
|
|
icon_,
|
|
color,
|
|
container,
|
|
@tagName(kind),
|
|
matches_cbor,
|
|
button.active,
|
|
selected,
|
|
button.hover,
|
|
theme,
|
|
&.{},
|
|
&.{},
|
|
if (container.len > 0) " → " else &.{},
|
|
);
|
|
}
|
|
|
|
fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, SymbolKind, ed.Selection } {
|
|
var label_: []const u8 = "";
|
|
var container: []const u8 = "";
|
|
var kind: u8 = 0;
|
|
var range: ed.Selection = .{};
|
|
_ = cbor.match(item_cbor, .{
|
|
cbor.any, // file_path
|
|
cbor.extract(&label_), // name
|
|
cbor.extract(&container), // parent_name
|
|
cbor.extract(&kind), // kind
|
|
cbor.extract(&range.begin.row), // range.begin.row
|
|
cbor.extract(&range.begin.col), // range.begin.col
|
|
cbor.extract(&range.end.row), // range.end.row
|
|
cbor.extract(&range.end.col), // range.end.col
|
|
cbor.any, // tags
|
|
cbor.any, // selectionRange.begin.row
|
|
cbor.any, // selectionRange.begin.col
|
|
cbor.any, // selectionRange.end.row
|
|
cbor.any, // selectionRange.end.col
|
|
cbor.any, // deprecated
|
|
cbor.any, // detail
|
|
}) catch false;
|
|
return .{ label_, container, @enumFromInt(kind), range };
|
|
}
|
|
|
|
fn find_closest(palette: *Type) ?usize {
|
|
const editor = tui.get_active_editor() orelse return null;
|
|
const cursor = editor.get_primary().cursor;
|
|
var previous: usize = 0;
|
|
for (palette.entries.items, 0..) |entry, idx| {
|
|
_, _, _, const sel = get_values(entry.cbor);
|
|
if (cursor.row < sel.begin.row) return previous + 1;
|
|
previous = idx;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
fn select(menu: **Type.MenuType, button: *Type.ButtonType, _: Type.Pos) void {
|
|
const editor = tui.get_active_editor() orelse return;
|
|
editor.clear_matches();
|
|
_, _, _, const sel = get_values(button.opts.label);
|
|
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
|
tp.self_pid().send(.{ "cmd", "goto_line_and_column", .{ sel.begin.row + 1, sel.begin.col + 1 } }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
|
}
|
|
|
|
pub fn updated(palette: *Type, button_: ?*Type.ButtonType) !void {
|
|
const button = button_ orelse return cancel(palette);
|
|
_, _, _, const sel = get_values(button.opts.label);
|
|
tp.self_pid().send(.{ "cmd", "focus_on_range", .{ sel.begin.row, sel.begin.col, sel.end.row, sel.end.col } }) catch {};
|
|
}
|
|
|
|
pub fn cancel(palette: *Type) !void {
|
|
const editor = tui.get_active_editor() orelse return;
|
|
editor.clear_matches();
|
|
editor.update_scroll_dest_abs(palette.value.view.row);
|
|
}
|