refactor: move more mode specific commands to helix & vim

This commit is contained in:
CJ van den Berg 2025-11-27 18:03:53 +01:00
parent 8d8f4b82cb
commit 66f8819a19
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
4 changed files with 274 additions and 262 deletions

View file

@ -75,8 +75,8 @@
["yy", ["copy_line_internal_vim"], ["cancel"]],
["<C-u>", "move_scroll_half_page_up_vim"],
["<C-d>", "move_scroll_half_page_down_vim"],
["<C-u>", "move_scroll_half_page_up"],
["<C-d>", "move_scroll_half_page_down"],
["zz", "scroll_view_center"],
@ -149,8 +149,8 @@
["p", ["paste_internal_vim"], ["enter_mode", "normal"]],
["P", ["paste_internal_vim"], ["enter_mode", "normal"]],
["<C-u>", "move_scroll_half_page_up_vim"],
["<C-d>", "move_scroll_half_page_down_vim"],
["<C-u>", "move_scroll_half_page_up"],
["<C-d>", "move_scroll_half_page_down"],
["zz", "scroll_view_center"],
["<S-.>", "indent"],
@ -196,8 +196,8 @@
["p", ["paste_internal_vim"], ["enter_mode", "normal"]],
["P", ["paste_internal_vim"], ["enter_mode", "normal"]],
["<C-u>", "move_scroll_half_page_up_vim"],
["<C-d>", "move_scroll_half_page_down_vim"],
["<C-u>", "move_scroll_half_page_up"],
["<C-d>", "move_scroll_half_page_down"],
["<S-.>", "indent"],
["<S-,>", "unindent"],

View file

