171 Commits

Author SHA1 Message Date
Greg Shuflin ce8fd8bd95 more clippy fixes 2026-03-17 04:02:29 -07:00
Greg Shuflin dbd89be1d7 cargo clippy 2026-03-17 03:55:50 -07:00
Greg Shuflin 55a541696d Show filename in status line from buffer's backing_file; update backing_file on save 2026-03-17 03:36:21 -07:00
Greg Shuflin 50f4d42d30 Replace MoveCursor { x, y } with MoveCursor(CursorTarget) to encode cursor semantics in the type system
CursorTarget::OnCharacter clamps to last visible char (Normal mode).
CursorTarget::InsertionPoint allows one past last char (Insert mode).
Centralizes clamping in the handler; simplifies configuration layer.
2026-03-16 17:09:44 -07:00
Greg Shuflin 537cd76ddc Add vim 'a' (append) command; clamp Normal mode cursor to last visible character 2026-03-16 14:45:08 -07:00
Greg Shuflin 66dfef45e1 Use unicode-width 2026-03-13 06:33:26 -07:00
Greg Shuflin 01040686d0 Fix some non-ascii unicode weirdness 2026-03-12 19:01:05 -07:00
Greg Shuflin 6a7ce13761 Add claude setting for rust fmt 2026-03-04 01:50:15 -08:00
Greg Shuflin 55f316f028 Command::NAMES as single source of truth for names/aliases; use in dispatch and completion
- Move Command enum to commands/mod.rs with NAMES, from_name, takes_path_arg
- Replace manual match in CommandAPI::execute with Command::from_name
- Derive canonical names for completion from Command::NAMES (first per variant)
- Simplify complete() to use Command::takes_path_arg instead of complete_path_arg
- Fix bug: 'h' was incorrectly listed as alias for both help and finder
2026-03-03 14:22:10 -08:00
Greg Shuflin 28191314b0 Tab-complete command names (open, quit, write, help, finder, list) 2026-03-03 04:57:59 -08:00
Greg Shuflin 8064b52679 Call completion::complete directly from handle_action; remove Commands::tab 2026-03-03 04:30:17 -08:00
Greg Shuflin 9d937237cf TODO items 2026-03-03 04:30:02 -08:00
Greg Shuflin 11c4d5f08a Remove q keybinding; quit only via :q 2026-03-03 04:14:22 -08:00
Greg Shuflin 3f786d96f4 Refactor completion into its own submodule; add :w path completion 2026-03-03 03:59:09 -08:00
Greg Shuflin 022bd302b0 Rename CommandAction::Tab to CommandAction::Complete 2026-03-03 02:17:35 -08:00
Greg Shuflin 51988bc871 Command mode: tab-complete file paths for :open 2026-03-02 21:54:10 -08:00
Greg Shuflin 65a3b2041a Normal mode: W/B for forward/backward WORD 2026-03-02 21:27:40 -08:00
Greg Shuflin a8d1d03b2d Normal mode: e/E for end of word/WORD 2026-03-02 21:21:08 -08:00
Greg Shuflin b7c17540fc Normal mode: 0/$ for start/end of line 2026-03-02 21:20:35 -08:00
Greg Shuflin f6b7108ff4 Normal mode: w/b word motion, G/gg file navigation
- Add CharClass enum (Word, Whitespace, Other) with char_class() fn
- Add next_pos/prev_pos helpers for line-boundary-aware buffer traversal
- Implement word_forward (w), word_backward (b), move_to_last_line (G)
- Wire gg via pending_operator mechanism (g then g → top of file)
- Also: :help off now uses BufferAction::Hide instead of Close
2026-03-02 14:29:23 -08:00
Greg Shuflin ab1632a13a Restructure EditorAction into a two-level tree
Replace the flat EditorAction enum with nested sub-enums:
- Edit(EditAction)      — text/cursor/mode mutations
- Buffer(BufferAction)  — buffer lifecycle and pane visibility
- Focus(FocusAction)    — focus management
- Command, Quit, Error  — unchanged

Migration:
- InsertText/DeleteChar/DeleteRange/MoveCursor/TransitionToMode → Edit(..)
- LoadBuffer → Buffer(Create{..})
- SaveBuffer → Buffer(Save{..})
- ShowPane   → Buffer(Show { content: Buffer(id), .. })
- Show(ShowTarget::Buffers) → Buffer(Show { content: Dynamic(Buffers), .. })
- HidePane { delete_buffer: false } → Buffer(Hide(id))
- HidePane { delete_buffer: true }  → Buffer(Close(id))
- FocusBuffer/FocusCommandBuffer/FocusPreviousBuffer → Focus(..)

