From 83af8ab1249b98bb5cf691b88bfc947d1d688710 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Mon, 18 Dec 2023 07:26:01 +0100 Subject: zig 0.11 changes --- README.md | 8 +++--- build.zig | 79 +++++++++++++++++++++++++++++++++--------------------- lib/spoon | 2 +- src/field.zig | 69 +++++++++++++++++++++++++++-------------------- src/io.zig | 6 ++++- src/main.zig | 12 ++++----- src/pointer.zig | 19 ++++++++----- src/stack.zig | 4 +-- src/stackStack.zig | 8 +++--- src/tui.zig | 48 ++++++++++++++++++++------------- 10 files changed, 152 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index a3e7b63..113b3a6 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Current limitations are : ## Dependencies -zig is required. Only zig version >= 0.10.1 on linux amd64 (Gentoo) is being regularly tested. +zig is required. Only zig version 0.11 on linux amd64 (Gentoo) is being regularly tested. ## Quick Install @@ -58,7 +58,7 @@ zig build For a non debug build, use either one of: ```sh -zig build -Drelease-safe -zig build -Drelease-small -zig build -Drelease-fast +zig build -Doptimize=ReleaseSafe +zig build -Doptimize=ReleaseSmall +zig build -Doptimize=ReleaseFast ``` diff --git a/build.zig b/build.zig index 3ac3e80..00ea514 100644 --- a/build.zig +++ b/build.zig @@ -1,45 +1,32 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. +pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); - - const exe = b.addExecutable("zigfunge98", "src/main.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); - exe.install(); - - const run_cmd = exe.run(); + const exe = b.addExecutable(.{ + .name = "zigfunge98", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + b.installArtifact(exe); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); } - - const tui = b.addExecutable("zigfunge98-tui", "src/tui.zig"); - tui.addPackagePath("spoon", "lib/spoon/import.zig"); - tui.setTarget(target); - tui.setBuildMode(mode); - tui.install(); - - const coverage = b.option(bool, "test-coverage", "Generate test coverage") orelse false; - const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); + const unit_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); - const exe_tests = b.addTest("src/main.zig"); - exe_tests.setTarget(target); - exe_tests.setBuildMode(mode); - + const coverage = b.option(bool, "test-coverage", "Generate test coverage") orelse false; // Code coverage with kcov, we need an allocator for the setup var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = general_purpose_allocator.deinit(); const gpa = general_purpose_allocator.allocator(); // We want to exclude the $HOME/.zig path const home = std.process.getEnvVarOwned(gpa, "HOME") catch ""; @@ -47,7 +34,8 @@ pub fn build(b: *std.build.Builder) void { const exclude = std.fmt.allocPrint(gpa, "--exclude-path={s}/.zig/", .{home}) catch ""; defer gpa.free(exclude); if (coverage) { - exe_tests.setExecCmd(&[_]?[]const u8{ + unit_tests.test_runner = "/usr/bin/kcov"; + unit_tests.setExecCmd(&[_]?[]const u8{ "kcov", exclude, //"--path-strip-level=3", // any kcov flags can be specified here @@ -56,6 +44,35 @@ pub fn build(b: *std.build.Builder) void { }); } + const run_unit_tests = b.addRunArtifact(unit_tests); const test_step = b.step("test", "Run unit tests"); - test_step.dependOn(&exe_tests.step); + test_step.dependOn(&run_unit_tests.step); + + // ----- TUI -------------------------------------------------------------- + const tui = b.addExecutable(.{ + .name = "zigfunge98-tui", + .root_source_file = .{ .path = "src/tui.zig" }, + .target = target, + .optimize = optimize, + }); + const spoon = b.createModule(.{ + .source_file = .{ .path = "lib/spoon/import.zig" }, + }); + tui.addModule("spoon", spoon); + b.installArtifact(tui); + const tui_cmd = b.addRunArtifact(tui); + tui_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + tui_cmd.addArgs(args); + } + const tui_step = b.step("run-tui", "Run the app"); + tui_step.dependOn(&tui_cmd.step); + const tui_unit_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/tui.zig" }, + .target = target, + .optimize = optimize, + }); + const tui_run_unit_tests = b.addRunArtifact(tui_unit_tests); + const tui_test_step = b.step("test-tui", "Run tui unit tests"); + tui_test_step.dependOn(&tui_run_unit_tests.step); } diff --git a/lib/spoon b/lib/spoon index 75dbab7..9fa5bb1 160000 --- a/lib/spoon +++ b/lib/spoon @@ -1 +1 @@ -Subproject commit 75dbab71771ca2ee5aadcd5ab7a4c503a9536031 +Subproject commit 9fa5bb1eafc30b3ff0cbe297a3e0f51dbc903831 diff --git a/src/field.zig b/src/field.zig index ef5e6ea..bf170fb 100644 --- a/src/field.zig +++ b/src/field.zig @@ -5,17 +5,17 @@ const Line = struct { x: i64 = 0, data: std.ArrayList(i64), fn blank(l: *Line, x: i64) void { - const lx = @intCast(i64, l.len()); + const lx: i64 = @intCast(l.len()); if (x < l.x or x > l.x + lx - 1) { // outside the field return; } else if (x > l.x and x < l.x + lx - 1) { // just set the value - l.data.items[@intCast(usize, x - l.x)] = ' '; + l.data.items[@intCast(x - l.x)] = ' '; } else if (lx == 1) { // this was the last character on the line l.data.items.len = 0; } else if (x == l.x) { // we need to remove leading spaces var i: usize = 1; while (l.data.items[i] == ' ') : (i += 1) {} - l.x += @intCast(i64, i); + l.x += @intCast(i); std.mem.copy(i64, l.data.items[0 .. l.len() - i], l.data.items[i..]); l.data.items.len -= i; } else { // we need to remove trailing spaces @@ -66,7 +66,8 @@ const Line = struct { self.allocator.destroy(self); } fn get(l: *Line, x: i64) i64 { - if (x >= l.x and x < l.x + @intCast(i64, l.len())) return l.data.items[@intCast(usize, x - @intCast(i64, l.x))]; + const ll: i64 = @intCast(l.len()); + if (x >= l.x and x < l.x + ll) return l.data.items[@intCast(x - l.x)]; return ' '; } fn init(allocator: std.mem.Allocator) !*Line { @@ -84,10 +85,10 @@ const Line = struct { try l.data.append(v); return; } - const lx = @intCast(i64, l.len()); + const lx: i64 = @intCast(l.len()); if (x >= l.x) { if (x < l.x + lx) { // just set the value - l.data.items[@intCast(usize, x - l.x)] = v; + l.data.items[@intCast(x - l.x)] = v; } else { // we need to add trailing spaces var i: usize = l.len(); while (i < x - l.x) : (i += 1) { @@ -97,12 +98,12 @@ const Line = struct { } } else { // we need to shift right and add leading spaces const oldLen = l.len(); - l.data.items.len += @intCast(usize, l.x - x); + l.data.items.len += @intCast(l.x - x); try l.data.ensureUnusedCapacity(l.len()); - std.mem.copyBackwards(i64, l.data.items[@intCast(usize, l.x - x)..], l.data.items[0..oldLen]); + std.mem.copyBackwards(i64, l.data.items[@intCast(l.x - x)..], l.data.items[0..oldLen]); l.data.items[0] = v; var i: usize = 1; - while (i < @intCast(usize, l.x - x)) : (i += 1) { + while (i < l.x - x) : (i += 1) { l.data.items[i] = ' '; } l.x = x; @@ -150,10 +151,11 @@ pub const Field = struct { lines: std.ArrayList(*Line), lx: usize = 0, pub fn blank(f: *Field, x: i64, y: i64) !void { - const ly = @intCast(i64, f.lines.items.len); + const ly = f.lines.items.len; if (ly == 0) return error.EmptyFieldError; - if (y < f.y or y >= f.y + ly) return; // outside the field - var l = f.lines.items[@intCast(usize, y - f.y)]; + const lly: i64 = @intCast(ly); + if (y < f.y or y >= f.y + lly) return; // outside the field + var l = f.lines.items[@intCast(y - f.y)]; if (l.len() == 0) return; // the line is already empty l.blank(x); if (l.len() == 0) { @@ -165,27 +167,29 @@ pub const Field = struct { while (f.lines.items[i].len() == 0) : (i += 1) { f.lines.items[i].deinit(); } - f.y += @intCast(i64, i); + f.y += @intCast(i); std.mem.copy(*Line, f.lines.items[0 .. f.lines.items.len - i], f.lines.items[i..]); f.lines.items.len -= i; - } else if (y == f.y + ly - 1) { // we need to remove trailing lines + } else if (y == f.y + lly - 1) { // we need to remove trailing lines l.deinit(); - var i: usize = @intCast(usize, ly) - 2; + var i: usize = ly - 2; while (f.lines.items[i].len() == 0) : (i -= 1) { f.lines.items[i].deinit(); } f.lines.items.len = i + 1; } } - if (x == f.x or x == f.x + @intCast(i64, f.lx) - 1) { // recalculate boundaries + const flx: i64 = @intCast(f.lx); + if (x == f.x or x == f.x + flx - 1) { // recalculate boundaries f.x = std.math.maxInt(i64); var x2: i64 = std.math.minInt(i64); for (f.lines.items) |line| { if (line.len() == 0) continue; if (f.x > line.x) f.x = line.x; - if (x2 < line.x + @intCast(i64, line.len())) x2 = line.x + @intCast(i64, line.len()); + const ll: i64 = @intCast(line.len()); + if (x2 < line.x + ll) x2 = line.x + ll; } - f.lx = @intCast(usize, x2 - f.x); + f.lx = @intCast(x2 - f.x); } } test "blank" { @@ -241,11 +245,12 @@ pub const Field = struct { self.allocator.destroy(self); } pub fn get(f: *Field, x: i64, y: i64) i64 { - if (y >= f.y and y < f.y + @intCast(i64, f.lines.items.len)) return f.lines.items[@intCast(usize, y - @intCast(i64, f.y))].get(x); + const fl: i64 = @intCast(f.lines.items.len); + if (y >= f.y and y < f.y + fl) return f.lines.items[@intCast(y - f.y)].get(x); return ' '; } pub fn getSize(f: Field) [4]i64 { - return [4]i64{ f.x, f.y, @intCast(i64, f.lx), @intCast(i64, f.lines.items.len) }; + return [4]i64{ f.x, f.y, @intCast(f.lx), @intCast(f.lines.items.len) }; } fn init(allocator: std.mem.Allocator) !*Field { var f = try allocator.create(Field); @@ -266,7 +271,9 @@ pub const Field = struct { return f; } inline fn isIn(f: *Field, x: i64, y: i64) bool { - return x >= f.x and y >= f.y and x < f.x + @intCast(i64, f.lx) and y < f.y + @intCast(i64, f.lines.items.len); + const fl: i64 = @intCast(f.lines.items.len); + const flx: i64 = @intCast(f.lx); + return x >= f.x and y >= f.y and x < f.x + flx and y < f.y + fl; } fn load(f: *Field, reader: anytype) !void { if (f.lines.items.len > 1 or f.lx > 0) return error.FIELD_NOT_EMPTY; @@ -334,8 +341,9 @@ pub const Field = struct { pub fn set(f: *Field, x: i64, y: i64, v: i64) !void { if (v == ' ') return f.blank(x, y); if (y >= f.y) { - if (y < f.y + @intCast(i64, f.lines.items.len)) { // the line exists - try f.lines.items[@intCast(usize, y - f.y)].set(x, v); + const fl: i64 = @intCast(f.lines.items.len); + if (y < f.y + fl) { // the line exists + try f.lines.items[@intCast(y - f.y)].set(x, v); } else { // append lines var i: usize = f.lines.items.len; while (i < y - f.y) : (i += 1) { @@ -347,27 +355,30 @@ pub const Field = struct { } } else { // preprend lines const oldLen = f.lines.items.len; - f.lines.items.len += @intCast(usize, f.y - y); + const dl: usize = @intCast(f.y - y); + f.lines.items.len += dl; try f.lines.ensureUnusedCapacity(f.lines.items.len); - std.mem.copyBackwards(*Line, f.lines.items[@intCast(usize, f.y - y)..], f.lines.items[0..oldLen]); + std.mem.copyBackwards(*Line, f.lines.items[dl..], f.lines.items[0..oldLen]); var l = try Line.init(f.allocator); try l.set(x, v); f.lines.items[0] = l; var i: usize = 1; - while (i < @intCast(usize, f.y - y)) : (i += 1) { + while (i < f.y - y) : (i += 1) { f.lines.items[i] = try Line.init(f.allocator); } f.y = y; } - if (x < f.x or x >= f.x + @intCast(i64, f.lx)) { // recalculate boundaries + const flx: i64 = @intCast(f.lx); + if (x < f.x or x >= f.x + flx) { // recalculate boundaries f.x = std.math.maxInt(i64); var x2: i64 = std.math.minInt(i64); for (f.lines.items) |line| { if (line.len() == 0) continue; if (f.x > line.x) f.x = line.x; - if (x2 < line.x + @intCast(i64, line.len())) x2 = line.x + @intCast(i64, line.len()); + const ll: i64 = @intCast(line.len()); + if (x2 < line.x + ll) x2 = line.x + ll; } - f.lx = @intCast(usize, x2 - f.x); + f.lx = @intCast(x2 - f.x); } return; } diff --git a/src/io.zig b/src/io.zig index 54abcfc..2cc0047 100644 --- a/src/io.zig +++ b/src/io.zig @@ -60,7 +60,11 @@ pub fn Context(comptime readerType: anytype, comptime writerType: anytype) type try std.testing.expectEqual(ioContext.decimalInput(), error.IOError); } pub fn characterOutput(self: Self, v: i64) !void { - try self.writer.print("{c}", .{@intCast(u8, v)}); + var vv: u8 = '?'; + if (v >= 0 and v <= 255) { + vv = @intCast(v); + } + try self.writer.print("{c}", .{vv}); return; } pub fn decimalOutput(self: Self, v: i64) !void { diff --git a/src/main.zig b/src/main.zig index 7337100..920d306 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,10 +3,10 @@ const interpreter = @import("interpreter.zig"); const io = @import("io.zig"); pub fn main() anyerror!void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer std.debug.assert(!gpa.deinit()); - var args = try std.process.argsAlloc(gpa.allocator()); - defer std.process.argsFree(gpa.allocator(), args); + var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; + const gpa = general_purpose_allocator.allocator(); + var args = try std.process.argsAlloc(gpa); + defer std.process.argsFree(gpa, args); if (args.len < 2) { std.debug.print("Usage: {s} \n", .{args[0]}); std.os.exit(1); @@ -16,11 +16,11 @@ pub fn main() anyerror!void { defer file.close(); const env: []const [*:0]const u8 = std.os.environ; - var i = try interpreter.Interpreter.init(gpa.allocator(), file.reader(), null, args, env[0..]); + var i = try interpreter.Interpreter.init(gpa, file.reader(), null, args, env[0..]); defer i.deinit(); var ioContext = io.context(std.io.getStdIn().reader(), std.io.getStdOut().writer()); - std.os.exit(@intCast(u8, try i.run(&ioContext))); + std.os.exit(@intCast(try i.run(&ioContext))); } const testTimestamp: i64 = 1660681247; diff --git a/src/pointer.zig b/src/pointer.zig index 75bc5ae..eeb1204 100644 --- a/src/pointer.zig +++ b/src/pointer.zig @@ -245,21 +245,26 @@ pub const Pointer = struct { // 18 i = 0; while (i < p.ss.data.items.len) : (i += 1) { - try p.ss.toss.push(@intCast(i64, p.ss.data.items[i].data.items.len)); + try p.ss.toss.push(@intCast(p.ss.data.items[i].data.items.len)); } - try p.ss.toss.push(@intCast(i64, height)); + try p.ss.toss.push(@intCast(height)); // 17 - try p.ss.toss.push(@intCast(i64, p.ss.data.items.len) + 1); + try p.ss.toss.push(@intCast(p.ss.data.items.len + 1)); // 16 const ts = if (p.timestamp) |v| v else std.time.timestamp(); - const now = std.time.epoch.EpochSeconds{ .secs = @intCast(u64, ts) }; + const now = std.time.epoch.EpochSeconds{ .secs = @intCast(ts) }; const epochDay = now.getEpochDay(); const daySeconds = now.getDaySeconds(); - try p.ss.toss.push(@intCast(i64, daySeconds.getHoursIntoDay()) * 256 * 256 + @intCast(i64, daySeconds.getMinutesIntoHour()) * 256 + @intCast(i64, daySeconds.getSecondsIntoMinute())); + const hours: i64 = @intCast(daySeconds.getHoursIntoDay()); + const minutes: i64 = @intCast(daySeconds.getMinutesIntoHour()); + const seconds: i64 = @intCast(daySeconds.getSecondsIntoMinute()); + try p.ss.toss.push(hours * 256 * 256 + minutes * 256 + seconds); // 15 const yearAndDay = epochDay.calculateYearDay(); + const year: i64 = @intCast(yearAndDay.year); const monthAndDay = yearAndDay.calculateMonthDay(); - try p.ss.toss.push(@intCast(i64, yearAndDay.year - 1900) * 256 * 256 + @intCast(i64, monthAndDay.month.numeric()) * 256 + @intCast(i64, monthAndDay.day_index)); + const month: i64 = @intCast(monthAndDay.month.numeric()); + try p.ss.toss.push((year - 1900) * 256 * 256 + month * 256 + monthAndDay.day_index); // 14 try p.ss.toss.pushVector([2]i64{ fieldSize[2] - 1, fieldSize[3] - 1 }); // 13 @@ -289,7 +294,7 @@ pub const Pointer = struct { // 1 try p.ss.toss.push(0b00000); // TODO update when implementing t, i, o and = if (n > 0) { - try p.ss.toss.yCommandPick(@intCast(usize, n), height); + try p.ss.toss.yCommandPick(@intCast(n), height); } }, '(' => { diff --git a/src/stack.zig b/src/stack.zig index c1f8696..dd76af1 100644 --- a/src/stack.zig +++ b/src/stack.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const vector = std.meta.Vector(2, i64); +const vector = @Vector(2, i64); pub const Stack = struct { allocator: std.mem.Allocator, @@ -78,7 +78,7 @@ pub const Stack = struct { // (aka begin) and '}' (aka end) stackstack commands try toss.data.ensureUnusedCapacity(n); var i: usize = n; - while (i >= std.math.min(soss.data.items.len, n) + 1) : (i -= 1) { + while (i >= @min(soss.data.items.len, n) + 1) : (i -= 1) { toss.data.appendAssumeCapacity(0); } while (i >= 1) : (i -= 1) { diff --git a/src/stackStack.zig b/src/stackStack.zig index a76d304..d846429 100644 --- a/src/stackStack.zig +++ b/src/stackStack.zig @@ -28,7 +28,7 @@ pub const StackStack = struct { const n = soss.pop(); self.toss = try stack.Stack.init(self.allocator); if (n > 0) { - try self.toss.transfert(soss, @intCast(u64, n)); + try self.toss.transfert(soss, @intCast(n)); } else if (n < 0) { var i: usize = 0; while (i < -n) : (i += 1) { @@ -85,9 +85,11 @@ pub const StackStack = struct { const n = self.toss.pop(); const v = soss.popVector(); if (n > 0) { - try soss.transfert(self.toss, @intCast(u64, n)); + const nn: usize = @intCast(n); + try soss.transfert(self.toss, nn); } else { - soss.discard(@intCast(u64, -n)); + const nn: usize = @intCast(-n); + soss.discard(nn); } self.toss.deinit(); self.toss = soss; diff --git a/src/tui.zig b/src/tui.zig index 8d60bce..8c4145f 100644 --- a/src/tui.zig +++ b/src/tui.zig @@ -9,10 +9,10 @@ var intp: *interpreter.Interpreter = undefined; pub fn main() anyerror!void { //--- befunge initialization ---------------------------------------------- - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer std.debug.assert(!gpa.deinit()); - args = try std.process.argsAlloc(gpa.allocator()); - defer std.process.argsFree(gpa.allocator(), args); + var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; + const gpa = general_purpose_allocator.allocator(); + args = try std.process.argsAlloc(gpa); + defer std.process.argsFree(gpa, args); if (args.len < 2) { std.debug.print("Usage: {s} \n", .{args[0]}); std.os.exit(1); @@ -22,7 +22,7 @@ pub fn main() anyerror!void { defer file.close(); const env: []const [*:0]const u8 = std.os.environ; - intp = try interpreter.Interpreter.init(gpa.allocator(), file.reader(), null, args, env[0..]); + intp = try interpreter.Interpreter.init(gpa, file.reader(), null, args, env[0..]); defer intp.deinit(); var ioContext = io.context(std.io.getStdIn().reader(), std.io.getStdOut().writer()); // TODO io functions for tui @@ -38,11 +38,13 @@ pub fn main() anyerror!void { }, null); var fds: [1]std.os.pollfd = undefined; - fds[0] = .{ - .fd = term.tty.handle, - .events = std.os.POLL.IN, - .revents = undefined, - }; + if (term.tty) |tty| { + fds[0] = .{ + .fd = tty, + .events = std.os.POLL.IN, + .revents = undefined, + }; + } try term.uncook(.{}); defer term.cook() catch {}; @@ -68,9 +70,8 @@ pub fn main() anyerror!void { term.deinit(); intp.deinit(); file.close(); - std.process.argsFree(gpa.allocator(), args); - std.debug.assert(!gpa.deinit()); - std.os.exit(@intCast(u8, code)); + std.process.argsFree(gpa, args); + std.os.exit(@intCast(code)); } try render(); } @@ -110,7 +111,8 @@ fn render() !void { var s = rc.restrictedPaddingWriter(16); const v = intp.pointer.ss.toss.data.items[n]; if (v >= 32 and v < 127) { - try s.writer().print("{c} - {d}", .{ @intCast(u8, v), v }); + const tv: u8 = @intCast(v); + try s.writer().print("{c} - {d}", .{ tv, v }); } else { try s.writer().print("{d}", .{v}); } @@ -119,28 +121,36 @@ fn render() !void { try rc.moveCursorTo(2, 18); try rc.setAttribute(.{ .fg = .blue, .reverse = true }); var fieldTitle = rc.restrictedPaddingWriter(term.width - 17); - const size = intp.field.getSize(); + const sizei = intp.field.getSize(); + const size = [4]usize{ @intCast(sizei[0]), @intCast(sizei[1]), @intCast(sizei[2]), @intCast(sizei[3]) }; try fieldTitle.writer().print("Funge field | top left corner:({d},{d}) size:{d}x{d}", .{ size[0], size[1], size[2], size[3] }); try fieldTitle.pad(); try rc.setAttribute(.{ .fg = .blue, .reverse = false }); var y: usize = 0; // TODO negative lines - while (y < @min(@intCast(usize, size[3]), term.height - 3)) : (y += 1) { + while (y < @min(size[3], term.height - 3)) : (y += 1) { var field = rc.restrictedPaddingWriter(term.width - 17); const line = intp.field.lines.items[y]; var x: usize = 0; if (line.x >= 0) { - try rc.moveCursorTo(y + 3, 18 + @intCast(usize, line.x)); + const lx: usize = @intCast(line.x); + try rc.moveCursorTo(y + 3, 18 + lx); } else { try rc.moveCursorTo(y + 3, 18); // TODO negative columns } while (x < @min(line.data.items.len, term.width - 18)) : (x += 1) { var reset = false; - if (x + @intCast(usize, line.x) == intp.pointer.x and y == intp.pointer.y) { // TODO negatives + const xx: i64 = @intCast(x); + if (xx + line.x == intp.pointer.x and y == intp.pointer.y) { // TODO negatives try rc.setAttribute(.{ .fg = .red, .reverse = true }); reset = true; } if (line.data.items[x] >= 32 and line.data.items[x] < 127) { - try field.writer().print("{c}", .{@intCast(u8, line.data.items[x])}); + const v = line.data.items[x]; + var vv: u8 = '?'; + if (v >= 32 and v < 127) { + vv = @intCast(v); + } + try field.writer().print("{c}", .{vv}); } else { try field.writer().writeAll("®"); } -- cgit v1.2.3