on main help sign in
fix(bangmode): include bang commands in history

๐Ÿ’˜ Generated with Crush Assisted-by: Crush:qwen3.7-max

commitf342edf052ef1ca35fb202c235a976b9ef6f45f9 authorChristian Rocha <christian@rocha.is> dateFri 19 Jun 2026, 20:24 (4 months ago) parent7e4bd6a
2 files changed+30โˆ’1
internal/ui/model/history.go+28 internal/ui/model/ui.go+2โˆ’1
internal/ui/model/history.go+28
@@ -3,6 +3,7 @@ package model
33import (
44 "context"
55 "log/slog"
6+ "strings"
67
78 tea "charm.land/bubbletea/v2"
89
@@ -36,6 +37,9 @@ func (m *UI) loadPromptHistory() tea.Cmd {
3637 if text := msg.Content().Text; text != "" {
3738 texts = append(texts, text)
3839 }
40+ for _, sc := range msg.ShellCommands() {
41+ texts = append(texts, "!"+sc.Command)
42+ }
3943 }
4044 return promptHistoryLoadedMsg{messages: texts}
4145 }
@@ -93,6 +97,7 @@ func (m *UI) handleHistoryEscape(msg tea.Msg) tea.Cmd {
9397 m.promptHistory.index = -1
9498 m.textarea.Reset()
9599 m.textarea.InsertString(m.promptHistory.draft)
100+ m.syncBangModeFromTextarea()
96101 return m.updateTextareaWithPrevHeight(nil, prevHeight)
97102 }
98103
@@ -108,6 +113,26 @@ func (m *UI) updateHistoryDraft(oldValue string) {
108113 }
109114}
110115
116+// syncBangModeFromTextarea engages or disengages bang mode based on
117+// whether the current textarea value starts with "!". The "!" prefix
118+// is stripped when entering bang mode and re-added when leaving it so
119+// the visible text always reflects the correct state.
120+func (m *UI) syncBangModeFromTextarea() {
121+ val := m.textarea.Value()
122+ hasBang := strings.HasPrefix(val, "!")
123+ if hasBang && !m.bangMode {
124+ m.bangMode = true
125+ m.bangWasEmpty = false
126+ m.textarea.SetValue(val[1:])
127+ m.textarea.MoveToBegin()
128+ } else if !hasBang && m.bangMode {
129+ m.bangMode = false
130+ m.bangWasEmpty = false
131+ }
132+ yolo := m.com.Workspace.PermissionSkipRequests()
133+ m.setEditorPrompt(yolo)
134+}
135+
111136// historyPrev changes the text area content to the previous message in the history
112137// it returns false if it could not find the previous message.
113138func (m *UI) historyPrev() bool {
@@ -125,6 +150,7 @@ func (m *UI) historyPrev() bool {
125150 m.textarea.Reset()
126151 m.textarea.InsertString(m.promptHistory.messages[nextIndex])
127152 m.textarea.MoveToBegin()
153+ m.syncBangModeFromTextarea()
128154 return true
129155}
130156
@@ -139,11 +165,13 @@ func (m *UI) historyNext() bool {
139165 m.promptHistory.index = -1
140166 m.textarea.Reset()
141167 m.textarea.InsertString(m.promptHistory.draft)
168+ m.syncBangModeFromTextarea()
142169 return true
143170 }
144171 m.promptHistory.index = nextIndex
145172 m.textarea.Reset()
146173 m.textarea.InsertString(m.promptHistory.messages[nextIndex])
174+ m.syncBangModeFromTextarea()
147175 return true
148176}
149177
internal/ui/model/ui.go+2โˆ’1
@@ -1014,6 +1014,7 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
10141014 cmds = append(cmds, cmd)
10151015 }
10161016 }
1017+ cmds = append(cmds, m.loadPromptHistory())
10171018 case hyperRefreshDoneMsg:
10181019 if cmd := m.handleSelectModel(msg.action); cmd != nil {
10191020 cmds = append(cmds, cmd)
@@ -2080,7 +2081,7 @@ func (m *UI) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
20802081 m.setEditorPrompt(yolo)
20812082 m.randomizePlaceholders()
20822083 m.historyReset()
2083โˆ’ return tea.Batch(m.runShellCommand(value), m.loadPromptHistory())
2084+ return tea.Batch(m.runShellCommand(value))
20842085 }
20852086
20862087 attachments := m.attachments.List()