1package chat
2
3import (
4 "github.com/charmbracelet/bubbles/key"
5 "github.com/charmbracelet/bubbles/textarea"
6 tea "github.com/charmbracelet/bubbletea"
7 "github.com/charmbracelet/lipgloss"
8 "github.com/kujtimiihoxha/termai/internal/tui/layout"
9 "github.com/kujtimiihoxha/termai/internal/tui/styles"
10)
11
12type editorCmp struct {
13 textarea textarea.Model
14}
15
16type focusedEditorKeyMaps struct {
17 Send key.Binding
18 Blur key.Binding
19}
20
21type bluredEditorKeyMaps struct {
22 Send key.Binding
23 Focus key.Binding
24}
25
26var focusedKeyMaps = focusedEditorKeyMaps{
27 Send: key.NewBinding(
28 key.WithKeys("ctrl+s"),
29 key.WithHelp("ctrl+s", "send message"),
30 ),
31 Blur: key.NewBinding(
32 key.WithKeys("esc"),
33 key.WithHelp("esc", "blur editor"),
34 ),
35}
36
37var bluredKeyMaps = bluredEditorKeyMaps{
38 Send: key.NewBinding(
39 key.WithKeys("ctrl+s", "enter"),
40 key.WithHelp("ctrl+s/enter", "send message"),
41 ),
42 Focus: key.NewBinding(
43 key.WithKeys("i"),
44 key.WithHelp("i", "focus editor"),
45 ),
46}
47
48func (m *editorCmp) Init() tea.Cmd {
49 return textarea.Blink
50}
51
52func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
53 var cmd tea.Cmd
54 if m.textarea.Focused() {
55 switch msg := msg.(type) {
56 case tea.KeyMsg:
57 if key.Matches(msg, focusedKeyMaps.Send) {
58 // TODO: send message
59 m.textarea.Reset()
60 m.textarea.Blur()
61 return m, nil
62 }
63 if key.Matches(msg, focusedKeyMaps.Blur) {
64 m.textarea.Blur()
65 return m, nil
66 }
67 }
68 m.textarea, cmd = m.textarea.Update(msg)
69 return m, cmd
70 }
71 switch msg := msg.(type) {
72 case tea.KeyMsg:
73 if key.Matches(msg, bluredKeyMaps.Send) {
74 // TODO: send message
75 m.textarea.Reset()
76 return m, nil
77 }
78 if key.Matches(msg, bluredKeyMaps.Focus) {
79 m.textarea.Focus()
80 return m, textarea.Blink
81 }
82 }
83
84 return m, nil
85}
86
87func (m *editorCmp) View() string {
88 style := lipgloss.NewStyle().Padding(0, 0, 0, 1).Bold(true)
89
90 return lipgloss.JoinHorizontal(lipgloss.Top, style.Render(">"), m.textarea.View())
91}
92
93func (m *editorCmp) SetSize(width, height int) {
94 m.textarea.SetWidth(width - 3) // account for the prompt and padding right
95 m.textarea.SetHeight(height)
96}
97
98func (m *editorCmp) GetSize() (int, int) {
99 return m.textarea.Width(), m.textarea.Height()
100}
101
102func (m *editorCmp) BindingKeys() []key.Binding {
103 bindings := layout.KeyMapToSlice(m.textarea.KeyMap)
104 if m.textarea.Focused() {
105 bindings = append(bindings, layout.KeyMapToSlice(focusedKeyMaps)...)
106 } else {
107 bindings = append(bindings, layout.KeyMapToSlice(bluredKeyMaps)...)
108 }
109 return bindings
110}
111
112func NewEditorCmp() tea.Model {
113 ti := textarea.New()
114 ti.Prompt = " "
115 ti.ShowLineNumbers = false
116 ti.BlurredStyle.Base = ti.BlurredStyle.Base.Background(styles.Background)
117 ti.BlurredStyle.CursorLine = ti.BlurredStyle.CursorLine.Background(styles.Background)
118 ti.BlurredStyle.Placeholder = ti.BlurredStyle.Placeholder.Background(styles.Background)
119 ti.BlurredStyle.Text = ti.BlurredStyle.Text.Background(styles.Background)
120
121 ti.FocusedStyle.Base = ti.FocusedStyle.Base.Background(styles.Background)
122 ti.FocusedStyle.CursorLine = ti.FocusedStyle.CursorLine.Background(styles.Background)
123 ti.FocusedStyle.Placeholder = ti.FocusedStyle.Placeholder.Background(styles.Background)
124 ti.FocusedStyle.Text = ti.BlurredStyle.Text.Background(styles.Background)
125 ti.Focus()
126 return &editorCmp{
127 textarea: ti,
128 }
129}