Ejemplo n.º 1
0
    def __init__(self,
                 buffer_name=DEFAULT_BUFFER,
                 input_processors=None,
                 lexer=None,
                 preview_search=False,
                 wrap_lines=True,
                 menu_position=None,
                 default_char=None):
        assert input_processors is None or all(isinstance(i, Processor) for i in input_processors)
        assert menu_position is None or callable(menu_position)
        assert lexer is None or isinstance(lexer, Lexer)

        self.preview_search = to_cli_filter(preview_search)
        self.wrap_lines = to_cli_filter(wrap_lines)

        self.input_processors = input_processors or []
        self.buffer_name = buffer_name
        self.menu_position = menu_position
        self.lexer = lexer or SimpleLexer()
        self.default_char = default_char or Char(token=Token.Transparent)

        #: LRU cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a faily easy way to cache such an expensive operation.
        self._token_lru_cache = _SimpleLRUCache(maxsize=8)

        #: Keep a similar cache for rendered screens. (when we scroll up/down
        #: through the screen, or when we change another buffer, we don't want
        #: to recreate the same screen again.)
        self._screen_lru_cache = _SimpleLRUCache(maxsize=8)

        self._xy_to_cursor_position = None
        self._last_click_timestamp = None
Ejemplo n.º 2
0
    def __init__(self,
                 registry=None,
                 enable_vi_mode=Never(),
                 enable_system_bindings=Never(),
                 enable_search=Always(),
                 enable_open_in_editor=Never(),
                 enable_all=Always()):

        # Accept both Filters and booleans as input.
        enable_vi_mode = to_cli_filter(enable_vi_mode)
        enable_system_bindings = to_cli_filter(enable_system_bindings)
        enable_open_in_editor = to_cli_filter(enable_open_in_editor)
        enable_all = to_cli_filter(enable_all)

        # Create registry.
        assert registry is None or isinstance(registry, Registry)
        self.registry = registry or Registry()

        # Emacs mode filter is the opposite of Vi mode.
        enable_emacs_mode = ~enable_vi_mode

        # Vi state. (Object to keep track of in which Vi mode we are.)
        self.vi_state = ViState()

        # Load basic bindings.
        load_basic_bindings(self.registry, enable_all)

        load_basic_system_bindings(self.registry,
                                   enable_system_bindings & enable_all)

        # Load emacs bindings.
        load_emacs_bindings(self.registry, enable_emacs_mode & enable_all)

        load_emacs_open_in_editor_bindings(
            self.registry,
            enable_emacs_mode & enable_open_in_editor & enable_all)

        load_emacs_search_bindings(
            self.registry, enable_emacs_mode & enable_search & enable_all)

        load_emacs_system_bindings(
            self.registry,
            enable_emacs_mode & enable_system_bindings & enable_all)

        # Load Vi bindings.
        load_vi_bindings(self.registry,
                         self.vi_state,
                         enable_visual_key=~enable_open_in_editor,
                         filter=enable_vi_mode & enable_all)

        load_vi_open_in_editor_bindings(
            self.registry, self.vi_state,
            enable_vi_mode & enable_open_in_editor & enable_all)

        load_vi_search_bindings(self.registry, self.vi_state,
                                enable_vi_mode & enable_search & enable_all)

        load_vi_system_bindings(
            self.registry, self.vi_state,
            enable_vi_mode & enable_system_bindings & enable_all)
Ejemplo n.º 3
0
    def __init__(self, get_tokens, default_char=None, get_default_char=None,
                 align_right=False, align_center=False,
                 has_focus=False, wrap_lines=True):
        assert default_char is None or isinstance(default_char, Char)
        assert get_default_char is None or callable(get_default_char)
        assert not (default_char and get_default_char)

        self.align_right = to_cli_filter(align_right)
        self.align_center = to_cli_filter(align_center)
        self._has_focus_filter = to_cli_filter(has_focus)
        self.wrap_lines = to_cli_filter(wrap_lines)

        self.get_tokens = get_tokens

        # Construct `get_default_char` callable.
        if default_char:
            get_default_char = lambda _: default_char
        elif not get_default_char:
            get_default_char = lambda _: Char(' ', Token)

        self.get_default_char = get_default_char

        #: Cache for rendered screens.
        self._screen_lru_cache = SimpleLRUCache(maxsize=18)
        self._token_lru_cache = SimpleLRUCache(maxsize=1)
            # Only cache one token list. We don't need the previous item.

        # Render info for the mouse support.
        self._tokens = None  # The last rendered tokens.
        self._pos_to_indexes = None  # Mapping from mouse positions (x,y) to
Ejemplo n.º 4
0
    def add_binding(self, *keys, **kwargs):
        """
        Decorator for annotating key bindings.

        :param filter: :class:`~prompt_toolkit.filters.CLIFilter` to determine
            when this key binding is active.
        :param eager: :class:`~prompt_toolkit.filters.CLIFilter` or `bool`.
            When True, ignore potential longer matches when this key binding is
            hit. E.g. when there is an active eager key binding for Ctrl-X,
            execute the handler immediately and ignore the key binding for
            Ctrl-X Ctrl-E of which it is a prefix.
        """
        filter = to_cli_filter(kwargs.pop('filter', True))
        eager = to_cli_filter(kwargs.pop('eager', False))
        to_cli_filter(kwargs.pop('invalidate_ui',
                                 True))  # Deprecated! (ignored.)

        assert not kwargs
        assert keys
        assert all(isinstance(k, (Key, text_type)) for k in keys), \
            'Key bindings should consist of Key and string (unicode) instances.'

        def decorator(func):
            # When a filter is Never, it will always stay disabled, so in that case
            # don't bother putting it in the registry. It will slow down every key
            # press otherwise.
            if not isinstance(filter, Never):
                self.key_bindings.append(
                    _Binding(keys, func, filter=filter, eager=eager))
                self._clear_cache()

            return func

        return decorator
Ejemplo n.º 5
0
    def add_binding(self, *keys, **kwargs):
        """
        Decorator for annotating key bindings.

        :param filter: :class:`~prompt_toolkit.filters.CLIFilter` to determine
            when this key binding is active.
        :param eager: :class:`~prompt_toolkit.filters.CLIFilter` or `bool`.
            When True, ignore potential longer matches when this key binding is
            hit. E.g. when there is an active eager key binding for Ctrl-X,
            execute the handler immediately and ignore the key binding for
            Ctrl-X Ctrl-E of which it is a prefix.
        """
        filter = to_cli_filter(kwargs.pop('filter', True))
        eager = to_cli_filter(kwargs.pop('eager', False))
        to_cli_filter(kwargs.pop('invalidate_ui', True))  # Deprecated! (ignored.)

        assert not kwargs
        assert keys
        assert all(isinstance(k, (Key, text_type)) for k in keys), \
            'Key bindings should consist of Key and string (unicode) instances.'

        def decorator(func):
            # When a filter is Never, it will always stay disabled, so in that case
            # don't bother putting it in the registry. It will slow down every key
            # press otherwise.
            if not isinstance(filter, Never):
                self.key_bindings.append(
                    _Binding(keys, func, filter=filter, eager=eager))
                self._clear_cache()

            return func
        return decorator
Ejemplo n.º 6
0
    def __init__(self, get_tokens, default_char=None, get_default_char=None,
                 align_right=False, align_center=False, has_focus=False):
        assert default_char is None or isinstance(default_char, Char)
        assert get_default_char is None or callable(get_default_char)
        assert not (default_char and get_default_char)

        self.align_right = to_cli_filter(align_right)
        self.align_center = to_cli_filter(align_center)
        self._has_focus_filter = to_cli_filter(has_focus)

        self.get_tokens = get_tokens

        # Construct `get_default_char` callable.
        if default_char:
            get_default_char = lambda _: default_char
        elif not get_default_char:
            get_default_char = lambda _: Char(' ', Token)

        self.get_default_char = get_default_char

        #: Cache for the content.
        self._content_cache = SimpleCache(maxsize=18)
        self._token_cache = SimpleCache(maxsize=1)
            # Only cache one token list. We don't need the previous item.

        # Render info for the mouse support.
        self._tokens = None
Ejemplo n.º 7
0
    def __init__(self,
                 get_tokens,
                 default_char=None,
                 get_default_char=None,
                 align_right=False,
                 align_center=False,
                 has_focus=False,
                 wrap_lines=True):
        assert default_char is None or isinstance(default_char, Char)
        assert get_default_char is None or callable(get_default_char)
        assert not (default_char and get_default_char)

        self.align_right = to_cli_filter(align_right)
        self.align_center = to_cli_filter(align_center)
        self._has_focus_filter = to_cli_filter(has_focus)
        self.wrap_lines = to_cli_filter(wrap_lines)

        self.get_tokens = get_tokens

        # Construct `get_default_char` callable.
        if default_char:
            get_default_char = lambda _: default_char
        elif not get_default_char:
            get_default_char = lambda _: Char(' ', Token)

        self.get_default_char = get_default_char

        #: Cache for rendered screens.
        self._screen_lru_cache = SimpleLRUCache(maxsize=18)
        self._token_lru_cache = SimpleLRUCache(maxsize=1)
        # Only cache one token list. We don't need the previous item.

        # Render info for the mouse support.
        self._tokens = None  # The last rendered tokens.
        self._pos_to_indexes = None  # Mapping from mouse positions (x,y) to
Ejemplo n.º 8
0
    def __init__(self, min_rows=3, suggested_max_column_width=30, show_meta=True, extra_filter=True):
        show_meta = to_cli_filter(show_meta)
        extra_filter = to_cli_filter(extra_filter)

        # Display filter: show when there are completions but not at the point
        # we are returning the input.
        full_filter = HasCompletions() & ~IsDone() & extra_filter

        any_completion_has_meta = Condition(lambda cli:
                any(c.display_meta for c in cli.current_buffer.complete_state.current_completions))

        # Create child windows.
        completions_window = ConditionalContainer(
            content=Window(
                content=MultiColumnCompletionMenuControl(
                    min_rows=min_rows, suggested_max_column_width=suggested_max_column_width),
                width=LayoutDimension(min=8),
                height=LayoutDimension(min=1)),
            filter=full_filter)

        meta_window = ConditionalContainer(
            content=Window(content=_SelectedCompletionMetaControl()),
            filter=show_meta & full_filter & any_completion_has_meta)

        # Initialise split.
        super(MultiColumnCompletionsMenu, self).__init__([
            completions_window,
            meta_window
        ])
Ejemplo n.º 9
0
    def __init__(self,
                 min_rows=3,
                 suggested_max_column_width=30,
                 show_meta=True,
                 extra_filter=True):
        show_meta = to_cli_filter(show_meta)
        extra_filter = to_cli_filter(extra_filter)

        # Display filter: show when there are completions but not at the point
        # we are returning the input.
        full_filter = HasCompletions() & ~IsDone() & extra_filter

        any_completion_has_meta = Condition(lambda cli: any(
            c.display_meta
            for c in cli.current_buffer.complete_state.current_completions))

        # Create child windows.
        completions_window = ConditionalContainer(content=Window(
            content=MultiColumnCompletionMenuControl(
                min_rows=min_rows,
                suggested_max_column_width=suggested_max_column_width),
            width=LayoutDimension(min=8),
            height=LayoutDimension(min=1)),
                                                  filter=full_filter)

        meta_window = ConditionalContainer(
            content=Window(content=_SelectedCompletionMetaControl()),
            filter=show_meta & full_filter & any_completion_has_meta)

        # Initialise split.
        super(MultiColumnCompletionsMenu,
              self).__init__([completions_window, meta_window])
Ejemplo n.º 10
0
    def __init__(self, content, width=None, height=None, get_width=None,
                 get_height=None, dont_extend_width=False, dont_extend_height=False,
                 left_margins=None, right_margins=None, scroll_offsets=None,
                 allow_scroll_beyond_bottom=False,
                 get_vertical_scroll=None, get_horizontal_scroll=None, always_hide_cursor=False):
        assert isinstance(content, UIControl)
        assert width is None or isinstance(width, LayoutDimension)
        assert height is None or isinstance(height, LayoutDimension)
        assert get_width is None or callable(get_width)
        assert get_height is None or callable(get_height)
        assert width is None or get_width is None
        assert height is None or get_height is None
        assert scroll_offsets is None or isinstance(scroll_offsets, ScrollOffsets)
        assert left_margins is None or all(isinstance(m, Margin) for m in left_margins)
        assert right_margins is None or all(isinstance(m, Margin) for m in right_margins)
        assert get_vertical_scroll is None or callable(get_vertical_scroll)
        assert get_horizontal_scroll is None or callable(get_horizontal_scroll)

        self.allow_scroll_beyond_bottom = to_cli_filter(allow_scroll_beyond_bottom)
        self.always_hide_cursor = to_cli_filter(always_hide_cursor)

        self.content = content
        self.dont_extend_width = dont_extend_width
        self.dont_extend_height = dont_extend_height
        self.left_margins = left_margins or []
        self.right_margins = right_margins or []
        self.scroll_offsets = scroll_offsets or ScrollOffsets()
        self.get_vertical_scroll = get_vertical_scroll
        self.get_horizontal_scroll = get_horizontal_scroll
        self._width = get_width or (lambda cli: width)
        self._height = get_height or (lambda cli: height)

        self.reset()
