示例#1
0
class RollingLinesWindow:
    def __init__(self,
                 limit: int,
                 *,
                 lexer: 'Optional[Lexer]' = None,
                 wrap_lines: bool = False,
                 dont_extend_height: bool = False,
                 last_line_return: bool = False):

        self.last_line_return = last_line_return
        self.buffer = Buffer(read_only=True)
        self.string_buffer = RollingLinesBuffer(limit)
        self.window = Window(content=BufferControl(buffer=self.buffer,
                                                   lexer=lexer,
                                                   focusable=True),
                             wrap_lines=wrap_lines,
                             dont_extend_height=dont_extend_height)

    def append(self, *lines: str):
        if self.string_buffer.append(*lines):
            cursor_pos = None
            new_text = self.string_buffer.get()
            if self.last_line_return:
                new_text += "\n"
            if self.buffer.cursor_position < len(self.buffer.text):
                cursor_pos = self.buffer.cursor_position
            self.buffer.set_document(Document(text=new_text,
                                              cursor_position=cursor_pos),
                                     bypass_readonly=True)

    def __pt_container__(self):
        return self.window
示例#2
0
文件: test_repl.py 项目: ihr/crash
    def test_undo_capitalize(self):
        buffer = Buffer()

        text = u'Selec'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'Selec', buffer.text)

        text = buffer.text + 't'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'SELECT', buffer.text)

        text = buffer.text + 'i'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'Selecti', buffer.text)

        text = buffer.text + 'on'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'Selection', buffer.text)
示例#3
0
文件: test_repl.py 项目: crate/crash
    def test_undo_capitalize(self):
        buffer = Buffer()

        text = 'Selec'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('Selec', buffer.text)

        text = buffer.text + 't'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('SELECT', buffer.text)

        text = buffer.text + 'i'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('Selecti', buffer.text)

        text = buffer.text + 'on'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('Selection', buffer.text)
示例#4
0
class Terminal(object):
    """
    Terminal widget for use in a prompt_toolkit layout.
    """
    def __init__(self,
                 command=['/bin/bash'],
                 before_exec_func=None,
                 bell_func=None,
                 style='',
                 width=None,
                 height=None,
                 done_callback=None):

        self.terminal_control = _TerminalControl(
            command=command,
            before_exec_func=before_exec_func,
            bell_func=bell_func,
            done_callback=done_callback)

        self.terminal_window = _Window(terminal_control=self.terminal_control,
                                       content=self.terminal_control,
                                       wrap_lines=False)

        # Key bindigns for copy buffer.
        kb = KeyBindings()

        @kb.add('c-c')
        def _(event):
            self.exit_copy_mode()

        @kb.add('space')
        def _(event):
            " Reset selection. "
            event.current_buffer.start_selection()

        @kb.add('enter', filter=has_selection)
        def _(event):
            " Reset selection. "
            data = event.current_buffer.copy_selection()
            event.app.clipboard.set_data(data)

        self.search_toolbar = SearchToolbar(
            forward_search_prompt='Search down: ',
            backward_search_prompt='Search up: ')

        self.copy_buffer = Buffer(read_only=True)
        self.copy_buffer_control = BufferControl(
            buffer=self.copy_buffer,
            search_buffer_control=self.search_toolbar.control,
            include_default_input_processors=False,
            input_processors=[
                _UseStyledTextProcessor(self),
                HighlightSelectionProcessor(),
                HighlightSearchProcessor(),
                HighlightIncrementalSearchProcessor(),
            ],
            preview_search=
            True,  # XXX: not sure why we need twice preview_search.
            key_bindings=kb)

        self.copy_window = Window(content=self.copy_buffer_control,
                                  wrap_lines=False)

        self.is_copying = False
        self.styled_copy_lines = [
        ]  # List of lists of (style, text) tuples, for each line.

        @Condition
        def is_copying():
            return self.is_copying

        self.container = FloatContainer(
            content=HSplit(
                [
                    # Either show terminal window or copy buffer.
                    VSplit([  # XXX: this nested VSplit should not have been necessary,
                        # but the ConditionalContainer which width can become
                        # zero will collapse the other elements.
                        ConditionalContainer(self.terminal_window,
                                             filter=~is_copying),
                        ConditionalContainer(self.copy_window,
                                             filter=is_copying),
                    ]),
                    ConditionalContainer(self.search_toolbar,
                                         filter=is_copying),
                ],
                style=style,
                width=width,
                height=height),
            floats=[
                Float(top=0,
                      right=0,
                      height=1,
                      content=ConditionalContainer(Window(
                          content=FormattedTextControl(
                              text=self._copy_position_formatted_text),
                          style='class:copy-mode-cursor-position'),
                                                   filter=is_copying))
            ])

    def _copy_position_formatted_text(self):
        """
        Return the cursor position text to be displayed in copy mode.
        """
        render_info = self.copy_window.render_info
        if render_info:
            return '[%s/%s]' % (render_info.cursor_position.y + 1,
                                render_info.content_height)
        else:
            return '[0/0]'

    def enter_copy_mode(self):
        # Suspend process.
        self.terminal_control.process.suspend()

        # Copy content into copy buffer.
        data_buffer = self.terminal_control.process.screen.pt_screen.data_buffer

        text = []
        styled_lines = []

        if data_buffer:
            for line_index in range(min(data_buffer), max(data_buffer) + 1):
                line = data_buffer[line_index]
                styled_line = []

                if line:
                    for column_index in range(0, max(line) + 1):
                        char = line[column_index]
                        text.append(char.char)
                        styled_line.append((char.style, char.char))

                text.append('\n')
                styled_lines.append(styled_line)
            text.pop()  # Drop last line ending.

        text = ''.join(text)

        self.copy_buffer.set_document(Document(text=text,
                                               cursor_position=len(text)),
                                      bypass_readonly=True)

        self.styled_lines = styled_lines

        # Enter copy mode.
        self.is_copying = True
        get_app().layout.focus(self.copy_window)

    def exit_copy_mode(self):
        # Resume process.
        self.terminal_control.process.resume()

        # focus terminal again.
        self.is_copying = False
        get_app().layout.focus(self.terminal_window)

    def __pt_container__(self):
        return self.container

    @property
    def process(self):
        return self.terminal_control.process
