mod(example/input): reorder input handling cases; add alt-b/f binding implementations
This commit is contained in:
@@ -87,10 +87,6 @@ const InputField = struct {
|
||||
.key => |key| {
|
||||
if (key.isAscii()) try this.input.append(key.cp);
|
||||
|
||||
// TODO support arrow keys for navigation?
|
||||
// TODO support readline keybindings (i.e. ctrl-k, ctrl-u, ctrl-b, ctrl-f, etc. and the equivalent alt bindings)
|
||||
// create an own `Element` implementation from this
|
||||
|
||||
if (key.eql(.{ .cp = zterm.input.Enter }) or key.eql(.{ .cp = zterm.input.KpEnter }))
|
||||
this.queue.push(.{ .accept = try this.input.toOwnedSlice() });
|
||||
|
||||
|
||||
@@ -28,16 +28,24 @@ const QuitText = struct {
|
||||
const InputField = struct {
|
||||
/// Offset from the end describing the current position of the cursor.
|
||||
cursor_offset: usize = 0,
|
||||
/// Configuration for the InputField.
|
||||
configuration: Configuration,
|
||||
/// Array holding the value of the input.
|
||||
input: std.ArrayList(u21),
|
||||
/// Reference to the app's queue to issue the associated event to trigger when completing the input.
|
||||
queue: *App.Queue,
|
||||
|
||||
/// Configuration for InputField's.
|
||||
pub const Configuration = struct {
|
||||
color: Color = .default,
|
||||
};
|
||||
|
||||
// TODO make the event to trigger user defined (needs to be `comptime`)
|
||||
// - can this even be agnostic to `u8` / `u21`?
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, queue: *App.Queue) @This() {
|
||||
pub fn init(allocator: std.mem.Allocator, queue: *App.Queue, configuration: Configuration) @This() {
|
||||
return .{
|
||||
.configuration = configuration,
|
||||
.input = .init(allocator),
|
||||
.queue = queue,
|
||||
};
|
||||
@@ -63,7 +71,7 @@ const InputField = struct {
|
||||
.key => |key| {
|
||||
assert(this.cursor_offset >= 0 and this.cursor_offset <= this.input.items.len);
|
||||
|
||||
// see *form* implementation in `zk`, which might become part of the library
|
||||
// readline commands
|
||||
if (key.eql(.{ .cp = zterm.input.Left }) or key.eql(.{ .cp = zterm.input.KpLeft }) or key.eql(.{ .cp = 'b', .mod = .{ .ctrl = true } })) {
|
||||
if (this.cursor_offset < this.input.items.len) this.cursor_offset += 1;
|
||||
}
|
||||
@@ -75,22 +83,6 @@ const InputField = struct {
|
||||
|
||||
if (key.eql(.{ .cp = 'a', .mod = .{ .ctrl = true } })) this.cursor_offset = this.input.items.len;
|
||||
|
||||
if (key.eql(.{ .cp = zterm.input.Backspace })) {
|
||||
if (this.cursor_offset < this.input.items.len) {
|
||||
_ = if (this.cursor_offset == 0) this.input.pop() else this.input.orderedRemove(this.input.items.len - this.cursor_offset - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (key.eql(.{ .cp = zterm.input.Delete }) or key.eql(.{ .cp = zterm.input.KpDelete })) {
|
||||
if (this.cursor_offset > 0) {
|
||||
_ = this.input.orderedRemove(this.input.items.len - this.cursor_offset);
|
||||
this.cursor_offset -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO support readline keybindings (i.e. alt bindings alt-b, alt-f
|
||||
// TODO maybe even ctrl-left, ctrl-right?)
|
||||
// readline commands
|
||||
if (key.eql(.{ .cp = 'k', .mod = .{ .ctrl = true } })) {
|
||||
while (this.cursor_offset > 0) {
|
||||
_ = this.input.pop();
|
||||
@@ -115,10 +107,52 @@ const InputField = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (key.eql(.{ .cp = 'b', .mod = .{ .alt = true } }) or key.eql(.{ .cp = zterm.input.Left, .mod = .{ .ctrl = true } }) or key.eql(.{ .cp = zterm.input.KpLeft, .mod = .{ .ctrl = true } })) {
|
||||
var non_whitespace = false;
|
||||
while (this.cursor_offset < this.input.items.len) {
|
||||
if (non_whitespace and this.input.items[this.input.items.len - this.cursor_offset - 1] == ' ') break;
|
||||
|
||||
// see backspace
|
||||
this.cursor_offset += 1;
|
||||
if (this.cursor_offset == this.input.items.len) break;
|
||||
const next = this.input.items[this.input.items.len - this.cursor_offset - 1];
|
||||
if (next != ' ') non_whitespace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (key.eql(.{ .cp = 'f', .mod = .{ .alt = true } }) or key.eql(.{ .cp = zterm.input.Right, .mod = .{ .ctrl = true } }) or key.eql(.{ .cp = zterm.input.KpRight, .mod = .{ .ctrl = true } })) {
|
||||
var non_whitespace = false;
|
||||
while (this.cursor_offset > 0) {
|
||||
if (non_whitespace and this.input.items[this.input.items.len - this.cursor_offset - 1] == ' ') {
|
||||
this.cursor_offset += 1; // correct cursor position back again to make sure the cursor is not on the whitespace, but at the end of the jumped word
|
||||
break;
|
||||
}
|
||||
|
||||
// see backspace
|
||||
this.cursor_offset -= 1;
|
||||
const next = this.input.items[this.input.items.len - this.cursor_offset - 1];
|
||||
if (next != ' ') non_whitespace = true;
|
||||
}
|
||||
}
|
||||
|
||||
// usual input keys
|
||||
if (key.isAscii()) try this.input.insert(this.input.items.len - this.cursor_offset, key.cp);
|
||||
|
||||
if (key.eql(.{ .cp = zterm.input.Backspace })) {
|
||||
if (this.cursor_offset < this.input.items.len) {
|
||||
_ = if (this.cursor_offset == 0) this.input.pop() else this.input.orderedRemove(this.input.items.len - this.cursor_offset - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (key.eql(.{ .cp = zterm.input.Delete }) or key.eql(.{ .cp = zterm.input.KpDelete })) {
|
||||
if (this.cursor_offset > 0) {
|
||||
_ = this.input.orderedRemove(this.input.items.len - this.cursor_offset);
|
||||
this.cursor_offset -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO enter to accept?
|
||||
// - shift+enter is not recognized by the input reader of `zterm`, so currently it is not possible to add newlines into the text box?
|
||||
if (key.eql(.{ .cp = zterm.input.Enter }) or key.eql(.{ .cp = zterm.input.KpEnter })) {
|
||||
this.queue.push(.{ .accept = try this.input.toOwnedSlice() });
|
||||
this.cursor_offset = 0;
|
||||
@@ -191,7 +225,9 @@ pub fn main() !void {
|
||||
var renderer = zterm.Renderer.Buffered.init(allocator);
|
||||
defer renderer.deinit();
|
||||
|
||||
var input_field: InputField = .init(allocator, &app.queue);
|
||||
var input_field: InputField = .init(allocator, &app.queue, .{
|
||||
.color = .black,
|
||||
});
|
||||
defer input_field.deinit();
|
||||
|
||||
var mouse_draw: MouseDraw = .{};
|
||||
@@ -284,6 +320,8 @@ const log = std.log.scoped(.default);
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const zterm = @import("zterm");
|
||||
const Color = zterm.Color;
|
||||
|
||||
const App = zterm.App(union(enum) {
|
||||
accept: []u21,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user