Hopefully fix some weirdness on tab completeion where it would read the entire screen instead of suggested tab completions.
This commit is contained in:
@@ -132,13 +132,6 @@ class TabCompletionManager:
|
|||||||
if candidate_text:
|
if candidate_text:
|
||||||
return self._clean_text(candidate_text)
|
return self._clean_text(candidate_text)
|
||||||
|
|
||||||
delta_text = self.env["screen"]["new_delta"]
|
|
||||||
if (
|
|
||||||
delta_text
|
|
||||||
and not self.env["screen"].get("new_delta_is_typing", False)
|
|
||||||
):
|
|
||||||
return self._clean_text(delta_text)
|
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def _get_cursor_line_inserted_text(
|
def _get_cursor_line_inserted_text(
|
||||||
@@ -184,26 +177,19 @@ class TabCompletionManager:
|
|||||||
return "".join(inserted_parts)
|
return "".join(inserted_parts)
|
||||||
|
|
||||||
def _get_candidate_text(self, old_lines, new_lines, cursor_y):
|
def _get_candidate_text(self, old_lines, new_lines, cursor_y):
|
||||||
if len(old_lines) != len(new_lines):
|
|
||||||
return self._get_inserted_lines(old_lines, new_lines, cursor_y)
|
|
||||||
|
|
||||||
changed_lines = []
|
|
||||||
old_cursor_line = (
|
old_cursor_line = (
|
||||||
old_lines[cursor_y].strip() if cursor_y < len(old_lines) else ""
|
old_lines[cursor_y].strip() if cursor_y < len(old_lines) else ""
|
||||||
)
|
)
|
||||||
for index, old_line in enumerate(old_lines):
|
return self._get_inserted_lines(
|
||||||
if index == cursor_y:
|
old_lines,
|
||||||
continue
|
new_lines,
|
||||||
if index < len(new_lines) and old_line != new_lines[index]:
|
self.env["screen"]["new_cursor"]["y"],
|
||||||
if new_lines[index].strip() == old_cursor_line:
|
old_cursor_line,
|
||||||
continue
|
|
||||||
changed_lines.append(new_lines[index])
|
|
||||||
|
|
||||||
return "\n".join(
|
|
||||||
line.rstrip() for line in changed_lines if line.strip()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_inserted_lines(self, old_lines, new_lines, cursor_y):
|
def _get_inserted_lines(
|
||||||
|
self, old_lines, new_lines, new_cursor_y, old_cursor_line
|
||||||
|
):
|
||||||
matcher = difflib.SequenceMatcher(
|
matcher = difflib.SequenceMatcher(
|
||||||
None, old_lines, new_lines, autojunk=False
|
None, old_lines, new_lines, autojunk=False
|
||||||
)
|
)
|
||||||
@@ -217,10 +203,15 @@ class TabCompletionManager:
|
|||||||
) in matcher.get_opcodes():
|
) in matcher.get_opcodes():
|
||||||
if tag not in ["insert", "replace"]:
|
if tag not in ["insert", "replace"]:
|
||||||
continue
|
continue
|
||||||
if new_end <= cursor_y:
|
if new_start > new_cursor_y:
|
||||||
|
continue
|
||||||
|
if tag == "replace" and any(
|
||||||
|
line.strip() for line in old_lines[old_start:old_end]
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
for line in new_lines[new_start:new_end]:
|
for line in new_lines[new_start:new_end]:
|
||||||
if line.strip():
|
stripped_line = line.strip()
|
||||||
|
if stripped_line and stripped_line != old_cursor_line:
|
||||||
inserted_lines.append(line.rstrip())
|
inserted_lines.append(line.rstrip())
|
||||||
return "\n".join(inserted_lines)
|
return "\n".join(inserted_lines)
|
||||||
|
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
# Fenrir TTY screen reader
|
# Fenrir TTY screen reader
|
||||||
# By Chrys, Storm Dragon, and contributors.
|
# By Chrys, Storm Dragon, and contributors.
|
||||||
|
|
||||||
version = "2026.05.29"
|
version = "2026.05.30"
|
||||||
code_name = "testing"
|
code_name = "testing"
|
||||||
|
|||||||
@@ -140,6 +140,93 @@ def test_candidate_list_speaks_visible_list_without_cursor_advance():
|
|||||||
assert manager.process_update() == "Documents/ Downloads/"
|
assert manager.process_update() == "Documents/ Downloads/"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_full_screen_scroll_speaks_only_inserted_candidate_list():
|
||||||
|
old_text = "\n".join(
|
||||||
|
[
|
||||||
|
"old top".ljust(30),
|
||||||
|
"old middle".ljust(30),
|
||||||
|
"old lower".ljust(30),
|
||||||
|
"old bottom".ljust(30),
|
||||||
|
"$ ./Toby".ljust(30),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
manager, env, _input_manager = _build_env(old_text, {"x": 8, "y": 4})
|
||||||
|
|
||||||
|
manager.capture_if_tab()
|
||||||
|
_set_screen_update(
|
||||||
|
env,
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"old middle".ljust(30),
|
||||||
|
"old lower".ljust(30),
|
||||||
|
"old bottom".ljust(30),
|
||||||
|
"TobyAccMod_V10-0.pk3 TobyConfig.ini".ljust(30),
|
||||||
|
"$ ./Toby".ljust(30),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
{"x": 8, "y": 4},
|
||||||
|
delta="\n".join(
|
||||||
|
[
|
||||||
|
"old middle",
|
||||||
|
"old lower",
|
||||||
|
"old bottom",
|
||||||
|
"TobyAccMod_V10-0.pk3 TobyConfig.ini",
|
||||||
|
"$ ./Toby",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert manager.process_update() == "TobyAccMod_V10-0.pk3 TobyConfig.ini"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_same_height_repaint_without_inserted_candidates_stays_silent():
|
||||||
|
old_text = "\n".join(
|
||||||
|
[
|
||||||
|
"old top".ljust(30),
|
||||||
|
"old middle".ljust(30),
|
||||||
|
"old lower".ljust(30),
|
||||||
|
"$ ./Toby".ljust(30),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
manager, env, _input_manager = _build_env(old_text, {"x": 8, "y": 3})
|
||||||
|
|
||||||
|
manager.capture_if_tab()
|
||||||
|
_set_screen_update(
|
||||||
|
env,
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"status line".ljust(30),
|
||||||
|
"old prompt history".ljust(30),
|
||||||
|
"unrelated output".ljust(30),
|
||||||
|
"$ ./Toby".ljust(30),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
{"x": 8, "y": 3},
|
||||||
|
delta="status line\nold prompt history\nunrelated output\n$ ./Toby",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert manager.process_update() == ""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_recent_tab_does_not_speak_delta_without_detected_completion():
|
||||||
|
old_text = "\n".join(["$ ./Toby".ljust(20), "".ljust(20)])
|
||||||
|
manager, env, _input_manager = _build_env(old_text, {"x": 8, "y": 0})
|
||||||
|
|
||||||
|
manager.capture_if_tab()
|
||||||
|
_set_screen_update(
|
||||||
|
env,
|
||||||
|
old_text,
|
||||||
|
{"x": 8, "y": 0},
|
||||||
|
delta="old unrelated screen content\n$ ./Toby",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert manager.process_update() == ""
|
||||||
|
assert env["commandBuffer"]["tabCompletion"]["pending"] is not None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
def test_no_screen_change_stays_silent_and_keeps_pending_briefly():
|
def test_no_screen_change_stays_silent_and_keeps_pending_briefly():
|
||||||
manager, env, _input_manager = _build_env(
|
manager, env, _input_manager = _build_env(
|
||||||
|
|||||||
Reference in New Issue
Block a user