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:
CJ van den Berg 2025-09-17 10:04:27 +02:00
parent 9bdc3e0a0a
commit 59921d8e10
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
2 changed files with 79 additions and 23 deletions

View file

@ -18,10 +18,12 @@ pub fn Create(options: type) type {
const Commands = command.Collection(cmds);
const ValueType = if (@hasDecl(options, "ValueType")) options.ValueType else usize;
allocator: Allocator,
buf: [30]u8 = undefined,
input: ?usize = null,
start: usize,
input: ?ValueType = null,
start: ValueType,
ctx: command.Context,
commands: Commands = undefined,
@ -31,7 +33,7 @@ pub fn Create(options: type) type {
self.* = .{
.allocator = allocator,
.ctx = .{ .args = try ctx.args.clone(allocator) },
.start = 0,
.start = if (@hasDecl(options, "ValueType")) ValueType{} else 0,
};
self.start = options.start(self);
try self.commands.init(self);
@ -55,27 +57,42 @@ pub fn Create(options: type) type {
fn update_mini_mode_text(self: *Self) void {
if (tui.mini_mode()) |mini_mode| {
mini_mode.text = if (self.input) |linenum|
(fmt.bufPrint(&self.buf, "{d}", .{linenum}) catch "")
else
"";
if (@hasDecl(options, "format_value")) {
mini_mode.text = options.format_value(self, self.input, &self.buf);
} 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);
}
}
fn insert_char(self: *Self, char: u8) void {
switch (char) {
'0' => {
if (self.input) |linenum| self.input = linenum * 10;
},
'1'...'9' => {
const digit: usize = @intCast(char - '0');
self.input = if (self.input) |x| x * 10 + digit else digit;
},
else => {},
const process_digit_ = if (@hasDecl(options, "process_digit")) options.process_digit else process_digit;
if (@hasDecl(options, "Separator")) {
switch (char) {
'0'...'9' => process_digit_(@intCast(char - '0')),
options.Separator => options.process_separator(self),
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 {
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 fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
if (self.input) |linenum| {
const newval = if (linenum < 10) 0 else linenum / 10;
self.input = if (newval == 0) null else newval;
if (self.input) |*input| {
if (@hasDecl(options, "delete")) {
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();
options.preview(self, self.ctx);
}