|
39 | 39 |
|
40 | 40 | def _read_key_unix() -> str: |
41 | 41 | """Read a single keypress on Unix, handling escape sequences.""" |
| 42 | + import os |
| 43 | + import select |
42 | 44 | import termios |
43 | 45 | import tty |
44 | 46 |
|
45 | 47 | fd = sys.stdin.fileno() |
46 | 48 | old = termios.tcgetattr(fd) |
47 | 49 | try: |
48 | 50 | tty.setraw(fd) |
49 | | - ch = sys.stdin.buffer.read(1) |
| 51 | + # Use os.read(fd) directly instead of sys.stdin.buffer.read() to avoid |
| 52 | + # Python's BufferedReader pre-buffering the entire escape sequence |
| 53 | + # (e.g. \x1b[A) into its internal buffer, which empties the underlying |
| 54 | + # fd so that the subsequent select.select() always times out and the |
| 55 | + # arrow key is misread as ESC. |
| 56 | + ch = os.read(fd, 1) |
50 | 57 | if ch == b"\x1b": |
51 | | - # Read potential escape sequence with a short timeout |
52 | | - import select |
53 | | - |
54 | | - if select.select([sys.stdin], [], [], 0.05)[0]: |
55 | | - ch2 = sys.stdin.buffer.read(1) |
56 | | - if ch2 == b"[" and select.select([sys.stdin], [], [], 0.05)[0]: |
57 | | - ch3 = sys.stdin.buffer.read(1) |
| 58 | + # Handle both CSI (\x1b[A/B) and SS3 (\x1bOA/B) sequences. |
| 59 | + # SS3 is sent by macOS Terminal, iTerm2, and other emulators when |
| 60 | + # application cursor-key mode is active. |
| 61 | + if select.select([fd], [], [], 0.1)[0]: |
| 62 | + ch2 = os.read(fd, 1) |
| 63 | + if ch2 in (b"[", b"O") and select.select([fd], [], [], 0.1)[0]: |
| 64 | + ch3 = os.read(fd, 1) |
58 | 65 | return {b"A": "UP", b"B": "DOWN"}.get(ch3, "ESC") |
59 | 66 | return "ESC" |
60 | 67 | return { |
@@ -487,6 +494,15 @@ def _get_client_configs() -> dict[str, tuple[str, str]]: |
487 | 494 | ), |
488 | 495 | "opencode.json", |
489 | 496 | ), |
| 497 | + "Void": ( |
| 498 | + _join_path( |
| 499 | + os.environ.get("XDG_CONFIG_HOME") or _join_path(home, ".config"), |
| 500 | + "void", |
| 501 | + ), |
| 502 | + "mcp_servers.json", |
| 503 | + ), |
| 504 | + "BoltAI": (_join_path(home, ".boltai"), "mcp.json"), |
| 505 | + "Kiro": (_join_path(home, ".kiro", "settings"), "mcp.json"), |
490 | 506 | "VS Code": ( |
491 | 507 | _join_path(home, "Library", "Application Support", "Code", "User"), |
492 | 508 | "settings.json", |
@@ -545,6 +561,8 @@ def _get_client_configs() -> dict[str, tuple[str, str]]: |
545 | 561 | "Copilot CLI": (_join_path(home, ".copilot"), "mcp-config.json"), |
546 | 562 | "Amazon Q": (_join_path(home, ".aws", "amazonq"), "mcp_config.json"), |
547 | 563 | "OpenCode": (_join_path(config_home, "opencode"), "opencode.json"), |
| 564 | + "Void": (_join_path(config_home, "void"), "mcp_servers.json"), |
| 565 | + "Kiro": (_join_path(home, ".kiro", "settings"), "mcp.json"), |
548 | 566 | "VS Code": (_join_path(config_home, "Code", "User"), "settings.json"), |
549 | 567 | "VS Code Insiders": (_join_path(config_home, "Code - Insiders", "User"), "settings.json"), |
550 | 568 | } |
@@ -601,6 +619,8 @@ def _get_client_configs() -> dict[str, tuple[str, str]]: |
601 | 619 | "Copilot CLI": (_join_path(home, ".copilot", platform="win32"), "mcp-config.json"), |
602 | 620 | "Amazon Q": (_join_path(home, ".aws", "amazonq", platform="win32"), "mcp_config.json"), |
603 | 621 | "OpenCode": (_join_path(appdata, "opencode", platform="win32"), "opencode.json"), |
| 622 | + "Void": (_join_path(appdata, "void", platform="win32"), "mcp_servers.json"), |
| 623 | + "Kiro": (_join_path(home, ".kiro", "settings", platform="win32"), "mcp.json"), |
604 | 624 | "VS Code": (_join_path(appdata, "Code", "User", platform="win32"), "settings.json"), |
605 | 625 | "VS Code Insiders": (_join_path(appdata, "Code - Insiders", "User", platform="win32"), "settings.json"), |
606 | 626 | } |
|
0 commit comments