Ejemplo n.º 11
0
    def __init__(self,
                 buffer_name=DEFAULT_BUFFER,
                 input_processors=None,
                 lexer=None,
                 preview_search=False,
                 wrap_lines=True,
                 menu_position=None,
                 default_char=None):
        assert input_processors is None or all(
            isinstance(i, Processor) for i in input_processors)
        assert menu_position is None or callable(menu_position)
        assert lexer is None or isinstance(lexer, Lexer)

        self.preview_search = to_cli_filter(preview_search)
        self.wrap_lines = to_cli_filter(wrap_lines)

        self.input_processors = input_processors or []
        self.buffer_name = buffer_name
        self.menu_position = menu_position
        self.lexer = lexer or SimpleLexer()
        self.default_char = default_char or Char(token=Token.Transparent)

        #: LRU cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a faily easy way to cache such an expensive operation.
        self._token_lru_cache = SimpleLRUCache(maxsize=8)

        #: Keep a similar cache for rendered screens. (when we scroll up/down
        #: through the screen, or when we change another buffer, we don't want
        #: to recreate the same screen again.)
        self._screen_lru_cache = SimpleLRUCache(maxsize=8)

        self._xy_to_cursor_position = None
        self._last_click_timestamp = None
Ejemplo n.º 12
0
    def __init__(self,
                 get_tokens,
                 default_char=None,
                 get_default_char=None,
                 align_right=False,
                 align_center=False,
                 has_focus=False):
        assert callable(get_tokens)
        assert default_char is None or isinstance(default_char, Char)
        assert get_default_char is None or callable(get_default_char)
        assert not (default_char and get_default_char)

        self.align_right = to_cli_filter(align_right)
        self.align_center = to_cli_filter(align_center)
        self._has_focus_filter = to_cli_filter(has_focus)

        self.get_tokens = get_tokens

        # Construct `get_default_char` callable.
        if default_char:
            get_default_char = lambda _: default_char
        elif not get_default_char:
            get_default_char = lambda _: Char(' ', Token.Transparent)

        self.get_default_char = get_default_char

        #: Cache for the content.
        self._content_cache = SimpleCache(maxsize=18)
        self._token_cache = SimpleCache(maxsize=1)
        # Only cache one token list. We don't need the previous item.

        # Render info for the mouse support.
        self._tokens = None
Ejemplo n.º 13
0
    def __init__(self, get_tokens, default_char=None, align_right=False, align_center=False,
                 has_focus=False):
        assert default_char is None or isinstance(default_char, Char)

        self.get_tokens = get_tokens
        self.default_char = default_char or Char(' ', Token)
        self.align_right = to_cli_filter(align_right)
        self.align_center = to_cli_filter(align_center)
        self._has_focus_filter = to_cli_filter(has_focus)
Ejemplo n.º 14
0
    def __init__(self, registry=None, enable_vi_mode=Never(), vi_state=None,
                 enable_system_bindings=Never(), enable_search=Always(),
                 enable_open_in_editor=Never(), enable_all=Always()):

        assert registry is None or isinstance(registry, Registry)
        assert vi_state is None or isinstance(vi_state, ViState)

        # Create registry.
        self.registry = registry or Registry()

        # Vi state. (Object to keep track of in which Vi mode we are.)
        self.vi_state = vi_state or ViState()

        # Accept both Filters and booleans as input.
        enable_vi_mode = to_cli_filter(enable_vi_mode)
        enable_system_bindings = to_cli_filter(enable_system_bindings)
        enable_open_in_editor = to_cli_filter(enable_open_in_editor)
        enable_all = to_cli_filter(enable_all)

        # Emacs mode filter is the opposite of Vi mode.
        enable_emacs_mode = ~enable_vi_mode

        # Load basic bindings.
        load_basic_bindings(self.registry, enable_all)

        load_basic_system_bindings(self.registry,
            enable_system_bindings & enable_all)

        # Load emacs bindings.
        load_emacs_bindings(self.registry, enable_emacs_mode & enable_all)

        load_emacs_open_in_editor_bindings(
            self.registry, enable_emacs_mode & enable_open_in_editor & enable_all)

        load_emacs_search_bindings(
            self.registry, enable_emacs_mode & enable_search & enable_all)

        load_emacs_system_bindings(
            self.registry, enable_emacs_mode & enable_system_bindings & enable_all)

        # Load Vi bindings.
        load_vi_bindings(self.registry, self.vi_state, enable_visual_key=~enable_open_in_editor,
                         filter=enable_vi_mode & enable_all)

        load_vi_open_in_editor_bindings(
            self.registry, self.vi_state,
            enable_vi_mode & enable_open_in_editor & enable_all)

        load_vi_search_bindings(
            self.registry, self.vi_state,
            enable_vi_mode & enable_search & enable_all)

        load_vi_system_bindings(
            self.registry, self.vi_state,
            enable_vi_mode & enable_system_bindings & enable_all)
    def __init__(self,
                 buffer_name=DEFAULT_BUFFER,
                 input_processors=None,
                 highlighters=None,
                 lexer=None,
                 preview_search=False,
                 search_buffer_name=SEARCH_BUFFER,
                 get_search_state=None,
                 wrap_lines=True,
                 menu_position=None,
                 default_char=None,
                 focus_on_click=False):
        assert input_processors is None or all(
            isinstance(i, Processor) for i in input_processors)
        assert highlighters is None or all(
            isinstance(i, Highlighter) for i in highlighters)
        assert menu_position is None or callable(menu_position)
        assert lexer is None or isinstance(lexer, Lexer)
        assert get_search_state is None or callable(get_search_state)

        self.preview_search = to_cli_filter(preview_search)
        self.get_search_state = get_search_state
        self.wrap_lines = to_cli_filter(wrap_lines)
        self.focus_on_click = to_cli_filter(focus_on_click)

        self.input_processors = input_processors or []
        self.highlighters = highlighters or []
        self.buffer_name = buffer_name
        self.menu_position = menu_position
        self.lexer = lexer or SimpleLexer()
        self.default_char = default_char or Char(token=Token.Transparent)
        self.search_buffer_name = search_buffer_name

        #: Cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a faily easy way to cache such an expensive operation.
        self._token_cache = SimpleCache(maxsize=8)

        #: Keep a similar cache for rendered screens. (when we scroll up/down
        #: through the screen, or when we change another buffer, we don't want
        #: to recreate the same screen again.)
        self._screen_cache = SimpleCache(maxsize=8)

        #: Highlight Cache.
        #: When nothing of the buffer content or processors has changed, but
        #: the highlighting of the selection/search changes,
        self._highlight_cache = SimpleCache(maxsize=8)

        self._xy_to_cursor_position = None
        self._last_click_timestamp = None
Ejemplo n.º 16
0
    def __init__(self,
                 content,
                 width=None,
                 height=None,
                 get_width=None,
                 get_height=None,
                 dont_extend_width=False,
                 dont_extend_height=False,
                 left_margins=None,
                 right_margins=None,
                 scroll_offsets=None,
                 allow_scroll_beyond_bottom=False,
                 get_vertical_scroll=None,
                 get_horizontal_scroll=None,
                 always_hide_cursor=False):
        assert isinstance(content, UIControl)
        assert width is None or isinstance(width, LayoutDimension)
        assert height is None or isinstance(height, LayoutDimension)
        assert get_width is None or callable(get_width)
        assert get_height is None or callable(get_height)
        assert width is None or get_width is None
        assert height is None or get_height is None
        assert scroll_offsets is None or isinstance(scroll_offsets,
                                                    ScrollOffsets)
        assert left_margins is None or all(
            isinstance(m, Margin) for m in left_margins)
        assert right_margins is None or all(
            isinstance(m, Margin) for m in right_margins)
        assert get_vertical_scroll is None or callable(get_vertical_scroll)
        assert get_horizontal_scroll is None or callable(get_horizontal_scroll)

        self.allow_scroll_beyond_bottom = to_cli_filter(
            allow_scroll_beyond_bottom)
        self.always_hide_cursor = to_cli_filter(always_hide_cursor)

        self.content = content
        self.dont_extend_width = dont_extend_width
        self.dont_extend_height = dont_extend_height
        self.left_margins = left_margins or []
        self.right_margins = right_margins or []
        self.scroll_offsets = scroll_offsets or ScrollOffsets()
        self.get_vertical_scroll = get_vertical_scroll
        self.get_horizontal_scroll = get_horizontal_scroll
        self._width = get_width or (lambda cli: width)
        self._height = get_height or (lambda cli: height)

        # Cache for the screens generated by the margin.
        self._margin_cache = SimpleLRUCache(maxsize=8)

        self.reset()
Ejemplo n.º 17
0
    def __init__(self,
                 buffer_name=DEFAULT_BUFFER,
                 input_processors=None,
                 highlighters=None,
                 lexer=None,
                 preview_search=False,
                 search_buffer_name=SEARCH_BUFFER,
                 get_search_state=None,
                 wrap_lines=True,
                 menu_position=None,
                 default_char=None,
                 focus_on_click=False):
        assert input_processors is None or all(isinstance(i, Processor) for i in input_processors)
        assert highlighters is None or all(isinstance(i, Highlighter) for i in highlighters)
        assert menu_position is None or callable(menu_position)
        assert lexer is None or isinstance(lexer, Lexer)
        assert get_search_state is None or callable(get_search_state)

        self.preview_search = to_cli_filter(preview_search)
        self.get_search_state = get_search_state
        self.wrap_lines = to_cli_filter(wrap_lines)
        self.focus_on_click = to_cli_filter(focus_on_click)

        self.input_processors = input_processors or []
        self.highlighters = highlighters or []
        self.buffer_name = buffer_name
        self.menu_position = menu_position
        self.lexer = lexer or SimpleLexer()
        self.default_char = default_char or Char(token=Token.Transparent)
        self.search_buffer_name = search_buffer_name

        #: Cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a faily easy way to cache such an expensive operation.
        self._token_cache = SimpleCache(maxsize=8)

        #: Keep a similar cache for rendered screens. (when we scroll up/down
        #: through the screen, or when we change another buffer, we don't want
        #: to recreate the same screen again.)
        self._screen_cache = SimpleCache(maxsize=8)

        #: Highlight Cache.
        #: When nothing of the buffer content or processors has changed, but
        #: the highlighting of the selection/search changes,
        self._highlight_cache = SimpleCache(maxsize=8)

        self._xy_to_cursor_position = None
        self._last_click_timestamp = None
Ejemplo n.º 18
0
    def __init__(self,
                 get_tokens,
                 default_char=None,
                 align_right=False,
                 align_center=False,
                 has_focus=False,
                 wrap_lines=True):
        assert default_char is None or isinstance(default_char, Char)

        self.get_tokens = get_tokens
        self.default_char = default_char or Char(' ', Token)
        self.align_right = to_cli_filter(align_right)
        self.align_center = to_cli_filter(align_center)
        self._has_focus_filter = to_cli_filter(has_focus)
        self.wrap_lines = to_cli_filter(wrap_lines)
Ejemplo n.º 19
0
    def __init__(
            self,
            registry=None,  # XXX: not used anymore.
            enable_vi_mode=None,  # (`enable_vi_mode` is deprecated.)
            enable_all=True,  #
            get_search_state=None,
            enable_abort_and_exit_bindings=False,
            enable_system_bindings=False,
            enable_search=False,
            enable_open_in_editor=False,
            enable_extra_page_navigation=False,
            enable_auto_suggest_bindings=False):

        assert registry is None or isinstance(registry, Registry)
        assert get_search_state is None or callable(get_search_state)
        enable_all = to_cli_filter(enable_all)

        defaults = load_key_bindings(
            get_search_state=get_search_state,
            enable_abort_and_exit_bindings=enable_abort_and_exit_bindings,
            enable_system_bindings=enable_system_bindings,
            enable_search=enable_search,
            enable_open_in_editor=enable_open_in_editor,
            enable_extra_page_navigation=enable_extra_page_navigation,
            enable_auto_suggest_bindings=enable_auto_suggest_bindings)

        # Note, we wrap this whole thing again in a MergedRegistry, because we
        # don't want the `enable_all` settings to apply on items that were
        # added to the registry as a whole.
        self.registry = MergedRegistry(
            [ConditionalRegistry(defaults, enable_all)])
    def __init__(
        self,
        registry=None,  # XXX: not used anymore.
        enable_vi_mode=None,  # (`enable_vi_mode` is deprecated.)
        enable_all=True,  #
        get_search_state=None,
        enable_abort_and_exit_bindings=False,
        enable_system_bindings=False,
        enable_search=False,
        enable_open_in_editor=False,
        enable_extra_page_navigation=False,
        enable_auto_suggest_bindings=False,
    ):

        assert registry is None or isinstance(registry, Registry)
        assert get_search_state is None or callable(get_search_state)
        enable_all = to_cli_filter(enable_all)

        defaults = load_key_bindings(
            get_search_state=get_search_state,
            enable_abort_and_exit_bindings=enable_abort_and_exit_bindings,
            enable_system_bindings=enable_system_bindings,
            enable_search=enable_search,
            enable_open_in_editor=enable_open_in_editor,
            enable_extra_page_navigation=enable_extra_page_navigation,
            enable_auto_suggest_bindings=enable_auto_suggest_bindings,
        )

        # Note, we wrap this whole thing again in a MergedRegistry, because we
        # don't want the `enable_all` settings to apply on items that were
        # added to the registry as a whole.
        self.registry = MergedRegistry([ConditionalRegistry(defaults, enable_all)])
