diff options
Diffstat (limited to '')
| -rw-r--r-- | build.zig | 38 | ||||
| -rw-r--r-- | src/Buffer.zig | 27 | ||||
| -rw-r--r-- | src/Config.zig | 6 | ||||
| -rw-r--r-- | src/Editor.zig | 42 | ||||
| -rw-r--r-- | src/KeyMap.zig | 64 | ||||
| -rw-r--r-- | src/KeyReader.zig | 16 | ||||
| -rw-r--r-- | src/RawMode.zig | 16 | ||||
| -rw-r--r-- | src/Row.zig | 22 | ||||
| -rw-r--r-- | src/Syntax.zig | 12 | ||||
| -rw-r--r-- | src/c.zig | 5 | ||||
| -rw-r--r-- | src/key.zig | 51 | ||||
| -rw-r--r-- | src/main.zig | 10 |
12 files changed, 162 insertions, 147 deletions
| @@ -1,11 +1,12 @@ | |||
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | const Builder = std.build.Builder; | 3 | const Builder = std.Build; |
| 4 | const SemanticVersion = std.SemanticVersion; | 4 | const SemanticVersion = std.SemanticVersion; |
| 5 | 5 | ||
| 6 | const share_prefix = "share/arkta/es/"; | 6 | const share_prefix = "share/arkta/es/"; |
| 7 | 7 | ||
| 8 | const version = "0.3.0"; | 8 | const version = "0.3.0"; |
| 9 | const semver = SemanticVersion.parse(version) catch unreachable; | ||
| 9 | 10 | ||
| 10 | const config = struct { | 11 | const 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 | ||
| 20 | fn installGeneratedFile(b: *Builder, comptime name: []const u8, data: []const u8) void { | 21 | fn 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 | ||
| 32 | pub fn build(b: *Builder) void { | 30 | pub 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, | |||
| 31 | syntax: ?Syntax, | 31 | syntax: ?Syntax, |
| 32 | 32 | ||
| 33 | pub fn init(allocator: Allocator, name: []const u8) !Buffer { | 33 | pub 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 | |||
| 225 | pub fn drawStatusBar(self: Buffer, writer: anytype, screencols: usize) !void { | 225 | pub 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 | ||
| 410 | pub fn pageUp(self: *Buffer, editor: Editor) void { | 410 | pub 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 | ||
| 440 | pub fn save(self: *Buffer, editor: *Editor) !void { | 440 | pub 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; | |||
| 5 | const ArrayList = std.ArrayList; | 5 | const ArrayList = std.ArrayList; |
| 6 | const Buffer = es.Buffer; | 6 | const Buffer = es.Buffer; |
| 7 | const Editor = @This(); | 7 | const Editor = @This(); |
| 8 | const File = std.fs.File; | ||
| 8 | const Key = es.Key; | 9 | const Key = es.Key; |
| 9 | const KeyMap = es.KeyMap; | 10 | const KeyMap = es.KeyMap; |
| 10 | const KeyReader = es.KeyReader; | 11 | const 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 | ||
| 353 | pub fn setStatusMessage(self: *Editor, comptime fmt: []const u8, args: anytype) !void { | 347 | pub 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 | ||
| 394 | fn getCursorPosition(row: *usize, col: *usize) !void { | 388 | // TODO[zigbug]: https://github.com/ziglang/zig/issues/18177 |
| 389 | // Replace with an inferred set | ||
| 390 | const CursorPositionError = error{ | ||
| 391 | MisformedTerminalResponse, | ||
| 392 | } || File.WriteError; | ||
| 393 | |||
| 394 | fn 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 | ||
| 420 | fn getWindowSize(rows: *usize, cols: *usize) !void { | 420 | fn 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 | ||
| 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) { |
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 @@ | |||
| 1 | const linux = std.os.linux; | 1 | const system = std.os.system; |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | 3 | ||
| 4 | const RawMode = @This(); | 4 | const 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 { | |||
| 51 | pub fn cleanWhiteSpace(self: *Row, buf: *Buffer) !void { | 51 | pub 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 { | |||
| 86 | pub fn indentationSize(self: Row) usize { | 86 | pub 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 { | |||
| 139 | const UpdateSyntaxError = std.mem.Allocator.Error; | 139 | const UpdateSyntaxError = std.mem.Allocator.Error; |
| 140 | pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void { | 140 | pub 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 | ||
| 11 | pub const chooseSyntax = ComptimeStringMap( | 11 | pub 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 | ||
| 17 | pub const Flags = struct { | 16 | pub const Flags = struct { |
| @@ -20,7 +19,7 @@ pub const Flags = struct { | |||
| 20 | }; | 19 | }; |
| 21 | 20 | ||
| 22 | name: []const u8, | 21 | name: []const u8, |
| 23 | keyword_classifier: fn([]const u8) ?Highlight, | 22 | keyword_classifier: *const fn ([]const u8) ?Highlight, |
| 24 | singleline_comment_start: ?[]const u8, | 23 | singleline_comment_start: ?[]const u8, |
| 25 | multiline_comment_start: ?[]const u8, | 24 | multiline_comment_start: ?[]const u8, |
| 26 | multiline_comment_end: ?[]const u8, | 25 | multiline_comment_end: ?[]const u8, |
| @@ -28,7 +27,7 @@ separators: []const u8, | |||
| 28 | flags: Flags, | 27 | flags: Flags, |
| 29 | 28 | ||
| 30 | pub fn isSeparator(self: Syntax, char: u8) bool { | 29 | pub 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 | ||
| 34 | pub fn pairWith( | 33 | pub 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 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const pid_t = std.c.pid_t; | ||
| 4 | |||
| 5 | pub 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 @@ | |||
| 1 | pub const Buffer = @import("Buffer.zig"); | 1 | pub const Buffer = @import("Buffer.zig"); |
| 2 | pub const c = @import("c.zig"); | ||
| 2 | pub const conf = @import("es-config"); | 3 | pub const conf = @import("es-config"); |
| 3 | pub const Config = @import("Config.zig"); | 4 | pub const Config = @import("Config.zig"); |
| 4 | pub const Editor = @import("Editor.zig"); | 5 | pub const Editor = @import("Editor.zig"); |
| @@ -13,6 +14,7 @@ pub const search = @import("search.zig").search; | |||
| 13 | pub const StringBuilder = @import("StringBuilder.zig"); | 14 | pub const StringBuilder = @import("StringBuilder.zig"); |
| 14 | pub const Syntax = @import("Syntax.zig"); | 15 | pub const Syntax = @import("Syntax.zig"); |
| 15 | 16 | ||
| 17 | const builtin = @import("builtin"); | ||
| 16 | const std = @import("std"); | 18 | const std = @import("std"); |
| 17 | 19 | ||
| 18 | const Allocator = std.mem.Allocator; | 20 | const Allocator = std.mem.Allocator; |
| @@ -21,6 +23,12 @@ const GPA = std.heap.GeneralPurposeAllocator(.{}); | |||
| 21 | 23 | ||
| 22 | var log_file: ?File = null; | 24 | var log_file: ?File = null; |
| 23 | 25 | ||
| 26 | // TODO[zigbug]: Why isn't getpid defined for Darwin? | ||
| 27 | const getpid = switch (builtin.os.tag) { | ||
| 28 | .macos, .ios, .tvos, .watchos => c.getpid, | ||
| 29 | else => std.os.system.getpid, | ||
| 30 | }; | ||
| 31 | |||
| 24 | pub fn log( | 32 | pub 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}); |