Skip to content

Commit 6ccdfc4

Browse files
committed
add commit message and flags input
1 parent 6055e4d commit 6ccdfc4

File tree

2 files changed

+158
-84
lines changed

2 files changed

+158
-84
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/mrados7/go-git-commands
1+
module github.com/mrados7/go-git-commands/g_c
22

33
go 1.21.5
44

main.go

Lines changed: 157 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,29 @@ import (
1212
tea "github.com/charmbracelet/bubbletea"
1313
)
1414

15+
var (
16+
focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#6FD0FB")).Bold(true)
17+
blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
18+
cursorStyle = focusedStyle.Copy()
19+
noStyle = lipgloss.NewStyle()
20+
21+
stagedFilesStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#10ffcb"))
22+
cursorModeHelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("244"))
23+
24+
focusedButton = focusedStyle.Copy().Render("[ Commit ]")
25+
blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Commit"))
26+
)
27+
1528
type (
1629
errMsg error
1730
)
1831

1932
type model struct {
20-
inputLabel string
21-
commitMessageInput textinput.Model
22-
flagsInput textinput.Model
23-
branch string
24-
err error
25-
askingForFlags bool
26-
stagedFiles []string
33+
focusInputIndex int
34+
inputs []textinput.Model
35+
branch string
36+
err error
37+
stagedFiles []string
2738
}
2839

