@@ -59,6 +59,26 @@ func mergeStyles(parent render.Style, child render.Style) render.Style {
5959 merged .Background = child .Background
6060 }
6161
62+ if child .Bold .Valid {
63+ merged .Bold = child .Bold
64+ }
65+
66+ if child .Dim .Valid {
67+ merged .Dim = child .Dim
68+ }
69+
70+ if child .Italic .Valid {
71+ merged .Italic = child .Italic
72+ }
73+
74+ if child .Underline .Valid {
75+ merged .Underline = child .Underline
76+ }
77+
78+ if child .Blink .Valid {
79+ merged .Blink = child .Blink
80+ }
81+
6282 return merged
6383}
6484
@@ -69,6 +89,15 @@ const (
6989 styleOpResetForeground
7090 styleOpSetBackground
7191 styleOpResetBackground
92+ styleOpSetBold
93+ styleOpSetDim
94+ styleOpResetIntensity
95+ styleOpSetItalic
96+ styleOpResetItalic
97+ styleOpSetUnderline
98+ styleOpResetUnderline
99+ styleOpSetBlink
100+ styleOpResetBlink
72101)
73102
74103type styleOp struct {
@@ -95,6 +124,57 @@ func calculateStyleDiff(old render.Style, new render.Style) []styleOp {
95124 }
96125 }
97126
127+ // Bold and dim share a single ANSI reset code, so they must be diffed
128+ // together. If either attribute needs to be turned off, emit one
129+ // styleOpResetIntensity and then re-enable whichever attribute remains active
130+ // in the new style even if its value did not change, because the shared reset
131+ // will have cleared it.
132+ oldBold := old .Bold .Valid && old .Bold .Value
133+ newBold := new .Bold .Valid && new .Bold .Value
134+ oldDim := old .Dim .Valid && old .Dim .Value
135+ newDim := new .Dim .Valid && new .Dim .Value
136+ needsIntensityReset := (oldBold && ! newBold ) || (oldDim && ! newDim )
137+ if needsIntensityReset {
138+ ops = append (ops , styleOp {Kind : styleOpResetIntensity })
139+ if newBold {
140+ ops = append (ops , styleOp {Kind : styleOpSetBold })
141+ }
142+ if newDim {
143+ ops = append (ops , styleOp {Kind : styleOpSetDim })
144+ }
145+ } else {
146+ if ! oldBold && newBold {
147+ ops = append (ops , styleOp {Kind : styleOpSetBold })
148+ }
149+ if ! oldDim && newDim {
150+ ops = append (ops , styleOp {Kind : styleOpSetDim })
151+ }
152+ }
153+
154+ if old .Italic != new .Italic {
155+ if new .Italic .Valid && new .Italic .Value {
156+ ops = append (ops , styleOp {Kind : styleOpSetItalic })
157+ } else {
158+ ops = append (ops , styleOp {Kind : styleOpResetItalic })
159+ }
160+ }
161+
162+ if old .Underline != new .Underline {
163+ if new .Underline .Valid && new .Underline .Value {
164+ ops = append (ops , styleOp {Kind : styleOpSetUnderline })
165+ } else {
166+ ops = append (ops , styleOp {Kind : styleOpResetUnderline })
167+ }
168+ }
169+
170+ if old .Blink != new .Blink {
171+ if new .Blink .Valid && new .Blink .Value {
172+ ops = append (ops , styleOp {Kind : styleOpSetBlink })
173+ } else {
174+ ops = append (ops , styleOp {Kind : styleOpResetBlink })
175+ }
176+ }
177+
98178 return ops
99179}
100180
@@ -112,48 +192,110 @@ func xterm16ColorPaletteIndexToEscapeCode(index int, isForeground bool) int {
112192 }
113193}
114194
115- func (r * Renderer ) applyStyleOp (op styleOp ) {
116- if r .options .promptEscapesRequired () {
117- fmt .Fprint (& r .buffer , r .options .Capabilities .PromptEscapes .Value .Start )
195+ func (r * Renderer ) setForeground (color render.Color ) {
196+ switch r .options .Capabilities .ColorSupport {
197+ case ColorSupportNone :
198+ case ColorSupportBasic :
199+ colorIndex := r .quantizer .Quantize (color )
200+ fmt .Fprintf (& r .buffer , "\x1b [%dm" , xterm16ColorPaletteIndexToEscapeCode (colorIndex , true ))
201+ case ColorSupport256 :
202+ colorIndex := r .quantizer .Quantize (color )
203+ fmt .Fprintf (& r .buffer , "\x1b [38;5;%dm" , colorIndex )
204+ case ColorSupportTrueColor :
205+ fmt .Fprintf (& r .buffer , "\x1b [38;2;%d;%d;%dm" , color .R , color .G , color .B )
118206 }
207+ }
119208
209+ func (r * Renderer ) resetForeground () {
210+ fmt .Fprint (& r .buffer , "\x1b [39m" )
211+ }
212+
213+ func (r * Renderer ) setBackground (color render.Color ) {
120214 switch r .options .Capabilities .ColorSupport {
121215 case ColorSupportNone :
122216 case ColorSupportBasic :
123- color := r .quantizer .Quantize (op .Color )
124- switch op .Kind {
125- case styleOpSetForeground :
126- fmt .Fprintf (& r .buffer , "\x1b [%dm" , xterm16ColorPaletteIndexToEscapeCode (color , true ))
127- case styleOpResetForeground :
128- fmt .Fprint (& r .buffer , "\x1b [39m" )
129- case styleOpSetBackground :
130- fmt .Fprintf (& r .buffer , "\x1b [%dm" , xterm16ColorPaletteIndexToEscapeCode (color , false ))
131- case styleOpResetBackground :
132- fmt .Fprint (& r .buffer , "\x1b [49m" )
133- }
217+ colorIndex := r .quantizer .Quantize (color )
218+ fmt .Fprintf (& r .buffer , "\x1b [%dm" , xterm16ColorPaletteIndexToEscapeCode (colorIndex , false ))
134219 case ColorSupport256 :
135- color := r .quantizer .Quantize (op .Color )
136- switch op .Kind {
137- case styleOpSetForeground :
138- fmt .Fprintf (& r .buffer , "\x1b [38;5;%dm" , color )
139- case styleOpResetForeground :
140- fmt .Fprint (& r .buffer , "\x1b [39m" )
141- case styleOpSetBackground :
142- fmt .Fprintf (& r .buffer , "\x1b [48;5;%dm" , color )
143- case styleOpResetBackground :
144- fmt .Fprint (& r .buffer , "\x1b [49m" )
145- }
220+ colorIndex := r .quantizer .Quantize (color )
221+ fmt .Fprintf (& r .buffer , "\x1b [48;5;%dm" , colorIndex )
146222 case ColorSupportTrueColor :
147- switch op .Kind {
148- case styleOpSetForeground :
149- fmt .Fprintf (& r .buffer , "\x1b [38;2;%d;%d;%dm" , op .Color .R , op .Color .G , op .Color .B )
150- case styleOpResetForeground :
151- fmt .Fprint (& r .buffer , "\x1b [39m" )
152- case styleOpSetBackground :
153- fmt .Fprintf (& r .buffer , "\x1b [48;2;%d;%d;%dm" , op .Color .R , op .Color .G , op .Color .B )
154- case styleOpResetBackground :
155- fmt .Fprint (& r .buffer , "\x1b [49m" )
156- }
223+ fmt .Fprintf (& r .buffer , "\x1b [48;2;%d;%d;%dm" , color .R , color .G , color .B )
224+ }
225+ }
226+
227+ func (r * Renderer ) resetBackground () {
228+ fmt .Fprint (& r .buffer , "\x1b [49m" )
229+ }
230+
231+ func (r * Renderer ) setBold () {
232+ fmt .Fprint (& r .buffer , "\x1b [1m" )
233+ }
234+
235+ func (r * Renderer ) setDim () {
236+ fmt .Fprint (& r .buffer , "\x1b [2m" )
237+ }
238+
239+ func (r * Renderer ) resetIntensity () {
240+ fmt .Fprint (& r .buffer , "\x1b [22m" )
241+ }
242+
243+ func (r * Renderer ) setItalic () {
244+ fmt .Fprint (& r .buffer , "\x1b [3m" )
245+ }
246+
247+ func (r * Renderer ) resetItalic () {
248+ fmt .Fprint (& r .buffer , "\x1b [23m" )
249+ }
250+
251+ func (r * Renderer ) setUnderline () {
252+ fmt .Fprint (& r .buffer , "\x1b [4m" )
253+ }
254+
255+ func (r * Renderer ) resetUnderline () {
256+ fmt .Fprint (& r .buffer , "\x1b [24m" )
257+ }
258+
259+ func (r * Renderer ) setBlink () {
260+ fmt .Fprint (& r .buffer , "\x1b [5m" )
261+ }
262+
263+ func (r * Renderer ) resetBlink () {
264+ fmt .Fprint (& r .buffer , "\x1b [25m" )
265+ }
266+
267+ func (r * Renderer ) applyStyleOp (op styleOp ) {
268+ if r .options .promptEscapesRequired () {
269+ fmt .Fprint (& r .buffer , r .options .Capabilities .PromptEscapes .Value .Start )
270+ }
271+
272+ switch op .Kind {
273+ case styleOpSetForeground :
274+ r .setForeground (op .Color )
275+ case styleOpResetForeground :
276+ r .resetForeground ()
277+ case styleOpSetBackground :
278+ r .setBackground (op .Color )
279+ case styleOpResetBackground :
280+ r .resetBackground ()
281+ case styleOpSetBold :
282+ r .setBold ()
283+ case styleOpSetDim :
284+ r .setDim ()
285+ case styleOpResetIntensity :
286+ r .resetIntensity ()
287+ case styleOpSetItalic :
288+ r .setItalic ()
289+ case styleOpResetItalic :
290+ r .resetItalic ()
291+ case styleOpSetUnderline :
292+ r .setUnderline ()
293+ case styleOpResetUnderline :
294+ r .resetUnderline ()
295+ case styleOpSetBlink :
296+ r .setBlink ()
297+ case styleOpResetBlink :
298+ r .resetBlink ()
157299 }
158300
159301 if r .options .promptEscapesRequired () {
0 commit comments