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