示例#5
0
class TextArea:
    """
    A simple input field.

    This is a higher level abstraction on top of several other classes with
    sane defaults.

    This widget does have the most common options, but it does not intend to
    cover every single use case. For more configurations options, you can
    always build a text area manually, using a
    :class:`~prompt_toolkit.buffer.Buffer`,
    :class:`~prompt_toolkit.layout.BufferControl` and
    :class:`~prompt_toolkit.layout.Window`.

    Buffer attributes:

    :param text: The initial text.
    :param multiline: If True, allow multiline input.
    :param completer: :class:`~prompt_toolkit.completion.Completer` instance
        for auto completion.
    :param complete_while_typing: Boolean.
    :param accept_handler: Called when `Enter` is pressed (This should be a
        callable that takes a buffer as input).
    :param history: :class:`~prompt_toolkit.history.History` instance.
    :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest`
        instance for input suggestions.

    BufferControl attributes:

    :param password: When `True`, display using asterisks.
    :param focusable: When `True`, allow this widget to receive the focus.
    :param focus_on_click: When `True`, focus after mouse click.
    :param input_processors: `None` or a list of
        :class:`~prompt_toolkit.layout.Processor` objects.

    Window attributes:

    :param lexer: :class:`~prompt_toolkit.lexers.Lexer` instance for syntax
        highlighting.
    :param wrap_lines: When `True`, don't scroll horizontally, but wrap lines.
    :param width: Window width. (:class:`~prompt_toolkit.layout.Dimension` object.)
    :param height: Window height. (:class:`~prompt_toolkit.layout.Dimension` object.)
    :param scrollbar: When `True`, display a scroll bar.
    :param style: A style string.
    :param dont_extend_width: When `True`, don't take up more width then the
                              preferred width reported by the control.
    :param dont_extend_height: When `True`, don't take up more width then the
                               preferred height reported by the control.
    :param get_line_prefix: None or a callable that returns formatted text to
        be inserted before a line. It takes a line number (int) and a
        wrap_count and returns formatted text. This can be used for
        implementation of line continuations, things like Vim "breakindent" and
        so on.

    Other attributes:

    :param search_field: An optional `SearchToolbar` object.
    """
    def __init__(self,
                 text: str = '',
                 multiline: FilterOrBool = True,
                 password: FilterOrBool = False,
                 lexer: Optional[Lexer] = None,
                 auto_suggest: Optional[AutoSuggest] = None,
                 completer: Optional[Completer] = None,
                 complete_while_typing: FilterOrBool = True,
                 accept_handler: Optional[BufferAcceptHandler] = None,
                 history: Optional[History] = None,
                 focusable: FilterOrBool = True,
                 focus_on_click: FilterOrBool = False,
                 wrap_lines: FilterOrBool = True,
                 read_only: FilterOrBool = False,
                 width: AnyDimension = None,
                 height: AnyDimension = None,
                 dont_extend_height: FilterOrBool = False,
                 dont_extend_width: FilterOrBool = False,
                 line_numbers: bool = False,
                 get_line_prefix: Optional[GetLinePrefixCallable] = None,
                 scrollbar: bool = False,
                 style: str = '',
                 search_field: Optional[SearchToolbar] = None,
                 preview_search: FilterOrBool = True,
                 prompt: AnyFormattedText = '',
                 input_processors: Optional[List[Processor]] = None) -> None:

        if search_field is None:
            search_control = None
        elif isinstance(search_field, SearchToolbar):
            search_control = search_field.control

        if input_processors is None:
            input_processors = []

        # Writeable attributes.
        self.completer = completer
        self.complete_while_typing = complete_while_typing
        self.lexer = lexer
        self.auto_suggest = auto_suggest
        self.read_only = read_only
        self.wrap_lines = wrap_lines

        self.buffer = Buffer(
            document=Document(text, 0),
            multiline=multiline,
            read_only=Condition(lambda: is_true(self.read_only)),
            completer=DynamicCompleter(lambda: self.completer),
            complete_while_typing=Condition(
                lambda: is_true(self.complete_while_typing)),
            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
            accept_handler=accept_handler,
            history=history)

        self.control = BufferControl(
            buffer=self.buffer,
            lexer=DynamicLexer(lambda: self.lexer),
            input_processors=[
                ConditionalProcessor(AppendAutoSuggestion(),
                                     has_focus(self.buffer) & ~is_done),
                ConditionalProcessor(processor=PasswordProcessor(),
                                     filter=to_filter(password)),
                BeforeInput(prompt, style='class:text-area.prompt'),
            ] + input_processors,
            search_buffer_control=search_control,
            preview_search=preview_search,
            focusable=focusable,
            focus_on_click=focus_on_click)

        if multiline:
            if scrollbar:
                right_margins = [ScrollbarMargin(display_arrows=True)]
            else:
                right_margins = []
            if line_numbers:
                left_margins = [NumberedMargin()]
            else:
                left_margins = []
        else:
            height = D.exact(1)
            left_margins = []
            right_margins = []

        style = 'class:text-area ' + style

        self.window = Window(
            height=height,
            width=width,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
            content=self.control,
            style=style,
            wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
            left_margins=left_margins,
            right_margins=right_margins,
            get_line_prefix=get_line_prefix)

    @property
    def text(self) -> str:
        """
        The `Buffer` text.
        """
        return self.buffer.text

    @text.setter
    def text(self, value: str) -> None:
        self.buffer.set_document(Document(value, 0), bypass_readonly=True)

    @property
    def document(self) -> Document:
        """
        The `Buffer` document (text + cursor position).
        """
        return self.buffer.document

    @document.setter
    def document(self, value: Document) -> None:
        self.buffer.document = value

    @property
    def accept_handler(self) -> Optional[BufferAcceptHandler]:
        """
        The accept handler. Called when the user accepts the input.
        """
        return self.buffer.accept_handler

    @accept_handler.setter
    def accept_handler(self, value: BufferAcceptHandler) -> None:
        self.buffer.accept_handler = value

    def __pt_container__(self) -> Container:
        return self.window
