set.go 22 KB

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