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// GetHorizontalPadding returns the style's left and right padding. Unset
139// values are measured as 0.
140func (s Style) GetHorizontalPadding() int {
141 return s.getAsInt(paddingLeftKey) + s.getAsInt(paddingRightKey)
142}
143
144// GetVerticalPadding returns the style's top and bottom padding. Unset values
145// are measured as 0.
146func (s Style) GetVerticalPadding() int {
147 return s.getAsInt(paddingTopKey) + s.getAsInt(paddingBottomKey)
148}
149
150// GetColorWhitespace returns the style's whitespace coloring setting. If no
151// value is set false is returned.
152func (s Style) GetColorWhitespace() bool {
153 return s.getAsBool(colorWhitespaceKey, false)
154}
155
156// GetMargin returns the style's top, right, bottom, and left margins, in that
157// order. 0 is returned for unset values.
158func (s Style) GetMargin() (top, right, bottom, left int) {
159 return s.getAsInt(marginTopKey),
160 s.getAsInt(marginRightKey),
161 s.getAsInt(marginBottomKey),
162 s.getAsInt(marginLeftKey)
163}
164
165// GetMarginTop returns the style's top margin. If no value is set 0 is
166// returned.
167func (s Style) GetMarginTop() int {
168 return s.getAsInt(marginTopKey)
169}
170
171// GetMarginRight returns the style's right margin. If no value is set 0 is
172// returned.
173func (s Style) GetMarginRight() int {
174 return s.getAsInt(marginRightKey)
175}
176
177// GetMarginBottom returns the style's bottom margin. If no value is set 0 is
178// returned.
179func (s Style) GetMarginBottom() int {
180 return s.getAsInt(marginBottomKey)
181}
182
183// GetMarginLeft returns the style's left margin. If no value is set 0 is
184// returned.
185func (s Style) GetMarginLeft() int {
186 return s.getAsInt(marginLeftKey)
187}
188
189// GetHorizontalMargins returns the style's left and right margins. Unset
190// values are measured as 0.
191func (s Style) GetHorizontalMargins() int {
192 return s.getAsInt(marginLeftKey) + s.getAsInt(marginRightKey)
193}
194
195// GetVerticalMargins returns the style's top and bottom margins. Unset values
196// are measured as 0.
197func (s Style) GetVerticalMargins() int {
198 return s.getAsInt(marginTopKey) + s.getAsInt(marginBottomKey)
199}
200
201// GetBorder returns the style's border style (type Border) and value for the
202// top, right, bottom, and left in that order. If no value is set for the
203// border style, Border{} is returned. For all other unset values false is
204// returned.
205func (s Style) GetBorder() (b Border, top, right, bottom, left bool) {
206 return s.getBorderStyle(),
207 s.getAsBool(borderTopKey, false),
208 s.getAsBool(borderRightKey, false),
209 s.getAsBool(borderBottomKey, false),
210 s.getAsBool(borderLeftKey, false)
211}
212
213// GetBorderStyle returns the style's border style (type Border). If no value
214// is set Border{} is returned.
215func (s Style) GetBorderStyle() Border {
216 return s.getBorderStyle()
217}
218
219// GetBorderTop returns the style's top border setting. If no value is set
220// false is returned.
221func (s Style) GetBorderTop() bool {
222 return s.getAsBool(borderTopKey, false)
223}
224
225// GetBorderRight returns the style's right border setting. If no value is set
226// false is returned.
227func (s Style) GetBorderRight() bool {
228 return s.getAsBool(borderRightKey, false)
229}
230
231// GetBorderBottom returns the style's bottom border setting. If no value is
232// set false is returned.
233func (s Style) GetBorderBottom() bool {
234 return s.getAsBool(borderBottomKey, false)
235}
236
237// GetBorderLeft returns the style's left border setting. If no value is
238// set false is returned.
239func (s Style) GetBorderLeft() bool {
240 return s.getAsBool(borderLeftKey, false)
241}
242
243// GetBorderTopForeground returns the style's border top foreground color. If
244// no value is set NoColor{} is returned.
245func (s Style) GetBorderTopForeground() color.Color {
246 return s.getAsColor(borderTopForegroundKey)
247}
248
249// GetBorderRightForeground returns the style's border right foreground color.
250// If no value is set NoColor{} is returned.
251func (s Style) GetBorderRightForeground() color.Color {
252 return s.getAsColor(borderRightForegroundKey)
253}
254
255// GetBorderBottomForeground returns the style's border bottom foreground
256// color. If no value is set NoColor{} is returned.
257func (s Style) GetBorderBottomForeground() color.Color {
258 return s.getAsColor(borderBottomForegroundKey)
259}
260
261// GetBorderLeftForeground returns the style's border left foreground
262// color. If no value is set NoColor{} is returned.
263func (s Style) GetBorderLeftForeground() color.Color {
264 return s.getAsColor(borderLeftForegroundKey)
265}
266
267// GetBorderTopBackground returns the style's border top background color. If
268// no value is set NoColor{} is returned.
269func (s Style) GetBorderTopBackground() color.Color {
270 return s.getAsColor(borderTopBackgroundKey)
271}
272
273// GetBorderRightBackground returns the style's border right background color.
274// If no value is set NoColor{} is returned.
275func (s Style) GetBorderRightBackground() color.Color {
276 return s.getAsColor(borderRightBackgroundKey)
277}
278
279// GetBorderBottomBackground returns the style's border bottom background
280// color. If no value is set NoColor{} is returned.
281func (s Style) GetBorderBottomBackground() color.Color {
282 return s.getAsColor(borderBottomBackgroundKey)
283}
284
285// GetBorderLeftBackground returns the style's border left background
286// color. If no value is set NoColor{} is returned.
287func (s Style) GetBorderLeftBackground() color.Color {
288 return s.getAsColor(borderLeftBackgroundKey)
289}
290
291// GetBorderTopWidth returns the width of the top border. If borders contain
292// runes of varying widths, the widest rune is returned. If no border exists on
293// the top edge, 0 is returned.
294//
295// Deprecated: This function simply calls Style.GetBorderTopSize.
296func (s Style) GetBorderTopWidth() int {
297 return s.GetBorderTopSize()
298}
299
300// GetBorderTopSize returns the width of the top border. If borders contain
301// runes of varying widths, the widest rune is returned. If no border exists on
302// the top edge, 0 is returned.
303func (s Style) GetBorderTopSize() int {
304 if s.isBorderStyleSetWithoutSides() {
305 return 1
306 }
307 if !s.getAsBool(borderTopKey, false) {
308 return 0
309 }
310 return s.getBorderStyle().GetTopSize()
311}
312
313// GetBorderLeftSize returns the width of the left border. If borders contain
314// runes of varying widths, the widest rune is returned. If no border exists on
315// the left edge, 0 is returned.
316func (s Style) GetBorderLeftSize() int {
317 if s.isBorderStyleSetWithoutSides() {
318 return 1
319 }
320 if !s.getAsBool(borderLeftKey, false) {
321 return 0
322 }
323 return s.getBorderStyle().GetLeftSize()
324}
325
326// GetBorderBottomSize returns the width of the bottom border. If borders
327// contain runes of varying widths, the widest rune is returned. If no border
328// exists on the left edge, 0 is returned.
329func (s Style) GetBorderBottomSize() int {
330 if s.isBorderStyleSetWithoutSides() {
331 return 1
332 }
333 if !s.getAsBool(borderBottomKey, false) {
334 return 0
335 }
336 return s.getBorderStyle().GetBottomSize()
337}
338
339// GetBorderRightSize returns the width of the right border. If borders
340// contain runes of varying widths, the widest rune is returned. If no border
341// exists on the right edge, 0 is returned.
342func (s Style) GetBorderRightSize() int {
343 if s.isBorderStyleSetWithoutSides() {
344 return 1
345 }
346 if !s.getAsBool(borderRightKey, false) {
347 return 0
348 }
349 return s.getBorderStyle().GetRightSize()
350}
351
352// GetHorizontalBorderSize returns the width of the horizontal borders. If
353// borders contain runes of varying widths, the widest rune is returned. If no
354// border exists on the horizontal edges, 0 is returned.
355func (s Style) GetHorizontalBorderSize() int {
356 return s.GetBorderLeftSize() + s.GetBorderRightSize()
357}
358
359// GetVerticalBorderSize returns the width of the vertical borders. If
360// borders contain runes of varying widths, the widest rune is returned. If no
361// border exists on the vertical edges, 0 is returned.
362func (s Style) GetVerticalBorderSize() int {
363 return s.GetBorderTopSize() + s.GetBorderBottomSize()
364}
365
366// GetInline returns the style's inline setting. If no value is set false is
367// returned.
368func (s Style) GetInline() bool {
369 return s.getAsBool(inlineKey, false)
370}
371
372// GetMaxWidth returns the style's max width setting. If no value is set 0 is
373// returned.
374func (s Style) GetMaxWidth() int {
375 return s.getAsInt(maxWidthKey)
376}
377
378// GetMaxHeight returns the style's max height setting. If no value is set 0 is
379// returned.
380func (s Style) GetMaxHeight() int {
381 return s.getAsInt(maxHeightKey)
382}
383
384// GetTabWidth returns the style's tab width setting. If no value is set 4 is
385// returned which is the implicit default.
386func (s Style) GetTabWidth() int {
387 return s.getAsInt(tabWidthKey)
388}
389
390// GetUnderlineSpaces returns whether or not the style is set to underline
391// spaces. If not value is set false is returned.
392func (s Style) GetUnderlineSpaces() bool {
393 return s.getAsBool(underlineSpacesKey, false)
394}
395
396// GetStrikethroughSpaces returns whether or not the style is set to strikethrough
397// spaces. If not value is set false is returned.
398func (s Style) GetStrikethroughSpaces() bool {
399 return s.getAsBool(strikethroughSpacesKey, false)
400}
401
402// GetHorizontalFrameSize returns the sum of the style's horizontal margins, padding
403// and border widths.
404//
405// Provisional: this method may be renamed.
406func (s Style) GetHorizontalFrameSize() int {
407 return s.GetHorizontalMargins() + s.GetHorizontalPadding() + s.GetHorizontalBorderSize()
408}
409
410// GetVerticalFrameSize returns the sum of the style's vertical margins, padding
411// and border widths.
412//
413// Provisional: this method may be renamed.
414func (s Style) GetVerticalFrameSize() int {
415 return s.GetVerticalMargins() + s.GetVerticalPadding() + s.GetVerticalBorderSize()
416}
417
418// GetFrameSize returns the sum of the margins, padding and border width for
419// both the horizontal and vertical margins.
420func (s Style) GetFrameSize() (x, y int) {
421 return s.GetHorizontalFrameSize(), s.GetVerticalFrameSize()
422}
423
424// GetTransform returns the transform set on the style. If no transform is set
425// nil is returned.
426func (s Style) GetTransform() func(string) string {
427 return s.getAsTransform(transformKey)
428}
429
430// Returns whether or not the given property is set.
431func (s Style) isSet(k propKey) bool {
432 return s.props.has(k)
433}
434
435func (s Style) getAsBool(k propKey, defaultVal bool) bool {
436 if !s.isSet(k) {
437 return defaultVal
438 }
439 return s.attrs&int(k) != 0
440}
441
442func (s Style) getAsColor(k propKey) color.Color {
443 if !s.isSet(k) {
444 return noColor
445 }
446
447 var c color.Color
448 switch k { //nolint:exhaustive
449 case foregroundKey:
450 c = s.fgColor
451 case backgroundKey:
452 c = s.bgColor
453 case marginBackgroundKey:
454 c = s.marginBgColor
455 case borderTopForegroundKey:
456 c = s.borderTopFgColor
457 case borderRightForegroundKey:
458 c = s.borderRightFgColor
459 case borderBottomForegroundKey:
460 c = s.borderBottomFgColor
461 case borderLeftForegroundKey:
462 c = s.borderLeftFgColor
463 case borderTopBackgroundKey:
464 c = s.borderTopBgColor
465 case borderRightBackgroundKey:
466 c = s.borderRightBgColor
467 case borderBottomBackgroundKey:
468 c = s.borderBottomBgColor
469 case borderLeftBackgroundKey:
470 c = s.borderLeftBgColor
471 }
472
473 if c != nil {
474 return c
475 }
476
477 return noColor
478}
479
480func (s Style) getAsInt(k propKey) int {
481 if !s.isSet(k) {
482 return 0
483 }
484 switch k { //nolint:exhaustive
485 case widthKey:
486 return s.width
487 case heightKey:
488 return s.height
489 case paddingTopKey:
490 return s.paddingTop
491 case paddingRightKey:
492 return s.paddingRight
493 case paddingBottomKey:
494 return s.paddingBottom
495 case paddingLeftKey:
496 return s.paddingLeft
497 case marginTopKey:
498 return s.marginTop
499 case marginRightKey:
500 return s.marginRight
501 case marginBottomKey:
502 return s.marginBottom
503 case marginLeftKey:
504 return s.marginLeft
505 case maxWidthKey:
506 return s.maxWidth
507 case maxHeightKey:
508 return s.maxHeight
509 case tabWidthKey:
510 return s.tabWidth
511 }
512 return 0
513}
514
515func (s Style) getAsPosition(k propKey) Position {
516 if !s.isSet(k) {
517 return Position(0)
518 }
519 switch k { //nolint:exhaustive
520 case alignHorizontalKey:
521 return s.alignHorizontal
522 case alignVerticalKey:
523 return s.alignVertical
524 }
525 return Position(0)
526}
527
528func (s Style) getBorderStyle() Border {
529 if !s.isSet(borderStyleKey) {
530 return noBorder
531 }
532 return s.borderStyle
533}
534
535func (s Style) getAsTransform(propKey) func(string) string {
536 if !s.isSet(transformKey) {
537 return nil
538 }
539 return s.transform
540}
541
542// Split a string into lines, additionally returning the size of the widest
543// line.
544func getLines(s string) (lines []string, widest int) {
545 s = strings.ReplaceAll(s, "\t", " ")
546 s = strings.ReplaceAll(s, "\r\n", "\n")
547 lines = strings.Split(s, "\n")
548
549 for _, l := range lines {
550 w := ansi.StringWidth(l)
551 if widest < w {
552 widest = w
553 }
554 }
555
556 return lines, widest
557}
558
559// isBorderStyleSetWithoutSides returns true if the border style is set but no
560// sides are set. This is used to determine if the border should be rendered by
561// default.
562func (s Style) isBorderStyleSetWithoutSides() bool {
563 var (
564 border = s.getBorderStyle()
565 topSet = s.isSet(borderTopKey)
566 rightSet = s.isSet(borderRightKey)
567 bottomSet = s.isSet(borderBottomKey)
568 leftSet = s.isSet(borderLeftKey)
569 )
570 return border != noBorder && !(topSet || rightSet || bottomSet || leftSet) //nolint:staticcheck
571}