Esempio n. 1
0
def main():
    stream = InputStream(callback)

    with raw_mode(sys.stdin.fileno()):
        while True:
            c = sys.stdin.read(1)
            stream.feed(c)
    def setUp(self):
        class _ProcessorMock(object):
            def __init__(self):
                self.keys = []

            def feed_key(self, key_press):
                self.keys.append(key_press)

        self.processor = _ProcessorMock()
        self.stream = InputStream(self.processor.feed_key)
Esempio n. 3
0
    def __init__(self, pymux, connection, client_address):
        self.pymux = pymux
        self.connection = connection
        self.client_address = client_address
        self.size = Size(rows=20, columns=80)
        self._closed = False

        self._recv_buffer = b''
        self.cli = None
        self._inputstream = InputStream(
            lambda key: self.cli.input_processor.feed_key(key))

        pymux.eventloop.add_reader(connection.fileno(), self._recv)
Esempio n. 4
0
    def set_application(self, app, callback=None):
        """
        Set ``CommandLineInterface`` instance for this connection.
        (This can be replaced any time.)

        :param cli: CommandLineInterface instance.
        :param callback: Callable that takes the result of the CLI.
        """
        assert isinstance(app, Application)
        assert callback is None or callable(callback)

        self.cli = CommandLineInterface(application=app,
                                        eventloop=self.eventloop,
                                        output=self.vt100_output)
        self.callback = callback

        # Create a parser, and parser callbacks.
        cb = self.cli.create_eventloop_callbacks()
        inputstream = InputStream(cb.feed_key)

        # Input decoder for stdin. (Required when working with multibyte
        # characters, like chinese input.)
        stdin_decoder_cls = getincrementaldecoder(self.encoding)
        stdin_decoder = [stdin_decoder_cls()]  # nonlocal

        # Tell the CLI that it's running. We don't start it through the run()
        # call, but will still want _redraw() to work.
        self.cli._is_running = True

        def data_received(data):
            """ TelnetProtocolParser 'data_received' callback """
            assert isinstance(data, binary_type)

            try:
                result = stdin_decoder[0].decode(data)
                inputstream.feed(result)
            except UnicodeDecodeError:
                stdin_decoder[0] = stdin_decoder_cls()
                return ''

        def size_received(rows, columns):
            """ TelnetProtocolParser 'size_received' callback """
            self.size = Size(rows=rows, columns=columns)
            cb.terminal_size_changed()

        self.parser = TelnetProtocolParser(data_received, size_received)
Esempio n. 5
0
    def set_cli(self, cli, callback=None):
        """
        Set ``CommandLineInterface`` instance for this connection.
        (This can be replaced any time.)

        :param cli: CommandLineInterface instance.
        :param callback: Callable that takes the result of the CLI.
        """
        assert isinstance(cli, CommandLineInterface)
        assert callback is None or callable(callback)

        self.cli = cli
        self.callback = callback

        # Replace the eventloop and renderer to integrate with the
        # telnet server.
        cli.eventloop = self.eventloop
        cli.renderer = Renderer(output=self.vt100_output)

        # Create a parser, and parser callbacks.
        cb = self.cli.create_eventloop_callbacks()
        inputstream = InputStream(cb.feed_key)

        # Input decoder for stdin. (Required when working with multibyte
        # characters, like chinese input.)
        stdin_decoder_cls = getincrementaldecoder(self.encoding)
        stdin_decoder = [stdin_decoder_cls()]  # nonlocal

        def data_received(data):
            """ TelnetProtocolParser 'data_received' callback """
            assert isinstance(data, binary_type)

            try:
                result = stdin_decoder[0].decode(data)
                inputstream.feed(result)
            except UnicodeDecodeError:
                stdin_decoder[0] = stdin_decoder_cls()
                return ''

        def size_received(rows, columns):
            """ TelnetProtocolParser 'size_received' callback """
            self.size = Size(rows=rows, columns=columns)
            cb.terminal_size_changed()

        self.parser = TelnetProtocolParser(data_received, size_received)