Ejemplo n.º 21
0
    def __init__(self, max_height=None, scroll_offset=0, extra_filter=True, display_arrows=False):
        extra_filter = to_cli_filter(extra_filter)
        display_arrows = to_cli_filter(display_arrows)

        super(CompletionsMenu, self).__init__(
            content=Window(
                content=CompletionsMenuControl(),
                width=LayoutDimension(min=8),
                height=LayoutDimension(min=1, max=max_height),
                scroll_offsets=ScrollOffsets(top=scroll_offset, bottom=scroll_offset),
                right_margins=[ScrollbarMargin(display_arrows=display_arrows)],
                dont_extend_width=True,
            ),
            # Show when there are completions but not at the point we are
            # returning the input.
            filter=HasCompletions() & ~IsDone() & extra_filter)
Ejemplo n.º 22
0
 def __init__(self,
              preview_search=False,
              search_buffer_name=SEARCH_BUFFER,
              get_search_state=None):
     self.preview_search = to_cli_filter(preview_search)
     self.search_buffer_name = search_buffer_name
     self.get_search_state = get_search_state
Ejemplo n.º 23
0
    def __init__(self, max_height=None, scroll_offset=0, extra_filter=True, display_arrows=False):
        extra_filter = to_cli_filter(extra_filter)
        display_arrows = to_cli_filter(display_arrows)

        super(CompletionsMenu, self).__init__(
            content=Window(
                content=CompletionsMenuControl(),
                width=LayoutDimension(min=8),
                height=LayoutDimension(min=1, max=max_height),
                scroll_offsets=ScrollOffsets(top=scroll_offset, bottom=scroll_offset),
                right_margins=[ScrollbarMargin(display_arrows=display_arrows)],
                dont_extend_width=True,
            ),
            # Show when there are completions but not at the point we are
            # returning the input.
            filter=HasCompletions() & ~IsDone() & extra_filter)
    def __init__(self, registry=None, filter=True):
        registry = registry or Registry()
        assert isinstance(registry, BaseRegistry)

        _AddRemoveMixin.__init__(self)

        self.registry = registry
        self.filter = to_cli_filter(filter)
Ejemplo n.º 25
0
    def __init__(self, registry=None, filter=True):
        registry = registry or Registry()
        assert isinstance(registry, BaseRegistry)

        _AddRemoveMixin.__init__(self)

        self.registry = registry
        self.filter = to_cli_filter(filter)
Ejemplo n.º 26
0
    def __init__(self, get_prompt_tokens, get_continuation_tokens=None,
                 show_numbers=False):
        assert callable(get_prompt_tokens)
        assert get_continuation_tokens is None or callable(get_continuation_tokens)
        show_numbers = to_cli_filter(show_numbers)

        self.get_prompt_tokens = get_prompt_tokens
        self.get_continuation_tokens = get_continuation_tokens
        self.show_numbers = show_numbers
    def __init__(self, get_prompt_tokens, get_continuation_tokens=None,
                 show_numbers=False):
        assert callable(get_prompt_tokens)
        assert get_continuation_tokens is None or callable(get_continuation_tokens)
        show_numbers = to_cli_filter(show_numbers)

        self.get_prompt_tokens = get_prompt_tokens
        self.get_continuation_tokens = get_continuation_tokens
        self.show_numbers = show_numbers
Ejemplo n.º 28
0
    def __init__(self,
                 get_tokens,
                 default_char=None,
                 align_right=False,
                 has_focus=False):
        assert default_char is None or isinstance(default_char, Char)

        self.get_tokens = get_tokens
        self.default_char = default_char or Char(' ', Token)
        self.align_right = align_right
        self._has_focus_filter = to_cli_filter(has_focus)
Ejemplo n.º 29
0
    def __init__(self, output, use_alternate_screen=False, mouse_support=False):
        assert isinstance(output, Output)

        self.output = output
        self.use_alternate_screen = use_alternate_screen
        self.mouse_support = to_cli_filter(mouse_support)

        self._in_alternate_screen = False
        self._mouse_support_enabled = False

        self.reset(_scroll=True)
Ejemplo n.º 30
0
def load_extra_emacs_page_navigation_bindings(registry, filter=None):
    """
    Key bindings, for scrolling up and down through pages.
    This are separate bindings, because GNU readline doesn't have them.
    """
    filter = to_cli_filter(filter)
    handle = create_handle_decorator(registry, filter & EmacsMode())

    handle(Keys.ControlV)(scroll_page_down)
    handle(Keys.PageDown)(scroll_page_down)
    handle(Keys.Escape, 'v')(scroll_page_up)
    handle(Keys.PageUp)(scroll_page_up)
Ejemplo n.º 31
0
    def __init__(self, get_tokens, default_char=None, get_default_char=None,
                 align_right=False, align_center=False,
                 has_focus=False, wrap_lines=True):
        assert default_char is None or isinstance(default_char, Char)
        assert get_default_char is None or callable(get_default_char)
        assert not (default_char and get_default_char)

        self.align_right = to_cli_filter(align_right)
        self.align_center = to_cli_filter(align_center)
        self._has_focus_filter = to_cli_filter(has_focus)
        self.wrap_lines = to_cli_filter(wrap_lines)

        self.get_tokens = get_tokens

        # Construct `get_default_char` callable.
        if default_char:
            get_default_char = lambda _: default_char
        elif not get_default_char:
            get_default_char = lambda _: Char(' ', Token)

        self.get_default_char = get_default_char
Ejemplo n.º 32
0
def load_extra_emacs_page_navigation_bindings(registry, filter=None):
    """
    Key bindings, for scrolling up and down through pages.
    This are separate bindings, because GNU readline doesn't have them.
    """
    filter = to_cli_filter(filter)
    handle = create_handle_decorator(registry, filter & EmacsMode())

    handle(Keys.ControlV)(scroll_page_down)
    handle(Keys.PageDown)(scroll_page_down)
    handle(Keys.Escape, 'v')(scroll_page_up)
    handle(Keys.PageUp)(scroll_page_up)
Ejemplo n.º 33
0
    def __init__(self, content, width=None, height=None, get_width=None,
                 get_height=None, filter=True, dont_extend_width=False,
                 dont_extend_height=False, scroll_offset=0, allow_scroll_beyond_bottom=False):
        assert isinstance(content, UIControl)
        assert width is None or isinstance(width, LayoutDimension)
        assert height is None or isinstance(height, LayoutDimension)
        assert get_width is None or callable(get_width)
        assert get_height is None or callable(get_height)
        assert width is None or get_width is None
        assert height is None or get_height is None
        assert isinstance(scroll_offset, Integer)

        self.filter = to_cli_filter(filter)
        self.allow_scroll_beyond_bottom = to_cli_filter(allow_scroll_beyond_bottom)

        self.content = content
        self.dont_extend_width = dont_extend_width
        self.dont_extend_height = dont_extend_height
        self.scroll_offset = scroll_offset
        self._width = get_width or (lambda cli: width)
        self._height = get_height or (lambda cli: height)

        self.reset()
Ejemplo n.º 34
0
    def __init__(self, pygments_lexer_cls, sync_from_start=True, syntax_sync=None):
        assert syntax_sync is None or isinstance(syntax_sync, SyntaxSync)

        self.pygments_lexer_cls = pygments_lexer_cls
        self.sync_from_start = to_cli_filter(sync_from_start)

        # Instantiate the Pygments lexer.
        self.pygments_lexer = pygments_lexer_cls(
            stripnl=False,
            stripall=False,
            ensurenl=False)

        # Create syntax sync instance.
        self.syntax_sync = syntax_sync or RegexSync.from_pygments_lexer_cls(pygments_lexer_cls)
Ejemplo n.º 35
0
    def __init__(self, pygments_lexer_cls, sync_from_start=True, syntax_sync=None):
        assert syntax_sync is None or isinstance(syntax_sync, SyntaxSync)

        self.pygments_lexer_cls = pygments_lexer_cls
        self.sync_from_start = to_cli_filter(sync_from_start)

        # Instantiate the Pygments lexer.
        self.pygments_lexer = pygments_lexer_cls(
            stripnl=False,
            stripall=False,
            ensurenl=False)

        # Create syntax sync instance.
        self.syntax_sync = syntax_sync or RegexSync.from_pygments_lexer_cls(pygments_lexer_cls)
Ejemplo n.º 36
0
    def __init__(self,
                 input_processors=None,
                 lexer=None,
                 show_line_numbers=False,
                 preview_search=False,
                 buffer_name=DEFAULT_BUFFER,
                 default_token=Token,
                 menu_position=None):
        assert input_processors is None or all(isinstance(i, Processor) for i in input_processors)
        assert menu_position is None or callable(menu_position)

        self.show_line_numbers = to_cli_filter(show_line_numbers)
        self.preview_search = to_cli_filter(preview_search)

        self.input_processors = input_processors or []
        self.buffer_name = buffer_name
        self.default_token = default_token
        self.menu_position = menu_position

        if lexer:
            self.lexer = lexer(
                stripnl=False,
                stripall=False,
                ensurenl=False)
        else:
            self.lexer = None

        #: LRU cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a faily easy way to cache such an expensive operation.
        self._token_lru_cache = _SimpleLRUCache(maxsize=8)

        #: Keep a similar cache for rendered screens. (when we scroll up/down
        #: through the screen, or when we change another buffer, we don't want
        #: to recreate the same screen again.)
        self._screen_lru_cache = _SimpleLRUCache(maxsize=8)
Ejemplo n.º 37
0
    def __init__(self,
                 buffer_name=DEFAULT_BUFFER,
                 input_processors=None,
                 lexer=None,
                 preview_search=False,
                 search_buffer_name=SEARCH_BUFFER,
                 get_search_state=None,
                 menu_position=None,
                 default_char=None,
                 focus_on_click=False):
        assert input_processors is None or all(isinstance(i, Processor) for i in input_processors)
        assert menu_position is None or callable(menu_position)
        assert lexer is None or isinstance(lexer, Lexer)
        assert get_search_state is None or callable(get_search_state)
        assert default_char is None or isinstance(default_char, Char)

        self.preview_search = to_cli_filter(preview_search)
        self.get_search_state = get_search_state
        self.focus_on_click = to_cli_filter(focus_on_click)

        self.input_processors = input_processors or []
        self.buffer_name = buffer_name
        self.menu_position = menu_position
        self.lexer = lexer or SimpleLexer()
        self.default_char = default_char or Char(token=Token.Transparent)
        self.search_buffer_name = search_buffer_name

        #: Cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a faily easy way to cache such an expensive operation.
        self._token_cache = SimpleCache(maxsize=8)
        self._processed_token_cache = SimpleCache(maxsize=8)

        self._xy_to_cursor_position = None
        self._last_click_timestamp = None
        self._last_get_processed_line = None
Ejemplo n.º 38
0
    def __init__(self,
                 buffer_name=DEFAULT_BUFFER,
                 input_processors=None,
                 lexer=None,
                 preview_search=False,
                 search_buffer_name=SEARCH_BUFFER,
                 get_search_state=None,
                 menu_position=None,
                 default_char=None,
                 focus_on_click=False):
        assert input_processors is None or all(
            isinstance(i, Processor) for i in input_processors)
        assert menu_position is None or callable(menu_position)
        assert lexer is None or isinstance(lexer, Lexer)
        assert get_search_state is None or callable(get_search_state)
        assert default_char is None or isinstance(default_char, Char)

        self.preview_search = to_cli_filter(preview_search)
        self.get_search_state = get_search_state
        self.focus_on_click = to_cli_filter(focus_on_click)

        self.input_processors = input_processors or []
        self.buffer_name = buffer_name
        self.menu_position = menu_position
        self.lexer = lexer or SimpleLexer()
        self.default_char = default_char or Char(token=Token.Transparent)
        self.search_buffer_name = search_buffer_name

        #: Cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a faily easy way to cache such an expensive operation.
        self._token_cache = SimpleCache(maxsize=8)

        self._xy_to_cursor_position = None
        self._last_click_timestamp = None
        self._last_get_processed_line = None
