authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2023-05-14 16:23:14 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2023-05-14 16:23:14 -07:00
logb70ad0161e9cad2176fe26d9a39a20eb8391b102
treef115994786d55012576ee31821c470ee616c4aeb
parenta9c50fb7d54d771a187730e7c304f18244b736bf

writeEscaped: use Utf8Iterator instead of u8 for loop


1 files changed, 38 insertions(+), 21 deletions(-)

src/lib.zig+38-21
......@@ -208,34 +208,51 @@ fn Field(comptime T: type, comptime field_name: string) type {
208208}
209209
210210pub 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| {
213216 try writer.writeAll(ent.entity);
214217 } else {
215 try writer.writeAll(&[_]u8{c});
218 try writer.writeAll(sl);
216219 }
217220 }
218221}
219222
220fn entityLookupBefore(in: string) ?htmlentities.Entity {
223fn 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
239fn isCodepointAnEntity(cp: u21) ?htmlentities.Entity {
240 switch (cp) {
241 '\n',
242 '.',
243 ':',
244 '(',
245 ')',
246 '%',
247 '+',
248 => return null,
249 else => {},
250 }
221251 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) {
239256 return e;
240257 }
241258 }