Esempio n. 6
0
    def run(self, stdin, callbacks):
        inputstream = InputStream(callbacks.feed_key)
        stdin_reader = PosixStdinReader(stdin.fileno())
        self._callbacks = callbacks

        if in_main_thread():
            ctx = call_on_sigwinch(self.received_winch)
        else:
            ctx = DummyContext()

        select_timeout = INPUT_TIMEOUT
        with ctx:
            while self._running:
                r, _, _ = select.select(
                    [stdin.fileno(), self._schedule_pipe_read], [], [],
                    select_timeout)
                if stdin.fileno() in r:
                    select_timeout = INPUT_TIMEOUT
                    data = stdin_reader.read()
                    inputstream.feed(data)
                    if stdin_reader.closed:
                        break
                elif self._schedule_pipe_read in r:
                    os.read(self._schedule_pipe_read, 8192)
                    while True:
                        try:
                            task = self._calls_from_executor.pop(0)
                        except IndexError:
                            break
                        else:
                            task()
                else:
                    # timeout
                    inputstream.flush()
                    callbacks.input_timeout()
                    select_timeout = None

        self._callbacks = None
Esempio n. 7
0
    def run(self, stdin, callbacks):
        """
        The input 'event loop'.
        """
        assert isinstance(stdin, Input)
        assert isinstance(callbacks, EventLoopCallbacks)
        assert not self._running

        if self.closed:
            raise Exception('Event loop already closed.')

        self._running = True
        self._callbacks = callbacks

        inputstream = InputStream(callbacks.feed_key)
        current_timeout = [INPUT_TIMEOUT]  # Nonlocal

        # Create reader class.
        stdin_reader = PosixStdinReader(stdin.fileno())

        # Only attach SIGWINCH signal handler in main thread.
        # (It's not possible to attach signal handlers in other threads. In
        # that case we should rely on a the main thread to call this manually
        # instead.)
        if in_main_thread():
            ctx = call_on_sigwinch(self.received_winch)
        else:
            ctx = DummyContext()

        def read_from_stdin():
            " Read user input. "
            # Feed input text.
            data = stdin_reader.read()
            inputstream.feed(data)

            # Set timeout again.
            current_timeout[0] = INPUT_TIMEOUT

            # Quit when the input stream was closed.
            if stdin_reader.closed:
                self.stop()

        self.add_reader(stdin, read_from_stdin)
        self.add_reader(self._schedule_pipe[0], None)

        with ctx:
            while self._running:
                # Call inputhook.
                with TimeIt() as inputhook_timer:
                    if self._inputhook_context:

                        def ready(wait):
                            " True when there is input ready. The inputhook should return control. "
                            return self._ready_for_reading(
                                current_timeout[0] if wait else 0) != []

                        self._inputhook_context.call_inputhook(ready)

                # Calculate remaining timeout. (The inputhook consumed some of the time.)
                if current_timeout[0] is None:
                    remaining_timeout = None
                else:
                    remaining_timeout = max(
                        0, current_timeout[0] - inputhook_timer.duration)

                # Wait until input is ready.
                fds = self._ready_for_reading(remaining_timeout)

                # When any of the FDs are ready. Call the appropriate callback.
                if fds:
                    # Create lists of high/low priority tasks. The main reason
                    # for this is to allow painting the UI to happen as soon as
                    # possible, but when there are many events happening, we
                    # don't want to call the UI renderer 1000x per second. If
                    # the eventloop is completely saturated with many CPU
                    # intensive tasks (like processing input/output), we say
                    # that drawing the UI can be postponed a little, to make
                    # CPU available. This will be a low priority task in that
                    # case.
                    tasks = []
                    low_priority_tasks = []
                    now = _now()

                    for fd in fds:
                        # For the 'call_from_executor' fd, put each pending
                        # item on either the high or low priority queue.
                        if fd == self._schedule_pipe[0]:
                            for c, max_postpone_until in self._calls_from_executor:
                                if max_postpone_until is None or max_postpone_until < now:
                                    tasks.append(c)
                                else:
                                    low_priority_tasks.append(
                                        (c, max_postpone_until))
                            self._calls_from_executor = []

                            # Flush all the pipe content.
                            os.read(self._schedule_pipe[0], 1024)
                        else:
                            handler = self._read_fds.get(fd)
                            if handler:
                                tasks.append(handler)

                    # Handle everything in random order. (To avoid starvation.)
                    random.shuffle(tasks)
                    random.shuffle(low_priority_tasks)

                    # When there are high priority tasks, run all these.
                    # Schedule low priority tasks for the next iteration.
                    if tasks:
                        for t in tasks:
                            t()

                        # Postpone low priority tasks.
                        for t, max_postpone_until in low_priority_tasks:
                            self.call_from_executor(
                                t, _max_postpone_until=max_postpone_until)
                    else:
                        # Currently there are only low priority tasks -> run them right now.
                        for t, _ in low_priority_tasks:
                            t()

                else:
                    # Flush all pending keys on a timeout. (This is most
                    # important to flush the vt100 'Escape' key early when
                    # nothing else follows.)
                    inputstream.flush()

                    # Fire input timeout event.
                    callbacks.input_timeout()
                    current_timeout[0] = None

        self.remove_reader(stdin)
        self.remove_reader(self._schedule_pipe[0])

        self._callbacks = None
