1const std = @import("std");
2const Io = std.Io;
3
4pub const UncheckedSliceWriter = struct {
5 const Self = @This();
6
7 pos: usize = 0,
8 slice: []u8,
9
10 pub fn write(self: *Self, char: u8) void {
11 self.slice[self.pos] = char;
12 self.pos += 1;
13 }
14
15 pub fn writeSlice(self: *Self, slice: []const u8) void {
16 for (slice) |c| {
17 self.write(c);
18 }
19 }
20
21 pub fn getWritten(self: Self) []u8 {
22 return self.slice[0..self.pos];
23 }
24};
25
26/// Emulates the Windows implementation of `iswdigit`, but only returns true
27/// for the non-ASCII digits that `iswdigit` on Windows would return true for.
28pub fn isNonAsciiDigit(c: u21) bool {
29 return switch (c) {
30 '²',
31 '³',
32 '¹',
33 '\u{660}'...'\u{669}',
34 '\u{6F0}'...'\u{6F9}',
35 '\u{7C0}'...'\u{7C9}',
36 '\u{966}'...'\u{96F}',
37 '\u{9E6}'...'\u{9EF}',
38 '\u{A66}'...'\u{A6F}',
39 '\u{AE6}'...'\u{AEF}',
40 '\u{B66}'...'\u{B6F}',
41 '\u{BE6}'...'\u{BEF}',
42 '\u{C66}'...'\u{C6F}',
43 '\u{CE6}'...'\u{CEF}',
44 '\u{D66}'...'\u{D6F}',
45 '\u{E50}'...'\u{E59}',
46 '\u{ED0}'...'\u{ED9}',
47 '\u{F20}'...'\u{F29}',
48 '\u{1040}'...'\u{1049}',
49 '\u{1090}'...'\u{1099}',
50 '\u{17E0}'...'\u{17E9}',
51 '\u{1810}'...'\u{1819}',
52 '\u{1946}'...'\u{194F}',
53 '\u{19D0}'...'\u{19D9}',
54 '\u{1B50}'...'\u{1B59}',
55 '\u{1BB0}'...'\u{1BB9}',
56 '\u{1C40}'...'\u{1C49}',
57 '\u{1C50}'...'\u{1C59}',
58 '\u{A620}'...'\u{A629}',
59 '\u{A8D0}'...'\u{A8D9}',
60 '\u{A900}'...'\u{A909}',
61 '\u{AA50}'...'\u{AA59}',
62 '\u{FF10}'...'\u{FF19}',
63 => true,
64 else => false,
65 };
66}
67
68pub const ErrorMessageType = enum { err, warning, note };
69
70pub fn renderErrorMessageToStderr(io: std.Io, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void {
71 var stderr = try io.lockStderr(&.{}, null);
72 defer io.unlockStderr();
73 try renderErrorMessage(stderr.terminal(), msg_type, format, args);
74}
75
76/// Used for generic colored errors/warnings/notes, more context-specific error messages
77/// are handled elsewhere.
78pub fn renderErrorMessage(t: Io.Terminal, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void {
79 const writer = t.writer;
80 switch (msg_type) {
81 .err => {
82 try t.setColor(.bold);
83 try t.setColor(.red);
84 try writer.writeAll("error: ");
85 },
86 .warning => {
87 try t.setColor(.bold);
88 try t.setColor(.yellow);
89 try writer.writeAll("warning: ");
90 },
91 .note => {
92 try t.setColor(.reset);
93 try t.setColor(.cyan);
94 try writer.writeAll("note: ");
95 },
96 }
97 try t.setColor(.reset);
98 if (msg_type == .err) {
99 try t.setColor(.bold);
100 }
101 try writer.print(format, args);
102 try writer.writeByte('\n');
103 try t.setColor(.reset);
104}
105
106pub fn isLineEndingPair(first: u8, second: u8) bool {
107 if (first != '\r' and first != '\n') return false;
108 if (second != '\r' and second != '\n') return false;
109
110 // can't be \n\n or \r\r
111 if (first == second) return false;
112
113 return true;
114}