Files changed: actions.rs, core/mod.rs, commands/api.rs, configuration.rs
2026-03-02 13:59:44 -08:00
Greg Shuflin c0221ed789 Run cargo fmt 2026-02-23 23:46:12 -08:00
Greg Shuflin f374e1f4ea Rename internal render helpers: buffer_visible_lines→view_scroll_ranges, single_buffer_lines→view_lines, terminal_buf_height→viewport_height 2026-02-23 13:40:05 -08:00
Greg Shuflin 93028a545d Insert mode: hardware cursor (SteadyBar) via frame.set_cursor_position 2026-02-23 03:45:28 -08:00
Greg Shuflin f549720e8c Insert mode: software beam cursor using '|' at insertion point
Hardware cursor shape (DECSCUSR/SetCursorStyle) proved unreliable
across terminals (e.g. tmux intercepts or ignores the escape).
Switch to a pure software approach: render a '|' span with
cursor_style (REVERSED) at the cursor x position on the cursor
line, the same way the Normal-mode block cursor is rendered.
No terminal feature detection needed.
2026-02-22 13:11:37 -08:00
Greg Shuflin 999f07fe51 Mode-dependent cursor: block in Normal, reversed style; Insert mode hardware cursor position 2026-02-22 12:50:04 -08:00
Greg Shuflin 307bfd5f76 Replace GutterColumn enum with GutterDef trait + DynGutterDef object-safe wrapper
- GutterDef: ergonomic non-object-safe trait with associated Prepared type
- DynGutterDef: object-safe wrapper using Box<dyn Any + Send> (erased-serde pattern)
- Blanket impl<G: GutterDef> DynGutterDef for G with downcast_ref in decorate_any
- LineCtx (Copy): per-line context with line_in_file: Option<usize> for beyond-EOF rows
- LineDecoration { left, right: Option<StyledText> }: side declared per decoration
- Built-in LineNumbers implements GutterDef directly
- BufferSettings: Vec<GutterColumn> -> Vec<Box<dyn DynGutterDef>>
- Renderer: prepare_boxed once per gutter per frame, decorate_any per line
2026-02-22 02:32:25 -08:00
Greg Shuflin 6089a08974 Allow dead code in some places 2026-02-21 14:01:39 -08:00
Greg Shuflin 923caf34c4 Wire up StyleName resolution in terminal renderer; Info style renders as light blue on white 2026-02-17 02:06:45 -08:00
Greg Shuflin 6162a43872 Add style module with StyleName, TextAttrs, and Theme; replace OverlayStyle with StyleName 2026-02-17 01:21:26 -08:00
Greg Shuflin 5fd96f9b91 Add virtual text overlay system for buffer-attached status messages 2026-02-16 23:13:42 -08:00
Greg Shuflin 6a6c935b58 simplification 2026-02-14 00:54:22 -08:00
Greg Shuflin 72020f0b83 Remove active_buffer_properties(), use active_buffer().properties() directly 2026-02-13 14:33:54 -08:00
Greg Shuflin 85baa2dd2d refactor module layout 2026-02-13 14:30:45 -08:00
Greg Shuflin b68bf4696f Remove Buffer enum wrapper, rename TextBuffer to Buffer
The single-variant Buffer::Text(TextBuffer) enum added unnecessary
destructuring at every usage site. Since there's only one buffer type,
flatten it to just Buffer directly.
2026-02-13 14:21:39 -08:00
Greg Shuflin 333fa83ab6 Generalize insert/delete actions: add x and dd support
Replace InsertCharacter(char) with InsertText(String) for chars, newlines, and future paste/macros. Add DeleteRange { from, to } for coordinate-based range deletion. Configuration returns Vec<EditorAction> to enable future compound operations. Add pending_operator state for multi-key dd sequence.
2026-02-12 19:08:54 -08:00
Greg Shuflin 3ca4a3ea7d Turn info pane into a buffer-backed pane 2026-02-12 18:47:41 -08:00
Greg Shuflin c6bef0c8c9 Title behavior change 2026-02-12 17:56:15 -08:00
Greg Shuflin 668967089f Replace COMMAND_BUFFER_ID with composable BufferProperties
- Add BufferProperties struct (listed, ephemeral, read_only, command)
- Add FocusCommandBuffer action so Configuration doesn't need buffer IDs
- Help popup uses info() properties and is dismissible with Escape
2026-02-12 02:06:29 -08:00
Greg Shuflin d404d8ffd9 More buffer design changes 2026-02-12 01:12:05 -08:00
Greg Shuflin 9ff2abceed Buffer design doc 2026-02-12 00:51:59 -08:00
Greg Shuflin ee03479a2f ratatui swap out deprecated method 2026-02-11 14:31:55 -08:00
Greg Shuflin d873935a77 fix some lints 2026-02-11 14:14:42 -08:00
Greg Shuflin 3c070f454a Make modes per-buffer, replace Command mode with command buffer focus 2026-02-11 12:01:24 -08:00
Greg Shuflin 4eb3cd4884 Add TODO.md with EditorAction improvement notes 2026-02-11 02:58:02 -08:00
Greg Shuflin 99e9ee1f35 Some refactoring 2026-02-10 21:44:28 -08:00
Greg Shuflin 0a9f0b89a7 Generalize pane visibility with ShowPane/HidePane actions
Replace PopupHelp and ToggleFinder with a general pane visibility system:
- Add PanePosition enum (Main, Floating, future: Sidebar, Split)
- ShowPane { buffer, position } displays a buffer in specified layout
- HidePane { buffer, delete_buffer } removes from layout, optionally deletes

