Skip to content

TUI rewrite: Remove Ragel token system, add TuiInput#13

Merged
tobi merged 17 commits intomasterfrom
2025-12-04-remove-token-system
Dec 4, 2025
Merged

TUI rewrite: Remove Ragel token system, add TuiInput#13
tobi merged 17 commits intomasterfrom
2025-12-04-remove-token-system

Conversation

@tobi
Copy link
Copy Markdown
Owner

@tobi tobi commented Dec 4, 2025

Summary

  • Replace Ragel-based token system with simpler stack-based ANSI styling
  • Add TuiInput system for text input fields with readline keybindings
  • Simplify command architecture - commands return scripts, main.c decides execution
  • Fix mouse wheel escape sequence handling
  • Memoize terminal size queries

Changes

TUI Styling:

  • Remove Ragel state machine (tokens.rl, tokens.c)
  • Add tui_style.c/h with stack-based style management
  • tui_push()/tui_pop() for nested styles with proper resets

TuiInput System:

  • Reusable text input with cursor management
  • Smart placeholder (dims untyped suffix while prefix matches)
  • Full readline keybindings: Ctrl+A/E/B/F/K/U/W, arrows, backspace, delete
  • Used by both search bar and delete confirmation dialog

Command Architecture:

  • Commands return zstr scripts instead of executing internally
  • run_script(script, exec_mode) - prints or executes based on bool
  • Simpler TestParams struct replaces Mode

Terminal Fixes:

  • Memoize get_window_size() with SIGWINCH invalidation
  • Properly consume mouse escape sequences (SGR, X10, urxvt)

Test plan

  • All 105 tests pass
  • Manual testing of search, navigation, delete confirmation
  • Mouse wheel no longer pollutes input buffer

🤖 Generated with Claude Code

tobi and others added 17 commits December 4, 2025 10:48
- Remove tokens.rl, tokens.c, tokens.h, and tokens_test.c (5,581 lines deleted)
- Add tui_style.h: ANSI escape codes, style types (TuiStyleString, Tui)
- Add tui_style.c: style stack implementation with targeted resets
- Update tui.h: selector types only (TryEntry, Mode, SelectionResult)
- Implement targeted style resets instead of full ANSI reset
  - Parse styles to determine what they change (fg, bg, bold, dim)
  - Only reset affected categories, preserving stacked backgrounds
- TuiStyleString API with tui_push/tui_pop/tui_print/tui_printf
- Rename tui_styled to tui_zstr_printf for consistency
- TUI_* style defines replace old token strings
- DANGER background now extends to end of line including metadata
Command Architecture:
- Remove Mode system - commands now return shell scripts as zstr
- run_script() takes bool exec_mode instead of Mode*
- Replace Mode struct with simpler TestParams (render_once, inject_keys)
- Commands no longer need to know about execution mode

TuiInput System:
- Add TuiInput struct with text, cursor, and placeholder fields
- Smart placeholder: shows dimmed suffix while input matches prefix
- Full readline keybindings: Ctrl+A/E/B/F/K/U/W, arrows, backspace, delete
- Refactor delete confirmation dialog to use tui_begin_screen API
- Main search input now uses shared TuiInput/tui_input_handle_key
- Remove duplicate handle_readline_keybinding function

Terminal Improvements:
- Memoize get_window_size() - only query after SIGWINCH
- Fix mouse wheel escape sequences (SGR, X10, urxvt protocols)
- Consume unrecognized CSI sequences to prevent buffer pollution
- tui_end_screen() now auto-clears to end of screen

Cleanup:
- Delete spec/token_system.md (obsolete)
- Remove ragel from flake.nix dependencies
- Update CLAUDE.md to remove token system documentation
- Remove stale token-related comments

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Use tui_begin_screen/tui_end_screen for all rendering
- Add memoized get_separator_line() helper
- Use tui_screen_line/tui_screen_line_selected for each row
- Use tui_screen_input() for search bar (auto cursor positioning)
- Remove manual cursor tracking and direct stdio writes
- Reduces render() from ~340 to ~180 lines (-145 lines net)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add static tui_style(zstr*, const char*) that writes style only when tui_no_colors is false
- Use in tui_push() instead of manual check
- Simplify tui_print/tui_printf: flags is 0 when colors disabled, so second check redundant
- Simplify tui_zstr_printf() using tui_style()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Rename tui_end_screen() to tui_free() for use with Z_CLEANUP attribute
- Add tui_drain_input() to consume remaining stdin after TUI exit
  (prevents leftover escape sequences from affecting shell)
- Use Z_CLEANUP(tui_free) in render() for automatic cleanup
- Call tui_drain_input() after disable_alternate_screen()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add cols field to Tui struct to track terminal width
- Add visible_width() helper to calculate width excluding ANSI codes
- Add truncate_at_width() to find byte offset for truncation
- Add tui_screen_write_truncated() with optional overflow indicator
  (e.g., "..." or "… ")

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Use tui_screen_write_truncated() for all lines (header, footer, content)
- Remove complex manual truncation/metadata logic from render()
- Fix visible_width() to handle UTF-8: skip continuation bytes,
  assume width 2 for non-ASCII (emojis etc)
- Fix truncate_at_width() similarly for consistent behavior
- Update prefix_len to 6 to match UTF-8 width calculation
- Metadata is right-aligned when space allows, hidden when truncated

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add decode_utf8() to properly decode UTF-8 codepoints
- Add codepoint_width() to distinguish emoji (width 2) from other
  non-ASCII chars like arrows and box drawing (width 1)
- Fix visible_width() and truncate_at_width() to use correct widths
- Fixes separator lines not filling terminal width

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Move tui_drain_input() after disable_raw_mode() for better timing
- Improve tui_drain_input() to disable ICANON and use 0.1s timeout
  to catch late-arriving bytes
- Fix metadata display: only show when line won't be truncated
  (spec: hide metadata if path is truncated)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Use visible_width() instead of strlen() for overflow indicator length,
so "… " counts as 2 chars (not 4 bytes), preventing early truncation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Metadata positioning now follows the spec exactly:
- available > 2: full metadata with padding
- available >= -meta_len+3: partial metadata (truncate from left)
- available < -meta_len+3: hide metadata, truncate name

This allows directory names to "overlay" metadata like a higher layer,
showing partial metadata when names are long but not extremely long.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Calculate correct padding for partial metadata to keep it
right-aligned at the terminal edge, not floating in the middle.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Footer help text truncates without ellipsis (NULL overflow)
- Partial metadata uses cols-1 to match full metadata alignment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Use cols (not cols-1) for partial metadata padding so it
reaches the right edge without being cut short by 1 char.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Partial metadata now uses exactly 1 space after the name,
showing as much metadata as fits in remaining space.
Simpler logic: space_for_meta = cols - path_end - 1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replaced complex available_space calculations with simple space_left:
- space_left = cols - path_end
- Full metadata: space_left > meta_len + 2
- Partial metadata: space_left > 3
- No metadata: truncation handles it

Removes conflicting conditions that caused inconsistent behavior
during window resize.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add new tui_screen_rwrite() function that writes content right-aligned,
  clears line with optional background color, then returns to column 1
- Add line_has_rwrite flag to Tui struct to prevent EOL clear from erasing
  right-aligned content on subsequent write
- Refactor list item rendering to use rwrite for metadata (time, score),
  eliminating manual padding/partial metadata calculation logic
- Fix list height calculation (rows - 7 instead of rows - 8)
- Fix truncation to strip trailing spaces before overflow indicator

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@tobi tobi merged commit c942a7a into master Dec 4, 2025
0 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant