summaryrefslogtreecommitdiff
path: root/src/KeyMap.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/KeyMap.zig')
-rw-r--r--src/KeyMap.zig64
1 files changed, 38 insertions, 26 deletions
diff --git a/src/KeyMap.zig b/src/KeyMap.zig
index e200faa..8df4c06 100644
--- a/src/KeyMap.zig
+++ b/src/KeyMap.zig
@@ -25,6 +25,7 @@ pub const Error = error{
25 std.os.RealPathError; 25 std.os.RealPathError;
26 26
27pub const BoundFn = fn (*Editor, *Buffer, Key) Error!void; 27pub const BoundFn = fn (*Editor, *Buffer, Key) Error!void;
28pub const BoundFnPtr = *const BoundFn;
28 29
29const Context = struct { 30const Context = struct {
30 pub fn hash(self: Context, key: []const Key) u64 { 31 pub fn hash(self: Context, key: []const Key) u64 {
@@ -65,13 +66,13 @@ const Keys = struct {
65const RawMap = HashMap([]const Key, Value, Context, std.hash_map.default_max_load_percentage); 66const RawMap = HashMap([]const Key, Value, Context, std.hash_map.default_max_load_percentage);
66 67
67const Value = union(enum) { 68const Value = union(enum) {
68 bound_fn: BoundFn, 69 bound_fn: BoundFnPtr,
69 chord: void, 70 chord: void,
70}; 71};
71 72
72allocator: Allocator, 73allocator: Allocator,
73current_chord: ArrayList(Key), 74current_chord: ArrayList(Key),
74default: ?BoundFn, 75default: ?BoundFnPtr,
75raw_map: RawMap, 76raw_map: RawMap,
76 77
77pub fn init(allocator: Allocator) KeyMap { 78pub fn init(allocator: Allocator) KeyMap {
@@ -90,22 +91,22 @@ pub fn defaultMap(allocator: Allocator) !KeyMap {
90 map.default = wrapFn(defaultFn); 91 map.default = wrapFn(defaultFn);
91 92
92 // M-g <*> 93 // M-g <*>
93 try map.bind(&.{Key.meta('g'), Key.char('g')}, Buffer.goToLine); 94 try map.bind(&.{ Key.meta('g'), Key.char('g') }, Buffer.goToLine);
94 95
95 // M-O <*> 96 // M-O <*>
96 try map.bind(&.{Key.meta('O'), Key.char('F')}, Buffer.moveEndOfLine); 97 try map.bind(&.{ Key.meta('O'), Key.char('F') }, Buffer.moveEndOfLine);
97 try map.bind(&.{Key.meta('O'), Key.char('H')}, Buffer.moveBeginningOfLine); 98 try map.bind(&.{ Key.meta('O'), Key.char('H') }, Buffer.moveBeginningOfLine);
98 99
99 // C-x C-<*> 100 // C-x C-<*>
100 try map.bind(&.{Key.ctrl('x'), Key.ctrl('b')}, Editor.switchBuffer); 101 try map.bind(&.{ Key.ctrl('x'), Key.ctrl('b') }, Editor.switchBuffer);
101 try map.bind(&.{Key.ctrl('x'), Key.ctrl('c')}, Editor.saveBuffersExit); 102 try map.bind(&.{ Key.ctrl('x'), Key.ctrl('c') }, Editor.saveBuffersExit);
102 try map.bind(&.{Key.ctrl('x'), Key.ctrl('f')}, Editor.openFile); 103 try map.bind(&.{ Key.ctrl('x'), Key.ctrl('f') }, Editor.openFile);
103 try map.bind(&.{Key.ctrl('x'), Key.ctrl('s')}, Buffer.save); 104 try map.bind(&.{ Key.ctrl('x'), Key.ctrl('s') }, Buffer.save);
104 105
105 // C-x <*> 106 // C-x <*>
106 try map.bind(&.{Key.ctrl('x'), Key.char('b')}, Editor.switchBuffer); 107 try map.bind(&.{ Key.ctrl('x'), Key.char('b') }, Editor.switchBuffer);
107 // TODO: C-x h for help 108 // TODO: C-x h for help
108 try map.bind(&.{Key.ctrl('x'), Key.char('k')}, Editor.killCurrentBuffer); 109 try map.bind(&.{ Key.ctrl('x'), Key.char('k') }, Editor.killCurrentBuffer);
109 110
110 // M-C-<*> 111 // M-C-<*>
111 try map.bind(&.{Key.meta(Key.ctrl('d'))}, Buffer.backwardDeleteChar); 112 try map.bind(&.{Key.meta(Key.ctrl('d'))}, Buffer.backwardDeleteChar);
@@ -166,7 +167,7 @@ pub fn bind(self: *KeyMap, keys: []const Key, comptime f: anytype) !void {
166 std.debug.assert(keys.len > 0); 167 std.debug.assert(keys.len > 0);
167 var idx: usize = 0; 168 var idx: usize = 0;
168 while (idx < keys.len - 1) : (idx += 1) { 169 while (idx < keys.len - 1) : (idx += 1) {
169 const subseq = try self.allocator.dupe(Key, keys[0..idx + 1]); 170 const subseq = try self.allocator.dupe(Key, keys[0 .. idx + 1]);
170 errdefer self.allocator.free(subseq); 171 errdefer self.allocator.free(subseq);
171 172
172 const gop = try self.raw_map.getOrPut(subseq); 173 const gop = try self.raw_map.getOrPut(subseq);
@@ -204,7 +205,7 @@ pub fn bind(self: *KeyMap, keys: []const Key, comptime f: anytype) !void {
204 const keys_wrap = Keys{ .keys = keys }; 205 const keys_wrap = Keys{ .keys = keys };
205 std.log.err( 206 std.log.err(
206 "Attempting to bind a shorter chord ({}) over longer one(s)", 207 "Attempting to bind a shorter chord ({}) over longer one(s)",
207 .{ keys_wrap }, 208 .{keys_wrap},
208 ); 209 );
209 return error.KeyBindError; 210 return error.KeyBindError;
210 }, 211 },
@@ -239,9 +240,9 @@ pub fn keypress(self: *KeyMap, editor: *Editor, buf: *Buffer, key: Key) !void {
239} 240}
240 241
241fn defaultFn(editor: *Editor, buffer: *Buffer, key: Key) !void { 242fn defaultFn(editor: *Editor, buffer: *Buffer, key: Key) !void {
242 if (@enumToInt(key) <= @enumToInt(Key.max_char)) { 243 if (@intFromEnum(key) <= @intFromEnum(Key.max_char)) {
243 const char = @intCast(u8, @enumToInt(key)); 244 const char: u8 = @intCast(@intFromEnum(key));
244 if (std.ascii.isGraph(char) or char == ' ') { 245 if (std.ascii.isPrint(char)) {
245 try buffer.insertChar(char); 246 try buffer.insertChar(char);
246 return; 247 return;
247 } 248 }
@@ -251,6 +252,17 @@ fn defaultFn(editor: *Editor, buffer: *Buffer, key: Key) !void {
251 try editor.setStatusMessage("Unknown key: {}", .{key}); 252 try editor.setStatusMessage("Unknown key: {}", .{key});
252} 253}
253 254
255// I think there's a bug in Zig's std.mem.eql
256fn typeEql(comptime a: []const type, comptime b: []const type) bool {
257 if (a.len != b.len) return false;
258 if (a.len == 0 or a.ptr == b.ptr) return true;
259
260 for (a, b) |a_elem, b_elem| {
261 if (a_elem != b_elem) return false;
262 }
263 return true;
264}
265
254fn wrapFn(comptime f: anytype) BoundFn { 266fn wrapFn(comptime f: anytype) BoundFn {
255 comptime { 267 comptime {
256 if (@TypeOf(f) == BoundFn) { 268 if (@TypeOf(f) == BoundFn) {
@@ -260,13 +272,13 @@ fn wrapFn(comptime f: anytype) BoundFn {
260 const fn_info = @typeInfo(@TypeOf(f)).Fn; 272 const fn_info = @typeInfo(@TypeOf(f)).Fn;
261 const should_try = if (fn_info.return_type) |return_type| @typeInfo(return_type) == .ErrorUnion else false; 273 const should_try = if (fn_info.return_type) |return_type| @typeInfo(return_type) == .ErrorUnion else false;
262 274
263 const args_info = fn_info.args; 275 const params_info = fn_info.params;
264 var args = [_]type { undefined } ** args_info.len; 276 var params = [_]type{undefined} ** params_info.len;
265 for (args_info) |arg_info, idx| { 277 for (params_info, 0..) |param_info, idx| {
266 args[idx] = arg_info.arg_type.?; 278 params[idx] = param_info.type.?;
267 } 279 }
268 280
269 if (std.mem.eql(type, &args, &.{*Buffer})) { 281 if (typeEql(&params, &.{*Buffer})) {
270 return struct { 282 return struct {
271 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void { 283 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void {
272 _ = e; 284 _ = e;
@@ -278,7 +290,7 @@ fn wrapFn(comptime f: anytype) BoundFn {
278 } 290 }
279 } 291 }
280 }.wf; 292 }.wf;
281 } else if (std.mem.eql(type, &args, &.{*Editor})) { 293 } else if (typeEql(&params, &.{*Editor})) {
282 return struct { 294 return struct {
283 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void { 295 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void {
284 _ = b; 296 _ = b;
@@ -290,7 +302,7 @@ fn wrapFn(comptime f: anytype) BoundFn {
290 } 302 }
291 } 303 }
292 }.wf; 304 }.wf;
293 } else if (std.mem.eql(type, &args, &.{*Editor, *Buffer})) { 305 } else if (typeEql(&params, &.{ *Editor, *Buffer })) {
294 return struct { 306 return struct {
295 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void { 307 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void {
296 _ = k; 308 _ = k;
@@ -301,7 +313,7 @@ fn wrapFn(comptime f: anytype) BoundFn {
301 } 313 }
302 } 314 }
303 }.wf; 315 }.wf;
304 } else if (std.mem.eql(type, &args, &.{*Buffer, *Editor})) { 316 } else if (typeEql(&params, &.{ *Buffer, *Editor })) {
305 return struct { 317 return struct {
306 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void { 318 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void {
307 _ = k; 319 _ = k;
@@ -312,7 +324,7 @@ fn wrapFn(comptime f: anytype) BoundFn {
312 } 324 }
313 } 325 }
314 }.wf; 326 }.wf;
315 } else if (std.mem.eql(type, &args, &.{*Buffer, Editor})) { 327 } else if (typeEql(&params, &.{ *Buffer, Editor })) {
316 return struct { 328 return struct {
317 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void { 329 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void {
318 _ = k; 330 _ = k;
@@ -323,7 +335,7 @@ fn wrapFn(comptime f: anytype) BoundFn {
323 } 335 }
324 } 336 }
325 }.wf; 337 }.wf;
326 } else if (std.mem.eql(type, &args, &.{*Editor, *Buffer, Key})) { 338 } else if (typeEql(&params, &.{ *Editor, *Buffer, Key })) {
327 return struct { 339 return struct {
328 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void { 340 pub fn wf(e: *Editor, b: *Buffer, k: Key) Error!void {
329 if (should_try) { 341 if (should_try) {