Fixed long standing bug where bottom of screen played for both top and bottom, found a couple other things that were off in the process.
This commit is contained in:
@@ -112,9 +112,9 @@ class command:
|
||||
"review", "end_of_screen"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("end of screen"),
|
||||
_("start of screen"),
|
||||
interrupt=True,
|
||||
sound_icon="EndOfScreen",
|
||||
sound_icon="StartOfScreen",
|
||||
)
|
||||
if line_break:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
|
||||
@@ -49,9 +49,9 @@ class command:
|
||||
"review", "end_of_screen"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("end of screen"),
|
||||
_("start of screen"),
|
||||
interrupt=True,
|
||||
sound_icon="EndOfScreen",
|
||||
sound_icon="StartOfScreen",
|
||||
)
|
||||
if line_break:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
|
||||
@@ -50,9 +50,9 @@ class command:
|
||||
"review", "end_of_screen"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("end of screen"),
|
||||
_("start of screen"),
|
||||
interrupt=True,
|
||||
sound_icon="EndOfScreen",
|
||||
sound_icon="StartOfScreen",
|
||||
)
|
||||
|
||||
def set_callback(self, callback):
|
||||
|
||||
@@ -95,9 +95,9 @@ class command:
|
||||
"review", "end_of_screen"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("end of screen"),
|
||||
_("start of screen"),
|
||||
interrupt=False,
|
||||
sound_icon="EndOfScreen",
|
||||
sound_icon="StartOfScreen",
|
||||
)
|
||||
if line_break:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
|
||||
@@ -60,9 +60,9 @@ class command:
|
||||
"review", "end_of_screen"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("end of screen"),
|
||||
_("start of screen"),
|
||||
interrupt=True,
|
||||
sound_icon="EndOfScreen",
|
||||
sound_icon="StartOfScreen",
|
||||
)
|
||||
if line_break:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
|
||||
@@ -50,9 +50,9 @@ class command:
|
||||
"review", "end_of_screen"
|
||||
):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
_("end of screen"),
|
||||
_("start of screen"),
|
||||
interrupt=True,
|
||||
sound_icon="EndOfScreen",
|
||||
sound_icon="StartOfScreen",
|
||||
)
|
||||
if line_break:
|
||||
if self.env["runtime"]["SettingsManager"].get_setting_as_bool(
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
# Fenrir TTY screen reader
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
version = "2026.05.24"
|
||||
version = "2026.05.29"
|
||||
code_name = "master"
|
||||
|
||||
@@ -47,7 +47,6 @@ def get_up_char(curr_x, curr_y, curr_text):
|
||||
curr_y -= 1
|
||||
if curr_y < 0:
|
||||
curr_y = 0
|
||||
else:
|
||||
end_of_screen = True
|
||||
curr_char = ""
|
||||
if not end_of_screen:
|
||||
@@ -63,7 +62,6 @@ def get_down_char(curr_x, curr_y, curr_text):
|
||||
curr_y += 1
|
||||
if curr_y >= len(wrapped_lines):
|
||||
curr_y = len(wrapped_lines) - 1
|
||||
else:
|
||||
end_of_screen = True
|
||||
curr_char = ""
|
||||
if not end_of_screen:
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from fenrirscreenreader.utils import char_utils
|
||||
|
||||
|
||||
COMMANDS_DIR = (
|
||||
Path(__file__).resolve().parents[2]
|
||||
/ "src"
|
||||
/ "fenrirscreenreader"
|
||||
/ "commands"
|
||||
/ "commands"
|
||||
)
|
||||
|
||||
|
||||
def load_command(name):
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
f"fenrir_{name}", COMMANDS_DIR / f"{name}.py"
|
||||
)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module.command()
|
||||
|
||||
|
||||
def build_environment(cursor):
|
||||
settings_manager = Mock()
|
||||
settings_manager.get_setting_as_bool.return_value = True
|
||||
output_manager = Mock()
|
||||
cursor_manager = Mock()
|
||||
cursor_manager.enter_review_mode_curr_text_cursor.return_value = None
|
||||
cursor_manager.get_review_or_text_cursor.return_value = cursor
|
||||
|
||||
return {
|
||||
"punctuation": {"PUNCTDICT": {" ": "space"}},
|
||||
"screen": {
|
||||
"newCursorReview": cursor.copy(),
|
||||
"new_cursor": cursor.copy(),
|
||||
"new_content_text": "abc\ndef",
|
||||
},
|
||||
"runtime": {
|
||||
"AttributeManager": Mock(has_attributes=Mock(return_value=False)),
|
||||
"CursorManager": cursor_manager,
|
||||
"OutputManager": output_manager,
|
||||
"SettingsManager": settings_manager,
|
||||
"TableManager": Mock(is_table_mode=Mock(return_value=False)),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def run_command(name, cursor):
|
||||
env = build_environment(cursor)
|
||||
command = load_command(name)
|
||||
command.initialize(env)
|
||||
command.run()
|
||||
return env["runtime"]["OutputManager"]
|
||||
|
||||
|
||||
def boundary_call(output_manager):
|
||||
return output_manager.present_text.call_args_list[-1]
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_previous_line_uses_start_of_screen_sound_at_top():
|
||||
output_manager = run_command("review_prev_line", {"x": 0, "y": 0})
|
||||
|
||||
call = boundary_call(output_manager)
|
||||
assert call.args[0] == "start of screen"
|
||||
assert call.kwargs["sound_icon"] == "StartOfScreen"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_next_line_uses_end_of_screen_sound_at_bottom():
|
||||
output_manager = run_command("review_next_line", {"x": 0, "y": 1})
|
||||
|
||||
call = boundary_call(output_manager)
|
||||
assert call.args[0] == "end of screen"
|
||||
assert call.kwargs["sound_icon"] == "EndOfScreen"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_previous_character_uses_start_of_screen_sound_at_top_left():
|
||||
output_manager = run_command("review_prev_char", {"x": 0, "y": 0})
|
||||
|
||||
call = boundary_call(output_manager)
|
||||
assert call.args[0] == "start of screen"
|
||||
assert call.kwargs["sound_icon"] == "StartOfScreen"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_next_character_uses_end_of_screen_sound_at_bottom_right():
|
||||
output_manager = run_command("review_next_char", {"x": 2, "y": 1})
|
||||
|
||||
call = boundary_call(output_manager)
|
||||
assert call.args[0] == "end of screen"
|
||||
assert call.kwargs["sound_icon"] == "EndOfScreen"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_vertical_character_navigation_reports_boundaries_only_at_edges():
|
||||
assert char_utils.get_up_char(0, 1, "abc\ndef") == (
|
||||
0,
|
||||
0,
|
||||
"a",
|
||||
False,
|
||||
)
|
||||
assert char_utils.get_up_char(0, 0, "abc\ndef") == (
|
||||
0,
|
||||
0,
|
||||
"",
|
||||
True,
|
||||
)
|
||||
assert char_utils.get_down_char(0, 0, "abc\ndef") == (
|
||||
0,
|
||||
1,
|
||||
"d",
|
||||
False,
|
||||
)
|
||||
assert char_utils.get_down_char(0, 1, "abc\ndef") == (
|
||||
0,
|
||||
1,
|
||||
"",
|
||||
True,
|
||||
)
|
||||
Reference in New Issue
Block a user