示例#6
0
文件: test_repl.py 项目: ihr/crash
    def test_capitalize(self):
        buffer = Buffer()

        text = u'selec'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'selec', buffer.text)

        text = u'select'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'SELECT', buffer.text)

        text = u'CREATE TABLE "select'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'CREATE TABLE "select', buffer.text)

        text = u'CREATE TABLE \'select\''
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'CREATE TABLE \'select\'', buffer.text)

        text = u'create table test (x int)'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'CREATE TABLE test (x INT)', buffer.text)

        text = u'create table test (a boolean, b string, c integer)'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'CREATE TABLE test (a BOOLEAN, b STRING, c INTEGER)',
                         buffer.text)

        text = u'create table test\n(a boolean, b string, c integer)'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(
            u'CREATE TABLE test\n(a BOOLEAN, b STRING, c INTEGER)',
            buffer.text)

        text = u'\select dynamic'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual(u'\select dynamic', buffer.text)
示例#7
0
文件: widgets.py 项目: plotski/upsies
class InputField:
    """Single line of user-editable text"""
    def __init__(self,
                 text='',
                 width=None,
                 extend_width=True,
                 read_only=False,
                 on_accepted=None,
                 on_changed=None,
                 style=''):
        self._activity_indicator = utils.ActivityIndicator(
            callback=self.set_text)
        self.read_only = read_only
        self.on_accepted = on_accepted
        self.buffer = Buffer(
            multiline=False,
            accept_handler=self._accept_handler,
            on_text_changed=on_changed,
            read_only=Condition(lambda: self.read_only),
        )
        self.container = Window(
            content=BufferControl(self.buffer),
            always_hide_cursor=Condition(lambda: self.read_only),
            width=width,
            dont_extend_height=True,
            dont_extend_width=not extend_width,
            style=style,
        )
        if text:
            self.set_text(text, ignore_callback=True)

    def _accept_handler(self, buffer):
        if self.on_accepted:
            self.on_accepted(buffer)
        # Do not clear input field on enter
        return True

    @property
    def text(self):
        return self.buffer.text

    @text.setter
    def text(self, text):
        self.set_text(text)

    def set_text(self,
                 text,
                 ignore_callback=False,
                 preserve_cursor_position=True):
        if preserve_cursor_position:
            curpos = self.buffer.cursor_position
        if ignore_callback:
            handlers = self.buffer.on_text_changed._handlers
            self.buffer.on_text_changed._handlers = []
        self.buffer.set_document(Document(text), bypass_readonly=True)
        if ignore_callback:
            self.buffer.on_text_changed._handlers = handlers
        if preserve_cursor_position:
            self.buffer.cursor_position = curpos

    @property
    def read_only(self):
        return self._read_only

    @read_only.setter
    def read_only(self, read_only):
        self._read_only = bool(read_only)

    @property
    def is_loading(self):
        """Whether an activity indicator is displayed"""
        return self._activity_indicator.active

    @is_loading.setter
    def is_loading(self, is_loading):
        self._activity_indicator.active = is_loading

    def __pt_container__(self):
        return self.container