Commands now compose LoadBuffer + ShowPane for popups. Removed FinderBuffer
and Buffer::Finder variant - all buffers are now TextBuffer.

Also adds jj preference to CLAUDE.md, and does some other refactoring
2026-02-10 17:54:20 -08:00
Greg Shuflin a84e5b9d3d Generalize buffer I/O with BufferSource and BufferDestination
Replace OpenFile/WriteBuffer with a more expressive LoadBuffer/SaveBuffer
that supports multiple content sources and destinations. This enables
scripts to populate buffers from files, literal text, or empty, and save
to explicit paths or backing files.

- Add BufferSource enum (File, Text, Empty)
- Add BufferDestination enum (File, future: Clipboard, etc.)
- LoadBuffer/SaveBuffer can target specific buffers or active buffer
- Add TextBuffer::from_text() constructor

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 13:21:59 -08:00
Greg Shuflin ed6280205e Refactor to minimal EditorAction architecture for scriptability
Move cursor movement logic from EditorCore/Cursor into Configuration layer.
This prepares the codebase for a Turing-complete scripting DSL by keeping
EditorAction minimal (only absolute MoveCursor { x, y }) and having the
scripting layer compute all movement targets via BufferQuery.

- Add BufferQuery trait for read-only buffer access
- Remove CursorMovement enum, replace with MoveCursor { x, y }
- Simplify Cursor to just hold position (remove move_cursor method)
- Configuration now computes movement targets using BufferQuery

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 21:24:26 -08:00
Greg Shuflin f80cc2da0d Refactor event loop from timer-driven to render-after-input
Replace the dual-rate timer rendering architecture with a direct
render-after-input loop. The old design used a background tokio task
(EventHandler) that ran two interval timers — 30 FPS while "active"
and 2 FPS when idle — forwarding events through an mpsc channel. This
introduced up to ~33ms of latency between a keypress and its screen
update, and added unnecessary complexity (background task, channel,
activity threshold heuristic).

The new design uses a single tokio::select! loop with three arms:
  1. Keyboard input: renders immediately after processing, then drains
     any additional buffered input via non-blocking poll before drawing
  2. Async command results: handles actions from the command channel
     (file I/O completion, etc.) and renders
  3. Idle timeout (500ms): renders for background updates like cursor
     blink

Structural changes:
- Remove Event enum, EventHandler struct, and its background task
- TerminalUI now owns crossterm::event::EventStream and the command
  output UnboundedReceiver directly
- EditorCore::new() returns (Self, UnboundedReceiver<EditorAction>)
  instead of storing the receiver internally
- Remove EditorCore::process_commands() — its logic moves into the
  main loop's select arm for command output
- Make EditorCore::handle_action() pub(crate) so the main loop can
  call it directly for command results
- Extract process_key() helper for KeyCode-to-Input mapping
- Add try_poll_crossterm() for non-blocking input draining

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:05:00 -08:00