Ejemplo n.º 39
0
    def __init__(self, style, output, use_alternate_screen=False, mouse_support=False):
        assert isinstance(style, Style)
        assert isinstance(output, Output)

        self.style = style
        self.output = output
        self.use_alternate_screen = use_alternate_screen
        self.mouse_support = to_cli_filter(mouse_support)

        self._in_alternate_screen = False
        self._mouse_support_enabled = False
        self._bracketed_paste_enabled = False

        # Waiting for CPR flag. True when we send the request, but didn't got a
        # response.
        self.waiting_for_cpr = False

        self.reset(_scroll=True)
Ejemplo n.º 40
0
    def __init__(self, style, output, use_alternate_screen=False, mouse_support=False):
        assert isinstance(style, Style)
        assert isinstance(output, Output)

        self.style = style
        self.output = output
        self.use_alternate_screen = use_alternate_screen
        self.mouse_support = to_cli_filter(mouse_support)

        self._in_alternate_screen = False
        self._mouse_support_enabled = False
        self._bracketed_paste_enabled = False

        # Waiting for CPR flag. True when we send the request, but didn't got a
        # response.
        self.waiting_for_cpr = False

        self.reset(_scroll=True)
Ejemplo n.º 41
0
    def __init__(self, content, width=None, height=None, get_width=None,
                 get_height=None, dont_extend_width=False,
                 dont_extend_height=False, scroll_offset=0, allow_scroll_beyond_bottom=False):
        assert isinstance(content, UIControl)
        assert width is None or isinstance(width, LayoutDimension)
        assert height is None or isinstance(height, LayoutDimension)
        assert get_width is None or callable(get_width)
        assert get_height is None or callable(get_height)
        assert width is None or get_width is None
        assert height is None or get_height is None
        assert isinstance(scroll_offset, Integer)

        self.allow_scroll_beyond_bottom = to_cli_filter(allow_scroll_beyond_bottom)

        self.content = content
        self.dont_extend_width = dont_extend_width
        self.dont_extend_height = dont_extend_height
        self.scroll_offset = scroll_offset
        self._width = get_width or (lambda cli: width)
        self._height = get_height or (lambda cli: height)

        self.reset()
Ejemplo n.º 42
0
    def __init__(self,
                 content,
                 width=None,
                 height=None,
                 get_width=None,
                 get_height=None,
                 dont_extend_width=False,
                 dont_extend_height=False,
                 left_margins=None,
                 right_margins=None,
                 scroll_offsets=None,
                 allow_scroll_beyond_bottom=False):
        assert isinstance(content, UIControl)
        assert width is None or isinstance(width, LayoutDimension)
        assert height is None or isinstance(height, LayoutDimension)
        assert get_width is None or callable(get_width)
        assert get_height is None or callable(get_height)
        assert width is None or get_width is None
        assert height is None or get_height is None
        assert scroll_offsets is None or isinstance(scroll_offsets,
                                                    ScrollOffsets)
        assert left_margins is None or all(
            isinstance(m, Margin) for m in left_margins)
        assert right_margins is None or all(
            isinstance(m, Margin) for m in right_margins)

        self.allow_scroll_beyond_bottom = to_cli_filter(
            allow_scroll_beyond_bottom)

        self.content = content
        self.dont_extend_width = dont_extend_width
        self.dont_extend_height = dont_extend_height
        self.left_margins = left_margins or []
        self.right_margins = right_margins or []
        self.scroll_offsets = scroll_offsets or ScrollOffsets()
        self._width = get_width or (lambda cli: width)
        self._height = get_height or (lambda cli: height)

        self.reset()
Ejemplo n.º 43
0
 def __init__(self, preview_search=False):
     self.preview_search = to_cli_filter(preview_search)
def CreatePromptLayout(config,
                       lexer=None,
                       is_password=False,
                       get_prompt_tokens=None,
                       get_continuation_tokens=None,
                       get_bottom_status_tokens=None,
                       get_bottom_toolbar_tokens=None,
                       extra_input_processors=None,
                       multiline=False,
                       show_help=True,
                       wrap_lines=True):
    """Create a container instance for the prompt."""
    assert get_bottom_status_tokens is None or callable(
        get_bottom_status_tokens)
    assert get_bottom_toolbar_tokens is None or callable(
        get_bottom_toolbar_tokens)
    assert get_prompt_tokens is None or callable(get_prompt_tokens)
    assert not (config.prompt and get_prompt_tokens)

    multi_column_completion_menu = filters.to_cli_filter(
        config.multi_column_completion_menu)
    multiline = filters.to_cli_filter(multiline)

    if get_prompt_tokens is None:
        get_prompt_tokens = lambda _: [(token.Token.Prompt, config.prompt)]

    has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = (
        shortcuts._split_multiline_prompt(get_prompt_tokens))  # pylint: disable=protected-access
    # TODO(b/35347840): reimplement _split_multiline_prompt to remove
    #                   protected-access.

    # Create processors list.
    input_processors = [
        processors.ConditionalProcessor(
            # By default, only highlight search when the search
            # input has the focus. (Note that this doesn't mean
            # there is no search: the Vi 'n' binding for instance
            # still allows to jump to the next match in
            # navigation mode.)
            processors.HighlightSearchProcessor(preview_search=True),
            filters.HasFocus(enums.SEARCH_BUFFER)),
        processors.HighlightSelectionProcessor(),
        processors.ConditionalProcessor(
            processors.AppendAutoSuggestion(),
            filters.HasFocus(enums.DEFAULT_BUFFER)
            & ~filters.IsDone()),
        processors.ConditionalProcessor(processors.PasswordProcessor(),
                                        is_password),
    ]

    if extra_input_processors:
        input_processors.extend(extra_input_processors)

    # Show the prompt before the input using the DefaultPrompt processor.
    # This also replaces it with reverse-i-search and 'arg' when required.
    # (Only for single line mode.)
    # (DefaultPrompt should always be at the end of the processors.)
    input_processors.append(
        processors.ConditionalProcessor(
            prompt.DefaultPrompt(get_prompt_tokens_2), ~multiline))

    # Create toolbars
    toolbars = []
    if config.fixed_prompt_position:
        help_height = dimension.LayoutDimension.exact(config.help_lines)
        help_filter = (show_help & ~filters.IsDone()
                       & filters.RendererHeightIsKnown())
    else:
        help_height = dimension.LayoutDimension(preferred=config.help_lines,
                                                max=config.help_lines)
        help_filter = (show_help & UserTypingFilter & ~filters.IsDone()
                       & filters.RendererHeightIsKnown())
    toolbars.append(
        containers.ConditionalContainer(layout.HSplit([
            layout.Window(
                controls.FillControl(char=screen.Char('_', token.Token.HSep)),
                height=dimension.LayoutDimension.exact(1)),
            layout.Window(help_window.HelpWindowControl(
                default_char=screen.Char(' ', token.Token.Toolbar)),
                          height=help_height),
        ]),
                                        filter=help_filter))
    if (config.bottom_status_line and get_bottom_status_tokens
            or config.bottom_bindings_line and get_bottom_toolbar_tokens):
        windows = []
        windows.append(
            layout.Window(
                controls.FillControl(char=screen.Char('_', token.Token.HSep)),
                height=dimension.LayoutDimension.exact(1)))
        if config.bottom_status_line and get_bottom_status_tokens:
            windows.append(
                layout.Window(controls.TokenListControl(
                    get_bottom_status_tokens,
                    default_char=screen.Char(' ', token.Token.Toolbar)),
                              height=dimension.LayoutDimension.exact(1)))
        if config.bottom_bindings_line and get_bottom_toolbar_tokens:
            windows.append(
                layout.Window(controls.TokenListControl(
                    get_bottom_toolbar_tokens,
                    default_char=screen.Char(' ', token.Token.Toolbar)),
                              height=dimension.LayoutDimension.exact(1)))
        toolbars.append(
            containers.ConditionalContainer(layout.HSplit(windows),
                                            filter=~filters.IsDone()
                                            & filters.RendererHeightIsKnown()))

    def GetHeight(cli):
        """Determine the height for the input buffer."""
        # If there is an autocompletion menu to be shown, make sure that our
        # layout has at least a minimal height in order to display it.
        if cli.config.completion_menu_lines and not cli.is_done:
            # Reserve the space, either when there are completions, or when
            # `complete_while_typing` is true and we expect completions very
            # soon.
            buf = cli.current_buffer
            # if UserTypingFilter(cli) or not buf.text or buf.complete_state:
            if UserTypingFilter(cli) or buf.complete_state:
                return dimension.LayoutDimension(
                    min=cli.config.completion_menu_lines + 1)
        return dimension.LayoutDimension()

    # Create and return Container instance.
    return layout.HSplit([
        # The main input, with completion menus floating on top of it.
        containers.FloatContainer(
            layout.HSplit([
                containers.ConditionalContainer(
                    layout.Window(
                        controls.TokenListControl(get_prompt_tokens_1),
                        dont_extend_height=True,
                        wrap_lines=wrap_lines,
                    ),
                    filters.Condition(has_before_tokens),
                ),
                layout.Window(
                    controls.BufferControl(
                        input_processors=input_processors,
                        lexer=lexer,
                        # Enable preview_search, we want to have immediate
                        # feedback in reverse-i-search mode.
                        preview_search=True,
                    ),
                    get_height=GetHeight,
                    left_margins=[
                        # In multiline mode, use the window margin to display
                        # the prompt and continuation tokens.
                        margins.ConditionalMargin(
                            margins.PromptMargin(get_prompt_tokens_2,
                                                 get_continuation_tokens),
                            filter=multiline,
                        ),
                    ],
                    wrap_lines=wrap_lines,
                ),
            ]),
            [
                # Completion menus.
                layout.Float(
                    xcursor=True,
                    ycursor=True,
                    content=menus.CompletionsMenu(
                        max_height=16,
                        scroll_offset=1,
                        extra_filter=(filters.HasFocus(enums.DEFAULT_BUFFER)
                                      & ~multi_column_completion_menu),
                    ),
                ),
                layout.Float(
                    ycursor=True,
                    content=menus.MultiColumnCompletionsMenu(
                        show_meta=True,
                        extra_filter=(filters.HasFocus(enums.DEFAULT_BUFFER)
                                      & multi_column_completion_menu),
                    ),
                ),
            ],
        ),
        pt_toolbars.ValidationToolbar(),
        pt_toolbars.SystemToolbar(),

        # In multiline mode, we use two toolbars for 'arg' and 'search'.
        containers.ConditionalContainer(pt_toolbars.ArgToolbar(), multiline),
        containers.ConditionalContainer(pt_toolbars.SearchToolbar(),
                                        multiline),
    ] + toolbars)