示例#8
0
class Pane(object):
    """
    One pane, containing one process and a search buffer for going into copy
    mode or displaying the help.
    """
    _pane_counter = 1000  # Start at 1000, to be sure to not confuse this with pane indexes.

    def __init__(self, process):
        assert isinstance(process, Process)

        self.process = process
        self.chosen_name = None

        # Displayed the clock instead of this pane content.
        self.clock_mode = False

        # Give unique ID.
        Pane._pane_counter += 1
        self.pane_id = Pane._pane_counter

        # Prompt_toolkit buffer, for displaying scrollable text.
        # (In copy mode, or help mode.)
        # Note: Because the scroll_buffer can only contain text, we also use the
        #       copy_token_list, that contains a token list with color information.
        self.scroll_buffer = Buffer(read_only=True)
        self.copy_token_list = []
        self.display_scroll_buffer = False
        self.scroll_buffer_title = ''

        # Search buffer, for use in copy mode. (Each pane gets its own search buffer.)
        self.search_buffer = Buffer()
        self.is_searching = False
        self.search_state = SearchState(ignore_case=False)

    @property
    def name(self):
        """
        The name for the window as displayed in the title bar and status bar.
        """
        # Name, explicitely set for the pane.
        if self.chosen_name:
            return self.chosen_name
        else:
            # Name from the process running inside the pane.
            name = self.process.get_name()
            if name:
                return os.path.basename(name)

        return ''

    def enter_copy_mode(self):
        """
        Suspend the process, and copy the screen content to the `scroll_buffer`.
        That way the user can search through the history and copy/paste.
        """
        document, token_list = self.process.create_copy_document()
        self._enter_scroll_buffer('Copy', document, token_list)

    def display_text(self, text, title=''):
        """
        Display the given text in the scroll buffer.
        """
        self._enter_scroll_buffer(
            title,
            document=Document(text, 0),
            token_list=[(Token, text)])

    def _enter_scroll_buffer(self, title, document, token_list):
        # Suspend child process.
        self.process.suspend()

        self.scroll_buffer.set_document(document, bypass_readonly=True)
        self.copy_token_list = token_list
        self.display_scroll_buffer = True
        self.scroll_buffer_title = title

        # Reset search state.
        self.search_state = SearchState(ignore_case=False)

    def exit_scroll_buffer(self):
        """
        Exit scroll buffer. (Exits help or copy mode.)
        """
        self.process.resume()
        self.display_scroll_buffer = False
示例#9
0
class Pane(object):
    """
    One pane, containing one process and a search buffer for going into copy
    mode or displaying the help.
    """
    _pane_counter = 1000  # Start at 1000, to be sure to not confuse this with pane indexes.

    def __init__(self, process):
        assert isinstance(process, Process)

        self.process = process
        self.chosen_name = None

        # Displayed the clock instead of this pane content.
        self.clock_mode = False

        # Give unique ID.
        Pane._pane_counter += 1
        self.pane_id = Pane._pane_counter

        # Prompt_toolkit buffer, for displaying scrollable text.
        # (In copy mode, or help mode.)
        # Note: Because the scroll_buffer can only contain text, we also use the
        #       copy_token_list, that contains a token list with color information.
        self.scroll_buffer = Buffer(read_only=True)
        self.copy_token_list = []
        self.display_scroll_buffer = False
        self.scroll_buffer_title = ''

        # Search buffer, for use in copy mode. (Each pane gets its own search buffer.)
        self.search_buffer = Buffer()
        self.is_searching = False
        self.search_state = SearchState(ignore_case=False)

    @property
    def name(self):
        """
        The name for the window as displayed in the title bar and status bar.
        """
        # Name, explicitely set for the pane.
        if self.chosen_name:
            return self.chosen_name
        else:
            # Name from the process running inside the pane.
            name = self.process.get_name()
            if name:
                return os.path.basename(name)

        return ''

    def enter_copy_mode(self):
        """
        Suspend the process, and copy the screen content to the `scroll_buffer`.
        That way the user can search through the history and copy/paste.
        """
        document, token_list = self.process.create_copy_document()
        self._enter_scroll_buffer('Copy', document, token_list)

    def display_text(self, text, title=''):
        """
        Display the given text in the scroll buffer.
        """
        self._enter_scroll_buffer(title,
                                  document=Document(text, 0),
                                  token_list=[(Token, text)])

    def _enter_scroll_buffer(self, title, document, token_list):
        # Suspend child process.
        self.process.suspend()

        self.scroll_buffer.set_document(document, bypass_readonly=True)
        self.copy_token_list = token_list
        self.display_scroll_buffer = True
        self.scroll_buffer_title = title

        # Reset search state.
        self.search_state = SearchState(ignore_case=False)

    def exit_scroll_buffer(self):
        """
        Exit scroll buffer. (Exits help or copy mode.)
        """
        self.process.resume()
        self.display_scroll_buffer = False
