main
Raw Download raw file
  1package lipgloss
  2
  3// Set a value on the underlying rules map.
  4func (s *Style) set(key propKey, value interface{}) {
  5	// We don't allow negative integers on any of our other values, so just keep
  6	// them at zero or above. We could use uints instead, but the
  7	// conversions are a little tedious, so we're sticking with ints for
  8	// sake of usability.
  9	switch key { //nolint:exhaustive
 10	case foregroundKey:
 11		s.fgColor = colorOrNil(value)
 12	case backgroundKey:
 13		s.bgColor = colorOrNil(value)
 14	case widthKey:
 15		s.width = max(0, value.(int))
 16	case heightKey:
 17		s.height = max(0, value.(int))
 18	case alignHorizontalKey:
 19		s.alignHorizontal = value.(Position)
 20	case alignVerticalKey:
 21		s.alignVertical = value.(Position)
 22	case paddingTopKey:
 23		s.paddingTop = max(0, value.(int))
 24	case paddingRightKey:
 25		s.paddingRight = max(0, value.(int))
 26	case paddingBottomKey:
 27		s.paddingBottom = max(0, value.(int))
 28	case paddingLeftKey:
 29		s.paddingLeft = max(0, value.(int))
 30	case marginTopKey:
 31		s.marginTop = max(0, value.(int))
 32	case marginRightKey:
 33		s.marginRight = max(0, value.(int))
 34	case marginBottomKey:
 35		s.marginBottom = max(0, value.(int))
 36	case marginLeftKey:
 37		s.marginLeft = max(0, value.(int))
 38	case marginBackgroundKey:
 39		s.marginBgColor = colorOrNil(value)
 40	case borderStyleKey:
 41		s.borderStyle = value.(Border)
 42	case borderTopForegroundKey:
 43		s.borderTopFgColor = colorOrNil(value)
 44	case borderRightForegroundKey:
 45		s.borderRightFgColor = colorOrNil(value)
 46	case borderBottomForegroundKey:
 47		s.borderBottomFgColor = colorOrNil(value)
 48	case borderLeftForegroundKey:
 49		s.borderLeftFgColor = colorOrNil(value)
 50	case borderTopBackgroundKey:
 51		s.borderTopBgColor = colorOrNil(value)
 52	case borderRightBackgroundKey:
 53		s.borderRightBgColor = colorOrNil(value)
 54	case borderBottomBackgroundKey:
 55		s.borderBottomBgColor = colorOrNil(value)
 56	case borderLeftBackgroundKey:
 57		s.borderLeftBgColor = colorOrNil(value)
 58	case maxWidthKey:
 59		s.maxWidth = max(0, value.(int))
 60	case maxHeightKey:
 61		s.maxHeight = max(0, value.(int))
 62	case tabWidthKey:
 63		// TabWidth is the only property that may have a negative value (and
 64		// that negative value can be no less than -1).
 65		s.tabWidth = value.(int)
 66	case transformKey:
 67		s.transform = value.(func(string) string)
 68	default:
 69		if v, ok := value.(bool); ok { //nolint:nestif
 70			if v {
 71				s.attrs |= int(key)
 72			} else {
 73				s.attrs &^= int(key)
 74			}
 75		} else if attrs, ok := value.(int); ok {
 76			// bool attrs
 77			if attrs&int(key) != 0 {
 78				s.attrs |= int(key)
 79			} else {
 80				s.attrs &^= int(key)
 81			}
 82		}
 83	}
 84
 85	// Set the prop on
 86	s.props = s.props.set(key)
 87}
 88
 89// setFrom sets the property from another style.
 90func (s *Style) setFrom(key propKey, i Style) {
 91	switch key { //nolint:exhaustive
 92	case foregroundKey:
 93		s.set(foregroundKey, i.fgColor)
 94	case backgroundKey:
 95		s.set(backgroundKey, i.bgColor)
 96	case widthKey:
 97		s.set(widthKey, i.width)
 98	case heightKey:
 99		s.set(heightKey, i.height)
100	case alignHorizontalKey:
101		s.set(alignHorizontalKey, i.alignHorizontal)
102	case alignVerticalKey:
103		s.set(alignVerticalKey, i.alignVertical)
104	case paddingTopKey:
105		s.set(paddingTopKey, i.paddingTop)
106	case paddingRightKey:
107		s.set(paddingRightKey, i.paddingRight)
108	case paddingBottomKey:
109		s.set(paddingBottomKey, i.paddingBottom)
110	case paddingLeftKey:
111		s.set(paddingLeftKey, i.paddingLeft)
112	case marginTopKey:
113		s.set(marginTopKey, i.marginTop)
114	case marginRightKey:
115		s.set(marginRightKey, i.marginRight)
116	case marginBottomKey:
117		s.set(marginBottomKey, i.marginBottom)
118	case marginLeftKey:
119		s.set(marginLeftKey, i.marginLeft)
120	case marginBackgroundKey:
121		s.set(marginBackgroundKey, i.marginBgColor)
122	case borderStyleKey:
123		s.set(borderStyleKey, i.borderStyle)
124	case borderTopForegroundKey:
125		s.set(borderTopForegroundKey, i.borderTopFgColor)
126	case borderRightForegroundKey:
127		s.set(borderRightForegroundKey, i.borderRightFgColor)
128	case borderBottomForegroundKey:
129		s.set(borderBottomForegroundKey, i.borderBottomFgColor)
130	case borderLeftForegroundKey:
131		s.set(borderLeftForegroundKey, i.borderLeftFgColor)
132	case borderTopBackgroundKey:
133		s.set(borderTopBackgroundKey, i.borderTopBgColor)
134	case borderRightBackgroundKey:
135		s.set(borderRightBackgroundKey, i.borderRightBgColor)
136	case borderBottomBackgroundKey:
137		s.set(borderBottomBackgroundKey, i.borderBottomBgColor)
138	case borderLeftBackgroundKey:
139		s.set(borderLeftBackgroundKey, i.borderLeftBgColor)
140	case maxWidthKey:
141		s.set(maxWidthKey, i.maxWidth)
142	case maxHeightKey:
143		s.set(maxHeightKey, i.maxHeight)
144	case tabWidthKey:
145		s.set(tabWidthKey, i.tabWidth)
146	case transformKey:
147		s.set(transformKey, i.transform)
148	default:
149		// Set attributes for set bool properties
150		s.set(key, i.attrs)
151	}
152}
153
154func colorOrNil(c interface{}) TerminalColor {
155	if c, ok := c.(TerminalColor); ok {
156		return c
157	}
158	return nil
159}
160
161// Bold sets a bold formatting rule.
162func (s Style) Bold(v bool) Style {
163	s.set(boldKey, v)
164	return s
165}
166
167// Italic sets an italic formatting rule. In some terminal emulators this will
168// render with "reverse" coloring if not italic font variant is available.
169func (s Style) Italic(v bool) Style {
170	s.set(italicKey, v)
171	return s
172}
173
174// Underline sets an underline rule. By default, underlines will not be drawn on
175// whitespace like margins and padding. To change this behavior set
176// UnderlineSpaces.
177func (s Style) Underline(v bool) Style {
178	s.set(underlineKey, v)
179	return s
180}
181
182// Strikethrough sets a strikethrough rule. By default, strikes will not be
183// drawn on whitespace like margins and padding. To change this behavior set
184// StrikethroughSpaces.
185func (s Style) Strikethrough(v bool) Style {
186	s.set(strikethroughKey, v)
187	return s
188}
189
190// Reverse sets a rule for inverting foreground and background colors.
191func (s Style) Reverse(v bool) Style {
192	s.set(reverseKey, v)
193	return s
194}
195
196// Blink sets a rule for blinking foreground text.
197func (s Style) Blink(v bool) Style {
198	s.set(blinkKey, v)
199	return s
200}
201
202// Faint sets a rule for rendering the foreground color in a dimmer shade.
203func (s Style) Faint(v bool) Style {
204	s.set(faintKey, v)
205	return s
206}
207
208// Foreground sets a foreground color.
209//
210//	// Sets the foreground to blue
211//	s := lipgloss.NewStyle().Foreground(lipgloss.Color("#0000ff"))
212//
213//	// Removes the foreground color
214//	s.Foreground(lipgloss.NoColor)
215func (s Style) Foreground(c TerminalColor) Style {
216	s.set(foregroundKey, c)
217	return s
218}
219
220// Background sets a background color.
221func (s Style) Background(c TerminalColor) Style {
222	s.set(backgroundKey, c)
223	return s
224}
225
226// Width sets the width of the block before applying margins. The width, if
227// set, also determines where text will wrap.
228func (s Style) Width(i int) Style {
229	s.set(widthKey, i)
230	return s
231}
232
233// Height sets the height of the block before applying margins. If the height of
234// the text block is less than this value after applying padding (or not), the
235// block will be set to this height.
236func (s Style) Height(i int) Style {
237	s.set(heightKey, i)
238	return s
239}
240
241// Align is a shorthand method for setting horizontal and vertical alignment.
242//
243// With one argument, the position value is applied to the horizontal alignment.
244//
245// With two arguments, the value is applied to the horizontal and vertical
246// alignments, in that order.
247func (s Style) Align(p ...Position) Style {
248	if len(p) > 0 {
249		s.set(alignHorizontalKey, p[0])
250	}
251	if len(p) > 1 {
252		s.set(alignVerticalKey, p[1])
253	}
254	return s
255}
256
257// AlignHorizontal sets a horizontal text alignment rule.
258func (s Style) AlignHorizontal(p Position) Style {
259	s.set(alignHorizontalKey, p)
260	return s
261}
262
263// AlignVertical sets a vertical text alignment rule.
264func (s Style) AlignVertical(p Position) Style {
265	s.set(alignVerticalKey, p)
266	return s
267}
268
269// Padding is a shorthand method for setting padding on all sides at once.
270//
271// With one argument, the value is applied to all sides.
272//
273// With two arguments, the value is applied to the vertical and horizontal
274// sides, in that order.
275//
276// With three arguments, the value is applied to the top side, the horizontal
277// sides, and the bottom side, in that order.
278//
279// With four arguments, the value is applied clockwise starting from the top
280// side, followed by the right side, then the bottom, and finally the left.
281//
282// With more than four arguments no padding will be added.
283func (s Style) Padding(i ...int) Style {
284	top, right, bottom, left, ok := whichSidesInt(i...)
285	if !ok {
286		return s
287	}
288
289	s.set(paddingTopKey, top)
290	s.set(paddingRightKey, right)
291	s.set(paddingBottomKey, bottom)
292	s.set(paddingLeftKey, left)
293	return s
294}
295
296// PaddingLeft adds padding on the left.
297func (s Style) PaddingLeft(i int) Style {
298	s.set(paddingLeftKey, i)
299	return s
300}
301
302// PaddingRight adds padding on the right.
303func (s Style) PaddingRight(i int) Style {
304	s.set(paddingRightKey, i)
305	return s
306}
307
308// PaddingTop adds padding to the top of the block.
309func (s Style) PaddingTop(i int) Style {
310	s.set(paddingTopKey, i)
311	return s
312}
313
314// PaddingBottom adds padding to the bottom of the block.
315func (s Style) PaddingBottom(i int) Style {
316	s.set(paddingBottomKey, i)
317	return s
318}
319
320// ColorWhitespace determines whether or not the background color should be
321// applied to the padding. This is true by default as it's more than likely the
322// desired and expected behavior, but it can be disabled for certain graphic
323// effects.
324//
325// Deprecated: Just use margins and padding.
326func (s Style) ColorWhitespace(v bool) Style {
327	s.set(colorWhitespaceKey, v)
328	return s
329}
330
331// Margin is a shorthand method for setting margins on all sides at once.
332//
333// With one argument, the value is applied to all sides.
334//
335// With two arguments, the value is applied to the vertical and horizontal
336// sides, in that order.
337//
338// With three arguments, the value is applied to the top side, the horizontal
339// sides, and the bottom side, in that order.
340//
341// With four arguments, the value is applied clockwise starting from the top
342// side, followed by the right side, then the bottom, and finally the left.
343//
344// With more than four arguments no margin will be added.
345func (s Style) Margin(i ...int) Style {
346	top, right, bottom, left, ok := whichSidesInt(i...)
347	if !ok {
348		return s
349	}
350
351	s.set(marginTopKey, top)
352	s.set(marginRightKey, right)
353	s.set(marginBottomKey, bottom)
354	s.set(marginLeftKey, left)
355	return s
356}
357
358// MarginLeft sets the value of the left margin.
359func (s Style) MarginLeft(i int) Style {
360	s.set(marginLeftKey, i)
361	return s
362}
363
364// MarginRight sets the value of the right margin.
365func (s Style) MarginRight(i int) Style {
366	s.set(marginRightKey, i)
367	return s
368}
369
370// MarginTop sets the value of the top margin.
371func (s Style) MarginTop(i int) Style {
372	s.set(marginTopKey, i)
373	return s
374}
375
376// MarginBottom sets the value of the bottom margin.
377func (s Style) MarginBottom(i int) Style {
378	s.set(marginBottomKey, i)
379	return s
380}
381
382// MarginBackground sets the background color of the margin. Note that this is
383// also set when inheriting from a style with a background color. In that case
384// the background color on that style will set the margin color on this style.
385func (s Style) MarginBackground(c TerminalColor) Style {
386	s.set(marginBackgroundKey, c)
387	return s
388}
389
390// Border is shorthand for setting the border style and which sides should
391// have a border at once. The variadic argument sides works as follows:
392//
393// With one value, the value is applied to all sides.
394//
395// With two values, the values are applied to the vertical and horizontal
396// sides, in that order.
397//
398// With three values, the values are applied to the top side, the horizontal
399// sides, and the bottom side, in that order.
400//
401// With four values, the values are applied clockwise starting from the top
402// side, followed by the right side, then the bottom, and finally the left.
403//
404// With more than four arguments the border will be applied to all sides.
405//
406// Examples:
407//
408//	// Applies borders to the top and bottom only
409//	lipgloss.NewStyle().Border(lipgloss.NormalBorder(), true, false)
410//
411//	// Applies rounded borders to the right and bottom only
412//	lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), false, true, true, false)
413func (s Style) Border(b Border, sides ...bool) Style {
414	s.set(borderStyleKey, b)
415
416	top, right, bottom, left, ok := whichSidesBool(sides...)
417	if !ok {
418		top = true
419		right = true
420		bottom = true
421		left = true
422	}
423
424	s.set(borderTopKey, top)
425	s.set(borderRightKey, right)
426	s.set(borderBottomKey, bottom)
427	s.set(borderLeftKey, left)
428
429	return s
430}
431
432// BorderStyle defines the Border on a style. A Border contains a series of
433// definitions for the sides and corners of a border.
434//
435// Note that if border visibility has not been set for any sides when setting
436// the border style, the border will be enabled for all sides during rendering.
437//
438// You can define border characters as you'd like, though several default
439// styles are included: NormalBorder(), RoundedBorder(), BlockBorder(),
440// OuterHalfBlockBorder(), InnerHalfBlockBorder(), ThickBorder(),
441// and DoubleBorder().
442//
443// Example:
444//
445//	lipgloss.NewStyle().BorderStyle(lipgloss.ThickBorder())
446func (s Style) BorderStyle(b Border) Style {
447	s.set(borderStyleKey, b)
448	return s
449}
450
451// BorderTop determines whether or not to draw a top border.
452func (s Style) BorderTop(v bool) Style {
453	s.set(borderTopKey, v)
454	return s
455}
456
457// BorderRight determines whether or not to draw a right border.
458func (s Style) BorderRight(v bool) Style {
459	s.set(borderRightKey, v)
460	return s
461}
462
463// BorderBottom determines whether or not to draw a bottom border.
464func (s Style) BorderBottom(v bool) Style {
465	s.set(borderBottomKey, v)
466	return s
467}
468
469// BorderLeft determines whether or not to draw a left border.
470func (s Style) BorderLeft(v bool) Style {
471	s.set(borderLeftKey, v)
472	return s
473}
474
475// BorderForeground is a shorthand function for setting all of the
476// foreground colors of the borders at once. The arguments work as follows:
477//
478// With one argument, the argument is applied to all sides.
479//
480// With two arguments, the arguments are applied to the vertical and horizontal
481// sides, in that order.
482//
483// With three arguments, the arguments are applied to the top side, the
484// horizontal sides, and the bottom side, in that order.
485//
486// With four arguments, the arguments are applied clockwise starting from the
487// top side, followed by the right side, then the bottom, and finally the left.
488//
489// With more than four arguments nothing will be set.
490func (s Style) BorderForeground(c ...TerminalColor) Style {
491	if len(c) == 0 {
492		return s
493	}
494
495	top, right, bottom, left, ok := whichSidesColor(c...)
496	if !ok {
497		return s
498	}
499
500	s.set(borderTopForegroundKey, top)
501	s.set(borderRightForegroundKey, right)
502	s.set(borderBottomForegroundKey, bottom)
503	s.set(borderLeftForegroundKey, left)
504
505	return s
506}
507
508// BorderTopForeground set the foreground color for the top of the border.
509func (s Style) BorderTopForeground(c TerminalColor) Style {
510	s.set(borderTopForegroundKey, c)
511	return s
512}
513
514// BorderRightForeground sets the foreground color for the right side of the
515// border.
516func (s Style) BorderRightForeground(c TerminalColor) Style {
517	s.set(borderRightForegroundKey, c)
518	return s
519}
520
521// BorderBottomForeground sets the foreground color for the bottom of the
522// border.
523func (s Style) BorderBottomForeground(c TerminalColor) Style {
524	s.set(borderBottomForegroundKey, c)
525	return s
526}
527
528// BorderLeftForeground sets the foreground color for the left side of the
529// border.
530func (s Style) BorderLeftForeground(c TerminalColor) Style {
531	s.set(borderLeftForegroundKey, c)
532	return s
533}
534
535// BorderBackground is a shorthand function for setting all of the
536// background colors of the borders at once. The arguments work as follows:
537//
538// With one argument, the argument is applied to all sides.
539//
540// With two arguments, the arguments are applied to the vertical and horizontal
541// sides, in that order.
542//
543// With three arguments, the arguments are applied to the top side, the
544// horizontal sides, and the bottom side, in that order.
545//
546// With four arguments, the arguments are applied clockwise starting from the
547// top side, followed by the right side, then the bottom, and finally the left.
548//
549// With more than four arguments nothing will be set.
550func (s Style) BorderBackground(c ...TerminalColor) Style {
551	if len(c) == 0 {
552		return s
553	}
554
555	top, right, bottom, left, ok := whichSidesColor(c...)
556	if !ok {
557		return s
558	}
559
560	s.set(borderTopBackgroundKey, top)
561	s.set(borderRightBackgroundKey, right)
562	s.set(borderBottomBackgroundKey, bottom)
563	s.set(borderLeftBackgroundKey, left)
564
565	return s
566}
567
568// BorderTopBackground sets the background color of the top of the border.
569func (s Style) BorderTopBackground(c TerminalColor) Style {
570	s.set(borderTopBackgroundKey, c)
571	return s
572}
573
574// BorderRightBackground sets the background color of right side the border.
575func (s Style) BorderRightBackground(c TerminalColor) Style {
576	s.set(borderRightBackgroundKey, c)
577	return s
578}
579
580// BorderBottomBackground sets the background color of the bottom of the
581// border.
582func (s Style) BorderBottomBackground(c TerminalColor) Style {
583	s.set(borderBottomBackgroundKey, c)
584	return s
585}
586
587// BorderLeftBackground set the background color of the left side of the
588// border.
589func (s Style) BorderLeftBackground(c TerminalColor) Style {
590	s.set(borderLeftBackgroundKey, c)
591	return s
592}
593
594// Inline makes rendering output one line and disables the rendering of
595// margins, padding and borders. This is useful when you need a style to apply
596// only to font rendering and don't want it to change any physical dimensions.
597// It works well with Style.MaxWidth.
598//
599// Because this in intended to be used at the time of render, this method will
600// not mutate the style and instead return a copy.
601//
602// Example:
603//
604//	var userInput string = "..."
605//	var userStyle = text.Style{ /* ... */ }
606//	fmt.Println(userStyle.Inline(true).Render(userInput))
607func (s Style) Inline(v bool) Style {
608	o := s // copy
609	o.set(inlineKey, v)
610	return o
611}
612
613// MaxWidth applies a max width to a given style. This is useful in enforcing
614// a certain width at render time, particularly with arbitrary strings and
615// styles.
616//
617// Because this in intended to be used at the time of render, this method will
618// not mutate the style and instead return a copy.
619//
620// Example:
621//
622//	var userInput string = "..."
623//	var userStyle = text.Style{ /* ... */ }
624//	fmt.Println(userStyle.MaxWidth(16).Render(userInput))
625func (s Style) MaxWidth(n int) Style {
626	o := s // copy
627	o.set(maxWidthKey, n)
628	return o
629}
630
631// MaxHeight applies a max height to a given style. This is useful in enforcing
632// a certain height at render time, particularly with arbitrary strings and
633// styles.
634//
635// Because this in intended to be used at the time of render, this method will
636// not mutate the style and instead returns a copy.
637func (s Style) MaxHeight(n int) Style {
638	o := s // copy
639	o.set(maxHeightKey, n)
640	return o
641}
642
643// NoTabConversion can be passed to [Style.TabWidth] to disable the replacement
644// of tabs with spaces at render time.
645const NoTabConversion = -1
646
647// TabWidth sets the number of spaces that a tab (/t) should be rendered as.
648// When set to 0, tabs will be removed. To disable the replacement of tabs with
649// spaces entirely, set this to [NoTabConversion].
650//
651// By default, tabs will be replaced with 4 spaces.
652func (s Style) TabWidth(n int) Style {
653	if n <= -1 {
654		n = -1
655	}
656	s.set(tabWidthKey, n)
657	return s
658}
659
660// UnderlineSpaces determines whether to underline spaces between words. By
661// default, this is true. Spaces can also be underlined without underlining the
662// text itself.
663func (s Style) UnderlineSpaces(v bool) Style {
664	s.set(underlineSpacesKey, v)
665	return s
666}
667
668// StrikethroughSpaces determines whether to apply strikethroughs to spaces
669// between words. By default, this is true. Spaces can also be struck without
670// underlining the text itself.
671func (s Style) StrikethroughSpaces(v bool) Style {
672	s.set(strikethroughSpacesKey, v)
673	return s
674}
675
676// Transform applies a given function to a string at render time, allowing for
677// the string being rendered to be manipuated.
678//
679// Example:
680//
681//	s := NewStyle().Transform(strings.ToUpper)
682//	fmt.Println(s.Render("raow!") // "RAOW!"
683func (s Style) Transform(fn func(string) string) Style {
684	s.set(transformKey, fn)
685	return s
686}
687
688// Renderer sets the renderer for the style. This is useful for changing the
689// renderer for a style that is being used in a different context.
690func (s Style) Renderer(r *Renderer) Style {
691	s.r = r
692	return s
693}
694
695// whichSidesInt is a helper method for setting values on sides of a block based
696// on the number of arguments. It follows the CSS shorthand rules for blocks
697// like margin, padding. and borders. Here are how the rules work:
698//
699// 0 args:  do nothing
700// 1 arg:   all sides
701// 2 args:  top -> bottom
702// 3 args:  top -> horizontal -> bottom
703// 4 args:  top -> right -> bottom -> left
704// 5+ args: do nothing.
705func whichSidesInt(i ...int) (top, right, bottom, left int, ok bool) {
706	switch len(i) {
707	case 1:
708		top = i[0]
709		bottom = i[0]
710		left = i[0]
711		right = i[0]
712		ok = true
713	case 2: //nolint:mnd
714		top = i[0]
715		bottom = i[0]
716		left = i[1]
717		right = i[1]
718		ok = true
719	case 3: //nolint:mnd
720		top = i[0]
721		left = i[1]
722		right = i[1]
723		bottom = i[2]
724		ok = true
725	case 4: //nolint:mnd
726		top = i[0]
727		right = i[1]
728		bottom = i[2]
729		left = i[3]
730		ok = true
731	}
732	return top, right, bottom, left, ok
733}
734
735// whichSidesBool is like whichSidesInt, except it operates on a series of
736// boolean values. See the comment on whichSidesInt for details on how this
737// works.
738func whichSidesBool(i ...bool) (top, right, bottom, left bool, ok bool) {
739	switch len(i) {
740	case 1:
741		top = i[0]
742		bottom = i[0]
743		left = i[0]
744		right = i[0]
745		ok = true
746	case 2: //nolint:mnd
747		top = i[0]
748		bottom = i[0]
749		left = i[1]
750		right = i[1]
751		ok = true
752	case 3: //nolint:mnd
753		top = i[0]
754		left = i[1]
755		right = i[1]
756		bottom = i[2]
757		ok = true
758	case 4: //nolint:mnd
759		top = i[0]
760		right = i[1]
761		bottom = i[2]
762		left = i[3]
763		ok = true
764	}
765	return top, right, bottom, left, ok
766}
767
768// whichSidesColor is like whichSides, except it operates on a series of
769// boolean values. See the comment on whichSidesInt for details on how this
770// works.
771func whichSidesColor(i ...TerminalColor) (top, right, bottom, left TerminalColor, ok bool) {
772	switch len(i) {
773	case 1:
774		top = i[0]
775		bottom = i[0]
776		left = i[0]
777		right = i[0]
778		ok = true
779	case 2: //nolint:mnd
780		top = i[0]
781		bottom = i[0]
782		left = i[1]
783		right = i[1]
784		ok = true
785	case 3: //nolint:mnd
786		top = i[0]
787		left = i[1]
788		right = i[1]
789		bottom = i[2]
790		ok = true
791	case 4: //nolint:mnd
792		top = i[0]
793		right = i[1]
794		bottom = i[2]
795		left = i[3]
796		ok = true
797	}
798	return top, right, bottom, left, ok
799}