Ejemplo n.º 45
0
def load_vi_bindings(registry, get_vi_state, enable_visual_key=Always(), get_search_state=None, filter=None):
    """
    Vi extensions.

    # Overview of Readline Vi commands:
    # http://www.catonmat.net/download/bash-vi-editing-mode-cheat-sheet.pdf

    :param get_vi_state: Callable that takes a CommandLineInterface instances and returns the used ViState.
    :param enable_visual_key: Filter to enable lowercase 'v' bindings. A reason to disable these
         are to support open-in-editor functionality. These key bindings conflict.
     :param get_search_state: None or a callable that takes a CommandLineInterface and returns a SearchState.
    """
    # Note: Some key bindings have the "~IsReadOnly()" filter added. This
    #       prevents the handler to be executed when the focus is on a
    #       read-only buffer.
    #       This is however only required for those that change the ViState to
    #       INSERT mode. The `Buffer` class itself throws the
    #       `EditReadOnlyBuffer` exception for any text operations which is
    #       handled correctly. There is no need to add "~IsReadOnly" to all key
    #       bindings that do text manipulation.

    assert callable(get_vi_state)
    enable_visual_key = to_cli_filter(enable_visual_key)

    # Default get_search_state.
    if get_search_state is None:
        def get_search_state(cli): return cli.search_state

    handle = create_handle_decorator(registry, filter)

    insert_mode = ViStateFilter(get_vi_state, InputMode.INSERT) & ~ filters.HasSelection()
    navigation_mode = ViStateFilter(get_vi_state, InputMode.NAVIGATION) & ~ filters.HasSelection()
    replace_mode = ViStateFilter(get_vi_state, InputMode.REPLACE) & ~ filters.HasSelection()
    selection_mode = filters.HasSelection()

    vi_transform_functions = [
        # Rot 13 transformation
        (('g', '?'), lambda string: codecs.encode(string, 'rot_13')),

        # To lowercase
        (('g', 'u'), lambda string: string.lower()),

        # To uppercase.
        (('g', 'U'), lambda string: string.upper()),

        # Swap case.
        # (XXX: If we would implement 'tildeop', the 'g' prefix is not required.)
        (('g', '~'), lambda string: string.swapcase()),
    ]

    def check_cursor_position(event):
        """
        After every command, make sure that if we are in navigation mode, we
        never put the cursor after the last character of a line. (Unless it's
        an empty line.)
        """
        buffer = event.current_buffer

        if (
                (filter is None or filter(event.cli)) and  # First make sure that this key bindings are active.

                get_vi_state(event.cli).input_mode == InputMode.NAVIGATION and
                buffer.document.is_cursor_at_the_end_of_line and
                len(buffer.document.current_line) > 0):
            buffer.cursor_position -= 1

    registry.on_handler_called += check_cursor_position

    @handle(Keys.Escape)
    def _(event):
        """
        Escape goes to vi navigation mode.
        """
        buffer = event.current_buffer
        vi_state = get_vi_state(event.cli)

        if vi_state.input_mode in (InputMode.INSERT, InputMode.REPLACE):
            buffer.cursor_position += buffer.document.get_cursor_left_position()

        vi_state.input_mode = InputMode.NAVIGATION

        if bool(buffer.selection_state):
            buffer.exit_selection()

    @handle('k', filter=selection_mode)
    def _(event):
        """
        Arrow up in selection mode.
        """
        event.current_buffer.cursor_up(count=event.arg)

    @handle('j', filter=selection_mode)
    def _(event):
        """
        Arrow down in selection mode.
        """
        event.current_buffer.cursor_down(count=event.arg)

    @handle('k', filter=navigation_mode)
    @handle(Keys.Up, filter=navigation_mode)
    @handle(Keys.ControlP, filter=navigation_mode)
    def _(event):
        """
        Arrow up and ControlP in navigation mode go up.
        """
        b = event.current_buffer
        b.auto_up(count=event.arg)

    @handle('j', filter=navigation_mode)
    @handle(Keys.Down, filter=navigation_mode)
    @handle(Keys.ControlN, filter=navigation_mode)
    def _(event):
        """
        Arrow down and Control-N in navigation mode.
        """
        b = event.current_buffer
        b.auto_down(count=event.arg)

    @handle(Keys.Backspace, filter=navigation_mode)
    def _(event):
        """
        In navigation-mode, move cursor.
        """
        event.current_buffer.cursor_position += \
            event.current_buffer.document.get_cursor_left_position(count=event.arg)

    @handle(Keys.ControlV, Keys.Any, filter=insert_mode)
    def _(event):
        """
        Insert a character literally (quoted insert).
        """
        event.current_buffer.insert_text(event.data, overwrite=False)

    @handle(Keys.ControlN, filter=insert_mode)
    def _(event):
        b = event.current_buffer

        if b.complete_state:
            b.complete_next()
        else:
            event.cli.start_completion(select_first=True)

    @handle(Keys.ControlP, filter=insert_mode)
    def _(event):
        """
        Control-P: To previous completion.
        """
        b = event.current_buffer

        if b.complete_state:
            b.complete_previous()
        else:
            event.cli.start_completion(select_last=True)

    @handle(Keys.ControlY, filter=insert_mode)
    def _(event):
        """
        Accept current completion.
        """
        event.current_buffer.complete_state = None

    @handle(Keys.ControlE, filter=insert_mode)
    def _(event):
        """
        Cancel completion. Go back to originally typed text.
        """
        event.current_buffer.cancel_completion()

    @handle(Keys.ControlJ, filter=navigation_mode)
    def _(event):
        """
        In navigation mode, pressing enter will always return the input.
        """
        b = event.current_buffer

        if b.accept_action.is_returnable:
            b.accept_action.validate_and_handle(event.cli, b)

    # ** In navigation mode **

    # List of navigation commands: http://hea-www.harvard.edu/~fine/Tech/vi.html

    @handle(Keys.Insert, filter=navigation_mode)
    def _(event):
        " Presing the Insert key. "
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('a', filter=navigation_mode & ~IsReadOnly())
            # ~IsReadOnly, because we want to stay in navigation mode for
            # read-only buffers.
    def _(event):
        event.current_buffer.cursor_position += event.current_buffer.document.get_cursor_right_position()
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('A', filter=navigation_mode & ~IsReadOnly())
    def _(event):
        event.current_buffer.cursor_position += event.current_buffer.document.get_end_of_line_position()
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('C', filter=navigation_mode & ~IsReadOnly())
    def _(event):
        """
        # Change to end of line.
        # Same as 'c$' (which is implemented elsewhere.)
        """
        buffer = event.current_buffer

        deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
        event.cli.clipboard.set_text(deleted)
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('c', 'c', filter=navigation_mode & ~IsReadOnly())
    @handle('S', filter=navigation_mode & ~IsReadOnly())
    def _(event):  # TODO: implement 'arg'
        """
        Change current line
        """
        buffer = event.current_buffer

        # We copy the whole line.
        data = ClipboardData(buffer.document.current_line, SelectionType.LINES)
        event.cli.clipboard.set_data(data)

        # But we delete after the whitespace
        buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)
        buffer.delete(count=buffer.document.get_end_of_line_position())
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('D', filter=navigation_mode)
    def _(event):
        buffer = event.current_buffer
        deleted = buffer.delete(count=buffer.document.get_end_of_line_position())
        event.cli.clipboard.set_text(deleted)

    @handle('d', 'd', filter=navigation_mode)
    def _(event):
        """
        Delete line. (Or the following 'n' lines.)
        """
        buffer = event.current_buffer

        # Split string in before/deleted/after text.
        lines = buffer.document.lines

        before = '\n'.join(lines[:buffer.document.cursor_position_row])
        deleted = '\n'.join(lines[buffer.document.cursor_position_row: buffer.document.cursor_position_row + event.arg])
        after = '\n'.join(lines[buffer.document.cursor_position_row + event.arg:])

        # Set new text.
        if before and after:
            before = before + '\n'

        # Set text and cursor position.
        buffer.document = Document(
            text=before + after,
            # Cursor At the start of the first 'after' line, after the leading whitespace.
            cursor_position = len(before) + len(after) - len(after.lstrip(' ')))

        # Set clipboard data
        event.cli.clipboard.set_data(ClipboardData(deleted, SelectionType.LINES))

    @handle('i', filter=navigation_mode & ~IsReadOnly())
    def _(event):
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('I', filter=navigation_mode & ~IsReadOnly())
    def _(event):
        get_vi_state(event.cli).input_mode = InputMode.INSERT
        event.current_buffer.cursor_position += event.current_buffer.document.get_start_of_line_position(after_whitespace=True)

    @handle('J', filter=navigation_mode)
    def _(event):
        """ Join lines. """
        for i in range(event.arg):
            event.current_buffer.join_next_line()

    @handle('J', filter=selection_mode)
    def _(event):
        """ Join selected lines. """
        event.current_buffer.join_selected_lines()

    @handle('n', filter=navigation_mode)
    def _(event):  # XXX: use `change_delete_move_yank_handler`
        """
        Search next.
        """
        event.current_buffer.apply_search(
            get_search_state(event.cli), include_current_position=False,
            count=event.arg)

    @handle('N', filter=navigation_mode)
    def _(event):  # TODO: use `change_delete_move_yank_handler`
        """
        Search previous.
        """
        event.current_buffer.apply_search(
            ~get_search_state(event.cli), include_current_position=False,
            count=event.arg)

    @handle('p', filter=navigation_mode)
    def _(event):
        """
        Paste after
        """
        event.current_buffer.paste_clipboard_data(
            event.cli.clipboard.get_data(),
            count=event.arg)

    @handle('P', filter=navigation_mode)
    def _(event):
        """
        Paste before
        """
        event.current_buffer.paste_clipboard_data(
            event.cli.clipboard.get_data(),
            before=True,
            count=event.arg)

    @handle('r', Keys.Any, filter=navigation_mode)
    def _(event):
        """
        Replace single character under cursor
        """
        event.current_buffer.insert_text(event.data * event.arg, overwrite=True)
        event.current_buffer.cursor_position -= 1

    @handle('R', filter=navigation_mode)
    def _(event):
        """
        Go to 'replace'-mode.
        """
        get_vi_state(event.cli).input_mode = InputMode.REPLACE

    @handle('s', filter=navigation_mode & ~IsReadOnly())
    def _(event):
        """
        Substitute with new text
        (Delete character(s) and go to insert mode.)
        """
        text = event.current_buffer.delete(count=event.arg)
        event.cli.clipboard.set_text(text)
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('u', filter=navigation_mode, save_before=(lambda e: False))
    def _(event):
        for i in range(event.arg):
            event.current_buffer.undo()

    @handle('V', filter=navigation_mode)
    def _(event):
        """
        Start lines selection.
        """
        event.current_buffer.start_selection(selection_type=SelectionType.LINES)

    @handle(Keys.ControlV, filter=navigation_mode)
    def _(event):
        " Enter block selection mode. "
        event.current_buffer.start_selection(selection_type=SelectionType.BLOCK)

    @handle('V', filter=selection_mode)
    def _(event):
        """
        Exit line selection mode, or go from non line selection mode to line
        selection mode.
        """
        selection_state = event.current_buffer.selection_state

        if selection_state.type != SelectionType.LINES:
            selection_state.type = SelectionType.LINES
        else:
            event.current_buffer.exit_selection()

    @handle('v', filter=navigation_mode & enable_visual_key)
    def _(event):
        " Enter character selection mode. "
        event.current_buffer.start_selection(selection_type=SelectionType.CHARACTERS)

    @handle('v', filter=selection_mode)
    def _(event):
        """
        Exit character selection mode, or go from non-character-selection mode
        to character selection mode.
        """
        selection_state = event.current_buffer.selection_state

        if selection_state.type != SelectionType.CHARACTERS:
            selection_state.type = SelectionType.CHARACTERS
        else:
            event.current_buffer.exit_selection()

    @handle(Keys.ControlV, filter=selection_mode)
    def _(event):
        """
        Exit block selection mode, or go from non block selection mode to block
        selection mode.
        """
        selection_state = event.current_buffer.selection_state

        if selection_state.type != SelectionType.BLOCK:
            selection_state.type = SelectionType.BLOCK
        else:
            event.current_buffer.exit_selection()


    @handle('a', 'w', filter=selection_mode)
    @handle('a', 'W', filter=selection_mode)
    def _(event):
        """
        Switch from visual linewise mode to visual characterwise mode.
        """
        buffer = event.current_buffer

        if buffer.selection_state and buffer.selection_state.type == SelectionType.LINES:
            buffer.selection_state.type = SelectionType.CHARACTERS

    @handle('x', filter=navigation_mode)
    def _(event):
        """
        Delete character.
        """
        text = event.current_buffer.delete(count=event.arg)
        event.cli.clipboard.set_text(text)

    @handle('x', filter=selection_mode)
    @handle('d', filter=selection_mode)
    def _(event):
        """
        Cut selection.
        """
        clipboard_data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(clipboard_data)

    @handle('c', filter=selection_mode & ~IsReadOnly())
    def _(event):
        """
        Change selection (cut and go to insert mode).
        """
        clipboard_data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(clipboard_data)
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('y', filter=selection_mode)
    def _(event):
        """
        Copy selection.
        """
        clipboard_data = event.current_buffer.copy_selection()
        event.cli.clipboard.set_data(clipboard_data)

    @handle('X', filter=navigation_mode)
    def _(event):
        text = event.current_buffer.delete_before_cursor()
        event.cli.clipboard.set_text(text)

    @handle('y', 'y', filter=navigation_mode)
    @handle('Y', filter=navigation_mode)
    def _(event):
        """
        Yank the whole line.
        """
        text = '\n'.join(event.current_buffer.document.lines_from_current[:event.arg])
        event.cli.clipboard.set_data(ClipboardData(text, SelectionType.LINES))

    @handle('+', filter=navigation_mode)
    def _(event):
        """
        Move to first non whitespace of next line
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_down_position(count=event.arg)
        buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)

    @handle('-', filter=navigation_mode)
    def _(event):
        """
        Move to first non whitespace of previous line
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.get_cursor_up_position(count=event.arg)
        buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=True)

    @handle('>', '>', filter=navigation_mode)
    def _(event):
        """
        Indent lines.
        """
        buffer = event.current_buffer
        current_row = buffer.document.cursor_position_row
        indent(buffer, current_row, current_row + event.arg)

    @handle('<', '<', filter=navigation_mode)
    def _(event):
        """
        Unindent lines.
        """
        current_row = event.current_buffer.document.cursor_position_row
        unindent(event.current_buffer, current_row, current_row + event.arg)

    @handle('>', filter=selection_mode)
    def _(event):
        """
        Indent selection
        """
        buffer = event.current_buffer
        selection_type = buffer.selection_state.type

        if selection_type == SelectionType.LINES:
            from_, to = buffer.document.selection_range()
            from_, _ = buffer.document.translate_index_to_position(from_)
            to, _ = buffer.document.translate_index_to_position(to)

            indent(buffer, from_, to + 1, count=event.arg)

    @handle('<', filter=selection_mode)
    def _(event):
        """
        Unindent selection
        """
        buffer = event.current_buffer
        selection_type = buffer.selection_state.type

        if selection_type == SelectionType.LINES:
            from_, to = buffer.document.selection_range()
            from_, _ = buffer.document.translate_index_to_position(from_)
            to, _ = buffer.document.translate_index_to_position(to)

            unindent(buffer, from_, to + 1, count=event.arg)

    @handle('O', filter=navigation_mode & ~IsReadOnly())
    def _(event):
        """
        Open line above and enter insertion mode
        """
        event.current_buffer.insert_line_above(
                copy_margin=not event.cli.in_paste_mode)
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('o', filter=navigation_mode & ~IsReadOnly())
    def _(event):
        """
        Open line below and enter insertion mode
        """
        event.current_buffer.insert_line_below(
                copy_margin=not event.cli.in_paste_mode)
        get_vi_state(event.cli).input_mode = InputMode.INSERT

    @handle('~', filter=navigation_mode)
    def _(event):
        """
        Reverse case of current character and move cursor forward.
        """
        buffer = event.current_buffer
        c = buffer.document.current_char

        if c is not None and c != '\n':
            c = (c.upper() if c.islower() else c.lower())
            buffer.insert_text(c, overwrite=True)

    @handle('#', filter=navigation_mode)
    def _(event):
        """
        Go to previous occurence of this word.
        """
        b = event.cli.current_buffer

        search_state = get_search_state(event.cli)
        search_state.text = b.document.get_word_under_cursor()
        search_state.direction = IncrementalSearchDirection.BACKWARD

        b.apply_search(search_state, count=event.arg,
                       include_current_position=False)

    @handle('*', filter=navigation_mode)
    def _(event):
        """
        Go to next occurence of this word.
        """
        b = event.cli.current_buffer

        search_state = get_search_state(event.cli)
        search_state.text = b.document.get_word_under_cursor()
        search_state.direction = IncrementalSearchDirection.FORWARD

        b.apply_search(search_state, count=event.arg,
                       include_current_position=False)

    @handle('(', filter=navigation_mode)
    def _(event):
        # TODO: go to begin of sentence.
        pass

    @handle(')', filter=navigation_mode)
    def _(event):
        # TODO: go to end of sentence.
        pass

    def change_delete_move_yank_handler(*keys, **kw):
        """
        Register a change/delete/move/yank handlers. e.g.  'dw'/'cw'/'w'/'yw'
        The decorated function should return a ``CursorRegion``.
        This decorator will create both the 'change', 'delete' and move variants,
        based on that ``CursorRegion``.

        When there is nothing selected yet, this will also handle the "visual"
        binding. E.g. 'viw' should select the current word.
        """
        no_move_handler = kw.pop('no_move_handler', False)

        # TODO: Also do '>' and '<' indent/unindent operators.
        # TODO: Also "gq": text formatting
        #  See: :help motion.txt
        def decorator(func):
            if not no_move_handler:
                @handle(*keys, filter=navigation_mode|selection_mode)
                def move(event):
                    """ Create move handler. """
                    region = func(event)
                    event.current_buffer.cursor_position += region.start

            def create_transform_handler(transform_func, *a):
                @handle(*(a + keys), filter=navigation_mode)
                def _(event):
                    """ Apply transformation (uppercase, lowercase, rot13, swap case). """
                    region = func(event)
                    start, end = region.sorted()
                    buffer = event.current_buffer

                    # Transform.
                    buffer.transform_region(
                        buffer.cursor_position + start,
                        buffer.cursor_position + end,
                        transform_func)

                    # Move cursor
                    buffer.cursor_position += (region.end or region.start)

            for k, f in vi_transform_functions:
                create_transform_handler(f, *k)

            @handle('y', *keys, filter=navigation_mode)
            def yank_handler(event):
                """ Create yank handler. """
                region = func(event)
                buffer = event.current_buffer

                start, end = region.sorted()
                substring = buffer.text[buffer.cursor_position + start: buffer.cursor_position + end]

                if substring:
                    event.cli.clipboard.set_text(substring)

            def create(delete_only):
                """ Create delete and change handlers. """
                @handle('cd'[delete_only], *keys, filter=navigation_mode & ~IsReadOnly())
                @handle('cd'[delete_only], *keys, filter=navigation_mode & ~IsReadOnly())
                def _(event):
                    region = func(event)
                    deleted = ''
                    buffer = event.current_buffer

                    if region:
                        start, end = region.sorted()

                        # Move to the start of the region.
                        buffer.cursor_position += start

                        # Delete until end of region.
                        deleted = buffer.delete(count=end-start)

                    # Set deleted/changed text to clipboard.
                    if deleted:
                        event.cli.clipboard.set_text(deleted)

                    # Only go back to insert mode in case of 'change'.
                    if not delete_only:
                        get_vi_state(event.cli).input_mode = InputMode.INSERT

            create(True)
            create(False)
            return func
        return decorator

    @change_delete_move_yank_handler('b')
    def _(event):
        """ Move one word or token left. """
        return CursorRegion(event.current_buffer.document.find_start_of_previous_word(count=event.arg) or 0)

    @change_delete_move_yank_handler('B')
    def _(event):
        """ Move one non-blank word left """
        return CursorRegion(event.current_buffer.document.find_start_of_previous_word(count=event.arg, WORD=True) or 0)

    @change_delete_move_yank_handler('$')
    def key_dollar(event):
        """ 'c$', 'd$' and '$':  Delete/change/move until end of line. """
        return CursorRegion(event.current_buffer.document.get_end_of_line_position())

    @change_delete_move_yank_handler('w')
    def _(event):
        """ 'word' forward. 'cw', 'dw', 'w': Delete/change/move one word.  """
        return CursorRegion(event.current_buffer.document.find_next_word_beginning(count=event.arg) or
                            event.current_buffer.document.get_end_of_document_position())

    @change_delete_move_yank_handler('W')
    def _(event):
        """ 'WORD' forward. 'cW', 'dW', 'W': Delete/change/move one WORD.  """
        return CursorRegion(event.current_buffer.document.find_next_word_beginning(count=event.arg, WORD=True) or
                            event.current_buffer.document.get_end_of_document_position())

    @change_delete_move_yank_handler('e')
    def _(event):
        """ End of 'word': 'ce', 'de', 'e' """
        end = event.current_buffer.document.find_next_word_ending(count=event.arg)
        return CursorRegion(end - 1 if end else 0)

    @change_delete_move_yank_handler('E')
    def _(event):
        """ End of 'WORD': 'cE', 'dE', 'E' """
        end = event.current_buffer.document.find_next_word_ending(count=event.arg, WORD=True)
        return CursorRegion(end - 1 if end else 0)

    @change_delete_move_yank_handler('i', 'w', no_move_handler=True)
    def _(event):
        """ Inner 'word': ciw and diw """
        start, end = event.current_buffer.document.find_boundaries_of_current_word()
        return CursorRegion(start, end)

    @change_delete_move_yank_handler('a', 'w', no_move_handler=True)
    def _(event):
        """ A 'word': caw and daw """
        start, end = event.current_buffer.document.find_boundaries_of_current_word(include_trailing_whitespace=True)
        return CursorRegion(start, end)

    @change_delete_move_yank_handler('i', 'W', no_move_handler=True)
    def _(event):
        """ Inner 'WORD': ciW and diW """
        start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True)
        return CursorRegion(start, end)

    @change_delete_move_yank_handler('a', 'W', no_move_handler=True)
    def _(event):
        """ A 'WORD': caw and daw """
        start, end = event.current_buffer.document.find_boundaries_of_current_word(WORD=True, include_trailing_whitespace=True)
        return CursorRegion(start, end)

    @change_delete_move_yank_handler('^')
    def key_circumflex(event):
        """ 'c^', 'd^' and '^': Soft start of line, after whitespace. """
        return CursorRegion(event.current_buffer.document.get_start_of_line_position(after_whitespace=True))

    @change_delete_move_yank_handler('0', no_move_handler=True)
    def key_zero(event):
        """
        'c0', 'd0': Hard start of line, before whitespace.
        (The move '0' key is implemented elsewhere, because a '0' could also change the `arg`.)
        """
        return CursorRegion(event.current_buffer.document.get_start_of_line_position(after_whitespace=False))

    def create_ci_ca_handles(ci_start, ci_end, inner):
                # TODO: 'dab', 'dib', (brackets or block) 'daB', 'diB', Braces.
                # TODO: 'dat', 'dit', (tags (like xml)
        """
        Delete/Change string between this start and stop character. But keep these characters.
        This implements all the ci", ci<, ci{, ci(, di", di<, ca", ca<, ... combinations.
        """
        @change_delete_move_yank_handler('ai'[inner], ci_start, no_move_handler=True)
        @change_delete_move_yank_handler('ai'[inner], ci_end, no_move_handler=True)
        def _(event):
            start = event.current_buffer.document.find_backwards(ci_start, in_current_line=False)
            end = event.current_buffer.document.find(ci_end, in_current_line=False)

            if start is not None and end is not None:
                offset = 0 if inner else 1
                return CursorRegion(start + 1 - offset, end + offset)
            else:
                # Nothing found.
                return CursorRegion(0)

    for inner in (False, True):
        for ci_start, ci_end in [('"', '"'), ("'", "'"), ("`", "`"),
                                 ('[', ']'), ('<', '>'), ('{', '}'), ('(', ')')]:
            create_ci_ca_handles(ci_start, ci_end, inner)

    @change_delete_move_yank_handler('{')
    def _(event):
        """
        Move to previous blank-line separated section.
        Implements '{', 'c{', 'd{', 'y{'
        """
        def match_func(text):
            return not text or text.isspace()

        line_index = event.current_buffer.document.find_previous_matching_line(
            match_func=match_func, count=event.arg)

        if line_index:
            index = event.current_buffer.document.get_cursor_up_position(count=-line_index)
        else:
            index = 0
        return CursorRegion(index)

    @change_delete_move_yank_handler('}')
    def _(event):
        """
        Move to next blank-line separated section.
        Implements '}', 'c}', 'd}', 'y}'
        """
        def match_func(text):
            return not text or text.isspace()

        line_index = event.current_buffer.document.find_next_matching_line(
            match_func=match_func, count=event.arg)

        if line_index:
            index = event.current_buffer.document.get_cursor_down_position(count=line_index)
        else:
            index = 0

        return CursorRegion(index)

    @change_delete_move_yank_handler('f', Keys.Any)
    def _(event):
        """
        Go to next occurance of character. Typing 'fx' will move the
        cursor to the next occurance of character. 'x'.
        """
        get_vi_state(event.cli).last_character_find = CharacterFind(event.data, False)
        match = event.current_buffer.document.find(event.data, in_current_line=True, count=event.arg)
        return CursorRegion(match or 0)

    @change_delete_move_yank_handler('F', Keys.Any)
    def _(event):
        """
        Go to previous occurance of character. Typing 'Fx' will move the
        cursor to the previous occurance of character. 'x'.
        """
        get_vi_state(event.cli).last_character_find = CharacterFind(event.data, True)
        return CursorRegion(event.current_buffer.document.find_backwards(event.data, in_current_line=True, count=event.arg) or 0)

    @change_delete_move_yank_handler('t', Keys.Any)
    def _(event):
        """
        Move right to the next occurance of c, then one char backward.
        """
        get_vi_state(event.cli).last_character_find = CharacterFind(event.data, False)
        match = event.current_buffer.document.find(event.data, in_current_line=True, count=event.arg)
        return CursorRegion(match - 1 if match else 0)

    @change_delete_move_yank_handler('T', Keys.Any)
    def _(event):
        """
        Move left to the previous occurance of c, then one char forward.
        """
        get_vi_state(event.cli).last_character_find = CharacterFind(event.data, True)
        match = event.current_buffer.document.find_backwards(event.data, in_current_line=True, count=event.arg)
        return CursorRegion(match + 1 if match else 0)

    def repeat(reverse):
        """
        Create ',' and ';' commands.
        """
        @change_delete_move_yank_handler(',' if reverse else ';')
        def _(event):
            # Repeat the last 'f'/'F'/'t'/'T' command.
            pos = 0
            vi_state = get_vi_state(event.cli)

            if vi_state.last_character_find:
                char = vi_state.last_character_find.character
                backwards = vi_state.last_character_find.backwards

                if reverse:
                    backwards = not backwards

                if backwards:
                    pos = event.current_buffer.document.find_backwards(char, in_current_line=True, count=event.arg)
                else:
                    pos = event.current_buffer.document.find(char, in_current_line=True, count=event.arg)
            return CursorRegion(pos or 0)
    repeat(True)
    repeat(False)

    @change_delete_move_yank_handler('h')
    @change_delete_move_yank_handler(Keys.Left)
    def _(event):
        """ Implements 'ch', 'dh', 'h': Cursor left. """
        return CursorRegion(event.current_buffer.document.get_cursor_left_position(count=event.arg))

    @change_delete_move_yank_handler('j', no_move_handler=True)
    def _(event):
        """ Implements 'cj', 'dj', 'j', ... Cursor up. """
        return CursorRegion(event.current_buffer.document.get_cursor_down_position(count=event.arg))

    @change_delete_move_yank_handler('k', no_move_handler=True)
    def _(event):
        """ Implements 'ck', 'dk', 'k', ... Cursor up. """
        return CursorRegion(event.current_buffer.document.get_cursor_up_position(count=event.arg))

    @change_delete_move_yank_handler('l')
    @change_delete_move_yank_handler(' ')
    @change_delete_move_yank_handler(Keys.Right)
    def _(event):
        """ Implements 'cl', 'dl', 'l', 'c ', 'd ', ' '. Cursor right. """
        return CursorRegion(event.current_buffer.document.get_cursor_right_position(count=event.arg))

    @change_delete_move_yank_handler('H')
    def _(event):
        """
        Moves to the start of the visible region. (Below the scroll offset.)
        Implements 'cH', 'dH', 'H'.
        """
        w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
        b = event.current_buffer

        if w:
            # When we find a Window that has BufferControl showing this window,
            # move to the start of the visible area.
            pos = (b.document.translate_row_col_to_index(
                       w.render_info.first_visible_line(after_scroll_offset=True), 0) -
                   b.cursor_position)

        else:
            # Otherwise, move to the start of the input.
            pos = -len(b.document.text_before_cursor)
        return CursorRegion(pos)

    @change_delete_move_yank_handler('M')
    def _(event):
        """
        Moves cursor to the vertical center of the visible region.
        Implements 'cM', 'dM', 'M'.
        """
        w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
        b = event.current_buffer

        if w:
            # When we find a Window that has BufferControl showing this window,
            # move to the center of the visible area.
            pos = (b.document.translate_row_col_to_index(
                       w.render_info.center_visible_line(), 0) -
                   b.cursor_position)

        else:
            # Otherwise, move to the start of the input.
            pos = -len(b.document.text_before_cursor)
        return CursorRegion(pos)

    @change_delete_move_yank_handler('L')
    def _(event):
        """
        Moves to the end of the visible region. (Above the scroll offset.)
        """
        w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
        b = event.current_buffer

        if w:
            # When we find a Window that has BufferControl showing this window,
            # move to the end of the visible area.
            pos = (b.document.translate_row_col_to_index(
                       w.render_info.last_visible_line(before_scroll_offset=True), 0) -
                   b.cursor_position)

        else:
            # Otherwise, move to the end of the input.
            pos = len(b.document.text_after_cursor)
        return CursorRegion(pos)

    @handle('z', '+', filter=navigation_mode|selection_mode)
    @handle('z', 't', filter=navigation_mode|selection_mode)
    @handle('z', Keys.ControlJ, filter=navigation_mode|selection_mode)
    def _(event):
        """
        Scrolls the window to makes the current line the first line in the visible region.
        """
        w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
        b = event.cli.current_buffer

        if w and w.render_info:
            # Calculate the offset that we need in order to position the row
            # containing the cursor in the center.
            cursor_position_row = b.document.cursor_position_row

            render_row = w.render_info.input_line_to_screen_line.get(cursor_position_row)
            if render_row is not None:
                w.vertical_scroll = max(0, render_row)


    @handle('z', '-', filter=navigation_mode|selection_mode)
    @handle('z', 'b', filter=navigation_mode|selection_mode)
    def _(event):
        """
        Scrolls the window to makes the current line the last line in the visible region.
        """
        w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
        b = event.cli.current_buffer

        if w and w.render_info:
            # Calculate the offset that we need in order to position the row
            # containing the cursor in the center.
            cursor_position_row = b.document.cursor_position_row

            render_row = w.render_info.input_line_to_screen_line.get(cursor_position_row)
            if render_row is not None:
                w.vertical_scroll = max(0, (render_row - w.render_info.window_height))

    @handle('z', 'z', filter=navigation_mode|selection_mode)
    def _(event):
        """
        Center Window vertically around cursor.
        """
        w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
        b = event.cli.current_buffer

        if w and w.render_info:
            # Calculate the offset that we need in order to position the row
            # containing the cursor in the center.
            cursor_position_row = b.document.cursor_position_row

            render_row = w.render_info.input_line_to_screen_line.get(cursor_position_row)
            if render_row is not None:
                w.vertical_scroll = max(0, int(render_row - w.render_info.window_height / 2))

    @change_delete_move_yank_handler('%')
    def _(event):
        """
        Implements 'c%', 'd%', '%, 'y%' (Move to corresponding bracket.)
        If an 'arg' has been given, go this this % position in the file.
        """
        buffer = event.current_buffer

        if event._arg:
            # If 'arg' has been given, the meaning of % is to go to the 'x%'
            # row in the file.
            if 0 < event.arg <= 100:
                absolute_index = buffer.document.translate_row_col_to_index(
                    int(event.arg * buffer.document.line_count / 100), 0)
                return CursorRegion(absolute_index - buffer.document.cursor_position)
            else:
                return CursorRegion(0)  # Do nothing.

        else:
            # Move to the corresponding opening/closing bracket (()'s, []'s and {}'s).
            return CursorRegion(buffer.document.matching_bracket_position)

    @change_delete_move_yank_handler('|')
    def _(event):
        # Move to the n-th column (you may specify the argument n by typing
        # it on number keys, for example, 20|).
        return CursorRegion(event.current_buffer.document.get_column_cursor_position(event.arg))

    @change_delete_move_yank_handler('g', 'g')
    def _(event):
        """
        Implements 'gg', 'cgg', 'ygg'
        """
        d = event.current_buffer.document

        if event._arg:
            # Move to the given line.
            return CursorRegion(d.translate_row_col_to_index(event.arg - 1, 0) - d.cursor_position)
        else:
            # Move to the top of the input.
            return CursorRegion(d.get_start_of_document_position())

    @change_delete_move_yank_handler('g', '_')
    def _(event):
        """
        Go to last non-blank of line.
        'g_', 'cg_', 'yg_', etc..
        """
        return CursorRegion(
            event.current_buffer.document.last_non_blank_of_current_line_position())

    @change_delete_move_yank_handler('g', 'e')
    def _(event):
        """
        Go to last character of previous word.
        'ge', 'cge', 'yge', etc..
        """
        return CursorRegion(
            event.current_buffer.document.find_start_of_previous_word(count=event.arg) or 0)

    @change_delete_move_yank_handler('g', 'E')
    def _(event):
        """
        Go to last character of previous WORD.
        'gE', 'cgE', 'ygE', etc..
        """
        return CursorRegion(
            event.current_buffer.document.find_start_of_previous_word(
                count=event.arg, WORD=True) or 0)

    @change_delete_move_yank_handler('G')
    def _(event):
        """
        Go to the end of the document. (If no arg has been given.)
        """
        return CursorRegion(len(event.current_buffer.document.text_after_cursor))

    @handle('G', filter=HasArg())
    def _(event):
        """
        If an argument is given, move to this line in the  history. (for
        example, 15G)
        """
        event.current_buffer.go_to_history(event.arg - 1)

    @handle(Keys.Any, filter=navigation_mode)
    @handle(Keys.Any, filter=selection_mode)
    def _(event):
        """
        Always handle numberics in navigation mode as arg.
        """
        if event.data in '123456789' or (event._arg and event.data == '0'):
            event.append_to_arg_count(event.data)
        elif event.data == '0':
            buffer = event.current_buffer
            buffer.cursor_position += buffer.document.get_start_of_line_position(after_whitespace=False)

    @handle(Keys.Any, filter=replace_mode)
    def _(event):
        """
        Insert data at cursor position.
        """
        event.current_buffer.insert_text(event.data, overwrite=True)

    def create_selection_transform_handler(keys, transform_func):
        """
        Apply transformation on selection (uppercase, lowercase, rot13, swap case).
        """
        @handle(*keys, filter=selection_mode)
        def _(event):
            for from_, to_ in event.current_buffer.document.selection_ranges():
                event.current_buffer.transform_region(from_, to_, transform_func)

    for k, f in vi_transform_functions:
        create_selection_transform_handler(k, f)

    @handle(Keys.ControlX, Keys.ControlL, filter=insert_mode)
    def _(event):
        """
        Pressing the ControlX - ControlL sequence in Vi mode does line
        completion based on the other lines in the document and the history.
        """
        event.current_buffer.start_history_lines_completion()

    @handle(Keys.ControlX, Keys.ControlF, filter=insert_mode)
    def _(event):
        """
        Complete file names.
        """
        # TODO
        pass
