summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2024-02-19 23:38:33 +0200
committerGravatar Uko Kokņevičs2024-02-19 23:38:33 +0200
commitd5d5f7f06397d73f497d352f2f38b1a53d932b0d (patch)
tree63e34f5f945f4ecf28f844ee02a5a0b7fc581459
parentCreate parent directory if doesn't exist on save (diff)
downloades-d5d5f7f06397d73f497d352f2f38b1a53d932b0d.tar.gz
es-d5d5f7f06397d73f497d352f2f38b1a53d932b0d.tar.xz
es-d5d5f7f06397d73f497d352f2f38b1a53d932b0d.zip
Big update to modern zig
Diffstat (limited to '')
-rw-r--r--build.zig38
-rw-r--r--src/Buffer.zig27
-rw-r--r--src/Config.zig6
-rw-r--r--src/Editor.zig42
-rw-r--r--src/KeyMap.zig64
-rw-r--r--src/KeyReader.zig16
-rw-r--r--src/RawMode.zig16
-rw-r--r--src/Row.zig22
-rw-r--r--src/Syntax.zig12
-rw-r--r--src/c.zig5
-rw-r--r--src/key.zig51
-rw-r--r--src/main.zig10
12 files changed, 162 insertions, 147 deletions
diff --git a/build.zig b/build.zig
index d65020a..429dc5b 100644
--- a/build.zig
+++ b/build.zig
@@ -1,11 +1,12 @@
1const std = @import("std"); 1const std = @import("std");
2 2
3const Builder = std.build.Builder; 3const Builder = std.Build;
4const SemanticVersion = std.SemanticVersion; 4const SemanticVersion = std.SemanticVersion;
5 5
6const share_prefix = "share/arkta/es/"; 6const share_prefix = "share/arkta/es/";
7 7
8const version = "0.3.0"; 8const version = "0.3.0";
9const semver = SemanticVersion.parse(version) catch unreachable;
9 10
10const config = struct { 11const config = struct {
11 template: []const u8 = @embedFile("es.ini.in"), 12 template: []const u8 = @embedFile("es.ini.in"),
@@ -18,37 +19,34 @@ const config = struct {
18}{}; 19}{};
19 20
20fn installGeneratedFile(b: *Builder, comptime name: []const u8, data: []const u8) void { 21fn installGeneratedFile(b: *Builder, comptime name: []const u8, data: []const u8) void {
21 const write_file = b.addWriteFile(name, data); 22 const write_files = b.addWriteFiles();
22 23 const write_file = write_files.add(name, data);
23 const write_file_install = b.addInstallFile( 24 const write_file_install = b.addInstallFile(write_file, share_prefix ++ name);
24 write_file.getFileSource(name).?, 25 write_file_install.step.dependOn(&write_files.step);
25 share_prefix ++ name,
26 );
27 write_file_install.step.dependOn(&write_file.step);
28 26
29 b.getInstallStep().dependOn(&write_file_install.step); 27 b.getInstallStep().dependOn(&write_file_install.step);
30} 28}
31 29
32pub fn build(b: *Builder) void { 30pub fn build(b: *Builder) void {
33 const target = b.standardTargetOptions(.{}); 31 const target = b.standardTargetOptions(.{});
34 const mode = b.standardReleaseOptions(); 32 const optimize = b.standardOptimizeOption(.{});
35 33
36 const options = b.addOptions(); 34 const options = b.addOptions();
37 options.addOption( 35 options.addOption(SemanticVersion, "es_version", semver);
38 SemanticVersion,
39 "es_version",
40 SemanticVersion.parse(version) catch unreachable,
41 );
42 options.addOption(bool, "default_hard_tabs", config.default.hard_tabs); 36 options.addOption(bool, "default_hard_tabs", config.default.hard_tabs);
43 options.addOption(usize, "default_line_limit", config.default.line_limit); 37 options.addOption(usize, "default_line_limit", config.default.line_limit);
44 options.addOption(usize, "default_page_overlap", config.default.page_overlap); 38 options.addOption(usize, "default_page_overlap", config.default.page_overlap);
45 options.addOption(usize, "default_tab_stop", config.default.tab_stop); 39 options.addOption(usize, "default_tab_stop", config.default.tab_stop);
46 40
47 const exe = b.addExecutable("es", "src/main.zig"); 41 const exe = b.addExecutable(.{
48 exe.setTarget(target); 42 .name = "es",
49 exe.setBuildMode(mode); 43 .version = semver,
50 exe.addOptions("es-config", options); 44 .root_source_file = .{ .path = "src/main.zig" },
51 exe.install(); 45 .target = target,
46 .optimize = optimize,
47 });
48 exe.root_module.addOptions("es-config", options);
49 b.installArtifact(exe);
52 50
53 installGeneratedFile( 51 installGeneratedFile(
54 b, 52 b,
@@ -56,7 +54,7 @@ pub fn build(b: *Builder) void {
56 comptime std.fmt.comptimePrint(config.template, config.default), 54 comptime std.fmt.comptimePrint(config.template, config.default),
57 ); 55 );
58 56
59 const run_cmd = exe.run(); 57 const run_cmd = b.addRunArtifact(exe);
60 run_cmd.step.dependOn(b.getInstallStep()); 58 run_cmd.step.dependOn(b.getInstallStep());
61 if (b.args) |args| { 59 if (b.args) |args| {
62 run_cmd.addArgs(args); 60 run_cmd.addArgs(args);
diff --git a/src/Buffer.zig b/src/Buffer.zig
index 8917772..473674c 100644
--- a/src/Buffer.zig
+++ b/src/Buffer.zig
@@ -31,11 +31,11 @@ config: Config,
31syntax: ?Syntax, 31syntax: ?Syntax,
32 32
33pub fn init(allocator: Allocator, name: []const u8) !Buffer { 33pub fn init(allocator: Allocator, name: []const u8) !Buffer {
34 var name_owned = try allocator.dupe(u8, name); 34 const name_owned = try allocator.dupe(u8, name);
35 errdefer allocator.free(name_owned); 35 errdefer allocator.free(name_owned);
36 36
37 // TODO: buffer-specific config support 37 // TODO: buffer-specific config support
38 var config = try Config.readConfig(allocator); 38 const config = try Config.readConfig(allocator);
39 39
40 return Buffer{ 40 return Buffer{
41 .allocator = allocator, 41 .allocator = allocator,
@@ -156,7 +156,7 @@ pub fn deleteRow(self: *Buffer, at: usize) void {
156 if (self.cy == self.rows.items.len) { 156 if (self.cy == self.rows.items.len) {
157 self.cx = 0; 157 self.cx = 0;
158 } else { 158 } else {
159 self.cx = std.math.min(self.cx, self.rows.items[self.cy].data.items.len); 159 self.cx = @min(self.cx, self.rows.items[self.cy].data.items.len);
160 } 160 }
161} 161}
162 162
@@ -184,7 +184,7 @@ pub fn drawRows(self: Buffer, writer: anytype, screenrows: usize, screencols: us
184 } 184 }
185 185
186 const char = row.rdata.items[rx]; 186 const char = row.rdata.items[rx];
187 if (std.ascii.isCntrl(char)) { 187 if (std.ascii.isControl(char)) {
188 const sym = [_]u8{if (char <= 26) char + '@' else '?'}; 188 const sym = [_]u8{if (char <= 26) char + '@' else '?'};
189 try writer.print("\x1b[7m{s}\x1b[m", .{&sym}); 189 try writer.print("\x1b[7m{s}\x1b[m", .{&sym});
190 last_hl = Highlight.none; 190 last_hl = Highlight.none;
@@ -225,7 +225,7 @@ pub fn drawRows(self: Buffer, writer: anytype, screenrows: usize, screencols: us
225pub fn drawStatusBar(self: Buffer, writer: anytype, screencols: usize) !void { 225pub fn drawStatusBar(self: Buffer, writer: anytype, screencols: usize) !void {
226 try writer.writeAll("\x1b[m\x1b[7m"); 226 try writer.writeAll("\x1b[m\x1b[7m");
227 227
228 var name = if (self.short_name.len > 20) 228 const name = if (self.short_name.len > 20)
229 try std.fmt.allocPrint( 229 try std.fmt.allocPrint(
230 self.allocator, 230 self.allocator,
231 "...{s}", 231 "...{s}",
@@ -250,8 +250,8 @@ pub fn drawStatusBar(self: Buffer, writer: anytype, screencols: usize) !void {
250 }); 250 });
251 defer self.allocator.free(rbuf); 251 defer self.allocator.free(rbuf);
252 252
253 var rlen = if (rbuf.len > screencols) screencols else rbuf.len; 253 const rlen = if (rbuf.len > screencols) screencols else rbuf.len;
254 var llen = if (lbuf.len > screencols - rlen) screencols - rlen else lbuf.len; 254 const llen = if (lbuf.len > screencols - rlen) screencols - rlen else lbuf.len;
255 255
256 try writer.writeAll(lbuf[0..llen]); 256 try writer.writeAll(lbuf[0..llen]);
257 try writer.writeByteNTimes(' ', screencols - llen - rlen); 257 try writer.writeByteNTimes(' ', screencols - llen - rlen);
@@ -286,7 +286,7 @@ pub fn goToLine(self: *Buffer, editor: *Editor) !void {
286 if (self.cy == self.rows.items.len) { 286 if (self.cy == self.rows.items.len) {
287 self.cx = 0; 287 self.cx = 0;
288 } else { 288 } else {
289 self.cx = std.math.min(self.cx, self.rows.items[self.cy].data.items.len); 289 self.cx = @min(self.cx, self.rows.items[self.cy].data.items.len);
290 } 290 }
291 } 291 }
292} 292}
@@ -409,7 +409,7 @@ pub fn pageDown(self: *Buffer, editor: Editor) void {
409 409
410pub fn pageUp(self: *Buffer, editor: Editor) void { 410pub fn pageUp(self: *Buffer, editor: Editor) void {
411 const screenrows = editor.screenrows; 411 const screenrows = editor.screenrows;
412 self.cy = std.math.min(self.rows.items.len, self.rowoff + self.config.page_overlap); 412 self.cy = @min(self.rows.items.len, self.rowoff + self.config.page_overlap);
413 var i: usize = 0; 413 var i: usize = 0;
414 while (i < screenrows) : (i += 1) { 414 while (i < screenrows) : (i += 1) {
415 self.previousLine(); 415 self.previousLine();
@@ -439,7 +439,9 @@ pub fn recenterTopBottom(self: *Buffer, editor: *Editor) !void {
439 439
440pub fn save(self: *Buffer, editor: *Editor) !void { 440pub fn save(self: *Buffer, editor: *Editor) !void {
441 if (self.file_path == null) { 441 if (self.file_path == null) {
442 const fname = (try editor.prompt(self.allocator, "Save as")) orelse { return; }; 442 const fname = (try editor.prompt(self.allocator, "Save as")) orelse {
443 return;
444 };
443 defer self.allocator.free(fname); 445 defer self.allocator.free(fname);
444 446
445 const file_path = try es.files.resolvePath(self.allocator, fname); 447 const file_path = try es.files.resolvePath(self.allocator, fname);
@@ -463,7 +465,8 @@ pub fn save(self: *Buffer, editor: *Editor) !void {
463 const file_path = self.file_path.?; 465 const file_path = self.file_path.?;
464 466
465 if (std.fs.path.dirname(file_path)) |dirname| { 467 if (std.fs.path.dirname(file_path)) |dirname| {
466 if (std.fs.openDirAbsolute(dirname, .{})) |*dir| { 468 var res_dir = std.fs.openDirAbsolute(dirname, .{});
469 if (res_dir) |*dir| {
467 dir.close(); 470 dir.close();
468 } else |_| { 471 } else |_| {
469 const prompt = try std.fmt.allocPrint( 472 const prompt = try std.fmt.allocPrint(
@@ -597,7 +600,7 @@ fn printWithLeftPadding(
597 padding: u8, 600 padding: u8,
598 args: anytype, 601 args: anytype,
599) !void { 602) !void {
600 var unpadded = try std.fmt.allocPrint(allocator, fmt, args); 603 const unpadded = try std.fmt.allocPrint(allocator, fmt, args);
601 defer allocator.free(unpadded); 604 defer allocator.free(unpadded);
602 605
603 std.debug.assert(unpadded.len <= width); 606 std.debug.assert(unpadded.len <= width);
diff --git a/src/Config.zig b/src/Config.zig
index ea11e5c..47e61a0 100644
--- a/src/Config.zig
+++ b/src/Config.zig
@@ -68,7 +68,7 @@ fn readConfigInBaseDir(allocator: Allocator, config: *Config, base_dir: []const
68 while (try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096)) |line_buf| { 68 while (try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096)) |line_buf| {
69 defer allocator.free(line_buf); 69 defer allocator.free(line_buf);
70 70
71 var line = std.mem.trim(u8, line_buf, &std.ascii.spaces); 71 var line = std.mem.trim(u8, line_buf, &std.ascii.whitespace);
72 if (line.len == 0 or line[0] == '#') { 72 if (line.len == 0 or line[0] == '#') {
73 continue; 73 continue;
74 } 74 }
@@ -77,8 +77,8 @@ fn readConfigInBaseDir(allocator: Allocator, config: *Config, base_dir: []const
77 return error.MalformedConfig; 77 return error.MalformedConfig;
78 }; 78 };
79 79
80 const key = std.mem.trimRight(u8, line[0..split], &std.ascii.spaces); 80 const key = std.mem.trimRight(u8, line[0..split], &std.ascii.whitespace);
81 const value = std.mem.trimLeft(u8, line[(split + 1)..], &std.ascii.spaces); 81 const value = std.mem.trimLeft(u8, line[(split + 1)..], &std.ascii.whitespace);
82 if (std.mem.eql(u8, key, "hard-tabs")) { 82 if (std.mem.eql(u8, key, "hard-tabs")) {
83 config.hard_tabs = try parseBool(value); 83 config.hard_tabs = try parseBool(value);
84 } else if (std.mem.eql(u8, key, "line-limit")) { 84 } else if (std.mem.eql(u8, key, "line-limit")) {
diff --git a/src/Editor.zig b/src/Editor.zig
index 7e56783..aa57c15 100644
--- a/src/Editor.zig
+++ b/src/Editor.zig
@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
5const ArrayList = std.ArrayList; 5const ArrayList = std.ArrayList;
6const Buffer = es.Buffer; 6const Buffer = es.Buffer;
7const Editor = @This(); 7const Editor = @This();
8const File = std.fs.File;
8const Key = es.Key; 9const Key = es.Key;
9const KeyMap = es.KeyMap; 10const KeyMap = es.KeyMap;
10const KeyReader = es.KeyReader; 11const KeyReader = es.KeyReader;
@@ -144,7 +145,8 @@ pub fn killCurrentBuffer(self: *Editor) !bool {
144 self.allocator.free(entry_to_kill.key); 145 self.allocator.free(entry_to_kill.key);
145 entry_to_kill.value.deinit(); 146 entry_to_kill.value.deinit();
146 147
147 if (self.buffers.valueIterator().next()) |buffer| { 148 var it = self.buffers.valueIterator();
149 if (it.next()) |buffer| {
148 self.buffer = buffer; 150 self.buffer = buffer;
149 } else { 151 } else {
150 self.buffer = try self.putBuffer("*scratch*"); 152 self.buffer = try self.putBuffer("*scratch*");
@@ -245,11 +247,11 @@ pub fn promptEx(
245 try cb(self, buf.items, key, cb_data); 247 try cb(self, buf.items, key, cb_data);
246 } 248 }
247 249
248 return buf.toOwnedSlice(); 250 return try buf.toOwnedSlice();
249 }, 251 },
250 else => if (@enumToInt(key) < @enumToInt(Key.max_char)) { 252 else => if (@intFromEnum(key) < @intFromEnum(Key.max_char)) {
251 const key_char = @intCast(u8, @enumToInt(key)); 253 const key_char: u8 = @intCast(@intFromEnum(key));
252 if (std.ascii.isSpace(key_char) or std.ascii.isGraph(key_char)) { 254 if (std.ascii.isWhitespace(key_char) or std.ascii.isPrint(key_char)) {
253 try buf.append(key_char); 255 try buf.append(key_char);
254 } 256 }
255 }, // TODO: else ?? 257 }, // TODO: else ??
@@ -272,15 +274,7 @@ pub fn promptYN(self: *Editor, prompt_str: []const u8) !bool {
272 var response = try self.prompt(self.allocator, full_prompt); 274 var response = try self.prompt(self.allocator, full_prompt);
273 defer if (response) |str| self.allocator.free(str); 275 defer if (response) |str| self.allocator.free(str);
274 // TODO: This can be improved 276 // TODO: This can be improved
275 while (response != null 277 while (response != null and (response.?.len == 0 or (response.?[0] != 'y' and response.?[0] != 'Y' and response.?[0] != 'n' and response.?[0] != 'N'))) {
276 and (response.?.len == 0
277 or (response.?[0] != 'y'
278 and response.?[0] != 'Y'
279 and response.?[0] != 'n'
280 and response.?[0] != 'N'
281 )
282 )
283 ) {
284 if (response) |str| self.allocator.free(str); 278 if (response) |str| self.allocator.free(str);
285 response = try self.prompt(self.allocator, full_prompt); 279 response = try self.prompt(self.allocator, full_prompt);
286 } 280 }
@@ -352,7 +346,7 @@ pub fn saveBuffersExit(self: *Editor) !void {
352 346
353pub fn setStatusMessage(self: *Editor, comptime fmt: []const u8, args: anytype) !void { 347pub fn setStatusMessage(self: *Editor, comptime fmt: []const u8, args: anytype) !void {
354 // Get new resources 348 // Get new resources
355 var new_msg = try std.fmt.allocPrint(self.allocator, fmt, args); 349 const new_msg = try std.fmt.allocPrint(self.allocator, fmt, args);
356 errdefer self.allocator.free(new_msg); 350 errdefer self.allocator.free(new_msg);
357 351
358 // Get rid of old resources (no errors) 352 // Get rid of old resources (no errors)
@@ -387,11 +381,17 @@ fn drawMessageBar(self: Editor, writer: anytype) !void {
387 } 381 }
388 382
389 if (self.statusmsg.?.len != 0 and std.time.milliTimestamp() - self.statusmsg_time < 5 * std.time.ms_per_s) { 383 if (self.statusmsg.?.len != 0 and std.time.milliTimestamp() - self.statusmsg_time < 5 * std.time.ms_per_s) {
390 try writer.writeAll(self.statusmsg.?[0..(std.math.min(self.statusmsg.?.len, self.screencols))]); 384 try writer.writeAll(self.statusmsg.?[0..(@min(self.statusmsg.?.len, self.screencols))]);
391 } 385 }
392} 386}
393 387
394fn getCursorPosition(row: *usize, col: *usize) !void { 388// TODO[zigbug]: https://github.com/ziglang/zig/issues/18177
389// Replace with an inferred set
390const CursorPositionError = error{
391 MisformedTerminalResponse,
392} || File.WriteError;
393
394fn getCursorPosition(row: *usize, col: *usize) CursorPositionError!void {
395 const std_out = std.io.getStdOut(); 395 const std_out = std.io.getStdOut();
396 try std_out.writeAll("\x1b[6n\r\n"); 396 try std_out.writeAll("\x1b[6n\r\n");
397 397
@@ -400,7 +400,7 @@ fn getCursorPosition(row: *usize, col: *usize) !void {
400 var response = std_in.readUntilDelimiter(&buf, 'R') catch |err| switch (err) { 400 var response = std_in.readUntilDelimiter(&buf, 'R') catch |err| switch (err) {
401 error.EndOfStream => return error.MisformedTerminalResponse, 401 error.EndOfStream => return error.MisformedTerminalResponse,
402 error.StreamTooLong => return error.MisformedTerminalResponse, 402 error.StreamTooLong => return error.MisformedTerminalResponse,
403 else => return @errSetCast(std.os.ReadError, err), 403 else => return @as(CursorPositionError, @errorCast(err)),
404 }; 404 };
405 405
406 if (response.len < 2 or response[0] != '\x1b' or response[1] != '[') { 406 if (response.len < 2 or response[0] != '\x1b' or response[1] != '[') {
@@ -418,9 +418,9 @@ fn getCursorPosition(row: *usize, col: *usize) !void {
418} 418}
419 419
420fn getWindowSize(rows: *usize, cols: *usize) !void { 420fn getWindowSize(rows: *usize, cols: *usize) !void {
421 var ws: std.os.linux.winsize = undefined; 421 var ws: std.os.system.winsize = undefined;
422 const rc = std.os.linux.ioctl(std.os.STDIN_FILENO, std.os.linux.T.IOCGWINSZ, @ptrToInt(&ws)); 422 const rc = std.os.system.ioctl(std.os.STDIN_FILENO, std.os.system.T.IOCGWINSZ, @intFromPtr(&ws));
423 switch (std.os.linux.getErrno(rc)) { 423 switch (std.os.system.getErrno(rc)) {
424 .SUCCESS => { 424 .SUCCESS => {
425 cols.* = ws.ws_col; 425 cols.* = ws.ws_col;
426 rows.* = ws.ws_row; 426 rows.* = ws.ws_row;
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) {
diff --git a/src/KeyReader.zig b/src/KeyReader.zig
index 2265975..28e6dcb 100644
--- a/src/KeyReader.zig
+++ b/src/KeyReader.zig
@@ -83,7 +83,7 @@ fn readByte(reader: File.Reader) Error!?u8 {
83 return reader.readByte() catch |err| switch (err) { 83 return reader.readByte() catch |err| switch (err) {
84 error.WouldBlock => null, 84 error.WouldBlock => null,
85 error.EndOfStream => null, 85 error.EndOfStream => null,
86 else => return @errSetCast(File.Reader.Error, err), 86 else => return @as(Error, @errorCast(err)),
87 }; 87 };
88} 88}
89 89
@@ -135,7 +135,7 @@ fn readControlSequence(self: *KeyReader, reader: File.Reader) !Key {
135 if (parameter_list.len == 0) { 135 if (parameter_list.len == 0) {
136 return key; 136 return key;
137 } else if (parameter_list.len == 1) { 137 } else if (parameter_list.len == 1) {
138 var count = std.math.max(1, parameter_list[0]) - 1; 138 var count = @max(1, parameter_list[0]) - 1;
139 try self.key_buf.ensureUnusedCapacity(count); 139 try self.key_buf.ensureUnusedCapacity(count);
140 while (count > 0) : (count -= 1) { 140 while (count > 0) : (count -= 1) {
141 self.key_buf.appendAssumeCapacity(key); 141 self.key_buf.appendAssumeCapacity(key);
@@ -143,7 +143,7 @@ fn readControlSequence(self: *KeyReader, reader: File.Reader) !Key {
143 143
144 return key; 144 return key;
145 } else if (parameter_list.len == 2) { 145 } else if (parameter_list.len == 2) {
146 var count = std.math.max(1, parameter_list[0]) - 1; 146 var count = @max(1, parameter_list[0]) - 1;
147 if (modKey(key, parameter_list[1])) |mod_key| { 147 if (modKey(key, parameter_list[1])) |mod_key| {
148 try self.key_buf.ensureUnusedCapacity(count); 148 try self.key_buf.ensureUnusedCapacity(count);
149 while (count > 0) : (count -= 1) { 149 while (count > 0) : (count -= 1) {
@@ -159,7 +159,7 @@ fn readControlSequence(self: *KeyReader, reader: File.Reader) !Key {
159 159
160 std.log.err( 160 std.log.err(
161 "Unknown terminal sequence '^[[{s}{s}{c}'", 161 "Unknown terminal sequence '^[[{s}{s}{c}'",
162 .{parameters.items, intermediates.items, final}, 162 .{ parameters.items, intermediates.items, final },
163 ); 163 );
164 164
165 try self.key_buf.ensureUnusedCapacity(parameters.items.len + intermediates.items.len + 1); 165 try self.key_buf.ensureUnusedCapacity(parameters.items.len + intermediates.items.len + 1);
@@ -169,7 +169,7 @@ fn readControlSequence(self: *KeyReader, reader: File.Reader) !Key {
169 } else { 169 } else {
170 std.log.err( 170 std.log.err(
171 "Unknown terminal sequence '^[[{s}{s}'", 171 "Unknown terminal sequence '^[[{s}{s}'",
172 .{parameters.items, intermediates.items}, 172 .{ parameters.items, intermediates.items },
173 ); 173 );
174 } 174 }
175 175
@@ -212,11 +212,13 @@ fn splitParameters(allocator: Allocator, parameters_string: []const u8) Allocato
212 usize, 212 usize,
213 parameter_string, 213 parameter_string,
214 10, 214 10,
215 ) catch { return null; }; 215 ) catch {
216 return null;
217 };
216 218
217 try parameters.append(parameter); 219 try parameters.append(parameter);
218 } 220 }
219 } 221 }
220 222
221 return parameters.toOwnedSlice(); 223 return try parameters.toOwnedSlice();
222} 224}
diff --git a/src/RawMode.zig b/src/RawMode.zig
index 7298922..f657ac8 100644
--- a/src/RawMode.zig
+++ b/src/RawMode.zig
@@ -1,4 +1,4 @@
1const linux = std.os.linux; 1const system = std.os.system;
2const std = @import("std"); 2const std = @import("std");
3 3
4const RawMode = @This(); 4const RawMode = @This();
@@ -14,16 +14,16 @@ pub fn init() !RawMode {
14 var raw = orig; 14 var raw = orig;
15 15
16 raw.iflag &= ~@as( 16 raw.iflag &= ~@as(
17 linux.tcflag_t, 17 system.tcflag_t,
18 linux.BRKINT | linux.ICRNL | linux.INPCK | linux.ISTRIP | linux.IXON, 18 system.BRKINT | system.ICRNL | system.INPCK | system.ISTRIP | system.IXON,
19 ); 19 );
20 raw.lflag &= ~@as(linux.tcflag_t, linux.ECHO | linux.ICANON | linux.IEXTEN | linux.ISIG); 20 raw.lflag &= ~@as(system.tcflag_t, system.ECHO | system.ICANON | system.IEXTEN | system.ISIG);
21 raw.oflag &= ~@as(linux.tcflag_t, linux.OPOST); 21 raw.oflag &= ~@as(system.tcflag_t, system.OPOST);
22 22
23 raw.cflag |= linux.CS8; 23 raw.cflag |= system.CS8;
24 24
25 raw.cc[linux.V.MIN] = 0; 25 raw.cc[system.V.MIN] = 0;
26 raw.cc[linux.V.TIME] = 1; 26 raw.cc[system.V.TIME] = 1;
27 27
28 try std.os.tcsetattr(std.os.STDIN_FILENO, .FLUSH, raw); 28 try std.os.tcsetattr(std.os.STDIN_FILENO, .FLUSH, raw);
29 29
diff --git a/src/Row.zig b/src/Row.zig
index d1de2aa..b8e1674 100644
--- a/src/Row.zig
+++ b/src/Row.zig
@@ -51,7 +51,7 @@ pub fn appendString(self: *Row, buf: *Buffer, str: []const u8) !void {
51pub fn cleanWhiteSpace(self: *Row, buf: *Buffer) !void { 51pub fn cleanWhiteSpace(self: *Row, buf: *Buffer) !void {
52 const orig_len = self.data.items.len; 52 const orig_len = self.data.items.len;
53 while (self.data.items.len > 0) { 53 while (self.data.items.len > 0) {
54 if (std.ascii.isBlank(self.data.items[self.data.items.len - 1])) { 54 if (std.ascii.isWhitespace(self.data.items[self.data.items.len - 1])) {
55 _ = self.data.pop(); 55 _ = self.data.pop();
56 } else { 56 } else {
57 break; 57 break;
@@ -86,7 +86,7 @@ pub fn deleteChar(self: *Row, buf: *Buffer, at: usize) !void {
86pub fn indentationSize(self: Row) usize { 86pub fn indentationSize(self: Row) usize {
87 var idx: usize = 0; 87 var idx: usize = 0;
88 while (idx < self.data.items.len) : (idx += 1) { 88 while (idx < self.data.items.len) : (idx += 1) {
89 if (!std.ascii.isBlank(self.data.items[idx])) { 89 if (!std.ascii.isWhitespace(self.data.items[idx])) {
90 break; 90 break;
91 } 91 }
92 } 92 }
@@ -105,7 +105,7 @@ pub fn rxToCx(self: Row, config: Config, rx: usize) usize {
105 } 105 }
106 106
107 var cur_rx: usize = 0; 107 var cur_rx: usize = 0;
108 for (self.data.items) |char, cx| { 108 for (self.data.items, 0..) |char, cx| {
109 if (char == '\t') { 109 if (char == '\t') {
110 cur_rx += config.tab_stop - (cur_rx % config.tab_stop); 110 cur_rx += config.tab_stop - (cur_rx % config.tab_stop);
111 } else { 111 } else {
@@ -139,7 +139,7 @@ pub fn update(self: *Row, buf: *Buffer) !void {
139const UpdateSyntaxError = std.mem.Allocator.Error; 139const UpdateSyntaxError = std.mem.Allocator.Error;
140pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void { 140pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void {
141 try self.hldata.resize(self.rdata.items.len); 141 try self.hldata.resize(self.rdata.items.len);
142 std.mem.set(Highlight, self.hldata.items, .normal); 142 @memset(self.hldata.items, .normal);
143 if (buf.syntax == null) { 143 if (buf.syntax == null) {
144 return; 144 return;
145 } 145 }
@@ -158,7 +158,7 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void {
158 std.debug.assert(scs.len != 0); 158 std.debug.assert(scs.len != 0);
159 if (curr_str_quote == null and !in_comment and scs.len + i <= self.rdata.items.len) { 159 if (curr_str_quote == null and !in_comment and scs.len + i <= self.rdata.items.len) {
160 if (std.mem.eql(u8, scs, self.rdata.items[i..(i + scs.len)])) { 160 if (std.mem.eql(u8, scs, self.rdata.items[i..(i + scs.len)])) {
161 std.mem.set(Highlight, self.hldata.items[i..], .comment); 161 @memset(self.hldata.items[i..], .comment);
162 break :main_loop; 162 break :main_loop;
163 } 163 }
164 } 164 }
@@ -172,7 +172,7 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void {
172 if (in_comment) { 172 if (in_comment) {
173 self.hldata.items[i] = .comment_ml; 173 self.hldata.items[i] = .comment_ml;
174 if (mce.len + i <= self.rdata.items.len and std.mem.eql(u8, mce, self.rdata.items[i..(i + mce.len)])) { 174 if (mce.len + i <= self.rdata.items.len and std.mem.eql(u8, mce, self.rdata.items[i..(i + mce.len)])) {
175 std.mem.set(Highlight, self.hldata.items[i..(i + mce.len)], .comment_ml); 175 @memset(self.hldata.items[i..(i + mce.len)], .comment_ml);
176 i += mce.len; 176 i += mce.len;
177 in_comment = false; 177 in_comment = false;
178 last_sep = i; 178 last_sep = i;
@@ -181,7 +181,7 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void {
181 continue :main_loop; 181 continue :main_loop;
182 } 182 }
183 } else if (mcs.len + i <= self.rdata.items.len and std.mem.eql(u8, mcs, self.rdata.items[i..(i + mcs.len)])) { 183 } else if (mcs.len + i <= self.rdata.items.len and std.mem.eql(u8, mcs, self.rdata.items[i..(i + mcs.len)])) {
184 std.mem.set(Highlight, self.hldata.items[i..(i + mcs.len)], .comment_ml); 184 @memset(self.hldata.items[i..(i + mcs.len)], .comment_ml);
185 i += mcs.len; 185 i += mcs.len;
186 in_comment = true; 186 in_comment = true;
187 continue :main_loop; 187 continue :main_loop;
@@ -218,9 +218,7 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void {
218 } 218 }
219 219
220 if (syntax.flags.hl_numbers) { 220 if (syntax.flags.hl_numbers) {
221 if ((std.ascii.isDigit(c) and (last_sep == i or prev_hl == .number)) 221 if ((std.ascii.isDigit(c) and (last_sep == i or prev_hl == .number)) or (c == '.' and prev_hl == .number)) {
222 or (c == '.' and prev_hl == .number)
223 ) {
224 self.hldata.items[i] = .number; 222 self.hldata.items[i] = .number;
225 i += 1; 223 i += 1;
226 continue :main_loop; 224 continue :main_loop;
@@ -230,7 +228,7 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void {
230 if (syntax.isSeparator(c)) { 228 if (syntax.isSeparator(c)) {
231 const id = self.rdata.items[last_sep..i]; 229 const id = self.rdata.items[last_sep..i];
232 if (syntax.keyword_classifier(id)) |hl| { 230 if (syntax.keyword_classifier(id)) |hl| {
233 std.mem.set(Highlight, self.hldata.items[last_sep..i], hl); 231 @memset(self.hldata.items[last_sep..i], hl);
234 } 232 }
235 233
236 last_sep = i + 1; 234 last_sep = i + 1;
@@ -242,7 +240,7 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void {
242 if (!in_comment) { 240 if (!in_comment) {
243 const id = self.rdata.items[last_sep..self.rdata.items.len]; 241 const id = self.rdata.items[last_sep..self.rdata.items.len];
244 if (syntax.keyword_classifier(id)) |hl| { 242 if (syntax.keyword_classifier(id)) |hl| {
245 std.mem.set(Highlight, self.hldata.items[last_sep..self.rdata.items.len], hl); 243 @memset(self.hldata.items[last_sep..self.rdata.items.len], hl);
246 } 244 }
247 } 245 }
248 246
diff --git a/src/Syntax.zig b/src/Syntax.zig
index 6858027..18ed477 100644
--- a/src/Syntax.zig
+++ b/src/Syntax.zig
@@ -10,8 +10,7 @@ const Syntax = @This();
10 10
11pub const chooseSyntax = ComptimeStringMap( 11pub const chooseSyntax = ComptimeStringMap(
12 Syntax, 12 Syntax,
13 pairWith(&makefile.filematch, makefile.syntax) 13 pairWith(&makefile.filematch, makefile.syntax) ++ pairWith(&zig.filematch, zig.syntax),
14 ++ pairWith(&zig.filematch, zig.syntax),
15).get; 14).get;
16 15
17pub const Flags = struct { 16pub const Flags = struct {
@@ -20,7 +19,7 @@ pub const Flags = struct {
20}; 19};
21 20
22name: []const u8, 21name: []const u8,
23keyword_classifier: fn([]const u8) ?Highlight, 22keyword_classifier: *const fn ([]const u8) ?Highlight,
24singleline_comment_start: ?[]const u8, 23singleline_comment_start: ?[]const u8,
25multiline_comment_start: ?[]const u8, 24multiline_comment_start: ?[]const u8,
26multiline_comment_end: ?[]const u8, 25multiline_comment_end: ?[]const u8,
@@ -28,7 +27,7 @@ separators: []const u8,
28flags: Flags, 27flags: Flags,
29 28
30pub fn isSeparator(self: Syntax, char: u8) bool { 29pub fn isSeparator(self: Syntax, char: u8) bool {
31 return std.ascii.isSpace(char) or std.mem.indexOfScalar(u8, self.separators, char) != null; 30 return std.ascii.isWhitespace(char) or std.mem.indexOfScalar(u8, self.separators, char) != null;
32} 31}
33 32
34pub fn pairWith( 33pub fn pairWith(
@@ -37,8 +36,8 @@ pub fn pairWith(
37) [keys.len]KeyValue(@TypeOf(value)) { 36) [keys.len]KeyValue(@TypeOf(value)) {
38 @setEvalBranchQuota(20000); 37 @setEvalBranchQuota(20000);
39 38
40 var pairs = [_]KeyValue(@TypeOf(value)) {undefined} ** keys.len; 39 var pairs = [_]KeyValue(@TypeOf(value)){undefined} ** keys.len;
41 for (keys) |key, i| { 40 for (keys, 0..) |key, i| {
42 pairs[i] = .{ .@"0" = key, .@"1" = value }; 41 pairs[i] = .{ .@"0" = key, .@"1" = value };
43 } 42 }
44 43
@@ -51,4 +50,3 @@ fn KeyValue(comptime V: type) type {
51 @"1": V, 50 @"1": V,
52 }; 51 };
53} 52}
54
diff --git a/src/c.zig b/src/c.zig
new file mode 100644
index 0000000..8fb0a79
--- /dev/null
+++ b/src/c.zig
@@ -0,0 +1,5 @@
1const std = @import("std");
2
3const pid_t = std.c.pid_t;
4
5pub extern "c" fn getpid() pid_t;
diff --git a/src/key.zig b/src/key.zig
index f2538bd..d2748e7 100644
--- a/src/key.zig
+++ b/src/key.zig
@@ -27,7 +27,7 @@ pub const Key = enum(u16) {
27 _, 27 _,
28 28
29 pub fn char(ch: u8) Key { 29 pub fn char(ch: u8) Key {
30 return @intToEnum(Key, ch); 30 return @enumFromInt(ch);
31 } 31 }
32 32
33 pub fn shift(k: anytype) Key { 33 pub fn shift(k: anytype) Key {
@@ -52,20 +52,16 @@ pub const Key = enum(u16) {
52 } 52 }
53 53
54 fn mod(comptime modifier: Key, k: Key) Key { 54 fn mod(comptime modifier: Key, k: Key) Key {
55 comptime std.debug.assert( 55 comptime std.debug.assert(modifier == .mod_shft or modifier == .mod_meta or modifier == .mod_ctrl);
56 modifier == .mod_shft
57 or modifier == .mod_meta
58 or modifier == .mod_ctrl
59 );
60 56
61 const shft_int = @enumToInt(Key.mod_shft); 57 const shft_int = @intFromEnum(Key.mod_shft);
62 const meta_int = @enumToInt(Key.mod_meta); 58 const meta_int = @intFromEnum(Key.mod_meta);
63 const ctrl_int = @enumToInt(Key.mod_ctrl); 59 const ctrl_int = @intFromEnum(Key.mod_ctrl);
64 60
65 const max_char_int = @enumToInt(Key.max_char); 61 const max_char_int = @intFromEnum(Key.max_char);
66 62
67 const mod_int = @enumToInt(modifier); 63 const mod_int = @intFromEnum(modifier);
68 const k_int = @enumToInt(k); 64 const k_int = @intFromEnum(k);
69 if (k_int & mod_int == mod_int) { 65 if (k_int & mod_int == mod_int) {
70 return k; 66 return k;
71 } 67 }
@@ -76,12 +72,12 @@ pub const Key = enum(u16) {
76 // Appending S- to a character is not smart 72 // Appending S- to a character is not smart
77 std.debug.assert(modifier != .mod_shft); 73 std.debug.assert(modifier != .mod_shft);
78 return switch (modifier) { 74 return switch (modifier) {
79 .mod_meta => @intToEnum(Key, k_int | meta_int), 75 .mod_meta => @enumFromInt(k_int | meta_int),
80 .mod_ctrl => @intToEnum(Key, k_origmod | (k_nomod & 0x1f)), 76 .mod_ctrl => @enumFromInt(k_origmod | (k_nomod & 0x1f)),
81 else => unreachable, 77 else => unreachable,
82 }; 78 };
83 } else { 79 } else {
84 return @intToEnum(Key, k_int | mod_int); 80 return @enumFromInt(k_int | mod_int);
85 } 81 }
86 } 82 }
87 83
@@ -125,15 +121,15 @@ pub const Key = enum(u16) {
125 options: std.fmt.FormatOptions, 121 options: std.fmt.FormatOptions,
126 writer: anytype, 122 writer: anytype,
127 ) @TypeOf(writer).Error!void { 123 ) @TypeOf(writer).Error!void {
128 const shft_int = @enumToInt(Key.mod_shft); 124 const shft_int = @intFromEnum(Key.mod_shft);
129 const meta_int = @enumToInt(Key.mod_meta); 125 const meta_int = @intFromEnum(Key.mod_meta);
130 const ctrl_int = @enumToInt(Key.mod_ctrl); 126 const ctrl_int = @intFromEnum(Key.mod_ctrl);
131 127
132 const key_int = @enumToInt(key); 128 const key_int = @intFromEnum(key);
133 if (key_int & shft_int == shft_int) { 129 if (key_int & shft_int == shft_int) {
134 try std.fmt.formatBuf("S-", options, writer); 130 try std.fmt.formatBuf("S-", options, writer);
135 return Key.format( 131 return Key.format(
136 @intToEnum(Key, key_int & ~shft_int), 132 @enumFromInt(key_int & ~shft_int),
137 "", 133 "",
138 options, 134 options,
139 writer, 135 writer,
@@ -141,7 +137,7 @@ pub const Key = enum(u16) {
141 } else if (key_int & meta_int == meta_int) { 137 } else if (key_int & meta_int == meta_int) {
142 try std.fmt.formatBuf("M-", options, writer); 138 try std.fmt.formatBuf("M-", options, writer);
143 return Key.format( 139 return Key.format(
144 @intToEnum(Key, key_int & ~meta_int), 140 @enumFromInt(key_int & ~meta_int),
145 "", 141 "",
146 options, 142 options,
147 writer, 143 writer,
@@ -149,22 +145,17 @@ pub const Key = enum(u16) {
149 } else if (key_int & ctrl_int == ctrl_int) { 145 } else if (key_int & ctrl_int == ctrl_int) {
150 try std.fmt.formatBuf("C-", options, writer); 146 try std.fmt.formatBuf("C-", options, writer);
151 return Key.format( 147 return Key.format(
152 @intToEnum(Key, key_int & ~ctrl_int), 148 @enumFromInt(key_int & ~ctrl_int),
153 "", 149 "",
154 options, 150 options,
155 writer, 151 writer,
156 ); 152 );
157 } else if (key_int < 0x20) { 153 } else if (key_int < 0x20) {
158 try std.fmt.formatBuf("C-", options, writer); 154 try std.fmt.formatBuf("C-", options, writer);
159 return Key.format( 155 return Key.format(Key.char(@intCast(key_int + 0x40)), "", options, writer);
160 Key.char(@intCast(u8, key_int + 0x40)),
161 "",
162 options,
163 writer
164 );
165 } else if (key_int < 0x100) { 156 } else if (key_int < 0x100) {
166 const ch = @intCast(u8, key_int); 157 const ch: u8 = @intCast(key_int);
167 if (std.ascii.isGraph(ch)) { 158 if (std.ascii.isPrint(ch)) {
168 return writer.writeByte(ch); 159 return writer.writeByte(ch);
169 } else { 160 } else {
170 try writer.writeAll("<\\x"); 161 try writer.writeAll("<\\x");
diff --git a/src/main.zig b/src/main.zig
index 7a3f007..fd1c304 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,4 +1,5 @@
1pub const Buffer = @import("Buffer.zig"); 1pub const Buffer = @import("Buffer.zig");
2pub const c = @import("c.zig");
2pub const conf = @import("es-config"); 3pub const conf = @import("es-config");
3pub const Config = @import("Config.zig"); 4pub const Config = @import("Config.zig");
4pub const Editor = @import("Editor.zig"); 5pub const Editor = @import("Editor.zig");
@@ -13,6 +14,7 @@ pub const search = @import("search.zig").search;
13pub const StringBuilder = @import("StringBuilder.zig"); 14pub const StringBuilder = @import("StringBuilder.zig");
14pub const Syntax = @import("Syntax.zig"); 15pub const Syntax = @import("Syntax.zig");
15 16
17const builtin = @import("builtin");
16const std = @import("std"); 18const std = @import("std");
17 19
18const Allocator = std.mem.Allocator; 20const Allocator = std.mem.Allocator;
@@ -21,6 +23,12 @@ const GPA = std.heap.GeneralPurposeAllocator(.{});
21 23
22var log_file: ?File = null; 24var log_file: ?File = null;
23 25
26// TODO[zigbug]: Why isn't getpid defined for Darwin?
27const getpid = switch (builtin.os.tag) {
28 .macos, .ios, .tvos, .watchos => c.getpid,
29 else => std.os.system.getpid,
30};
31
24pub fn log( 32pub fn log(
25 comptime level: std.log.Level, 33 comptime level: std.log.Level,
26 comptime scope: @TypeOf(.EnumLiteral), 34 comptime scope: @TypeOf(.EnumLiteral),
@@ -45,7 +53,7 @@ pub fn main() !void {
45 const log_file_name = try std.fmt.allocPrint( 53 const log_file_name = try std.fmt.allocPrint(
46 allocator, 54 allocator,
47 "/tmp/es.{}.log", 55 "/tmp/es.{}.log",
48 .{std.os.linux.getpid()}, 56 .{getpid()},
49 ); 57 );
50 defer { 58 defer {
51 std.log.info("Logs in {s}", .{log_file_name}); 59 std.log.info("Logs in {s}", .{log_file_name});