Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 56 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,71 @@ Enable performance logging:
set -g @easymotion-perf 'true'
```

## Motion Types

The plugin supports multiple motion types, controlled by the `TMUX_EASYMOTION_MOTION_TYPE` environment variable:

- **s** (default): 1-character search - prompts for a single character and shows hints for all matches
- **s2**: 2-character search - prompts for two consecutive characters for more precise matching

### Motion Type Implementation

Each motion type is set up via different tmux key bindings in easymotion.tmux:

- **@easymotion-key**: Legacy binding (backward compatible, uses 's' mode)
- **@easymotion-s**: Explicit 1-char search binding
- **@easymotion-s2**: 2-char search binding (uses two sequential `command-prompt` calls)

The `main()` function in easymotion.py reads the `MOTION_TYPE` environment variable and:
1. For 's': reads 1 character from the temp file
2. For 's2': reads 2 characters from the temp file
3. Calls `find_matches()` with the search pattern

### 2-Character Search Details

The `find_matches()` function was refactored to support multi-character patterns:
- Accepts `search_pattern` (1+ characters) instead of `search_ch` (single character)
- For multi-char patterns, checks substring matches at each position
- Handles wide character boundaries - skips matches that would split a wide (CJK) character
- Smartsign applies to **all pattern lengths** via `generate_smartsign_patterns()`

### Smartsign Architecture

**Design Principle**: Smartsign is a **generic transformation layer** that works independently of search mode.

**Key Components**:

1. **`generate_smartsign_patterns(pattern)`**: Generic pattern generator
- Works for patterns of **any length** (1-char, 2-char, 3-char, etc.)
- Each character position is independently expanded if it has a smartsign mapping
- Returns all possible combinations using Cartesian product
- Example: `"3,"` → `["3,", "#,", "3<", "#<"]` (4 combinations)

2. **`find_matches(panes, search_pattern)`**: Pattern-agnostic matching engine
- Calls `generate_smartsign_patterns()` to get all pattern variants
- Performs matching logic once for all variants
- No mode-specific smartsign logic needed

3. **Extensibility**: New search modes automatically get smartsign support
- Mode determines **what to search** (user input, word boundaries, etc.)
- Smartsign determines **how to expand the pattern**
- Matching logic is unified

**Performance**: For 2-char search with both chars having mappings, maximum 4 pattern variants. For 3-char, maximum 8 variants. This is acceptable overhead.

## Configuration Options (tmux.conf)

All options are read from tmux options in easymotion.tmux and passed as environment variables to the Python script:

- `@easymotion-key`: Trigger key binding (default: 's')
- `@easymotion-key`: Trigger key binding for 1-char search (default: 's', backward compatible)
- `@easymotion-s`: Explicit 1-char search key binding (optional)
- `@easymotion-s2`: 2-char search key binding (optional, e.g., 'f')
- `@easymotion-hints`: Characters used for hints (default: 'asdghklqwertyuiopzxcvbnmfj;')
- `@easymotion-vertical-border`: Character for vertical borders (default: '│')
- `@easymotion-horizontal-border`: Character for horizontal borders (default: '─')
- `@easymotion-use-curses`: Use curses instead of ANSI sequences (default: 'false')
- `@easymotion-case-sensitive`: Case-sensitive search (default: 'false')
- `@easymotion-smartsign`: Enable smartsign feature to match shifted symbols (default: 'false')
- `@easymotion-smartsign`: Enable smartsign feature to match shifted symbols (default: 'false', works with all search modes)

## Important Implementation Notes

Expand Down
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,30 @@ Press `prefix` + `I` to install
### Options:

```bash
# ============================================================================
# Key Bindings - Motion Types
# ============================================================================

# 1-Character Search (Traditional)
# Usage: prefix + <key> → type a character → hints appear at all occurrences
# Use case: Quick jumps when the target character is unique or easy to spot
# set -g @easymotion-key 's' # Legacy 1-char search (default: 's', backward compatible)
set -g @easymotion-s 's'

# 2-Character Search (similar to leap.nvim)
# Usage: prefix + <key> → type 2 chars → hints appear only where both match consecutively
# Use case: Reduce screen clutter by narrowing down matches with 2 characters
# Benefits:
# - Fewer hints on screen = easier to read
# - More precise targeting
# - Supports CJK (wide) characters
# - Works with case-sensitivity and smartsign options
set -g @easymotion-s2 'f'

# ============================================================================
# Other Configuration Options
# ============================================================================

# Keys used for hints (default: 'asdghklqwertyuiopzxcvbnmfj;')
set -g @easymotion-hints 'asdfghjkl;'

Expand All @@ -58,6 +82,7 @@ set -g @easymotion-perf 'true'
set -g @easymotion-case-sensitive 'true'

# Enable smartsign feature (default: false)
# Works with all search modes (s, s2, etc.)
set -g @easymotion-smartsign 'true'
```

Expand All @@ -72,9 +97,12 @@ bind-key -T copy-mode-vi V send-keys -X select-line;
```


### Usage
`prefix` + `s` -> hit a character -> hit hints (jump to position) -> press `ve` and `y` to copy
### Usage Examples

**Copy a word:**
`prefix` + `s` → type character → select hint → press `ve` and `y` to copy

**Paste:**
`prefix` + `]` to paste


Expand Down
46 changes: 46 additions & 0 deletions common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env bash

# Common functions and configuration for easymotion modes

# Read configuration from tmux options
get_tmux_option() {
local option=$1
local default_value=$2
local option_value=$(tmux show-option -gqv "$option")
if [ -z $option_value ]; then
echo $default_value
else
echo $option_value
fi
}

# Get all configuration options
HINTS=$(get_tmux_option "@easymotion-hints" "asdghklqwertyuiopzxcvbnmfj;")
VERTICAL_BORDER=$(get_tmux_option "@easymotion-vertical-border" "│")
HORIZONTAL_BORDER=$(get_tmux_option "@easymotion-horizontal-border" "─")
USE_CURSES=$(get_tmux_option "@easymotion-use-curses" "false")
DEBUG=$(get_tmux_option "@easymotion-debug" "false")
PERF=$(get_tmux_option "@easymotion-perf" "false")
CASE_SENSITIVE=$(get_tmux_option "@easymotion-case-sensitive" "false")
SMARTSIGN=$(get_tmux_option "@easymotion-smartsign" "false")

# Create temporary input file with reset character
create_input_file() {
local tmp_file=$(mktemp -t tmux-easymotion_keystroke-XXXXXXX)
printf '\x03' > "$tmp_file"
echo "$tmp_file"
}

# Build environment variables string for neww -d
build_env_vars() {
local motion_type=$1
echo "TMUX_EASYMOTION_HINTS=\"$HINTS\" \
TMUX_EASYMOTION_VERTICAL_BORDER=\"$VERTICAL_BORDER\" \
TMUX_EASYMOTION_HORIZONTAL_BORDER=\"$HORIZONTAL_BORDER\" \
TMUX_EASYMOTION_USE_CURSES=\"$USE_CURSES\" \
TMUX_EASYMOTION_DEBUG=\"$DEBUG\" \
TMUX_EASYMOTION_PERF=\"$PERF\" \
TMUX_EASYMOTION_CASE_SENSITIVE=\"$CASE_SENSITIVE\" \
TMUX_EASYMOTION_SMARTSIGN=\"$SMARTSIGN\" \
TMUX_EASYMOTION_MOTION_TYPE=\"$motion_type\""
}
Loading
Loading