diff --git a/src/tui/mode/mini/goto.zig b/src/tui/mode/mini/goto.zig index 6607dc6..e8bc12a 100644 --- a/src/tui/mode/mini/goto.zig +++ b/src/tui/mode/mini/goto.zig @@ -1,3 +1,4 @@ +const fmt = @import("std").fmt; const command = @import("command"); 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 create = Type.create; +pub const ValueType = @import("../../editor.zig").Cursor; + pub fn name(_: *Type) []const u8 { return "#goto"; } -pub fn start(_: *Type) usize { - const editor = tui.get_active_editor() orelse return 1; - return editor.get_primary().cursor.row + 1; +pub fn start(_: *Type) ValueType { + const editor = tui.get_active_editor() orelse return .{}; + 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; @@ -19,5 +50,9 @@ pub const apply = goto; pub const cancel = goto; 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 {}; + } } diff --git a/src/tui/mode/mini/numeric_input.zig b/src/tui/mode/mini/numeric_input.zig index 5b6be0f..ad32849 100644 --- a/src/tui/mode/mini/numeric_input.zig +++ b/src/tui/mode/mini/numeric_input.zig @@ -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); }