summaryrefslogtreecommitdiff
path: root/src/tui_components.zig
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-06-16 11:34:47 -0600
committert <t@tjp.lol>2026-06-16 11:35:41 -0600
commit0efda28ab5edb9ab90f648410c5867140d2868f3 (patch)
tree8619574764a055b8ac161c5cb954f7c1c687c3e4 /src/tui_components.zig
parentf8c6d45755acb5abf9ac68931268b7945da0fae0 (diff)
preserve indentation of sub-lists, reset formatting for the component after closing formatting
Diffstat (limited to 'src/tui_components.zig')
-rw-r--r--src/tui_components.zig35
1 files changed, 34 insertions, 1 deletions
diff --git a/src/tui_components.zig b/src/tui_components.zig
index 4f74210..f85c294 100644
--- a/src/tui_components.zig
+++ b/src/tui_components.zig
@@ -156,6 +156,30 @@ pub fn displayWidthStyled(text: []const u8) usize {
return cols;
}
+fn reapplyAfterReset(alloc: std.mem.Allocator, text: []const u8, bg_open: []const u8, fg_open: []const u8) ![]const u8 {
+ const reset = theme.reset;
+ var count: usize = 0;
+ var pos: usize = 0;
+ while (std.mem.indexOfPos(u8, text, pos, reset)) |idx| {
+ count += 1;
+ pos = idx + reset.len;
+ }
+ if (count == 0) return alloc.dupe(u8, text);
+
+ const extra = count * (bg_open.len + fg_open.len);
+ var out = try std.ArrayList(u8).initCapacity(alloc, text.len + extra);
+ errdefer out.deinit(alloc);
+ pos = 0;
+ while (std.mem.indexOfPos(u8, text, pos, reset)) |idx| {
+ try out.appendSlice(alloc, text[pos .. idx + reset.len]);
+ try out.appendSlice(alloc, bg_open);
+ try out.appendSlice(alloc, fg_open);
+ pos = idx + reset.len;
+ }
+ try out.appendSlice(alloc, text[pos..]);
+ return try out.toOwnedSlice(alloc);
+}
+
/// ANSI-aware version of `truncateToCols`; never cuts inside a CSI sequence and
/// does not count escapes toward the column budget.
pub fn truncateStyledToCols(text: []const u8, max_cols: usize) []const u8 {
@@ -755,10 +779,19 @@ pub const UserText = struct {
const pad_str = try a.alloc(u8, right_pad);
defer a.free(pad_str);
@memset(pad_str, ' ');
+
+ // Markdown inline styles currently close with a full SGR reset.
+ // Inside the user-message block that reset must be immediately
+ // followed by the block's bg+fg again, otherwise the faint user
+ // background disappears for the rest of the visual line (including
+ // right padding) after `code`, *em*, **strong**, etc.
+ const inner_user = try reapplyAfterReset(a, inner, bg.open(), fg.open());
+ defer a.free(inner_user);
+
const composed = try std.fmt.allocPrint(
a,
"{s}{s}{s}{s}{s}{s}",
- .{ bg.open(), fg.open(), indent, inner, pad_str, theme.reset },
+ .{ bg.open(), fg.open(), indent, inner_user, pad_str, theme.reset },
);
try out.append(a, composed);
}