Skip to content

Commit

Permalink
Add: ByteScreen
Browse files Browse the repository at this point in the history
  • Loading branch information
eight04 committed Feb 28, 2024
1 parent eac6000 commit 08a46e7
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ dist/
*.egg-info/
.eggs/
.pytest_cache/
.venv/
2 changes: 1 addition & 1 deletion pyte/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import io
from typing import Union

from .screens import Screen, DiffScreen, HistoryScreen, DebugScreen
from .screens import Screen, DiffScreen, HistoryScreen, DebugScreen, ByteScreen
from .streams import Stream, ByteStream


Expand Down
46 changes: 40 additions & 6 deletions pyte/screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
)
from .streams import Stream

wcwidth: Callable[[str], int] = lru_cache(maxsize=4096)(_wcwidth)

KT = TypeVar("KT")
VT = TypeVar("VT")

Expand Down Expand Up @@ -135,7 +133,7 @@ def __missing__(self, key: KT) -> VT:


_DEFAULT_MODE = set([mo.DECAWM, mo.DECTCEM])

_DEFAULT_WCWIDTH: Callable[[str], int] = lru_cache(maxsize=4096)(_wcwidth)

class Screen:
"""
Expand Down Expand Up @@ -222,6 +220,7 @@ def __init__(self, columns: int, lines: int) -> None:
self.reset()
self.mode = _DEFAULT_MODE.copy()
self.margins: Optional[Margins] = None
self.wcwidth = _DEFAULT_WCWIDTH

def __repr__(self) -> str:
return ("{0}({1}, {2})".format(self.__class__.__name__,
Expand All @@ -237,8 +236,8 @@ def render(line: StaticDefaultDict[int, Char]) -> Generator[str, None, None]:
is_wide_char = False
continue
char = line[x].data
assert sum(map(wcwidth, char[1:])) == 0
is_wide_char = wcwidth(char[0]) == 2
assert sum(map(self.wcwidth, char[1:])) == 0
is_wide_char = self.wcwidth(char[0]) == 2
yield char

return ["".join(render(self.buffer[y])) for y in range(self.lines)]
Expand Down Expand Up @@ -479,7 +478,7 @@ def draw(self, data: str) -> None:
self.g1_charset if self.charset else self.g0_charset)

for char in data:
char_width = wcwidth(char)
char_width = self.wcwidth(char)

# If this was the last column in a line and auto wrap mode is
# enabled, move the cursor to the beginning of the next line,
Expand Down Expand Up @@ -1337,3 +1336,38 @@ def __getattribute__(self, attr: str) -> Callable[..., None]:
return self.only_wrapper(attr)
else:
return lambda *args, **kwargs: None

def byte_screen_wcwidth(text: str):
# FIXME: should we always return 1?
n = _DEFAULT_WCWIDTH(text)
if n <= 0 and text <= "\xff":
return 1
return n

class ByteScreen(Screen):
"""A screen that draws bytes and stores byte-string in the buffer, including un-printable/zero-length chars."""
def __init__(self, *args, encoding: str | None=None, **kwargs):
"""
:param encoding: The encoding of the screen. If set, the byte-string will be decoded when calling :meth:`ByteScreen.display`.
"""
super().__init__(*args, **kwargs)
self.encoding = encoding
self.wcwidth = byte_screen_wcwidth

def draw(self, data: str | bytes):
if isinstance(data, bytes):
data = data.decode("latin-1")
return super().draw(data)

@property
def display(self) -> List[str]:
if not self.encoding:
return super().display

def render(line: StaticDefaultDict[int, Char]) -> Generator[str, None, None]:
for x in range(self.columns):
char = line[x].data
yield char

return ["".join(render(self.buffer[y])).encode("latin-1").decode(self.encoding) for y in range(self.lines)]

10 changes: 10 additions & 0 deletions tests/test_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1583,3 +1583,13 @@ def test_screen_set_icon_name_title():

screen.set_title(text)
assert screen.title == text


def test_byte_screen() -> None:
screen = pyte.ByteScreen(10, 1, encoding="big5")

text = "限".encode("big5")
screen.draw(text)
assert screen.display[0].strip() == "限"
assert screen.buffer[0][0].data == "\xad"

0 comments on commit 08a46e7

Please sign in to comment.