turbo-editors/turbo-corepublic Fork 0
28d59854361aeda8541d853093e732126f3d7bff
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.

statusbar.go · 120 lines · 3.4 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 17h ago1package ui
2
3import (
4 "github.com/gdamore/tcell/v2"
5
6 "codeberg.org/turbo-editors/turbo-core/theme"
7)
8
9// StatusItem is one clickable hint on the status bar, such as "F2 Save".
10type StatusItem struct {
11 Key string
12 Label string
13 Action func()
14}
15
16// width returns how many cells the item occupies, the separating space
17// included.
18func (s StatusItem) width() int {
19 return len([]rune(s.Key)) + 1 + len([]rune(s.Label)) + 2
20}
21
22// StatusBar is the row of key hints along the bottom of the screen.
23//
24// A message set with SetMessage temporarily replaces the hints, which is how
25// the editor reports "File saved" or a language-server error without opening a
26// dialog for it.
27type StatusBar struct {
28 Box
29 items []StatusItem
30 message string
31 extra string
32}
33
34// NewStatusBar returns a status bar showing the given hints.
35func NewStatusBar(items ...StatusItem) *StatusBar {
36 return &StatusBar{items: items}
37}
38
39// SetItems replaces the hints, as changing context does.
40func (s *StatusBar) SetItems(items ...StatusItem) { s.items = items }
41
42// Message returns the message currently shown instead of the hints.
43func (s *StatusBar) Message() string { return s.message }
44
45// SetMessage shows a message in place of the hints. Pass the empty string to
46// bring the hints back.
47func (s *StatusBar) SetMessage(message string) { s.message = message }
48
49// SetExtra sets the text shown right-aligned, which the editor uses for the
50// cursor position and the language-server state.
51func (s *StatusBar) SetExtra(extra string) { s.extra = extra }
52
53// Draw paints the bar.
54func (s *StatusBar) Draw(p *Painter, th *theme.Theme) {
55 bar := p.Sub(s.Bounds())
56 normal := th.Style(theme.KeyStatusBar)
57 bar.Clear(normal)
58
59 // The right-aligned text is drawn first and its start becomes the limit
60 // for everything on the left, so the two can never overwrite each other.
61 limit := s.drawExtra(bar, th)
62
63 if s.message != "" {
64 bar.TextLimited(1, 0, limit-1, s.message, normal)
65 return
66 }
67 s.drawItems(bar, th, limit)
68}
69
70// drawItems paints the key hints from the left, stopping at limit.
71func (s *StatusBar) drawItems(p *Painter, th *theme.Theme, limit int) {
72 normal, key := th.Style(theme.KeyStatusBar), th.Style(theme.KeyStatusBarKey)
73
74 x := 1
75 for _, item := range s.items {
76 if x+item.width() > limit {
77 return // the rest would run into the right-aligned text
78 }
79 x = p.Text(x, 0, item.Key, key)
80 x = p.Text(x, 0, " "+item.Label+" ", normal)
81 }
82}
83
84// drawExtra paints the right-aligned text and returns the column it starts at,
85// which is where everything drawn from the left has to stop.
86func (s *StatusBar) drawExtra(p *Painter, th *theme.Theme) int {
87 width := p.Size().W
88 if s.extra == "" {
89 return width
90 }
91
92 // The text is cut from the left when it is too long, so that the part
93 // that matters most — the cursor position — is the part that survives.
94 text := []rune(s.extra)
95 if len(text) > width-2 {
96 text = text[:max(width-2, 0)]
97 }
98
99 x := max(width-len(text)-1, 0)
100 p.Text(x, 0, string(text), th.Style(theme.KeyStatusBarHint))
101 return x
102}
103
104// HandleMouse runs the action of the hint that was clicked.
105func (s *StatusBar) HandleMouse(ev *tcell.EventMouse) bool {
106 if !s.hit(ev) || ev.Buttons() != tcell.Button1 || s.message != "" {
107 return s.hit(ev)
108 }
109
110 x, _ := ev.Position()
111 cursor := s.Bounds().X + 1
112 for _, item := range s.items {
113 if x >= cursor && x < cursor+item.width() && item.Action != nil {
114 item.Action()
115 return true
116 }
117 cursor += item.width()
118 }
119 return true
120}