- Replace gtx.Event(nil) with key.Filter{Focus: focusedID} and
key.FocusFilter{Target: focusedID} so Gio correctly routes key
and edit events to the focused editor text field.
- Convert EditorState.CursorPosition (byte offset) to line/column
coordinates for accurate cursor rendering.
- Add debug logging in HandleKeyDown and HandleCursorMove.
4.1 KiB
4.1 KiB
Editor Implementation Plan
1. Design Principles
- Single-Owner Pattern: The logic goroutine is the exclusive authority for modifying the editor buffer, cursor, and selection state.
- Asynchronous I/O: File saving and loading operations are delegated to the worker pool. The UI never blocks on disk operations.
- Buffer-Based Editing: For performance, the editor will eventually utilize a gap buffer or rope data structure. For MVP, string manipulation is acceptable if performance targets are met.
- Event-Driven: Keyboard input, mouse interactions, and menu actions are passed through the existing
inputChanto the logic goroutine.
2. Core State Structure
The State struct in internal/editor/state.go will be extended to track active editing session data:
type EditorState struct {
Buffer string // Document content (or gap buffer)
CursorPosition int // Byte offset
SelectionStart int // -1 if no selection
SelectionEnd int // -1 if no selection
UndoStack []EditCommand // For undo/redo
Dirty bool // Needs save
}
3. Implementation Phases
Phase 1: Basic Buffer Management & Cursor
- Define
EditorState(Cursor, Selection, Dirty flag). - Implement cursor navigation (Arrow keys: Left, Right, Up, Down).
- Implement basic buffer updates (Insert character, Delete/Backspace).
- Implement cursor display and blink animation.
- Update
EditorLayoutto display cursor and selection highlight.
Phase 2: File IO Integration
- Implement
SaveFilehandler: DispatchWriteFileTaskto worker pool. - Implement
LoadFilehandler: DispatchReadFileTaskto worker pool (existing inlogic.go). - Status bar integration: Show "Saving..." indicator, "Modified" status.
Phase 3: Text Editing Operations
- Implement Cut/Copy/Paste interactions.
- Implement multi-line text navigation (Home/End, PageUp/PageDown).
- Implement text selection display and mouse interaction.
- Implement soft-wrap toggle (already exists, need to verify logic).
Phase 4: Polish & Advanced Features
- Undo/Redo stack implementation.
- Performance testing with large files (>1MB).
4. Interaction Flow (Example: Keyboard/Mouse Input)
- User performs an action (types a character, taps an icon).
- UI (Renderer) registers the element's interaction (
event.Opfor keys,gesture.Addfor mouse) within its clip context. - Main Loop captures the event (using
key.Filterfor keys,gesture.Updatefor mouse). - Main Loop generates an
InputEventand sends it toinputChan. - Logic Goroutine receives the event, triggers the corresponding
HandlerinTheState. - Logic Goroutine modifies state, and sends updated elements back through
frameChan. - Renderer paints the new frame.
5. Performance Targets
| Operation | Target | Mechanism |
|---|---|---|
| Typing latency | < 16ms | Single-owner logic update, immediate frame redraw |
| File Load (1MB) | < 100ms | Async worker pool read, background loading |
| File Save | < 100ms | Async worker pool write |
| Undo/Redo | < 10ms | O(1) or O(N) memory-based buffer update |
7. Input Handling Mechanism
7.1 Mouse/Touch Input
- Uses
gesture.Clickandgesture.Scroll. - Registered via
event.Opand gestureAdd()within the clip context of the element. - Processed by
Renderer.CheckGesturesand dispatched viaInputEventto the logic goroutine.
7.2 Keyboard Input
- Registration: Elements register as input handlers using
event.Op(gtx.Ops, elementID). This tags the current clip context for input routing. - Focus: Focus is managed by the logic goroutine. When an element is focused,
key.FocusCmd{Tag: elementID}is submitted to the operation stack. - Filtering: Keyboard events are processed in the main loop using
key.Filter{Focus: focusedElementID}to ensure events are only routed to the active element. - Routing:
key.Event(for key presses) andkey.EditEvent(for text input) are converted intoInputEventstructs and sent to the logic goroutine viainputChanfor state updates.