| ... | @@ -12,7 +12,7 @@ pub fn formatId( | ... | @@ -12,7 +12,7 @@ pub fn formatId( |
| 12 | return writer.writeAll(bytes); | 12 | return writer.writeAll(bytes); |
| 13 | } | 13 | } |
| 14 | try writer.writeAll("@\""); | 14 | try writer.writeAll("@\""); |
| 15 | try formatEscapes(bytes, fmt, options, writer); | 15 | try formatEscapes(bytes, "", options, writer); |
| 16 | try writer.writeByte('"'); | 16 | try writer.writeByte('"'); |
| 17 | } | 17 | } |
| 18 | | 18 | |
| ... | @@ -32,6 +32,9 @@ pub fn isValidId(bytes: []const u8) bool { | ... | @@ -32,6 +32,9 @@ pub fn isValidId(bytes: []const u8) bool { |
| 32 | return std.zig.Token.getKeyword(bytes) == null; | 32 | return std.zig.Token.getKeyword(bytes) == null; |
| 33 | } | 33 | } |
| 34 | | 34 | |
| | 35 | /// Print the string as escaped contents of a double quoted or single-quoted string. |
| | 36 | /// Format `{}` treats contents as a double-quoted string. |
| | 37 | /// Format `{'}` treats contents as a single-quoted string. |
| 35 | pub fn formatEscapes( | 38 | pub fn formatEscapes( |
| 36 | bytes: []const u8, | 39 | bytes: []const u8, |
| 37 | comptime fmt: []const u8, | 40 | comptime fmt: []const u8, |
| ... | @@ -43,8 +46,24 @@ pub fn formatEscapes( | ... | @@ -43,8 +46,24 @@ pub fn formatEscapes( |
| 43 | '\r' => try writer.writeAll("\\r"), | 46 | '\r' => try writer.writeAll("\\r"), |
| 44 | '\t' => try writer.writeAll("\\t"), | 47 | '\t' => try writer.writeAll("\\t"), |
| 45 | '\\' => try writer.writeAll("\\\\"), | 48 | '\\' => try writer.writeAll("\\\\"), |
| 46 | '"' => try writer.writeAll("\\\""), | 49 | '"' => { |
| 47 | '\'' => try writer.writeAll("\\'"), | 50 | if (fmt.len == 1 and fmt[0] == '\'') { |
| | 51 | try writer.writeByte('"'); |
| | 52 | } else if (fmt.len == 0) { |
| | 53 | try writer.writeAll("\\\""); |
| | 54 | } else { |
| | 55 | @compileError("expected {} or {'}, found {" ++ fmt ++ "}"); |
| | 56 | } |
| | 57 | }, |
| | 58 | '\'' => { |
| | 59 | if (fmt.len == 1 and fmt[0] == '\'') { |
| | 60 | try writer.writeAll("\\'"); |
| | 61 | } else if (fmt.len == 0) { |
| | 62 | try writer.writeByte('\''); |
| | 63 | } else { |
| | 64 | @compileError("expected {} or {'}, found {" ++ fmt ++ "}"); |
| | 65 | } |
| | 66 | }, |
| 48 | ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte), | 67 | ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte), |
| 49 | // Use hex escapes for rest any unprintable characters. | 68 | // Use hex escapes for rest any unprintable characters. |
| 50 | else => { | 69 | else => { |
| ... | @@ -54,7 +73,10 @@ pub fn formatEscapes( | ... | @@ -54,7 +73,10 @@ pub fn formatEscapes( |
| 54 | }; | 73 | }; |
| 55 | } | 74 | } |
| 56 | | 75 | |
| 57 | /// Return a Formatter for Zig Escapes | 76 | /// Return a Formatter for Zig Escapes of a double quoted string. |
| | 77 | /// The format specifier must be one of: |
| | 78 | /// * `{}` treats contents as a double-quoted string. |
| | 79 | /// * `{'}` treats contents as a single-quoted string. |
| 58 | pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(formatEscapes) { | 80 | pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(formatEscapes) { |
| 59 | return .{ .data = bytes }; | 81 | return .{ .data = bytes }; |
| 60 | } | 82 | } |
| ... | @@ -67,6 +89,9 @@ test "escape invalid identifiers" { | ... | @@ -67,6 +89,9 @@ test "escape invalid identifiers" { |
| 67 | try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")}); | 89 | try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")}); |
| 68 | try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")}); | 90 | try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")}); |
| 69 | try expectFmt( | 91 | try expectFmt( |
| 70 | \\" \\ hi \x07 \x11 \" derp \'" | 92 | \\" \\ hi \x07 \x11 " derp \'" |
| | 93 | , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); |
| | 94 | try expectFmt( |
| | 95 | \\" \\ hi \x07 \x11 \" derp '" |
| 71 | , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); | 96 | , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); |
| 72 | } | 97 | } |