Ejemplo n.º 46
0
    def __init__(self, processor, filter):
        assert isinstance(processor, Processor)

        self.processor = processor
        self.filter = to_cli_filter(filter)
Ejemplo n.º 47
0
 def __init__(self, display_arrows=False):
     self.display_arrows = to_cli_filter(display_arrows)
Ejemplo n.º 48
0
 def __init__(self, relative=False, display_tildes=False):
     self.relative = to_cli_filter(relative)
     self.display_tildes = to_cli_filter(display_tildes)
 def __init__(self, relative=False, display_tildes=False):
     self.relative = to_cli_filter(relative)
     self.display_tildes = to_cli_filter(display_tildes)
Ejemplo n.º 50
0
    def __init__(self, margin, filter):
        assert isinstance(margin, Margin)

        self.margin = margin
        self.filter = to_cli_filter(filter)
Ejemplo n.º 51
0
    def __init__(self, content, filter):
        assert isinstance(content, Container)

        self.content = content
        self.filter = to_cli_filter(filter)
    def __init__(self, margin, filter):
        assert isinstance(margin, Margin)

        self.margin = margin
        self.filter = to_cli_filter(filter)
Ejemplo n.º 53
0
 def __init__(self, preview_search=False):
     self.preview_search = to_cli_filter(preview_search)
