feat: Helix & Vim mode: adding more commands (#218)

* Helix mode: select_left

* select_to_char_right implementation

* Vim select_to_char_left

* Helix select_to_char_left

* Helix & Vim: select_end

* select_to_char_left: Avoid panic with no selection

* select_left_helix: handling panic and shrinking code

* Correcting helix left and right select

* Helix mode: select_left

* select_to_char_right implementation

* Vim select_to_char_left

* Helix select_to_char_left

* Helix & Vim: select_end

* select_to_char_left: Avoid panic with no selection

* select_left_helix: handling panic and shrinking code

* Correcting helix left and right select

* Enable_selection on init_command

* move_to_char modification

* move_or_select

---------

Co-authored-by: CJ van den Berg <cj@vdbonline.com>
This commit is contained in:
Levi 2025-04-08 05:28:29 -03:00 committed by GitHub
parent 716f871d03
commit fb985a703a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 126 additions and 43 deletions

View file

@ -8,6 +8,7 @@ const tui = @import("../tui.zig");
const Editor = @import("../editor.zig").Editor;
const Buffer = @import("Buffer");
const Cursor = Buffer.Cursor;
const Selection = Buffer.Selection;
var commands: Commands = undefined;
@ -135,6 +136,73 @@ const cmds_ = struct {
ed.clamp();
}
pub const cut_forward_internal_inclusive_meta: Meta = .{ .description = "Cut next character to internal clipboard (inclusive)" };
pub fn select_right_helix(_: *void, _: Ctx) Result {
const mv = tui.mainview() orelse return;
const ed = mv.get_active_editor() orelse return;
const root = try ed.buf_root();
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
const sel = try cursel.enable_selection(root, ed.metrics);
// handling left to right transition
const sel_begin: i32 = @intCast(sel.begin.col);
const sel_end: i32 = @intCast(sel.end.col);
if ((sel_begin - sel_end) == 1 and sel.begin.row == sel.end.row) {
try Editor.move_cursor_right(root, &sel.end, ed.metrics);
sel.begin.col -= 1;
}
try Editor.move_cursor_right(root, &sel.end, ed.metrics);
cursel.cursor = sel.end;
cursel.check_selection(root, ed.metrics);
};
ed.clamp();
}
pub const select_right_helix_meta: Meta = .{ .description = "Select right" };
pub fn select_left_helix(_: *void, _: Ctx) Result {
const mv = tui.mainview() orelse return;
const ed = mv.get_active_editor() orelse return;
const root = try ed.buf_root();
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
if (cursel.selection == null) {
cursel.selection = Selection.from_cursor(&cursel.cursor);
try cursel.selection.?.begin.move_right(root, ed.metrics);
}
if (cursel.selection) |*sel| {
try Editor.move_cursor_left(root, &sel.end, ed.metrics);
cursel.cursor = sel.end;
if (sel.begin.col == sel.end.col and sel.begin.row == sel.end.row) {
try sel.begin.move_right(root, ed.metrics);
try Editor.move_cursor_left(root, &sel.end, ed.metrics);
cursel.cursor = sel.end;
}
}
cursel.check_selection(root, ed.metrics);
};
ed.clamp();
}
pub const select_left_helix_meta: Meta = .{ .description = "Select left" };
pub fn select_to_char_right_helix(_: *void, ctx: Ctx) Result {
const mv = tui.mainview() orelse return;
const ed = mv.get_active_editor() orelse return;
const root = try ed.buf_root();
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
const sel = try cursel.enable_selection(root, ed.metrics);
try Editor.move_cursor_to_char_right(root, &sel.end, ctx, ed.metrics);
try Editor.move_cursor_right(root, &sel.end, ed.metrics);
cursel.cursor = sel.end;
cursel.check_selection(root, ed.metrics);
};
ed.clamp();
}
pub const select_to_char_right_helix_meta: Meta = .{ .description = "Move to char right" };
};
fn move_cursor_word_left_helix(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {

View file

@ -1,3 +1,4 @@
const std = @import("std");
const tp = @import("thespian");
const input = @import("input");
@ -15,28 +16,24 @@ const Commands = command.Collection(cmds);
allocator: Allocator,
key: [6]u8 = undefined,
direction: Direction,
operation_command: []const u8,
operation: Operation,
commands: Commands = undefined,
const Direction = enum {
left,
right,
};
const Operation = enum {
move,
select,
};
pub fn create(allocator: Allocator, ctx: command.Context) !struct { tui.Mode, tui.MiniMode } {
var direction: Direction = undefined;
var egc: []const u8 = undefined;
const select = if (tui.get_active_editor()) |editor| if (editor.get_primary().selection) |_| true else false else false;
_ = ctx.args.match(.{tp.extract(&direction)}) catch return error.InvalidMoveToCharArgument;
_ = ctx.args.match(.{tp.extract(&egc)}) catch return error.InvalidMoveToCharArgument;
const self: *Self = try allocator.create(Self);
self.* = .{
.allocator = allocator,
.direction = direction,
.operation_command = try allocator.dupe(u8, egc),
.operation = if (select) .select else .move,
};
try self.commands.init(self);
@ -49,19 +46,14 @@ pub fn create(allocator: Allocator, ctx: command.Context) !struct { tui.Mode, tu
pub fn deinit(self: *Self) void {
self.commands.deinit();
self.allocator.free(self.operation_command);
self.allocator.destroy(self);
}
fn name(self: *Self) []const u8 {
return switch (self.operation) {
.move => switch (self.direction) {
.left => "↶ move",
.right => "↷ move",
},
.select => switch (self.direction) {
.left => "󰒅 ↶ select",
.right => "󰒅 ↷ select",
},
.move => "move",
.select => "select",
};
}
@ -70,17 +62,7 @@ pub fn receive(_: *Self, _: tp.pid_ref, _: tp.message) error{Exit}!bool {
}
fn execute_operation(self: *Self, ctx: command.Context) command.Result {
const cmd = switch (self.direction) {
.left => switch (self.operation) {
.move => "move_to_char_left",
.select => "select_to_char_left",
},
.right => switch (self.operation) {
.move => "move_to_char_right",
.select => "select_to_char_right",
},
};
try command.executeName(cmd, ctx);
try command.executeName(self.operation_command, ctx);
try command.executeName("exit_mini_mode", .{});
}