diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index b344cc8a9d..340a35bdde 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -134,8 +134,9 @@ strip: bool = false, unwindlib: ?[]const u8 = null, pub fn deinit(d: *Driver) void { + const io = d.comp.io; for (d.link_objects.items[d.link_objects.items.len - d.temp_file_count ..]) |obj| { - std.fs.deleteFileAbsolute(obj) catch {}; + Io.Dir.deleteFileAbsolute(io, obj) catch {}; d.comp.gpa.free(obj); } d.inputs.deinit(d.comp.gpa); diff --git a/lib/compiler/resinator/cli.zig b/lib/compiler/resinator/cli.zig index ddf3ca18b7..59843585a2 100644 --- a/lib/compiler/resinator/cli.zig +++ b/lib/compiler/resinator/cli.zig @@ -125,8 +125,8 @@ pub const Diagnostics = struct { try self.errors.append(self.allocator, error_details); } - pub fn renderToStderr(self: *Diagnostics, io: Io, args: []const []const u8) void { - const stderr = io.lockStderr(&.{}, null); + pub fn renderToStderr(self: *Diagnostics, io: Io, args: []const []const u8) Io.Cancelable!void { + const stderr = try io.lockStderr(&.{}, null); defer io.unlockStderr(); self.renderToWriter(args, stderr.terminal()) catch return; } @@ -419,7 +419,7 @@ pub const Arg = struct { }; } - pub fn looksLikeFilepath(self: Arg) bool { + pub fn looksLikeFilepath(self: Arg, io: Io) bool { const meets_min_requirements = self.prefix == .slash and isSupportedInputExtension(std.fs.path.extension(self.full)); if (!meets_min_requirements) return false; @@ -438,7 +438,7 @@ pub const Arg = struct { // It's still possible for a file path to look like a /fo option but not actually // be one, e.g. `/foo/bar.rc`. As a last ditch effort to reduce false negatives, // check if the file path exists and, if so, then we ignore the 'could be /fo option'-ness - std.fs.accessAbsolute(self.full, .{}) catch return false; + Io.Dir.accessAbsolute(io, self.full, .{}) catch return false; return true; } @@ -490,7 +490,7 @@ pub const ParseError = error{ParseError} || Allocator.Error; /// Note: Does not run `Options.maybeAppendRC` automatically. If that behavior is desired, /// it must be called separately. -pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagnostics) ParseError!Options { +pub fn parse(allocator: Allocator, io: Io, args: []const []const u8, diagnostics: *Diagnostics) ParseError!Options { var options = Options{ .allocator = allocator }; errdefer options.deinit(); @@ -530,7 +530,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn } const args_remaining = args.len - arg_i; - if (args_remaining <= 2 and arg.looksLikeFilepath()) { + if (args_remaining <= 2 and arg.looksLikeFilepath(io)) { var err_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i }; try err_details.msg.appendSlice(allocator, "this argument was inferred to be a filepath, so argument parsing was terminated"); try diagnostics.append(err_details); @@ -1344,41 +1344,42 @@ test parsePercent { try std.testing.expectError(error.InvalidFormat, parsePercent("~1")); } -pub fn renderErrorMessage(writer: *std.Io.Writer, config: std.Io.tty.Config, err_details: Diagnostics.ErrorDetails, args: []const []const u8) !void { - try config.setColor(writer, .dim); +pub fn renderErrorMessage(t: Io.Terminal, err_details: Diagnostics.ErrorDetails, args: []const []const u8) !void { + const writer = t.writer; + try t.setColor(.dim); try writer.writeAll(""); - try config.setColor(writer, .reset); - try config.setColor(writer, .bold); + try t.setColor(.reset); + try t.setColor(.bold); try writer.writeAll(": "); switch (err_details.type) { .err => { - try config.setColor(writer, .red); + try t.setColor(.red); try writer.writeAll("error: "); }, .warning => { - try config.setColor(writer, .yellow); + try t.setColor(.yellow); try writer.writeAll("warning: "); }, .note => { - try config.setColor(writer, .cyan); + try t.setColor(.cyan); try writer.writeAll("note: "); }, } - try config.setColor(writer, .reset); - try config.setColor(writer, .bold); + try t.setColor(.reset); + try t.setColor(.bold); try writer.writeAll(err_details.msg.items); try writer.writeByte('\n'); - try config.setColor(writer, .reset); + try t.setColor(.reset); if (!err_details.print_args) { try writer.writeByte('\n'); return; } - try config.setColor(writer, .dim); + try t.setColor(.dim); const prefix = " ... "; try writer.writeAll(prefix); - try config.setColor(writer, .reset); + try t.setColor(.reset); const arg_with_name = args[err_details.arg_index]; const prefix_slice = arg_with_name[0..err_details.arg_span.prefix_len]; @@ -1389,15 +1390,15 @@ pub fn renderErrorMessage(writer: *std.Io.Writer, config: std.Io.tty.Config, err try writer.writeAll(prefix_slice); if (before_name_slice.len > 0) { - try config.setColor(writer, .dim); + try t.setColor(.dim); try writer.writeAll(before_name_slice); - try config.setColor(writer, .reset); + try t.setColor(.reset); } try writer.writeAll(name_slice); if (after_name_slice.len > 0) { - try config.setColor(writer, .dim); + try t.setColor(.dim); try writer.writeAll(after_name_slice); - try config.setColor(writer, .reset); + try t.setColor(.reset); } var next_arg_len: usize = 0; @@ -1415,13 +1416,13 @@ pub fn renderErrorMessage(writer: *std.Io.Writer, config: std.Io.tty.Config, err if (err_details.arg_span.value_offset >= arg_with_name.len) { try writer.writeByte(' '); } - try config.setColor(writer, .dim); + try t.setColor(.dim); try writer.writeAll(" ..."); - try config.setColor(writer, .reset); + try t.setColor(.reset); } try writer.writeByte('\n'); - try config.setColor(writer, .green); + try t.setColor(.green); try writer.splatByteAll(' ', prefix.len); // Special case for when the option is *only* a prefix (e.g. invalid option: -) if (err_details.arg_span.prefix_len == arg_with_name.len) { @@ -1447,7 +1448,7 @@ pub fn renderErrorMessage(writer: *std.Io.Writer, config: std.Io.tty.Config, err } } try writer.writeByte('\n'); - try config.setColor(writer, .reset); + try t.setColor(.reset); } fn testParse(args: []const []const u8) !Options { diff --git a/lib/compiler/resinator/compile.zig b/lib/compiler/resinator/compile.zig index 2d6ea87efb..4f75fca18a 100644 --- a/lib/compiler/resinator/compile.zig +++ b/lib/compiler/resinator/compile.zig @@ -96,7 +96,7 @@ pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io var search_dirs: std.ArrayList(SearchDir) = .empty; defer { for (search_dirs.items) |*search_dir| { - search_dir.deinit(allocator); + search_dir.deinit(allocator, io); } search_dirs.deinit(allocator); } @@ -406,7 +406,7 @@ pub const Compiler = struct { // `/test.bin` relative to include paths and instead only treats it as // an absolute path. if (std.fs.path.isAbsolute(path)) { - const file = try utils.openFileNotDir(Io.Dir.cwd(), path, .{}); + const file = try utils.openFileNotDir(Io.Dir.cwd(), io, path, .{}); errdefer file.close(io); if (self.dependencies) |dependencies| { @@ -418,7 +418,7 @@ pub const Compiler = struct { var first_error: ?(std.Io.File.OpenError || std.Io.File.StatError) = null; for (self.search_dirs) |search_dir| { - if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| { + if (utils.openFileNotDir(search_dir.dir, io, path, .{})) |file| { errdefer file.close(io); if (self.dependencies) |dependencies| { diff --git a/lib/compiler/resinator/errors.zig b/lib/compiler/resinator/errors.zig index 6146f777cd..4f41a5b56d 100644 --- a/lib/compiler/resinator/errors.zig +++ b/lib/compiler/resinator/errors.zig @@ -67,9 +67,9 @@ pub const Diagnostics = struct { return @intCast(index); } - pub fn renderToStderr(self: *Diagnostics, cwd: Io.Dir, source: []const u8, source_mappings: ?SourceMappings) void { + pub fn renderToStderr(self: *Diagnostics, cwd: Io.Dir, source: []const u8, source_mappings: ?SourceMappings) Io.Cancelable!void { const io = self.io; - const stderr = io.lockStderr(&.{}, null); + const stderr = try io.lockStderr(&.{}, null); defer io.unlockStderr(); for (self.errors.items) |err_details| { renderErrorMessage(io, stderr.terminal(), cwd, err_details, source, self.strings.items, source_mappings) catch return; @@ -901,8 +901,7 @@ const truncated_str = "<...truncated...>"; pub fn renderErrorMessage( io: Io, - writer: *std.Io.Writer, - tty_config: std.Io.tty.Config, + t: Io.Terminal, cwd: Io.Dir, err_details: ErrorDetails, source: []const u8, @@ -927,36 +926,37 @@ pub fn renderErrorMessage( const err_line = if (corresponding_span) |span| span.start_line else err_details.token.line_number; - try tty_config.setColor(writer, .bold); + const writer = t.writer; + try t.setColor(.bold); if (corresponding_file) |file| { try writer.writeAll(file); } else { - try tty_config.setColor(writer, .dim); + try t.setColor(.dim); try writer.writeAll(""); - try tty_config.setColor(writer, .reset); - try tty_config.setColor(writer, .bold); + try t.setColor(.reset); + try t.setColor(.bold); } try writer.print(":{d}:{d}: ", .{ err_line, column }); switch (err_details.type) { .err => { - try tty_config.setColor(writer, .red); + try t.setColor(.red); try writer.writeAll("error: "); }, .warning => { - try tty_config.setColor(writer, .yellow); + try t.setColor(.yellow); try writer.writeAll("warning: "); }, .note => { - try tty_config.setColor(writer, .cyan); + try t.setColor(.cyan); try writer.writeAll("note: "); }, .hint => unreachable, } - try tty_config.setColor(writer, .reset); - try tty_config.setColor(writer, .bold); + try t.setColor(.reset); + try t.setColor(.bold); try err_details.render(writer, source, strings); try writer.writeByte('\n'); - try tty_config.setColor(writer, .reset); + try t.setColor(.reset); if (!err_details.print_source_line) { try writer.writeByte('\n'); @@ -983,20 +983,20 @@ pub fn renderErrorMessage( try writer.writeAll(source_line_for_display.line); if (source_line_for_display.truncated) { - try tty_config.setColor(writer, .dim); + try t.setColor(.dim); try writer.writeAll(truncated_str); - try tty_config.setColor(writer, .reset); + try t.setColor(.reset); } try writer.writeByte('\n'); - try tty_config.setColor(writer, .green); + try t.setColor(.green); const num_spaces = truncated_visual_info.point_offset - truncated_visual_info.before_len; try writer.splatByteAll(' ', num_spaces); try writer.splatByteAll('~', truncated_visual_info.before_len); try writer.writeByte('^'); try writer.splatByteAll('~', truncated_visual_info.after_len); try writer.writeByte('\n'); - try tty_config.setColor(writer, .reset); + try t.setColor(.reset); if (corresponding_span != null and corresponding_file != null) { var worth_printing_lines: bool = true; @@ -1021,22 +1021,22 @@ pub fn renderErrorMessage( break :blk null; }, }; - defer if (corresponding_lines) |*cl| cl.deinit(); + defer if (corresponding_lines) |*cl| cl.deinit(io); - try tty_config.setColor(writer, .bold); + try t.setColor(.bold); if (corresponding_file) |file| { try writer.writeAll(file); } else { - try tty_config.setColor(writer, .dim); + try t.setColor(.dim); try writer.writeAll(""); - try tty_config.setColor(writer, .reset); - try tty_config.setColor(writer, .bold); + try t.setColor(.reset); + try t.setColor(.bold); } try writer.print(":{d}:{d}: ", .{ err_line, column }); - try tty_config.setColor(writer, .cyan); + try t.setColor(.cyan); try writer.writeAll("note: "); - try tty_config.setColor(writer, .reset); - try tty_config.setColor(writer, .bold); + try t.setColor(.reset); + try t.setColor(.bold); try writer.writeAll("this line originated from line"); if (corresponding_span.?.start_line != corresponding_span.?.end_line) { try writer.print("s {}-{}", .{ corresponding_span.?.start_line, corresponding_span.?.end_line }); @@ -1044,7 +1044,7 @@ pub fn renderErrorMessage( try writer.print(" {}", .{corresponding_span.?.start_line}); } try writer.print(" of file '{s}'\n", .{corresponding_file.?}); - try tty_config.setColor(writer, .reset); + try t.setColor(.reset); if (!worth_printing_lines) return; @@ -1055,21 +1055,21 @@ pub fn renderErrorMessage( }) |display_line| { try writer.writeAll(display_line.line); if (display_line.truncated) { - try tty_config.setColor(writer, .dim); + try t.setColor(.dim); try writer.writeAll(truncated_str); - try tty_config.setColor(writer, .reset); + try t.setColor(.reset); } try writer.writeByte('\n'); } break :write_lines null; }; if (write_lines_err) |err| { - try tty_config.setColor(writer, .red); + try t.setColor(.red); try writer.writeAll(" | "); - try tty_config.setColor(writer, .reset); - try tty_config.setColor(writer, .dim); + try t.setColor(.reset); + try t.setColor(.dim); try writer.print("unable to print line(s) from file: {s}\n", .{@errorName(err)}); - try tty_config.setColor(writer, .reset); + try t.setColor(.reset); } try writer.writeByte('\n'); } @@ -1120,12 +1120,12 @@ const CorrespondingLines = struct { var corresponding_lines = CorrespondingLines{ .span = corresponding_span, - .file = try utils.openFileNotDir(cwd, corresponding_file, .{}), + .file = try utils.openFileNotDir(cwd, io, corresponding_file, .{}), .code_page = err_details.code_page, .file_reader = undefined, }; corresponding_lines.file_reader = corresponding_lines.file.reader(io, file_reader_buf); - errdefer corresponding_lines.deinit(); + errdefer corresponding_lines.deinit(io); try corresponding_lines.writeLineFromStreamVerbatim( &corresponding_lines.file_reader.interface, diff --git a/lib/compiler/resinator/main.zig b/lib/compiler/resinator/main.zig index 7e2e8403ca..f311b2a512 100644 --- a/lib/compiler/resinator/main.zig +++ b/lib/compiler/resinator/main.zig @@ -64,18 +64,18 @@ pub fn main() !void { var options = options: { var cli_diagnostics = cli.Diagnostics.init(gpa); defer cli_diagnostics.deinit(); - var options = cli.parse(gpa, cli_args, &cli_diagnostics) catch |err| switch (err) { + var options = cli.parse(gpa, io, cli_args, &cli_diagnostics) catch |err| switch (err) { error.ParseError => { - try error_handler.emitCliDiagnostics(gpa, cli_args, &cli_diagnostics); + try error_handler.emitCliDiagnostics(gpa, io, cli_args, &cli_diagnostics); std.process.exit(1); }, else => |e| return e, }; - try options.maybeAppendRC(Io.Dir.cwd()); + try options.maybeAppendRC(io, Io.Dir.cwd()); if (!zig_integration) { // print any warnings/notes - cli_diagnostics.renderToStderr(io, cli_args); + try cli_diagnostics.renderToStderr(io, cli_args); // If there was something printed, then add an extra newline separator // so that there is a clear separation between the cli diagnostics and whatever // gets printed after @@ -193,7 +193,7 @@ pub fn main() !void { }; }, .filename => |input_filename| { - break :full_input Io.Dir.cwd().readFileAlloc(input_filename, gpa, .unlimited) catch |err| { + break :full_input Io.Dir.cwd().readFileAlloc(io, input_filename, gpa, .unlimited) catch |err| { try error_handler.emitMessage(gpa, io, .err, "unable to read input file path '{s}': {s}", .{ input_filename, @errorName(err) }); std.process.exit(1); }; @@ -206,7 +206,7 @@ pub fn main() !void { if (options.preprocess == .only) { switch (options.output_source) { .stdio => |output_file| { - try output_file.writeAll(full_input); + try output_file.writeStreamingAll(io, full_input); }, .filename => |output_filename| { try Io.Dir.cwd().writeFile(io, .{ .sub_path = output_filename, .data = full_input }); @@ -224,16 +224,16 @@ pub fn main() !void { .source = .{ .memory = .empty }, } else if (options.input_format == .res) - IoStream.fromIoSource(options.input_source, .input) catch |err| { + IoStream.fromIoSource(io, options.input_source, .input) catch |err| { try error_handler.emitMessage(gpa, io, .err, "unable to read res file path '{s}': {s}", .{ options.input_source.filename, @errorName(err) }); std.process.exit(1); } else - IoStream.fromIoSource(options.output_source, .output) catch |err| { + IoStream.fromIoSource(io, options.output_source, .output) catch |err| { try error_handler.emitMessage(gpa, io, .err, "unable to create output file '{s}': {s}", .{ options.output_source.filename, @errorName(err) }); std.process.exit(1); }; - defer res_stream.deinit(gpa); + defer res_stream.deinit(gpa, io); const res_data = res_data: { if (options.input_format != .res) { @@ -269,7 +269,7 @@ pub fn main() !void { defer diagnostics.deinit(); var output_buffer: [4096]u8 = undefined; - var res_stream_writer = res_stream.source.writer(gpa, &output_buffer); + var res_stream_writer = res_stream.source.writer(gpa, io, &output_buffer); defer res_stream_writer.deinit(&res_stream.source); const output_buffered_stream = res_stream_writer.interface(); @@ -303,7 +303,7 @@ pub fn main() !void { // print any warnings/notes if (!zig_integration) { - diagnostics.renderToStderr(io, Io.Dir.cwd(), final_input, mapping_results.mappings); + try diagnostics.renderToStderr(Io.Dir.cwd(), final_input, mapping_results.mappings); } // write the depfile @@ -356,14 +356,14 @@ pub fn main() !void { }; defer resources.deinit(); - var coff_stream = IoStream.fromIoSource(options.output_source, .output) catch |err| { + var coff_stream = IoStream.fromIoSource(io, options.output_source, .output) catch |err| { try error_handler.emitMessage(gpa, io, .err, "unable to create output file '{s}': {s}", .{ options.output_source.filename, @errorName(err) }); std.process.exit(1); }; - defer coff_stream.deinit(gpa); + defer coff_stream.deinit(gpa, io); var coff_output_buffer: [4096]u8 = undefined; - var coff_output_buffered_stream = coff_stream.source.writer(gpa, &coff_output_buffer); + var coff_output_buffered_stream = coff_stream.source.writer(gpa, io, &coff_output_buffer); var cvtres_diagnostics: cvtres.Diagnostics = .{ .none = {} }; cvtres.writeCoff(gpa, coff_output_buffered_stream.interface(), resources.list.items, options.coff_options, &cvtres_diagnostics) catch |err| { @@ -413,22 +413,22 @@ const IoStream = struct { pub const IoDirection = enum { input, output }; - pub fn fromIoSource(source: cli.Options.IoSource, io: IoDirection) !IoStream { + pub fn fromIoSource(io: Io, source: cli.Options.IoSource, io_direction: IoDirection) !IoStream { return .{ .name = switch (source) { .filename => |filename| filename, - .stdio => switch (io) { + .stdio => switch (io_direction) { .input => "", .output => "", }, }, .intermediate = false, - .source = try Source.fromIoSource(source, io), + .source = try Source.fromIoSource(io, source, io_direction), }; } - pub fn deinit(self: *IoStream, allocator: Allocator) void { - self.source.deinit(allocator); + pub fn deinit(self: *IoStream, allocator: Allocator, io: Io) void { + self.source.deinit(allocator, io); } pub fn cleanupAfterError(self: *IoStream, io: Io) void { @@ -450,11 +450,11 @@ const IoStream = struct { /// The source has been closed and any usage of the Source in this state is illegal (except deinit). closed: void, - pub fn fromIoSource(source: cli.Options.IoSource, io: IoDirection) !Source { + pub fn fromIoSource(io: Io, source: cli.Options.IoSource, io_direction: IoDirection) !Source { switch (source) { .filename => |filename| return .{ - .file = switch (io) { - .input => try openFileNotDir(Io.Dir.cwd(), filename, .{}), + .file = switch (io_direction) { + .input => try openFileNotDir(Io.Dir.cwd(), io, filename, .{}), .output => try Io.Dir.cwd().createFile(io, filename, .{}), }, }, @@ -641,7 +641,7 @@ fn getIncludePaths( }; const target = std.zig.resolveTargetQueryOrFatal(io, target_query); const is_native_abi = target_query.isNativeAbi(); - const detected_libc = std.zig.LibCDirs.detect(arena, zig_lib_dir, &target, is_native_abi, true, null) catch |err| switch (err) { + const detected_libc = std.zig.LibCDirs.detect(arena, io, zig_lib_dir, &target, is_native_abi, true, null) catch |err| switch (err) { error.OutOfMemory => |e| return e, else => return error.MingwIncludesNotFound, }; @@ -672,7 +672,7 @@ const ErrorHandler = union(enum) { try server.serveErrorBundle(error_bundle); }, - .stderr => diagnostics.renderToStderr(io, args), + .stderr => return diagnostics.renderToStderr(io, args), } } @@ -696,7 +696,7 @@ const ErrorHandler = union(enum) { }, .stderr => { // aro errors have already been emitted - const stderr = io.lockStderr(&.{}, null); + const stderr = try io.lockStderr(&.{}, null); defer io.unlockStderr(); try renderErrorMessage(stderr.terminal(), .err, "{s}", .{fail_msg}); }, @@ -706,7 +706,6 @@ const ErrorHandler = union(enum) { pub fn emitDiagnostics( self: *ErrorHandler, allocator: Allocator, - io: Io, cwd: Io.Dir, source: []const u8, diagnostics: *Diagnostics, @@ -719,7 +718,7 @@ const ErrorHandler = union(enum) { try server.serveErrorBundle(error_bundle); }, - .stderr => diagnostics.renderToStderr(io, cwd, source, mappings), + .stderr => return diagnostics.renderToStderr(cwd, source, mappings), } } diff --git a/lib/compiler/resinator/utils.zig b/lib/compiler/resinator/utils.zig index 285342ad74..42d3cc5e31 100644 --- a/lib/compiler/resinator/utils.zig +++ b/lib/compiler/resinator/utils.zig @@ -92,31 +92,32 @@ pub const ErrorMessageType = enum { err, warning, note }; /// Used for generic colored errors/warnings/notes, more context-specific error messages /// are handled elsewhere. -pub fn renderErrorMessage(writer: *std.Io.Writer, config: std.Io.tty.Config, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void { +pub fn renderErrorMessage(t: Io.Terminal, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void { + const writer = t.writer; switch (msg_type) { .err => { - try config.setColor(writer, .bold); - try config.setColor(writer, .red); + try t.setColor(.bold); + try t.setColor(.red); try writer.writeAll("error: "); }, .warning => { - try config.setColor(writer, .bold); - try config.setColor(writer, .yellow); + try t.setColor(.bold); + try t.setColor(.yellow); try writer.writeAll("warning: "); }, .note => { - try config.setColor(writer, .reset); - try config.setColor(writer, .cyan); + try t.setColor(.reset); + try t.setColor(.cyan); try writer.writeAll("note: "); }, } - try config.setColor(writer, .reset); + try t.setColor(.reset); if (msg_type == .err) { - try config.setColor(writer, .bold); + try t.setColor(.bold); } try writer.print(format, args); try writer.writeByte('\n'); - try config.setColor(writer, .reset); + try t.setColor(.reset); } pub fn isLineEndingPair(first: u8, second: u8) bool {