terminal: preserve underline style in DECRQSS

DECRQSS previously serialized every active underline as SGR 4,
which caused double, curly, dotted, and dashed styles to round-trip
as single underlines.

Emit the 4:n form for extended underline styles while retaining the
legacy 4 form for single underlines, and cover every supported style.
This commit is contained in:
Mitchell Hashimoto
2026-07-26 14:32:28 -07:00
parent 4c725242b7
commit cb2fef3902

View File

@@ -3593,6 +3593,13 @@ pub fn printAttributes(self: *Terminal, buf: []u8) ![]const u8 {
}
for (attrs[0..i]) |c| {
// Preserve underline styles. Kind of a hack to special case '4'
// here but its easier than changing how we do all attributes.
if (c == '4' and pen.flags.underline != .single) {
try writer.print(";4:{}", .{@intFromEnum(pen.flags.underline)});
continue;
}
try writer.print(";{c}", .{c});
}
@@ -13743,13 +13750,23 @@ test "Terminal: printAttributes" {
try testing.expectEqualStrings("0;1;2;3;4;5;7;8;9;38:2::100:200:255;48:2::101:102:103", buf);
}
{
try t.setAttribute(.{ .underline = .single });
defer t.setAttribute(.unset) catch unreachable;
const Case = struct {
underline: sgr.Attribute.Underline,
expected: []const u8,
};
for ([_]Case{
.{ .underline = .single, .expected = "0;4" },
.{ .underline = .double, .expected = "0;4:2" },
.{ .underline = .curly, .expected = "0;4:3" },
.{ .underline = .dotted, .expected = "0;4:4" },
.{ .underline = .dashed, .expected = "0;4:5" },
}) |case| {
try t.setAttribute(.{ .underline = case.underline });
const buf = try t.printAttributes(&storage);
try testing.expectEqualStrings("0;4", buf);
try testing.expectEqualStrings(case.expected, buf);
}
try t.setAttribute(.unset);
{
const buf = try t.printAttributes(&storage);
try testing.expectEqualStrings("0", buf);