Hopefully final touches on the new tab completion.

This commit is contained in:
Storm Dragon
2026-05-09 00:14:36 -04:00
parent 0af7d94014
commit be78db0d58
4 changed files with 93 additions and 1 deletions

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.core.tabCompletionManager import TabCompletionManager
class command:
def __init__(self):
self.manager = TabCompletionManager()
def initialize(self, environment):
self.env = environment
self.manager.initialize(environment)
def shutdown(self):
pass
def get_description(self):
return _("Announces tab completions on cursor movement")
def run(self):
text = self.manager.process_update()
if not text:
return
do_interrupt = True
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
"speech", "auto_read_incoming"
):
do_interrupt = False
self.env["runtime"]["OutputManager"].present_text(
text,
interrupt=do_interrupt,
announce_capital=True,
flush=False,
)
def set_callback(self, callback):
pass

View File

@@ -39,6 +39,9 @@ class TabCompletionManager:
def process_update(self):
self._ensure_state()
state = self.env["commandBuffer"]["tabCompletion"]
if self._was_recently_processed(state):
return ""
pending = state.get("pending")
if not pending:
pending = self._build_pending_from_recent_tab_update()
@@ -62,6 +65,14 @@ class TabCompletionManager:
state["lastProcessedTime"] = time.time()
return spoken_text
def _was_recently_processed(self, state):
if state.get("lastProcessedDelta") != self.env["screen"]["new_delta"]:
return False
last_time = state.get("lastProcessedTime")
if not last_time:
return False
return time.time() - last_time <= self.timeout
def _build_pending_from_recent_tab_update(self):
if not self._recent_tab_input():
return None

View File

@@ -4,5 +4,5 @@
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
version = "2026.05.08"
version = "2026.05.09"
code_name = "testing"

View File

@@ -81,6 +81,43 @@ def test_unique_completion_speaks_inserted_suffix():
assert state["lastProcessedDelta"] == "cuments/"
@pytest.mark.unit
def test_small_completion_speaks_inserted_suffix():
manager, env, _input_manager = _build_env(
"cd gi".ljust(20), {"x": 5, "y": 0}
)
manager.capture_if_tab()
_set_screen_update(
env,
"cd git/".ljust(20),
{"x": 7, "y": 0},
delta="t/",
typing=True,
)
assert manager.process_update() == "t/"
@pytest.mark.unit
def test_completion_processed_once_for_cursor_and_screen_update():
manager, env, _input_manager = _build_env(
"cd gi".ljust(20), {"x": 5, "y": 0}
)
manager.capture_if_tab()
_set_screen_update(
env,
"cd git/".ljust(20),
{"x": 7, "y": 0},
delta="t/",
typing=True,
)
assert manager.process_update() == "t/"
assert manager.process_update() == ""
@pytest.mark.unit
def test_candidate_list_speaks_visible_list_without_cursor_advance():
old_text = "\n".join(["$ cd Do".ljust(20), "".ljust(20), "".ljust(20)])