res-code: fix key forwarding + add MenuBar UI element #17

Open
opened 2026-07-27 22:01:56 +00:00 by agent · 1 comment
Member

res-code: fix key forwarding + add MenuBar UI element

Problem

After the Phase 1 refactoring of core/lib/edit (removing the mode system and key handling), res-code's key forwarding is broken. At extra/internal/code/keys.go:135:

updated, cmd := e.Update(msg)

This forwards key messages to edit.Editor.Update(), which now only handles WindowSizeMsg and MouseMsg. Key messages are silently dropped — res-code cannot type, navigate, or edit text.

Plan

Part 1: Fix res-code key forwarding (CRITICAL)

Replace the e.Update(msg) forwarding in keys.go:129-139 with direct calls to the raw methods on edit.Editor.

Before (broken):

updated, cmd := e.Update(msg)
if ed, ok := updated.(*edit.Editor); ok {
    m.tabs[m.activeTab].editor = ed
}

After (working):

switch msg.Type {
case tea.KeyEnter:
    e.InsertNewline()
case tea.KeyBackspace:
    e.Backspace()
case tea.KeyDelete:
    e.Delete()
case tea.KeyTab:
    e.InsertTab()
case tea.KeyUp:
    e.MoveUp(1)
case tea.KeyDown:
    e.MoveDown(1)
case tea.KeyLeft:
    e.MoveLeft()
case tea.KeyRight:
    e.MoveRight()
case tea.KeyCtrlLeft:
    e.MoveWordLeft()
case tea.KeyCtrlRight:
    e.MoveWordRight()
case tea.KeyHome:
    e.MoveLineStart()
case tea.KeyEnd:
    e.MoveLineEnd()
case tea.KeyCtrlHome:
    e.MoveFileStart()
case tea.KeyCtrlEnd:
    e.MoveFileEnd()
case tea.KeyPgUp:
    e.MoveUp(e.Height() - 1)
case tea.KeyPgDown:
    e.MoveDown(e.Height() - 1)
case tea.KeyCtrlUp:
    e.ScrollUp(1)
case tea.KeyCtrlDown:
    e.ScrollDown(1)
case tea.KeyCtrlZ:
    e.Undo()
case tea.KeyCtrlY:
    e.Redo()
case tea.KeyCtrlU:
    e.DeleteToSOL()
case tea.KeySpace:
    e.InsertRune(' ')
case tea.KeyRunes:
    for _, r := range msg.Runes {
        e.InsertRune(r)
    }
}

Also deduplicate doFind() — replace with e.Find(query) from the library.

Files to change:

  • extra/internal/code/keys.go — replace e.Update(msg) forwarding, replace doFind() with e.Find()

Part 2: Add MenuBar to core/lib/cmd/ui

New VS Code-style menu bar with categorized dropdowns. This is a new UI element in the cmd/ui package.

Design:

┌──────────────────────────────────────────────────┐
│ File  Edit  View  Help                           │  ← menu bar
├──────────────────────────────────────────────────┤
│ File ▾                                          │  ← dropdown
│   New Tab          Ctrl+N                        │
│   Open...          Ctrl+O                        │
│   Save             Ctrl+S          ──────        │
│   Save As...       Ctrl+K S                      │
│   Close Tab        Ctrl+W                        │
│   ──────                                        │
│   Quit             Ctrl+Q                        │
└──────────────────────────────────────────────────┘

API:

type MenuItem struct {
    Label    string
    Shortcut string      // displayed right-aligned (e.g. "Ctrl+S")
    ID       string      // command identifier returned on confirm
    Disabled bool
    Separator bool       // renders as horizontal line
}

type MenuCategory struct {
    Label string
    Items []MenuItem
}

type MenuBar struct {
    categories []MenuCategory
    open       int  // -1 = no dropdown open
    selected   int  // item index within open dropdown
    width      int
    focused    bool
}

func NewMenuBar(categories []MenuCategory) *MenuBar
func (m *MenuBar) SetWidth(w int)
func (m *MenuBar) Open(category int)   // open a specific dropdown
func (m *MenuBar) Close()              // close any open dropdown
func (m *MenuBar) IsOpen() bool        // any dropdown open?
func (m *MenuBar) Update(msg tea.KeyMsg) (MenuBar, tea.Cmd) // returns selected ID on Enter
func (m *MenuBar) View() string        // renders bar + open dropdown

Keyboard navigation:

  • Left/Right — move between categories (when bar is focused)
  • Enter/Down — open dropdown / move down in dropdown
  • Up — move up in dropdown
  • Enter on item — confirm, return item ID
  • Esc — close dropdown
  • Alt+F, Alt+E, etc. — open specific category (optional, for power users)

Files to create:

  • core/lib/cmd/ui/menu.go — MenuBar implementation

Files to update:

  • core/lib/cmd/ui/types.go — update package doc to list MenuBar

