Skip to content

Commit 5dc2956

Browse files
committed
Highlight current result using text styles not sizes
Works better when the current result is moved around
1 parent fbdce69 commit 5dc2956

File tree

3 files changed

+81
-57
lines changed

3 files changed

+81
-57
lines changed

kittens/choose_files/main.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,25 @@ type State struct {
3232
exclude_patterns []*regexp.Regexp
3333
score_patterns []ScorePattern
3434
search_text string
35+
current_idx int
3536
}
3637

37-
func (s State) BaseDir() string { return utils.IfElse(s.base_dir == "", default_cwd, s.base_dir) }
38-
func (s State) SelectDirs() bool { return s.select_dirs }
39-
func (s State) Multiselect() bool { return s.multiselect }
40-
func (s State) MaxDepth() int { return utils.IfElse(s.max_depth < 1, 4, s.max_depth) }
41-
func (s State) String() string { return utils.Repr(s) }
42-
func (s State) SearchText() string { return s.search_text }
38+
func (s State) BaseDir() string { return utils.IfElse(s.base_dir == "", default_cwd, s.base_dir) }
39+
func (s State) SelectDirs() bool { return s.select_dirs }
40+
func (s State) Multiselect() bool { return s.multiselect }
41+
func (s State) MaxDepth() int { return utils.IfElse(s.max_depth < 1, 4, s.max_depth) }
42+
func (s State) String() string { return utils.Repr(s) }
43+
func (s State) SearchText() string { return s.search_text }
44+
func (s *State) SetSearchText(val string) {
45+
if s.search_text != val {
46+
s.search_text = val
47+
s.current_idx = 0
48+
}
49+
}
4350
func (s State) ExcludePatterns() []*regexp.Regexp { return s.exclude_patterns }
4451
func (s State) ScorePatterns() []ScorePattern { return s.score_patterns }
52+
func (s State) CurrentIndex() int { return s.current_idx }
53+
func (s *State) SetCurrentIndex(val int) { s.current_idx = max(0, val) }
4554
func (s State) CurrentDir() string {
4655
return utils.IfElse(s.current_dir == "", s.BaseDir(), s.current_dir)
4756
}

kittens/choose_files/results.go

Lines changed: 64 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"unicode/utf8"
99

1010
"github.com/kovidgoyal/kitty/tools/icons"
11-
"github.com/kovidgoyal/kitty/tools/tui/loop"
1211
"github.com/kovidgoyal/kitty/tools/utils"
1312
"github.com/kovidgoyal/kitty/tools/utils/style"
1413
"github.com/kovidgoyal/kitty/tools/wcswidth"
@@ -55,26 +54,16 @@ func (h *Handler) draw_no_matches_message(in_progress bool) {
5554
}
5655

5756
const matching_position_style = "fg=green"
57+
const current_style = "fg=intense-white bold"
5858

