width.go 1.3 KB

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