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:
		
							parent
							
								
									716f871d03
								
							
						
					
					
						commit
						fb985a703a
					
				
					 6 changed files with 126 additions and 43 deletions
				
			
		| 
						 | 
				
			
			@ -96,7 +96,7 @@ pub const CurSel = struct {
 | 
			
		|||
        self.* = .{};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn enable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection {
 | 
			
		||||
    pub fn enable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection {
 | 
			
		||||
        return switch (tui.get_selection_style()) {
 | 
			
		||||
            .normal => self.enable_selection_normal(),
 | 
			
		||||
            .inclusive => try self.enable_selection_inclusive(root, metrics),
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,7 @@ pub const CurSel = struct {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn check_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
 | 
			
		||||
    pub fn check_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
 | 
			
		||||
        if (self.selection) |sel| if (sel.empty()) {
 | 
			
		||||
            self.disable_selection(root, metrics);
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -2123,7 +2123,7 @@ pub const Editor = struct {
 | 
			
		|||
        return if (cursor.col == first) cursor.move_begin() else cursor.move_to(root, cursor.row, first, metrics);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn move_cursor_right(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
 | 
			
		||||
    pub fn move_cursor_right(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
 | 
			
		||||
        try cursor.move_right(root, metrics);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3089,6 +3089,18 @@ pub const Editor = struct {
 | 
			
		|||
    }
 | 
			
		||||
    pub const move_to_char_right_meta: Meta = .{ .arguments = &.{.integer} };
 | 
			
		||||
 | 
			
		||||
    pub fn move_or_select_to_char_left(self: *Self, ctx: Context) Result {
 | 
			
		||||
        const selected = if (self.get_primary().selection) |_| true else false;
 | 
			
		||||
        if (selected) try self.select_to_char_left(ctx) else try self.move_to_char_left(ctx);
 | 
			
		||||
    }
 | 
			
		||||
    pub const move_or_select_to_char_left_meta: Meta = .{ .arguments = &.{.integer} };
 | 
			
		||||
 | 
			
		||||
    pub fn move_or_select_to_char_right(self: *Self, ctx: Context) Result {
 | 
			
		||||
        const selected = if (self.get_primary().selection) |_| true else false;
 | 
			
		||||
        if (selected) try self.select_to_char_right(ctx) else try self.move_to_char_right(ctx);
 | 
			
		||||
    }
 | 
			
		||||
    pub const move_or_select_to_char_right_meta: Meta = .{ .arguments = &.{.integer} };
 | 
			
		||||
 | 
			
		||||
    pub fn move_up(self: *Self, _: Context) Result {
 | 
			
		||||
        const root = try self.buf_root();
 | 
			
		||||
        self.with_cursors_const(root, move_cursor_up) catch {};
 | 
			
		||||
| 
						 | 
				
			
			@ -3592,6 +3604,12 @@ pub const Editor = struct {
 | 
			
		|||
    }
 | 
			
		||||
    pub const cancel_meta: Meta = .{ .description = "Cancel current action" };
 | 
			
		||||
 | 
			
		||||
    pub fn enable_selection(self: *Self, _: Context) Result {
 | 
			
		||||
        const root = try self.buf_root();
 | 
			
		||||
        _ = try self.get_primary().enable_selection(root, self.metrics);
 | 
			
		||||
    }
 | 
			
		||||
    pub const enable_selection_meta: Meta = .{ .description = "Enable selection" };
 | 
			
		||||
 | 
			
		||||
    pub fn select_line_vim(self: *Self, _: Context) Result {
 | 
			
		||||
        self.selection_mode = .line;
 | 
			
		||||
        for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel|
 | 
			
		||||
| 
						 | 
				
			
			@ -3702,6 +3720,16 @@ pub const Editor = struct {
 | 
			
		|||
    }
 | 
			
		||||
    pub const select_to_char_left_meta: Meta = .{ .arguments = &.{.integer} };
 | 
			
		||||
 | 
			
		||||
    pub fn select_to_char_left_vim(self: *Self, ctx: Context) Result {
 | 
			
		||||
        const root = try self.buf_root();
 | 
			
		||||
        for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
 | 
			
		||||
            if (cursel.selection) |*sel| try sel.begin.move_right(root, self.metrics);
 | 
			
		||||
        };
 | 
			
		||||
        self.with_selections_const_arg(root, move_cursor_to_char_left, ctx) catch {};
 | 
			
		||||
        self.clamp();
 | 
			
		||||
    }
 | 
			
		||||
    pub const select_to_char_left_vim_meta: Meta = .{ .arguments = &.{.integer} };
 | 
			
		||||
 | 
			
		||||
    pub fn select_to_char_right(self: *Self, ctx: Context) Result {
 | 
			
		||||
        const root = try self.buf_root();
 | 
			
		||||
        self.with_selections_const_arg(root, move_cursor_to_char_right, ctx) catch {};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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", .{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue