Compare commits

...

8 commits

5 changed files with 83 additions and 20 deletions

View file

@ -1012,6 +1012,7 @@ fn send_completion_items(to: tp.pid_ref, file_path: []const u8, row: usize, col:
if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&item)))) return error.InvalidMessageField; if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&item)))) return error.InvalidMessageField;
try send_completion_item(to, file_path, row, col, item, if (len > 1) true else is_incomplete); try send_completion_item(to, file_path, row, col, item, if (len > 1) true else is_incomplete);
} }
return to.send(.{ "cmd", "add_completion_done", .{ file_path, row, col } }) catch error.ClientFailed;
} }
fn invalid_field(field: []const u8) error{InvalidMessage} { fn invalid_field(field: []const u8) error{InvalidMessage} {

View file

@ -838,11 +838,8 @@ const cmds = struct {
tp.more, tp.more,
})) return error.InvalidAddDiagnosticArgument; })) return error.InvalidAddDiagnosticArgument;
file_path = project_manager.normalize_file_path(file_path); file_path = project_manager.normalize_file_path(file_path);
if (self.get_active_editor()) |editor| { if (self.get_active_editor()) |editor| if (std.mem.eql(u8, file_path, editor.file_path orelse ""))
if (std.mem.eql(u8, file_path, editor.file_path orelse ""))
try editor.add_completion(row, col, is_incomplete, ctx.args); try editor.add_completion(row, col, is_incomplete, ctx.args);
try tui.open_overlay(@import("mode/overlay/completion_palette.zig").Type);
}
} }
pub const add_completion_meta: Meta = .{ pub const add_completion_meta: Meta = .{
.arguments = &.{ .arguments = &.{
@ -871,6 +868,28 @@ const cmds = struct {
}, },
}; };
pub fn add_completion_done(self: *Self, ctx: Ctx) Result {
var file_path: []const u8 = undefined;
var row: usize = undefined;
var col: usize = undefined;
if (!try ctx.args.match(.{
tp.extract(&file_path),
tp.extract(&row),
tp.extract(&col),
})) return error.InvalidAddDiagnosticArgument;
file_path = project_manager.normalize_file_path(file_path);
if (self.get_active_editor()) |editor| if (std.mem.eql(u8, file_path, editor.file_path orelse ""))
try tui.open_overlay(@import("mode/overlay/completion_palette.zig").Type);
}
pub const add_completion_done_meta: Meta = .{
.arguments = &.{
.string, // file_path
.integer, // row
.integer, // col
},
};
pub fn rename_symbol_item(self: *Self, ctx: Ctx) Result { pub fn rename_symbol_item(self: *Self, ctx: Ctx) Result {
const editor = self.get_active_editor() orelse return; const editor = self.get_active_editor() orelse return;
// because the incoming message is an array of Renames, we manuallly // because the incoming message is an array of Renames, we manuallly

View file

@ -3,9 +3,11 @@ const cbor = @import("cbor");
const tp = @import("thespian"); const tp = @import("thespian");
const root = @import("root"); const root = @import("root");
const command = @import("command"); const command = @import("command");
const Buffer = @import("Buffer");
const tui = @import("../../tui.zig"); const tui = @import("../../tui.zig");
pub const Type = @import("palette.zig").Create(@This()); pub const Type = @import("palette.zig").Create(@This());
const ed = @import("../../editor.zig");
const module_name = @typeName(@This()); const module_name = @typeName(@This());
const Widget = @import("../../Widget.zig"); const Widget = @import("../../Widget.zig");
@ -20,8 +22,15 @@ pub const Entry = struct {
cbor: []const u8, cbor: []const u8,
}; };
pub const ValueType = struct {
start: ed.CurSel = .{},
replace: ?Buffer.Selection = null,
};
pub const defaultValue: ValueType = .{};
pub fn load_entries(palette: *Type) !usize { pub fn load_entries(palette: *Type) !usize {
const editor = tui.get_active_editor() orelse return error.NotFound; const editor = tui.get_active_editor() orelse return error.NotFound;
palette.value.start = editor.get_primary().*;
var iter: []const u8 = editor.completions.items; var iter: []const u8 = editor.completions.items;
while (iter.len > 0) { while (iter.len > 0) {
var cbor_item: []const u8 = undefined; var cbor_item: []const u8 = undefined;
@ -31,7 +40,9 @@ pub fn load_entries(palette: *Type) !usize {
var max_label_len: usize = 0; var max_label_len: usize = 0;
for (palette.entries.items) |*item| { for (palette.entries.items) |*item| {
const label_, const sort_text, _ = get_values(item.cbor); const label_, const sort_text, _, const replace = get_values(item.cbor);
if (palette.value.replace == null)
palette.value.replace = replace;
item.label = label_; item.label = label_;
item.sort_text = sort_text; item.sort_text = sort_text;
max_label_len = @max(max_label_len, item.label.len); max_label_len = @max(max_label_len, item.label.len);
@ -49,6 +60,14 @@ pub fn load_entries(palette: *Type) !usize {
return if (max_label_len > label.len + 3) 0 else label.len + 3 - max_label_len; return 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 {
return if (palette.value.replace) |replace| blk: {
const editor = tui.get_active_editor() orelse break :blk allocator.dupe(u8, "");
const sel: Buffer.Selection = .{ .begin = replace.begin, .end = palette.value.start.cursor };
break :blk editor.get_selection(sel, allocator) catch break :blk allocator.dupe(u8, "");
} else allocator.dupe(u8, "");
}
pub fn clear_entries(palette: *Type) void { pub fn clear_entries(palette: *Type) void {
palette.entries.clearRetainingCapacity(); palette.entries.clearRetainingCapacity();
} }
@ -71,7 +90,7 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonState, theme: *const Widget.
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&item_cbor)) catch false)) return false; 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; if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) return false;
const label_, _, const kind = get_values(item_cbor); const label_, _, const kind, _ = get_values(item_cbor);
const icon_: []const u8 = kind_icon(@enumFromInt(kind)); const icon_: []const u8 = kind_icon(@enumFromInt(kind));
const color: u24 = 0x0; const color: u24 = 0x0;
const indicator: []const u8 = &.{}; const indicator: []const u8 = &.{};
@ -79,10 +98,11 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonState, theme: *const Widget.
return tui.render_file_item(&button.plane, label_, icon_, color, indicator, matches_cbor, button.active, selected, button.hover, theme); return tui.render_file_item(&button.plane, label_, icon_, color, indicator, matches_cbor, button.active, selected, button.hover, theme);
} }
fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8 } { fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer.Selection } {
var label_: []const u8 = ""; var label_: []const u8 = "";
var sort_text: []const u8 = ""; var sort_text: []const u8 = "";
var kind: u8 = 0; var kind: u8 = 0;
var replace: Buffer.Selection = .{};
_ = cbor.match(item_cbor, .{ _ = cbor.match(item_cbor, .{
cbor.any, // file_path cbor.any, // file_path
cbor.any, // row cbor.any, // row
@ -102,20 +122,32 @@ fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8 } {
cbor.any, // insert.begin.col cbor.any, // insert.begin.col
cbor.any, // insert.end.row cbor.any, // insert.end.row
cbor.any, // insert.end.col cbor.any, // insert.end.col
cbor.any, // replace.begin.row cbor.extract(&replace.begin.row), // replace.begin.row
cbor.any, // replace.begin.col cbor.extract(&replace.begin.col), // replace.begin.col
cbor.any, // replace.end.row cbor.extract(&replace.end.row), // replace.end.row
cbor.any, // replace.end.col cbor.extract(&replace.end.col), // replace.end.col
}) catch false; }) catch false;
return .{ label_, sort_text, kind }; return .{ label_, sort_text, kind, replace };
} }
fn select(menu: **Type.MenuState, button: *Type.ButtonState) void { fn select(menu: **Type.MenuState, button: *Type.ButtonState) 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", "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); tp.self_pid().send(.{ "cmd", "insert_chars", .{label_} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
} }
pub fn updated(palette: *Type, button_: ?*Type.ButtonState) !void {
const button = button_ orelse return cancel(palette);
_, _, _, const replace = get_values(button.opts.label);
const editor = tui.get_active_editor() orelse return error.NotFound;
editor.get_primary().selection = if (replace.empty()) null else replace;
}
pub fn cancel(palette: *Type) !void {
const editor = tui.get_active_editor() orelse return;
editor.get_primary().selection = palette.value.start.selection;
}
const CompletionItemKind = enum(u8) { const CompletionItemKind = enum(u8) {
None = 0, None = 0,
Text = 1, Text = 1,

View file

@ -40,8 +40,11 @@ pub fn Create(options: type) type {
view_pos: usize = 0, view_pos: usize = 0,
total_items: usize = 0, total_items: usize = 0,
value: ValueType = if (@hasDecl(options, "defaultValue")) options.defaultValue else {},
const Entry = options.Entry; const Entry = options.Entry;
const Self = @This(); const Self = @This();
const ValueType = if (@hasDecl(options, "ValueType")) options.ValueType else void;
pub const MenuState = Menu.State(*Self); pub const MenuState = Menu.State(*Self);
pub const ButtonState = Button.State(*Menu.State(*Self)); pub const ButtonState = Button.State(*Menu.State(*Self));
@ -88,6 +91,12 @@ pub fn Create(options: type) type {
if (@hasDecl(options, "restore_state")) if (@hasDecl(options, "restore_state"))
options.restore_state(self) catch {}; options.restore_state(self) catch {};
try self.commands.init(self); try self.commands.init(self);
if (@hasDecl(options, "initial_query")) blk: {
const initial_query = options.initial_query(self, self.allocator) catch break :blk;
defer self.allocator.free(initial_query);
try self.inputbox.text.appendSlice(self.allocator, initial_query);
self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8);
}
try self.start_query(0); try self.start_query(0);
try mv.floating_views.add(self.modal.widget()); try mv.floating_views.add(self.modal.widget());
try mv.floating_views.add(self.menu.container_widget); try mv.floating_views.add(self.menu.container_widget);

View file

@ -189,7 +189,7 @@ fn init(allocator: Allocator) InitError!*Self {
} }
self.mainview_ = try MainView.create(allocator); self.mainview_ = try MainView.create(allocator);
resize(); resize();
self.set_terminal_style(); self.set_terminal_style(self.current_theme());
try save_config(); try save_config();
try self.init_input_namespace(); try self.init_input_namespace();
if (tp.env.get().is("restore-session")) { if (tp.env.get().is("restore-session")) {
@ -773,7 +773,7 @@ fn set_theme_by_name(self: *Self, name: []const u8, action: enum { none, store }
self.light_parsed_theme = parsed_theme; self.light_parsed_theme = parsed_theme;
}, },
} }
self.set_terminal_style(); self.set_terminal_style(&theme_);
self.logger.print("theme: {s}", .{theme_.description}); self.logger.print("theme: {s}", .{theme_.description});
switch (action) { switch (action) {
.none => {}, .none => {},
@ -790,12 +790,14 @@ fn set_theme_by_name(self: *Self, name: []const u8, action: enum { none, store }
fn force_color_scheme(self: *Self, color_scheme: @TypeOf(self.color_scheme)) void { fn force_color_scheme(self: *Self, color_scheme: @TypeOf(self.color_scheme)) void {
self.color_scheme = color_scheme; self.color_scheme = color_scheme;
self.color_scheme_locked = true; self.color_scheme_locked = true;
self.set_terminal_style(self.current_theme());
self.logger.print("color scheme: {s} ({s})", .{ @tagName(self.color_scheme), self.current_theme().name }); self.logger.print("color scheme: {s} ({s})", .{ @tagName(self.color_scheme), self.current_theme().name });
} }
fn set_color_scheme(self: *Self, color_scheme: @TypeOf(self.color_scheme)) void { fn set_color_scheme(self: *Self, color_scheme: @TypeOf(self.color_scheme)) void {
if (self.color_scheme_locked) return; if (self.color_scheme_locked) return;
self.color_scheme = color_scheme; self.color_scheme = color_scheme;
self.set_terminal_style(self.current_theme());
self.logger.print("color scheme: {s} ({s})", .{ @tagName(self.color_scheme), self.current_theme().name }); self.logger.print("color scheme: {s} ({s})", .{ @tagName(self.color_scheme), self.current_theme().name });
} }
@ -1548,12 +1550,12 @@ pub const fallbacks: []const FallBack = &[_]FallBack{
.{ .ts = "text.title", .tm = "entity.name.section" }, .{ .ts = "text.title", .tm = "entity.name.section" },
}; };
fn set_terminal_style(self: *Self) void { fn set_terminal_style(self: *Self, theme_: *const Widget.Theme) void {
if (build_options.gui or self.config_.enable_terminal_color_scheme) { if (build_options.gui or self.config_.enable_terminal_color_scheme) {
self.rdr_.set_terminal_style(self.current_theme().editor); self.rdr_.set_terminal_style(theme_.editor);
self.rdr_.set_terminal_cursor_color(self.current_theme().editor_cursor.bg.?); self.rdr_.set_terminal_cursor_color(theme_.editor_cursor.bg.?);
if (self.rdr_.vx.caps.multi_cursor) if (self.rdr_.vx.caps.multi_cursor)
self.rdr_.set_terminal_secondary_cursor_color(self.current_theme().editor_cursor_secondary.bg orelse self.current_theme().editor_cursor.bg.?); self.rdr_.set_terminal_secondary_cursor_color(theme_.editor_cursor_secondary.bg orelse theme_.editor_cursor.bg.?);
} }
} }