width.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package liner
  2. import "unicode"
  3. // These character classes are mostly zero width (when combined).
  4. // A few might not be, depending on the user's font. Fixing this
  5. // is non-trivial, given that some terminals don't support
  6. // ANSI DSR/CPR
  7. var zeroWidth = []*unicode.RangeTable{
  8. unicode.Mn,
  9. unicode.Me,
  10. unicode.Cc,
  11. unicode.Cf,
  12. }
  13. var doubleWidth = []*unicode.RangeTable{
  14. unicode.Han,
  15. unicode.Hangul,
  16. unicode.Hiragana,
  17. unicode.Katakana,
  18. }
  19. // countGlyphs considers zero-width characters to be zero glyphs wide,
  20. // and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide.
  21. func countGlyphs(s []rune) int {
  22. n := 0
  23. for _, r := range s {
  24. // speed up the common case
  25. if r < 127 {
  26. n++
  27. continue
  28. }
  29. switch {
  30. case unicode.IsOneOf(zeroWidth, r):
  31. case unicode.IsOneOf(doubleWidth, r):
  32. n += 2
  33. default:
  34. n++
  35. }
  36. }
  37. return n
  38. }
  39. func countMultiLineGlyphs(s []rune, columns int, start int) int {
  40. n := start
  41. for _, r := range s {
  42. if r < 127 {
  43. n++
  44. continue
  45. }
  46. switch {
  47. case unicode.IsOneOf(zeroWidth, r):
  48. case unicode.IsOneOf(doubleWidth, r):
  49. n += 2
  50. // no room for a 2-glyphs-wide char in the ending
  51. // so skip a column and display it at the beginning
  52. if n%columns == 1 {
  53. n++
  54. }
  55. default:
  56. n++
  57. }
  58. }
  59. return n
  60. }
  61. func getPrefixGlyphs(s []rune, num int) []rune {
  62. p := 0
  63. for n := 0; n < num && p < len(s); p++ {
  64. // speed up the common case
  65. if s[p] < 127 {
  66. n++
  67. continue
  68. }
  69. if !unicode.IsOneOf(zeroWidth, s[p]) {
  70. n++
  71. }
  72. }
  73. for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) {
  74. p++
  75. }
  76. return s[:p]
  77. }
  78. func getSuffixGlyphs(s []rune, num int) []rune {
  79. p := len(s)
  80. for n := 0; n < num && p > 0; p-- {
  81. // speed up the common case
  82. if s[p-1] < 127 {
  83. n++
  84. continue
  85. }
  86. if !unicode.IsOneOf(zeroWidth, s[p-1]) {
  87. n++
  88. }
  89. }
  90. return s[p:]
  91. }