Commit Graph

122 Commits

Author SHA1 Message Date
93a5f879f5 feat: implement atomic writes for filesystem backend
- Add WriteFile method to mock filesystem (non-atomic path, creates files)
- Implement WriteFileAtomic in mock with temp file + rename pattern
  using .tmp/ directory, matching real filesystem semantics
- Update WriteFileTask.Execute() to use WriteFileAtomic
- Update FlushAll() to use WriteFileAtomic
- Fix mock to create files on write (matching os.WriteFile behavior)
- Update tests to match new semantics (create-if-not-exists)
2026-06-04 18:01:51 -04:00
d73cb0be2c Integrate real filesystem with interface abstraction
- Define pool.FileSystem interface in internal/io/pool/filesystem.go
- Move DirEntry interface to internal/io/pool/types/types.go to break
  the pool <-> mock import cycle
- Implement real.FileSystem with atomic writes (temp file + os.Rename)
- Update mock.FileSystem to satisfy pool.FileSystem interface
- Update worker pool tasks to accept pool.FileSystem interface
- Update main.go to use RealFileSystem by default, with -root flag
- Update all browser/editor/test references to types.DirEntry
2026-06-04 16:19:38 -04:00
672dcbe6b3 Fix cursor movement bug in scrolled editor and add regression test 2026-06-04 13:53:42 -04:00
ca828569f7 Fix deadlock when opening files and update E2E tests 2026-06-04 13:06:30 -04:00
d06f8af0f7 Documentation updates. 2026-06-04 08:38:11 -04:00
bef3929f40 fix: update tests and fix SetCursorFromPoint panic
- Rewrite cursor_test.go to use the current GlyphLayout-based API
  instead of the deleted byteOffsetToLineCol function
- Add guard for empty/missing layout slices in SetCursorFromPoint
  to prevent index-out-of-range panic on empty documents
- Add missing Advance field to e2e test GlyphLayout initialization
- Add cmd/pad/pad binary to .gitignore
2026-06-04 07:24:44 -04:00
dbe822d3f6 Doc updates. 2026-06-03 22:51:22 -04:00
979656c2d0 Fix cursor Y positioning logic in editor 2026-06-03 22:47:06 -04:00
6939550527 Fix cursor positioning and add utf8 import 2026-06-03 22:37:38 -04:00
0b727ff3b2 Fix cursor positioning for end-of-line clicks 2026-06-03 22:35:24 -04:00
d090447f2d Show soft keyboard on editor focus 2026-06-03 22:31:49 -04:00
b37e6bfecf Update to gioui v0.10.0. 2026-06-03 22:17:52 -04:00
bab239a38a Implement click-to-move cursor in the editor 2026-06-03 22:04:16 -04:00
62d1f827e0 Fix cursor rendering lag and implement Enter key newline insertion 2026-06-03 20:19:35 -04:00
3f53836ade Implement vertical cursor movement and reset cursor on file open 2026-06-03 19:49:27 -04:00
d33e68ab2c fix(editor): fix cursor positioning, scrolling, and clipping
- Fix cursor vertical alignment and ensure it respects ScrollOffset.
- Fix scrolling in editor page by correctly registering scroll interactions in the renderer.
- Ensure cursor is clipped to the editor text area to prevent drawing over status bars.
2026-06-03 19:19:14 -04:00
a5d1c4bee6 Compute glyphLayout after text rendering. Implement correct cursor
movement.
2026-06-03 19:01:05 -04:00
ccd258306e browser: fix search when SortIndex is unavailable
recomputeSearchResults now falls back to searching loaded Pages
directly when SortIndex is not available, instead of returning nil
results. This fixes all search tests and handles the brief window
between app launch and index completion.
2026-06-03 14:22:06 -04:00
f515c4ec3b Documentation updates. 2026-06-03 12:01:25 -04:00
1609731ca1 doc(editor): add GlyphLayout architecture for cursor placement tracking
- Add Section 8 describing GlyphLayout data structure and feedback path
- Renderer captures byte offsets, X/Y positions, and advance widths during shaping
- Layout flows via layoutChan to logic goroutine, replacing lastLineYChan
- Editor uses layout for accurate cursor rendering and navigation
- Handles word wrap, screen resize, editing, scroll, and non-fixed-width fonts
2026-06-03 11:07:12 -04:00
bb55b4ab81 Bug fixes. 2026-06-03 10:38:29 -04:00
0dac354f2a fix(editor): wire key events to cursor movement
- 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.
2026-06-03 07:41:18 -04:00
a17c3760f2 Fix browser search scrolling and remove list item selection highlight 2026-06-02 13:51:48 -04:00
57a185fa36 Fix bugs in e2e tests and remove list item selection highlight 2026-06-02 13:30:09 -04:00
367e6e9052 Deadlock fix: no channel sends during frame rendering while mutex is locked. 2026-06-02 11:32:57 -04:00
b838b4c75f fix: resolve navigation and file content loading issues 2026-06-02 10:23:43 -04:00
ec87e95b35 fix: integrate browser-to-editor file loading and remove sample text 2026-06-02 09:33:12 -04:00
2c3702f421 fix(browser): fix directory navigation and entry tapping 2026-06-02 08:14:59 -04:00
99b733cb7d fix(browser): fix search scrolling, clamping and zero-result search behavior 2026-06-01 21:22:11 -04:00
94db42d2ad feat(browser): Implement lazy loading and E2E tests for browser 2026-06-01 20:37:59 -04:00
3a2e21e4b3 Start frameReceiver first before logic.Run(). 2026-06-01 12:03:47 -04:00
dc80c8a8e8 Remove scroll debug statements. Add one extra element to browser listview
so that we have a partial item displayed at the bottom and not a blank space.
2026-06-01 11:58:57 -04:00
6709f52e0f Fix browser page scrolling by initializing EntryHeight and correcting scroll handler type assertion 2026-06-01 10:57:34 -04:00
281298ac1f Add spec.md documentation 2026-05-31 23:21:52 +00:00
ce8dd82bb0 Remove duplicate browser state and fix sort mode toggle
- Remove currentBrowserState global and SetBrowserState from browser package
- Browser now receives sortHandler as a parameter instead of using global state
- Fix sort mode toggle: reload pages after clearing cache (was showing 'Loading...')
- Add String() methods to all UI element types for debugging
- Add e2e tests for sort mode functionality (5 tests)

