<commit_before>import curses
import locale

# hack to get curses+unicode working
locale.setlocale(locale.LC_ALL, '')

################################################################################
# constants

ELLIPSE = u'\u2026'

# attributes
# why not bits? better tooling around strings
ATTRIBUTES = {
    'B': curses.A_BOLD,
    'S': curses.A_STANDOUT,
    'U': curses.A_UNDERLINE,
    'R': curses.A_REVERSE,  # reverse the colors
}

class Exit(Exception):
    pass

################################################################################
# utilities

def log(stuff):
    f = open('log', 'a')
    print >>f, stuff

################################################################################
# class hierarchy

class Application(object):
    current_window = None
    windows = {}
    modals = {}

    screen = None
    window = None

    colors = [('black', 'white')]

    def run(self):
        curses.wrapper(self.run_curses)

    def run_curses(self, screen):
        # init some curses geometry
        self.screen = screen

        # set up curses colors
        curses.use_default_colors()
        curses.curs_set(0)
        assert len(self.colors) <= 4, 'Too many colors defined'
        assert len(self.colors) > 0, 'Not enough colors defined'
        for i,c in enumerate(self.colors):
            background = getattr(curses, 'COLOR_' + c[0].upper())
            foreground = getattr(curses, 'COLOR_' + c[1].upper())
            curses.init_pair(i, background, foreground)

        # wait for a character for only 0.1s
        curses.halfdelay(1)

        # use the first window as the default window
        self.current_window = self.windows['default']
        self.render()

        while 1:
            input_value = screen.getch()
            # handle non-character input
            try:
                key = chr(input_value)
            except ValueError:
                key = input_value
            # pass the character input to the event loop
            try:
                self.handle(key)
            except Exit:
                return

    def get_size(self):
        return self.screen.getmaxyx()[1], self.screen.getmaxyx()[0]

    def render(self):
        self.screen.clear()
        size = self.get_size()
        w,h = size
        rlines, rstyles = self.current_window.render(size)
        for i,res in enumerate(zip(rlines, rstyles)):
            line, styles = res
            # convert to a unified representation
            style_chars = ['' for j in range(w)]
            for style, start, end in styles:
                for j in range(start, end):
                    style_chars[j] += style
            # convert back to ranges
            style_ranges = []
            current = None
            current_start = None
            for j,s in enumerate(style_chars):
                if s != current:
                    if current_start is not None:
                        style_ranges.append((current, current_start, j))
                    current_start = j
                    current = s
            style_ranges.append((current, current_start, j+1))
            # output the strings with the right styles
            for style, start, end in style_ranges:
                style_attr = 0
                for char in style:
                    style_attr |= ATTRIBUTES.get(char)
                # catch scrolling-past the end of the screen error
                try:
                    self.screen.addstr(i, start,
                                       line[start:end].encode('utf8'),
                                       style_attr)
                except curses.error as e:
                    if i < h - 1 and end == w:
                        raise e
        self.screen.refresh()

    def handle(self, key):
        # see if the application needs to run it's own handler
        signal = self.current_window.handle(key)
        if signal is None:
            # default behavior is to just quit
            if key == 'q':
                raise Exit<commit_msg>Add redraw on window resize<commit_after>import curses
import locale

# hack to get curses+unicode working
locale.setlocale(locale.LC_ALL, '')

################################################################################
# constants

ELLIPSE = u'\u2026'

# attributes
# why not bits? better tooling around strings
ATTRIBUTES = {
    'B': curses.A_BOLD,
    'S': curses.A_STANDOUT,
    'U': curses.A_UNDERLINE,
    'R': curses.A_REVERSE,  # reverse the colors
}

class Exit(Exception):
    pass

################################################################################
# utilities

def log(stuff):
    f = open('log', 'a')
    print >>f, stuff

################################################################################
# class hierarchy

class Application(object):
    current_window = None
    windows = {}
    modals = {}

    screen = None
    window = None

    colors = [('black', 'white')]

    def run(self):
        curses.wrapper(self.run_curses)

    def run_curses(self, screen):
        # init some curses geometry
        self.screen = screen

        # set up curses colors
        curses.use_default_colors()
        curses.curs_set(0)
        assert len(self.colors) <= 4, 'Too many colors defined'
        assert len(self.colors) > 0, 'Not enough colors defined'
        for i,c in enumerate(self.colors):
            background = getattr(curses, 'COLOR_' + c[0].upper())
            foreground = getattr(curses, 'COLOR_' + c[1].upper())
            curses.init_pair(i, background, foreground)

        # wait for a character for only 0.1s
        curses.halfdelay(1)

        # use the first window as the default window
        self.current_window = self.windows['default']
        self.render()

        while 1:
            input_value = screen.getch()
            # handle non-character input
            try:
                key = chr(input_value)
            except ValueError:
                key = input_value
            # pass the character input to the event loop
            try:
                self.handle(key)
            except Exit:
                return

    def get_size(self):
        return self.screen.getmaxyx()[1], self.screen.getmaxyx()[0]

    def render(self):
        self.screen.clear()
        size = self.get_size()
        w,h = size
        rlines, rstyles = self.current_window.render(size)
        for i,res in enumerate(zip(rlines, rstyles)):
            line, styles = res
            # convert to a unified representation
            style_chars = ['' for j in range(w)]
            for style, start, end in styles:
                for j in range(start, end):
                    style_chars[j] += style
            # convert back to ranges
            style_ranges = []
            current = None
            current_start = None
            for j,s in enumerate(style_chars):
                if s != current:
                    if current_start is not None:
                        style_ranges.append((current, current_start, j))
                    current_start = j
                    current = s
            style_ranges.append((current, current_start, j+1))
            # output the strings with the right styles
            for style, start, end in style_ranges:
                style_attr = 0
                for char in style:
                    style_attr |= ATTRIBUTES.get(char)
                # catch scrolling-past the end of the screen error
                try:
                    self.screen.addstr(i, start,
                                       line[start:end].encode('utf8'),
                                       style_attr)
                except curses.error as e:
                    if i < h - 1 and end == w:
                        raise e
        self.screen.refresh()

    def handle(self, key):
        # see if the application needs to run it's own handler
        signal = self.current_window.handle(key)
        if signal is None:
            # default behavior is to just quit
            if key == 'q':
                raise Exit
            elif key == curses.KEY_RESIZE:
                self.render()
{'fraction_non_alphanumeric': 0.14366335418966997, 'fraction_numerical': 0.004662004662004662, 'mean_word_length': 1.7503373819163293, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '147269', 'n_tokens_mistral': 2217, 'n_tokens_neox': 2086, 'n_words': 623}