示例#10
0
文件: test_repl.py 项目: crate/crash
    def test_capitalize(self):
        buffer = Buffer()

        text = 'selec'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('selec', buffer.text)

        text = 'select'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('SELECT', buffer.text)

        text = 'CREATE TABLE "select'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('CREATE TABLE "select', buffer.text)

        text = 'CREATE TABLE \'select\''
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('CREATE TABLE \'select\'', buffer.text)

        text = 'create table test (x int)'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('CREATE TABLE test (x INT)', buffer.text)

        text = 'create table test (a boolean, b string, c integer)'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('CREATE TABLE test (a BOOLEAN, b STRING, c INTEGER)', buffer.text)

        text = 'create table test\n(a boolean, b string, c integer)'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('CREATE TABLE test\n(a BOOLEAN, b STRING, c INTEGER)', buffer.text)

        text = '\\select dynamic'
        buffer.set_document(Document(text, len(text)))
        self.capitalizer.apply_capitalization(buffer)
        self.assertEqual('\\select dynamic', buffer.text)
示例#11
0
class TextArea(object):
    """
    A simple input field.

    This contains a ``prompt_toolkit`` :class:`~prompt_toolkit.buffer.Buffer`
    object that hold the text data structure for the edited buffer, the
    :class:`~prompt_toolkit.layout.BufferControl`, which applies a
    :class:`~prompt_toolkit.lexers.Lexer` to the text and turns it into a
    :class:`~prompt_toolkit.layout.UIControl`, and finally, this
    :class:`~prompt_toolkit.layout.UIControl` is wrapped in a
    :class:`~prompt_toolkit.layout.Window` object (just like any
    :class:`~prompt_toolkit.layout.UIControl`), which is responsible for the
    scrolling.

    This widget does have some options, but it does not intend to cover every
    single use case. For more configurations options, you can always build a
    text area manually, using a :class:`~prompt_toolkit.buffer.Buffer`,
    :class:`~prompt_toolkit.layout.BufferControl` and
    :class:`~prompt_toolkit.layout.Window`.

    :param text: The initial text.
    :param multiline: If True, allow multiline input.
    :param lexer: :class:`~prompt_toolkit.lexers.Lexer` instance for syntax highlighting.
    :param completer: :class:`~prompt_toolkit.completion.Completer` instance for auto completion.
    :param focusable: When `True`, allow this widget to receive the focus.
    :param wrap_lines: When `True`, don't scroll horizontally, but wrap lines.
    :param width: Window width. (:class:`~prompt_toolkit.layout.Dimension` object.)
    :param height: Window height. (:class:`~prompt_toolkit.layout.Dimension` object.)
    :param password: When `True`, display using asterisks.
    :param accept_handler: Called when `Enter` is pressed.
    :param scrollbar: When `True`, display a scroll bar.
    :param search_field: An optional `SearchToolbar` object.
    :param style: A style string.
    :param dont_extend_height:
    :param dont_extend_width:
    """
    def __init__(self,
                 text='',
                 multiline=True,
                 password=False,
                 lexer=None,
                 completer=None,
                 accept_handler=None,
                 focusable=True,
                 wrap_lines=True,
                 read_only=False,
                 width=None,
                 height=None,
                 dont_extend_height=False,
                 dont_extend_width=False,
                 line_numbers=False,
                 scrollbar=False,
                 style='',
                 search_field=None,
                 preview_search=True,
                 prompt=''):
        assert isinstance(text, six.text_type)
        assert search_field is None or isinstance(search_field, SearchToolbar)

        if search_field is None:
            search_control = None
        elif isinstance(search_field, SearchToolbar):
            search_control = search_field.control

        self.buffer = Buffer(document=Document(text, 0),
                             multiline=multiline,
                             read_only=read_only,
                             completer=completer,
                             complete_while_typing=True,
                             accept_handler=(lambda buff: accept_handler(buff))
                             if accept_handler else None)

        self.control = BufferControl(
            buffer=self.buffer,
            lexer=lexer,
            input_processors=[
                ConditionalProcessor(processor=PasswordProcessor(),
                                     filter=to_filter(password)),
                BeforeInput(prompt, style='class:text-area.prompt'),
            ],
            search_buffer_control=search_control,
            preview_search=preview_search,
            focusable=focusable)

        if multiline:
            if scrollbar:
                right_margins = [ScrollbarMargin(display_arrows=True)]
            else:
                right_margins = []
            if line_numbers:
                left_margins = [NumberedMargin()]
            else:
                left_margins = []
        else:
            wrap_lines = False  # Never wrap for single line input.
            height = D.exact(1)
            left_margins = []
            right_margins = []

        style = 'class:text-area ' + style

        self.window = Window(height=height,
                             width=width,
                             dont_extend_height=dont_extend_height,
                             dont_extend_width=dont_extend_width,
                             content=self.control,
                             style=style,
                             wrap_lines=wrap_lines,
                             left_margins=left_margins,
                             right_margins=right_margins)

    @property
    def text(self):
        return self.buffer.text

    @text.setter
    def text(self, value):
        self.buffer.set_document(Document(value, 0), bypass_readonly=True)

    @property
    def document(self):
        return self.buffer.document

    @document.setter
    def document(self, value):
        self.buffer.document = value

    def __pt_container__(self):
        return self.window