The editor now owns all state; the browser is a pure function receiving
state and handlers through parameters.
2026-05-31 23:20:21 +00:00
86328bab5b doc: normalize SPEC.md to spec.md (case rename)
Content preserved in doc/spec.md. Lowercase naming is more
portable across case-insensitive filesystems.
2026-05-31 19:21:28 +00:00
3f1c881a06 browser: document lazy loading implementation plan
- Add detailed §15 lazy loading plan with 7 implementation steps
- Update Phase 2 checklist with specific tasks
- Add E2E test harness for browser files
- Refactor browser layout and handler structure
- Add .gitignore for common patterns

WIP: Actual lazy loading not yet implemented.
2026-05-31 18:43:46 +00:00
6a43e3c0db Add e2e test harness for testing editor logic without Gio display
- internal/test/e2e/: FrameCapture, Harness, ElementAssertions, helpers
- internal/editor/logic.go: Add done channel and Done() method for graceful shutdown
- internal/editor/mock_setup.go: Mock filesystem for tests
- internal/browser/: Browser layout and search logic
- internal/io/: Worker pool for async tasks
- Update architecture docs and spec
2026-05-31 08:56:30 -04:00
a1ef84609f Fix search update bug. 2026-05-28 20:46:54 -04:00
831f0dac81 Implement four-way sort cycling for browser listview
- Added four sort modes: Date ↓, Date ↑, Name ↑, Name ↓
- Sorting happens only when sort mode changes, not every frame
- Sorted entries are cached in SortedEntries field
- Search query changes trigger re-filtering and re-sorting
- Scroll offset resets on sort change
2026-05-28 16:42:12 -04:00
8f185341b3 Implement per-pixel smooth scrolling for ListView
- Changed BrowserScrollOffset and ListView.ScrollOffset from int (row index)
  to ui.Dp (pixel offset) for smooth per-pixel scrolling
- Updated HandleBrowserScroll to use raw Dp delta instead of row-based
  scrolling with minimum ±1 row jumps
- Fixed search not triggering new frames by detecting query changes in
  main.go FrameEvent handler
- Fixed click misalignment by indexing RowFilenames with local index i
  instead of rowGlobalIndex
- Fixed bottom clamping using actual BrowserListHeight and corrected
  formula: maxScroll = totalRows * rowHeight - BrowserListHeight
