def __init__( self, text, mark_sequence, text_plane=None, context=None, starting_point=None ): """ Args: text (Sequence): the stream of characters to be rendered - it can be a string or a list of 1-grapheme strings. mark_sequence (Mapping): A mappign with Mark objects. The keys either represent index positions on the text where the mark will be processed, or they can be at the special index "config" denoting marks that are to have their indexes processed according to other enviroment circunstances (like the current "tick" - and possibly 'current position') The value at each item can contain a single Mark or a of Markers. text_plane (terminedia.text.planes.TextPlane): area where the output is to be rendered on iterating. The Text object will be searched for aditional "Mark" objects that will compose the syle and position when encountered (they are less prioritary than the Marks passed in mark_sequence) If no Text object is given, the instance may still be iterated to retrieve a sequence of char, context and position - for example, when generating output directly to a tty. context (terminedia.Context): parent context. By default the context attached to the given text_plane is used starting_point: first position to be yielded when iteration starts (from which rules apply according to context.direction and others given by the matched "Mark" objects. Defaults to (0, 0) Helper class to render text that will both hold embedded style information, conveyed in "Mark" objects (with information like "at position 10, push foreground color 'red'"), and respect Mark objects embedded in the "text_plane" associanted rendering space. Style changes are all on top of a given "parent context" if any (otherwise, the text_plane context is used, or None) The rendering part include yielding the proper position of each rendering character,as contexts convey also text printing direction and marks can not only push a new printing direction, but also "teleport" the rendering point for the next character altogether. """ self.text = text self.mark_sequence = mark_sequence self.parent_context = context self._last_index_processed = None self.context = Context() self.text_plane = text_plane self.starting_point = V2(starting_point) if starting_point else V2(0, 0) self.current_position = self.starting_point self._sanity_counter = 0 self.locals = threading.local() if isinstance(text, GraphemeIter): self.cooked_text = text else: new_text = self.cooked_text = GraphemeIter(text) # adjust mark items to match graphemes instead of characters: sorted_old_keys = sorted(key for key in mark_sequence.keys() if isinstance(key, int)) new_keys = {old_key: new_key for old_key, new_key in zip( sorted_old_keys, new_text.iter_cooked_indexes(sorted_old_keys) )} self.mark_sequence = {new_keys.get(old_key, old_key): value for old_key, value in mark_sequence.items()}
def __init__(self, size=(), clear_screen=True, backend="ansi"): if not size: #: Set in runtime to a method to retrieve the screen width, height. #: The class is **not** aware of terminal resizings while running, though. self.get_size = lambda: V2(os.get_terminal_size()) try: size = self.get_size() except OSError as error: if error.errno == 25: logger.error( "This terminal type does not allow guessing screen size." "Pass an explicit (cols, rows) size when instantiating {self.__class__}" ) raise else: self.get_size = lambda: V2(size) #: Namespace to configure drawing and printing color and other parameters. #: Currently, the attributes that are used from here are #: ``color``, ``background``, ``direction``, ``effects`` and ``char``. self.context = Context() #: Namespace for drawing methods, containing an instance of the :any:`Drawing` class self.draw = Drawing(self.set_at, self.reset_at, self.get_size, self.context) self.width, self.height = self.size = size #: Namespace to allow high-resolution drawing using a :any:`HighRes` instance #: One should either use the public methods in HighRes or the methods on the #: :any:`Drawing` instance at ``Screen.high.draw`` to do 1/4 block pixel #: manipulation. self.high = HighRes(self) self.braille = HighRes(self, block_class=BrailleChars, block_width=2, block_height=4) self.square = HighRes(self, block_class=HalfChars, block_width=1, block_height=2) self.sextant = HighRes(self, block_class=SextantChars, block_width=2, block_height=3) self.text = terminedia.text.TextPlane(self) self.backend = backend = backend.upper() if backend == "ANSI": from terminedia.terminal import JournalingScreenCommands as CommandsClass elif backend == "HTML": from terminedia.html import JournalingHTMLCommands as CommandsClass else: raise ValueError(f"Unrecognized backend: {backend!r}.") #: Namespace for low-level rendering commands, an instance of :any:`JournalingCommandsMixin`. #: This attribute can be used as a context manager to group #: various output operations in a single block that is rendered at once. self.commands = CommandsClass() self.clear_screen = clear_screen self.data = FullShape.new((self.width, self.height)) # Synchronize context for data and screen painting. self.data.context = self.context from terminedia import context self.root_context = context self._last_setitem = 0
def _prepare_context(self): self.context = Context() source = self.text_plane.owner.context self._parent_context_data = {key:value for key, value in source} self._reset_context()
def context(self): return Context()