Skip to content
This repository was archived by the owner on Sep 18, 2025. It is now read-only.

Commit 72afeb9

Browse files
committed
small fixes
1 parent 333ea6e commit 72afeb9

File tree

10 files changed

+106
-75
lines changed

10 files changed

+106
-75
lines changed

internal/diff/patch.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,9 @@ func (p *Parser) isDone(prefixes []string) bool {
9191
if p.index >= len(p.lines) {
9292
return true
9393
}
94-
if prefixes != nil {
95-
for _, prefix := range prefixes {
96-
if strings.HasPrefix(p.lines[p.index], prefix) {
97-
return true
98-
}
94+
for _, prefix := range prefixes {
95+
if strings.HasPrefix(p.lines[p.index], prefix) {
96+
return true
9997
}
10098
}
10199
return false
@@ -219,7 +217,7 @@ func (p *Parser) parseUpdateFile(text string) (PatchAction, error) {
219217
sectionStr = p.lines[p.index]
220218
p.index++
221219
}
222-
if !(defStr != "" || sectionStr != "" || index == 0) {
220+
if defStr == "" && sectionStr == "" && index != 0 {
223221
return action, NewDiffError(fmt.Sprintf("Invalid Line:\n%s", p.lines[p.index]))
224222
}
225223
if strings.TrimSpace(defStr) != "" {
@@ -433,12 +431,13 @@ func peekNextSection(lines []string, initialIndex int) ([]string, []Chunk, int,
433431
delLines = make([]string, 0, 8)
434432
insLines = make([]string, 0, 8)
435433
}
436-
if mode == "delete" {
434+
switch mode {
435+
case "delete":
437436
delLines = append(delLines, line)
438437
old = append(old, line)
439-
} else if mode == "add" {
438+
case "add":
440439
insLines = append(insLines, line)
441-
} else {
440+
default:
442441
old = append(old, line)
443442
}
444443
}
@@ -513,7 +512,7 @@ func IdentifyFilesAdded(text string) []string {
513512

514513
func getUpdatedFile(text string, action PatchAction, path string) (string, error) {
515514
if action.Type != ActionUpdate {
516-
return "", errors.New("Expected UPDATE action")
515+
return "", errors.New("expected UPDATE action")
517516
}
518517
origLines := strings.Split(text, "\n")
519518
destLines := make([]string, 0, len(origLines)) // Preallocate with capacity
@@ -543,18 +542,19 @@ func getUpdatedFile(text string, action PatchAction, path string) (string, error
543542
func PatchToCommit(patch Patch, orig map[string]string) (Commit, error) {
544543
commit := Commit{Changes: make(map[string]FileChange, len(patch.Actions))}
545544
for pathKey, action := range patch.Actions {
546-
if action.Type == ActionDelete {
545+
switch action.Type {
546+
case ActionDelete:
547547
oldContent := orig[pathKey]
548548
commit.Changes[pathKey] = FileChange{
549549
Type: ActionDelete,
550550
OldContent: &oldContent,
551551
}
552-
} else if action.Type == ActionAdd {
552+
case ActionAdd:
553553
commit.Changes[pathKey] = FileChange{
554554
Type: ActionAdd,
555555
NewContent: action.NewFile,
556556
}
557-
} else if action.Type == ActionUpdate {
557+
case ActionUpdate:
558558
newContent, err := getUpdatedFile(orig[pathKey], action, pathKey)
559559
if err != nil {
560560
return Commit{}, err
@@ -619,18 +619,19 @@ func LoadFiles(paths []string, openFn func(string) (string, error)) (map[string]
619619

620620
func ApplyCommit(commit Commit, writeFn func(string, string) error, removeFn func(string) error) error {
621621
for p, change := range commit.Changes {
622-
if change.Type == ActionDelete {
622+
switch change.Type {
623+
case ActionDelete:
623624
if err := removeFn(p); err != nil {
624625
return err
625626
}
626-
} else if change.Type == ActionAdd {
627+
case ActionAdd:
627628
if change.NewContent == nil {
628629
return NewDiffError(fmt.Sprintf("Add action for %s has nil new_content", p))
629630
}
630631
if err := writeFn(p, *change.NewContent); err != nil {
631632
return err
632633
}
633-
} else if change.Type == ActionUpdate {
634+
case ActionUpdate:
634635
if change.NewContent == nil {
635636
return NewDiffError(fmt.Sprintf("Update action for %s has nil new_content", p))
636637
}

internal/llm/agent/agent.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ func (a *agent) processGeneration(ctx context.Context, sessionID, content string
221221
agentMessage, toolResults, err := a.streamAndHandleEvents(ctx, sessionID, msgHistory)
222222
if err != nil {
223223
if errors.Is(err, context.Canceled) {
224+
agentMessage.AddFinish(message.FinishReasonCanceled)
225+
a.messages.Update(context.Background(), agentMessage)
224226
return a.err(ErrRequestCancelled)
225227
}
226228
return a.err(fmt.Errorf("failed to process events: %w", err))

internal/llm/tools/edit.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,20 +141,20 @@ func (e *editTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
141141
if params.OldString == "" {
142142
response, err = e.createNewFile(ctx, params.FilePath, params.NewString)
143143
if err != nil {
144-
return response, nil
144+
return response, err
145145
}
146146
}
147147

148148
if params.NewString == "" {
149149
response, err = e.deleteContent(ctx, params.FilePath, params.OldString)
150150
if err != nil {
151-
return response, nil
151+
return response, err
152152
}
153153
}
154154

155155
response, err = e.replaceContent(ctx, params.FilePath, params.OldString, params.NewString)
156156
if err != nil {
157-
return response, nil
157+
return response, err
158158
}
159159
if response.IsError {
160160
// Return early if there was an error during content replacement

internal/tui/components/chat/editor.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ type editorCmp struct {
2121
textarea textarea.Model
2222
}
2323

24+
type FocusEditorMsg bool
25+
2426
type focusedEditorKeyMaps struct {
2527
Send key.Binding
2628
OpenEditor key.Binding
@@ -112,7 +114,6 @@ func (m *editorCmp) send() tea.Cmd {
112114
util.CmdHandler(SendMsg{
113115
Text: value,
114116
}),
115-
util.CmdHandler(EditorFocusMsg(false)),
116117
)
117118
}
118119

@@ -124,9 +125,13 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
124125
m.session = msg
125126
}
126127
return m, nil
128+
case FocusEditorMsg:
129+
if msg {
130+
m.textarea.Focus()
131+
return m, tea.Batch(textarea.Blink, util.CmdHandler(EditorFocusMsg(true)))
132+
}
127133
case tea.KeyMsg:
128134
if key.Matches(msg, focusedKeyMaps.OpenEditor) {
129-
m.textarea.Blur()
130135
return m, openEditor()
131136
}
132137
// if the key does not match any binding, return

internal/tui/components/chat/list.go

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ import (
2222
"github.com/kujtimiihoxha/opencode/internal/tui/util"
2323
)
2424

25+
type cacheItem struct {
26+
width int
27+
content []uiMessage
28+
}
2529
type messagesCmp struct {
2630
app *app.App
2731
width, height int
@@ -32,8 +36,9 @@ type messagesCmp struct {
3236
uiMessages []uiMessage
3337
currentMsgID string
3438
mutex sync.Mutex
35-
cachedContent map[string][]uiMessage
39+
cachedContent map[string]cacheItem
3640
spinner spinner.Model
41+
lastUpdate time.Time
3742
rendering bool
3843
}
3944
type renderFinishedMsg struct{}
@@ -44,6 +49,8 @@ func (m *messagesCmp) Init() tea.Cmd {
4449

4550
func (m *messagesCmp) preloadSessions() tea.Cmd {
4651
return func() tea.Msg {
52+
m.mutex.Lock()
53+
defer m.mutex.Unlock()
4754
sessions, err := m.app.Sessions.List(context.Background())
4855
if err != nil {
4956
return util.ReportError(err)()
@@ -67,13 +74,13 @@ func (m *messagesCmp) preloadSessions() tea.Cmd {
6774
}
6875
logging.Debug("preloaded sessions")
6976

70-
return nil
77+
return func() tea.Msg {
78+
return renderFinishedMsg{}
79+
}
7180
}
7281
}
7382

7483
func (m *messagesCmp) cacheSessionMessages(messages []message.Message, width int) {
75-
m.mutex.Lock()
76-
defer m.mutex.Unlock()
7784
pos := 0
7885
if m.width == 0 {
7986
return
@@ -87,7 +94,10 @@ func (m *messagesCmp) cacheSessionMessages(messages []message.Message, width int
8794
width,
8895
pos,
8996
)
90-
m.cachedContent[msg.ID] = []uiMessage{userMsg}
97+
m.cachedContent[msg.ID] = cacheItem{
98+
width: width,
99+
content: []uiMessage{userMsg},
100+
}
91101
pos += userMsg.height + 1 // + 1 for spacing
92102
case message.Assistant:
93103
assistantMessages := renderAssistantMessage(
@@ -102,7 +112,10 @@ func (m *messagesCmp) cacheSessionMessages(messages []message.Message, width int
102112
for _, msg := range assistantMessages {
103113
pos += msg.height + 1 // + 1 for spacing
104114
}
105-
m.cachedContent[msg.ID] = assistantMessages
115+
m.cachedContent[msg.ID] = cacheItem{
116+
width: width,
117+
content: assistantMessages,
118+
}
106119
}
107120
}
108121
}
@@ -223,8 +236,8 @@ func (m *messagesCmp) renderView() {
223236
for inx, msg := range m.messages {
224237
switch msg.Role {
225238
case message.User:
226-
if messages, ok := m.cachedContent[msg.ID]; ok {
227-
m.uiMessages = append(m.uiMessages, messages...)
239+
if cache, ok := m.cachedContent[msg.ID]; ok && cache.width == m.width {
240+
m.uiMessages = append(m.uiMessages, cache.content...)
228241
continue
229242
}
230243
userMsg := renderUserMessage(
@@ -234,11 +247,14 @@ func (m *messagesCmp) renderView() {
234247
pos,
235248
)
236249
m.uiMessages = append(m.uiMessages, userMsg)
237-
m.cachedContent[msg.ID] = []uiMessage{userMsg}
250+
m.cachedContent[msg.ID] = cacheItem{
251+
width: m.width,
252+
content: []uiMessage{userMsg},
253+
}
238254
pos += userMsg.height + 1 // + 1 for spacing
239255
case message.Assistant:
240-
if messages, ok := m.cachedContent[msg.ID]; ok {
241-
m.uiMessages = append(m.uiMessages, messages...)
256+
if cache, ok := m.cachedContent[msg.ID]; ok && cache.width == m.width {
257+
m.uiMessages = append(m.uiMessages, cache.content...)
242258
continue
243259
}
244260
assistantMessages := renderAssistantMessage(
@@ -254,7 +270,10 @@ func (m *messagesCmp) renderView() {
254270
m.uiMessages = append(m.uiMessages, msg)
255271
pos += msg.height + 1 // + 1 for spacing
256272
}
257-
m.cachedContent[msg.ID] = assistantMessages
273+
m.cachedContent[msg.ID] = cacheItem{
274+
width: m.width,
275+
content: assistantMessages,
276+
}
258277
}
259278
}
260279

@@ -418,6 +437,10 @@ func (m *messagesCmp) SetSize(width, height int) tea.Cmd {
418437
m.height = height
419438
m.viewport.Width = width
420439
m.viewport.Height = height - 2
440+
for _, msg := range m.messages {
441+
delete(m.cachedContent, msg.ID)
442+
}
443+
m.uiMessages = make([]uiMessage, 0)
421444
m.renderView()
422445
return m.preloadSessions()
423446
}
@@ -456,7 +479,7 @@ func NewMessagesCmp(app *app.App) tea.Model {
456479
return &messagesCmp{
457480
app: app,
458481
writingMode: true,
459-
cachedContent: make(map[string][]uiMessage),
482+
cachedContent: make(map[string]cacheItem),
460483
viewport: viewport.New(0, 0),
461484
spinner: s,
462485
}

internal/tui/components/chat/message.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ func renderToolResponse(toolCall message.ToolCall, response message.ToolResult,
389389
errContent := fmt.Sprintf("Error: %s", strings.ReplaceAll(response.Content, "\n", " "))
390390
errContent = ansi.Truncate(errContent, width-1, "...")
391391
return styles.BaseStyle.
392+
Width(width).
392393
Foreground(styles.Error).
393394
Render(errContent)
394395
}

internal/tui/components/dialog/permission.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ type PermissionDialogCmp interface {
4040
}
4141

4242
type permissionsMapping struct {
43-
LeftRight key.Binding
43+
Left key.Binding
44+
Right key.Binding
4445
EnterSpace key.Binding
4546
Allow key.Binding
4647
AllowSession key.Binding
@@ -49,9 +50,13 @@ type permissionsMapping struct {
4950
}
5051

5152
var permissionsKeys = permissionsMapping{
52-
LeftRight: key.NewBinding(
53-
key.WithKeys("left", "right"),
54-
key.WithHelp("←/→", "switch options"),
53+
Left: key.NewBinding(
54+
key.WithKeys("left"),
55+
key.WithHelp("←", "switch options"),
56+
),
57+
Right: key.NewBinding(
58+
key.WithKeys("right"),
59+
key.WithHelp("→", "switch options"),
5560
),
5661
EnterSpace: key.NewBinding(
5762
key.WithKeys("enter", " "),
@@ -104,21 +109,18 @@ func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
104109
p.diffCache = make(map[string]string)
105110
case tea.KeyMsg:
106111
switch {
107-
case key.Matches(msg, permissionsKeys.LeftRight) || key.Matches(msg, permissionsKeys.Tab):
108-
// Change selected option
112+
case key.Matches(msg, permissionsKeys.Right) || key.Matches(msg, permissionsKeys.Tab):
109113
p.selectedOption = (p.selectedOption + 1) % 3
110114
return p, nil
115+
case key.Matches(msg, permissionsKeys.Left):
116+
p.selectedOption = (p.selectedOption + 2) % 3
111117
case key.Matches(msg, permissionsKeys.EnterSpace):
112-
// Select current option
113118
return p, p.selectCurrentOption()
114119
case key.Matches(msg, permissionsKeys.Allow):
115-
// Select Allow
116120
return p, util.CmdHandler(PermissionResponseMsg{Action: PermissionAllow, Permission: p.permission})
117121
case key.Matches(msg, permissionsKeys.AllowSession):
118-
// Select Allow for session
119122
return p, util.CmdHandler(PermissionResponseMsg{Action: PermissionAllowForSession, Permission: p.permission})
120123
case key.Matches(msg, permissionsKeys.Deny):
121-
// Select Deny
122124
return p, util.CmdHandler(PermissionResponseMsg{Action: PermissionDeny, Permission: p.permission})
123125
default:
124126
// Pass other keys to viewport

0 commit comments

Comments
 (0)