turbo-editors/turbo-corepublic Fork 0
v0.9.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

picker_draw.go · 96 lines · 2.9 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 14h ago1// Drawing the picker: the popup that lists the agent's commands or the
2// project's files while a "/" or "@" word is being typed. Local coordinates,
3// like everything else in view_draw.go.
4
5package acp
6
7import (
8 "strings"
9
10 "codeberg.org/turbo-editors/turbo-core/theme"
11 "codeberg.org/turbo-editors/turbo-core/ui"
12)
13
14// drawPicker paints the popup just above the rule, over the bottom of the
15// conversation, when there is something to list.
16func (v *View) drawPicker(p *ui.Painter, th *theme.Theme) {
17 choices := v.refresh()
18 room := v.transcriptHeight()
19 if len(choices) == 0 || room < 3 {
20 v.picker.bounds = ui.Rect{}
21 return
22 }
23
24 height := min(min(len(choices), pickerRows)+2, room)
25 width := min(max(widestChoice(choices)+4, pickerMinWidth), p.Size().W)
26 bounds := ui.Rect{X: 0, Y: room - height, W: width, H: height}
27 v.picker.bounds = bounds
28
29 frame := th.Style(theme.KeyCompletionFrame)
30 for row := range height {
31 p.HLine(bounds.X, bounds.Y+row, width, ' ', th.Style(theme.KeyCompletionItem))
32 }
33 ui.DrawFrame(p, bounds, ui.FrameSingle, frame)
34 p.TextLimited(bounds.X+2, bounds.Y, max(width-4, 0), v.pickerTitle(), frame)
35
36 for row := range height - 2 {
37 index := v.picker.top + row
38 if index >= len(choices) {
39 break
40 }
41 v.drawChoice(p, th, row, choices[index], index == v.picker.selected)
42 }
43}
44
45// pickerTitle names what is being listed, on the frame.
46func (v *View) pickerTitle() string {
47 if _, word := v.typedWord(); strings.HasPrefix(word, string(mentionRune)) {
48 return " files "
49 }
50 return " commands "
51}
52
53// widestChoice is the width of the longest line the popup will show.
54func widestChoice(choices []Choice) int {
55 widest := 0
56 for _, choice := range choices {
57 widest = max(widest, len([]rune(choiceText(choice))))
58 }
59 return widest
60}
61
62// choiceText is one line of the popup as plain text: the label, the
63// description, and the hint in angle brackets.
64func choiceText(choice Choice) string {
65 text := choice.Label
66 if choice.Detail != "" {
67 text += " " + choice.Detail
68 }
69 if choice.Hint != "" {
70 text += " <" + choice.Hint + ">"
71 }
72 return text
73}
74
75// drawChoice paints one line of the popup — row rows below the frame's top,
76// inside the bounds drawPicker just recorded: the label in the item colour,
77// the rest in the detail colour, the whole row highlighted when it is the one.
78func (v *View) drawChoice(p *ui.Painter, th *theme.Theme, row int, choice Choice, selected bool) {
79 style := th.Style(theme.KeyCompletionItem)
80 detail := th.Style(theme.KeyCompletionDetail)
81 if selected {
82 style = th.Style(theme.KeyCompletionSelected)
83 detail = style
84 }
85
86 bounds := v.picker.bounds
87 x, y := bounds.X+1, bounds.Y+1+row
88 width := bounds.W - 2
89 p.HLine(x, y, width, ' ', style)
90
91 end := p.TextLimited(x, y, width, choice.Label, style)
92 rest := strings.TrimPrefix(choiceText(choice), choice.Label)
93 if rest != "" && end < x+width {
94 p.TextLimited(end, y, x+width-end, rest, detail)
95 }
96}