feat: restore cursor column when cancelling goto mini mode
This commit refactors the numeric_input mini mode to make the input value type generic. This allows the goto mini mode to store the origin column along with the row. Also, this will allow more complex numeric_input modes, for example a goto mini mode that supports column and row.
This commit is contained in:
parent
9bdc3e0a0a
commit
59921d8e10
2 changed files with 79 additions and 23 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
const fmt = @import("std").fmt;
|
||||||
const command = @import("command");
|
const command = @import("command");
|
||||||
|
|
||||||
const tui = @import("../../tui.zig");
|
const tui = @import("../../tui.zig");
|
||||||
|
@ -5,13 +6,43 @@ const tui = @import("../../tui.zig");
|
||||||
pub const Type = @import("numeric_input.zig").Create(@This());
|
pub const Type = @import("numeric_input.zig").Create(@This());
|
||||||
pub const create = Type.create;
|
pub const create = Type.create;
|
||||||
|
|
||||||
|
pub const ValueType = @import("../../editor.zig").Cursor;
|
||||||
|
|
||||||
pub fn name(_: *Type) []const u8 {
|
pub fn name(_: *Type) []const u8 {
|
||||||
return "#goto";
|
return "#goto";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(_: *Type) usize {
|
pub fn start(_: *Type) ValueType {
|
||||||
const editor = tui.get_active_editor() orelse return 1;
|
const editor = tui.get_active_editor() orelse return .{};
|
||||||
return editor.get_primary().cursor.row + 1;
|
return editor.get_primary().cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_digit(self: *Type, digit: u8) void {
|
||||||
|
switch (digit) {
|
||||||
|
0 => {
|
||||||
|
if (self.input) |*x| x.row = x.row * 10;
|
||||||
|
},
|
||||||
|
1...9 => {
|
||||||
|
if (self.input) |*x| {
|
||||||
|
x.row = x.row * 10 + digit;
|
||||||
|
} else {
|
||||||
|
self.input = .{ .row = digit };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(self: *Type, input: *ValueType) void {
|
||||||
|
const newval = if (input.row < 10) 0 else input.row / 10;
|
||||||
|
if (newval == 0) self.input = null else input.row = newval;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_value(_: *Type, input: ?ValueType, buf: []u8) []const u8 {
|
||||||
|
return if (input) |value|
|
||||||
|
(fmt.bufPrint(buf, "{d}", .{value.row}) catch "")
|
||||||
|
else
|
||||||
|
"";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const preview = goto;
|
pub const preview = goto;
|
||||||
|
@ -19,5 +50,9 @@ pub const apply = goto;
|
||||||
pub const cancel = goto;
|
pub const cancel = goto;
|
||||||
|
|
||||||
fn goto(self: *Type, _: command.Context) void {
|
fn goto(self: *Type, _: command.Context) void {
|
||||||
command.executeName("goto_line", command.fmt(.{self.input orelse self.start})) catch {};
|
if (self.input) |input| {
|
||||||
|
command.executeName("goto_line", command.fmt(.{input.row})) catch {};
|
||||||
|
} else {
|
||||||
|
command.executeName("goto_line_and_column", command.fmt(.{ self.start.row, self.start.col })) catch {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,12 @@ pub fn Create(options: type) type {
|
||||||
|
|
||||||
const Commands = command.Collection(cmds);
|
const Commands = command.Collection(cmds);
|
||||||
|
|
||||||
|
const ValueType = if (@hasDecl(options, "ValueType")) options.ValueType else usize;
|
||||||
|
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
buf: [30]u8 = undefined,
|
buf: [30]u8 = undefined,
|
||||||
input: ?usize = null,
|
input: ?ValueType = null,
|
||||||
start: usize,
|
start: ValueType,
|
||||||
ctx: command.Context,
|
ctx: command.Context,
|
||||||
commands: Commands = undefined,
|
commands: Commands = undefined,
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ pub fn Create(options: type) type {
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.ctx = .{ .args = try ctx.args.clone(allocator) },
|
.ctx = .{ .args = try ctx.args.clone(allocator) },
|
||||||
.start = 0,
|
.start = if (@hasDecl(options, "ValueType")) ValueType{} else 0,
|
||||||
};
|
};
|
||||||
self.start = options.start(self);
|
self.start = options.start(self);
|
||||||
try self.commands.init(self);
|
try self.commands.init(self);
|
||||||
|
@ -55,27 +57,42 @@ pub fn Create(options: type) type {
|
||||||
|
|
||||||
fn update_mini_mode_text(self: *Self) void {
|
fn update_mini_mode_text(self: *Self) void {
|
||||||
if (tui.mini_mode()) |mini_mode| {
|
if (tui.mini_mode()) |mini_mode| {
|
||||||
mini_mode.text = if (self.input) |linenum|
|
if (@hasDecl(options, "format_value")) {
|
||||||
(fmt.bufPrint(&self.buf, "{d}", .{linenum}) catch "")
|
mini_mode.text = options.format_value(self, self.input, &self.buf);
|
||||||
else
|
} else {
|
||||||
"";
|
mini_mode.text = if (self.input) |linenum|
|
||||||
|
(fmt.bufPrint(&self.buf, "{d}", .{linenum}) catch "")
|
||||||
|
else
|
||||||
|
"";
|
||||||
|
}
|
||||||
mini_mode.cursor = tui.egc_chunk_width(mini_mode.text, 0, 1);
|
mini_mode.cursor = tui.egc_chunk_width(mini_mode.text, 0, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_char(self: *Self, char: u8) void {
|
fn insert_char(self: *Self, char: u8) void {
|
||||||
switch (char) {
|
const process_digit_ = if (@hasDecl(options, "process_digit")) options.process_digit else process_digit;
|
||||||
'0' => {
|
if (@hasDecl(options, "Separator")) {
|
||||||
if (self.input) |linenum| self.input = linenum * 10;
|
switch (char) {
|
||||||
},
|
'0'...'9' => process_digit_(@intCast(char - '0')),
|
||||||
'1'...'9' => {
|
options.Separator => options.process_separator(self),
|
||||||
const digit: usize = @intCast(char - '0');
|
else => {},
|
||||||
self.input = if (self.input) |x| x * 10 + digit else digit;
|
}
|
||||||
},
|
} else {
|
||||||
else => {},
|
switch (char) {
|
||||||
|
'0'...'9' => process_digit_(self, @intCast(char - '0')),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_digit(self: *Self, digit: u8) void {
|
||||||
|
self.input = switch (digit) {
|
||||||
|
0 => if (self.input) |value| value * 10 else 0,
|
||||||
|
1...9 => if (self.input) |x| x * 10 + digit else digit,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_bytes(self: *Self, bytes: []const u8) void {
|
fn insert_bytes(self: *Self, bytes: []const u8) void {
|
||||||
for (bytes) |c| self.insert_char(c);
|
for (bytes) |c| self.insert_char(c);
|
||||||
}
|
}
|
||||||
|
@ -101,9 +118,13 @@ pub fn Create(options: type) type {
|
||||||
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
||||||
|
|
||||||
pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
|
pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
|
||||||
if (self.input) |linenum| {
|
if (self.input) |*input| {
|
||||||
const newval = if (linenum < 10) 0 else linenum / 10;
|
if (@hasDecl(options, "delete")) {
|
||||||
self.input = if (newval == 0) null else newval;
|
options.delete(self, input);
|
||||||
|
} else {
|
||||||
|
const newval = if (input.* < 10) 0 else input.* / 10;
|
||||||
|
self.input = if (newval == 0) null else newval;
|
||||||
|
}
|
||||||
self.update_mini_mode_text();
|
self.update_mini_mode_text();
|
||||||
options.preview(self, self.ctx);
|
options.preview(self, self.ctx);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue