1package model
2
3import (
4 "fmt"
5 "log/slog"
6 "strings"
7
8 "charm.land/bubbles/v2/key"
9 tea "charm.land/bubbletea/v2"
10 "charm.land/lipgloss/v2"
11 "github.com/charmbracelet/crush/internal/config"
12 "github.com/charmbracelet/crush/internal/home"
13 "github.com/charmbracelet/crush/internal/ui/common"
14)
15
16// markProjectInitialized marks the current project as initialized in the config.
17func (m *UI) markProjectInitialized() tea.Msg {
18 // TODO: handle error so we show it in the tui footer
19 err := config.MarkProjectInitialized()
20 if err != nil {
21 slog.Error(err.Error())
22 }
23 return nil
24}
25
26// updateInitializeView handles keyboard input for the project initialization prompt.
27func (m *UI) updateInitializeView(msg tea.KeyPressMsg) (cmds []tea.Cmd) {
28 switch {
29 case key.Matches(msg, m.keyMap.Initialize.Enter):
30 if m.onboarding.yesInitializeSelected {
31 cmds = append(cmds, m.initializeProject())
32 } else {
33 cmds = append(cmds, m.skipInitializeProject())
34 }
35 case key.Matches(msg, m.keyMap.Initialize.Switch):
36 m.onboarding.yesInitializeSelected = !m.onboarding.yesInitializeSelected
37 case key.Matches(msg, m.keyMap.Initialize.Yes):
38 cmds = append(cmds, m.initializeProject())
39 case key.Matches(msg, m.keyMap.Initialize.No):
40 cmds = append(cmds, m.skipInitializeProject())
41 }
42 return cmds
43}
44
45// initializeProject starts project initialization and transitions to the landing view.
46func (m *UI) initializeProject() tea.Cmd {
47 // TODO: initialize the project
48 // for now we just go to the landing page
49 m.state = uiLanding
50 m.focus = uiFocusEditor
51 // TODO: actually send a message to the agent
52 return m.markProjectInitialized
53}
54
55// skipInitializeProject skips project initialization and transitions to the landing view.
56func (m *UI) skipInitializeProject() tea.Cmd {
57 // TODO: initialize the project
58 m.state = uiLanding
59 m.focus = uiFocusEditor
60 // mark the project as initialized
61 return m.markProjectInitialized
62}
63
64// initializeView renders the project initialization prompt with Yes/No buttons.
65func (m *UI) initializeView() string {
66 cfg := m.com.Config()
67 s := m.com.Styles.Initialize
68 cwd := home.Short(cfg.WorkingDir())
69 initFile := cfg.Options.InitializeAs
70
71 header := s.Header.Render("Would you like to initialize this project?")
72 path := s.Accent.PaddingLeft(2).Render(cwd)
73 desc := s.Content.Render(fmt.Sprintf("When I initialize your codebase I examine the project and put the result into an %s file which serves as general context.", initFile))
74 hint := s.Content.Render("You can also initialize anytime via ") + s.Accent.Render("ctrl+p") + s.Content.Render(".")
75 prompt := s.Content.Render("Would you like to initialize now?")
76
77 buttons := common.ButtonGroup(m.com.Styles, []common.ButtonOpts{
78 {Text: "Yep!", Selected: m.onboarding.yesInitializeSelected},
79 {Text: "Nope", Selected: !m.onboarding.yesInitializeSelected},
80 }, " ")
81
82 // max width 60 so the text is compact
83 width := min(m.layout.main.Dx(), 60)
84
85 return lipgloss.NewStyle().
86 Width(width).
87 Height(m.layout.main.Dy()).
88 PaddingBottom(1).
89 AlignVertical(lipgloss.Bottom).
90 Render(strings.Join(
91 []string{
92 header,
93 path,
94 desc,
95 hint,
96 prompt,
97 buttons,
98 },
99 "\n\n",
100 ))
101}