summaryrefslogtreecommitdiff
path: root/src/key.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/key.zig')
-rw-r--r--src/key.zig102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/key.zig b/src/key.zig
new file mode 100644
index 0000000..1a68ebb
--- /dev/null
+++ b/src/key.zig
@@ -0,0 +1,102 @@
1const std = @import("std");
2
3pub const Key = enum(u16) {
4 return_ = 0x0d,
5 escape = 0x1b,
6 space = 0x20,
7 backspace = 0x7f,
8 max_char = 0xff,
9
10 meta_nil = 0x100,
11 meta_max_char = 0x1ff,
12
13 left,
14 right,
15 up,
16 down,
17 delete,
18 home,
19 end,
20 page_up,
21 page_down,
22
23 _,
24
25 pub fn char(ch: u8) Key {
26 return @intToEnum(Key, ch);
27 }
28
29 pub fn ctrl(ch: u8) Key {
30 return @intToEnum(Key, ch & 0x1f);
31 }
32
33 pub fn format(
34 key: Key,
35 comptime fmt: []const u8,
36 options: std.fmt.FormatOptions,
37 writer: anytype,
38 ) @TypeOf(writer).Error!void {
39 comptime if (fmt.len != 0) {
40 @compileError("Key doesn't support {" ++ fmt ++ "} format");
41 };
42
43 return switch (key) {
44 .return_ => std.fmt.formatBuf("<return>", options, writer),
45 .escape => std.fmt.formatBuf("<escape>", options, writer),
46 .space => std.fmt.formatBuf("<space>", options, writer),
47 .backspace => std.fmt.formatBuf("<backspace>", options, writer),
48 .max_char => key.formatGeneric(options, writer),
49
50 .meta_nil, .meta_max_char => key.formatGeneric(options, writer),
51
52 .left => std.fmt.formatBuf("<left>", options, writer),
53 .right => std.fmt.formatBuf("<right>", options, writer),
54 .up => std.fmt.formatBuf("<up>", options, writer),
55 .down => std.fmt.formatBuf("<down>", options, writer),
56 .delete => std.fmt.formatBuf("<delete>", options, writer),
57 .home => std.fmt.formatBuf("<home>", options, writer),
58 .end => std.fmt.formatBuf("<end>", options, writer),
59 .page_up => std.fmt.formatBuf("<page-up>", options, writer),
60 .page_down => std.fmt.formatBuf("<page-down>", options, writer),
61
62 _ => key.formatGeneric(options, writer),
63 };
64 }
65
66 pub fn meta(ch: u8) Key {
67 return @intToEnum(Key, ch + @enumToInt(Key.meta_nil));
68 }
69
70 pub fn metaCtrl(ch: u8) Key {
71 return @intToEnum(Key, (ch & 0x1f) + @enumToInt(Key.meta_nil));
72 }
73
74 fn formatGeneric(
75 key: Key,
76 options: std.fmt.FormatOptions,
77 writer: anytype,
78 ) @TypeOf(writer).Error!void {
79 const key_int = @enumToInt(key);
80 if (key_int < @enumToInt(Key.space)) {
81 const ch = std.ascii.toLower(@intCast(u8, key_int + 0x40));
82 const buf = [_]u8{'C', '-', ch};
83 return std.fmt.formatBuf(&buf, options, writer);
84 } else if (key_int < @enumToInt(Key.meta_nil)) {
85 const buf = [_]u8{@intCast(u8, key_int)};
86 // This should be printed as C-? or <backspace>, it's dealt with in
87 // format()
88 std.debug.assert(buf[0] != '\x7F');
89 return std.fmt.formatBuf(&buf, options, writer);
90 } else if (key_int <= @enumToInt(Key.meta_max_char)) {
91 try std.fmt.formatBuf("M-", options, writer);
92 return Key.format(
93 @intToEnum(Key, key_int - @enumToInt(Key.meta_nil)),
94 "",
95 options,
96 writer,
97 );
98 } else {
99 unreachable;
100 }
101 }
102};