Esempio n. 8
0
    def run(self, stdin, callbacks):
        """
        The input 'event loop'.
        """
        assert isinstance(stdin, Input)
        assert isinstance(callbacks, EventLoopCallbacks)
        assert not self._running

        if self.closed:
            raise Exception('Event loop already closed.')

        self._running = True
        self._callbacks = callbacks

        inputstream = InputStream(callbacks.feed_key)
        current_timeout = INPUT_TIMEOUT

        # Create reader class.
        stdin_reader = PosixStdinReader(stdin.fileno())

        # Only attach SIGWINCH signal handler in main thread.
        # (It's not possible to attach signal handlers in other threads. In
        # that case we should rely on a the main thread to call this manually
        # instead.)
        if in_main_thread():
            ctx = call_on_sigwinch(self.received_winch)
        else:
            ctx = DummyContext()

        with ctx:
            while self._running:
                # Call inputhook.
                with TimeIt() as inputhook_timer:
                    if self._inputhook_context:

                        def ready(wait):
                            " True when there is input ready. The inputhook should return control. "
                            return self._ready_for_reading(
                                stdin, current_timeout if wait else 0) != []

                        self._inputhook_context.call_inputhook(ready)

                # Calculate remaining timeout. (The inputhook consumed some of the time.)
                if current_timeout is None:
                    remaining_timeout = None
                else:
                    remaining_timeout = max(
                        0, current_timeout - inputhook_timer.duration)

                # Wait until input is ready.
                r = self._ready_for_reading(stdin, remaining_timeout)

                # If we got a character, feed it to the input stream. If we got
                # none, it means we got a repaint request.
                if stdin in r:
                    # Feed input text.
                    data = stdin_reader.read()
                    inputstream.feed(data)

                    # Set timeout again.
                    current_timeout = INPUT_TIMEOUT

                # When any of the registered read pipes are ready. Call the
                # appropriate callback.
                elif set(r) & set(self._read_fds):
                    for fd in r:
                        handler = self._read_fds.get(fd)
                        if handler:
                            handler()

                # If we receive something on our "call_from_executor" pipe, process
                # these callbacks in a thread safe way.
                elif self._schedule_pipe[0] in r:
                    # Flush all the pipe content.
                    os.read(self._schedule_pipe[0], 1024)

                    # Process calls from executor.
                    calls_from_executor, self._calls_from_executor = self._calls_from_executor, []
                    for c in calls_from_executor:
                        c()

                else:
                    # Flush all pending keys on a timeout. (This is most
                    # important to flush the vt100 'Escape' key early when
                    # nothing else follows.)
                    inputstream.flush()

                    # Fire input timeout event.
                    callbacks.input_timeout()
                    current_timeout = None

        self._callbacks = None
def stream(processor):
    return InputStream(processor.feed_key)
Esempio n. 10
0
def stream(processor):
    from prompt_toolkit.terminal.vt100_input import InputStream
    return InputStream(processor.feed_key)