Compare commits
15 commits
764a8cce41
...
3dfb93fbd2
| Author | SHA1 | Date | |
|---|---|---|---|
| 3dfb93fbd2 | |||
| 4e4ec855ed | |||
| d069250d17 | |||
| 4638c38032 | |||
| 83bbbfebe3 | |||
| 4d81123c76 | |||
| b3425d5c59 | |||
| 6f1806cd95 | |||
| 989557fb6d | |||
| fd9fa4ee8f | |||
| 1803584940 | |||
| 67c6965eaa | |||
| fb5c67280f | |||
| 4394940594 | |||
| 9dd12ad7dc |
7 changed files with 76 additions and 102 deletions
|
|
@ -502,7 +502,6 @@ pub fn build_exe(
|
|||
.{ .name = "EventHandler", .module = EventHandler_mod },
|
||||
.{ .name = "input", .module = input_mod },
|
||||
.{ .name = "thespian", .module = thespian_mod },
|
||||
.{ .name = "log", .module = log_mod },
|
||||
.{ .name = "Buffer", .module = Buffer_mod },
|
||||
.{ .name = "config", .module = config_mod },
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ const std = @import("std");
|
|||
const tp = @import("thespian");
|
||||
const cbor = @import("cbor");
|
||||
const builtin = @import("builtin");
|
||||
const log = @import("log");
|
||||
const root = @import("soft_root").root;
|
||||
|
||||
const input = @import("input");
|
||||
|
|
@ -16,6 +15,8 @@ const KeyEvent = input.KeyEvent;
|
|||
const SelectionStyle = @import("Buffer").Selection.Style;
|
||||
pub const CursorShape = @import("config").CursorShape;
|
||||
|
||||
const log = std.log.scoped(.keybind);
|
||||
|
||||
const parse_flow = @import("parse_flow.zig");
|
||||
const parse_vim = @import("parse_vim.zig");
|
||||
|
||||
|
|
@ -245,11 +246,9 @@ pub fn set_namespace(namespace_name: []const u8) LoadError!void {
|
|||
fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadError!*const BindingSet {
|
||||
const namespace = current_namespace();
|
||||
var binding_set = namespace.get_mode(mode_name) orelse {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("get_namespace_mode", "ERROR: mode not found: {s}", .{mode_name});
|
||||
log.err("ERROR: mode not found: {s}", .{mode_name});
|
||||
var iter = namespace.modes.iterator();
|
||||
while (iter.next()) |entry| logger.print("available modes: {s}", .{entry.key_ptr.*});
|
||||
logger.deinit();
|
||||
while (iter.next()) |entry| log.info("available modes: {s}", .{entry.key_ptr.*});
|
||||
return error.NotFound;
|
||||
};
|
||||
binding_set.set_insert_command(insert_command);
|
||||
|
|
@ -367,11 +366,8 @@ const Command = struct {
|
|||
fn execute_const(self: *const @This()) void {
|
||||
var buf: [2048]u8 = undefined;
|
||||
@memcpy(buf[0..self.args.len], self.args);
|
||||
command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } }) catch |e| {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("init/deinit_command", "ERROR: {s} {s}", .{ self.command, @errorName(e) });
|
||||
logger.deinit();
|
||||
};
|
||||
command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } }) catch |e|
|
||||
log.err("ERROR: {s} {s}", .{ self.command, @errorName(e) });
|
||||
}
|
||||
|
||||
fn has_integer_argument(id: command.ID) bool {
|
||||
|
|
@ -390,9 +386,7 @@ const Command = struct {
|
|||
switch (state) {
|
||||
.command => {
|
||||
if (token != .string) {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("keybind.load", "ERROR: invalid command token {any}", .{token});
|
||||
logger.deinit();
|
||||
log.err("ERROR: invalid command token {any}", .{token});
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
command_ = try allocator.dupe(u8, token.string);
|
||||
|
|
@ -404,9 +398,7 @@ const Command = struct {
|
|||
else => {
|
||||
const json = try std.json.Stringify.valueAlloc(allocator, token, .{});
|
||||
defer allocator.free(json);
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("keybind.load", "ERROR: invalid command argument '{s}'", .{json});
|
||||
logger.deinit();
|
||||
log.err("ERROR: invalid command argument '{s}'", .{json});
|
||||
return error.InvalidFormat;
|
||||
},
|
||||
}
|
||||
|
|
@ -538,30 +530,22 @@ const BindingSet = struct {
|
|||
_ = event;
|
||||
bindings: for (bindings) |entry| {
|
||||
if (entry.len < 2) {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("keybind.load", "ERROR: invalid binding definition {any}", .{entry});
|
||||
logger.deinit();
|
||||
log.err("ERROR: invalid binding definition {any}", .{entry});
|
||||
continue :bindings;
|
||||
}
|
||||
const keys = entry[0];
|
||||
if (keys != .string) {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("keybind.load", "ERROR: invalid binding key definition {any}", .{keys});
|
||||
logger.deinit();
|
||||
log.err("ERROR: invalid binding key definition {any}", .{keys});
|
||||
continue :bindings;
|
||||
}
|
||||
|
||||
const key_events = switch (self.syntax) {
|
||||
.flow => parse_flow.parse_key_events(allocator, keys.string) catch |e| {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("keybind.load", "ERROR: {s} {s}", .{ @errorName(e), parse_flow.parse_error_message });
|
||||
logger.deinit();
|
||||
log.err("ERROR: {s} {s}", .{ @errorName(e), parse_flow.parse_error_message });
|
||||
break;
|
||||
},
|
||||
.vim => parse_vim.parse_key_events(allocator, keys.string) catch |e| {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("keybind.load.vim", "ERROR: {s} {s}", .{ @errorName(e), parse_vim.parse_error_message });
|
||||
logger.deinit();
|
||||
log.err("ERROR: {s} {s}", .{ @errorName(e), parse_vim.parse_error_message });
|
||||
break;
|
||||
},
|
||||
};
|
||||
|
|
@ -577,9 +561,7 @@ const BindingSet = struct {
|
|||
if (cmd_entry != .array) {
|
||||
const json = try std.json.Stringify.valueAlloc(allocator, cmd_entry, .{});
|
||||
defer allocator.free(json);
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("keybind.load", "ERROR: invalid command definition {s}", .{json});
|
||||
logger.deinit();
|
||||
log.err("ERROR: invalid command definition {s}", .{json});
|
||||
continue :bindings;
|
||||
}
|
||||
try cmds.append(allocator, try Command.load(allocator, cmd_entry.array.items));
|
||||
|
|
@ -793,10 +775,7 @@ const BindingSet = struct {
|
|||
input.key.left_shift, input.key.right_shift => return,
|
||||
else => {},
|
||||
};
|
||||
|
||||
const logger = log.logger("keybind");
|
||||
defer logger.deinit();
|
||||
logger.print("C-? for key hints", .{});
|
||||
log.info("{f} is unbound, press C-? for key hints", .{current_key_event_sequence_fmt()});
|
||||
}
|
||||
|
||||
/// Retrieve bindings that will match a key event sequence
|
||||
|
|
@ -900,8 +879,15 @@ const KeyEventSequenceFmt = struct {
|
|||
key_events: []const KeyEvent,
|
||||
|
||||
pub fn format(self: @This(), writer: anytype) !void {
|
||||
for (self.key_events) |key_event|
|
||||
try writer.print(" {f}", .{input.key_event_short_fmt(key_event)});
|
||||
var first = true;
|
||||
for (self.key_events) |key_event| {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
try writer.print(" ", .{});
|
||||
}
|
||||
try writer.print("{f}", .{input.key_event_short_fmt(key_event)});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -985,7 +971,7 @@ test "match" {
|
|||
}
|
||||
|
||||
test "json" {
|
||||
var bindings: BindingSet = .{ .name = "test", .selection_style = .normal };
|
||||
var bindings: BindingSet = .{ .name = "test", .config_section = "test_section", .selection_style = .normal };
|
||||
_ = try bindings.process_key_event(input.KeyEvent.from_key('j'));
|
||||
_ = try bindings.process_key_event(input.KeyEvent.from_key('k'));
|
||||
_ = try bindings.process_key_event(input.KeyEvent.from_key('g'));
|
||||
|
|
|
|||
|
|
@ -260,7 +260,11 @@ pub fn std_log_function(
|
|||
const log_pid = std_log_pid orelse return;
|
||||
const prefix = "[" ++ comptime level.asText() ++ "] ";
|
||||
var buf: [max_log_message]u8 = undefined;
|
||||
const output = std.fmt.bufPrint(&buf, prefix ++ format, args) catch "MESSAGE TOO LARGE";
|
||||
const fmt = switch (level) {
|
||||
.warn, .debug => prefix ++ format,
|
||||
.err, .info => format,
|
||||
};
|
||||
const output = std.fmt.bufPrint(&buf, fmt, args) catch "MESSAGE TOO LARGE";
|
||||
if (level == .err) {
|
||||
log_pid.send(.{ "log", "error", @tagName(scope), "std.log", "->", output }) catch {};
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ pub const application_subtext = "a programmer's text editor";
|
|||
pub const application_description = application_title ++ ": " ++ application_subtext;
|
||||
|
||||
pub const std_options: std.Options = .{
|
||||
// .log_level = if (builtin.mode == .Debug) .debug else .warn,
|
||||
.log_level = if (builtin.mode == .Debug) .info else .warn,
|
||||
.log_level = if (builtin.mode == .Debug) .debug else .info,
|
||||
.logFn = log.std_log_function,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ const Process = struct {
|
|||
var buf: [1024]u8 = undefined;
|
||||
const json = self.argv.to_json(&buf) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.handlers.log_execute)
|
||||
self.logger.print("shell: execute {s}", .{json});
|
||||
self.logger.print("execute {s}", .{json});
|
||||
self.sp = tp.subprocess.init(self.allocator, self.argv, module_name, self.stdin_behavior) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ var show_page: usize = 0;
|
|||
|
||||
pub fn render_current_input_mode(allocator: std.mem.Allocator, select_mode: keybind.SelectMode, theme: *const Widget.Theme) void {
|
||||
const mode = tui.input_mode() orelse return;
|
||||
const bindings = blk: {
|
||||
const b = mode.current_key_event_sequence_bindings(allocator, select_mode) catch return;
|
||||
break :blk if (b.len > 0) b else mode.current_bindings(allocator, select_mode) catch return;
|
||||
};
|
||||
const key_events = mode.current_key_event_sequence_bindings(allocator, select_mode) catch return;
|
||||
const bindings = if (key_events.len > 0)
|
||||
key_events
|
||||
else
|
||||
mode.current_bindings(allocator, select_mode) catch return;
|
||||
defer allocator.free(bindings);
|
||||
return render(mode, bindings, theme, .full);
|
||||
return render(mode, bindings, theme, if (key_events.len > 0) .no_key_event_prefix else .full);
|
||||
}
|
||||
|
||||
pub fn render_current_key_event_sequence(allocator: std.mem.Allocator, select_mode: keybind.SelectMode, theme: *const Widget.Theme) void {
|
||||
|
|
@ -53,7 +54,7 @@ fn render(mode: *keybind.Mode, bindings: []const keybind.Binding, theme: *const
|
|||
const max_len = max_prefix_len + max_description_len + 2 + 2;
|
||||
const widget_style = tui.get_widget_style(widget_type);
|
||||
const scr = tui.screen();
|
||||
const max_screen_height = scr.h -| widget_style.padding.top -| widget_style.padding.bottom -| 1;
|
||||
const max_screen_height = scr.h -| widget_style.padding.top -| widget_style.padding.bottom -| 3;
|
||||
const max_items = @min(bindings.len, max_screen_height);
|
||||
const page_size = max_screen_height;
|
||||
var top = show_page * page_size;
|
||||
|
|
@ -90,12 +91,22 @@ fn render(mode: *keybind.Mode, bindings: []const keybind.Binding, theme: *const
|
|||
}
|
||||
if (widget_style.padding.top > 0) {
|
||||
top_layer_.cursor_move_yx(@intCast(0), @intCast(3)) catch return;
|
||||
_ = top_layer_.print("{s} {s}/{s} {s}", .{
|
||||
widget_style.border.nib,
|
||||
keybind.get_namespace(),
|
||||
mode.bindings.config_section,
|
||||
widget_style.border.nie,
|
||||
}) catch {};
|
||||
if (key_events.len > 0) {
|
||||
_ = top_layer_.print("{s} {s}/{s} prefix: {s} {s}", .{
|
||||
widget_style.border.nib,
|
||||
keybind.get_namespace(),
|
||||
mode.bindings.config_section,
|
||||
key_events,
|
||||
widget_style.border.nie,
|
||||
}) catch {};
|
||||
} else {
|
||||
_ = top_layer_.print("{s} {s}/{s} {s}", .{
|
||||
widget_style.border.nib,
|
||||
keybind.get_namespace(),
|
||||
mode.bindings.config_section,
|
||||
widget_style.border.nie,
|
||||
}) catch {};
|
||||
}
|
||||
}
|
||||
|
||||
// workaround vaxis.Layer issue
|
||||
|
|
@ -133,14 +144,17 @@ fn render(mode: *keybind.Mode, bindings: []const keybind.Binding, theme: *const
|
|||
break :blk writer.buffered();
|
||||
};
|
||||
plane.cursor_move_yx(@intCast(y), 0) catch break;
|
||||
_ = plane.print("{s}", .{keybind_txt[key_events.len..]}) catch {};
|
||||
switch (render_mode) {
|
||||
.no_key_event_prefix => _ = plane.print("{s}", .{keybind_txt[key_events.len..]}) catch {},
|
||||
.full => _ = plane.print(" {s}", .{keybind_txt}) catch {},
|
||||
}
|
||||
}
|
||||
|
||||
plane.set_style(style_label);
|
||||
|
||||
for (bindings[top..], 0..) |binding, y| {
|
||||
if (y >= max_items) break;
|
||||
const padding = max_prefix_len + 2;
|
||||
const padding = max_prefix_len + 3;
|
||||
|
||||
const description = blk: {
|
||||
const id = binding.commands[0].command_id orelse
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ const Buffer = @import("Buffer");
|
|||
const Cursor = Buffer.Cursor;
|
||||
const Selection = Buffer.Selection;
|
||||
|
||||
const Direction = enum { backwards, forwards };
|
||||
|
||||
var commands: Commands = undefined;
|
||||
|
||||
pub fn init() !void {
|
||||
|
|
@ -244,62 +242,62 @@ 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 move_next_word_start(_: *void, ctx: Ctx) Result {
|
||||
try move_to_word(ctx, Editor.move_cursor_word_right_vim, .forwards);
|
||||
try move_to_word(ctx, Editor.move_cursor_word_right_vim);
|
||||
}
|
||||
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 {
|
||||
try extend_to_word(ctx, Editor.move_cursor_word_right_vim, .forwards);
|
||||
try extend_to_word(ctx, Editor.move_cursor_word_right_vim);
|
||||
}
|
||||
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 {
|
||||
try move_to_word(ctx, move_cursor_long_word_right, .forwards);
|
||||
try move_to_word(ctx, move_cursor_long_word_right);
|
||||
}
|
||||
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 {
|
||||
try extend_to_word(ctx, move_cursor_long_word_right, .forwards);
|
||||
try extend_to_word(ctx, move_cursor_long_word_right);
|
||||
}
|
||||
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 {
|
||||
try move_to_word(ctx, move_cursor_word_left_helix, .backwards);
|
||||
try move_to_word(ctx, move_cursor_word_left_helix);
|
||||
}
|
||||
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 {
|
||||
try extend_to_word(ctx, move_cursor_word_left_helix, .backwards);
|
||||
try extend_to_word(ctx, move_cursor_word_left_helix);
|
||||
}
|
||||
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 {
|
||||
try move_to_word(ctx, move_cursor_long_word_left, .backwards);
|
||||
try move_to_word(ctx, move_cursor_long_word_left);
|
||||
}
|
||||
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 {
|
||||
try extend_to_word(ctx, move_cursor_long_word_left, .backwards);
|
||||
try extend_to_word(ctx, move_cursor_long_word_left);
|
||||
}
|
||||
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 {
|
||||
try move_to_word(ctx, move_cursor_word_right_end_helix, .forwards);
|
||||
try move_to_word(ctx, move_cursor_word_right_end_helix);
|
||||
}
|
||||
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 {
|
||||
try extend_to_word(ctx, move_cursor_word_right_end_helix, .forwards);
|
||||
try extend_to_word(ctx, move_cursor_word_right_end_helix);
|
||||
}
|
||||
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 {
|
||||
try move_to_word(ctx, move_cursor_long_word_right_end, .forwards);
|
||||
try move_to_word(ctx, move_cursor_long_word_right_end);
|
||||
}
|
||||
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 {
|
||||
try extend_to_word(ctx, move_cursor_long_word_right_end, .forwards);
|
||||
try extend_to_word(ctx, move_cursor_long_word_right_end);
|
||||
}
|
||||
pub const extend_next_long_word_end_meta: Meta = .{ .description = "Extend next long word end", .arguments = &.{.integer} };
|
||||
|
||||
|
|
@ -528,7 +526,7 @@ fn match_bracket(root: Buffer.Root, cursel: *CurSel, ctx: command.Context, metri
|
|||
}
|
||||
}
|
||||
|
||||
fn move_to_word(ctx: command.Context, move: Editor.cursor_operator_const, direction: Direction) command.Result {
|
||||
fn move_to_word(ctx: command.Context, move: Editor.cursor_operator_const) command.Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
|
@ -539,45 +537,18 @@ fn move_to_word(ctx: command.Context, move: Editor.cursor_operator_const, direct
|
|||
if (repeat > 1) ed.with_cursors_const_repeat(root, move, command.fmt(.{repeat - 1})) catch {};
|
||||
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
var sel = Selection.from_cursor(&cursel.cursor);
|
||||
const cur = sel.begin.test_at(root, is_not_whitespace_or_eol, ed.metrics);
|
||||
if (direction == .backwards) {
|
||||
sel.begin.move_left(root, ed.metrics) catch continue;
|
||||
const prev = sel.begin.test_at(root, Editor.is_not_word_char, ed.metrics);
|
||||
sel.begin = sel.end;
|
||||
if (!cur or cur != prev)
|
||||
sel.begin.move_right(root, ed.metrics) catch continue;
|
||||
} else {
|
||||
sel.end.move_right(root, ed.metrics) catch continue;
|
||||
const next = sel.end.test_at(root, Editor.is_not_word_char, ed.metrics);
|
||||
if (!cur and cur != next)
|
||||
sel.begin = sel.end;
|
||||
}
|
||||
cursel.cursor = sel.end;
|
||||
cursel.selection = sel;
|
||||
cursel.selection = null;
|
||||
};
|
||||
ed.with_selections_const_repeat(root, move, command.fmt(.{1})) catch {};
|
||||
ed.clamp();
|
||||
}
|
||||
|
||||
fn extend_to_word(ctx: command.Context, move: Editor.cursor_operator_const, _: Direction) command.Result {
|
||||
fn extend_to_word(ctx: command.Context, move: Editor.cursor_operator_const) command.Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
var repeat: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
const sel = cursel.enable_selection(root, ed.metrics);
|
||||
const pivot: usize = if (sel.is_reversed()) sel.begin.col -| 1 else sel.begin.col;
|
||||
var i: usize = repeat;
|
||||
while (i > 0) : (i -= 1) {
|
||||
try move(root, &sel.end, ed.metrics);
|
||||
}
|
||||
sel.begin.col = if (sel.is_reversed()) pivot +| 1 else pivot;
|
||||
cursel.cursor = sel.end;
|
||||
};
|
||||
|
||||
ed.with_selections_const_repeat(root, move, ctx) catch {};
|
||||
ed.clamp();
|
||||
}
|
||||
|
||||
|
|
@ -859,6 +830,7 @@ fn move_noop(_: Buffer.Root, _: *Cursor, _: Buffer.Metrics) error{Stop}!void {}
|
|||
fn move_cursor_word_right_end_helix(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
|
||||
try Editor.move_cursor_right(root, cursor, metrics);
|
||||
Editor.move_cursor_right_until(root, cursor, Editor.is_word_boundary_right_vim, metrics);
|
||||
try cursor.move_right(root, metrics);
|
||||
}
|
||||
|
||||
fn move_cursor_to_char_left_beyond_eol(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics, ctx: command.Context) error{Stop}!void {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue