Skip to content

Comments

feat(emulator): Add more SGR attributes, basic ANSI color, including …#935

Merged
gdamore merged 1 commit intomainfrom
more-sgr
Dec 28, 2025
Merged

feat(emulator): Add more SGR attributes, basic ANSI color, including …#935
gdamore merged 1 commit intomainfrom
more-sgr

Conversation

@gdamore
Copy link
Owner

@gdamore gdamore commented Dec 28, 2025

…tests.

Summary by CodeRabbit

  • New Features

    • Expanded terminal formatting: broader SGR attribute support (bold, dim, italic, underline variants, double-underline, strike-through, reverse, overline, blink) and improved foreground/background color handling with proper reset behavior; placeholders added for extended color modes.
  • Tests

    • New tests validating combinations of SGR attributes and ECMA-48 8-color handling, including color restoration across foreground/background changes.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 28, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds ECMA-48 SGR handling to the terminal emulator and tests: expands processSgr to handle additional attribute codes (bold/dim interplay, underline variants, italic, blink, reverse, strikethrough, overline) and basic 8-color FG/BG setting and resets; adds tests verifying SGR attributes and 8-color behavior.

Changes

Cohort / File(s) Summary
Tests
mock/term_test.go
Adds TestSgrAttr (verifies combinations and clearing of SGR attributes: bold, dim, italic, underline variants, double-underline, blink, reverse, strikethrough, resets) and TestSgrColor8 (verifies ECMA-48 8-color FG/BG handling and color reset/restoration). Adds import of github.com/gdamore/tcell/v3/color.
SGR processing
vt/emulate.go
Extends processSgr to: reset attributes and colors on code 0 via Colorer; handle interplay between bold/dim (1/2) and explicit clears (22); add clears/toggles for double-underline (21), italic (23), underline mask (24), blink (25), reverse (27), strikethrough (29), overline on/off (53/55); implement basic 30–37/39 FG and 40–47/49 BG 8-color handling; leave 38/48 extended-color handling as TODO. No public API changes.

Sequence Diagram(s)

(omitted — changes are internal SGR handling and tests without a multi-component sequential flow)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I nibble codes in lines of green,

Bold and dim and in-between.
Eight small colors hop and play,
Tests keep mischief far away.
A rabbit cheers the terminal way.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: adding more SGR attributes and basic ANSI color support to the emulator with tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1eafc2f and 417eef5.

📒 Files selected for processing (2)
  • mock/term_test.go
  • vt/emulate.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Dec 28, 2025

Codecov Report

❌ Patch coverage is 94.73684% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.52%. Comparing base (352fb32) to head (417eef5).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
vt/emulate.go 94.73% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #935      +/-   ##
==========================================
+ Coverage   33.37%   35.52%   +2.14%     
==========================================
  Files          34       34              
  Lines        3053     3091      +38     
==========================================
+ Hits         1019     1098      +79     
+ Misses       1976     1935      -41     
  Partials       58       58              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 352fb32 and 9e57b53.

📒 Files selected for processing (2)
  • mock/term_test.go
  • vt/emulate.go
🧰 Additional context used
🧬 Code graph analysis (2)
mock/term_test.go (3)
vt/coord.go (1)
  • Coord (28-31)
vt/attr.go (14)
  • Attr (18-18)
  • Bold (22-22)
  • Dim (25-25)
  • Plain (21-21)
  • Italic (26-26)
  • Underline (28-28)
  • DoubleUnderline (33-33)
  • CurlyUnderline (34-34)
  • DottedUnderline (35-35)
  • DashedUnderline (36-36)
  • StrikeThrough (27-27)
  • Reverse (24-24)
  • Overline (29-29)
  • Blink (23-23)
color/color.go (4)
  • Teal (67-67)
  • Green (63-63)
  • Silver (68-68)
  • Black (61-61)
vt/emulate.go (3)
vt/attr.go (9)
  • Dim (25-25)
  • Bold (22-22)
  • UnderlineMask (37-37)
  • DoubleUnderline (33-33)
  • Italic (26-26)
  • Blink (23-23)
  • Reverse (24-24)
  • StrikeThrough (27-27)
  • Overline (29-29)
vt/backend.go (1)
  • Colorer (59-69)
color/color.go (2)
  • Black (61-61)
  • Reset (860-860)
🔇 Additional comments (7)
vt/emulate.go (4)

383-388: LGTM on Bold/Dim mutual exclusivity.

Clearing the conflicting attribute before setting the new one correctly implements the ECMA-48 behavior where Bold (1) and Dim (2) are mutually exclusive.


414-428: LGTM on attribute clearing codes.

The ECMA-48 attribute off codes (21–29) are correctly implemented:

  • 21: Doubly underlined
  • 22: Normal intensity (clears Bold/Dim)
  • 23–29: Clear italic, underline, blink, reverse, strikethrough respectively

380-382: Verify: SGR 0 does not reset colors.

With the new color handling (cases 30–49), SGR 0 currently only resets em.attr but does not reset foreground/background colors via the Colorer interface. Per ECMA-48, SGR 0 should reset all rendition attributes including colors. Consider whether this is intentional or if colors should also be reset.


448-451: LGTM on Overline handling.

Cases 53 (enable) and 55 (disable) for Overline attribute are correctly implemented per ECMA-48.

mock/term_test.go (3)

22-22: LGTM!

Import correctly added for the new color-related tests.


412-483: Well-structured attribute tests.

Good coverage of:

  • Bold/Dim mutual exclusivity
  • Individual attribute clearing (22, 23, 24, 25, 27, 29)
  • Underline variants (simple, double, curly, dotted, dashed)
  • Invalid underline sub-parameter (4:9) falling back to plain underline
  • Compound attributes (strikethrough + reverse + overline)

485-512: Good color test coverage.

The test correctly verifies:

  • Setting foreground (36 = Teal) and background (42 = Green) colors
  • Reset foreground (39) restores to default (Silver)
  • Reset background (49) restores to default (Black)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
vt/emulate.go (1)

443-446: Comment typo still present.

The inline comment on line 443 still reads "simple foreground colors" but should read "simple background colors" since cases 40-47 set background colors.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e57b53 and 1eafc2f.

📒 Files selected for processing (2)
  • mock/term_test.go
  • vt/emulate.go
🧰 Additional context used
🧬 Code graph analysis (2)
vt/emulate.go (3)
vt/backend.go (1)
  • Colorer (59-69)
color/color.go (2)
  • Reset (860-860)
  • Black (61-61)
vt/attr.go (9)
  • Dim (25-25)
  • Bold (22-22)
  • UnderlineMask (37-37)
  • DoubleUnderline (33-33)
  • Italic (26-26)
  • Blink (23-23)
  • Reverse (24-24)
  • StrikeThrough (27-27)
  • Overline (29-29)
mock/term_test.go (5)
mock/term.go (1)
  • NewMockTerm (111-117)
mock/backend.go (1)
  • MockOptSize (168-168)
vt/coord.go (1)
  • Coord (28-31)
vt/attr.go (13)
  • Attr (18-18)
  • Bold (22-22)
  • Dim (25-25)
  • Plain (21-21)
  • Underline (28-28)
  • DoubleUnderline (33-33)
  • CurlyUnderline (34-34)
  • DottedUnderline (35-35)
  • DashedUnderline (36-36)
  • StrikeThrough (27-27)
  • Reverse (24-24)
  • Overline (29-29)
  • Blink (23-23)
color/color.go (4)
  • Teal (67-67)
  • Green (63-63)
  • Silver (68-68)
  • Black (61-61)
🔇 Additional comments (7)
vt/emulate.go (5)

383-386: LGTM! Proper SGR 0 reset behavior.

The addition of color reset when processing SGR 0 correctly implements ECMA-48 behavior, which requires resetting both attributes and colors to defaults.


388-392: LGTM! Correct Bold/Dim mutual exclusivity.

The implementation properly ensures Bold and Dim are mutually exclusive, aligning with ECMA-48 terminal behavior where setting one clears the other.


418-432: LGTM! Proper ECMA-48 SGR attribute clearing.

The implementation of SGR codes 21-29 correctly handles attribute clearing per ECMA-48 specifications. The use of bitwise clear operations is appropriate.


434-442: LGTM! Correct ANSI 8-color foreground implementation.

The implementation properly handles SGR codes 30-37 for setting 8-color foreground and 39 for resetting. The color offset calculation is correct.


452-455: LGTM! Proper overline attribute handling.

The implementation correctly handles SGR codes 53 (enable overline) and 55 (disable overline) using appropriate bitwise operations.

mock/term_test.go (2)

22-22: LGTM! Necessary import for color testing.

The color package import is required for the new color-related test assertions in TestSgrColor8.


493-537: Good test coverage for 8-color SGR codes.

The test properly verifies foreground/background color setting (SGR 30-37, 40-47) and reset behavior (SGR 39, 49, 0). The expected default colors (Silver for foreground, Black for background) correctly match the actual defaults configured in the mock terminal backend (mock/backend.go, lines 183-184).

Comment on lines 412 to 491
// TestSgrAttr tests a variety of combinations of Sgr settings.
func TestSgrAttr(t *testing.T) {
trm := NewMockTerm(MockOptSize{X: 80, Y: 24})
defer mustClose(t, trm)
mustStart(t, trm)

writeF(t, trm, "\x1b[H")
writeF(t, trm, "\x1b[1mA") // bold
if attr := trm.GetCell(vt.Coord{X: 0, Y: 0}).Attr; attr != vt.Bold {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[2mB") // dim
if attr := trm.GetCell(vt.Coord{X: 1, Y: 0}).Attr; attr != vt.Dim { // dim is exclusive of bold
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[22mC") // clear both
if attr := trm.GetCell(vt.Coord{X: 2, Y: 0}).Attr; attr != vt.Plain {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[3;2mD") // italic, dim
if attr := trm.GetCell(vt.Coord{X: 3, Y: 0}).Attr; attr != vt.Italic|vt.Dim {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[22mE") // dim, should leave italic
if attr := trm.GetCell(vt.Coord{X: 4, Y: 0}).Attr; attr != vt.Italic {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[23mF") // clear italic
if attr := trm.GetCell(vt.Coord{X: 5, Y: 0}).Attr; attr != vt.Plain {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[3;4mG") // simple underline
if attr := trm.GetCell(vt.Coord{X: 6, Y: 0}).Attr; attr != vt.Italic|vt.Underline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[21mH") // double underline (ECMA)
if attr := trm.GetCell(vt.Coord{X: 7, Y: 0}).Attr; attr != vt.Italic|vt.DoubleUnderline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[4mI") // simple underline
if attr := trm.GetCell(vt.Coord{X: 8, Y: 0}).Attr; attr != vt.Italic|vt.Underline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[4:2mJ") // simple underline
if attr := trm.GetCell(vt.Coord{X: 9, Y: 0}).Attr; attr != vt.Italic|vt.DoubleUnderline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[4:3mI") // curly underline
if attr := trm.GetCell(vt.Coord{X: 10, Y: 0}).Attr; attr != vt.Italic|vt.CurlyUnderline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[4:4mJ") // dotted underline
if attr := trm.GetCell(vt.Coord{X: 11, Y: 0}).Attr; attr != vt.Italic|vt.DottedUnderline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[4:5mK") // dashed underline
if attr := trm.GetCell(vt.Coord{X: 12, Y: 0}).Attr; attr != vt.Italic|vt.DashedUnderline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[4:9mL") // junk treats as plain
if attr := trm.GetCell(vt.Coord{X: 13, Y: 0}).Attr; attr != vt.Italic|vt.Underline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[4:5;24mM") // clustering, clear it
if attr := trm.GetCell(vt.Coord{X: 14, Y: 0}).Attr; attr != vt.Italic {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[0;9;7;53mN") // clear, striketrhough, reverse, overlined
if attr := trm.GetCell(vt.Coord{X: 15, Y: 0}).Attr; attr != vt.StrikeThrough|vt.Reverse|vt.Overline {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[5;27;29;55mO")
if attr := trm.GetCell(vt.Coord{X: 16, Y: 0}).Attr; attr != vt.Blink {
t.Errorf("wrong attr: %x", attr)
}
writeF(t, trm, "\x1b[25mP")
if attr := trm.GetCell(vt.Coord{X: 17, Y: 0}).Attr; attr != vt.Plain {
t.Errorf("wrong attr: %x", attr)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Excellent test coverage for SGR attributes.

The test comprehensively verifies the new SGR attribute handling, including mutual exclusivity of bold/dim, various underline styles, and proper clearing of individual attributes.

Minor typo on line 479: "striketrhough" should be "strikethrough" in the comment.

🤖 Prompt for AI Agents
In mock/term_test.go around lines 412 to 491, there is a minor typo in the
comment on line 479 where "striketrhough" should read "strikethrough"; update
that single-word comment to the correct spelling without changing surrounding
code or test logic.

@gdamore gdamore merged commit 417eef5 into main Dec 28, 2025
14 of 15 checks passed
@gdamore gdamore deleted the more-sgr branch December 28, 2025 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant