| ... | ... | @@ -208,34 +208,51 @@ fn Field(comptime T: type, comptime field_name: string) type { |
| 208 | 208 | } |
| 209 | 209 | |
| 210 | 210 | pub fn writeEscaped(s: string, writer: anytype) !void { |
| 211 | | for (s) |c| { |
| 212 | | if (entityLookupBefore(&[_]u8{c})) |ent| { |
| 211 | const view = std.unicode.Utf8View.initUnchecked(s); |
| 212 | var iter = view.iterator(); |
| 213 | while (nextCodepointSliceLossy(&iter)) |sl| { |
| 214 | const cp = std.unicode.utf8Decode(sl) catch unreachable; |
| 215 | if (isCodepointAnEntity(cp)) |ent| { |
| 213 | 216 | try writer.writeAll(ent.entity); |
| 214 | 217 | } else { |
| 215 | | try writer.writeAll(&[_]u8{c}); |
| 218 | try writer.writeAll(sl); |
| 216 | 219 | } |
| 217 | 220 | } |
| 218 | 221 | } |
| 219 | 222 | |
| 220 | | fn entityLookupBefore(in: string) ?htmlentities.Entity { |
| 223 | fn nextCodepointSliceLossy(it: *std.unicode.Utf8Iterator) ?[]const u8 { |
| 224 | if (it.i >= it.bytes.len) return null; |
| 225 | const cp_len = std.unicode.utf8ByteSequenceLength(it.bytes[it.i]) catch { |
| 226 | it.i += 1; |
| 227 | return "�"; |
| 228 | }; |
| 229 | if (it.i + cp_len > it.bytes.len) return null; |
| 230 | const maybe = it.bytes[it.i..][0..cp_len]; |
| 231 | _ = std.unicode.utf8Decode(maybe) catch { |
| 232 | it.i += 1; |
| 233 | return "�"; |
| 234 | }; |
| 235 | it.i += cp_len; |
| 236 | return maybe; |
| 237 | } |
| 238 | |
| 239 | fn isCodepointAnEntity(cp: u21) ?htmlentities.Entity { |
| 240 | switch (cp) { |
| 241 | '\n', |
| 242 | '.', |
| 243 | ':', |
| 244 | '(', |
| 245 | ')', |
| 246 | '%', |
| 247 | '+', |
| 248 | => return null, |
| 249 | else => {}, |
| 250 | } |
| 221 | 251 | for (htmlentities.ENTITIES) |e| { |
| 222 | | if (!std.mem.endsWith(u8, e.entity, ";")) { |
| 223 | | continue; |
| 224 | | } |
| 225 | | if (in.len == 1) { |
| 226 | | switch (in[0]) { |
| 227 | | '\n', |
| 228 | | '.', |
| 229 | | ':', |
| 230 | | '(', |
| 231 | | ')', |
| 232 | | '%', |
| 233 | | '+', |
| 234 | | => return null, |
| 235 | | else => {}, |
| 236 | | } |
| 237 | | } |
| 238 | | if (std.mem.eql(u8, e.characters, in)) { |
| 252 | if (e.entity.len == 0) continue; |
| 253 | if (e.entity[e.entity.len - 1] != ';') continue; |
| 254 | |
| 255 | if (e.codepoints == .Single and e.codepoints.Single == cp) { |
| 239 | 256 | return e; |
| 240 | 257 | } |
| 241 | 258 | } |