|
12 | 12 | from itertools import islice |
13 | 13 | from typing import List, Optional |
14 | 14 |
|
| 15 | +# ANSI escape sequences |
| 16 | +ESC = '\033' |
| 17 | +CLEAR = f'{ESC}[2J' |
| 18 | +CLEAR_LINE = f'{ESC}[2K' |
| 19 | +HIDE_CURSOR = f'{ESC}[?25l' |
| 20 | +SHOW_CURSOR = f'{ESC}[?25h' |
| 21 | +RESET = f'{ESC}[0m' |
| 22 | +DIM = f'{ESC}[2m' |
| 23 | + |
| 24 | +# Configuration from environment |
| 25 | +KEYS = os.environ.get('TMUX_EASYMOTION_KEYS', 'asdfghjkl;') |
| 26 | +VERTICAL_BORDER = os.environ.get('TMUX_EASYMOTION_VERTICAL_BORDER', '│') |
| 27 | +HORIZONTAL_BORDER = os.environ.get('TMUX_EASYMOTION_HORIZONTAL_BORDER', '─') |
| 28 | +HINT1_FG = os.environ.get('TMUX_EASYMOTION_HINT1_FG', f'{ESC}[1;31m') |
| 29 | +HINT2_FG = os.environ.get('TMUX_EASYMOTION_HINT2_FG', f'{ESC}[1;32m') |
15 | 30 |
|
16 | 31 | def perf_timer(func_name=None): |
17 | 32 | """Performance timing decorator that only logs when TMUX_EASYMOTION_PERF is true""" |
@@ -41,31 +56,14 @@ def setup_logging(): |
41 | 56 | logging.getLogger().disabled = True |
42 | 57 | return |
43 | 58 |
|
44 | | - log_file = os.path.expanduser( '~/easymotion.log') |
| 59 | + log_file = os.path.expanduser('~/easymotion.log') |
45 | 60 | logging.basicConfig( |
46 | 61 | filename=log_file, |
47 | 62 | level=logging.DEBUG, |
48 | 63 | format='%(asctime)s - %(levelname)s - %(message)s' |
49 | 64 | ) |
50 | 65 |
|
51 | 66 |
|
52 | | -# ANSI escape sequences |
53 | | -ESC = '\033' |
54 | | -CLEAR = f'{ESC}[2J' |
55 | | -CLEAR_LINE = f'{ESC}[2K' |
56 | | -HIDE_CURSOR = f'{ESC}[?25l' |
57 | | -SHOW_CURSOR = f'{ESC}[?25h' |
58 | | -RESET = f'{ESC}[0m' |
59 | | -RED_FG = f'{ESC}[31m' |
60 | | -GREEN_FG = f'{ESC}[32m' |
61 | | -DIM = f'{ESC}[2m' |
62 | | - |
63 | | -# Configuration from environment |
64 | | -KEYS = os.environ.get('TMUX_EASYMOTION_KEYS', 'asdfghjkl;') |
65 | | -VERTICAL_BORDER = os.environ.get('TMUX_EASYMOTION_VERTICAL_BORDER', '│') |
66 | | -HORIZONTAL_BORDER = os.environ.get('TMUX_EASYMOTION_HORIZONTAL_BORDER', '─') |
67 | | - |
68 | | - |
69 | 67 | @functools.lru_cache(maxsize=1024) |
70 | 68 | def get_char_width(char: str) -> int: |
71 | 69 | """Get visual width of a single character with caching""" |
@@ -222,6 +220,7 @@ def to_terminal_coords(y: int, x: int) -> tuple[int, int]: |
222 | 220 | """ |
223 | 221 | return y + 1, x + 1 |
224 | 222 |
|
| 223 | + |
225 | 224 | def getch(): |
226 | 225 | """Get a single character from terminal""" |
227 | 226 | fd = sys.stdin.fileno() |
@@ -361,14 +360,17 @@ def draw_all_panes(panes, max_x, padding_cache, terminal_height): |
361 | 360 | # draw vertical borders |
362 | 361 | if pane.start_x + pane.width < max_x: |
363 | 362 | for y in range(pane.start_y, pane.start_y + visible_height): |
364 | | - term_y, term_x = to_terminal_coords(y, pane.start_x + pane.width) |
365 | | - sys.stdout.write(f'{ESC}[{term_y};{term_x}H{DIM}{VERTICAL_BORDER}{RESET}') |
| 363 | + term_y, term_x = to_terminal_coords( |
| 364 | + y, pane.start_x + pane.width) |
| 365 | + sys.stdout.write(f'{ESC}[{term_y};{term_x}H{ |
| 366 | + DIM}{VERTICAL_BORDER}{RESET}') |
366 | 367 |
|
367 | 368 | # draw horizontal borders for non-last pane |
368 | 369 | end_y = pane.start_y + visible_height |
369 | 370 | if end_y < terminal_height and pane != sorted_panes[-1]: |
370 | 371 | term_y, term_x = to_terminal_coords(end_y, pane.start_x) |
371 | | - sys.stdout.write(f'{ESC}[{term_y};{term_x}H{DIM}{HORIZONTAL_BORDER * pane.width}{RESET}') |
| 372 | + sys.stdout.write(f'{ESC}[{term_y};{term_x}H{DIM}{ |
| 373 | + HORIZONTAL_BORDER * pane.width}{RESET}') |
372 | 374 |
|
373 | 375 | sys.stdout.flush() |
374 | 376 |
|
@@ -403,11 +405,13 @@ def draw_all_hints(panes, terminal_height): |
403 | 405 | x = pane.start_x + col |
404 | 406 | if (y < min(pane.start_y + pane.height, terminal_height) and x + get_char_width(char) <= pane.start_x + pane.width): |
405 | 407 | term_y, term_x = to_terminal_coords(y, x) |
406 | | - sys.stdout.write(f'{ESC}[{term_y};{term_x}H{RED_FG}{hint[0]}{RESET}') |
| 408 | + sys.stdout.write(f'{ESC}[{term_y};{term_x}H{ |
| 409 | + HINT1_FG}{hint[0]}{RESET}') |
407 | 410 | char_width = get_char_width(char) |
408 | 411 | if x + char_width < pane.start_x + pane.width: |
409 | 412 | term_y, term_x = to_terminal_coords(y, x + char_width) |
410 | | - sys.stdout.write(f'{ESC}[{term_y};{term_x}H{GREEN_FG}{hint[1]}{RESET}') |
| 413 | + sys.stdout.write(f'{ESC}[{term_y};{term_x}H{ |
| 414 | + HINT2_FG}{hint[1]}{RESET}') |
411 | 415 | sys.stdout.flush() |
412 | 416 |
|
413 | 417 |
|
@@ -448,10 +452,12 @@ def main(): |
448 | 452 | char_width = get_char_width(char) |
449 | 453 | if (y < min(pane.start_y + pane.height, terminal_height) and x + char_width <= pane.start_x + pane.width): |
450 | 454 | # Clear first position and show second character |
451 | | - sys.stdout.write(f'{ESC}[{y + 1};{x + 1}H{GREEN_FG}{hint[1]}{RESET}') |
| 455 | + sys.stdout.write( |
| 456 | + f'{ESC}[{y + 1};{x + 1}H{HINT2_FG}{hint[1]}{RESET}') |
452 | 457 | # Restore original character in second position (if there's space) |
453 | 458 | if x + char_width + 1 < pane.start_x + pane.width: |
454 | | - sys.stdout.write(f'{ESC}[{y + 1};{x + char_width + 1}H{char}') |
| 459 | + sys.stdout.write( |
| 460 | + f'{ESC}[{y + 1};{x + char_width + 1}H{char}') |
455 | 461 | sys.stdout.flush() |
456 | 462 |
|
457 | 463 | # Handle second character selection |
|
0 commit comments