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("", options, writer), .escape => std.fmt.formatBuf("", options, writer), .space => std.fmt.formatBuf("", options, writer), .backspace => std.fmt.formatBuf("", options, writer), .max_char => key.formatGeneric(options, writer), .meta_nil, .meta_max_char => key.formatGeneric(options, writer), .left => std.fmt.formatBuf("", options, writer), .right => std.fmt.formatBuf("", options, writer), .up => std.fmt.formatBuf("", options, writer), .down => std.fmt.formatBuf("", options, writer), .delete => std.fmt.formatBuf("", options, writer), .home => std.fmt.formatBuf("", options, writer), .end => std.fmt.formatBuf("", options, writer), .page_up => std.fmt.formatBuf("", options, writer), .page_down => std.fmt.formatBuf("", 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 , 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; } } };