utils.zig (3827B) - Raw
1 const std = @import("std"); 2 const builtin = @import("builtin"); 3 4 /// Like std.io.FixedBufferStream but does no bounds checking 5 pub const UncheckedSliceWriter = struct { 6 const Self = @This(); 7 8 pos: usize = 0, 9 slice: []u8, 10 11 pub fn write(self: *Self, char: u8) void { 12 self.slice[self.pos] = char; 13 self.pos += 1; 14 } 15 16 pub fn writeSlice(self: *Self, slice: []const u8) void { 17 for (slice) |c| { 18 self.write(c); 19 } 20 } 21 22 pub fn getWritten(self: Self) []u8 { 23 return self.slice[0..self.pos]; 24 } 25 }; 26 27 /// Cross-platform 'std.fs.Dir.openFile' wrapper that will always return IsDir if 28 /// a directory is attempted to be opened. 29 /// TODO: Remove once https://github.com/ziglang/zig/issues/5732 is addressed. 30 pub fn openFileNotDir(cwd: std.fs.Dir, path: []const u8, flags: std.fs.File.OpenFlags) std.fs.File.OpenError!std.fs.File { 31 const file = try cwd.openFile(path, flags); 32 errdefer file.close(); 33 // https://github.com/ziglang/zig/issues/5732 34 if (builtin.os.tag != .windows) { 35 const stat = try file.stat(); 36 37 if (stat.kind == .directory) 38 return error.IsDir; 39 } 40 return file; 41 } 42 43 /// Emulates the Windows implementation of `iswdigit`, but only returns true 44 /// for the non-ASCII digits that `iswdigit` on Windows would return true for. 45 pub fn isNonAsciiDigit(c: u21) bool { 46 return switch (c) { 47 '²', 48 '³', 49 '¹', 50 '\u{660}'...'\u{669}', 51 '\u{6F0}'...'\u{6F9}', 52 '\u{7C0}'...'\u{7C9}', 53 '\u{966}'...'\u{96F}', 54 '\u{9E6}'...'\u{9EF}', 55 '\u{A66}'...'\u{A6F}', 56 '\u{AE6}'...'\u{AEF}', 57 '\u{B66}'...'\u{B6F}', 58 '\u{BE6}'...'\u{BEF}', 59 '\u{C66}'...'\u{C6F}', 60 '\u{CE6}'...'\u{CEF}', 61 '\u{D66}'...'\u{D6F}', 62 '\u{E50}'...'\u{E59}', 63 '\u{ED0}'...'\u{ED9}', 64 '\u{F20}'...'\u{F29}', 65 '\u{1040}'...'\u{1049}', 66 '\u{1090}'...'\u{1099}', 67 '\u{17E0}'...'\u{17E9}', 68 '\u{1810}'...'\u{1819}', 69 '\u{1946}'...'\u{194F}', 70 '\u{19D0}'...'\u{19D9}', 71 '\u{1B50}'...'\u{1B59}', 72 '\u{1BB0}'...'\u{1BB9}', 73 '\u{1C40}'...'\u{1C49}', 74 '\u{1C50}'...'\u{1C59}', 75 '\u{A620}'...'\u{A629}', 76 '\u{A8D0}'...'\u{A8D9}', 77 '\u{A900}'...'\u{A909}', 78 '\u{AA50}'...'\u{AA59}', 79 '\u{FF10}'...'\u{FF19}', 80 => true, 81 else => false, 82 }; 83 } 84 85 pub const ErrorMessageType = enum { err, warning, note }; 86 87 /// Used for generic colored errors/warnings/notes, more context-specific error messages 88 /// are handled elsewhere. 89 pub fn renderErrorMessage(writer: *std.io.Writer, config: std.io.tty.Config, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void { 90 switch (msg_type) { 91 .err => { 92 try config.setColor(writer, .bold); 93 try config.setColor(writer, .red); 94 try writer.writeAll("error: "); 95 }, 96 .warning => { 97 try config.setColor(writer, .bold); 98 try config.setColor(writer, .yellow); 99 try writer.writeAll("warning: "); 100 }, 101 .note => { 102 try config.setColor(writer, .reset); 103 try config.setColor(writer, .cyan); 104 try writer.writeAll("note: "); 105 }, 106 } 107 try config.setColor(writer, .reset); 108 if (msg_type == .err) { 109 try config.setColor(writer, .bold); 110 } 111 try writer.print(format, args); 112 try writer.writeByte('\n'); 113 try config.setColor(writer, .reset); 114 } 115 116 pub fn isLineEndingPair(first: u8, second: u8) bool { 117 if (first != '\r' and first != '\n') return false; 118 if (second != '\r' and second != '\n') return false; 119 120 // can't be \n\n or \r\r 121 if (first == second) return false; 122 123 return true; 124 }