width.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package uniseg
  2. // EastAsianAmbiguousWidth specifies the monospace width for East Asian
  3. // characters classified as Ambiguous. The default is 1 but some rare fonts
  4. // render them with a width of 2.
  5. var EastAsianAmbiguousWidth = 1
  6. // runeWidth returns the monospace width for the given rune. The provided
  7. // grapheme property is a value mapped by the [graphemeCodePoints] table.
  8. //
  9. // Every rune has a width of 1, except for runes with the following properties
  10. // (evaluated in this order):
  11. //
  12. // - Control, CR, LF, Extend, ZWJ: Width of 0
  13. // - \u2e3a, TWO-EM DASH: Width of 3
  14. // - \u2e3b, THREE-EM DASH: Width of 4
  15. // - East-Asian width Fullwidth and Wide: Width of 2 (Ambiguous and Neutral
  16. // have a width of 1)
  17. // - Regional Indicator: Width of 2
  18. // - Extended Pictographic: Width of 2, unless Emoji Presentation is "No".
  19. func runeWidth(r rune, graphemeProperty int) int {
  20. switch graphemeProperty {
  21. case prControl, prCR, prLF, prExtend, prZWJ:
  22. return 0
  23. case prRegionalIndicator:
  24. return 2
  25. case prExtendedPictographic:
  26. if property(emojiPresentation, r) == prEmojiPresentation {
  27. return 2
  28. }
  29. return 1
  30. }
  31. switch r {
  32. case 0x2e3a:
  33. return 3
  34. case 0x2e3b:
  35. return 4
  36. }
  37. switch propertyEastAsianWidth(r) {
  38. case prW, prF:
  39. return 2
  40. case prA:
  41. return EastAsianAmbiguousWidth
  42. }
  43. return 1
  44. }
  45. // StringWidth returns the monospace width for the given string, that is, the
  46. // number of same-size cells to be occupied by the string.
  47. func StringWidth(s string) (width int) {
  48. state := -1
  49. for len(s) > 0 {
  50. var w int
  51. _, s, w, state = FirstGraphemeClusterInString(s, state)
  52. width += w
  53. }
  54. return
  55. }