1from __future__ import unicode_literals
2
3from ..enums import IncrementalSearchDirection
4
5from .processors import BeforeInput
6
7from .lexers import SimpleLexer
8from .dimension import LayoutDimension
9from .controls import BufferControl, TokenListControl, UIControl, UIContent
10from .containers import Window, ConditionalContainer
11from .screen import Char
12from .utils import token_list_len
13from prompt_toolkit.enums import SEARCH_BUFFER, SYSTEM_BUFFER
14from prompt_toolkit.filters import HasFocus, HasArg, HasCompletions, HasValidationError, HasSearch, Always, IsDone
15from prompt_toolkit.token import Token
16
17__all__ = (
18    'TokenListToolbar',
19    'ArgToolbar',
20    'CompletionsToolbar',
21    'SearchToolbar',
22    'SystemToolbar',
23    'ValidationToolbar',
24)
25
26
27class TokenListToolbar(ConditionalContainer):
28    def __init__(self, get_tokens, filter=Always(), **kw):
29        super(TokenListToolbar, self).__init__(
30            content=Window(
31                TokenListControl(get_tokens, **kw),
32                height=LayoutDimension.exact(1)),
33            filter=filter)
34
35
36class SystemToolbarControl(BufferControl):
37    def __init__(self):
38        token = Token.Toolbar.System
39
40        super(SystemToolbarControl, self).__init__(
41            buffer_name=SYSTEM_BUFFER,
42            default_char=Char(token=token),
43            lexer=SimpleLexer(token=token.Text),
44            input_processors=[BeforeInput.static('Shell command: ', token)],)
45
46
47class SystemToolbar(ConditionalContainer):
48    def __init__(self):
49        super(SystemToolbar, self).__init__(
50            content=Window(
51                SystemToolbarControl(),
52                height=LayoutDimension.exact(1)),
53            filter=HasFocus(SYSTEM_BUFFER) & ~IsDone())
54
55
56class ArgToolbarControl(TokenListControl):
57    def __init__(self):
58        def get_tokens(cli):
59            arg = cli.input_processor.arg
60            if arg == '-':
61                arg = '-1'
62
63            return [
64                (Token.Toolbar.Arg, 'Repeat: '),
65                (Token.Toolbar.Arg.Text, arg),
66            ]
67
68        super(ArgToolbarControl, self).__init__(get_tokens)
69
70
71class ArgToolbar(ConditionalContainer):
72    def __init__(self):
73        super(ArgToolbar, self).__init__(
74            content=Window(
75                ArgToolbarControl(),
76                height=LayoutDimension.exact(1)),
77            filter=HasArg())
78
79
80class SearchToolbarControl(BufferControl):
81    """
82    :param vi_mode: Display '/' and '?' instead of I-search.
83    """
84    def __init__(self, vi_mode=False):
85        token = Token.Toolbar.Search
86
87        def get_before_input(cli):
88            if not cli.is_searching:
89                text = ''
90            elif cli.search_state.direction == IncrementalSearchDirection.BACKWARD:
91                text = ('?' if vi_mode else 'I-search backward: ')
92            else:
93                text = ('/' if vi_mode else 'I-search: ')
94
95            return [(token, text)]
96
97        super(SearchToolbarControl, self).__init__(
98            buffer_name=SEARCH_BUFFER,
99            input_processors=[BeforeInput(get_before_input)],
100            default_char=Char(token=token),
101            lexer=SimpleLexer(token=token.Text))
102
103
104class SearchToolbar(ConditionalContainer):
105    def __init__(self, vi_mode=False):
106        super(SearchToolbar, self).__init__(
107            content=Window(
108                SearchToolbarControl(vi_mode=vi_mode),
109                height=LayoutDimension.exact(1)),
110            filter=HasSearch() & ~IsDone())
111
112
113class CompletionsToolbarControl(UIControl):
114    token = Token.Toolbar.Completions
115
116    def create_content(self, cli, width, height):
117        complete_state = cli.current_buffer.complete_state
118        if complete_state:
119            completions = complete_state.current_completions
120            index = complete_state.complete_index  # Can be None!
121
122            # Width of the completions without the left/right arrows in the margins.
123            content_width = width - 6
124
125            # Booleans indicating whether we stripped from the left/right
126            cut_left = False
127            cut_right = False
128
129            # Create Menu content.
130            tokens = []
131
132            for i, c in enumerate(completions):
133                # When there is no more place for the next completion
134                if token_list_len(tokens) + len(c.display) >= content_width:
135                    # If the current one was not yet displayed, page to the next sequence.
136                    if i <= (index or 0):
137                        tokens = []
138                        cut_left = True
139                    # If the current one is visible, stop here.
140                    else:
141                        cut_right = True
142                        break
143
144                tokens.append((self.token.Completion.Current if i == index else self.token.Completion, c.display))
145                tokens.append((self.token, ' '))
146
147            # Extend/strip until the content width.
148            tokens.append((self.token, ' ' * (content_width - token_list_len(tokens))))
149            tokens = tokens[:content_width]
150
151            # Return tokens
152            all_tokens = [
153                (self.token, ' '),
154                (self.token.Arrow, '<' if cut_left else ' '),
155                (self.token, ' '),
156            ] + tokens + [
157                (self.token, ' '),
158                (self.token.Arrow, '>' if cut_right else ' '),
159                (self.token, ' '),
160            ]
161        else:
162            all_tokens = []
163
164        def get_line(i):
165            return all_tokens
166
167        return UIContent(get_line=get_line, line_count=1)
168
169
170class CompletionsToolbar(ConditionalContainer):
171    def __init__(self, extra_filter=Always()):
172        super(CompletionsToolbar, self).__init__(
173            content=Window(
174                CompletionsToolbarControl(),
175                height=LayoutDimension.exact(1)),
176            filter=HasCompletions() & ~IsDone() & extra_filter)
177
178
179class ValidationToolbarControl(TokenListControl):
180    def __init__(self, show_position=False):
181        token = Token.Toolbar.Validation
182
183        def get_tokens(cli):
184            buffer = cli.current_buffer
185
186            if buffer.validation_error:
187                row, column = buffer.document.translate_index_to_position(
188                    buffer.validation_error.cursor_position)
189
190                if show_position:
191                    text = '%s (line=%s column=%s)' % (
192                        buffer.validation_error.message, row + 1, column + 1)
193                else:
194                    text = buffer.validation_error.message
195
196                return [(token, text)]
197            else:
198                return []
199
200        super(ValidationToolbarControl, self).__init__(get_tokens)
201
202
203class ValidationToolbar(ConditionalContainer):
204    def __init__(self, show_position=False):
205        super(ValidationToolbar, self).__init__(
206            content=Window(
207                ValidationToolbarControl(show_position=show_position),
208                height=LayoutDimension.exact(1)),
209            filter=HasValidationError() & ~IsDone())
210