Hopefully make pty more similar to tested console behavior.
This commit is contained in:
@@ -356,32 +356,37 @@ class ScreenManager:
|
|||||||
# Not typing - handle as line-by-line content change
|
# Not typing - handle as line-by-line content change
|
||||||
# This catches: incoming messages, screen updates,
|
# This catches: incoming messages, screen updates,
|
||||||
# application output, etc.
|
# application output, etc.
|
||||||
|
appended_text = self._get_recent_cursor_line_append()
|
||||||
|
if appended_text is not None:
|
||||||
|
diff_list = ["+ " + appended_text]
|
||||||
|
typing = True
|
||||||
|
else:
|
||||||
|
|
||||||
# Pre-process screen text for comparison - collapse multiple spaces to single space
|
# Pre-process screen text for comparison - collapse multiple spaces to single space
|
||||||
# This normalization prevents spurious diffs from spacing
|
# This normalization prevents spurious diffs from spacing
|
||||||
# inconsistencies
|
# inconsistencies
|
||||||
old_screen_text = self._space_normalize_regex.sub(
|
old_screen_text = self._space_normalize_regex.sub(
|
||||||
" ",
|
" ",
|
||||||
self.env["runtime"][
|
self.env["runtime"][
|
||||||
"ScreenManager"
|
"ScreenManager"
|
||||||
].get_window_area_in_text(
|
].get_window_area_in_text(
|
||||||
self.env["screen"]["old_content_text"]
|
self.env["screen"]["old_content_text"]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
new_screen_text = self._space_normalize_regex.sub(
|
new_screen_text = self._space_normalize_regex.sub(
|
||||||
" ",
|
" ",
|
||||||
self.env["runtime"][
|
self.env["runtime"][
|
||||||
"ScreenManager"
|
"ScreenManager"
|
||||||
].get_window_area_in_text(
|
].get_window_area_in_text(
|
||||||
self.env["screen"]["new_content_text"]
|
self.env["screen"]["new_content_text"]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
diff = self.differ.compare(
|
diff = self.differ.compare(
|
||||||
old_screen_text.split("\n"),
|
old_screen_text.split("\n"),
|
||||||
new_screen_text.split("\n"),
|
new_screen_text.split("\n"),
|
||||||
)
|
)
|
||||||
diff_list = list(diff)
|
diff_list = list(diff)
|
||||||
|
|
||||||
# Extract added and removed content from diff results
|
# Extract added and removed content from diff results
|
||||||
# Output format depends on whether this was detected as typing
|
# Output format depends on whether this was detected as typing
|
||||||
@@ -453,6 +458,44 @@ class ScreenManager:
|
|||||||
)
|
)
|
||||||
return screen in ignore_screens
|
return screen in ignore_screens
|
||||||
|
|
||||||
|
def _get_recent_cursor_line_append(self):
|
||||||
|
try:
|
||||||
|
if time.time() - self.env["runtime"][
|
||||||
|
"InputManager"
|
||||||
|
].get_last_input_time() > 0.3:
|
||||||
|
return None
|
||||||
|
|
||||||
|
old_lines = self.env["screen"]["old_content_text"].split("\n")
|
||||||
|
new_lines = self.env["screen"]["new_content_text"].split("\n")
|
||||||
|
cursor_y = self.env["screen"]["new_cursor"]["y"]
|
||||||
|
if (
|
||||||
|
len(old_lines) != len(new_lines)
|
||||||
|
or cursor_y < 0
|
||||||
|
or cursor_y >= len(new_lines)
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
|
changed_lines = [
|
||||||
|
index
|
||||||
|
for index, old_line in enumerate(old_lines)
|
||||||
|
if index >= len(new_lines) or old_line != new_lines[index]
|
||||||
|
]
|
||||||
|
if changed_lines != [cursor_y]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
old_line = old_lines[cursor_y]
|
||||||
|
new_line = new_lines[cursor_y]
|
||||||
|
old_line = old_line.rstrip()
|
||||||
|
if not new_line.startswith(old_line):
|
||||||
|
return None
|
||||||
|
|
||||||
|
appended_text = new_line[len(old_line):].strip()
|
||||||
|
if appended_text == "" or len(appended_text) > 4:
|
||||||
|
return None
|
||||||
|
return appended_text
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
def is_screen_change(self):
|
def is_screen_change(self):
|
||||||
if not self.env["screen"]["oldTTY"]:
|
if not self.env["screen"]["oldTTY"]:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ class TestIncomingCommand:
|
|||||||
[
|
[
|
||||||
"Status old",
|
"Status old",
|
||||||
"Users old",
|
"Users old",
|
||||||
"alice: hi",
|
"UserA: hi",
|
||||||
"bob: hello",
|
"UserB: hello",
|
||||||
"> ",
|
"> ",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -97,19 +97,19 @@ class TestIncomingCommand:
|
|||||||
[
|
[
|
||||||
"Status new",
|
"Status new",
|
||||||
"Users new",
|
"Users new",
|
||||||
"bob: hello",
|
"UserB: hello",
|
||||||
"carol: test",
|
"UserC: test",
|
||||||
"> ",
|
"> ",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
env["screen"]["new_delta"] = "\n".join(
|
env["screen"]["new_delta"] = "\n".join(
|
||||||
["Status new", "Users new", "carol: test"]
|
["Status new", "Users new", "UserC: test"]
|
||||||
)
|
)
|
||||||
|
|
||||||
command.run()
|
command.run()
|
||||||
|
|
||||||
output_manager.present_text.assert_called_once_with(
|
output_manager.present_text.assert_called_once_with(
|
||||||
"carol: test", interrupt=False, flush=False
|
"UserC: test", interrupt=False, flush=False
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_keeps_header_update_when_no_lower_screen_insert_exists(
|
def test_keeps_header_update_when_no_lower_screen_insert_exists(
|
||||||
@@ -120,16 +120,16 @@ class TestIncomingCommand:
|
|||||||
[
|
[
|
||||||
"Status old",
|
"Status old",
|
||||||
"Users old",
|
"Users old",
|
||||||
"alice: hi",
|
"UserA: hi",
|
||||||
"bob: hello",
|
"UserB: hello",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
env["screen"]["new_content_text"] = "\n".join(
|
env["screen"]["new_content_text"] = "\n".join(
|
||||||
[
|
[
|
||||||
"Status new",
|
"Status new",
|
||||||
"Users new",
|
"Users new",
|
||||||
"alice: hi",
|
"UserA: hi",
|
||||||
"bob: hello",
|
"UserB: hello",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
env["screen"]["new_delta"] = "\n".join(["Status new", "Users new"])
|
env["screen"]["new_delta"] = "\n".join(["Status new", "Users new"])
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import time
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -18,6 +19,7 @@ def _build_screen_manager(old_text, old_cursor):
|
|||||||
),
|
),
|
||||||
"CursorManager": Mock(is_application_window_set=Mock(return_value=False)),
|
"CursorManager": Mock(is_application_window_set=Mock(return_value=False)),
|
||||||
"DebugManager": Mock(write_debug_out=Mock()),
|
"DebugManager": Mock(write_debug_out=Mock()),
|
||||||
|
"InputManager": Mock(get_last_input_time=Mock(return_value=0)),
|
||||||
"ScreenManager": manager,
|
"ScreenManager": manager,
|
||||||
"SettingsManager": Mock(get_setting_as_bool=Mock(return_value=False)),
|
"SettingsManager": Mock(get_setting_as_bool=Mock(return_value=False)),
|
||||||
},
|
},
|
||||||
@@ -61,3 +63,38 @@ def test_prompt_repaint_during_typing_keeps_only_typed_delta():
|
|||||||
|
|
||||||
assert env["screen"]["new_delta"] == "h"
|
assert env["screen"]["new_delta"] == "h"
|
||||||
assert env["screen"]["new_delta_is_typing"] is True
|
assert env["screen"]["new_delta_is_typing"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_tui_input_line_append_is_typing_delta():
|
||||||
|
manager, env = _build_screen_manager(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"<UserA> hi".ljust(20),
|
||||||
|
"[Username] ".ljust(20),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
{"x": 11, "y": 1},
|
||||||
|
)
|
||||||
|
env["runtime"]["InputManager"].get_last_input_time.return_value = time.time()
|
||||||
|
|
||||||
|
manager.update(
|
||||||
|
{
|
||||||
|
"bytes": b"",
|
||||||
|
"lines": 2,
|
||||||
|
"columns": 20,
|
||||||
|
"textCursor": {"x": 12, "y": 1},
|
||||||
|
"screen": "pty",
|
||||||
|
"text": "\n".join(
|
||||||
|
[
|
||||||
|
"<UserA> hi".ljust(20),
|
||||||
|
"[Username] l".ljust(20),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"attributes": [],
|
||||||
|
},
|
||||||
|
"onScreenUpdate",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert env["screen"]["new_delta"] == "l"
|
||||||
|
assert env["screen"]["new_delta_is_typing"] is True
|
||||||
|
|||||||
Reference in New Issue
Block a user