Ejemplo n.º 54
0
 def __init__(self, preview_search=Never()):
     self.preview_search = to_cli_filter(preview_search)
Ejemplo n.º 55
0
def load_emacs_search_bindings(registry, get_search_state=None, filter=None):
    filter = to_cli_filter(filter)

    handle = create_handle_decorator(registry, filter & EmacsMode())
    has_focus = HasFocus(SEARCH_BUFFER)

    assert get_search_state is None or callable(get_search_state)

    if not get_search_state:

        def get_search_state(cli):
            return cli.search_state

    @handle(Keys.ControlG, filter=has_focus)
    @handle(Keys.ControlC, filter=has_focus)
    # NOTE: the reason for not also binding Escape to this one, is that we want
    #       Alt+Enter to accept input directly in incremental search mode.
    def _(event):
        """
        Abort an incremental search and restore the original line.
        """
        search_buffer = event.cli.buffers[SEARCH_BUFFER]

        search_buffer.reset()
        event.cli.pop_focus()

    @handle(Keys.ControlJ, filter=has_focus)
    def _(event):
        """
        When enter pressed in isearch, quit isearch mode. (Multiline
        isearch would be too complicated.)
        """
        input_buffer = event.cli.buffers.previous(event.cli)
        search_buffer = event.cli.buffers[SEARCH_BUFFER]

        # Update search state.
        if search_buffer.text:
            get_search_state(event.cli).text = search_buffer.text

        # Apply search.
        input_buffer.apply_search(get_search_state(event.cli),
                                  include_current_position=True)

        # Add query to history of search line.
        search_buffer.append_to_history()
        search_buffer.reset()

        # Focus previous document again.
        event.cli.pop_focus()

    @handle(Keys.ControlR, filter=~has_focus)
    def _(event):
        get_search_state(
            event.cli).direction = IncrementalSearchDirection.BACKWARD
        event.cli.push_focus(SEARCH_BUFFER)

    @handle(Keys.ControlS, filter=~has_focus)
    def _(event):
        get_search_state(
            event.cli).direction = IncrementalSearchDirection.FORWARD
        event.cli.push_focus(SEARCH_BUFFER)

    def incremental_search(cli, direction, count=1):
        " Apply search, but keep search buffer focussed. "
        # Update search_state.
        search_state = get_search_state(cli)
        direction_changed = search_state.direction != direction

        search_state.text = cli.buffers[SEARCH_BUFFER].text
        search_state.direction = direction

        # Apply search to current buffer.
        if not direction_changed:
            input_buffer = cli.buffers.previous(cli)
            input_buffer.apply_search(search_state,
                                      include_current_position=False,
                                      count=count)

    @handle(Keys.ControlR, filter=has_focus)
    @handle(Keys.Up, filter=has_focus)
    def _(event):
        incremental_search(event.cli,
                           IncrementalSearchDirection.BACKWARD,
                           count=event.arg)

    @handle(Keys.ControlS, filter=has_focus)
    @handle(Keys.Down, filter=has_focus)
    def _(event):
        incremental_search(event.cli,
                           IncrementalSearchDirection.FORWARD,
                           count=event.arg)
