···288288 if (cur_width + next_width > max_width) {
289289 // Trim the word to see if it can fit on a line by itself
290290 const trimmed = trimWSPLeft(word);
291291- const trimmed_width = next_width - trimmed.len;
291291+ // New width is the previous width minus the number of cells we trimmed because we
292292+ // are only trimming cells that would have been 1 wide (' ' and '\t' both measure as
293293+ // 1 wide)
294294+ const trimmed_width = next_width -| (word.len - trimmed.len);
292295 if (trimmed_width > max_width) {
293296 // Won't fit on line by itself, so fit as much on this line as we can
294297 for (word) |cell| {
···377380 // The last character will be an ellipsis
378381 try std.testing.expectEqualStrings("…", surface.buffer[surface.buffer.len - 1].char.grapheme);
379382 }
383383+}
384384+385385+test "long word wrapping" {
386386+ var rich_text: RichText = .{
387387+ .text = &.{
388388+ .{ .text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
389389+ },
390390+ };
391391+392392+ const rich_widget = rich_text.widget();
393393+394394+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
395395+ defer arena.deinit();
396396+ const ucd = try vaxis.Unicode.init(arena.allocator());
397397+ vxfw.DrawContext.init(&ucd, .unicode);
398398+399399+ const len = rich_text.text[0].text.len;
400400+ const width: u16 = 8;
401401+402402+ const ctx: vxfw.DrawContext = .{
403403+ .arena = arena.allocator(),
404404+ .min = .{},
405405+ .max = .{ .width = width, .height = null },
406406+ };
407407+408408+ const surface = try rich_widget.draw(ctx);
409409+ // Height should be length / width
410410+ try std.testing.expectEqual(len / width, surface.size.height);
380411}
381412382413test "refAllDecls" {