3
3
Main entry point to the AWS Shell.
4
4
5
5
"""
6
- from prompt_toolkit .buffer import Buffer
6
+ from prompt_toolkit .document import Document
7
7
from prompt_toolkit .shortcuts import create_eventloop
8
- from prompt_toolkit .shortcuts import create_default_application
9
- from prompt_toolkit .shortcuts import create_default_layout
10
- from prompt_toolkit import Application , CommandLineInterface , AbortAction
11
- from prompt_toolkit .filters import Always
12
- from prompt_toolkit .interface import AcceptAction
8
+ from prompt_toolkit .buffer import Buffer
9
+ from prompt_toolkit .enums import DEFAULT_BUFFER , SEARCH_BUFFER
10
+ from prompt_toolkit .filters import IsDone , HasFocus , Always , RendererHeightIsKnown , to_cli_filter
11
+ from prompt_toolkit .interface import CommandLineInterface , Application , AbortAction , AcceptAction
13
12
from prompt_toolkit .key_binding .manager import KeyBindingManager
13
+ from prompt_toolkit .layout import Window , HSplit , VSplit , FloatContainer , Float
14
+ from prompt_toolkit .layout .containers import ConditionalContainer
15
+ from prompt_toolkit .layout .controls import BufferControl , TokenListControl , FillControl
16
+ from prompt_toolkit .layout .dimension import LayoutDimension
17
+ from prompt_toolkit .layout .menus import CompletionsMenu , MultiColumnCompletionsMenu
18
+ from prompt_toolkit .layout .processors import PasswordProcessor , HighlightSearchProcessor , \
19
+ HighlightSelectionProcessor , ConditionalProcessor
20
+ from prompt_toolkit .layout .prompt import DefaultPrompt
21
+ from prompt_toolkit .layout .screen import Char
22
+ from prompt_toolkit .layout .toolbars import ValidationToolbar , SystemToolbar , ArgToolbar , SearchToolbar
23
+ from prompt_toolkit .layout .utils import explode_tokens
24
+ from prompt_toolkit .utils import Callback
25
+ from pygments .token import Token
26
+
27
+ from awsshell .compat import text_type
14
28
15
29
16
30
def create_layout ():
@@ -32,22 +46,207 @@ def create_application(completer, history):
32
46
enable_vi_mode = True ,
33
47
enable_system_bindings = False ,
34
48
enable_open_in_editor = False ).registry
35
-
49
+ buffers = {
50
+ 'clidocs' : Buffer (read_only = True )
51
+ }
36
52
37
53
return Application (
38
54
layout = create_layout (),
55
+ buffers = buffers ,
39
56
buffer = create_buffer (completer , history ),
40
57
on_abort = AbortAction .RAISE_EXCEPTION ,
41
58
on_exit = AbortAction .RAISE_EXCEPTION ,
59
+ on_input_timeout = Callback (on_input_timeout ),
42
60
key_bindings_registry = key_bindings_registry ,
43
61
)
44
62
45
63
64
+ def on_input_timeout (cli ):
65
+ buffer = cli .current_buffer
66
+ document = buffer .document
67
+ text = document .text
68
+ cli .buffers ['clidocs' ].reset (initial_document = Document (text , cursor_position = 0 ))
69
+
70
+
46
71
def create_cli_interface (completer , history ):
47
72
# A CommandLineInterface from prompt_toolkit
48
73
# accepts two things: an application and an
49
- # eventloop .
74
+ # event loop .
50
75
loop = create_eventloop ()
51
76
app = create_application (completer , history )
52
77
cli = CommandLineInterface (application = app , eventloop = loop )
53
78
return cli
79
+
80
+
81
+ def create_default_layout (message = '' , lexer = None , is_password = False ,
82
+ reserve_space_for_menu = False ,
83
+ get_prompt_tokens = None , get_bottom_toolbar_tokens = None ,
84
+ display_completions_in_columns = False ,
85
+ extra_input_processors = None , multiline = False ):
86
+ """
87
+ Generate default layout.
88
+ Returns a ``Layout`` instance.
89
+
90
+ :param message: Text to be used as prompt.
91
+ :param lexer: Lexer to be used for the highlighting.
92
+ :param is_password: `bool` or `CLIFilter`. When True, display input as '*'.
93
+ :param reserve_space_for_menu: When True, make sure that a minimal height is
94
+ allocated in the terminal, in order to display the completion menu.
95
+ :param get_prompt_tokens: An optional callable that returns the tokens to be
96
+ shown in the menu. (To be used instead of a `message`.)
97
+ :param get_bottom_toolbar_tokens: An optional callable that returns the
98
+ tokens for a toolbar at the bottom.
99
+ :param display_completions_in_columns: `bool` or `CLIFilter`. Display the
100
+ completions in multiple columns.
101
+ :param multiline: `bool` or `CLIFilter`. When True, prefer a layout that is
102
+ more adapted for multiline input. Text after newlines is automatically
103
+ indented, and search/arg input is shown below the input, instead of
104
+ replacing the prompt.
105
+ """
106
+ assert isinstance (message , text_type )
107
+ assert get_bottom_toolbar_tokens is None or callable (get_bottom_toolbar_tokens )
108
+ assert get_prompt_tokens is None or callable (get_prompt_tokens )
109
+ assert not (message and get_prompt_tokens )
110
+
111
+ display_completions_in_columns = to_cli_filter (display_completions_in_columns )
112
+ multiline = to_cli_filter (multiline )
113
+
114
+ if get_prompt_tokens is None :
115
+ get_prompt_tokens = lambda _ : [(Token .Prompt , message )]
116
+
117
+ get_prompt_tokens_1 , get_prompt_tokens_2 = _split_multiline_prompt (get_prompt_tokens )
118
+ # Create processors list.
119
+ # (DefaultPrompt should always be at the end.)
120
+ input_processors = [ConditionalProcessor (
121
+ # By default, only highlight search when the search
122
+ # input has the focus. (Note that this doesn't mean
123
+ # there is no search: the Vi 'n' binding for instance
124
+ # still allows to jump to the next match in
125
+ # navigation mode.)
126
+ HighlightSearchProcessor (preview_search = Always ()),
127
+ HasFocus (SEARCH_BUFFER )),
128
+ HighlightSelectionProcessor (),
129
+ ConditionalProcessor (PasswordProcessor (), is_password )]
130
+
131
+ if extra_input_processors :
132
+ input_processors .extend (extra_input_processors )
133
+
134
+ # Show the prompt before the input (using the DefaultPrompt processor.
135
+ # This also replaces it with reverse-i-search and 'arg' when required.
136
+ # (Only for single line mode.)
137
+ input_processors .append (ConditionalProcessor (
138
+ DefaultPrompt (get_prompt_tokens ), ~ multiline ))
139
+
140
+ # Create bottom toolbar.
141
+ if get_bottom_toolbar_tokens :
142
+ toolbars = [ConditionalContainer (
143
+ Window (TokenListControl (get_bottom_toolbar_tokens ,
144
+ default_char = Char (' ' , Token .Toolbar )),
145
+ height = LayoutDimension .exact (1 )),
146
+ filter = ~ IsDone () & RendererHeightIsKnown ())]
147
+ else :
148
+ toolbars = []
149
+
150
+ def get_height (cli ):
151
+ # If there is an autocompletion menu to be shown, make sure that our
152
+ # layout has at least a minimal height in order to display it.
153
+ if reserve_space_for_menu and not cli .is_done :
154
+ return LayoutDimension (min = 8 )
155
+ else :
156
+ return LayoutDimension ()
157
+
158
+ # Create and return Layout instance.
159
+ return HSplit ([
160
+ ConditionalContainer (
161
+ Window (
162
+ TokenListControl (get_prompt_tokens_1 ),
163
+ dont_extend_height = True ),
164
+ filter = multiline ,
165
+ ),
166
+ VSplit ([
167
+ # In multiline mode, the prompt is displayed in a left pane.
168
+ ConditionalContainer (
169
+ Window (
170
+ TokenListControl (get_prompt_tokens_2 ),
171
+ dont_extend_width = True ,
172
+ ),
173
+ filter = multiline ,
174
+ ),
175
+ # The main input, with completion menus floating on top of it.
176
+ FloatContainer (
177
+ Window (
178
+ BufferControl (
179
+ input_processors = input_processors ,
180
+ lexer = lexer ,
181
+ # Enable preview_search, we want to have immediate feedback
182
+ # in reverse-i-search mode.
183
+ preview_search = Always ()),
184
+ get_height = get_height ,
185
+ ),
186
+ [
187
+ Float (xcursor = True ,
188
+ ycursor = True ,
189
+ content = CompletionsMenu (
190
+ max_height = 16 ,
191
+ scroll_offset = 1 ,
192
+ extra_filter = HasFocus (DEFAULT_BUFFER ) &
193
+ ~ display_completions_in_columns )),
194
+ Float (xcursor = True ,
195
+ ycursor = True ,
196
+ content = MultiColumnCompletionsMenu (
197
+ extra_filter = HasFocus (DEFAULT_BUFFER ) &
198
+ display_completions_in_columns ,
199
+ show_meta = Always ()))
200
+ ]
201
+ ),
202
+ ]),
203
+ ConditionalContainer (
204
+ content = Window (height = LayoutDimension .exact (1 ),
205
+ content = FillControl (u'\u2500 ' , token = Token .Separator )),
206
+ #filter=HasSignature(python_input) & ShowDocstring(python_input) & ~IsDone()),
207
+ filter = ~ IsDone ()),
208
+ ConditionalContainer (
209
+ content = Window (
210
+ BufferControl (
211
+ buffer_name = 'clidocs' ,
212
+ ),
213
+ height = LayoutDimension (max = 12 )),
214
+ #filter=HasSignature(python_input) & ShowDocstring(python_input) & ~IsDone(),
215
+ filter = ~ IsDone (),
216
+ ),
217
+ ValidationToolbar (),
218
+ SystemToolbar (),
219
+
220
+ # In multiline mode, we use two toolbars for 'arg' and 'search'.
221
+ ConditionalContainer (ArgToolbar (), multiline ),
222
+ ConditionalContainer (SearchToolbar (), multiline ),
223
+ ] + toolbars )
224
+
225
+
226
+ def _split_multiline_prompt (get_prompt_tokens ):
227
+ """
228
+ Take a `get_prompt_tokens` function. and return two new functions instead.
229
+ One that returns the tokens to be shown on the lines above the input, and
230
+ another one with the tokens to be shown at the first line of the input.
231
+ """
232
+ def before (cli ):
233
+ result = []
234
+ found_nl = False
235
+ for token , char in reversed (explode_tokens (get_prompt_tokens (cli ))):
236
+ if char == '\n ' :
237
+ found_nl = True
238
+ elif found_nl :
239
+ result .insert (0 , (token , char ))
240
+ return result
241
+
242
+ def first_input_line (cli ):
243
+ result = []
244
+ for token , char in reversed (explode_tokens (get_prompt_tokens (cli ))):
245
+ if char == '\n ' :
246
+ break
247
+ else :
248
+ result .insert (0 , (token , char ))
249
+ return result
250
+
251
+ return before , first_input_line
252
+
0 commit comments