@ -1628,7 +1628,7 @@ pub const Editor = struct {
return row < sel.begin.row or (row == sel.begin.row and col < sel.begin.col);
}
inline fn screen_cursor(self: *const Self, cursor: *const Cursor) ?Cursor {
pub inline fn screen_cursor(self: *const Self, cursor: *const Cursor) ?Cursor {
return if (self.view.is_visible(cursor)) .{
.row = cursor.row - self.view.row,
.col = cursor.col - self.view.col,
@ -1741,7 +1741,7 @@ pub const Editor = struct {
try self.send_editor_cursel_msg("jump_source", self.get_primary());
}
fn send_editor_jump_destination(self: *Self) !void {
pub fn send_editor_jump_destination(self: *Self) !void {
try self.send_editor_cursel_msg("jump_destination", self.get_primary());
}
@ -1959,7 +1959,7 @@ pub const Editor = struct {
try move(root, &cursel.cursor, view, metrics);
}
fn with_cursors_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void {
pub fn with_cursors_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void {
var someone_stopped = false;
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel|
with_cursor_and_view_const(root, move, cursel, view, self.metrics) catch {
@ -2028,7 +2028,7 @@ pub const Editor = struct {
cursel.cursor = sel.end;
}
fn with_selections_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void {
pub fn with_selections_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void {
var someone_stopped = false;
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel|
with_selection_and_view_const(root, move, cursel, view, self.metrics) catch {
@ -2346,7 +2346,7 @@ pub const Editor = struct {
return false;
}
fn is_eol_left(_: Buffer.Root, cursor: *const Cursor, _: Buffer.Metrics) bool {
pub fn is_eol_left(_: Buffer.Root, cursor: *const Cursor, _: Buffer.Metrics) bool {
if (cursor.col == 0)
return true;
return false;
@ -2359,22 +2359,6 @@ pub const Editor = struct {
return false;
}
fn is_eol_right_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width - 1)
return true;
return false;
}
fn is_eol_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width)
return true;
return false;
}
pub fn move_cursor_left(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
try cursor.move_left(root, metrics);
}
@ -2384,7 +2368,7 @@ pub const Editor = struct {
move_cursor_left(root, cursor, metrics) catch return;
}
fn move_cursor_left_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void {
pub fn move_cursor_left_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void {
if (!pred(root, cursor, metrics))
move_cursor_left(root, cursor, metrics) catch return;
}
@ -2407,7 +2391,7 @@ pub const Editor = struct {
move_cursor_right(root, cursor, metrics) catch return;
}
fn move_cursor_right_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void {
pub fn move_cursor_right_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void {
if (!pred(root, cursor, metrics))
move_cursor_right(root, cursor, metrics) catch return;
}
@ -2416,32 +2400,18 @@ pub const Editor = struct {
cursor.move_end(root, metrics);
}
fn move_cursor_end_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
move_cursor_right_until(root, cursor, is_eol_vim, metrics);
}
fn move_cursor_up(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
cursor.move_up(root, metrics) catch |e| switch (e) {
error.Stop => cursor.move_begin(),
};
}
fn move_cursor_up_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_up(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
pub fn move_cursor_down(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
cursor.move_down(root, metrics) catch |e| switch (e) {
error.Stop => cursor.move_end(root, metrics),
};
}
fn move_cursor_down_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_down(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_buffer_begin(_: Buffer.Root, cursor: *Cursor, _: Buffer.Metrics) !void {
cursor.move_buffer_begin();
}
@ -2458,24 +2428,6 @@ pub const Editor = struct {
cursor.move_page_down(root, view, metrics);
}
fn move_cursor_half_page_up(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_up(root, view, metrics);
}
fn move_cursor_half_page_up_vim(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_up(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_half_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_down(root, view, metrics);
}
fn move_cursor_half_page_down_vim(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_down(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
pub fn primary_click(self: *Self, y: c_int, x: c_int) !void {
const root = self.buf_root() catch return;
if (self.fast_scroll) {
@ -3190,14 +3142,6 @@ pub const Editor = struct {
}
pub const delete_line_meta: Meta = .{ .description = "Delete current line", .arguments = &.{.integer} };
pub fn cut_to_end_vim(self: *Self, _: Context) Result {
const b = try self.buf_for_update();
const root = try self.cut_to(move_cursor_end_vim, b.root);
try self.update_buf(root);
self.clamp();
}
pub const cut_to_end_vim_meta: Meta = .{ .description = "Cut to end of line (vim)" };
pub fn join_next_line(self: *Self, ctx: Context) Result {
const b = try self.buf_for_update();
try self.with_cursors_const_repeat(b.root, move_cursor_end, ctx);
@ -3248,28 +3192,6 @@ pub const Editor = struct {
}
pub const move_right_meta: Meta = .{ .description = "Move cursor right", .arguments = &.{.integer} };
fn move_cursor_left_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
move_cursor_left_unless(root, cursor, is_eol_left, metrics);
}
fn move_cursor_right_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
move_cursor_right_unless(root, cursor, is_eol_right_vim, metrics);
}
pub fn move_left_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_left_vim, ctx) catch {};
self.clamp();
}
pub const move_left_vim_meta: Meta = .{ .description = "Move cursor left (vim)", .arguments = &.{.integer} };
pub fn move_right_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_right_vim, ctx) catch {};
self.clamp();
}
pub const move_right_vim_meta: Meta = .{ .description = "Move cursor right (vim)", .arguments = &.{.integer} };
fn move_cursor_word_begin(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
if (is_non_word_char_at_cursor(root, cursor, metrics)) {
move_cursor_left_until(root, cursor, is_word_boundary_right, metrics);
@ -3556,13 +3478,6 @@ pub const Editor = struct {
}
pub const move_up_meta: Meta = .{ .description = "Move cursor up", .arguments = &.{.integer} };
pub fn move_up_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_up_vim, ctx) catch {};
self.clamp();
}
pub const move_up_vim_meta: Meta = .{ .description = "Move cursor up (vim)", .arguments = &.{.integer} };
pub fn add_cursor_up(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
var repeat: usize = 1;
@ -3583,13 +3498,6 @@ pub const Editor = struct {
}
pub const move_down_meta: Meta = .{ .description = "Move cursor down", .arguments = &.{.integer} };
pub fn move_down_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_down_vim, ctx) catch {};
self.clamp();
}
pub const move_down_vim_meta: Meta = .{ .description = "Move cursor down (vim)", .arguments = &.{.integer} };
pub fn add_cursor_down(self: *Self, ctx: Context) Result {
var repeat: usize = 1;
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
@ -4027,54 +3935,6 @@ pub const Editor = struct {
}
pub const move_scroll_page_down_meta: Meta = .{ .description = "Move and scroll page down" };
pub fn move_scroll_half_page_up(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_up, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_up(.{});
}
}
pub const move_scroll_half_page_up_meta: Meta = .{ .description = "Move and scroll half a page up" };
pub fn move_scroll_half_page_up_vim(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_up_vim, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_up(.{});
}
}
pub const move_scroll_half_page_up_vim_meta: Meta = .{ .description = "Move and scroll half a page up (vim)" };
pub fn move_scroll_half_page_down(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_down, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_down(.{});
}
}
pub const move_scroll_half_page_down_meta: Meta = .{ .description = "Move and scroll half a page down" };
pub fn move_scroll_half_page_down_vim(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_down_vim, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_down(.{});
}
}
pub const move_scroll_half_page_down_vim_meta: Meta = .{ .description = "Move and scroll half a page down (vim)" };
pub fn smart_move_begin(self: *Self, _: Context) Result {
const root = try self.buf_root();
try self.with_cursors_const_once(root, smart_move_cursor_begin);
@ -4363,24 +4223,6 @@ pub const Editor = struct {
}
pub const select_page_down_meta: Meta = .{ .description = "Select page down" };
pub fn select_half_page_up(self: *Self, _: Context) Result {
try self.send_editor_jump_source();
const root = try self.buf_root();
try self.with_selections_and_view_const(root, move_cursor_half_page_up, &self.view);
self.clamp();
try self.send_editor_jump_destination();
}
pub const select_half_page_up_meta: Meta = .{ .description = "Select half a page up" };
pub fn select_half_page_down(self: *Self, _: Context) Result {
try self.send_editor_jump_source();
const root = try self.buf_root();
try self.with_selections_and_view_const(root, move_cursor_half_page_down, &self.view);
self.clamp();
try self.send_editor_jump_destination();
}
pub const select_half_page_down_meta: Meta = .{ .description = "Select half a page down" };
pub fn select_all(self: *Self, _: Context) Result {
try self.send_editor_jump_source();
self.cancel_all_selections();

View file

@ -13,16 +13,19 @@ const CurSel = @import("../editor.zig").CurSel;
const Buffer = @import("Buffer");
const Cursor = Buffer.Cursor;
const Selection = Buffer.Selection;
const View = Buffer.View;
const char_class = Editor.char_class;
const Direction = enum { backwards, forwards };
var commands: Commands = undefined;
const Self = Editor;
pub fn init() !void {
var v: void = {};
try commands.init(&v);
const mv = tui.mainview() orelse return;
const ed = mv.get_active_editor() orelse return;
try commands.init(ed);
}
pub fn deinit() void {
@ -30,60 +33,60 @@ pub fn deinit() void {
}
const Commands = command.Collection(cmds_);
const Ctx = command.Context;
const Context = command.Context;
const Meta = command.Metadata;
const Result = command.Result;
const cmds_ = struct {
pub const Target = void;
pub const Target = Self;
pub fn w(_: *void, _: Ctx) Result {
pub fn w(_: *Self, _: Context) Result {
try cmd("save_file", .{});
}
pub const w_meta: Meta = .{ .description = "w (write/save file)" };
pub fn q(_: *void, _: Ctx) Result {
pub fn q(_: *Self, _: Context) Result {
try cmd("quit", .{});
}
pub const q_meta: Meta = .{ .description = "q (quit)" };
pub fn qa(_: *void, _: Ctx) Result {
pub fn qa(_: *Self, _: Context) Result {
try cmd("quit", .{});
}
pub const qa_meta: Meta = .{ .description = "qa (close all)" };
pub fn @"q!"(_: *void, _: Ctx) Result {
pub fn @"q!"(_: *Self, _: Context) Result {
try cmd("quit_without_saving", .{});
}
pub const @"q!_meta": Meta = .{ .description = "q! (quit without saving)" };
pub fn @"qa!"(_: *void, _: Ctx) Result {
pub fn @"qa!"(_: *Self, _: Context) Result {
try cmd("quit_without_saving", .{});
}
pub const @"qa!_meta": Meta = .{ .description = "qa! (quit without saving)" };
pub fn wq(_: *void, _: Ctx) Result {
pub fn wq(_: *Self, _: Context) Result {
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
}
pub const wq_meta: Meta = .{ .description = "wq (write/save file and quit)" };
pub fn @"x!"(_: *void, _: Ctx) Result {
pub fn @"x!"(_: *Self, _: Context) Result {
try cmd("save_file", command.fmt(.{ "then", .{ "quit_without_saving", .{} } }));
}
pub const @"x!_meta": Meta = .{ .description = "x! (write/save file and exit, ignoring other unsaved changes)" };
pub fn x(_: *void, _: Ctx) Result {
pub fn x(_: *Self, _: Context) Result {
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
}
pub const x_meta: Meta = .{ .description = "x (write/save file and quit)" };
pub fn wa(_: *void, _: Ctx) Result {
pub fn wa(_: *Self, _: Context) Result {
if (tui.get_buffer_manager()) |bm|
bm.save_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
}
pub const wa_meta: Meta = .{ .description = "wa (save all)" };
pub fn xa(_: *void, _: Ctx) Result {
pub fn xa(_: *Self, _: Context) Result {
if (tui.get_buffer_manager()) |bm| {
bm.save_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
try cmd("quit", .{});
@ -91,7 +94,7 @@ const cmds_ = struct {
}
pub const xa_meta: Meta = .{ .description = "xa (write all and quit)" };
pub fn @"xa!"(_: *void, _: Ctx) Result {
pub fn @"xa!"(_: *Self, _: Context) Result {
if (tui.get_buffer_manager()) |bm| {
bm.save_all() catch {};
try cmd("quit_without_saving", .{});
@ -99,14 +102,14 @@ const cmds_ = struct {
}
pub const @"xa!_meta": Meta = .{ .description = "xa! (write all and exit, ignoring other unsaved changes)" };
pub fn wqa(_: *void, _: Ctx) Result {
pub fn wqa(_: *Self, _: Context) Result {
if (tui.get_buffer_manager()) |bm|
bm.save_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
try cmd("quit", .{});
}
pub const wqa_meta: Meta = .{ .description = "wqa (write all and quit)" };
pub fn @"wqa!"(_: *void, _: Ctx) Result {
pub fn @"wqa!"(_: *Self, _: Context) Result {
if (tui.get_buffer_manager()) |bm| {
bm.save_all() catch {};
try cmd("quit_without_saving", .{});
@ -114,54 +117,54 @@ const cmds_ = struct {
}
pub const @"wqa!_meta": Meta = .{ .description = "wqa! (write all and exit, ignoring unsaved changes)" };
pub fn rl(_: *void, _: Ctx) Result {
pub fn rl(_: *Self, _: Context) Result {
try cmd("reload_file", .{});
}
pub const rl_meta: Meta = .{ .description = "rl (reload current file)" };
pub fn rla(_: *void, _: Ctx) Result {
pub fn rla(_: *Self, _: Context) Result {
if (tui.get_buffer_manager()) |bm|
bm.reload_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
}
pub const rla_meta: Meta = .{ .description = "rla (reload all files)" };
pub fn o(_: *void, _: Ctx) Result {
pub fn o(_: *Self, _: Context) Result {
try cmd("open_file", .{});
}
pub const o_meta: Meta = .{ .description = "o (open file)" };
pub fn @"wq!"(_: *void, _: Ctx) Result {
pub fn @"wq!"(_: *Self, _: Context) Result {
cmd("save_file", .{}) catch {};
try cmd("quit_without_saving", .{});
}
pub const @"wq!_meta": Meta = .{ .description = "wq! (write/save file and quit without saving)" };
pub fn n(_: *void, _: Ctx) Result {
pub fn n(_: *Self, _: Context) Result {
try cmd("create_new_file", .{});
}
pub const n_meta: Meta = .{ .description = "n (Create new buffer/tab)" };
pub fn bn(_: *void, _: Ctx) Result {
pub fn bn(_: *Self, _: Context) Result {
try cmd("next_tab", .{});
}
pub const bn_meta: Meta = .{ .description = "bn (Next buffer/tab)" };
pub fn bp(_: *void, _: Ctx) Result {
pub fn bp(_: *Self, _: Context) Result {
try cmd("previous_tab", .{});
}
pub const bp_meta: Meta = .{ .description = "bp (Previous buffer/tab)" };
pub fn bc(_: *void, _: Ctx) Result {
pub fn bc(_: *Self, _: Context) Result {
try cmd("delete_buffer", .{});
}
pub const bc_meta: Meta = .{ .description = "bc (Close buffer/tab)" };
pub fn @"bc!"(_: *void, _: Ctx) Result {
pub fn @"bc!"(_: *Self, _: Context) Result {
try cmd("close_file_without_saving", .{});
}
pub const @"bc!_meta": Meta = .{ .description = "bc! (Close buffer/tab, ignoring changes)" };
pub fn @"bco!"(_: *void, _: Ctx) Result {
pub fn @"bco!"(_: *Self, _: Context) Result {
const mv = tui.mainview() orelse return;
if (tui.get_buffer_manager()) |bm| {
if (mv.get_active_buffer()) |buffer| try bm.delete_others(buffer);
@ -169,7 +172,7 @@ const cmds_ = struct {
}
pub const @"bco!_meta": Meta = .{ .description = "bco! (Close other buffers/tabs, discarding changes)" };
pub fn bco(_: *void, _: Ctx) Result {
pub fn bco(_: *Self, _: Context) Result {
const logger = log.logger("helix-mode");
defer logger.deinit();
const mv = tui.mainview() orelse return;
@ -184,7 +187,49 @@ const cmds_ = struct {
}
pub const bco_meta: Meta = .{ .description = "bco (Close other buffers/tabs)" };
pub fn save_selection(_: *void, _: Ctx) Result {
pub fn move_scroll_half_page_up(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_up, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_up(.{});
}
}
pub const move_scroll_half_page_up_meta: Meta = .{ .description = "Move and scroll half a page up" };
pub fn move_scroll_half_page_down(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_down, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_down(.{});
}
}
pub const move_scroll_half_page_down_meta: Meta = .{ .description = "Move and scroll half a page down" };
pub fn select_half_page_up(self: *Self, _: Context) Result {
try self.send_editor_jump_source();
const root = try self.buf_root();
try self.with_selections_and_view_const(root, move_cursor_half_page_up, &self.view);
self.clamp();
try self.send_editor_jump_destination();
}
pub const select_half_page_up_meta: Meta = .{ .description = "Select half a page up" };
pub fn select_half_page_down(self: *Self, _: Context) Result {
try self.send_editor_jump_source();
const root = try self.buf_root();
try self.with_selections_and_view_const(root, move_cursor_half_page_down, &self.view);
self.clamp();
try self.send_editor_jump_destination();
}
pub const select_half_page_down_meta: Meta = .{ .description = "Select half a page down" };
pub fn save_selection(_: *Self, _: Context) Result {
const logger = log.logger("helix-mode");
defer logger.deinit();
logger.print("saved location", .{});
@ -202,7 +247,7 @@ const cmds_ = struct {
}
pub const save_selection_meta: Meta = .{ .description = "Save current selection to location history" };
pub fn split_selection_on_newline(_: *void, _: Ctx) Result {
pub fn split_selection_on_newline(_: *Self, _: Context) Result {
const ed, const root = get_buf() orelse return;
const cursels = try ed.cursels.toOwnedSlice(ed.allocator);
defer ed.allocator.free(cursels);
@ -213,14 +258,14 @@ const cmds_ = struct {
}
pub const split_selection_on_newline_meta: Meta = .{ .description = "Add cursor to each line in selection helix" };
pub fn match_brackets(_: *void, ctx: Ctx) Result {
pub fn match_brackets(_: *Self, ctx: Context) Result {
const ed, const root = get_buf() orelse return;
try ed.with_cursels_const_once_arg(root, &match_bracket, ctx);
ed.clamp();
}
pub const match_brackets_meta: Meta = .{ .description = "Goto matching bracket" };
pub fn extend_line_below(_: *void, ctx: Ctx) Result {
pub fn extend_line_below(_: *Self, ctx: Context) Result {
const ed, const root = get_buf() orelse return;
var repeat: usize = 1;
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
@ -240,73 +285,73 @@ const cmds_ = struct {
}
pub const extend_line_below_meta: Meta = .{ .arguments = &.{.integer}, .description = "Select current line, if already selected, extend to next line" };
pub fn init_helix_select_mode(_: *void, _: Ctx) Result {
pub fn init_helix_select_mode(_: *Self, _: Context) Result {
_, const ed = get_context() orelse return;
try ed.enable_selection(.{});
}
pub const init_helix_select_mode_meta: Meta = .{};
pub fn move_next_word_start(_: *void, ctx: Ctx) Result {
pub fn move_next_word_start(_: *Self, ctx: Context) Result {
try move_to_word(ctx, Editor.move_cursor_word_right_vim, .forwards);
}
pub const move_next_word_start_meta: Meta = .{ .description = "Move next word start", .arguments = &.{.integer} };
pub fn extend_next_word_start(_: *void, ctx: Ctx) Result {
pub fn extend_next_word_start(_: *Self, ctx: Context) Result {
try extend_to_word(ctx, Editor.move_cursor_word_right_vim, .forwards);
}
pub const extend_next_word_start_meta: Meta = .{ .description = "Extend next word start", .arguments = &.{.integer} };
pub fn move_next_long_word_start(_: *void, ctx: Ctx) Result {
pub fn move_next_long_word_start(_: *Self, ctx: Context) Result {
try move_to_word(ctx, move_cursor_long_word_right, .forwards);
}
pub const move_next_long_word_start_meta: Meta = .{ .description = "Move next long word start", .arguments = &.{.integer} };
pub fn extend_next_long_word_start(_: *void, ctx: Ctx) Result {
pub fn extend_next_long_word_start(_: *Self, ctx: Context) Result {
try extend_to_word(ctx, move_cursor_long_word_right, .forwards);
}
pub const extend_next_long_word_start_meta: Meta = .{ .description = "Extend next long word start", .arguments = &.{.integer} };
pub fn move_prev_word_start(_: *void, ctx: Ctx) Result {
pub fn move_prev_word_start(_: *Self, ctx: Context) Result {
try move_cursels_const_repeat(move_cursor_prev_word_start, ctx);
}
pub const move_prev_word_start_meta: Meta = .{ .description = "Move previous word start", .arguments = &.{.integer} };
pub fn extend_prev_word_start(_: *void, ctx: Ctx) Result {
pub fn extend_prev_word_start(_: *Self, ctx: Context) Result {
try move_cursels_const_repeat(move_cursor_prev_word_start_extend, ctx);
}
pub const extend_prev_word_start_meta: Meta = .{ .description = "Extend previous word start", .arguments = &.{.integer} };
pub fn move_prev_long_word_start(_: *void, ctx: Ctx) Result {
pub fn move_prev_long_word_start(_: *Self, ctx: Context) Result {
try move_to_word(ctx, move_cursor_long_word_left, .backwards);
}
pub const move_prev_long_word_start_meta: Meta = .{ .description = "Move previous long word start", .arguments = &.{.integer} };
pub fn extend_prev_long_word_start(_: *void, ctx: Ctx) Result {
pub fn extend_prev_long_word_start(_: *Self, ctx: Context) Result {
try extend_to_word(ctx, move_cursor_long_word_left, .backwards);
}
pub const extend_prev_long_word_start_meta: Meta = .{ .description = "Extend previous word start", .arguments = &.{.integer} };
pub fn move_next_word_end(_: *void, ctx: Ctx) Result {
pub fn move_next_word_end(_: *Self, ctx: Context) Result {
try move_to_word(ctx, move_cursor_word_right_end_helix, .forwards);
}
pub const move_next_word_end_meta: Meta = .{ .description = "Move next word end", .arguments = &.{.integer} };
pub fn extend_next_word_end(_: *void, ctx: Ctx) Result {
pub fn extend_next_word_end(_: *Self, ctx: Context) Result {
try extend_to_word(ctx, move_cursor_word_right_end_helix, .forwards);
}
pub const extend_next_word_end_meta: Meta = .{ .description = "Extend next word end", .arguments = &.{.integer} };
pub fn move_next_long_word_end(_: *void, ctx: Ctx) Result {
pub fn move_next_long_word_end(_: *Self, ctx: Context) Result {
try move_to_word(ctx, move_cursor_long_word_right_end, .forwards);
}
pub const move_next_long_word_end_meta: Meta = .{ .description = "Move next long word end", .arguments = &.{.integer} };
pub fn extend_next_long_word_end(_: *void, ctx: Ctx) Result {
pub fn extend_next_long_word_end(_: *Self, ctx: Context) Result {
try extend_to_word(ctx, move_cursor_long_word_right_end, .forwards);
}
pub const extend_next_long_word_end_meta: Meta = .{ .description = "Extend next long word end", .arguments = &.{.integer} };
pub fn cut_forward_internal_inclusive(_: *void, _: Ctx) Result {
pub fn cut_forward_internal_inclusive(_: *Self, _: Context) Result {
const ed, const b = get_buf_for_update() orelse return;
tui.clipboard_start_group();
const root = try ed.cut_to(move_noop, b.root);
@ -315,7 +360,7 @@ const cmds_ = struct {
}
pub const cut_forward_internal_inclusive_meta: Meta = .{ .description = "Cut next character to internal clipboard (inclusive)" };
pub fn select_right_helix(_: *void, ctx: Ctx) Result {
pub fn select_right_helix(_: *Self, ctx: Context) Result {
const ed, const root = get_buf() orelse return;
var repeat: usize = 1;
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
@ -340,7 +385,7 @@ const cmds_ = struct {
}
pub const select_right_helix_meta: Meta = .{ .description = "Select right", .arguments = &.{.integer} };
pub fn select_left_helix(_: *void, ctx: Ctx) Result {
pub fn select_left_helix(_: *Self, ctx: Context) Result {
const ed, const root = get_buf() orelse return;
var repeat: usize = 1;
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
@ -368,47 +413,47 @@ const cmds_ = struct {
}
pub const select_left_helix_meta: Meta = .{ .description = "Select left", .arguments = &.{.integer} };
pub fn select_to_char_left_helix(_: *void, ctx: Ctx) Result {
pub fn select_to_char_left_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &select_cursel_to_char_left_helix);
}
pub const select_to_char_left_helix_meta: Meta = .{ .description = "Select to char left" };
pub fn select_till_char_left_helix(_: *void, ctx: Ctx) Result {
pub fn select_till_char_left_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &select_cursel_till_char_left_helix);
}
pub const select_till_char_left_helix_meta: Meta = .{ .description = "Select until char left" };
pub fn extend_to_char_left_helix(_: *void, ctx: Ctx) Result {
pub fn extend_to_char_left_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &extend_cursel_to_char_left_helix);
}
pub const extend_to_char_left_helix_meta: Meta = .{ .description = "Extend Selection to char left" };
pub fn extend_till_char_left_helix(_: *void, ctx: Ctx) Result {
pub fn extend_till_char_left_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &extend_cursel_till_char_left_helix);
}
pub const extend_till_char_left_helix_meta: Meta = .{ .description = "Extend Selection until char left" };
pub fn select_till_char_right_helix(_: *void, ctx: Ctx) Result {
pub fn select_till_char_right_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &select_cursel_till_char_right_helix);
}
pub const select_till_char_right_helix_meta: Meta = .{ .description = "Select until char right" };
pub fn select_to_char_right_helix(_: *void, ctx: Ctx) Result {
pub fn select_to_char_right_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &select_cursel_to_char_right_helix);
}
pub const select_to_char_right_helix_meta: Meta = .{ .description = "Select to char right" };
pub fn extend_till_char_right_helix(_: *void, ctx: Ctx) Result {
pub fn extend_till_char_right_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &extend_cursel_till_char_right_helix);
}
pub const extend_till_char_right_helix_meta: Meta = .{ .description = "Extend Selection until char right" };
pub fn extend_to_char_right_helix(_: *void, ctx: Ctx) Result {
pub fn extend_to_char_right_helix(_: *Self, ctx: Context) Result {
try to_char_helix(ctx, &extend_cursel_to_char_right_helix);
}
pub const extend_to_char_right_helix_meta: Meta = .{ .description = "Extend Selection to char right" };
pub fn select_textobject_inner(_: *void, ctx: Ctx) Result {
pub fn select_textobject_inner(_: *Self, ctx: Context) Result {
const ed, const root = get_buf() orelse return error.Stop;
var action: []const u8 = "";
@ -425,7 +470,7 @@ const cmds_ = struct {
}
pub const select_textobject_inner_meta: Meta = .{ .description = "select inside object helix" };
pub fn select_textobject_around(_: *void, ctx: Ctx) Result {
pub fn select_textobject_around(_: *Self, ctx: Context) Result {
const ed, const root = get_buf() orelse return;
var action: []const u8 = "";
@ -442,7 +487,7 @@ const cmds_ = struct {
}
pub const select_textobject_around_meta: Meta = .{ .description = "select around object helix" };
pub fn copy_helix(_: *void, _: Ctx) Result {
pub fn copy_helix(_: *Self, _: Context) Result {
const ed, const root = get_buf() orelse return;
tui.clipboard_start_group();
@ -453,22 +498,22 @@ const cmds_ = struct {
}
pub const copy_helix_meta: Meta = .{ .description = "Copy selection to clipboard (helix)" };
pub fn paste_after(_: *void, ctx: Ctx) Result {
pub fn paste_after(_: *Self, ctx: Context) Result {
try paste_helix(ctx, insert_after);
}
pub const paste_after_meta: Meta = .{ .description = "Paste from clipboard after selection" };
pub fn replace_selections_with_clipboard(_: *void, ctx: Ctx) Result {
pub fn replace_selections_with_clipboard(_: *Self, ctx: Context) Result {
try paste_helix(ctx, insert_replace_selection);
}
pub const replace_selections_with_clipboard_meta: Meta = .{ .description = "Replace selection from clipboard" };
pub fn paste_clipboard_before(_: *void, ctx: Ctx) Result {
pub fn paste_clipboard_before(_: *Self, ctx: Context) Result {
try paste_helix(ctx, insert_before);
}
pub const paste_clipboard_before_meta: Meta = .{ .description = "Paste from clipboard before selection" };
pub fn replace_with_character_helix(_: *void, ctx: Ctx) Result {
pub fn replace_with_character_helix(_: *Self, ctx: Context) Result {
const ed, const b = get_buf_for_update() orelse return;
var root = b.root;
root = try ed.with_cursels_mut_once_arg(root, replace_cursel_with_character, ed.allocator, ctx);
@ -554,7 +599,7 @@ fn move_cursor_prev_word_start_extend(root: Buffer.Root, cursel: *CurSel, metric
try move_cursor_prev_word_start(root, cursel, metrics);
}
fn move_cursels_const_repeat(move: Editor.cursel_operator_const, ctx: Ctx) Result {
fn move_cursels_const_repeat(move: Editor.cursel_operator_const, ctx: Context) Result {
const ed, const root = get_buf() orelse return;
try ed.with_cursels_const_repeat(root, move, ctx);
ed.clamp();
@ -1294,6 +1339,14 @@ fn is_cursel_from_extend_line_below(cursel: CurSel) bool {
return false;
}
fn move_cursor_half_page_up(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_up(root, view, metrics);
}
fn move_cursor_half_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_down(root, view, metrics);
}
const private = @This();
// exports for unittests
pub const test_internal = struct {

View file

@ -2,11 +2,19 @@ const std = @import("std");
const command = @import("command");
const cmd = command.executeName;
const tui = @import("../tui.zig");
const Editor = @import("../editor.zig").Editor;
const Buffer = @import("Buffer");
const Cursor = Buffer.Cursor;
const View = Buffer.View;
var commands: Commands = undefined;
const Self = Editor;
pub fn init() !void {
var v: void = {};
try commands.init(&v);
const mv = tui.mainview() orelse return;
const ed = mv.get_active_editor() orelse return;
try commands.init(ed);
}
pub fn deinit() void {
@ -14,74 +22,75 @@ pub fn deinit() void {
}
const Commands = command.Collection(cmds_);
const cmds_ = struct {
pub const Target = void;
const Ctx = command.Context;
const Context = command.Context;
const Meta = command.Metadata;
const Result = command.Result;
pub fn w(_: *void, _: Ctx) Result {
const cmds_ = struct {
pub const Target = Self;
pub fn w(_: *Self, _: Context) Result {
try cmd("save_file", .{});
}
pub const w_meta: Meta = .{ .description = "w (write file)" };
pub fn q(_: *void, _: Ctx) Result {
pub fn q(_: *Self, _: Context) Result {
try cmd("quit", .{});
}
pub const q_meta: Meta = .{ .description = "q (quit)" };
pub fn @"q!"(_: *void, _: Ctx) Result {
pub fn @"q!"(_: *Self, _: Context) Result {
try cmd("quit_without_saving", .{});
}
pub const @"q!_meta": Meta = .{ .description = "q! (quit without saving)" };
pub fn @"qa!"(_: *void, _: Ctx) Result {
pub fn @"qa!"(_: *Self, _: Context) Result {
try cmd("quit_without_saving", .{});
}
pub const @"qa!_meta": Meta = .{ .description = "qa! (quit without saving anything)" };
pub fn wq(_: *void, _: Ctx) Result {
pub fn wq(_: *Self, _: Context) Result {
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
}
pub const wq_meta: Meta = .{ .description = "wq (write file and quit)" };
pub fn @"wq!"(_: *void, _: Ctx) Result {
pub fn @"wq!"(_: *Self, _: Context) Result {
cmd("save_file", .{}) catch {};
try cmd("quit_without_saving", .{});
}
pub const @"wq!_meta": Meta = .{ .description = "wq! (write file and quit without saving)" };
pub fn @"e!"(_: *void, _: Ctx) Result {
pub fn @"e!"(_: *Self, _: Context) Result {
try cmd("reload_file", .{});
}
pub const @"e!_meta": Meta = .{ .description = "e! (force reload current file)" };
pub fn bd(_: *void, _: Ctx) Result {
pub fn bd(_: *Self, _: Context) Result {
try cmd("close_file", .{});
}
pub const bd_meta: Meta = .{ .description = "bd (Close file)" };
pub fn bw(_: *void, _: Ctx) Result {
pub fn bw(_: *Self, _: Context) Result {
try cmd("delete_buffer", .{});
}
pub const bw_meta: Meta = .{ .description = "bw (Delete buffer)" };
pub fn bnext(_: *void, _: Ctx) Result {
pub fn bnext(_: *Self, _: Context) Result {
try cmd("next_tab", .{});
}
pub const bnext_meta: Meta = .{ .description = "bnext (Next buffer/tab)" };
pub fn bprevious(_: *void, _: Ctx) Result {
pub fn bprevious(_: *Self, _: Context) Result {
try cmd("next_tab", .{});
}
pub const bprevious_meta: Meta = .{ .description = "bprevious (Previous buffer/tab)" };
pub fn ls(_: *void, _: Ctx) Result {
pub fn ls(_: *Self, _: Context) Result {
try cmd("switch_buffers", .{});
}
pub const ls_meta: Meta = .{ .description = "ls (List/switch buffers)" };
pub fn move_begin_or_add_integer_argument_zero(_: *void, _: Ctx) Result {
pub fn move_begin_or_add_integer_argument_zero(_: *Self, _: Context) Result {
return if (@import("keybind").current_integer_argument()) |_|
command.executeName("add_integer_argument_digit", command.fmt(.{0}))
else
@ -89,7 +98,7 @@ const cmds_ = struct {
}
pub const move_begin_or_add_integer_argument_zero_meta: Meta = .{ .description = "Move cursor to beginning of line (vim)" };
pub fn enter_mode_at_next_char(self: *void, ctx: Ctx) Result {
pub fn enter_mode_at_next_char(self: *Self, ctx: Context) Result {
_ = self; // autofix
_ = ctx; // autofix
//TODO
@ -98,7 +107,7 @@ const cmds_ = struct {
pub const enter_mode_at_next_char_meta: Meta = .{ .description = "Move forward one char and change mode" };
pub fn enter_mode_on_newline_down(self: *void, ctx: Ctx) Result {
pub fn enter_mode_on_newline_down(self: *Self, ctx: Context) Result {
_ = self; // autofix
_ = ctx; // autofix
//TODO
@ -107,7 +116,7 @@ const cmds_ = struct {
pub const enter_mode_on_newline_down_meta: Meta = .{ .description = "Insert a newline and change mode" };
pub fn enter_mode_on_newline_up(self: *void, ctx: Ctx) Result {
pub fn enter_mode_on_newline_up(self: *Self, ctx: Context) Result {
_ = self; // autofix
_ = ctx; // autofix
//TODO
@ -115,7 +124,7 @@ const cmds_ = struct {
}
pub const enter_mode_on_newline_up_meta: Meta = .{ .description = "Insert a newline above the current line and change mode" };
pub fn enter_mode_at_line_begin(self: *void, ctx: Ctx) Result {
pub fn enter_mode_at_line_begin(self: *Self, ctx: Context) Result {
_ = self; // autofix
_ = ctx; // autofix
//TODO
@ -124,7 +133,7 @@ const cmds_ = struct {
pub const enter_mode_at_line_begin_meta: Meta = .{ .description = "Goto line begin and change mode" };
pub fn enter_mode_at_line_end(self: *void, ctx: Ctx) Result {
pub fn enter_mode_at_line_end(self: *Self, ctx: Context) Result {
_ = self; // autofix
_ = ctx; // autofix
//TODO
@ -132,7 +141,7 @@ const cmds_ = struct {
}
pub const enter_mode_at_line_end_meta: Meta = .{ .description = "Goto line end and change mode" };
pub fn copy_line(self: *void, ctx: Ctx) Result {
pub fn copy_line(self: *Self, ctx: Context) Result {
_ = self; // autofix
_ = ctx; // autofix
//TODO
@ -140,4 +149,112 @@ const cmds_ = struct {
}
pub const copy_line_meta: Meta = .{ .description = "Copies the current line" };
pub fn move_scroll_half_page_up(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_up, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_up(.{});
}
}
pub const move_scroll_half_page_up_meta: Meta = .{ .description = "Move and scroll half a page up" };
pub fn move_scroll_half_page_down(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_down, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_down(.{});
}
}
pub const move_scroll_half_page_down_meta: Meta = .{ .description = "Move and scroll half a page down" };
pub fn move_left_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_left_vim, ctx) catch {};
self.clamp();
}
pub const move_left_vim_meta: Meta = .{ .description = "Move cursor left (vim)", .arguments = &.{.integer} };
pub fn move_right_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_right_vim, ctx) catch {};
self.clamp();
}
pub const move_right_vim_meta: Meta = .{ .description = "Move cursor right (vim)", .arguments = &.{.integer} };
pub fn cut_to_end_vim(self: *Self, _: Context) Result {
const b = try self.buf_for_update();
const root = try self.cut_to(move_cursor_end_vim, b.root);
try self.update_buf(root);
self.clamp();
}
pub const cut_to_end_vim_meta: Meta = .{ .description = "Cut to end of line (vim)" };
pub fn move_up_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_up_vim, ctx) catch {};
self.clamp();
}
pub const move_up_vim_meta: Meta = .{ .description = "Move cursor up (vim)", .arguments = &.{.integer} };
pub fn move_down_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_down_vim, ctx) catch {};
self.clamp();
}
pub const move_down_vim_meta: Meta = .{ .description = "Move cursor down (vim)", .arguments = &.{.integer} };
};
fn is_eol_right_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width - 1)
return true;
return false;
}
fn is_eol_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width)
return true;
return false;
}
fn move_cursor_half_page_up(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_up(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_half_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_down(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_up_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_up(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_down_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_down(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_end_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
Editor.move_cursor_right_until(root, cursor, is_eol_vim, metrics);
}
fn move_cursor_left_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
Editor.move_cursor_left_unless(root, cursor, Editor.is_eol_left, metrics);
}
fn move_cursor_right_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
Editor.move_cursor_right_unless(root, cursor, is_eol_right_vim, metrics);
}