59-
func (h *Handler) draw_matching_result(r *ResultItem) {
60-
icon := icon_for(r.abspath, r.dir_entry)
61-
h.lp.MoveCursorHorizontally(1)
62-
p, s, _ := strings.Cut(h.lp.SprintStyled(matching_position_style, " "), " ")
63-
h.lp.QueueWriteString(p)
64-
h.lp.DrawSizedText(icon, loop.SizedText{Scale: 2})
65-
h.lp.QueueWriteString(s)
66-
text := r.text
67-
available_width := (h.screen_size.width - 6) / 2
68-
add_ellipsis := false
69-
if wcswidth.Stringwidth(text) > available_width {
70-
text = wcswidth.TruncateToVisualLength(text, available_width-2)
71-
add_ellipsis = true
72-
}
73-
h.render_match_with_positions(text, add_ellipsis, r.positions, 2)
74-
}
75-
76-
func (h *Handler) render_match_with_positions(text string, add_ellipsis bool, positions []int, scale int) {
59+
func (h *Handler) render_match_with_positions(text string, add_ellipsis bool, positions []int, is_current bool) {
7760
prefix, suffix, _ := strings.Cut(h.lp.SprintStyled(matching_position_style, " "), " ")
61+
if is_current {
62+
p, s, _ := strings.Cut(h.lp.SprintStyled(current_style, " "), " ")
63+
h.lp.QueueWriteString(p)
64+
defer h.lp.QueueWriteString(s)
65+
suffix += p
66+
}
7867
write_chunk := func(text string, emphasize bool) {
7968
if text == "" {
8069
return
@@ -85,11 +74,7 @@ func (h *Handler) render_match_with_positions(text string, add_ellipsis bool, po
8574
h.lp.QueueWriteString(suffix)
8675
}()
8776
}
88-
if scale > 1 {
89-
h.lp.DrawSizedText(text, loop.SizedText{Scale: scale})
90-
} else {
91-
h.lp.QueueWriteString(text)
92-
}
77+
h.lp.QueueWriteString(text)
9378
}
9479
at := 0
9580
limit := len(text)
@@ -129,29 +114,40 @@ func icon_for(path string, x os.DirEntry) string {
129114
return ans
130115
}
131116

132-
func (h *Handler) draw_column_of_matches(matches []*ResultItem, x, available_width, num_extra_matches int) {
117+
func (h *Handler) draw_column_of_matches(matches []*ResultItem, current_idx int, x, available_width, num_before, num_after int) {
118+
if num_before > 0 {
119+
h.lp.QueueWriteString("\r")
120+
h.lp.MoveCursorHorizontally(x)
121+
h.lp.QueueWriteString("… ")
122+
text := h.lp.SprintStyled("italic", fmt.Sprintf("%d prev matches", num_before))
123+
h.render_match_with_positions(text, false, nil, false)
124+
}
133125
for i, m := range matches {
134126
h.lp.QueueWriteString("\r")
135127
h.lp.MoveCursorHorizontally(x)
136128
icon := icon_for(m.abspath, m.dir_entry)
137-
text := ""
129+
text := m.text
138130
add_ellipsis := false
139-
positions := m.positions
140-
if num_extra_matches > 0 && i == len(matches)-1 {
141-
icon = "… "
142-
text = h.lp.SprintStyled("italic", fmt.Sprintf("%d more matches", num_extra_matches))
143-
positions = nil
131+
if wcswidth.Stringwidth(text) > available_width-3 {
132+
text = wcswidth.TruncateToVisualLength(text, available_width-4)
133+
add_ellipsis = true
134+
}
135+
is_current := i == current_idx
136+
if is_current {
137+
h.lp.QueueWriteString(h.lp.SprintStyled(matching_position_style, icon+" "))
144138
} else {
145-
text = m.text
146-
if wcswidth.Stringwidth(text) > available_width-3 {
147-
text = wcswidth.TruncateToVisualLength(text, available_width-4)
148-
add_ellipsis = true
149-
}
139+
h.lp.QueueWriteString(icon + " ")
150140
}
151-
h.lp.QueueWriteString(icon + " ")
152-
h.render_match_with_positions(text, add_ellipsis, positions, 1)
141+
h.render_match_with_positions(text, add_ellipsis, m.positions, is_current)
153142
h.lp.MoveCursorVertically(1)
154143
}
144+
if num_after > 0 {
145+
h.lp.QueueWriteString("\r")
146+
h.lp.MoveCursorHorizontally(x)
147+
h.lp.QueueWriteString("… ")
148+
text := h.lp.SprintStyled("italic", fmt.Sprintf("%d more matches", num_after))
149+
h.render_match_with_positions(text, false, nil, false)
150+
}
155151
}
156152

157153
func (h *Handler) draw_list_of_results(matches []*ResultItem, y, height int) {
@@ -169,14 +165,39 @@ func (h *Handler) draw_list_of_results(matches []*ResultItem, y, height int) {
169165
}
170166
col_width = available_width / num_cols
171167
}
168+
num_that_can_be_displayed := num_cols * height
169+
num_after, num_before := 0, 0
170+
idx := min(h.state.CurrentIndex(), len(matches)-1)
171+
if idx == 0 {
172+
num_after = max(0, len(matches)-num_that_can_be_displayed)
173+
} else {
174+
num_after = max(0, len(matches)-num_that_can_be_displayed)
175+
last_idx := len(matches) - 1 - num_after
176+
if last_idx < idx {
177+
num_before = last_idx - idx
178+
num_after = max(0, num_after-num_before)
179+
}
180+
}
181+
pos := num_before
172182
x := 1
173183
for i := range num_cols {
174-
is_last := i == num_cols-1
175-
chunk := matches[:min(len(matches), height)]
176-
matches = matches[len(chunk):]
184+
is_last, is_first := i == num_cols-1, i == 0
185+
num := height
186+
if is_first && num_before > 0 {
187+
num--
188+
}
189+
if is_last && num_after > 0 {
190+
num--
191+
}
177192
h.lp.MoveCursorTo(x, y)
178-
h.draw_column_of_matches(chunk, x, col_width-1, utils.IfElse(is_last, len(matches), 0))
193+
limit := min(len(matches), pos+num)
194+
h.draw_column_of_matches(matches[pos:limit], idx-pos, x, col_width-1, num_before, utils.IfElse(is_last, len(matches)-limit, 0))
179195
x += col_width
196+
pos += num
197+
num_before = 0
198+
if pos >= len(matches) {
199+
break
200+
}
180201
}
181202
}
182203

@@ -192,14 +213,7 @@ func (h *Handler) draw_results(y, bottom_margin int, matches []*ResultItem, in_p
192213
case 0:
193214
h.draw_no_matches_message(in_progress)
194215
default:
195-
switch h.state.SearchText() {
196-
case "":
197-
h.draw_list_of_results(matches, y, height-2)
198-
default:
199-
h.draw_matching_result(matches[0])
200-
y += 2
201-
h.draw_list_of_results(matches[1:], y, height-4)
202-
}
216+
h.draw_list_of_results(matches, y, height-2)
203217
}
204218
return
205219
}

kittens/choose_files/search-bar.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ func (h *Handler) handle_edit_keys(ev *loop.KeyEvent) bool {
6464
if h.state.SearchText() == "" {
6565
h.lp.Beep()
6666
} else {
67-
h.state.search_text = h.state.search_text[:len(h.state.search_text)-1]
67+
g := wcswidth.SplitIntoGraphemes(h.state.search_text)
68+
h.state.SetSearchText(strings.Join(g[:len(g)-1], ""))
6869
return true
6970
}
7071
}

0 commit comments

Comments
 (0)