2940
func main() {
@@ -38,11 +49,8 @@ func initialModel() model {
3849
if err != nil {
3950
log.Fatal(err)
4051
}
41-
stagedFiles, errStaged := getStagedFiles()
4252

43-
if errStaged != nil {
44-
log.Fatal(errStaged)
45-
}
53+
stagedFiles := getStagedFiles()
4654

4755
result := strings.Split(branch, "/")
4856

@@ -55,34 +63,77 @@ func initialModel() model {
5563
branchType := strings.ToUpper(result[0])
5664
ticketId := strings.ToUpper(result[1])
5765

58-
ti := textinput.New()
59-
ti.SetValue(fmt.Sprintf("[%s] [%s] ", branchType, ticketId))
60-
ti.Focus()
61-
ti.CharLimit = 156
62-
63-
return model{
64-
inputLabel: "Enter commit message:",
65-
commitMessageInput: ti,
66-
branch: branch,
67-
err: nil,
68-
stagedFiles: stagedFiles,
66+
m := model{
67+
inputs: make([]textinput.Model, 2),
68+
branch: branch,
69+
err: nil,
70+
focusInputIndex: 0,
71+
stagedFiles: stagedFiles,
72+
}
73+
74+
var t textinput.Model
75+
for i := range m.inputs {
76+
t = textinput.New()
77+
t.Cursor.Style = cursorStyle
78+
t.CharLimit = 72
79+
80+
switch i {
81+
case 0:
82+
t.SetValue(fmt.Sprintf("[%s] [%s] ", branchType, ticketId))
83+
t.Focus()
84+
t.PromptStyle = focusedStyle
85+
t.TextStyle = focusedStyle
86+
case 1:
87+
t.ShowSuggestions = true
88+
commitFlags := []string{
89+
"--message",
90+
"--all",
91+
"--patch",
92+
"--reuse-message",
93+
"--amend",
94+
"--signoff",
95+
"--no-verify",
96+
"--allow-empty",
97+
"--no-edit",
98+
}
99+
t.SetSuggestions(commitFlags)
100+
t.Placeholder = "Commit flags"
101+
}
102+
103+
m.inputs[i] = t
69104
}
105+
106+
return m
107+
}
108+
109+
func getCurrentGitBranch() (string, error) {
110+
cmd := exec.Command("git", "branch", "--show-current")
111+
output, err := cmd.CombinedOutput()
112+
if err != nil {
113+
return "", fmt.Errorf("error getting branch name: %v", err)
114+
}
115+
116+
return strings.TrimSpace(string(output)), nil
70117
}
71118

72119
func (m model) Init() tea.Cmd {
73120
return textinput.Blink
74121
}
75122

76123
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
77-
var cmd tea.Cmd
78-
79124
switch msg := msg.(type) {
80125
case tea.KeyMsg:
81126
switch msg.Type {
82-
case tea.KeyEnter:
83-
if m.askingForFlags {
127+
128+
// Set focus to next input
129+
case tea.KeyShiftTab, tea.KeyEnter, tea.KeyUp, tea.KeyDown:
130+
s := msg.String()
131+
132+
// Did the user press enter while the submit button was focused?
133+
// If so, exit.
134+
if s == "enter" && m.focusInputIndex == len(m.inputs) {
84135
// Execute git commit command with flags
85-
commitCmd := exec.Command("git", "commit", m.flagsInput.Value(), "-m", m.commitMessageInput.Value())
136+
commitCmd := exec.Command("git", "commit", m.inputs[0].Value(), "-m", m.inputs[1].Value())
86137
commitCmd.Stdout = os.Stdout
87138
commitCmd.Stderr = os.Stderr
88139

@@ -92,85 +143,108 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
92143
}
93144

94145
return m, tea.Quit
146+
}
147+
148+
// Cycle indexes
149+
if s == "up" || s == "shift+tab" {
150+
m.focusInputIndex--
95151
} else {
96-
m.inputLabel = "Commit flags"
97-
// Ask for commit flags
98-
flagsInput := textinput.New()
99-
commitFlags := []string{
100-
"--message",
101-
"--all",
102-
"--patch",
103-
"--reuse-message",
104-
"--amend",
105-
"--signoff",
106-
"--no-verify",
107-
"--allow-empty",
108-
"--no-edit",
152+
m.focusInputIndex++
153+
}
154+
155+
if m.focusInputIndex > len(m.inputs) {
156+
m.focusInputIndex = 0
157+
} else if m.focusInputIndex < 0 {
158+
m.focusInputIndex = len(m.inputs)
159+
}
160+
161+
cmds := make([]tea.Cmd, len(m.inputs))
162+
for i := 0; i <= len(m.inputs)-1; i++ {
163+
if i == m.focusInputIndex {
164+
// Set focused state
165+
cmds[i] = m.inputs[i].Focus()
166+
m.inputs[i].PromptStyle = focusedStyle
167+
m.inputs[i].TextStyle = focusedStyle
168+
continue
109169
}
110-
flagsInput.SetSuggestions(commitFlags)
111-
flagsInput.ShowSuggestions = true
112-
flagsInput.Focus()
113-
m.flagsInput = flagsInput
114-
m.askingForFlags = true
115-
return m, nil
170+
// Remove focused state
171+
m.inputs[i].Blur()
172+
m.inputs[i].PromptStyle = noStyle
173+
m.inputs[i].TextStyle = noStyle
116174
}
175+
176+
return m, tea.Batch(cmds...)
117177
case tea.KeyCtrlC, tea.KeyEsc:
118178
return m, tea.Quit
119179
}
120180
}
121181

122-
if m.askingForFlags {
123-
m.flagsInput, cmd = m.flagsInput.Update(msg)
124-
} else {
125-
m.commitMessageInput, cmd = m.commitMessageInput.Update(msg)
126-
}
182+
cmd := m.updateInputs(msg)
127183

128184
return m, cmd
129185
}
130186

131-
func (m model) View() string {
132-
var inputView string
133-
if m.askingForFlags {
134-
inputView = m.flagsInput.View()
135-
} else {
136-
inputView = m.commitMessageInput.View()
187+
func (m *model) updateInputs(msg tea.Msg) tea.Cmd {
188+
cmds := make([]tea.Cmd, len(m.inputs))
189+
190+
for i := range m.inputs {
191+
m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
137192
}
138193

139-
currentCommitMessage := "Current commit message: " + m.commitMessageInput.Value() + " " + m.flagsInput.Value()
194+
return tea.Batch(cmds...)
195+
}
140196

141-
stagedFiles := strings.Join(m.stagedFiles, "\n")
197+
func (m model) View() string {
198+
var b strings.Builder
142199

143-
currentBranch := lipgloss.NewStyle().Foreground(lipgloss.Color("#fbd87f")).SetString(fmt.Sprintf("Current branch: %s", m.branch))
144-
inputLabel := lipgloss.NewStyle().Foreground(lipgloss.Color("#b5f8fe")).SetString(m.inputLabel).Bold(true)
145-
inputStyle := lipgloss.NewStyle().SetString(inputView)
200+
currentBranch := lipgloss.NewStyle().Foreground(lipgloss.Color("#fcbda1")).SetString(fmt.Sprintf("Branch: %s", m.branch))
146201

147-
return fmt.Sprintf(
148-
"%s\n\n%s\n\n%s\n%s\n\n%s",
149-
currentBranch.Render(),
150-
currentCommitMessage,
151-
inputLabel.Render(),
152-
inputStyle.Render(),
153-
stagedFiles,
154-
) + "\n"
155-
}
202+
b.WriteString(currentBranch.Render())
203+
b.WriteRune('\n')
204+
b.WriteRune('\n')
156205

157-
// cmds
158-
func getCurrentGitBranch() (string, error) {
159-
cmd := exec.Command("git", "branch", "--show-current")
160-
output, err := cmd.CombinedOutput()
161-
if err != nil {
162-
return "", fmt.Errorf("error getting branch name: %v", err)
206+
currentCommitCommand := lipgloss.NewStyle().Foreground(lipgloss.Color("#a1e0fc")).SetString(fmt.Sprintf("git commit -m \"%s\" %s", m.inputs[0].Value(), m.inputs[1].Value()))
207+
208+
b.WriteString(currentCommitCommand.Render())
209+
b.WriteRune('\n')
210+
b.WriteRune('\n')
211+
212+
inputLabels := []string{"Commit message ", "Commit flags "}
213+
214+
for i := range m.inputs {
215+
if i == m.focusInputIndex {
216+
b.WriteString(lipgloss.NewStyle().Foreground(lipgloss.Color("#6FD0FB")).Bold(true).SetString(inputLabels[i]).Render())
217+
} else {
218+
b.WriteString(inputLabels[i])
219+
}
220+
b.WriteString(m.inputs[i].View())
221+
b.WriteRune('\n')
222+
if i < len(m.inputs)-1 {
223+
b.WriteRune('\n')
224+
}
163225
}
164226

165-
return strings.TrimSpace(string(output)), nil
227+
button := &blurredButton
228+
if m.focusInputIndex == len(m.inputs) {
229+
button = &focusedButton
230+
}
231+
fmt.Fprintf(&b, "\n\n%s\n\n", *button)
232+
233+
b.WriteString("Staged changes: ")
234+
b.WriteRune('\n')
235+
b.WriteString(stagedFilesStyle.Render(strings.Join(m.stagedFiles, "\n")))
236+
237+
b.WriteRune('\n')
238+
239+
return b.String()
166240
}
167241

168-
func getStagedFiles() ([]string, error) {
169-
cmd := exec.Command("git", "diff", "--cached", "--name-only")
170-
output, err := cmd.CombinedOutput()
242+
func getStagedFiles() []string {
243+
cmd := exec.Command("git", "diff", "--name-only", "--cached")
244+
out, err := cmd.Output()
171245
if err != nil {
172-
return nil, fmt.Errorf("error getting staged files: %v", err)
246+
return []string{}
173247
}
174248

175-
return strings.Split(strings.TrimSpace(string(output)), "\n"), nil
249+
return strings.Split(string(out), "\n")
176250
}

0 commit comments

Comments
 (0)