Skip to content

Commit 5937bbd

Browse files
authored
feat: easymotion-s2 mode (#11)
1 parent 96b18cd commit 5937bbd

File tree

8 files changed

+788
-71
lines changed

8 files changed

+788
-71
lines changed

CLAUDE.md

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,71 @@ Enable performance logging:
6868
set -g @easymotion-perf 'true'
6969
```
7070

71+
## Motion Types
72+
73+
The plugin supports multiple motion types, controlled by the `TMUX_EASYMOTION_MOTION_TYPE` environment variable:
74+
75+
- **s** (default): 1-character search - prompts for a single character and shows hints for all matches
76+
- **s2**: 2-character search - prompts for two consecutive characters for more precise matching
77+
78+
### Motion Type Implementation
79+
80+
Each motion type is set up via different tmux key bindings in easymotion.tmux:
81+
82+
- **@easymotion-key**: Legacy binding (backward compatible, uses 's' mode)
83+
- **@easymotion-s**: Explicit 1-char search binding
84+
- **@easymotion-s2**: 2-char search binding (uses two sequential `command-prompt` calls)
85+
86+
The `main()` function in easymotion.py reads the `MOTION_TYPE` environment variable and:
87+
1. For 's': reads 1 character from the temp file
88+
2. For 's2': reads 2 characters from the temp file
89+
3. Calls `find_matches()` with the search pattern
90+
91+
### 2-Character Search Details
92+
93+
The `find_matches()` function was refactored to support multi-character patterns:
94+
- Accepts `search_pattern` (1+ characters) instead of `search_ch` (single character)
95+
- For multi-char patterns, checks substring matches at each position
96+
- Handles wide character boundaries - skips matches that would split a wide (CJK) character
97+
- Smartsign applies to **all pattern lengths** via `generate_smartsign_patterns()`
98+
99+
### Smartsign Architecture
100+
101+
**Design Principle**: Smartsign is a **generic transformation layer** that works independently of search mode.
102+
103+
**Key Components**:
104+
105+
1. **`generate_smartsign_patterns(pattern)`**: Generic pattern generator
106+
- Works for patterns of **any length** (1-char, 2-char, 3-char, etc.)
107+
- Each character position is independently expanded if it has a smartsign mapping
108+
- Returns all possible combinations using Cartesian product
109+
- Example: `"3,"``["3,", "#,", "3<", "#<"]` (4 combinations)
110+
111+
2. **`find_matches(panes, search_pattern)`**: Pattern-agnostic matching engine
112+
- Calls `generate_smartsign_patterns()` to get all pattern variants
113+
- Performs matching logic once for all variants
114+
- No mode-specific smartsign logic needed
115+
116+
3. **Extensibility**: New search modes automatically get smartsign support
117+
- Mode determines **what to search** (user input, word boundaries, etc.)
118+
- Smartsign determines **how to expand the pattern**
119+
- Matching logic is unified
120+
121+
**Performance**: For 2-char search with both chars having mappings, maximum 4 pattern variants. For 3-char, maximum 8 variants. This is acceptable overhead.
122+
71123
## Configuration Options (tmux.conf)
72124

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

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

83137
## Important Implementation Notes
84138

README.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,30 @@ Press `prefix` + `I` to install
3838
### Options:
3939

4040
```bash
41+
# ============================================================================
42+
# Key Bindings - Motion Types
43+
# ============================================================================
44+
45+
# 1-Character Search (Traditional)
46+
# Usage: prefix + <key> → type a character → hints appear at all occurrences
47+
# Use case: Quick jumps when the target character is unique or easy to spot
48+
# set -g @easymotion-key 's' # Legacy 1-char search (default: 's', backward compatible)
49+
set -g @easymotion-s 's'
50+
51+
# 2-Character Search (similar to leap.nvim)
52+
# Usage: prefix + <key> → type 2 chars → hints appear only where both match consecutively
53+
# Use case: Reduce screen clutter by narrowing down matches with 2 characters
54+
# Benefits:
55+
# - Fewer hints on screen = easier to read
56+
# - More precise targeting
57+
# - Supports CJK (wide) characters
58+
# - Works with case-sensitivity and smartsign options
59+
set -g @easymotion-s2 'f'
60+
61+
# ============================================================================
62+
# Other Configuration Options
63+
# ============================================================================
64+
4165
# Keys used for hints (default: 'asdghklqwertyuiopzxcvbnmfj;')
4266
set -g @easymotion-hints 'asdfghjkl;'
4367

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

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

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

7499

75-
### Usage
76-
`prefix` + `s` -> hit a character -> hit hints (jump to position) -> press `ve` and `y` to copy
100+
### Usage Examples
101+
102+
**Copy a word:**
103+
`prefix` + `s` → type character → select hint → press `ve` and `y` to copy
77104

105+
**Paste:**
78106
`prefix` + `]` to paste
79107

80108

common.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env bash
2+
3+
# Common functions and configuration for easymotion modes
4+
5+
# Read configuration from tmux options
6+
get_tmux_option() {
7+
local option=$1
8+
local default_value=$2
9+
local option_value=$(tmux show-option -gqv "$option")
10+
if [ -z $option_value ]; then
11+
echo $default_value
12+
else
13+
echo $option_value
14+
fi
15+
}
16+
17+
# Get all configuration options
18+
HINTS=$(get_tmux_option "@easymotion-hints" "asdghklqwertyuiopzxcvbnmfj;")
19+
VERTICAL_BORDER=$(get_tmux_option "@easymotion-vertical-border" "")
20+
HORIZONTAL_BORDER=$(get_tmux_option "@easymotion-horizontal-border" "")
21+
USE_CURSES=$(get_tmux_option "@easymotion-use-curses" "false")
22+
DEBUG=$(get_tmux_option "@easymotion-debug" "false")
23+
PERF=$(get_tmux_option "@easymotion-perf" "false")
24+
CASE_SENSITIVE=$(get_tmux_option "@easymotion-case-sensitive" "false")
25+
SMARTSIGN=$(get_tmux_option "@easymotion-smartsign" "false")
26+
27+
# Create temporary input file with reset character
28+
create_input_file() {
29+
local tmp_file=$(mktemp -t tmux-easymotion_keystroke-XXXXXXX)
30+
printf '\x03' > "$tmp_file"
31+
echo "$tmp_file"
32+
}
33+
34+
# Build environment variables string for neww -d
35+
build_env_vars() {
36+
local motion_type=$1
37+
echo "TMUX_EASYMOTION_HINTS=\"$HINTS\" \
38+
TMUX_EASYMOTION_VERTICAL_BORDER=\"$VERTICAL_BORDER\" \
39+
TMUX_EASYMOTION_HORIZONTAL_BORDER=\"$HORIZONTAL_BORDER\" \
40+
TMUX_EASYMOTION_USE_CURSES=\"$USE_CURSES\" \
41+
TMUX_EASYMOTION_DEBUG=\"$DEBUG\" \
42+
TMUX_EASYMOTION_PERF=\"$PERF\" \
43+
TMUX_EASYMOTION_CASE_SENSITIVE=\"$CASE_SENSITIVE\" \
44+
TMUX_EASYMOTION_SMARTSIGN=\"$SMARTSIGN\" \
45+
TMUX_EASYMOTION_MOTION_TYPE=\"$motion_type\""
46+
}

0 commit comments

Comments
 (0)