2026-05-28 16:14:11 -04:00
23fdeabad4 Fix scroll clipping: ListView now clips scroll gestures to its region
- Add clippableElement interface for elements that need their own clip region
- ListView implements NeedsClip() so drawElement pushes a clip before Draw
- RegisterScroll no longer has its own clip; relies on element clip context
- Aligns with Gio's clip-based gesture registration model
- Fix scroll events firing outside the visible list area on browser page

Also:
- Update touch.md documentation to reflect clip-based interaction model
- Remove debug logging from ListView.Draw
- Remove TODO-click-fixes.md (all items resolved)
2026-05-28 14:56:12 -04:00
ad3049dd22 Browser page: scroll + click coexist via register order fix
- Added Page state (BrowserPage/EditorPage) and SortMode
- BrowserLayout with 30 static entries, sort toggle, search placeholder
- ListView rows clickable via per-row RegisterClick
- Scroll gesture registered at START of ListView.Draw (before clicks)
  so click gestures registered later are checked first during hit test
- Unique IDs for interactive elements: editor_text, browser_list, search_bar
- ListView.Interactions() filters out Scroll (registered in Draw, not registerInteraction)
- RegisterScroll added to Renderer, called from element Draw methods
- lastLineYChan frame loop fixed: only re-layout if value changed
- Back icon added, editor status bar shows active filename
2026-05-27 12:14:25 -04:00
0246316d8f Add word-wrapped text display with two-finger scroll
- Renderer computes word wrap via single LayoutString pass with
  WrapHeuristically policy; glyphs drawn inline at FlagLineBreak
- Fixed line height (fontSize * 1.2), independent of glyph metrics
- Two-finger trackpad scroll via gesture.Scroll with vertical axis
- Display line feedback: renderer reports last glyph Y after each
  Draw; logic uses it to clamp scroll offset so last line stops
  at bottom of viewport with lineHeight/2 padding
- ScrollRange fix: {Min: -(1<<30), Max: 1<<30} ensures scroll
  delta is consumed (empty range consumes nothing via clampSplit)
- Line counting fix: only FlagLineBreak increments count; buffer
  flushes (32-glyph cap) draw but don't count
2026-05-26 20:26:20 -04:00
ae04aabb70 Documentation update. 2026-05-26 10:00:14 -04:00
1596dab72d Initial InputEvent handling. Clickable "Wrap" text label. 2026-05-26 09:46:35 -04:00
50e9ca5b34 Updates to rendering pipeline and documentation. 2026-05-25 17:40:35 -04:00
22c1d5bed1 fix: correct text layout and rendering pipeline
- Fix render.go: replace broken material.Label with shaper-based text
  rendering (LayoutString + Shape + glyph iteration) per Gio's paintGlyph
- Fix render.go: only apply clip rects at container boundaries; leaf
  elements have zero-size regions that were clipping all text out
- Fix render.go: call r.drawElement recursively for container children
  so nested containers work and clips are applied correctly
- Fix render.go: add drawLineText/drawLine helpers matching Gio's
  paintGlyph offset calculation (x + first.X, y + first.Y)
- Fix element.go: Button.Draw now uses r.drawText instead of duplicate
  broken material.Label code; Label defaults to black when color is unset
- Fix state.go: container children use relative coordinates instead of
  mixed screen-space/container-relative positions
- Fix main.go: ConfigEvent carries raw pixel dimensions only; ScaleEvent
  carries scale only; layout is computed once per frame using both,
  eliminating the infinite Invalidate() loop
2026-05-18 21:03:22 -04:00
8739bae517 refactor: unified Element interface with Draw method and Container type
- Add Draw(gtx, r *Renderer) to Element interface
- Add Container type that implements Element and holds []Element children
- Leaf types (Label, Icon, Button) implement Draw themselves
- Single recursive drawElement function in Renderer — no switch/case
- Remove StatusBar/BottomBar — replaced by Container
- Remove shaper.go — no longer needed with Gio material labels
- Simplify main.go — scale via ScaleProvider interface
- 5 files changed, shaper.go deleted
2026-05-18 11:25:43 -04:00
93a7a0a0b2 fix: remove duplicate scale storage, read from State via ScaleProvider interface
- Remove Renderer.scale field and SetScale method
- Add ScaleProvider interface to avoid editor/ui import cycle
- Add Scale() method to State, rename Scale field to scale
- Renderer reads scale through r.scale.Scale()
- Fix icons.go blank import preventing embed.FS usage
- Update main.go to pass State as ScaleProvider to Renderer
2026-05-17 10:59:29 -04:00