##// END OF EJS Templates
Merge pull request #12336 from Carreau/black_formatting
Matthias Bussonnier -
r25755:3546aed8 merge
parent child Browse files
Show More
@@ -1,273 +1,276 b''
1 1 """
2 2 Module to define and register Terminal IPython shortcuts with
3 3 :mod:`prompt_toolkit`
4 4 """
5 5
6 6 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 8
9 9 import warnings
10 10 import signal
11 11 import sys
12 12 from typing import Callable
13 13
14 14
15 15 from prompt_toolkit.application.current import get_app
16 16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
17 17 from prompt_toolkit.filters import (has_focus, has_selection, Condition,
18 18 vi_insert_mode, emacs_insert_mode, has_completions, vi_mode)
19 19 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
20 20 from prompt_toolkit.key_binding import KeyBindings
21 21
22 22 from IPython.utils.decorators import undoc
23 23
24 24 @undoc
25 25 @Condition
26 26 def cursor_in_leading_ws():
27 27 before = get_app().current_buffer.document.current_line_before_cursor
28 28 return (not before) or before.isspace()
29 29
30 30
31 31 def create_ipython_shortcuts(shell):
32 32 """Set up the prompt_toolkit keyboard shortcuts for IPython"""
33 33
34 34 kb = KeyBindings()
35 35 insert_mode = vi_insert_mode | emacs_insert_mode
36 36
37 37 if getattr(shell, 'handle_return', None):
38 38 return_handler = shell.handle_return(shell)
39 39 else:
40 40 return_handler = newline_or_execute_outer(shell)
41 41
42 42 kb.add('enter', filter=(has_focus(DEFAULT_BUFFER)
43 43 & ~has_selection
44 44 & insert_mode
45 45 ))(return_handler)
46 46
47 47 def reformat_and_execute(event):
48 48 reformat_text_before_cursor(event.current_buffer, event.current_buffer.document, shell)
49 49 event.current_buffer.validate_and_handle()
50 50
51 51 kb.add('escape', 'enter', filter=(has_focus(DEFAULT_BUFFER)
52 52 & ~has_selection
53 53 & insert_mode
54 54 ))(reformat_and_execute)
55 55
56 56 kb.add('c-\\')(force_exit)
57 57
58 58 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
59 59 )(previous_history_or_previous_completion)
60 60
61 61 kb.add('c-n', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
62 62 )(next_history_or_next_completion)
63 63
64 64 kb.add('c-g', filter=(has_focus(DEFAULT_BUFFER) & has_completions)
65 65 )(dismiss_completion)
66 66
67 67 kb.add('c-c', filter=has_focus(DEFAULT_BUFFER))(reset_buffer)
68 68
69 69 kb.add('c-c', filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)
70 70
71 71 supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
72 72 kb.add('c-z', filter=supports_suspend)(suspend_to_bg)
73 73
74 74 # Ctrl+I == Tab
75 75 kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
76 76 & ~has_selection
77 77 & insert_mode
78 78 & cursor_in_leading_ws
79 79 ))(indent_buffer)
80 80 kb.add('c-o', filter=(has_focus(DEFAULT_BUFFER) & emacs_insert_mode)
81 81 )(newline_autoindent_outer(shell.input_transformer_manager))
82 82
83 83 kb.add('f2', filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
84 84
85 85 if shell.display_completions == 'readlinelike':
86 86 kb.add('c-i', filter=(has_focus(DEFAULT_BUFFER)
87 87 & ~has_selection
88 88 & insert_mode
89 89 & ~cursor_in_leading_ws
90 90 ))(display_completions_like_readline)
91 91
92 92 if sys.platform == 'win32':
93 93 kb.add('c-v', filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
94 94
95 95 return kb
96 96
97 97
98 98 def reformat_text_before_cursor(buffer, document, shell):
99 99 text = buffer.delete_before_cursor(len(document.text[:document.cursor_position]))
100 100 try:
101 101 formatted_text = shell.reformat_handler(text)
102 102 buffer.insert_text(formatted_text)
103 103 except Exception as e:
104 104 buffer.insert_text(text)
105 105
106 106
107 107 def newline_or_execute_outer(shell):
108 108
109 109 def newline_or_execute(event):
110 110 """When the user presses return, insert a newline or execute the code."""
111 111 b = event.current_buffer
112 112 d = b.document
113 113
114 114 if b.complete_state:
115 115 cc = b.complete_state.current_completion
116 116 if cc:
117 117 b.apply_completion(cc)
118 118 else:
119 119 b.cancel_completion()
120 120 return
121 121
122 122 # If there's only one line, treat it as if the cursor is at the end.
123 123 # See https://github.com/ipython/ipython/issues/10425
124 124 if d.line_count == 1:
125 125 check_text = d.text
126 126 else:
127 127 check_text = d.text[:d.cursor_position]
128 128 status, indent = shell.check_complete(check_text)
129 129
130 130 # if all we have after the cursor is whitespace: reformat current text
131 131 # before cursor
132 132 after_cursor = d.text[d.cursor_position:]
133 reformatted = False
133 134 if not after_cursor.strip():
134 135 reformat_text_before_cursor(b, d, shell)
136 reformatted = True
135 137 if not (d.on_last_line or
136 138 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
137 139 ):
138 140 if shell.autoindent:
139 141 b.insert_text('\n' + indent)
140 142 else:
141 143 b.insert_text('\n')
142 144 return
143 145
144 146 if (status != 'incomplete') and b.accept_handler:
147 if not reformatted:
145 148 reformat_text_before_cursor(b, d, shell)
146 149 b.validate_and_handle()
147 150 else:
148 151 if shell.autoindent:
149 152 b.insert_text('\n' + indent)
150 153 else:
151 154 b.insert_text('\n')
152 155 return newline_or_execute
153 156
154 157
155 158 def previous_history_or_previous_completion(event):
156 159 """
157 160 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
158 161
159 162 If completer is open this still select previous completion.
160 163 """
161 164 event.current_buffer.auto_up()
162 165
163 166
164 167 def next_history_or_next_completion(event):
165 168 """
166 169 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
167 170
168 171 If completer is open this still select next completion.
169 172 """
170 173 event.current_buffer.auto_down()
171 174
172 175
173 176 def dismiss_completion(event):
174 177 b = event.current_buffer
175 178 if b.complete_state:
176 179 b.cancel_completion()
177 180
178 181
179 182 def reset_buffer(event):
180 183 b = event.current_buffer
181 184 if b.complete_state:
182 185 b.cancel_completion()
183 186 else:
184 187 b.reset()
185 188
186 189
187 190 def reset_search_buffer(event):
188 191 if event.current_buffer.document.text:
189 192 event.current_buffer.reset()
190 193 else:
191 194 event.app.layout.focus(DEFAULT_BUFFER)
192 195
193 196 def suspend_to_bg(event):
194 197 event.app.suspend_to_background()
195 198
196 199 def force_exit(event):
197 200 """
198 201 Force exit (with a non-zero return value)
199 202 """
200 203 sys.exit("Quit")
201 204
202 205 def indent_buffer(event):
203 206 event.current_buffer.insert_text(' ' * 4)
204 207
205 208 @undoc
206 209 def newline_with_copy_margin(event):
207 210 """
208 211 DEPRECATED since IPython 6.0
209 212
210 213 See :any:`newline_autoindent_outer` for a replacement.
211 214
212 215 Preserve margin and cursor position when using
213 216 Control-O to insert a newline in EMACS mode
214 217 """
215 218 warnings.warn("`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
216 219 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
217 220 DeprecationWarning, stacklevel=2)
218 221
219 222 b = event.current_buffer
220 223 cursor_start_pos = b.document.cursor_position_col
221 224 b.newline(copy_margin=True)
222 225 b.cursor_up(count=1)
223 226 cursor_end_pos = b.document.cursor_position_col
224 227 if cursor_start_pos != cursor_end_pos:
225 228 pos_diff = cursor_start_pos - cursor_end_pos
226 229 b.cursor_right(count=pos_diff)
227 230
228 231 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
229 232 """
230 233 Return a function suitable for inserting a indented newline after the cursor.
231 234
232 235 Fancier version of deprecated ``newline_with_copy_margin`` which should
233 236 compute the correct indentation of the inserted line. That is to say, indent
234 237 by 4 extra space after a function definition, class definition, context
235 238 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
236 239 """
237 240
238 241 def newline_autoindent(event):
239 242 """insert a newline after the cursor indented appropriately."""
240 243 b = event.current_buffer
241 244 d = b.document
242 245
243 246 if b.complete_state:
244 247 b.cancel_completion()
245 248 text = d.text[:d.cursor_position] + '\n'
246 249 _, indent = inputsplitter.check_complete(text)
247 250 b.insert_text('\n' + (' ' * (indent or 0)), move_cursor=False)
248 251
249 252 return newline_autoindent
250 253
251 254
252 255 def open_input_in_editor(event):
253 256 event.app.current_buffer.open_in_editor()
254 257
255 258
256 259 if sys.platform == 'win32':
257 260 from IPython.core.error import TryNext
258 261 from IPython.lib.clipboard import (ClipboardEmpty,
259 262 win32_clipboard_get,
260 263 tkinter_clipboard_get)
261 264
262 265 @undoc
263 266 def win_paste(event):
264 267 try:
265 268 text = win32_clipboard_get()
266 269 except TryNext:
267 270 try:
268 271 text = tkinter_clipboard_get()
269 272 except (TryNext, ClipboardEmpty):
270 273 return
271 274 except ClipboardEmpty:
272 275 return
273 276 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
General Comments 0
You need to be logged in to leave comments. Login now