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