<commit_before># -*- coding: utf-8 -*- 
import logging

from curtsies.fmtfuncs import bold
from curtsies.fsarray import fsarray
from curtsies.bpythonparse import func_for_letter
from curtsies.fmtstr import fmtstr, linesplit

from bpython._py3compat import py3
if not py3:
    import inspect

# All paint functions should
# * return an array of the width they were asked for
# * return an array not taller than the height they were asked for

def display_linize(msg, columns):
    """Returns lines obtained by splitting msg over multiple lines.

    Warning: if msg is empty, returns an empty list of lines"""
    display_lines = ([msg[start:end]
                        for start, end in zip(
                            range(0, len(msg), columns),
                            range(columns, len(msg)+columns, columns))]
                    if msg else [])
    return display_lines

def paint_history(rows, columns, display_lines):
    lines = []
    for r, line in zip(range(rows), display_lines[-rows:]):
        lines.append(fmtstr(line))
    r = fsarray(lines, width=columns)
    assert r.shape[0] <= rows, repr(r.shape)+' '+repr(rows)
    assert r.shape[1] <= columns, repr(r.shape)+' '+repr(columns)
    return r

def paint_current_line(rows, columns, current_display_line):
    lines = display_linize(current_display_line, columns)
    return fsarray(lines, width=columns)

def matches_lines(rows, columns, matches, current, config):
    highlight_color = func_for_letter(config.color_scheme['operator'].lower())
    #TODO ...that's not really what operator is for
    if not matches:
        return []
    color = func_for_letter(config.color_scheme['main'])
    max_match_width = max(len(m) for m in matches)
    words_wide = max(1, (columns - 1) // (max_match_width + 1))
    matches_lines = [fmtstr(' ').join(color(m.ljust(max_match_width))
                                        if m != current
                                        else highlight_color(m.ljust(max_match_width))
                                      for m in matches[i:i+words_wide])
                     for i in range(0, len(matches), words_wide)]
    logging.debug('match: %r' % current)
    logging.debug('matches_lines: %r' % matches_lines)
    return matches_lines

def formatted_argspec(argspec, columns, config):
    # Pretty directly taken from bpython.cli
    is_bound_method = argspec[2]
    func = argspec[0]
    args = argspec[1][0]
    kwargs = argspec[1][3]
    _args = argspec[1][1] #*args
    _kwargs = argspec[1][2] #**kwargs
    is_bound_method = argspec[2]
    in_arg = argspec[3]
    if py3:<commit_msg>fix attribute access completion<commit_after># -*- coding: utf-8 -*- 
import logging
import os

from curtsies.fmtfuncs import bold
from curtsies.fsarray import fsarray
from curtsies.bpythonparse import func_for_letter
from curtsies.fmtstr import fmtstr, linesplit

from bpython._py3compat import py3
if not py3:
    import inspect

# All paint functions should
# * return an array of the width they were asked for
# * return an array not taller than the height they were asked for

def display_linize(msg, columns):
    """Returns lines obtained by splitting msg over multiple lines.

    Warning: if msg is empty, returns an empty list of lines"""
    display_lines = ([msg[start:end]
                        for start, end in zip(
                            range(0, len(msg), columns),
                            range(columns, len(msg)+columns, columns))]
                    if msg else [])
    return display_lines

def paint_history(rows, columns, display_lines):
    lines = []
    for r, line in zip(range(rows), display_lines[-rows:]):
        lines.append(fmtstr(line))
    r = fsarray(lines, width=columns)
    assert r.shape[0] <= rows, repr(r.shape)+' '+repr(rows)
    assert r.shape[1] <= columns, repr(r.shape)+' '+repr(columns)
    return r

def paint_current_line(rows, columns, current_display_line):
    lines = display_linize(current_display_line, columns)
    return fsarray(lines, width=columns)

def matches_lines(rows, columns, matches, current, config):
    highlight_color = func_for_letter(config.color_scheme['operator'].lower())
    #TODO ...that's not really what operator is for

    if not matches:
        return []
    color = func_for_letter(config.color_scheme['main'])
    max_match_width = max(len(m) for m in matches)
    words_wide = max(1, (columns - 1) // (max_match_width + 1))
    if os.path.sep in matches[0]: # filename completion
        pass
    elif '.' in matches[0]:
        matches = [m.rstrip('.').rsplit('.')[-1] for m in matches]
        if current:
            current = current.rstrip('.').rsplit('.')[-1]
    else:
        pass

    matches_lines = [fmtstr(' ').join(color(m.ljust(max_match_width))
                                        if m != current
                                        else highlight_color(m.ljust(max_match_width))
                                      for m in matches[i:i+words_wide])
                     for i in range(0, len(matches), words_wide)]

    logging.debug('match: %r' % current)
    logging.debug('matches_lines: %r' % matches_lines)
    return matches_lines

def formatted_argspec(argspec, columns, config):
    # Pretty directly taken from bpython.cli
    is_bound_method = argspec[2]
    func = argspec[0]
    args = argspec[1][0]
    kwargs = argspec[1][3]
    _args = argspec[1][1] #*args
    _kwargs = argspec[1][2] #**kwargs
    is_bound_method = argspec[2]
    in_arg = argspec[3]
    if py3:
{'fraction_non_alphanumeric': 0.11030478955007257, 'fraction_numerical': 0.009433962264150943, 'mean_word_length': 2.725, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2219445', 'n_tokens_mistral': 1677, 'n_tokens_neox': 1641, 'n_words': 474}