model.go RawHistoryFolder
1package prompt
2
3import (
4 renderer "github.com/bnema/vev-vt"
5 "github.com/bnema/vev/internal/domain"
6 "github.com/bnema/vev/internal/usecase/ui"
7)
8
9// RenderStyles contains daemon-supplied semantic chrome roles. The zero value
10// is intentionally not used by RenderStyled; isolated Render callers retain
11// the historic neutral defaults.
12type RenderStyles struct {
13 Base renderer.Style
14 Selection renderer.Style
15}
16
17type Model struct {
18 title string
19 text ui.TextInput
20 errMsg string
21}
22
23func New(title, initial string) *Model {
24 m := &Model{title: title}
25 m.text.SetValue(initial)
26 return m
27}
28
29func (m *Model) Insert(r rune) {
30 if m == nil {
31 return
32 }
33 m.errMsg = ""
34 m.text.Insert(r)
35}
36
37func (m *Model) Backspace() {
38 if m == nil {
39 return
40 }
41 m.errMsg = ""
42 m.text.Backspace()
43}
44
45func (m *Model) Value() string {
46 if m == nil {
47 return ""
48 }
49 return m.text.Value()
50}
51
52// promptInputPrefix leads the value line on row 0 of the rendered frame.
53const promptInputPrefix = "> "
54
55// Caret is the value caret column on row 0 of a Render frame of size inner
56// (see ui.InputCaret).
57func (m *Model) Caret(inner domain.Size) (int, bool) {
58 return ui.InputCaret(inner, promptInputPrefix, m.Value())
59}
60
61func (m *Model) Title() string {
62 if m == nil {
63 return ""
64 }
65 return m.title
66}
67
68func (m *Model) SetError(msg string) {
69 if m != nil {
70 m.errMsg = msg
71 }
72}
73
74func (m *Model) Render(inner domain.Size, accentStyle ...renderer.Style) renderer.Frame {
75 base := renderer.DefaultStyle()
76 selection := base
77 selection.Inverse = true
78 if len(accentStyle) > 0 {
79 selection = accentStyle[0]
80 }
81 return m.RenderStyled(inner, RenderStyles{Base: base, Selection: selection})
82}
83
84// RenderStyled renders with explicit chrome roles captured by the daemon.
85func (m *Model) RenderStyled(inner domain.Size, styles RenderStyles) renderer.Frame {
86 frame := renderer.NewFrame(max(inner.Cols, 0), max(inner.Rows, 0))
87 if frame.Width == 0 || frame.Height == 0 {
88 return frame
89 }
90 ui.FillRect(frame, domain.Rect{Width: frame.Width, Height: frame.Height}, renderer.Cell{Rune: ' ', Style: styles.Base})
91 ui.DrawInputLine(frame, 0, promptInputPrefix, m.Value(), styles.Base)
92 if frame.Height > 1 && m != nil && m.errMsg != "" {
93 ui.DrawText(frame, 0, 1, frame.Width, m.errMsg, styles.Selection)
94 }
95 return frame
96}