示例#12
0
class TextArea(object):
    """
    A simple input field.

    This is a higher level abstraction on top of several other classes with
    sane defaults.

    This widget does have the most common options, but it does not intend to
    cover every single use case. For more configurations options, you can
    always build a text area manually, using a
    :class:`~prompt_toolkit.buffer.Buffer`,
    :class:`~prompt_toolkit.layout.BufferControl` and
    :class:`~prompt_toolkit.layout.Window`.

    Buffer attributes:

    :param text: The initial text.
    :param multiline: If True, allow multiline input.
    :param completer: :class:`~prompt_toolkit.completion.Completer` instance
        for auto completion.
    :param complete_while_typing: Boolean.
    :param accept_handler: Called when `Enter` is pressed (This should be a
        callable that takes a buffer as input).
    :param history: :class:`~prompt_toolkit.history.History` instance.
    :param auto_suggest: :class:`~prompt_toolkit.auto_suggest.AutoSuggest`
        instance for input suggestions.

    BufferControl attributes:

    :param password: When `True`, display using asterisks.
    :param focusable: When `True`, allow this widget to receive the focus.
    :param focus_on_click: When `True`, focus after mouse click.
    :param input_processors: `None` or a list of
        :class:`~prompt_toolkit.layout.Processor` objects.

    Window attributes:

    :param lexer: :class:`~prompt_toolkit.lexers.Lexer` instance for syntax
        highlighting.
    :param wrap_lines: When `True`, don't scroll horizontally, but wrap lines.
    :param width: Window width. (:class:`~prompt_toolkit.layout.Dimension` object.)
    :param height: Window height. (:class:`~prompt_toolkit.layout.Dimension` object.)
    :param scrollbar: When `True`, display a scroll bar.
    :param style: A style string.
    :param dont_extend_width: When `True`, don't take up more width then the
                              preferred width reported by the control.
    :param dont_extend_height: When `True`, don't take up more width then the
                               preferred height reported by the control.
    :param get_line_prefix: None or a callable that returns formatted text to
        be inserted before a line. It takes a line number (int) and a
        wrap_count and returns formatted text. This can be used for
        implementation of line continuations, things like Vim "breakindent" and
        so on.

    Other attributes:

    :param search_field: An optional `SearchToolbar` object.
    """
    def __init__(self, text='', multiline=True, password=False,
                 lexer=None, auto_suggest=None, completer=None,
                 complete_while_typing=True, accept_handler=None, history=None,
                 focusable=True, focus_on_click=False, wrap_lines=True,
                 read_only=False, width=None, height=None,
                 dont_extend_height=False, dont_extend_width=False,
                 line_numbers=False, get_line_prefix=None, scrollbar=False,
                 style='', search_field=None, preview_search=True, prompt='',
                 input_processors=None):
       # assert isinstance(text, six.text_type)

        if search_field is None:
            search_control = None

        if input_processors is None:
            input_processors = []

        # Writeable attributes.
        self.completer = completer
        self.complete_while_typing = complete_while_typing
        self.lexer = lexer
        self.auto_suggest = auto_suggest
        self.read_only = read_only
        self.wrap_lines = wrap_lines

        self.buffer = Buffer(
            document=Document(text, 0),
            multiline=multiline,
            read_only=Condition(lambda: is_true(self.read_only)),
            completer=DynamicCompleter(lambda: self.completer),
            complete_while_typing=Condition(
                lambda: is_true(self.complete_while_typing)),
            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
            accept_handler=accept_handler,
            history=history)

        self.control = BufferControl(
            buffer=self.buffer,
            lexer=DynamicLexer(lambda: self.lexer),
            input_processors=[
                ConditionalProcessor(
                    AppendAutoSuggestion(),
                    has_focus(self.buffer) & is_done), #
                ConditionalProcessor(
                    processor=PasswordProcessor(),
                    filter=to_filter(password)
                ),
                BeforeInput(prompt, style='class:text-area.prompt'),
            ] + input_processors,
            search_buffer_control=search_control,
            preview_search=preview_search,
            focusable=focusable,
            focus_on_click=focus_on_click)

        if multiline:
            if scrollbar:
                right_margins = [ScrollbarMargin(display_arrows=True)]
            else:
                right_margins = []
            if line_numbers:
                left_margins = [NumberedMargin()]
            else:
                left_margins = []
        else:
            height = D.exact(1)
            left_margins = []
            right_margins = []

        style = 'class:text-area ' + style

        self.window = Window(
            height=height,
            width=width,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
            content=self.control,
            style=style,
            wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
            left_margins=left_margins,
            right_margins=right_margins,
            get_line_prefix=get_line_prefix)

    @property
    def text(self):
        """
        The `Buffer` text.
        """
        return self.buffer.text

    @text.setter
    def text(self, value):
        self.buffer.set_document(Document(value, 0), bypass_readonly=True)

    @property
    def document(self):
        """
        The `Buffer` document (text + cursor position).
        """
        return self.buffer.document

    @document.setter
    def document(self, value):
        self.buffer.document = value

    @property
    def accept_handler(self):
        """
        The accept handler. Called when the user accepts the input.
        """
        return self.buffer.accept_handler

    @accept_handler.setter
    def accept_handler(self, value):
        self.buffer.accept_handler = value

    def __pt_container__(self):
        return self.window
