Source code for thurible.log

"""
log
~~~

An object for displaying a history of updating messages, such as a
log.
"""
from collections import deque
from dataclasses import dataclass
from typing import Optional, Sequence

from thurible.panel import Content, Message, Title


# Available update message.
[docs] @dataclass class Update(Message): """Create a new :class:`thurible.log.Update` object. This object is a command message used to instruct the currently displayed :class:`thurible.Log` to add the text given in the message. :param text: The message to add to the panel. :return: An :class:`thurible.Update` object. :rtype: thurible.Update :usage: To create a new :class:`thurible.Update` object: .. testcode:: import thurible update = thurible.Update('spam') """ text: str
# Class.
[docs] class Log(Content, Title): """Create a new :class:`thurible.Log` object. This class displays messages from the application in "last in first out" (LIFO) format. It's intended for situations were you want to provide the user a rolling display of status messages. As a subclass of :class:`thurible.panel.Content` and :class:`thurible.panel.Title`, it can also take those parameters and has those public methods and properties. :param content: (Optional.) A sequence of strings to display in the panel when it is first displayed in the terminal. The first item in the sequence is considered the most recent. :param maxlen: (Optional.) The total number of entries the :class:`thurible.Log` will store. This is used to allow the terminal window to be resized without causing the loss of any messages. It's not intended for the user to be able to scroll to view messages that have rolled off the terminal. :return: A :class:`Log` object. :rtype: thurible.Log :usage: To create a new :class:`thurible.Log` object: .. testcode:: import thurible dialog = thurible.Log() To create a new :class:`thurible.Log` object that will show a maximum of three messages at a time and starts with a welcome message: .. testsetup:: log import thurible log = thurible.Log(['Welcome!',], maxlen=3) .. testcode:: log log = thurible.Log(['Welcome!',], maxlen=3) To update the messages in a log use a :class:`thurible.Update` message: .. testcode:: log update = thurible.Update('spam') log.update(update) Information on the sizing of :class:`thurible.Log` objects can be found in the :ref:`sizing` section below. """ def __init__( self, content: Optional[Sequence[str]] = None, maxlen: int = 50, *args, **kwargs ) -> None: super().__init__(*args, **kwargs) self.maxlen = maxlen if content is None: content = deque(maxlen=self.maxlen) elif not isinstance(content, deque): d: deque[str] = deque(maxlen=self.maxlen) for item in content: d.appendleft(item) content = d self.content = content self._wrapped_width = -1 def __str__(self) -> str: """Return a string that will draw the entire panel.""" # Set up. inner_height = self.inner_height y = self.inner_y x = self.inner_x result = super().__str__() # Write the contents of the log. result += self._visible( self.lines, self.inner_height, self.inner_x, self.inner_y ) return result # Properties. @property def lines(self) -> list[str]: """The lines of text available to be displayed in the panel after they have been wrapped to fit the width of the interior of the panel. A message from the application may be split into multiple lines. :return: A :class:`list` object containing each line of text as a :class:`str`. :rtype: list """ width = self.inner_width if width != self._wrapped_width: wrapped = [] for line in self.content: wrapped.extend(self.term.wrap(line, width=width)) self._lines = wrapped self._wrapped_width = width return self._lines # Public methods.
[docs] def update(self, msg: Message) -> str: result = super().update(msg) if isinstance(msg, Update): self.content.appendleft(msg.text) self._wrapped_width = -1 result += self.clear_contents() result += self._visible( self.lines, self.inner_height, self.inner_x, self.inner_y ) return result
# Private helper methods. def _visible( self, lines: Sequence[str], height: int, x: int, y: int ) -> str: result = '' for line in lines[:height]: result += self._move_cursor(y, x) + line y += 1 return result