mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Translate "escape" to "^" when XTermParser has to backtrack
This commit is contained in:
@@ -1,18 +1,19 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
import re
|
||||
from typing import Any, Callable, Generator, Iterable
|
||||
|
||||
from . import messages
|
||||
from . import events
|
||||
from ._types import MessageTarget
|
||||
from ._parser import Awaitable, Parser, TokenCallback
|
||||
from . import messages
|
||||
from ._ansi_sequences import ANSI_SEQUENCES_KEYS
|
||||
from ._parser import Awaitable, Parser, TokenCallback
|
||||
from ._types import MessageTarget
|
||||
|
||||
# When trying to determine whether the current sequence is a supported/valid
|
||||
# escape sequence, at which length should we give up and consider our search
|
||||
# to be unsuccessful?
|
||||
from .keys import Keys
|
||||
|
||||
_MAX_SEQUENCE_SEARCH_THRESHOLD = 20
|
||||
|
||||
_re_mouse_event = re.compile("^" + re.escape("\x1b[") + r"(<?[\d;]+[mM]|M...)\Z")
|
||||
@@ -24,7 +25,6 @@ _re_bracketed_paste_end = re.compile(r"^\x1b\[201~$")
|
||||
|
||||
|
||||
class XTermParser(Parser[events.Event]):
|
||||
|
||||
_re_sgr_mouse = re.compile(r"\x1b\[<(\d+);(\d+);(\d+)([Mm])")
|
||||
|
||||
def __init__(
|
||||
@@ -144,12 +144,11 @@ class XTermParser(Parser[events.Event]):
|
||||
or len(sequence) > _MAX_SEQUENCE_SEARCH_THRESHOLD
|
||||
):
|
||||
for character in sequence:
|
||||
keys = get_key_ansi_sequence(character, None)
|
||||
if keys is not None:
|
||||
for key in keys:
|
||||
on_token(events.Key(self.sender, key=key))
|
||||
else:
|
||||
on_token(events.Key(self.sender, key=character))
|
||||
key_events = self._sequence_to_key_events(character)
|
||||
for event in key_events:
|
||||
if event.key == "escape":
|
||||
event = events.Key(event.sender, key="^")
|
||||
on_token(event)
|
||||
break
|
||||
|
||||
sequence_character = yield read1()
|
||||
@@ -171,10 +170,10 @@ class XTermParser(Parser[events.Event]):
|
||||
|
||||
if not bracketed_paste:
|
||||
# Was it a pressed key event that we received?
|
||||
keys = get_key_ansi_sequence(sequence, None)
|
||||
if keys is not None:
|
||||
for key in keys:
|
||||
on_token(events.Key(self.sender, key=key))
|
||||
key_events = list(self._sequence_to_key_events(sequence))
|
||||
for event in key_events:
|
||||
on_token(event)
|
||||
if key_events:
|
||||
break
|
||||
# Or a mouse event?
|
||||
mouse_match = _re_mouse_event.match(sequence)
|
||||
@@ -201,9 +200,11 @@ class XTermParser(Parser[events.Event]):
|
||||
break
|
||||
else:
|
||||
if not bracketed_paste:
|
||||
keys = get_key_ansi_sequence(character, None)
|
||||
if keys is not None:
|
||||
for key in keys:
|
||||
on_token(events.Key(self.sender, key=key))
|
||||
else:
|
||||
on_token(events.Key(self.sender, key=character))
|
||||
for event in self._sequence_to_key_events(character):
|
||||
on_token(event)
|
||||
|
||||
def _sequence_to_key_events(self, sequence: str) -> Iterable[events.Key]:
|
||||
default = (sequence,) if len(sequence) == 1 else ()
|
||||
keys = ANSI_SEQUENCES_KEYS.get(sequence, default)
|
||||
for key in keys:
|
||||
yield events.Key(self.sender, key)
|
||||
|
||||
@@ -67,8 +67,8 @@ def test_cant_match_escape_sequence_too_long(parser):
|
||||
assert len(events) == len(sequence)
|
||||
assert all(isinstance(event, Key) for event in events)
|
||||
|
||||
# '\x1b' is translated to 'escape'
|
||||
assert events[0].key == "escape"
|
||||
# When we backtrack '\x1b' is translated to '^'
|
||||
assert events[0].key == "^"
|
||||
|
||||
# The rest of the characters correspond to the expected key presses
|
||||
events = events[1:]
|
||||
@@ -87,7 +87,7 @@ def test_unknown_sequence_followed_by_known_sequence(parser):
|
||||
sequence = unknown_sequence + known_sequence
|
||||
events = parser.feed(sequence)
|
||||
|
||||
assert next(events).key == "escape"
|
||||
assert next(events).key == "^"
|
||||
assert next(events).key == "["
|
||||
assert next(events).key == "?"
|
||||
assert next(events).key == "end"
|
||||
|
||||
Reference in New Issue
Block a user