width.go 1.6 KB

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