示例#13
0
class HoundCli(object):
    """
    Abstracts CSVHound CLI
    """
    def __init__(self):

        # create left and right buffers in main area
        self.left_buffer = Buffer(read_only=True)
        self.right_buffer = Buffer()

        # sample text to get us going
        test_text = 'test\none\ntwo\nthree'

        # this is how to explicity write new content to a read-only buffer
        self.left_buffer.set_document(Document(test_text),
                                      bypass_readonly=True)

        # create windows; you need a Windor and a BufferControl to display Buffer
        # content
        self.left_window = Window(BufferControl(buffer=self.left_buffer))
        self.right_window = Window(BufferControl(buffer=self.right_buffer))

        self.command_window = Window(height=1, style='class:line')
        self.command_area = HSplit([
            self.command_window,
            Window(height=1, char='\u2500', style='class:line')
        ])

        self.main_body = VSplit([
            self.left_window,

            # A vertical line in the middle. We explicitly specify the width, to make
            # sure that the layout engine will not try to divide the whole width by
            # three for all these windows.
            Window(width=1, char='\u2502', style='class:line'),

            # Display the Result buffer on the right.
            self.right_window,
        ])

        self.title_area = Window(
            height=1,
            content=FormattedTextControl(self.get_titlebar_text),
            align=WindowAlign.LEFT,
            # style='class:reverse')
            style='bg:DarkBlue Gold')

        self.message_area = Window(
            height=1,
            content=DummyControl(),
            align=WindowAlign.LEFT,
            # style='class:reverse')
            style='bg:DarkBlue Gold')

        self.status_area = Window(height=1,
                                  content=DummyControl(),
                                  align=WindowAlign.LEFT,
                                  style='bg:DarkBlue Gold')
        # style='class:reverse')

        self.float_content = HSplit([
            self.title_area, self.message_area,
            Window(height=1, char='\u2500', style='class:line'),
            self.command_area, self.main_body, self.status_area
        ])

        self.root_container = FloatContainer(content=self.float_content,
                                             floats=[
                                                 Float(xcursor=True,
                                                       ycursor=True,
                                                       content=CompletionsMenu(
                                                           max_height=16,
                                                           scroll_offset=1))
                                             ])

        self.kb = KeyBindings()

        self.kb.add('c-n')(focus_next)
        self.kb.add('c-p')(focus_previous)

        @self.kb.add('c-c', eager=True)
        @self.kb.add('c-q', eager=True)
        def _(event):
            """
            Pressing Ctrl-Q or Ctrl-C will exit the user interface.

            Setting a return value means: quit the event loop that drives the user
            interface and return this value from the `Application.run()` call.

            Note that Ctrl-Q does not work on all terminals. Sometimes it requires
            executing `stty -ixon`.
            """
            event.app.exit()

        @self.kb.add('o')
        def _(event):
            """
            attempt to insert a file open command prompt
            """
            self.cmd_buffer_open = self.create_cmd_buffer("open")
            self.cmd_open_control = self.create_cmd_control(
                self.cmd_buffer_open, prompt='[Open file:] ')

            self.command_area.children[0].content = self.cmd_open_control

            app = get_app()
            app.layout.focus(self.command_area)

        self.application = None

        self._current_table = None

    # define initial titlebar text
    def get_titlebar_text(self):
        return [
            ('class:title', ' CSV Hound'),
            ('class:title', ' (Press [Ctrl-Q] to quit.)'),
        ]

    def get_status_text(self, message):
        return [
            ('Gold', '     ' + message),
            # ('class:red', '     '+message),
        ]

    # accept_handler for open command
    def do_open(self, _):
        logger.debug('attempting to open file [' + _.text + ']...')
        if (csvhound.core.file_exists(_.text)):
            model = csvhound.core.BaseHound()
            self._current_table = model.get_table_from_file(_.text)

            output = "Rows: " + str(len(self._current_table.rows))
            output += "\nColumns: " + str(len(self._current_table.columns))
            output += "\n---------------------------------------------------"
            output += '\n'
            output += '\nTABLE COLUMNS:\n\n'

            # rows = model.describe_table()
            details = model.describe_table()
            for detail in details:
                # print(detail)
                output += detail[0] + ' [' + detail[1] + ']\n'

            self.left_buffer.set_document(Document(output),
                                          bypass_readonly=True)

            # hide previous command buffer control
            self.status_area.content = FormattedTextControl(
                self.get_status_text('file open: ' + _.text))
        else:
            self.status_area.content = FormattedTextControl(
                self.get_status_text('file not found: ' + _.text))
        self.command_area.children[0].content = DummyControl()
        app = get_app()
        app.layout.focus(self.left_buffer)

    def do_inspect(self, _):
        self.right_buffer.text = "INSPECT:\n" + _.text
        # hide previous command buffer control
        self.command_area.children[0].content = DummyControl()
        self.status_area.content = FormattedTextControl(
            self.get_status_text('inspect file: ' + _.text))
        app = get_app()
        app.layout.focus(self.left_buffer)

    # create a command buffer for a given command, with named accept_handler
    def create_cmd_buffer(self, command):
        completer = PathCompleter()
        # if command == 'open' or command == 'inspect':
        # completer=PathCompleter()
        # else:
        # completer=None
        accept_handler = getattr(self, 'do_' + command)
        return Buffer(completer=completer,
                      name='cmd_buffer_' + command,
                      accept_handler=accept_handler,
                      multiline=False)

    # create command buffer control with given command buffer
    def create_cmd_control(self, buffer, prompt='>>>> '):
        return BufferControl(buffer,
                             input_processors=[
                                 BeforeInput(prompt,
                                             style='class:text-area.prompt')
                             ])

    def create_application(self):
        self.application = Application(
            layout=Layout(self.root_container),
            key_bindings=self.kb,

            # Let's add mouse support!
            mouse_support=True,

            # Using an alternate screen buffer means as much as: "run full screen".
            # It switches the terminal to an alternate screen.
            full_screen=True)

    def run_application(self):
        self.application.run()