Part 3: Wire MenuBar into res-code

Add a menu bar to res-code as an alternative to the current keybind-only interface.

Menu structure for res-code:

File:   New Tab (Ctrl+N), Open (Ctrl+O), Save (Ctrl+S), Save As (Ctrl+K S), Close (Ctrl+W), Quit (Ctrl+Q)
Edit:   Undo (Ctrl+Z), Redo (Ctrl+Y), Delete Line (Ctrl+K K), Find (Ctrl+F), Go to Line (Ctrl+G)
View:   Toggle Sidebar (Ctrl+B), Toggle Terminal (Ctrl+T), Help (Ctrl+H)

Files to change:

  • extra/internal/code/model.go — add MenuBar field, focus zone, mode
  • extra/internal/code/keys.go — handle MenuBar input when focused, dispatch menu commands
  • extra/internal/code/render.go — render menu bar at top of screen

Verification

  1. cd core && go build ./... && go test ./...
  2. cd extra && go build ./...
  3. Launch res-code — type text, navigate with arrows, save with Ctrl+S
  4. Press F2 or : — palette opens, type :w to save
  5. Menu bar visible at top — click or use keyboard to open dropdowns
  6. Menu items trigger correct actions (New Tab, Save, Find, etc.)

Labels

proj-core-lib, proj-extra-code, tier-3-hard

## res-code: fix key forwarding + add MenuBar UI element ### Problem After the Phase 1 refactoring of `core/lib/edit` (removing the mode system and key handling), res-code's key forwarding is broken. At `extra/internal/code/keys.go:135`: ```go updated, cmd := e.Update(msg) ``` This forwards key messages to `edit.Editor.Update()`, which now only handles `WindowSizeMsg` and `MouseMsg`. Key messages are silently dropped — **res-code cannot type, navigate, or edit text**. ### Plan #### Part 1: Fix res-code key forwarding (CRITICAL) Replace the `e.Update(msg)` forwarding in `keys.go:129-139` with direct calls to the raw methods on `edit.Editor`. **Before (broken):** ```go updated, cmd := e.Update(msg) if ed, ok := updated.(*edit.Editor); ok { m.tabs[m.activeTab].editor = ed } ``` **After (working):** ```go switch msg.Type { case tea.KeyEnter: e.InsertNewline() case tea.KeyBackspace: e.Backspace() case tea.KeyDelete: e.Delete() case tea.KeyTab: e.InsertTab() case tea.KeyUp: e.MoveUp(1) case tea.KeyDown: e.MoveDown(1) case tea.KeyLeft: e.MoveLeft() case tea.KeyRight: e.MoveRight() case tea.KeyCtrlLeft: e.MoveWordLeft() case tea.KeyCtrlRight: e.MoveWordRight() case tea.KeyHome: e.MoveLineStart() case tea.KeyEnd: e.MoveLineEnd() case tea.KeyCtrlHome: e.MoveFileStart() case tea.KeyCtrlEnd: e.MoveFileEnd() case tea.KeyPgUp: e.MoveUp(e.Height() - 1) case tea.KeyPgDown: e.MoveDown(e.Height() - 1) case tea.KeyCtrlUp: e.ScrollUp(1) case tea.KeyCtrlDown: e.ScrollDown(1) case tea.KeyCtrlZ: e.Undo() case tea.KeyCtrlY: e.Redo() case tea.KeyCtrlU: e.DeleteToSOL() case tea.KeySpace: e.InsertRune(' ') case tea.KeyRunes: for _, r := range msg.Runes { e.InsertRune(r) } } ``` Also deduplicate `doFind()` — replace with `e.Find(query)` from the library. **Files to change:** - `extra/internal/code/keys.go` — replace `e.Update(msg)` forwarding, replace `doFind()` with `e.Find()` #### Part 2: Add MenuBar to `core/lib/cmd/ui` New VS Code-style menu bar with categorized dropdowns. This is a new UI element in the cmd/ui package. **Design:** ``` ┌──────────────────────────────────────────────────┐ │ File Edit View Help │ ← menu bar ├──────────────────────────────────────────────────┤ │ File ▾ │ ← dropdown │ New Tab Ctrl+N │ │ Open... Ctrl+O │ │ Save Ctrl+S ────── │ │ Save As... Ctrl+K S │ │ Close Tab Ctrl+W │ │ ────── │ │ Quit Ctrl+Q │ └──────────────────────────────────────────────────┘ ``` **API:** ```go type MenuItem struct { Label string Shortcut string // displayed right-aligned (e.g. "Ctrl+S") ID string // command identifier returned on confirm Disabled bool Separator bool // renders as horizontal line } type MenuCategory struct { Label string Items []MenuItem } type MenuBar struct { categories []MenuCategory open int // -1 = no dropdown open selected int // item index within open dropdown width int focused bool } func NewMenuBar(categories []MenuCategory) *MenuBar func (m *MenuBar) SetWidth(w int) func (m *MenuBar) Open(category int) // open a specific dropdown func (m *MenuBar) Close() // close any open dropdown func (m *MenuBar) IsOpen() bool // any dropdown open? func (m *MenuBar) Update(msg tea.KeyMsg) (MenuBar, tea.Cmd) // returns selected ID on Enter func (m *MenuBar) View() string // renders bar + open dropdown ``` **Keyboard navigation:** - `Left`/`Right` — move between categories (when bar is focused) - `Enter`/`Down` — open dropdown / move down in dropdown - `Up` — move up in dropdown - `Enter` on item — confirm, return item ID - `Esc` — close dropdown - `Alt+F`, `Alt+E`, etc. — open specific category (optional, for power users) **Files to create:** - `core/lib/cmd/ui/menu.go` — MenuBar implementation **Files to update:** - `core/lib/cmd/ui/types.go` — update package doc to list MenuBar #### Part 3: Wire MenuBar into res-code Add a menu bar to res-code as an alternative to the current keybind-only interface. **Menu structure for res-code:** ``` File: New Tab (Ctrl+N), Open (Ctrl+O), Save (Ctrl+S), Save As (Ctrl+K S), Close (Ctrl+W), Quit (Ctrl+Q) Edit: Undo (Ctrl+Z), Redo (Ctrl+Y), Delete Line (Ctrl+K K), Find (Ctrl+F), Go to Line (Ctrl+G) View: Toggle Sidebar (Ctrl+B), Toggle Terminal (Ctrl+T), Help (Ctrl+H) ``` **Files to change:** - `extra/internal/code/model.go` — add MenuBar field, focus zone, mode - `extra/internal/code/keys.go` — handle MenuBar input when focused, dispatch menu commands - `extra/internal/code/render.go` — render menu bar at top of screen ### Verification 1. `cd core && go build ./... && go test ./...` 2. `cd extra && go build ./...` 3. Launch res-code — type text, navigate with arrows, save with Ctrl+S 4. Press F2 or `:` — palette opens, type `:w` to save 5. Menu bar visible at top — click or use keyboard to open dropdowns 6. Menu items trigger correct actions (New Tab, Save, Find, etc.) ### Labels `proj-core-lib`, `proj-extra-code`, `tier-3-hard`
Author
Member

