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

Commit 4d9082c

Browse files
committed
remove edit/normal mode
1 parent 1b22acb commit 4d9082c

File tree

10 files changed

+92
-116
lines changed

10 files changed

+92
-116
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# OpenCode
1+
# OpenCode
22

33
> **⚠️ Early Development Notice:** This project is in early development and is not yet ready for production use. Features may change, break, or be incomplete. Use at your own risk.
44

internal/tui/components/chat/editor.go

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ type FocusEditorMsg bool
2626
type focusedEditorKeyMaps struct {
2727
Send key.Binding
2828
OpenEditor key.Binding
29-
Blur key.Binding
3029
}
3130

3231
type bluredEditorKeyMaps struct {
@@ -35,30 +34,11 @@ type bluredEditorKeyMaps struct {
3534
OpenEditor key.Binding
3635
}
3736

38-
var focusedKeyMaps = focusedEditorKeyMaps{
37+
var KeyMaps = focusedEditorKeyMaps{
3938
Send: key.NewBinding(
4039
key.WithKeys("ctrl+s"),
4140
key.WithHelp("ctrl+s", "send message"),
4241
),
43-
Blur: key.NewBinding(
44-
key.WithKeys("esc"),
45-
key.WithHelp("esc", "focus messages"),
46-
),
47-
OpenEditor: key.NewBinding(
48-
key.WithKeys("ctrl+e"),
49-
key.WithHelp("ctrl+e", "open editor"),
50-
),
51-
}
52-
53-
var bluredKeyMaps = bluredEditorKeyMaps{
54-
Send: key.NewBinding(
55-
key.WithKeys("ctrl+s", "enter"),
56-
key.WithHelp("ctrl+s/enter", "send message"),
57-
),
58-
Focus: key.NewBinding(
59-
key.WithKeys("i"),
60-
key.WithHelp("i", "focus editor"),
61-
),
6242
OpenEditor: key.NewBinding(
6343
key.WithKeys("ctrl+e"),
6444
key.WithHelp("ctrl+e", "open editor"),
@@ -88,6 +68,9 @@ func openEditor() tea.Cmd {
8868
if err != nil {
8969
return util.ReportError(err)
9070
}
71+
if len(content) == 0 {
72+
return util.ReportWarn("Message is empty")
73+
}
9174
os.Remove(tmpfile.Name())
9275
return SendMsg{
9376
Text: string(content),
@@ -106,7 +89,6 @@ func (m *editorCmp) send() tea.Cmd {
10689

10790
value := m.textarea.Value()
10891
m.textarea.Reset()
109-
m.textarea.Blur()
11092
if value == "" {
11193
return nil
11294
}
@@ -131,26 +113,32 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
131113
return m, tea.Batch(textarea.Blink, util.CmdHandler(EditorFocusMsg(true)))
132114
}
133115
case tea.KeyMsg:
134-
if key.Matches(msg, focusedKeyMaps.OpenEditor) {
116+
if key.Matches(msg, messageKeys.PageUp) || key.Matches(msg, messageKeys.PageDown) ||
117+
key.Matches(msg, messageKeys.HalfPageUp) || key.Matches(msg, messageKeys.HalfPageDown) {
118+
return m, nil
119+
}
120+
if key.Matches(msg, KeyMaps.OpenEditor) {
135121
if m.app.CoderAgent.IsSessionBusy(m.session.ID) {
136122
return m, util.ReportWarn("Agent is working, please wait...")
137123
}
138124
return m, openEditor()
139125
}
140126
// if the key does not match any binding, return
141-
if m.textarea.Focused() && key.Matches(msg, focusedKeyMaps.Send) {
127+
if m.textarea.Focused() && key.Matches(msg, KeyMaps.Send) {
142128
return m, m.send()
143129
}
144-
if !m.textarea.Focused() && key.Matches(msg, bluredKeyMaps.Send) {
145-
return m, m.send()
146-
}
147-
if m.textarea.Focused() && key.Matches(msg, focusedKeyMaps.Blur) {
148-
m.textarea.Blur()
149-
return m, util.CmdHandler(EditorFocusMsg(false))
150-
}
151-
if !m.textarea.Focused() && key.Matches(msg, bluredKeyMaps.Focus) {
152-
m.textarea.Focus()
153-
return m, tea.Batch(textarea.Blink, util.CmdHandler(EditorFocusMsg(true)))
130+
131+
// Handle Enter key
132+
if m.textarea.Focused() && msg.String() == "enter" {
133+
value := m.textarea.Value()
134+
if len(value) > 0 && value[len(value)-1] == '\\' {
135+
// If the last character is a backslash, remove it and add a newline
136+
m.textarea.SetValue(value[:len(value)-1] + "\n")
137+
return m, nil
138+
} else {
139+
// Otherwise, send the message
140+
return m, m.send()
141+
}
154142
}
155143
}
156144
m.textarea, cmd = m.textarea.Update(msg)
@@ -175,13 +163,7 @@ func (m *editorCmp) GetSize() (int, int) {
175163

176164
func (m *editorCmp) BindingKeys() []key.Binding {
177165
bindings := []key.Binding{}
178-
if m.textarea.Focused() {
179-
bindings = append(bindings, layout.KeyMapToSlice(focusedKeyMaps)...)
180-
} else {
181-
bindings = append(bindings, layout.KeyMapToSlice(bluredKeyMaps)...)
182-
}
183-
184-
bindings = append(bindings, layout.KeyMapToSlice(m.textarea.KeyMap)...)
166+
bindings = append(bindings, layout.KeyMapToSlice(KeyMaps)...)
185167
return bindings
186168
}
187169

internal/tui/components/chat/list.go

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/kujtimiihoxha/opencode/internal/message"
1515
"github.com/kujtimiihoxha/opencode/internal/pubsub"
1616
"github.com/kujtimiihoxha/opencode/internal/session"
17-
"github.com/kujtimiihoxha/opencode/internal/tui/layout"
1817
"github.com/kujtimiihoxha/opencode/internal/tui/styles"
1918
"github.com/kujtimiihoxha/opencode/internal/tui/util"
2019
)
@@ -26,7 +25,6 @@ type cacheItem struct {
2625
type messagesCmp struct {
2726
app *app.App
2827
width, height int
29-
writingMode bool
3028
viewport viewport.Model
3129
session session.Session
3230
messages []message.Message
@@ -38,15 +36,40 @@ type messagesCmp struct {
3836
}
3937
type renderFinishedMsg struct{}
4038

39+
type MessageKeys struct {
40+
PageDown key.Binding
41+
PageUp key.Binding
42+
HalfPageUp key.Binding
43+
HalfPageDown key.Binding
44+
}
45+
46+
var messageKeys = MessageKeys{
47+
PageDown: key.NewBinding(
48+
key.WithKeys("pgdown"),
49+
key.WithHelp("f/pgdn", "page down"),
50+
),
51+
PageUp: key.NewBinding(
52+
key.WithKeys("pgup"),
53+
key.WithHelp("b/pgup", "page up"),
54+
),
55+
HalfPageUp: key.NewBinding(
56+
key.WithKeys("ctrl+u"),
57+
key.WithHelp("ctrl+u", "½ page up"),
58+
),
59+
HalfPageDown: key.NewBinding(
60+
key.WithKeys("ctrl+d", "ctrl+d"),
61+
key.WithHelp("ctrl+d", "½ page down"),
62+
),
63+
}
64+
4165
func (m *messagesCmp) Init() tea.Cmd {
4266
return tea.Batch(m.viewport.Init(), m.spinner.Tick)
4367
}
4468

4569
func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
4670
var cmds []tea.Cmd
4771
switch msg := msg.(type) {
48-
case EditorFocusMsg:
49-
m.writingMode = bool(msg)
72+
5073
case SessionSelectedMsg:
5174
if msg.ID != m.session.ID {
5275
cmd := m.SetSession(msg)
@@ -63,10 +86,6 @@ func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
6386
case renderFinishedMsg:
6487
m.rendering = false
6588
m.viewport.GotoBottom()
66-
case tea.KeyMsg:
67-
if m.writingMode {
68-
return m, nil
69-
}
7089
case pubsub.Event[message.Message]:
7190
needsRerender := false
7291
if msg.Type == pubsub.CreatedEvent {
@@ -326,22 +345,14 @@ func (m *messagesCmp) working() string {
326345
func (m *messagesCmp) help() string {
327346
text := ""
328347

329-
if m.writingMode {
348+
if m.app.CoderAgent.IsBusy() {
330349
text += lipgloss.JoinHorizontal(
331350
lipgloss.Left,
332351
styles.BaseStyle.Foreground(styles.ForgroundDim).Bold(true).Render("press "),
333352
styles.BaseStyle.Foreground(styles.Forground).Bold(true).Render("esc"),
334-
styles.BaseStyle.Foreground(styles.ForgroundDim).Bold(true).Render(" to exit writing mode"),
335-
)
336-
} else {
337-
text += lipgloss.JoinHorizontal(
338-
lipgloss.Left,
339-
styles.BaseStyle.Foreground(styles.ForgroundDim).Bold(true).Render("press "),
340-
styles.BaseStyle.Foreground(styles.Forground).Bold(true).Render("i"),
341-
styles.BaseStyle.Foreground(styles.ForgroundDim).Bold(true).Render(" to start writing"),
353+
styles.BaseStyle.Foreground(styles.ForgroundDim).Bold(true).Render(" to exit cancel"),
342354
)
343355
}
344-
345356
return styles.BaseStyle.
346357
Width(m.width).
347358
Render(text)
@@ -398,18 +409,26 @@ func (m *messagesCmp) SetSession(session session.Session) tea.Cmd {
398409
}
399410

400411
func (m *messagesCmp) BindingKeys() []key.Binding {
401-
bindings := layout.KeyMapToSlice(m.viewport.KeyMap)
402-
return bindings
412+
return []key.Binding{
413+
m.viewport.KeyMap.PageDown,
414+
m.viewport.KeyMap.PageUp,
415+
m.viewport.KeyMap.HalfPageUp,
416+
m.viewport.KeyMap.HalfPageDown,
417+
}
403418
}
404419

405420
func NewMessagesCmp(app *app.App) tea.Model {
406421
s := spinner.New()
407422
s.Spinner = spinner.Pulse
423+
vp := viewport.New(0, 0)
424+
vp.KeyMap.PageUp = messageKeys.PageUp
425+
vp.KeyMap.PageDown = messageKeys.PageDown
426+
vp.KeyMap.HalfPageUp = messageKeys.HalfPageUp
427+
vp.KeyMap.HalfPageDown = messageKeys.HalfPageDown
408428
return &messagesCmp{
409429
app: app,
410-
writingMode: true,
411430
cachedContent: make(map[string]cacheItem),
412-
viewport: viewport.New(0, 0),
431+
viewport: vp,
413432
spinner: s,
414433
}
415434
}

internal/tui/components/dialog/commands.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ func (c *commandDialogCmp) View() string {
190190
styles.BaseStyle.Width(maxWidth).Render(""),
191191
styles.BaseStyle.Width(maxWidth).Render(lipgloss.JoinVertical(lipgloss.Left, commandItems...)),
192192
styles.BaseStyle.Width(maxWidth).Render(""),
193-
styles.BaseStyle.Width(maxWidth).Padding(0, 1).Foreground(styles.ForgroundDim).Render("↑/k: up ↓/j: down enter: select esc: cancel"),
194193
)
195194

196195
return styles.BaseStyle.Padding(1, 2).
@@ -244,4 +243,3 @@ func NewCommandDialogCmp() CommandDialog {
244243
selectedCommandID: "",
245244
}
246245
}
247-

internal/tui/components/dialog/help.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (h *helpCmp) render() string {
6262
var (
6363
pairs []string
6464
width int
65-
rows = 14 - 2
65+
rows = 10 - 2
6666
)
6767
for i := 0; i < len(bindings); i += rows {
6868
var (

internal/tui/components/dialog/init.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ func (k initDialogKeyMap) ShortHelp() []key.Binding {
4646
key.WithHelp("enter", "confirm"),
4747
),
4848
key.NewBinding(
49-
key.WithKeys("esc"),
50-
key.WithHelp("esc", "cancel"),
49+
key.WithKeys("esc", "q"),
50+
key.WithHelp("esc/q", "cancel"),
5151
),
5252
key.NewBinding(
5353
key.WithKeys("y", "n"),
@@ -114,6 +114,7 @@ func (m InitDialogCmp) View() string {
114114
Padding(1, 1).
115115
Render("Would you like to initialize this project?")
116116

117+
maxWidth = min(maxWidth, m.width-10)
117118
yesStyle := styles.BaseStyle
118119
noStyle := styles.BaseStyle
119120

@@ -144,12 +145,6 @@ func (m InitDialogCmp) View() string {
144145
Padding(1, 0).
145146
Render(buttons)
146147

147-
help := styles.BaseStyle.
148-
Width(maxWidth).
149-
Padding(0, 1).
150-
Foreground(styles.ForgroundDim).
151-
Render("tab/←/→: toggle y/n: yes/no enter: confirm esc: cancel")
152-
153148
content := lipgloss.JoinVertical(
154149
lipgloss.Left,
155150
title,
@@ -158,7 +153,6 @@ func (m InitDialogCmp) View() string {
158153
question,
159154
buttons,
160155
styles.BaseStyle.Width(maxWidth).Render(""),
161-
help,
162156
)
163157

164158
return styles.BaseStyle.Padding(1, 2).

internal/tui/components/dialog/permission.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ var permissionsKeys = permissionsMapping{
6464
),
6565
Allow: key.NewBinding(
6666
key.WithKeys("a"),
67-
key.WithHelp("a", "allow"),
67+
key.WithHelp("a", "[a]llow"),
6868
),
6969
AllowSession: key.NewBinding(
70-
key.WithKeys("A"),
71-
key.WithHelp("A", "allow for session"),
70+
key.WithKeys("s"),
71+
key.WithHelp("s", "allow for [s]ession"),
7272
),
7373
Deny: key.NewBinding(
7474
key.WithKeys("d"),
75-
key.WithHelp("d", "deny"),
75+
key.WithHelp("d", "[d]eny"),
7676
),
7777
Tab: key.NewBinding(
7878
key.WithKeys("tab"),
@@ -375,18 +375,14 @@ func (p *permissionDialogCmp) render() string {
375375
contentFinal = p.renderDefaultContent()
376376
}
377377

378-
// Add help text
379-
helpText := styles.BaseStyle.Width(p.width - 4).Padding(0, 1).Foreground(styles.ForgroundDim).Render("←/→/tab: switch options a: allow A: allow for session d: deny enter/space: confirm")
380-
381378
content := lipgloss.JoinVertical(
382379
lipgloss.Top,
383380
title,
384381
styles.BaseStyle.Render(strings.Repeat(" ", lipgloss.Width(title))),
385382
headerContent,
386383
contentFinal,
387384
buttons,
388-
styles.BaseStyle.Render(strings.Repeat(" ", p.width - 4)),
389-
helpText,
385+
styles.BaseStyle.Render(strings.Repeat(" ", p.width-4)),
390386
)
391387

392388
return styles.BaseStyle.

internal/tui/components/dialog/session.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ func (s *sessionDialogCmp) View() string {
122122
}
123123
}
124124

125+
maxWidth = max(30, min(maxWidth, s.width-15)) // Limit width to avoid overflow
126+
125127
// Limit height to avoid taking up too much screen space
126128
maxVisibleSessions := min(10, len(s.sessions))
127129

@@ -169,7 +171,6 @@ func (s *sessionDialogCmp) View() string {
169171
styles.BaseStyle.Width(maxWidth).Render(""),
170172
styles.BaseStyle.Width(maxWidth).Render(lipgloss.JoinVertical(lipgloss.Left, sessionItems...)),
171173
styles.BaseStyle.Width(maxWidth).Render(""),
172-
styles.BaseStyle.Width(maxWidth).Padding(0, 1).Foreground(styles.ForgroundDim).Render("↑/k: up ↓/j: down enter: select esc: cancel"),
173174
)
174175

175176
return styles.BaseStyle.Padding(1, 2).
@@ -223,4 +224,3 @@ func NewSessionDialogCmp() SessionDialog {
223224
selectedSessionID: "",
224225
}
225226
}
226-

0 commit comments

Comments
 (0)