Compare commits

...

9 commits

6 changed files with 144 additions and 51 deletions

View file

@ -169,6 +169,17 @@ pub fn print_aligned_right(self: *Plane, y: c_int, comptime fmt: anytype, args:
return self.putstr(text);
}
pub fn print_right(self: *Plane, comptime fmt: anytype, args: anytype) !usize {
var buf: [fmt.len + 4096]u8 = undefined;
const text = try std.fmt.bufPrint(&buf, fmt, args);
const width = self.window.width;
const text_width: usize = self.egc_chunk_width(text, 0, 1);
const col: usize = @intCast(self.col);
const space = width -| col;
self.col += @intCast(space -| text_width);
return self.putstr(text);
}
pub fn print_aligned_center(self: *Plane, y: c_int, comptime fmt: anytype, args: anytype) !usize {
var buf: [fmt.len + 4096]u8 = undefined;
const width = self.window.width;

View file

@ -43,13 +43,17 @@ pub fn handle_resize(self: *Self, pos: Widget.Box) void {
self.view_rows = pos.h;
}
pub fn set_content(self: *Self, content: []const u8) !void {
self.clear();
pub fn append_content(self: *Self, content: []const u8) !void {
var iter = std.mem.splitScalar(u8, content, '\n');
while (iter.next()) |line|
(try self.lines.addOne(self.allocator)).* = try self.allocator.dupe(u8, line);
}
pub fn set_content(self: *Self, content: []const u8) !void {
self.clear();
return self.append_content(content);
}
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
self.plane.set_base_style(theme.panel);
self.plane.erase();

View file

@ -167,7 +167,7 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
if (self.get_active_editor()) |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.add_info_content(lines);
try self.set_info_content(lines, .replace);
if (self.get_active_editor()) |editor|
editor.add_hover_highlight(.{
.begin = .{ .row = begin_line, .col = begin_pos },
@ -268,10 +268,10 @@ fn bottom_bar_primary_drag(self: *Self, y: usize) tp.result {
}
}
fn toggle_panel_view(self: *Self, view: anytype, enable_only: bool) !void {
fn toggle_panel_view(self: *Self, view: anytype, mode: enum { toggle, enable, disable }) !void {
if (self.panels) |panels| {
if (panels.get(@typeName(view))) |w| {
if (!enable_only) {
if (mode != .enable) {
panels.remove(w.*);
if (panels.empty()) {
self.widgets.remove(panels.widget());
@ -279,9 +279,10 @@ fn toggle_panel_view(self: *Self, view: anytype, enable_only: bool) !void {
}
}
} else {
try panels.add(try view.create(self.allocator, self.widgets.plane));
if (mode != .disable)
try panels.add(try view.create(self.allocator, self.widgets.plane));
}
} else {
} else if (mode != .disable) {
const panels = try WidgetList.createH(self.allocator, self.widgets.plane, "panel", .{ .static = self.panel_height orelse self.box().h / 5 });
try self.widgets.add(panels.widget());
try panels.add(try view.create(self.allocator, self.widgets.plane));
@ -439,8 +440,8 @@ const cmds = struct {
try self.close_all_editors();
self.delete_all_buffers();
self.clear_find_in_files_results(.diagnostics);
if (self.file_list_type == .diagnostics and self.is_panel_view_showing(filelist_view))
try self.toggle_panel_view(filelist_view, false);
if (self.file_list_type == .diagnostics)
try self.toggle_panel_view(filelist_view, .disable);
self.buffer_manager.deinit();
self.buffer_manager = Buffer.Manager.init(self.allocator);
}
@ -817,46 +818,46 @@ const cmds = struct {
pub fn toggle_panel(self: *Self, _: Ctx) Result {
if (self.is_panel_view_showing(logview))
try self.toggle_panel_view(logview, false)
try self.toggle_panel_view(logview, .toggle)
else if (self.is_panel_view_showing(info_view))
try self.toggle_panel_view(info_view, false)
try self.toggle_panel_view(info_view, .toggle)
else if (self.is_panel_view_showing(filelist_view))
try self.toggle_panel_view(filelist_view, false)
try self.toggle_panel_view(filelist_view, .toggle)
else if (self.is_panel_view_showing(input_view))
try self.toggle_panel_view(input_view, false)
try self.toggle_panel_view(input_view, .toggle)
else
try self.toggle_panel_view(logview, false);
try self.toggle_panel_view(logview, .toggle);
}
pub const toggle_panel_meta: Meta = .{ .description = "Toggle panel" };
pub fn toggle_logview(self: *Self, _: Ctx) Result {
try self.toggle_panel_view(logview, false);
try self.toggle_panel_view(logview, .toggle);
}
pub const toggle_logview_meta: Meta = .{};
pub fn show_logview(self: *Self, _: Ctx) Result {
try self.toggle_panel_view(logview, true);
try self.toggle_panel_view(logview, .enable);
}
pub const show_logview_meta: Meta = .{ .description = "View log" };
pub fn toggle_inputview(self: *Self, _: Ctx) Result {
try self.toggle_panel_view(input_view, false);
try self.toggle_panel_view(input_view, .toggle);
}
pub const toggle_inputview_meta: Meta = .{ .description = "Toggle raw input log" };
pub fn toggle_inspector_view(self: *Self, _: Ctx) Result {
try self.toggle_panel_view(@import("inspector_view.zig"), false);
try self.toggle_panel_view(@import("inspector_view.zig"), .toggle);
}
pub const toggle_inspector_view_meta: Meta = .{ .description = "Toggle inspector view" };
pub fn show_inspector_view(self: *Self, _: Ctx) Result {
try self.toggle_panel_view(@import("inspector_view.zig"), true);
try self.toggle_panel_view(@import("inspector_view.zig"), .enable);
}
pub const show_inspector_view_meta: Meta = .{};
pub fn close_find_in_files_results(self: *Self, _: Ctx) Result {
if (self.file_list_type == .find_in_files and self.is_panel_view_showing(filelist_view))
try self.toggle_panel_view(filelist_view, false);
if (self.file_list_type == .find_in_files)
try self.toggle_panel_view(filelist_view, .disable);
}
pub const close_find_in_files_results_meta: Meta = .{ .description = "Close find in files results view" };
@ -1172,8 +1173,8 @@ const cmds = struct {
editor.clear_diagnostics();
self.clear_find_in_files_results(.diagnostics);
if (self.file_list_type == .diagnostics and self.is_panel_view_showing(filelist_view))
try self.toggle_panel_view(filelist_view, false);
if (self.file_list_type == .diagnostics)
try self.toggle_panel_view(filelist_view, .disable);
}
pub const clear_diagnostics_meta: Meta = .{ .arguments = &.{.string} };
@ -1842,8 +1843,7 @@ fn add_find_in_files_result(
lines: []const u8,
severity: ed.Diagnostic.Severity,
) tp.result {
if (!self.is_panel_view_showing(filelist_view))
_ = self.toggle_panel_view(filelist_view, false) catch |e| return tp.exit_error(e, @errorReturnTrace());
_ = self.toggle_panel_view(filelist_view, .enable) catch |e| return tp.exit_error(e, @errorReturnTrace());
const fl = self.get_panel_view(filelist_view) orelse @panic("filelist_view missing");
if (self.file_list_type != file_list_type) {
self.clear_find_in_files_results(self.file_list_type);
@ -1877,11 +1877,18 @@ fn clear_find_in_files_results(self: *Self, file_list_type: FileListType) void {
fl.reset();
}
fn add_info_content(self: *Self, content: []const u8) tp.result {
pub fn set_info_content(self: *Self, content: []const u8, mode: enum { replace, append }) tp.result {
if (content.len == 0) return;
if (!self.is_panel_view_showing(info_view))
_ = self.toggle_panel_view(info_view, false) catch |e| return tp.exit_error(e, @errorReturnTrace());
_ = self.toggle_panel_view(info_view, .enable) catch |e| return tp.exit_error(e, @errorReturnTrace());
const info = self.get_panel_view(info_view) orelse @panic("info_view missing");
info.set_content(content) catch |e| return tp.exit_error(e, @errorReturnTrace());
switch (mode) {
.replace => info.set_content(content) catch |e| return tp.exit_error(e, @errorReturnTrace()),
.append => info.append_content(content) catch |e| return tp.exit_error(e, @errorReturnTrace()),
}
tui.need_render();
}
pub fn cancel_info_content(self: *Self) tp.result {
_ = self.toggle_panel_view(info_view, .disable) catch |e| return tp.exit_error(e, @errorReturnTrace());
tui.need_render();
}

View file

@ -15,11 +15,12 @@ pub const label = "Select completion";
pub const name = "completion";
pub const description = "completions";
pub const icon = "󱎸 ";
pub const modal_dim = false;
pub const placement = .top_right;
pub const Entry = struct {
label: []const u8,
sort_text: []const u8,
detail: []const u8,
cbor: []const u8,
};
@ -29,7 +30,7 @@ pub const ValueType = struct {
};
pub const defaultValue: ValueType = .{};
var max_detail: usize = 0;
var max_description: usize = 0;
pub fn load_entries(palette: *Type) !usize {
const editor = tui.get_active_editor() orelse return error.NotFound;
@ -38,21 +39,24 @@ pub fn load_entries(palette: *Type) !usize {
while (iter.len > 0) {
var cbor_item: []const u8 = undefined;
if (!try cbor.matchValue(&iter, cbor.extract_cbor(&cbor_item))) return error.BadCompletion;
(try palette.entries.addOne(palette.allocator)).* = .{ .cbor = cbor_item, .label = undefined, .sort_text = undefined, .detail = undefined };
(try palette.entries.addOne(palette.allocator)).* = .{ .cbor = cbor_item, .label = undefined, .sort_text = undefined };
}
max_detail = 0;
max_description = 0;
var max_label_len: usize = 0;
for (palette.entries.items) |*item| {
const label_, const sort_text, _, const maybe_replace, _, const detail = get_values(item.cbor);
const label_, const sort_text, _, const maybe_replace, _, const label_detail, const label_description, _, _ = get_values(item.cbor);
if (get_replace_selection(maybe_replace)) |replace| {
if (palette.value.replace == null) palette.value.replace = replace;
}
item.label = label_;
item.sort_text = sort_text;
item.detail = detail;
var lines = std.mem.splitScalar(u8, label_description, '\n');
const label_description_len = if (lines.next()) |desc| desc.len else label_description.len;
max_label_len = @max(max_label_len, item.label.len);
max_detail = @max(max_detail, item.detail.len);
max_description = @max(max_description, label_description_len + label_detail.len);
}
const less_fn = struct {
@ -64,8 +68,8 @@ pub fn load_entries(palette: *Type) !usize {
}.less_fn;
std.mem.sort(Entry, palette.entries.items, {}, less_fn);
max_detail = @min(max_detail, tui.screen().w -| max_label_len -| 10);
return @max(max_detail, if (max_label_len > label.len + 3) 0 else label.len + 3 - max_label_len);
max_description = @min(max_description, tui.screen().w -| max_label_len -| 10);
return @max(max_description, if (max_label_len > label.len + 3) 0 else label.len + 3 - max_label_len);
}
pub fn initial_query(palette: *Type, allocator: std.mem.Allocator) error{OutOfMemory}![]const u8 {
@ -90,6 +94,8 @@ pub fn add_menu_entry(palette: *Type, entry: *Entry, matches: ?[]const usize) !v
palette.items += 1;
}
//pub fn render_symbol( self: *renderer.Plane, symbol: []const u8, icon: []const u8, color: u24, detail: []const u8, description: []const u8, matches_cbor: []const u8, active: bool, selected: bool, hover: bool, theme_: *const Widget.Theme, ) bool
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;
@ -98,18 +104,17 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonType, theme: *const Widget.T
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 kind, _, _, const detail = get_values(item_cbor);
const label_, _, const kind, _, _, const label_detail, const label_description, _, _ = get_values(item_cbor);
const icon_: []const u8 = kind_icon(@enumFromInt(kind));
const color: u24 = 0x0;
const indicator: []const u8 = detail;
return tui.render_file_item(
return tui.render_symbol(
&button.plane,
label_,
icon_,
color,
indicator[0..@min(max_detail - 3, indicator.len)],
if (max_detail < indicator.len) "" else "",
label_detail,
label_description,
matches_cbor,
button.active,
selected,
@ -118,11 +123,12 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonType, theme: *const Widget.T
);
}
fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer.Selection, []const u8, []const u8 } {
fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer.Selection, []const u8, []const u8, []const u8, []const u8, []const u8 } {
var label_: []const u8 = "";
var label_detail: []const u8 = "";
var label_description: []const u8 = "";
var detail: []const u8 = "";
var documentation: []const u8 = "";
var sort_text: []const u8 = "";
var kind: u8 = 0;
var insertTextFormat: usize = 0;
@ -139,7 +145,7 @@ fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer
cbor.extract(&label_description), // label_description
cbor.extract(&kind), // kind
cbor.extract(&detail), // detail
cbor.any, // documentation
cbor.extract(&documentation), // documentation
cbor.any, // documentation_kind
cbor.extract(&sort_text), // sortText
cbor.extract(&insertTextFormat), // insertTextFormat
@ -154,7 +160,7 @@ fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer
cbor.extract(&replace.end.col), // replace.end.col
cbor.extract_cbor(&additionalTextEdits),
}) catch false;
return .{ label_, sort_text, kind, replace, additionalTextEdits, if (detail.len > 0) detail else label_detail };
return .{ label_, sort_text, kind, replace, additionalTextEdits, label_detail, label_description, detail, documentation };
}
const TextEdit = struct { newText: []const u8 = &.{}, insert: ?Range = null, replace: ?Range = null };
@ -171,21 +177,32 @@ fn get_replace_selection(replace: Buffer.Selection) ?Buffer.Selection {
}
fn select(menu: **Type.MenuType, button: *Type.ButtonType, _: Type.Pos) void {
const label_, _, _, _, _, _ = get_values(button.opts.label);
const label_, _, _, _, _, _, _, _, _ = 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", "insert_chars", .{label_} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
const mv = tui.mainview() orelse return;
mv.cancel_info_content() catch {};
}
pub fn updated(palette: *Type, button_: ?*Type.ButtonType) !void {
const button = button_ orelse return cancel(palette);
_, _, _, const replace, _, _ = get_values(button.opts.label);
const label_, _, _, const replace, _, _, _, const detail, const documentation = get_values(button.opts.label);
const editor = tui.get_active_editor() orelse return error.NotFound;
editor.get_primary().selection = get_replace_selection(replace);
const mv = tui.mainview() orelse return;
try mv.set_info_content(label_, .replace);
try mv.set_info_content(" ", .append); // blank line
try mv.set_info_content(detail, .append);
try mv.set_info_content(" ", .append); // blank line
try mv.set_info_content(documentation, .append);
}
pub fn cancel(palette: *Type) !void {
const editor = tui.get_active_editor() orelse return;
editor.get_primary().selection = palette.value.start.selection;
const mv = tui.mainview() orelse return;
mv.cancel_info_content() catch {};
}
const CompletionItemKind = enum(u8) {

View file

@ -190,7 +190,7 @@ pub fn Create(options: type) type {
fn prepare_resize(self: *Self) Widget.Box {
const screen = tui.screen();
const w = self.prepare_width();
const w = self.prepare_width(screen);
return switch (self.placement) {
.top_center => self.prepare_resize_top_center(screen, w),
.top_left => self.prepare_resize_top_left(screen, w),
@ -198,8 +198,8 @@ pub fn Create(options: type) type {
};
}
fn prepare_width(self: *Self) usize {
return @max(@min(self.longest + 3, max_menu_width) + 2 + self.longest_hint, options.label.len + 2);
fn prepare_width(self: *Self, screen: Widget.Box) usize {
return @min(screen.w - 2, @max(@min(self.longest + 3, max_menu_width) + 2 + self.longest_hint, options.label.len + 2));
}
fn prepare_resize_at_x(self: *Self, screen: Widget.Box, w: usize, x: usize) Widget.Box {

View file

@ -2100,6 +2100,60 @@ pub fn render_file_vcs_item_cbor(self: *renderer.Plane, file_item_cbor: []const
return render_file_vcs_item(self, file_path_, icon, color, indicator, vcs_status, matches_cbor, active, selected, hover, theme_);
}
pub fn render_symbol(
self: *renderer.Plane,
symbol: []const u8,
icon: []const u8,
color: u24,
detail: []const u8,
description: []const u8,
matches_cbor: []const u8,
active: bool,
selected: bool,
hover: bool,
theme_: *const Widget.Theme,
) bool {
const style_base = theme_.editor_widget;
const style_symbol = if (active) theme_.editor_cursor else if (hover or selected) theme_.editor_selection else theme_.editor_widget;
const style_detail: Widget.Theme.Style = .{ .bg = style_symbol.bg, .fg = theme_.input_placeholder.fg, .fs = theme_.input_placeholder.fs };
const style_description = if (find_scope_style(theme_, "entity.name")) |sty| sty.style else style_detail;
self.set_base_style(style_base);
self.erase();
self.home();
self.set_style(style_symbol);
if (active or hover or selected) {
self.fill(" ");
self.home();
}
self.set_style(style_description);
render_pointer(self, selected);
const icon_width = render_file_icon(self, icon, color);
self.set_style(style_symbol);
_ = self.print("{s}", .{symbol}) catch {};
self.set_style(style_detail);
_ = self.print("{s}", .{detail}) catch {};
var lines = std.mem.splitScalar(u8, description, '\n');
if (lines.next()) |desc| {
self.set_style(style_description);
_ = self.print_right(" {s} ", .{desc}) catch {};
}
var iter = matches_cbor;
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) {
render_match_cell(self, 0, index + 2 + icon_width, theme_) catch break;
} else break;
}
return false;
}
fn get_or_create_theme_file(self: *Self, allocator: std.mem.Allocator) ![]const u8 {
const theme_name = self.current_theme().name;
if (root.read_theme(allocator, theme_name)) |content| {