Complete

Part 1: Fix res-code key forwarding

  • Replaced e.Update(msg) (which silently dropped key messages) with direct calls to InsertRune, MoveUp, Backspace, etc.
  • Deduplicated doFind() — now calls e.Find() from the library
  • Removed unused imports (edit, buffer, fmt)
  • Commit: eaad4ab

Part 2: Add MenuBar to core/lib/cmd/ui

  • New MenuBar widget with MenuCategoryMenuItem (label, shortcut, ID, separator, disabled)
  • Keyboard nav: Left/Right between categories, Up/Down in dropdown, Enter to confirm, Esc to close
  • Returns item ID string on confirmation
  • Commit: b241434

Part 3: Wire MenuBar into res-code

  • Menu structure: File (New/Open/Save/SaveAs/Close/Quit), Edit (Undo/Redo/DeleteLine/Find/Goto), View (Sidebar/Terminal/Help)
  • F10 toggles menu bar focus
  • dispatchMenuCommand() routes menu IDs to existing IDE functions
  • Menu bar renders at top of screen, editor height adjusted for extra row
  • Commit: 4dd1b71

Build verification

  • core/go build, go test, go vet all clean
  • extra/go build clean
## Complete ✅ ### Part 1: Fix res-code key forwarding - Replaced `e.Update(msg)` (which silently dropped key messages) with direct calls to `InsertRune`, `MoveUp`, `Backspace`, etc. - Deduplicated `doFind()` — now calls `e.Find()` from the library - Removed unused imports (`edit`, `buffer`, `fmt`) - Commit: `eaad4ab` ### Part 2: Add MenuBar to core/lib/cmd/ui - New `MenuBar` widget with `MenuCategory` → `MenuItem` (label, shortcut, ID, separator, disabled) - Keyboard nav: Left/Right between categories, Up/Down in dropdown, Enter to confirm, Esc to close - Returns item ID string on confirmation - Commit: `b241434` ### Part 3: Wire MenuBar into res-code - Menu structure: File (New/Open/Save/SaveAs/Close/Quit), Edit (Undo/Redo/DeleteLine/Find/Goto), View (Sidebar/Terminal/Help) - F10 toggles menu bar focus - `dispatchMenuCommand()` routes menu IDs to existing IDE functions - Menu bar renders at top of screen, editor height adjusted for extra row - Commit: `4dd1b71` ### Build verification - `core/` — `go build`, `go test`, `go vet` all clean - `extra/` — `go build` clean
agent reopened this issue 2026-08-03 23:39:13 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
residual/.agent#17
No description provided.