1package lipgloss
2
3import (
4 "image/color"
5 "strings"
6
7 "github.com/charmbracelet/x/ansi"
8)
9
10// GetBold returns the style's bold value. If no value is set false is returned.
11func (s Style) GetBold() bool {
12 return s.getAsBool(boldKey, false)
13}
14
15// GetItalic returns the style's italic value. If no value is set false is
16// returned.
17func (s Style) GetItalic() bool {
18 return s.getAsBool(italicKey, false)
19}
20
21// GetUnderline returns the style's underline value. If no value is set false is
22// returned.
23func (s Style) GetUnderline() bool {
24 return s.getAsBool(underlineKey, false)
25}
26
27// GetStrikethrough returns the style's strikethrough value. If no value is set false
28// is returned.
29func (s Style) GetStrikethrough() bool {
30 return s.getAsBool(strikethroughKey, false)
31}
32
33// GetReverse returns the style's reverse value. If no value is set false is
34// returned.
35func (s Style) GetReverse() bool {
36 return s.getAsBool(reverseKey, false)
37}
38
39// GetBlink returns the style's blink value. If no value is set false is
40// returned.
41func (s Style) GetBlink() bool {
42 return s.getAsBool(blinkKey, false)
43}
44
45// GetFaint returns the style's faint value. If no value is set false is
46// returned.
47func (s Style) GetFaint() bool {
48 return s.getAsBool(faintKey, false)
49}
50
51// GetForeground returns the style's foreground color. If no value is set
52// NoColor{} is returned.
53func (s Style) GetForeground() color.Color {
54 return s.getAsColor(foregroundKey)
55}
56
57// GetBackground returns the style's background color. If no value is set
58// NoColor{} is returned.
59func (s Style) GetBackground() color.Color {
60 return s.getAsColor(backgroundKey)
61}
62
63// GetWidth returns the style's width setting. If no width is set 0 is
64// returned.
65func (s Style) GetWidth() int {
66 return s.getAsInt(widthKey)
67}
68
69// GetHeight returns the style's height setting. If no height is set 0 is
70// returned.
71func (s Style) GetHeight() int {
72 return s.getAsInt(heightKey)
73}
74
75// GetAlign returns the style's implicit horizontal alignment setting.
76// If no alignment is set Position.Left is returned.
77func (s Style) GetAlign() Position {
78 v := s.getAsPosition(alignHorizontalKey)
79 if v == Position(0) {
80 return Left
81 }
82 return v
83}
84
85// GetAlignHorizontal returns the style's implicit horizontal alignment setting.
86// If no alignment is set Position.Left is returned.
87func (s Style) GetAlignHorizontal() Position {
88 v := s.getAsPosition(alignHorizontalKey)
89 if v == Position(0) {
90 return Left
91 }
92 return v
93}
94
95// GetAlignVertical returns the style's implicit vertical alignment setting.
96// If no alignment is set Position.Top is returned.
97func (s Style) GetAlignVertical() Position {
98 v := s.getAsPosition(alignVerticalKey)
99 if v == Position(0) {
100 return Top
101 }
102 return v
103}
104
105// GetPadding returns the style's top, right, bottom, and left padding values,
106// in that order. 0 is returned for unset values.
107func (s Style) GetPadding() (top, right, bottom, left int) {
108 return s.getAsInt(paddingTopKey),
109 s.getAsInt(paddingRightKey),
110 s.getAsInt(paddingBottomKey),
111 s.getAsInt(paddingLeftKey)
112}
113
114// GetPaddingTop returns the style's top padding. If no value is set 0 is
115// returned.
116func (s Style) GetPaddingTop() int {
117 return s.getAsInt(paddingTopKey)
118}
119
120// GetPaddingRight returns the style's right padding. If no value is set 0 is
121// returned.
122func (s Style) GetPaddingRight() int {
123 return s.getAsInt(paddingRightKey)
124}
125
126// GetPaddingBottom returns the style's bottom padding. If no value is set 0 is
127// returned.
128func (s Style) GetPaddingBottom() int {
129 return s.getAsInt(paddingBottomKey)
130}
131
132// GetPaddingLeft returns the style's left padding. If no value is set 0 is
133// returned.
134func (s Style) GetPaddingLeft() int {
135 return s.getAsInt(paddingLeftKey)
136}
137
138// GetPaddingChar returns the style's padding character. If no value is set a
139// space (`\u0020`) is returned.
140func (s Style) GetPaddingChar() rune {
141 char := s.getAsRune(paddingCharKey)
142 if char == 0 {
143 return ' '
144 }
145 return char
146}
147
148// GetHorizontalPadding returns the style's left and right padding. Unset
149// values are measured as 0.
150func (s Style) GetHorizontalPadding() int {
151 return s.getAsInt(paddingLeftKey) + s.getAsInt(paddingRightKey)
152}
153
154// GetVerticalPadding returns the style's top and bottom padding. Unset values
155// are measured as 0.
156func (s Style) GetVerticalPadding() int {
157 return s.getAsInt(paddingTopKey) + s.getAsInt(paddingBottomKey)
158}
159
160// GetColorWhitespace returns the style's whitespace coloring setting. If no
161// value is set false is returned.
162func (s Style) GetColorWhitespace() bool {
163 return s.getAsBool(colorWhitespaceKey, false)
164}
165
166// GetMargin returns the style's top, right, bottom, and left margins, in that
167// order. 0 is returned for unset values.
168func (s Style) GetMargin() (top, right, bottom, left int) {
169 return s.getAsInt(marginTopKey),
170 s.getAsInt(marginRightKey),
171 s.getAsInt(marginBottomKey),
172 s.getAsInt(marginLeftKey)
173}
174
175// GetMarginTop returns the style's top margin. If no value is set 0 is
176// returned.
177func (s Style) GetMarginTop() int {
178 return s.getAsInt(marginTopKey)
179}
180
181// GetMarginRight returns the style's right margin. If no value is set 0 is
182// returned.
183func (s Style) GetMarginRight() int {
184 return s.getAsInt(marginRightKey)
185}
186
187// GetMarginBottom returns the style's bottom margin. If no value is set 0 is
188// returned.
189func (s Style) GetMarginBottom() int {
190 return s.getAsInt(marginBottomKey)
191}
192
193// GetMarginLeft returns the style's left margin. If no value is set 0 is
194// returned.
195func (s Style) GetMarginLeft() int {
196 return s.getAsInt(marginLeftKey)
197}
198
199// GetMarginChar returns the style's padding character. If no value is set a
200// space (`\u0020`) is returned.
201func (s Style) GetMarginChar() rune {
202 char := s.getAsRune(marginCharKey)
203 if char == 0 {
204 return ' '
205 }
206 return char
207}
208
209// GetHorizontalMargins returns the style's left and right margins. Unset
210// values are measured as 0.
211func (s Style) GetHorizontalMargins() int {
212 return s.getAsInt(marginLeftKey) + s.getAsInt(marginRightKey)
213}
214
215// GetVerticalMargins returns the style's top and bottom margins. Unset values
216// are measured as 0.
217func (s Style) GetVerticalMargins() int {
218 return s.getAsInt(marginTopKey) + s.getAsInt(marginBottomKey)
219}
220
221// GetBorder returns the style's border style (type Border) and value for the
222// top, right, bottom, and left in that order. If no value is set for the
223// border style, Border{} is returned. For all other unset values false is
224// returned.
225func (s Style) GetBorder() (b Border, top, right, bottom, left bool) {
226 return s.getBorderStyle(),
227 s.getAsBool(borderTopKey, false),
228 s.getAsBool(borderRightKey, false),
229 s.getAsBool(borderBottomKey, false),
230 s.getAsBool(borderLeftKey, false)
231}
232
233// GetBorderStyle returns the style's border style (type Border). If no value
234// is set Border{} is returned.
235func (s Style) GetBorderStyle() Border {
236 return s.getBorderStyle()
237}
238
239// GetBorderTop returns the style's top border setting. If no value is set
240// false is returned.
241func (s Style) GetBorderTop() bool {
242 return s.getAsBool(borderTopKey, false)
243}
244
245// GetBorderRight returns the style's right border setting. If no value is set
246// false is returned.
247func (s Style) GetBorderRight() bool {
248 return s.getAsBool(borderRightKey, false)
249}
250
251// GetBorderBottom returns the style's bottom border setting. If no value is
252// set false is returned.
253func (s Style) GetBorderBottom() bool {
254 return s.getAsBool(borderBottomKey, false)
255}
256
257// GetBorderLeft returns the style's left border setting. If no value is
258// set false is returned.
259func (s Style) GetBorderLeft() bool {
260 return s.getAsBool(borderLeftKey, false)
261}
262
263// GetBorderTopForeground returns the style's border top foreground color. If
264// no value is set NoColor{} is returned.
265func (s Style) GetBorderTopForeground() color.Color {
266 return s.getAsColor(borderTopForegroundKey)
267}
268
269// GetBorderRightForeground returns the style's border right foreground color.
270// If no value is set NoColor{} is returned.
271func (s Style) GetBorderRightForeground() color.Color {
272 return s.getAsColor(borderRightForegroundKey)
273}
274
275// GetBorderBottomForeground returns the style's border bottom foreground
276// color. If no value is set NoColor{} is returned.
277func (s Style) GetBorderBottomForeground() color.Color {
278 return s.getAsColor(borderBottomForegroundKey)
279}
280
281// GetBorderLeftForeground returns the style's border left foreground
282// color. If no value is set NoColor{} is returned.
283func (s Style) GetBorderLeftForeground() color.Color {
284 return s.getAsColor(borderLeftForegroundKey)
285}
286
287// GetBorderTopBackground returns the style's border top background color. If
288// no value is set NoColor{} is returned.
289func (s Style) GetBorderTopBackground() color.Color {
290 return s.getAsColor(borderTopBackgroundKey)
291}
292
293// GetBorderRightBackground returns the style's border right background color.
294// If no value is set NoColor{} is returned.
295func (s Style) GetBorderRightBackground() color.Color {
296 return s.getAsColor(borderRightBackgroundKey)
297}
298
299// GetBorderBottomBackground returns the style's border bottom background
300// color. If no value is set NoColor{} is returned.
301func (s Style) GetBorderBottomBackground() color.Color {
302 return s.getAsColor(borderBottomBackgroundKey)
303}
304
305// GetBorderLeftBackground returns the style's border left background
306// color. If no value is set NoColor{} is returned.
307func (s Style) GetBorderLeftBackground() color.Color {
308 return s.getAsColor(borderLeftBackgroundKey)
309}
310
311// GetBorderTopWidth returns the width of the top border. If borders contain
312// runes of varying widths, the widest rune is returned. If no border exists on
313// the top edge, 0 is returned.
314//
315// Deprecated: This function simply calls Style.GetBorderTopSize.
316func (s Style) GetBorderTopWidth() int {
317 return s.GetBorderTopSize()
318}
319
320// GetBorderTopSize returns the width of the top border. If borders contain
321// runes of varying widths, the widest rune is returned. If no border exists on
322// the top edge, 0 is returned.
323func (s Style) GetBorderTopSize() int {
324 if s.isBorderStyleSetWithoutSides() {
325 return 1
326 }
327 if !s.getAsBool(borderTopKey, false) {
328 return 0
329 }
330 return s.getBorderStyle().GetTopSize()
331}
332
333// GetBorderLeftSize returns the width of the left border. If borders contain
334// runes of varying widths, the widest rune is returned. If no border exists on
335// the left edge, 0 is returned.
336func (s Style) GetBorderLeftSize() int {
337 if s.isBorderStyleSetWithoutSides() {
338 return 1
339 }
340 if !s.getAsBool(borderLeftKey, false) {
341 return 0
342 }
343 return s.getBorderStyle().GetLeftSize()
344}
345
346// GetBorderBottomSize returns the width of the bottom border. If borders
347// contain runes of varying widths, the widest rune is returned. If no border
348// exists on the left edge, 0 is returned.
349func (s Style) GetBorderBottomSize() int {
350 if s.isBorderStyleSetWithoutSides() {
351 return 1
352 }
353 if !s.getAsBool(borderBottomKey, false) {
354 return 0
355 }
356 return s.getBorderStyle().GetBottomSize()
357}
358
359// GetBorderRightSize returns the width of the right border. If borders
360// contain runes of varying widths, the widest rune is returned. If no border
361// exists on the right edge, 0 is returned.
362func (s Style) GetBorderRightSize() int {
363 if s.isBorderStyleSetWithoutSides() {
364 return 1
365 }
366 if !s.getAsBool(borderRightKey, false) {
367 return 0
368 }
369 return s.getBorderStyle().GetRightSize()
370}
371
372// GetHorizontalBorderSize returns the width of the horizontal borders. If
373// borders contain runes of varying widths, the widest rune is returned. If no
374// border exists on the horizontal edges, 0 is returned.
375func (s Style) GetHorizontalBorderSize() int {
376 return s.GetBorderLeftSize() + s.GetBorderRightSize()
377}
378
379// GetVerticalBorderSize returns the width of the vertical borders. If
380// borders contain runes of varying widths, the widest rune is returned. If no
381// border exists on the vertical edges, 0 is returned.
382func (s Style) GetVerticalBorderSize() int {
383 return s.GetBorderTopSize() + s.GetBorderBottomSize()
384}
385
386// GetInline returns the style's inline setting. If no value is set false is
387// returned.
388func (s Style) GetInline() bool {
389 return s.getAsBool(inlineKey, false)
390}
391
392// GetMaxWidth returns the style's max width setting. If no value is set 0 is
393// returned.
394func (s Style) GetMaxWidth() int {
395 return s.getAsInt(maxWidthKey)
396}
397
398// GetMaxHeight returns the style's max height setting. If no value is set 0 is
399// returned.
400func (s Style) GetMaxHeight() int {
401 return s.getAsInt(maxHeightKey)
402}
403
404// GetTabWidth returns the style's tab width setting. If no value is set 4 is
405// returned which is the implicit default.
406func (s Style) GetTabWidth() int {
407 return s.getAsInt(tabWidthKey)
408}
409
410// GetUnderlineSpaces returns whether or not the style is set to underline
411// spaces. If not value is set false is returned.
412func (s Style) GetUnderlineSpaces() bool {
413 return s.getAsBool(underlineSpacesKey, false)
414}
415
416// GetStrikethroughSpaces returns whether or not the style is set to strikethrough
417// spaces. If not value is set false is returned.
418func (s Style) GetStrikethroughSpaces() bool {
419 return s.getAsBool(strikethroughSpacesKey, false)
420}
421
422// GetHorizontalFrameSize returns the sum of the style's horizontal margins, padding
423// and border widths.
424//
425// Provisional: this method may be renamed.
426func (s Style) GetHorizontalFrameSize() int {
427 return s.GetHorizontalMargins() + s.GetHorizontalPadding() + s.GetHorizontalBorderSize()
428}
429
430// GetVerticalFrameSize returns the sum of the style's vertical margins, padding
431// and border widths.
432//
433// Provisional: this method may be renamed.
434func (s Style) GetVerticalFrameSize() int {
435 return s.GetVerticalMargins() + s.GetVerticalPadding() + s.GetVerticalBorderSize()
436}
437
438// GetFrameSize returns the sum of the margins, padding and border width for
439// both the horizontal and vertical margins.
440func (s Style) GetFrameSize() (x, y int) {
441 return s.GetHorizontalFrameSize(), s.GetVerticalFrameSize()
442}
443
444// GetTransform returns the transform set on the style. If no transform is set
445// nil is returned.
446func (s Style) GetTransform() func(string) string {
447 return s.getAsTransform(transformKey)
448}
449
450// Returns whether or not the given property is set.
451func (s Style) isSet(k propKey) bool {
452 return s.props.has(k)
453}
454
455func (s Style) getAsRune(k propKey) rune {
456 if !s.isSet(k) {
457 return 0
458 }
459 switch k { //nolint:exhaustive
460 case paddingCharKey:
461 return s.paddingChar
462 case marginCharKey:
463 return s.marginChar
464 }
465 return 0
466}
467
468func (s Style) getAsBool(k propKey, defaultVal bool) bool {
469 if !s.isSet(k) {
470 return defaultVal
471 }
472 return s.attrs&int(k) != 0
473}
474
475func (s Style) getAsColor(k propKey) color.Color {
476 if !s.isSet(k) {
477 return noColor
478 }
479
480 var c color.Color
481 switch k { //nolint:exhaustive
482 case foregroundKey:
483 c = s.fgColor
484 case backgroundKey:
485 c = s.bgColor
486 case marginBackgroundKey:
487 c = s.marginBgColor
488 case borderTopForegroundKey:
489 c = s.borderTopFgColor
490 case borderRightForegroundKey:
491 c = s.borderRightFgColor
492 case borderBottomForegroundKey:
493 c = s.borderBottomFgColor
494 case borderLeftForegroundKey:
495 c = s.borderLeftFgColor
496 case borderTopBackgroundKey:
497 c = s.borderTopBgColor
498 case borderRightBackgroundKey:
499 c = s.borderRightBgColor
500 case borderBottomBackgroundKey:
501 c = s.borderBottomBgColor
502 case borderLeftBackgroundKey:
503 c = s.borderLeftBgColor
504 }
505
506 if c != nil {
507 return c
508 }
509
510 return noColor
511}
512
513func (s Style) getAsInt(k propKey) int {
514 if !s.isSet(k) {
515 return 0
516 }
517 switch k { //nolint:exhaustive
518 case widthKey:
519 return s.width
520 case heightKey:
521 return s.height
522 case paddingTopKey:
523 return s.paddingTop
524 case paddingRightKey:
525 return s.paddingRight
526 case paddingBottomKey:
527 return s.paddingBottom
528 case paddingLeftKey:
529 return s.paddingLeft
530 case marginTopKey:
531 return s.marginTop
532 case marginRightKey:
533 return s.marginRight
534 case marginBottomKey:
535 return s.marginBottom
536 case marginLeftKey:
537 return s.marginLeft
538 case maxWidthKey:
539 return s.maxWidth
540 case maxHeightKey:
541 return s.maxHeight
542 case tabWidthKey:
543 return s.tabWidth
544 }
545 return 0
546}
547
548func (s Style) getAsPosition(k propKey) Position {
549 if !s.isSet(k) {
550 return Position(0)
551 }
552 switch k { //nolint:exhaustive
553 case alignHorizontalKey:
554 return s.alignHorizontal
555 case alignVerticalKey:
556 return s.alignVertical
557 }
558 return Position(0)
559}
560
561func (s Style) getBorderStyle() Border {
562 if !s.isSet(borderStyleKey) {
563 return noBorder
564 }
565 return s.borderStyle
566}
567
568func (s Style) getAsTransform(propKey) func(string) string {
569 if !s.isSet(transformKey) {
570 return nil
571 }
572 return s.transform
573}
574
575// Split a string into lines, additionally returning the size of the widest
576// line.
577func getLines(s string) (lines []string, widest int) {
578 s = strings.ReplaceAll(s, "\t", " ")
579 s = strings.ReplaceAll(s, "\r\n", "\n")
580 lines = strings.Split(s, "\n")
581
582 for _, l := range lines {
583 w := ansi.StringWidth(l)
584 if widest < w {
585 widest = w
586 }
587 }
588
589 return lines, widest
590}
591
592// isBorderStyleSetWithoutSides returns true if the border style is set but no
593// sides are set. This is used to determine if the border should be rendered by
594// default.
595func (s Style) isBorderStyleSetWithoutSides() bool {
596 var (
597 border = s.getBorderStyle()
598 topSet = s.isSet(borderTopKey)
599 rightSet = s.isSet(borderRightKey)
600 bottomSet = s.isSet(borderBottomKey)
601 leftSet = s.isSet(borderLeftKey)
602 )
603 return border != noBorder && !(topSet || rightSet || bottomSet || leftSet) //nolint:staticcheck
604}