Feat/picker multi select#52
Open
sigfriedCub1990 wants to merge 34 commits into
Open
Conversation
* Add ASCII BEL symbol to notify tmux on test failure * Refactor BEL notification * Add --notify-on-failure option * Adjust tests to pass with new option * Move BEL notification logic to the Terminal layer. Update README --------- Co-authored-by: olzhasar <o.arystanov@gmail.com>
* Migrate to uv. Remove tox * Use "latest" release in sphinx conf. Update README
Add a fuzzy matching module with: - fuzzy_match(): case-insensitive subsequence matching with scoring (consecutive bonus, word-boundary bonus, shorter-tail bonus) - find_test_files(): discovers test files (test_*.py, *_test.py) via rglob - fuzzy_filter(): filters and ranks candidates by fuzzy match score
Add an fzf-style interactive TUI (press 't') that lets users: - Type a query to fuzzy-filter test files with live-updating results - Navigate results with arrow keys (up/down) - Select a file with Enter to run pytest on it - Cancel with Escape to return to the watcher Components: - picker.py: PickerState, key event parsing (including arrow escape sequences), pure-function state machine, ANSI rendering with highlighted cursor row, injectable I/O for testability - FuzzyFilterCommand in commands.py: discovers test files, launches the picker, preserves CLI flags, triggers pytest on selection
Two bugs in _read_key_event caused arrow keys to be misinterpreted as Escape (cancelling the picker): 1. Python's BufferedReader eagerly consumes bytes from the fd into its internal buffer. When select() checks the OS-level fd for the continuation bytes of an escape sequence (e.g. '[' and 'B' after ESC), it finds nothing — the bytes are already in Python's buffer. read_char() returns None, and the sequence is treated as bare ESC. Fix: _read_continuation() retries up to 4 times on None returns before giving up, giving the buffered bytes a chance to surface. 2. Application-mode arrow keys (ESC O A/B) were not recognized — only normal-mode (ESC [ A/B) was handled. Some terminals send application-mode sequences depending on configuration. Fix: accept both 'O' and '[' as the second byte of arrow sequences. Added 12 new tests: - 7 _read_key_event tests for None gaps and application-mode sequences - 5 end-to-end run_picker tests with gapped readers simulating real terminal behavior
The previous retry-based fix could not work. The real problem: 1. Arrow key press sends 3 bytes to the OS fd: \x1b [ B 2. select(fd) reports data available 3. sys.stdin.read(1) triggers Python's BufferedReader to call os.read(fd, 8192) internally, pulling ALL 3 bytes into Python's buffer, but only returning the first (\x1b) 4. _read_continuation retries read_char(), but each retry calls select(fd) which sees an EMPTY fd — the bytes are permanently trapped in Python's BufferedReader, invisible to select() 5. All retries fail → arrow key misinterpreted as Escape → picker cancels immediately Fix: replace sys.stdin.read(1) with os.read(fd, 1) via make_raw_reader(). This bypasses Python's BufferedReader entirely, so select() and reads operate on the same OS-level buffer. Each os.read(fd, 1) consumes exactly 1 byte, leaving the rest on the fd for the next select() call. Added 6 new tests (TestMakeRawReader): - Single byte read, None on empty, byte-by-byte escape sequence reading - Arrow key parsing through raw reader - Multiple arrow keys in a single burst - Full run_picker end-to-end using raw reader on a real pipe fd
In raw terminal mode, \n only moves the cursor down without returning
to column 0. Replace all terminal output \n with \r\n in the picker
to fix the garbled initial render.
Also fix:
- finally block bare \n causing misaligned post-picker output
- _printed_line_count to use splitlines() for robustness
- tests to use splitlines() instead of split("\n")
Tab toggles a mark on the current item and moves down; Shift-Tab toggles and moves up (ESC [ Z, previously misread as Escape). Enter accepts all marked files — or the highlighted one when none are marked — and passes them all to the test runner, following fzf semantics. Marks are stored by value so they survive re-filtering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.