|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +tmux-easymotion is a tmux plugin that provides vim-easymotion-like functionality for quickly jumping to visible text positions across tmux panes. The key feature that distinguishes this plugin is its ability to jump between split panes within a tmux window. |
| 8 | + |
| 9 | +## Architecture |
| 10 | + |
| 11 | +The plugin consists of three main components: |
| 12 | + |
| 13 | +1. **easymotion.tmux** (bash): TPM plugin entry point that reads tmux options and sets up key bindings. It spawns a background tmux window that runs the Python script with environment variables for configuration. |
| 14 | + |
| 15 | +2. **easymotion.py** (Python): Core implementation that: |
| 16 | + - Uses either curses or ANSI escape sequences for rendering (configurable) |
| 17 | + - Captures all visible pane contents via `tmux capture-pane` |
| 18 | + - Implements hint generation and assignment based on distance from cursor |
| 19 | + - Handles wide (CJK) characters with proper width calculations |
| 20 | + - Supports both normal mode and copy mode cursor positioning |
| 21 | + |
| 22 | +3. **Rendering Strategy**: The plugin uses an abstract `Screen` class with two implementations: |
| 23 | + - `Curses`: Standard curses-based rendering (opt-in via `@easymotion-use-curses`) |
| 24 | + - `AnsiSequence`: ANSI escape sequence rendering (default, more portable) |
| 25 | + |
| 26 | +## Key Technical Details |
| 27 | + |
| 28 | +### Wide Character Handling |
| 29 | +The codebase has special handling for double-width characters (CJK characters). Functions like `get_char_width()`, `get_string_width()`, and `get_true_position()` convert between visual columns and string indices. When modifying character position logic, always use `get_true_position()` to convert visual columns to true string positions. |
| 30 | + |
| 31 | +### Hint Generation Algorithm |
| 32 | +The `generate_hints()` function dynamically balances single-character and double-character hints to minimize keystrokes. It ensures double-character hints never start with characters used as single-character hints. The `assign_hints_by_distance()` function sorts matches by Euclidean distance from the cursor. |
| 33 | + |
| 34 | +### Pane Information Gathering |
| 35 | +`get_initial_tmux_info()` makes a single tmux call to batch-fetch all pane information (positions, dimensions, cursor state, scroll position) for performance. It handles zoomed windows by filtering out non-active panes. |
| 36 | + |
| 37 | +### Input Flow |
| 38 | +User input flows through a temporary file (created by `mktemp`) to handle the initial search character, then switches to direct stdin reading via `getch()` for hint selection. This avoids conflicts with tmux's command-prompt. |
| 39 | + |
| 40 | +## Development Commands |
| 41 | + |
| 42 | +### Running Tests |
| 43 | +```bash |
| 44 | +pytest test_easymotion.py -v --cache-clear |
| 45 | +``` |
| 46 | + |
| 47 | +### Testing in tmux |
| 48 | +After making changes, reload the plugin in tmux: |
| 49 | +```bash |
| 50 | +# In tmux, press prefix + I to reload TPM plugins |
| 51 | +# Or source the config manually: |
| 52 | +tmux source-file ~/.tmux.conf |
| 53 | +``` |
| 54 | + |
| 55 | +### Debugging |
| 56 | +Enable debug logging by setting in ~/.tmux.conf: |
| 57 | +```bash |
| 58 | +set -g @easymotion-debug 'true' |
| 59 | +``` |
| 60 | +Logs are written to ~/easymotion.log |
| 61 | + |
| 62 | +Enable performance logging: |
| 63 | +```bash |
| 64 | +set -g @easymotion-perf 'true' |
| 65 | +``` |
| 66 | + |
| 67 | +## Configuration Options (tmux.conf) |
| 68 | + |
| 69 | +All options are read from tmux options in easymotion.tmux and passed as environment variables to the Python script: |
| 70 | + |
| 71 | +- `@easymotion-key`: Trigger key binding (default: 's') |
| 72 | +- `@easymotion-hints`: Characters used for hints (default: 'asdghklqwertyuiopzxcvbnmfj;') |
| 73 | +- `@easymotion-vertical-border`: Character for vertical borders (default: '│') |
| 74 | +- `@easymotion-horizontal-border`: Character for horizontal borders (default: '─') |
| 75 | +- `@easymotion-use-curses`: Use curses instead of ANSI sequences (default: 'false') |
| 76 | +- `@easymotion-case-sensitive`: Case-sensitive search (default: 'false') |
| 77 | +- `@easymotion-smartsign`: Enable smartsign feature to match shifted symbols (default: 'false') |
| 78 | + |
| 79 | +## Important Implementation Notes |
| 80 | + |
| 81 | +- The Python script runs in a detached tmux window (`neww -d`) to avoid interfering with the user's session |
| 82 | +- Cursor position differs between normal mode and copy mode - check `pane.copy_mode` flag |
| 83 | +- The `__slots__` optimization on `PaneInfo` reduces memory overhead |
| 84 | +- Functions decorated with `@perf_timer()` only log timing when `TMUX_EASYMOTION_PERF` is enabled |
| 85 | +- The `@functools.lru_cache` on width calculation functions significantly improves performance with repeated characters |
0 commit comments