示例#14
0
class FormattedTextArea:
    """Just like text area, but it accepts formatted content."""
    def __init__(
        self,
        text="",
        focusable=False,
        wrap_lines=True,
        width=None,
        height=None,
        scrollbar=False,
        dont_extend_height=True,
        dont_extend_width=False,
        read_only=True,
    ):
        self.read_only = read_only
        formatted_text = to_formatted_text(text)
        plain_text = fragment_list_to_text(formatted_text)
        self.buffer = Buffer(
            document=Document(plain_text, 0),
            read_only=Condition(lambda: self.read_only),
        )
        self.control = FormattedBufferControl(
            buffer=self.buffer,
            formatted_text=formatted_text,
            input_processors=[
                FormatTextProcessor(),
                HighlightSelectionProcessor()
            ],
            include_default_input_processors=False,
            focusable=focusable,
            focus_on_click=focusable,
        )
        self.scrollbar = scrollbar
        right_margins = [
            ConditionalMargin(
                ScrollbarMargin(display_arrows=True),
                filter=Condition(lambda: self.scrollbar),
            ),
        ]
        self.window = Window(
            content=self.control,
            width=width,
            height=height,
            wrap_lines=wrap_lines,
            right_margins=right_margins,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
        )

    @property
    def document(self):
        return self.buffer.document

    @document.setter
    def document(self, value):
        self.buffer.set_document(value, bypass_readonly=True)

    @property
    def text(self):
        return self.buffer.text

    @text.setter
    def text(self, text):
        formatted_text = to_formatted_text(text)
        self.control.update_formatted_text(formatted_text)
        plain_text = fragment_list_to_text(formatted_text)
        self.document = Document(plain_text, 0)

    def __pt_container__(self):
        return self.window