<commit_before>"""NCurses application class."""

from operator import attrgetter

from eaf.app import Application
from eaf.render import Renderer

import xoinvader.curses_utils

from xoinvader.common import Settings
from xoinvader.utils import Point


INVISIBLE_SYMBOLS = " "
"""Symbols that renderer must not render on the screen."""


class CursesRenderer(Renderer):
    """Curses renderer."""

    def __init__(self, screen):
        super().__init__(screen)

    def clear(self):
        self.screen.erase()
        self.screen.border(0)

    def render_objects(self, objects):
        """Render all renderable objects."""

        border = Point(*self.screen.getmaxyx()[::-1])
    
        # TODO: Move sorting to some kind of object manager
        # Must be sorted on adding objects
        for obj in sorted(objects, key=attrgetter("render_priority")):
            gpos_list, data_gen = obj.get_render_data()
    
            for data in data_gen:
                for gpos in gpos_list:
                    lpos, image, style = data
                    cpos = (gpos + lpos)[int]
    
                    if (
                        (cpos.x >= border.x - 1 or cpos.y >= border.y - 1) or
                        (cpos.x <= 0 or cpos.y <= 0)
                    ) and not obj.draw_on_border:
                        obj.remove_obsolete(gpos)
                        continue
    
                    if image in INVISIBLE_SYMBOLS:
                        continue
    
                    if style:
                        self.screen.addstr(
                            cpos.y, cpos.x,
                            image, style)
                    else:
                        self.screen.addstr(cpos.y, cpos.x, image)

    def present(self):
        self.screen.refresh()

    def get_width(self):
        return self.screen.getmaxyx()[0]

    def get_height(self):
        return self.screen.getmaxyx()[1]


class CursesApplication(Application):
    """Curses-powered application class."""

    def __init__(self):
        window = xoinvader.curses_utils.create_window(
            ncols=Settings.layout.field.border.x,
            nlines=Settings.layout.field.border.y)
        renderer = CursesRenderer(window)

        super().__init__(renderer, window)

        self._clock = xoinvader.curses_utils.get_clock()

    def set_caption(self, caption: str, icontitle: str = ""):
        """Set window caption.

        :param caption: window caption
        :param icontitle: short title
        """

        # FIXME: Maybe we can update text via terminal API
        pass

    def stop(self):
        self._ioloop.add_callback(
            lambda: xoinvader.curses_utils.deinit_curses(self.renderer.screen))
        super().stop()
<commit_msg>application: add default palette and getter<commit_after>"""NCurses application class."""

from operator import attrgetter

from eaf.app import Application
from eaf.render import Renderer

import xoinvader.curses_utils

from xoinvader.common import Settings
from xoinvader.curses_utils import Palette
from xoinvader.utils import Point


INVISIBLE_SYMBOLS = " "
"""Symbols that renderer must not render on the screen."""


class CursesRenderer(Renderer):
    """Curses renderer."""

    def __init__(self, screen):
        super().__init__(screen)

    def clear(self):
        self.screen.erase()
        self.screen.border(0)

    def render_objects(self, objects):
        """Render all renderable objects."""

        border = Point(*self.screen.getmaxyx()[::-1])
    
        # TODO: Move sorting to some kind of object manager
        # Must be sorted on adding objects
        for obj in sorted(objects, key=attrgetter("render_priority")):
            gpos_list, data_gen = obj.get_render_data()
    
            for data in data_gen:
                for gpos in gpos_list:
                    lpos, image, style = data
                    cpos = (gpos + lpos)[int]

                    if (
                        (cpos.x >= border.x - 1 or cpos.y >= border.y - 1) or
                        (cpos.x <= 0 or cpos.y <= 0)
                    ) and not obj.draw_on_border:
                        obj.remove_obsolete(gpos)
                        continue
    
                    if image in INVISIBLE_SYMBOLS:
                        continue
    
                    if style:
                        self.screen.addstr(
                            cpos.y, cpos.x,
                            image, style)
                    else:
                        self.screen.addstr(cpos.y, cpos.x, image)

    def present(self):
        self.screen.refresh()

    def get_width(self):
        return self.screen.getmaxyx()[0]

    def get_height(self):
        return self.screen.getmaxyx()[1]


class CursesApplication(Application):
    """Curses-powered application class."""

    def __init__(self):
        window = xoinvader.curses_utils.create_window(
            ncols=Settings.layout.field.border.x,
            nlines=Settings.layout.field.border.y)
        renderer = CursesRenderer(window)

        super().__init__(renderer, window)

        self._clock = xoinvader.curses_utils.get_clock()
        self._palette = Palette()

    def set_caption(self, caption: str, icontitle: str = ""):
        """Set window caption.

        :param caption: window caption
        :param icontitle: short title
        """

        # FIXME: Maybe we can update text via terminal API
        pass

    def stop(self):
        self._ioloop.add_callback(
            lambda: xoinvader.curses_utils.deinit_curses(self.renderer.screen))
        super().stop()

    @property
    def palette(self) -> Palette:
        """Palette getter."""

        return self._palette

    @palette.setter
    def palette(self, palette: Palette):
        """Palette setter."""

        if not isinstance(palette, Palette):
            raise TypeError(f"Expected Palette class, got {type(palette)}")

        self.palette = palette

{'fraction_non_alphanumeric': 0.09741784037558686, 'fraction_numerical': 0.0026827632461435278, 'mean_word_length': 1.809703250117758, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1350084', 'n_tokens_mistral': 1752, 'n_tokens_neox': 1654, 'n_words': 418}