Skip to content

Commit 0aea845

Browse files
committed
axtree: a better write string
1 parent 9696bb5 commit 0aea845

File tree

1 file changed

+70
-19
lines changed

1 file changed

+70
-19
lines changed

src/cdp/AXNode.zig

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -881,31 +881,82 @@ pub const Walker = struct {
881881
}
882882
};
883883

884-
// write a JSON string.
885-
// replaces all whitspaces with a single space.
884+
// Replace successives whitespaces with one withespace.
885+
// Trims left and right according to the options.
886+
// Returns true if the string ends with a trimmed whitespace.
886887
fn writeString(s: []const u8, w: anytype) !void {
887-
if (!std.unicode.utf8ValidateSlice(s)) {
888-
return error.InvalidUTF8String;
889-
}
890-
891-
// replace white spaces with single space.
892888
try w.beginWriteRaw();
893889
try w.writer.writeByte('\"');
894-
var cursor: usize = 0;
890+
try stripWhitespaces(s, w.writer);
891+
try w.writer.writeByte('\"');
892+
w.endWriteRaw();
893+
}
894+
895+
fn stripWhitespaces(s: []const u8, writer: anytype) !void {
896+
var start: usize = 0;
897+
var prev_w: ?bool = null;
898+
var is_w: bool = undefined;
899+
895900
for (s, 0..) |c, i| {
896-
if (std.ascii.isWhitespace(c)) {
897-
// write string until space
898-
if (cursor < i) {
899-
try w.writer.writeAll(s[cursor..i]);
900-
try w.writer.writeByte(' ');
901+
is_w = std.ascii.isWhitespace(c);
902+
903+
// Detect the first char type.
904+
if (prev_w == null) {
905+
prev_w = is_w;
906+
}
907+
// The current char is the same kind of char, the chunk continues.
908+
if (prev_w.? == is_w) {
909+
continue;
910+
}
911+
912+
// Starting here, the chunk changed.
913+
if (is_w) {
914+
// We have a chunk of non-whitespaces, we write it as it.
915+
try writer.writeAll(s[start..i]);
916+
} else {
917+
// We have a chunk of whitespaces, replace with one space,
918+
// depending the position.
919+
if (start > 0) {
920+
try writer.writeByte(' ');
901921
}
902-
cursor = i + 1;
903922
}
923+
// Start the new chunk.
924+
prev_w = is_w;
925+
start = i;
904926
}
905-
// write the reminder string
906-
if (cursor < s.len) {
907-
try w.writer.writeAll(s[cursor..]);
927+
// Write the reminder chunk.
928+
if (!is_w) {
929+
// last chunk is non whitespaces.
930+
try writer.writeAll(s[start..]);
931+
}
932+
}
933+
934+
test "AXnode: stripWhitespaces" {
935+
const allocator = std.testing.allocator;
936+
937+
const TestCase = struct {
938+
value: []const u8,
939+
expected: []const u8,
940+
};
941+
942+
const test_cases = [_]TestCase{
943+
.{ .value = " ", .expected = "" },
944+
.{ .value = " ", .expected = "" },
945+
.{ .value = "foo bar", .expected = "foo bar" },
946+
.{ .value = "foo bar", .expected = "foo bar" },
947+
.{ .value = " foo bar", .expected = "foo bar" },
948+
.{ .value = "foo bar ", .expected = "foo bar" },
949+
.{ .value = " foo bar ", .expected = "foo bar" },
950+
.{ .value = "foo\n\tbar", .expected = "foo bar" },
951+
.{ .value = "\tfoo bar baz \t\n yeah\r\n", .expected = "foo bar baz yeah" },
952+
};
953+
954+
var buffer = std.io.Writer.Allocating.init(allocator);
955+
defer buffer.deinit();
956+
957+
for (test_cases) |test_case| {
958+
buffer.clearRetainingCapacity();
959+
try stripWhitespaces(test_case.value, &buffer.writer);
960+
try std.testing.expectEqualStrings(test_case.expected, buffer.written());
908961
}
909-
try w.writer.writeByte('\"');
910-
w.endWriteRaw();
911962
}

0 commit comments

Comments
 (0)