<commit_before>import abc
import typing

import urwid
from urwid.text_layout import calc_coords

import mitmproxy.command
import mitmproxy.flow
import mitmproxy.master
import mitmproxy.types


class Completer:
    @abc.abstractmethod
    def cycle(self, forward: bool = True) -> str:
        raise NotImplementedError()


class ListCompleter(Completer):
    def __init__(
            self,
            start: str,
            options: typing.Sequence[str],
    ) -> None:
        self.start = start
        self.options: typing.List[str] = []
        for o in options:
            if o.startswith(start):
                self.options.append(o)
        self.options.sort()
        self.offset = 0

    def cycle(self, forward: bool = True) -> str:
        if not self.options:
            return self.start
        ret = self.options[self.offset]
        delta = 1 if forward else -1
        self.offset = (self.offset + delta) % len(self.options)
        return ret


class CompletionState(typing.NamedTuple):
    completer: Completer
    parsed: typing.Sequence[mitmproxy.command.ParseResult]


class CommandBuffer:
    def __init__(self, master: mitmproxy.master.Master, start: str = "") -> None:
        self.master = master
        self.text = start
        # Cursor is always within the range [0:len(buffer)].
        self._cursor = len(self.text)
        self.completion: typing.Optional[CompletionState] = None

    @property
    def cursor(self) -> int:
        return self._cursor

    @cursor.setter
    def cursor(self, x) -> None:
        if x < 0:
            self._cursor = 0
        elif x > len(self.text):
            self._cursor = len(self.text)
        else:
            self._cursor = x<commit_msg>List was not cycled right for tab autocompletion<commit_after>import abc
import typing

import urwid
from urwid.text_layout import calc_coords

import mitmproxy.command
import mitmproxy.flow
import mitmproxy.master
import mitmproxy.types


class Completer:
    @abc.abstractmethod
    def cycle(self, forward: bool = True) -> str:
        raise NotImplementedError()


class ListCompleter(Completer):
    def __init__(
            self,
            start: str,
            options: typing.Sequence[str],
    ) -> None:
        self.start = start
        self.options: typing.List[str] = []
        for o in options:
            if o.startswith(start):
                self.options.append(o)
        self.options.sort()
        self.pos = None

    def cycle(self, forward: bool = True) -> str:
        if not self.options:
            return self.start
        if self.pos is None:
            self.pos = 0 if forward else len(self.options) - 1
        else:
            delta = 1 if forward else -1
            self.pos = (self.pos + delta) % len(self.options)
        return self.options[self.pos]


class CompletionState(typing.NamedTuple):
    completer: Completer
    parsed: typing.Sequence[mitmproxy.command.ParseResult]


class CommandBuffer:
    def __init__(self, master: mitmproxy.master.Master, start: str = "") -> None:
        self.master = master
        self.text = start
        # Cursor is always within the range [0:len(buffer)].
        self._cursor = len(self.text)
        self.completion: typing.Optional[CompletionState] = None

    @property
    def cursor(self) -> int:
        return self._cursor

    @cursor.setter
    def cursor(self, x) -> None:
        if x < 0:
            self._cursor = 0
        elif x > len(self.text):
            self._cursor = len(self.text)
        else:
            self._cursor = x
{'fraction_non_alphanumeric': 0.09775280898876404, 'fraction_numerical': 0.003651685393258427, 'mean_word_length': 2.120946538124452, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, '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': '405935', 'n_tokens_mistral': 1062, 'n_tokens_neox': 1034, 'n_words': 282}