Ejemplo n.º 56
0
def load_emacs_bindings(registry, filter=Always()):
    """
    Some e-macs extensions.
    """
    # Overview of Readline emacs commands:
    # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf
    filter = to_cli_filter(filter)

    handle = create_handle_decorator(registry, filter & EmacsMode())
    insert_mode = EmacsInsertMode()
    has_selection = HasSelection()

    @handle(Keys.Escape)
    def _(event):
        """
        By default, ignore escape key.

        (If we don't put this here, and Esc is followed by a key which sequence
        is not handled, we'll insert an Escape character in the input stream.
        Something we don't want and happens to easily in emacs mode.
        Further, people can always use ControlQ to do a quoted insert.)
        """
        pass

    handle(Keys.ControlA)(get_by_name('beginning-of-line'))
    handle(Keys.ControlB)(get_by_name('backward-char'))
    handle(Keys.ControlDelete, filter=insert_mode)(get_by_name('kill-word'))
    handle(Keys.ControlE)(get_by_name('end-of-line'))
    handle(Keys.ControlF)(get_by_name('forward-char'))
    handle(Keys.ControlLeft)(get_by_name('backward-word'))
    handle(Keys.ControlRight)(get_by_name('forward-word'))
    handle(Keys.ControlX, 'r', 'y', filter=insert_mode)(get_by_name('yank'))
    handle(Keys.ControlY, filter=insert_mode)(get_by_name('yank'))
    handle(Keys.Escape, 'b')(get_by_name('backward-word'))
    handle(Keys.Escape, 'c',
           filter=insert_mode)(get_by_name('capitalize-word'))
    handle(Keys.Escape, 'd', filter=insert_mode)(get_by_name('kill-word'))
    handle(Keys.Escape, 'f')(get_by_name('forward-word'))
    handle(Keys.Escape, 'l', filter=insert_mode)(get_by_name('downcase-word'))
    handle(Keys.Escape, 'u', filter=insert_mode)(get_by_name('uppercase-word'))
    handle(Keys.Escape, Keys.ControlH,
           filter=insert_mode)(get_by_name('unix-word-rubout'))
    handle(Keys.Escape, Keys.Backspace,
           filter=insert_mode)(get_by_name('unix-word-rubout'))
    handle(Keys.Escape, '\\',
           filter=insert_mode)(get_by_name('delete-horizontal-space'))

    handle(Keys.ControlUnderscore,
           save_before=(lambda e: False),
           filter=insert_mode)(get_by_name('undo'))

    handle(Keys.ControlX,
           Keys.ControlU,
           save_before=(lambda e: False),
           filter=insert_mode)(get_by_name('undo'))

    handle(Keys.Escape, '<',
           filter=~has_selection)(get_by_name('beginning-of-history'))
    handle(Keys.Escape, '>',
           filter=~has_selection)(get_by_name('end-of-history'))

    @handle(Keys.ControlN)
    def _(event):
        " Next line. "
        event.current_buffer.auto_down()

    @handle(Keys.ControlO, filter=insert_mode)
    def _(event):
        " Insert newline, but don't move the cursor. "
        event.current_buffer.insert_text('\n', move_cursor=False)

    @handle(Keys.ControlP)
    def _(event):
        " Previous line. "
        event.current_buffer.auto_up(count=event.arg)

    @handle(Keys.ControlQ, Keys.Any, filter=~has_selection)
    def _(event):
        """
        Quoted insert.

        For vt100 terminals, you have to disable flow control by running
        ``stty -ixon``, otherwise Ctrl-Q and Ctrl-S are captured by the
        terminal.
        """
        event.current_buffer.insert_text(event.data, overwrite=False)

    def handle_digit(c):
        """
        Handle input of arguments.
        The first number needs to be preceeded by escape.
        """
        @handle(c, filter=HasArg())
        @handle(Keys.Escape, c)
        def _(event):
            event.append_to_arg_count(c)

    for c in '0123456789':
        handle_digit(c)

    @handle(Keys.Escape, '-', filter=~HasArg())
    def _(event):
        """
        """
        if event._arg is None:
            event.append_to_arg_count('-')

    @handle('-', filter=Condition(lambda cli: cli.input_processor.arg == '-'))
    def _(event):
        """
        When '-' is typed again, after exactly '-' has been given as an
        argument, ignore this.
        """
        event.cli.input_processor.arg = '-'

    is_returnable = Condition(
        lambda cli: cli.current_buffer.accept_action.is_returnable)

    # Meta + Newline: always accept input.
    handle(Keys.Escape, Keys.ControlJ,
           filter=insert_mode & is_returnable)(get_by_name('accept-line'))

    def character_search(buff, char, count):
        if count < 0:
            match = buff.document.find_backwards(char,
                                                 in_current_line=True,
                                                 count=-count)
        else:
            match = buff.document.find(char, in_current_line=True, count=count)

        if match is not None:
            buff.cursor_position += match

    @handle(Keys.ControlSquareClose, Keys.Any)
    def _(event):
        " When Ctl-] + a character is pressed. go to that character. "
        character_search(event.current_buffer, event.data, event.arg)

    @handle(Keys.Escape, Keys.ControlSquareClose, Keys.Any)
    def _(event):
        " Like Ctl-], but backwards. "
        character_search(event.current_buffer, event.data, -event.arg)

    @handle(Keys.Escape, 'a')
    def _(event):
        " Previous sentence. "
        # TODO:

    @handle(Keys.Escape, 'e')
    def _(event):
        " Move to end of sentence. "
        # TODO:

    @handle(Keys.Escape, 't', filter=insert_mode)
    def _(event):
        """
        Swap the last two words before the cursor.
        """
        # TODO

    @handle(Keys.Escape, '.', filter=insert_mode)
    def _(event):
        """
        Rotate through the last word (white-space delimited) of the previous lines in history.
        """
        # TODO

    @handle(Keys.Escape, '*', filter=insert_mode)
    def _(event):
        """
        `meta-*`: Insert all possible completions of the preceding text.
        """
        buff = event.current_buffer

        # List all completions.
        complete_event = CompleteEvent(text_inserted=False,
                                       completion_requested=True)
        completions = list(
            buff.completer.get_completions(buff.document, complete_event))

        # Insert them.
        text_to_insert = ' '.join(c.text for c in completions)
        buff.insert_text(text_to_insert)

    @handle(Keys.ControlX, Keys.ControlX)
    def _(event):
        """
        Move cursor back and forth between the start and end of the current
        line.
        """
        buffer = event.current_buffer

        if buffer.document.is_cursor_at_the_end_of_line:
            buffer.cursor_position += buffer.document.get_start_of_line_position(
                after_whitespace=False)
        else:
            buffer.cursor_position += buffer.document.get_end_of_line_position(
            )

    @handle(Keys.ControlSpace)
    def _(event):
        """
        Start of the selection (if the current buffer is not empty).
        """
        # Take the current cursor position as the start of this selection.
        buff = event.current_buffer
        if buff.text:
            buff.start_selection(selection_type=SelectionType.CHARACTERS)

    @handle(Keys.ControlG, filter=~has_selection)
    def _(event):
        """
        Control + G: Cancel completion menu and validation state.
        """
        event.current_buffer.complete_state = None
        event.current_buffer.validation_error = None

    @handle(Keys.ControlG, filter=has_selection)
    def _(event):
        """
        Cancel selection.
        """
        event.current_buffer.exit_selection()

    @handle(Keys.ControlW, filter=has_selection)
    @handle(Keys.ControlX, 'r', 'k', filter=has_selection)
    def _(event):
        """
        Cut selected text.
        """
        data = event.current_buffer.cut_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Escape, 'w', filter=has_selection)
    def _(event):
        """
        Copy selected text.
        """
        data = event.current_buffer.copy_selection()
        event.cli.clipboard.set_data(data)

    @handle(Keys.Escape, Keys.Left)
    def _(event):
        """
        Cursor to start of previous word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_previous_word_beginning(
            count=event.arg) or 0

    @handle(Keys.Escape, Keys.Right)
    def _(event):
        """
        Cursor to start of next word.
        """
        buffer = event.current_buffer
        buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \
            buffer.document.get_end_of_document_position()

    @handle(Keys.Escape, '/', filter=insert_mode)
    def _(event):
        """
        M-/: Complete.
        """
        b = event.current_buffer
        if b.complete_state:
            b.complete_next()
        else:
            event.cli.start_completion(select_first=True)

    @handle(Keys.ControlC, '>', filter=has_selection)
    def _(event):
        """
        Indent selected text.
        """
        buffer = event.current_buffer

        buffer.cursor_position += buffer.document.get_start_of_line_position(
            after_whitespace=True)

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        indent(buffer, from_, to + 1, count=event.arg)

    @handle(Keys.ControlC, '<', filter=has_selection)
    def _(event):
        """
        Unindent selected text.
        """
        buffer = event.current_buffer

        from_, to = buffer.document.selection_range()
        from_, _ = buffer.document.translate_index_to_position(from_)
        to, _ = buffer.document.translate_index_to_position(to)

        unindent(buffer, from_, to + 1, count=event.arg)
Ejemplo n.º 57
0
    def __init__(self, registry=None,
                 enable_vi_mode=None,  # (`enable_vi_mode` is deprecated.)
                 get_search_state=None,
                 enable_abort_and_exit_bindings=False,
                 enable_system_bindings=False, enable_search=False,
                 enable_open_in_editor=False, enable_extra_page_navigation=False,
                 enable_auto_suggest_bindings=False,
                 enable_all=True):

        assert registry is None or isinstance(registry, Registry)
        assert get_search_state is None or callable(get_search_state)

        # Create registry.
        self.registry = registry or Registry()

        # Accept both Filters and booleans as input.
        enable_abort_and_exit_bindings = to_cli_filter(enable_abort_and_exit_bindings)
        enable_system_bindings = to_cli_filter(enable_system_bindings)
        enable_search = to_cli_filter(enable_search)
        enable_open_in_editor = to_cli_filter(enable_open_in_editor)
        enable_extra_page_navigation = to_cli_filter(enable_extra_page_navigation)
        enable_auto_suggest_bindings = to_cli_filter(enable_auto_suggest_bindings)
        enable_all = to_cli_filter(enable_all)

        # Load basic bindings.
        load_basic_bindings(self.registry, enable_all)
        load_mouse_bindings(self.registry, enable_all)

        load_abort_and_exit_bindings(
            self.registry, enable_abort_and_exit_bindings & enable_all)

        load_basic_system_bindings(self.registry,
            enable_system_bindings & enable_all)

        # Load emacs bindings.
        load_emacs_bindings(self.registry, enable_all)

        load_emacs_open_in_editor_bindings(
            self.registry, enable_open_in_editor & enable_all)

        load_emacs_search_bindings(
            self.registry,
            filter=enable_search & enable_all,
            get_search_state=get_search_state)

        load_emacs_system_bindings(
            self.registry, enable_system_bindings & enable_all)

        load_extra_emacs_page_navigation_bindings(
            self.registry,
            enable_extra_page_navigation & enable_all)

        # Load Vi bindings.
        load_vi_bindings(
            self.registry, enable_visual_key=~enable_open_in_editor,
            filter=enable_all,
            get_search_state=get_search_state)

        load_vi_open_in_editor_bindings(
            self.registry,
            enable_open_in_editor & enable_all)

        load_vi_search_bindings(
            self.registry,
            filter=enable_search & enable_all,
            get_search_state=get_search_state)

        load_vi_system_bindings(
            self.registry,
            enable_system_bindings & enable_all)

        load_extra_vi_page_navigation_bindings(
            self.registry,
            enable_extra_page_navigation & enable_all)

        # Suggestion bindings.
        # (This has to come at the end, because the Vi bindings also have an
        # implementation for the "right arrow", but we really want the
        # suggestion binding when a suggestion is available.)
        load_auto_suggestion_bindings(
            self.registry,
            enable_auto_suggest_bindings & enable_all)
Ejemplo n.º 58
0
    def __init__(self, processor, filter):
        assert isinstance(processor, Processor)

        self.processor = processor
        self.filter = to_cli_filter(filter)
 def __init__(self, display_arrows=False):
     self.display_arrows = to_cli_filter(display_arrows)