diff options
| author | 2024-02-19 23:38:33 +0200 | |
|---|---|---|
| committer | 2024-02-19 23:38:33 +0200 | |
| commit | d5d5f7f06397d73f497d352f2f38b1a53d932b0d (patch) | |
| tree | 63e34f5f945f4ecf28f844ee02a5a0b7fc581459 /src/KeyMap.zig | |
| parent | Create parent directory if doesn't exist on save (diff) | |
| download | es-d5d5f7f06397d73f497d352f2f38b1a53d932b0d.tar.gz es-d5d5f7f06397d73f497d352f2f38b1a53d932b0d.tar.xz es-d5d5f7f06397d73f497d352f2f38b1a53d932b0d.zip | |
Big update to modern zig
Diffstat (limited to 'src/KeyMap.zig')
| -rw-r--r-- | src/KeyMap.zig | 64 |
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 | ||
| 27 | pub const BoundFn = fn (*Editor, *Buffer, Key) Error!void; | 27 | pub const BoundFn = fn (*Editor, *Buffer, Key) Error!void; |
| 28 | pub const BoundFnPtr = *const BoundFn; | ||
| 28 | 29 | ||
| 29 | const Context = struct { | 30 | const 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 { | |||
| 65 | const RawMap = HashMap([]const Key, Value, Context, std.hash_map.default_max_load_percentage); | 66 | const RawMap = HashMap([]const Key, Value, Context, std.hash_map.default_max_load_percentage); |
| 66 | 67 | ||
| 67 | const Value = union(enum) { | 68 | const Value = union(enum) { |
| 68 | bound_fn: BoundFn, | 69 | bound_fn: BoundFnPtr, |
| 69 | chord: void, | 70 | chord: void, |
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 72 | allocator: Allocator, | 73 | allocator: Allocator, |
| 73 | current_chord: ArrayList(Key), | 74 | current_chord: ArrayList(Key), |
| 74 | default: ?BoundFn, | 75 | default: ?BoundFnPtr, |
| 75 | raw_map: RawMap, | 76 | raw_map: RawMap, |
| 76 | 77 | ||
| 77 | pub fn init(allocator: Allocator) KeyMap { | 78 | pub 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 | ||
| 241 | fn defaultFn(editor: *Editor, buffer: *Buffer, key: Key) !void { | 242 | fn 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 | ||
| 256 | fn 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 | |||
| 254 | fn wrapFn(comptime f: anytype) BoundFn { | 266 | fn 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(¶ms, &.{*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(¶ms, &.{*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(¶ms, &.{ *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(¶ms, &.{ *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(¶ms, &.{ *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(¶ms, &.{ *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) { |