family_list.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package choose_fonts
  2. import (
  3. "fmt"
  4. "kitty/tools/tui"
  5. "kitty/tools/tui/subseq"
  6. "kitty/tools/utils"
  7. "kitty/tools/wcswidth"
  8. )
  9. var _ = fmt.Print
  10. type FamilyList struct {
  11. families, all_families []string
  12. current_search string
  13. display_strings []string
  14. widths []int
  15. max_width, current_idx int
  16. }
  17. func (self *FamilyList) Len() int {
  18. return len(self.families)
  19. }
  20. func (self *FamilyList) Select(family string) bool {
  21. for idx, q := range self.families {
  22. if q == family {
  23. self.current_idx = idx
  24. return true
  25. }
  26. }
  27. return false
  28. }
  29. func (self *FamilyList) Next(delta int, allow_wrapping bool) bool {
  30. l := func() int { return self.Len() }
  31. if l() == 0 {
  32. return false
  33. }
  34. idx := self.current_idx + delta
  35. if !allow_wrapping && (idx < 0 || idx > l()) {
  36. return false
  37. }
  38. for idx < 0 {
  39. idx += l()
  40. }
  41. self.current_idx = idx % l()
  42. return true
  43. }
  44. func limit_lengths(text string) string {
  45. t, _ := wcswidth.TruncateToVisualLengthWithWidth(text, 31)
  46. if len(t) >= len(text) {
  47. return text
  48. }
  49. return t + "…"
  50. }
  51. func match(expression string, items []string) []*subseq.Match {
  52. matches := subseq.ScoreItems(expression, items, subseq.Options{Level1: " "})
  53. matches = utils.StableSort(matches, func(a, b *subseq.Match) int {
  54. if b.Score < a.Score {
  55. return -1
  56. }
  57. if b.Score > a.Score {
  58. return 1
  59. }
  60. return 0
  61. })
  62. return matches
  63. }
  64. const (
  65. MARK_BEFORE = "\033[33m"
  66. MARK_AFTER = "\033[39m"
  67. )
  68. func apply_search(families []string, expression string, marks ...string) (matched_families []string, display_strings []string) {
  69. mark_before, mark_after := MARK_BEFORE, MARK_AFTER
  70. if len(marks) == 2 {
  71. mark_before, mark_after = marks[0], marks[1]
  72. }
  73. results := utils.Filter(match(expression, families), func(x *subseq.Match) bool { return x.Score > 0 })
  74. matched_families = make([]string, 0, len(results))
  75. display_strings = make([]string, 0, len(results))
  76. for _, m := range results {
  77. text := m.Text
  78. positions := m.Positions
  79. for i := len(positions) - 1; i >= 0; i-- {
  80. p := positions[i]
  81. text = text[:p] + mark_before + text[p:p+1] + mark_after + text[p+1:]
  82. }
  83. display_strings = append(display_strings, text)
  84. matched_families = append(matched_families, m.Text)
  85. }
  86. return
  87. }
  88. func make_family_names_clickable(family string) string {
  89. id := wcswidth.StripEscapeCodes(family)
  90. return tui.InternalHyperlink(family, "family-chosen:"+id)
  91. }
  92. func (self *FamilyList) UpdateFamilies(families []string) {
  93. self.families, self.all_families = families, families
  94. if self.current_search != "" {
  95. self.families, self.display_strings = apply_search(self.all_families, self.current_search)
  96. self.display_strings = utils.Map(limit_lengths, self.display_strings)
  97. } else {
  98. self.display_strings = utils.Map(limit_lengths, families)
  99. }
  100. self.display_strings = utils.Map(make_family_names_clickable, self.display_strings)
  101. self.widths = utils.Map(wcswidth.Stringwidth, self.display_strings)
  102. self.max_width = utils.Max(0, self.widths...)
  103. self.current_idx = 0
  104. }
  105. func (self *FamilyList) UpdateSearch(query string) bool {
  106. if query == self.current_search || len(self.all_families) == 0 {
  107. return false
  108. }
  109. self.current_search = query
  110. self.UpdateFamilies(self.all_families)
  111. return true
  112. }
  113. type Line struct {
  114. text string
  115. width int
  116. is_current bool
  117. }
  118. func (self *FamilyList) Lines(num_rows int) []Line {
  119. if num_rows < 1 {
  120. return nil
  121. }
  122. ans := make([]Line, 0, len(self.display_strings))
  123. before_num := utils.Min(self.current_idx, num_rows-1)
  124. start := self.current_idx - before_num
  125. for i := start; i < utils.Min(start+num_rows, len(self.display_strings)); i++ {
  126. ans = append(ans, Line{self.display_strings[i], self.widths[i], i == self.current_idx})
  127. }
  128. return ans
  129. }
  130. func (self *FamilyList) SelectFamily(family string) bool {
  131. for i, f := range self.families {
  132. if f == family {
  133. self.current_idx = i
  134. return true
  135. }
  136. }
  137. return false
  138. }
  139. func (self *FamilyList) CurrentFamily() string {
  140. if self.current_idx >= 0 && self.current_idx < len(self.families) {
  141. return self.families[self.current_idx]
  142. }
  143. return ""
  144. }