##// END OF EJS Templates
autoreformat
Matthias Bussonnier -
Show More
@@ -1,485 +1,509 b''
1 """
1 """
2 Module to define and register Terminal IPython shortcuts with
2 Module to define and register Terminal IPython shortcuts with
3 :mod:`prompt_toolkit`
3 :mod:`prompt_toolkit`
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 import warnings
9 import warnings
10 import signal
10 import signal
11 import sys
11 import sys
12 import re
12 import re
13 from typing import Callable
13 from typing import Callable
14
14
15
15
16 from prompt_toolkit.application.current import get_app
16 from prompt_toolkit.application.current import get_app
17 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
17 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
18 from prompt_toolkit.filters import (has_focus, has_selection, Condition,
18 from prompt_toolkit.filters import (has_focus, has_selection, Condition,
19 vi_insert_mode, emacs_insert_mode, has_completions, vi_mode)
19 vi_insert_mode, emacs_insert_mode, has_completions, vi_mode)
20 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
20 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
21 from prompt_toolkit.key_binding import KeyBindings
21 from prompt_toolkit.key_binding import KeyBindings
22 from prompt_toolkit.key_binding.bindings import named_commands as nc
22 from prompt_toolkit.key_binding.bindings import named_commands as nc
23 from prompt_toolkit.key_binding.vi_state import InputMode, ViState
23 from prompt_toolkit.key_binding.vi_state import InputMode, ViState
24
24
25 from IPython.utils.decorators import undoc
25 from IPython.utils.decorators import undoc
26
26
27 @undoc
27 @undoc
28 @Condition
28 @Condition
29 def cursor_in_leading_ws():
29 def cursor_in_leading_ws():
30 before = get_app().current_buffer.document.current_line_before_cursor
30 before = get_app().current_buffer.document.current_line_before_cursor
31 return (not before) or before.isspace()
31 return (not before) or before.isspace()
32
32
33
33
34 def create_ipython_shortcuts(shell):
34 def create_ipython_shortcuts(shell):
35 """Set up the prompt_toolkit keyboard shortcuts for IPython"""
35 """Set up the prompt_toolkit keyboard shortcuts for IPython"""
36
36
37 kb = KeyBindings()
37 kb = KeyBindings()
38 insert_mode = vi_insert_mode | emacs_insert_mode
38 insert_mode = vi_insert_mode | emacs_insert_mode
39
39
40 if getattr(shell, 'handle_return', None):
40 if getattr(shell, 'handle_return', None):
41 return_handler = shell.handle_return(shell)
41 return_handler = shell.handle_return(shell)
42 else:
42 else:
43 return_handler = newline_or_execute_outer(shell)
43 return_handler = newline_or_execute_outer(shell)
44
44
45 kb.add('enter', filter=(has_focus(DEFAULT_BUFFER)
45 kb.add('enter', filter=(has_focus(DEFAULT_BUFFER)
46 & ~has_selection
46 & ~has_selection
47 & insert_mode
47 & insert_mode
48 ))(return_handler)
48 ))(return_handler)
49
49
50 def reformat_and_execute(event):
50 def reformat_and_execute(event):
51 reformat_text_before_cursor(event.current_buffer, event.current_buffer.document, shell)
51 reformat_text_before_cursor(event.current_buffer, event.current_buffer.document, shell)
52 event.current_buffer.validate_and_handle()
52 event.current_buffer.validate_and_handle()
53
53
54 kb.add('escape', 'enter', filter=(has_focus(DEFAULT_BUFFER)
54 kb.add('escape', 'enter', filter=(has_focus(DEFAULT_BUFFER)
55 & ~has_selection
55 & ~has_selection
56 & insert_mode
56 & insert_mode
57 ))(reformat_and_execute)
57 ))(reformat_and_execute)
58
58
59 kb.add('c-\\')(force_exit)
59 kb.add('c-\\')(force_exit)
60
60
61 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
61 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
62 )(previous_history_or_previous_completion)
62 )(previous_history_or_previous_completion)
63
63
64 kb.add('c-n', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
64 kb.add('c-n', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
65 )(next_history_or_next_completion)
65 )(next_history_or_next_completion)
66
66
67 kb.add('c-g', filter=(has_focus(DEFAULT_BUFFER) & has_completions)
67 kb.add('c-g', filter=(has_focus(DEFAULT_BUFFER) & has_completions)
68 )(dismiss_completion)
68 )(dismiss_completion)
69
69
70 kb.add('c-c', filter=has_focus(DEFAULT_BUFFER))(reset_buffer)
70 kb.add('c-c', filter=has_focus(DEFAULT_BUFFER))(reset_buffer)
71
71
72 kb.add('c-c', filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)
72 kb.add('c-c', filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)
73
73
74 supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
74 supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
75 kb.add('c-z', filter=supports_suspend)(suspend_to_bg)
75 kb.add('c-z', filter=supports_suspend)(suspend_to_bg)
76
76
77 # Ctrl+I == Tab
77 # Ctrl+I == Tab
78 kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
78 kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
79 & ~has_selection
79 & ~has_selection
80 & insert_mode
80 & insert_mode
81 & cursor_in_leading_ws
81 & cursor_in_leading_ws
82 ))(indent_buffer)
82 ))(indent_buffer)
83 kb.add('c-o', filter=(has_focus(DEFAULT_BUFFER) & emacs_insert_mode)
83 kb.add('c-o', filter=(has_focus(DEFAULT_BUFFER) & emacs_insert_mode)
84 )(newline_autoindent_outer(shell.input_transformer_manager))
84 )(newline_autoindent_outer(shell.input_transformer_manager))
85
85
86 kb.add('f2', filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
86 kb.add('f2', filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
87
87
88 focused_insert = (vi_insert_mode | emacs_insert_mode) & has_focus(DEFAULT_BUFFER)
88 focused_insert = (vi_insert_mode | emacs_insert_mode) & has_focus(DEFAULT_BUFFER)
89 _preceding_text_cache = {}
89 _preceding_text_cache = {}
90 _following_text_cache = {}
90 _following_text_cache = {}
91
91
92
93 def preceding_text(pattern):
92 def preceding_text(pattern):
94 try:
93 try:
95 return _preceding_text_cache[pattern]
94 return _preceding_text_cache[pattern]
96 except KeyError:
95 except KeyError:
97 pass
96 pass
98 m = re.compile(pattern)
97 m = re.compile(pattern)
99
98
100 def _preceding_text():
99 def _preceding_text():
101 app = get_app()
100 app = get_app()
102 return bool(m.match(app.current_buffer.document.current_line_before_cursor))
101 return bool(m.match(app.current_buffer.document.current_line_before_cursor))
103
102
104 condition = Condition(_preceding_text)
103 condition = Condition(_preceding_text)
105 _preceding_text_cache[pattern] = condition
104 _preceding_text_cache[pattern] = condition
106 return condition
105 return condition
107
106
108
109 def following_text(pattern):
107 def following_text(pattern):
110 try:
108 try:
111 return _following_text_cache[pattern]
109 return _following_text_cache[pattern]
112 except KeyError:
110 except KeyError:
113 pass
111 pass
114 m = re.compile(pattern)
112 m = re.compile(pattern)
115
113
116 def _following_text():
114 def _following_text():
117 app = get_app()
115 app = get_app()
118 return bool(m.match(app.current_buffer.document.current_line_after_cursor))
116 return bool(m.match(app.current_buffer.document.current_line_after_cursor))
119
117
120 condition = Condition(_following_text)
118 condition = Condition(_following_text)
121 _following_text_cache[pattern] = condition
119 _following_text_cache[pattern] = condition
122 return condition
120 return condition
123
121
124
125 # auto match
122 # auto match
126 @kb.add('(', filter=focused_insert & following_text(r"[,)}\]]|$"))
123 @kb.add("(", filter=focused_insert & following_text(r"[,)}\]]|$"))
127 def _(event):
124 def _(event):
128 event.current_buffer.insert_text("()")
125 event.current_buffer.insert_text("()")
129 event.current_buffer.cursor_left()
126 event.current_buffer.cursor_left()
130
127
131 @kb.add('[', filter=focused_insert & following_text(r"[,)}\]]|$"))
128 @kb.add("[", filter=focused_insert & following_text(r"[,)}\]]|$"))
132 def _(event):
129 def _(event):
133 event.current_buffer.insert_text("[]")
130 event.current_buffer.insert_text("[]")
134 event.current_buffer.cursor_left()
131 event.current_buffer.cursor_left()
135
132
136 @kb.add('{', filter=focused_insert & following_text(r"[,)}\]]|$"))
133 @kb.add("{", filter=focused_insert & following_text(r"[,)}\]]|$"))
137 def _(event):
134 def _(event):
138 event.current_buffer.insert_text("{}")
135 event.current_buffer.insert_text("{}")
139 event.current_buffer.cursor_left()
136 event.current_buffer.cursor_left()
140
137
141 @kb.add('"', filter=focused_insert & following_text(r"[,)}\]]|$"))
138 @kb.add('"', filter=focused_insert & following_text(r"[,)}\]]|$"))
142 def _(event):
139 def _(event):
143 event.current_buffer.insert_text('""')
140 event.current_buffer.insert_text('""')
144 event.current_buffer.cursor_left()
141 event.current_buffer.cursor_left()
145
142
146 @kb.add("'", filter=focused_insert & following_text(r"[,)}\]]|$"))
143 @kb.add("'", filter=focused_insert & following_text(r"[,)}\]]|$"))
147 def _(event):
144 def _(event):
148 event.current_buffer.insert_text("''")
145 event.current_buffer.insert_text("''")
149 event.current_buffer.cursor_left()
146 event.current_buffer.cursor_left()
150
147
151 # raw string
148 # raw string
152 @kb.add('(', filter=focused_insert & preceding_text(r".*(r|R)[\"'](-*)$"))
149 @kb.add("(", filter=focused_insert & preceding_text(r".*(r|R)[\"'](-*)$"))
153 def _(event):
150 def _(event):
154 matches = re.match(r".*(r|R)[\"'](-*)", event.current_buffer.document.current_line_before_cursor)
151 matches = re.match(
152 r".*(r|R)[\"'](-*)",
153 event.current_buffer.document.current_line_before_cursor,
154 )
155 dashes = matches.group(2) or ""
155 dashes = matches.group(2) or ""
156 event.current_buffer.insert_text("()" + dashes)
156 event.current_buffer.insert_text("()" + dashes)
157 event.current_buffer.cursor_left(len(dashes) + 1)
157 event.current_buffer.cursor_left(len(dashes) + 1)
158
158
159 @kb.add('[', filter=focused_insert & preceding_text(r".*(r|R)[\"'](-*)$"))
159 @kb.add("[", filter=focused_insert & preceding_text(r".*(r|R)[\"'](-*)$"))
160 def _(event):
160 def _(event):
161 matches = re.match(r".*(r|R)[\"'](-*)", event.current_buffer.document.current_line_before_cursor)
161 matches = re.match(
162 r".*(r|R)[\"'](-*)",
163 event.current_buffer.document.current_line_before_cursor,
164 )
162 dashes = matches.group(2) or ""
165 dashes = matches.group(2) or ""
163 event.current_buffer.insert_text("[]" + dashes)
166 event.current_buffer.insert_text("[]" + dashes)
164 event.current_buffer.cursor_left(len(dashes) + 1)
167 event.current_buffer.cursor_left(len(dashes) + 1)
165
168
166 @kb.add('{', filter=focused_insert & preceding_text(r".*(r|R)[\"'](-*)$"))
169 @kb.add("{", filter=focused_insert & preceding_text(r".*(r|R)[\"'](-*)$"))
167 def _(event):
170 def _(event):
168 matches = re.match(r".*(r|R)[\"'](-*)", event.current_buffer.document.current_line_before_cursor)
171 matches = re.match(
172 r".*(r|R)[\"'](-*)",
173 event.current_buffer.document.current_line_before_cursor,
174 )
169 dashes = matches.group(2) or ""
175 dashes = matches.group(2) or ""
170 event.current_buffer.insert_text("{}" + dashes)
176 event.current_buffer.insert_text("{}" + dashes)
171 event.current_buffer.cursor_left(len(dashes) + 1)
177 event.current_buffer.cursor_left(len(dashes) + 1)
172
178
173 @kb.add('"', filter=focused_insert & preceding_text(r".*(r|R)$"))
179 @kb.add('"', filter=focused_insert & preceding_text(r".*(r|R)$"))
174 def _(event):
180 def _(event):
175 event.current_buffer.insert_text('""')
181 event.current_buffer.insert_text('""')
176 event.current_buffer.cursor_left()
182 event.current_buffer.cursor_left()
177
183
178 @kb.add("'", filter=focused_insert & preceding_text(r".*(r|R)$"))
184 @kb.add("'", filter=focused_insert & preceding_text(r".*(r|R)$"))
179 def _(event):
185 def _(event):
180 event.current_buffer.insert_text("''")
186 event.current_buffer.insert_text("''")
181 event.current_buffer.cursor_left()
187 event.current_buffer.cursor_left()
182
188
183 # just move cursor
189 # just move cursor
184 @kb.add(')', filter=focused_insert & following_text(r"^\)"))
190 @kb.add(")", filter=focused_insert & following_text(r"^\)"))
185 @kb.add(']', filter=focused_insert & following_text(r"^\]"))
191 @kb.add("]", filter=focused_insert & following_text(r"^\]"))
186 @kb.add('}', filter=focused_insert & following_text(r"^\}"))
192 @kb.add("}", filter=focused_insert & following_text(r"^\}"))
187 @kb.add('"', filter=focused_insert & following_text("^\""))
193 @kb.add('"', filter=focused_insert & following_text('^"'))
188 @kb.add("'", filter=focused_insert & following_text("^'"))
194 @kb.add("'", filter=focused_insert & following_text("^'"))
189 def _(event):
195 def _(event):
190 event.current_buffer.cursor_right()
196 event.current_buffer.cursor_right()
191
197
192 @kb.add('backspace', filter=focused_insert & preceding_text(r".*\($") & following_text(r"^\)"))
198 @kb.add(
193 @kb.add('backspace', filter=focused_insert & preceding_text(r".*\[$") & following_text(r"^\]"))
199 "backspace",
194 @kb.add('backspace', filter=focused_insert & preceding_text(r".*\{$") & following_text(r"^\}"))
200 filter=focused_insert & preceding_text(r".*\($") & following_text(r"^\)"),
195 @kb.add('backspace', filter=focused_insert & preceding_text('.*"$') & following_text('^"'))
201 )
196 @kb.add('backspace', filter=focused_insert & preceding_text(r".*'$") & following_text(r"^'"))
202 @kb.add(
203 "backspace",
204 filter=focused_insert & preceding_text(r".*\[$") & following_text(r"^\]"),
205 )
206 @kb.add(
207 "backspace",
208 filter=focused_insert & preceding_text(r".*\{$") & following_text(r"^\}"),
209 )
210 @kb.add(
211 "backspace",
212 filter=focused_insert & preceding_text('.*"$') & following_text('^"'),
213 )
214 @kb.add(
215 "backspace",
216 filter=focused_insert & preceding_text(r".*'$") & following_text(r"^'"),
217 )
197 def _(event):
218 def _(event):
198 event.current_buffer.delete()
219 event.current_buffer.delete()
199 event.current_buffer.delete_before_cursor()
220 event.current_buffer.delete_before_cursor()
200
221
201
222 if shell.display_completions == "readlinelike":
202 if shell.display_completions == 'readlinelike':
223 kb.add(
203 kb.add('c-i', filter=(has_focus(DEFAULT_BUFFER)
224 "c-i",
225 filter=(
226 has_focus(DEFAULT_BUFFER)
204 & ~has_selection
227 & ~has_selection
205 & insert_mode
228 & insert_mode
206 & ~cursor_in_leading_ws
229 & ~cursor_in_leading_ws
207 ))(display_completions_like_readline)
230 ),
231 )(display_completions_like_readline)
208
232
209 if sys.platform == "win32":
233 if sys.platform == "win32":
210 kb.add("c-v", filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
234 kb.add("c-v", filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
211
235
212 @Condition
236 @Condition
213 def ebivim():
237 def ebivim():
214 return shell.emacs_bindings_in_vi_insert_mode
238 return shell.emacs_bindings_in_vi_insert_mode
215
239
216 focused_insert_vi = has_focus(DEFAULT_BUFFER) & vi_insert_mode
240 focused_insert_vi = has_focus(DEFAULT_BUFFER) & vi_insert_mode
217
241
218 # Needed for to accept autosuggestions in vi insert mode
242 # Needed for to accept autosuggestions in vi insert mode
219 @kb.add("c-e", filter=focused_insert_vi & ebivim)
243 @kb.add("c-e", filter=focused_insert_vi & ebivim)
220 def _(event):
244 def _(event):
221 b = event.current_buffer
245 b = event.current_buffer
222 suggestion = b.suggestion
246 suggestion = b.suggestion
223 if suggestion:
247 if suggestion:
224 b.insert_text(suggestion.text)
248 b.insert_text(suggestion.text)
225 else:
249 else:
226 nc.end_of_line(event)
250 nc.end_of_line(event)
227
251
228 @kb.add("c-f", filter=focused_insert_vi)
252 @kb.add("c-f", filter=focused_insert_vi)
229 def _(event):
253 def _(event):
230 b = event.current_buffer
254 b = event.current_buffer
231 suggestion = b.suggestion
255 suggestion = b.suggestion
232 if suggestion:
256 if suggestion:
233 b.insert_text(suggestion.text)
257 b.insert_text(suggestion.text)
234 else:
258 else:
235 nc.forward_char(event)
259 nc.forward_char(event)
236
260
237 @kb.add("escape", "f", filter=focused_insert_vi & ebivim)
261 @kb.add("escape", "f", filter=focused_insert_vi & ebivim)
238 def _(event):
262 def _(event):
239 b = event.current_buffer
263 b = event.current_buffer
240 suggestion = b.suggestion
264 suggestion = b.suggestion
241 if suggestion:
265 if suggestion:
242 t = re.split(r"(\S+\s+)", suggestion.text)
266 t = re.split(r"(\S+\s+)", suggestion.text)
243 b.insert_text(next((x for x in t if x), ""))
267 b.insert_text(next((x for x in t if x), ""))
244 else:
268 else:
245 nc.forward_word(event)
269 nc.forward_word(event)
246
270
247 # Simple Control keybindings
271 # Simple Control keybindings
248 key_cmd_dict = {
272 key_cmd_dict = {
249 "c-a": nc.beginning_of_line,
273 "c-a": nc.beginning_of_line,
250 "c-b": nc.backward_char,
274 "c-b": nc.backward_char,
251 "c-k": nc.kill_line,
275 "c-k": nc.kill_line,
252 "c-w": nc.backward_kill_word,
276 "c-w": nc.backward_kill_word,
253 "c-y": nc.yank,
277 "c-y": nc.yank,
254 "c-_": nc.undo,
278 "c-_": nc.undo,
255 }
279 }
256
280
257 for key, cmd in key_cmd_dict.items():
281 for key, cmd in key_cmd_dict.items():
258 kb.add(key, filter=focused_insert_vi & ebivim)(cmd)
282 kb.add(key, filter=focused_insert_vi & ebivim)(cmd)
259
283
260 # Alt and Combo Control keybindings
284 # Alt and Combo Control keybindings
261 keys_cmd_dict = {
285 keys_cmd_dict = {
262 # Control Combos
286 # Control Combos
263 ("c-x", "c-e"): nc.edit_and_execute,
287 ("c-x", "c-e"): nc.edit_and_execute,
264 ("c-x", "e"): nc.edit_and_execute,
288 ("c-x", "e"): nc.edit_and_execute,
265 # Alt
289 # Alt
266 ("escape", "b"): nc.backward_word,
290 ("escape", "b"): nc.backward_word,
267 ("escape", "c"): nc.capitalize_word,
291 ("escape", "c"): nc.capitalize_word,
268 ("escape", "d"): nc.kill_word,
292 ("escape", "d"): nc.kill_word,
269 ("escape", "h"): nc.backward_kill_word,
293 ("escape", "h"): nc.backward_kill_word,
270 ("escape", "l"): nc.downcase_word,
294 ("escape", "l"): nc.downcase_word,
271 ("escape", "u"): nc.uppercase_word,
295 ("escape", "u"): nc.uppercase_word,
272 ("escape", "y"): nc.yank_pop,
296 ("escape", "y"): nc.yank_pop,
273 ("escape", "."): nc.yank_last_arg,
297 ("escape", "."): nc.yank_last_arg,
274 }
298 }
275
299
276 for keys, cmd in keys_cmd_dict.items():
300 for keys, cmd in keys_cmd_dict.items():
277 kb.add(*keys, filter=focused_insert_vi & ebivim)(cmd)
301 kb.add(*keys, filter=focused_insert_vi & ebivim)(cmd)
278
302
279 def get_input_mode(self):
303 def get_input_mode(self):
280 app = get_app()
304 app = get_app()
281 app.ttimeoutlen = shell.ttimeoutlen
305 app.ttimeoutlen = shell.ttimeoutlen
282 app.timeoutlen = shell.timeoutlen
306 app.timeoutlen = shell.timeoutlen
283
307
284 return self._input_mode
308 return self._input_mode
285
309
286 def set_input_mode(self, mode):
310 def set_input_mode(self, mode):
287 shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
311 shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
288 cursor = "\x1b[{} q".format(shape)
312 cursor = "\x1b[{} q".format(shape)
289
313
290 if hasattr(sys.stdout, "_cli"):
314 if hasattr(sys.stdout, "_cli"):
291 write = sys.stdout._cli.output.write_raw
315 write = sys.stdout._cli.output.write_raw
292 else:
316 else:
293 write = sys.stdout.write
317 write = sys.stdout.write
294
318
295 write(cursor)
319 write(cursor)
296 sys.stdout.flush()
320 sys.stdout.flush()
297
321
298 self._input_mode = mode
322 self._input_mode = mode
299
323
300 if shell.editing_mode == "vi" and shell.modal_cursor:
324 if shell.editing_mode == "vi" and shell.modal_cursor:
301 ViState._input_mode = InputMode.INSERT
325 ViState._input_mode = InputMode.INSERT
302 ViState.input_mode = property(get_input_mode, set_input_mode)
326 ViState.input_mode = property(get_input_mode, set_input_mode)
303
327
304 return kb
328 return kb
305
329
306
330
307 def reformat_text_before_cursor(buffer, document, shell):
331 def reformat_text_before_cursor(buffer, document, shell):
308 text = buffer.delete_before_cursor(len(document.text[:document.cursor_position]))
332 text = buffer.delete_before_cursor(len(document.text[:document.cursor_position]))
309 try:
333 try:
310 formatted_text = shell.reformat_handler(text)
334 formatted_text = shell.reformat_handler(text)
311 buffer.insert_text(formatted_text)
335 buffer.insert_text(formatted_text)
312 except Exception as e:
336 except Exception as e:
313 buffer.insert_text(text)
337 buffer.insert_text(text)
314
338
315
339
316 def newline_or_execute_outer(shell):
340 def newline_or_execute_outer(shell):
317
341
318 def newline_or_execute(event):
342 def newline_or_execute(event):
319 """When the user presses return, insert a newline or execute the code."""
343 """When the user presses return, insert a newline or execute the code."""
320 b = event.current_buffer
344 b = event.current_buffer
321 d = b.document
345 d = b.document
322
346
323 if b.complete_state:
347 if b.complete_state:
324 cc = b.complete_state.current_completion
348 cc = b.complete_state.current_completion
325 if cc:
349 if cc:
326 b.apply_completion(cc)
350 b.apply_completion(cc)
327 else:
351 else:
328 b.cancel_completion()
352 b.cancel_completion()
329 return
353 return
330
354
331 # If there's only one line, treat it as if the cursor is at the end.
355 # If there's only one line, treat it as if the cursor is at the end.
332 # See https://github.com/ipython/ipython/issues/10425
356 # See https://github.com/ipython/ipython/issues/10425
333 if d.line_count == 1:
357 if d.line_count == 1:
334 check_text = d.text
358 check_text = d.text
335 else:
359 else:
336 check_text = d.text[:d.cursor_position]
360 check_text = d.text[:d.cursor_position]
337 status, indent = shell.check_complete(check_text)
361 status, indent = shell.check_complete(check_text)
338
362
339 # if all we have after the cursor is whitespace: reformat current text
363 # if all we have after the cursor is whitespace: reformat current text
340 # before cursor
364 # before cursor
341 after_cursor = d.text[d.cursor_position:]
365 after_cursor = d.text[d.cursor_position:]
342 reformatted = False
366 reformatted = False
343 if not after_cursor.strip():
367 if not after_cursor.strip():
344 reformat_text_before_cursor(b, d, shell)
368 reformat_text_before_cursor(b, d, shell)
345 reformatted = True
369 reformatted = True
346 if not (d.on_last_line or
370 if not (d.on_last_line or
347 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
371 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
348 ):
372 ):
349 if shell.autoindent:
373 if shell.autoindent:
350 b.insert_text('\n' + indent)
374 b.insert_text('\n' + indent)
351 else:
375 else:
352 b.insert_text('\n')
376 b.insert_text('\n')
353 return
377 return
354
378
355 if (status != 'incomplete') and b.accept_handler:
379 if (status != 'incomplete') and b.accept_handler:
356 if not reformatted:
380 if not reformatted:
357 reformat_text_before_cursor(b, d, shell)
381 reformat_text_before_cursor(b, d, shell)
358 b.validate_and_handle()
382 b.validate_and_handle()
359 else:
383 else:
360 if shell.autoindent:
384 if shell.autoindent:
361 b.insert_text('\n' + indent)
385 b.insert_text('\n' + indent)
362 else:
386 else:
363 b.insert_text('\n')
387 b.insert_text('\n')
364 return newline_or_execute
388 return newline_or_execute
365
389
366
390
367 def previous_history_or_previous_completion(event):
391 def previous_history_or_previous_completion(event):
368 """
392 """
369 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
393 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
370
394
371 If completer is open this still select previous completion.
395 If completer is open this still select previous completion.
372 """
396 """
373 event.current_buffer.auto_up()
397 event.current_buffer.auto_up()
374
398
375
399
376 def next_history_or_next_completion(event):
400 def next_history_or_next_completion(event):
377 """
401 """
378 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
402 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
379
403
380 If completer is open this still select next completion.
404 If completer is open this still select next completion.
381 """
405 """
382 event.current_buffer.auto_down()
406 event.current_buffer.auto_down()
383
407
384
408
385 def dismiss_completion(event):
409 def dismiss_completion(event):
386 b = event.current_buffer
410 b = event.current_buffer
387 if b.complete_state:
411 if b.complete_state:
388 b.cancel_completion()
412 b.cancel_completion()
389
413
390
414
391 def reset_buffer(event):
415 def reset_buffer(event):
392 b = event.current_buffer
416 b = event.current_buffer
393 if b.complete_state:
417 if b.complete_state:
394 b.cancel_completion()
418 b.cancel_completion()
395 else:
419 else:
396 b.reset()
420 b.reset()
397
421
398
422
399 def reset_search_buffer(event):
423 def reset_search_buffer(event):
400 if event.current_buffer.document.text:
424 if event.current_buffer.document.text:
401 event.current_buffer.reset()
425 event.current_buffer.reset()
402 else:
426 else:
403 event.app.layout.focus(DEFAULT_BUFFER)
427 event.app.layout.focus(DEFAULT_BUFFER)
404
428
405 def suspend_to_bg(event):
429 def suspend_to_bg(event):
406 event.app.suspend_to_background()
430 event.app.suspend_to_background()
407
431
408 def force_exit(event):
432 def force_exit(event):
409 """
433 """
410 Force exit (with a non-zero return value)
434 Force exit (with a non-zero return value)
411 """
435 """
412 sys.exit("Quit")
436 sys.exit("Quit")
413
437
414 def indent_buffer(event):
438 def indent_buffer(event):
415 event.current_buffer.insert_text(' ' * 4)
439 event.current_buffer.insert_text(' ' * 4)
416
440
417 @undoc
441 @undoc
418 def newline_with_copy_margin(event):
442 def newline_with_copy_margin(event):
419 """
443 """
420 DEPRECATED since IPython 6.0
444 DEPRECATED since IPython 6.0
421
445
422 See :any:`newline_autoindent_outer` for a replacement.
446 See :any:`newline_autoindent_outer` for a replacement.
423
447
424 Preserve margin and cursor position when using
448 Preserve margin and cursor position when using
425 Control-O to insert a newline in EMACS mode
449 Control-O to insert a newline in EMACS mode
426 """
450 """
427 warnings.warn("`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
451 warnings.warn("`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
428 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
452 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
429 DeprecationWarning, stacklevel=2)
453 DeprecationWarning, stacklevel=2)
430
454
431 b = event.current_buffer
455 b = event.current_buffer
432 cursor_start_pos = b.document.cursor_position_col
456 cursor_start_pos = b.document.cursor_position_col
433 b.newline(copy_margin=True)
457 b.newline(copy_margin=True)
434 b.cursor_up(count=1)
458 b.cursor_up(count=1)
435 cursor_end_pos = b.document.cursor_position_col
459 cursor_end_pos = b.document.cursor_position_col
436 if cursor_start_pos != cursor_end_pos:
460 if cursor_start_pos != cursor_end_pos:
437 pos_diff = cursor_start_pos - cursor_end_pos
461 pos_diff = cursor_start_pos - cursor_end_pos
438 b.cursor_right(count=pos_diff)
462 b.cursor_right(count=pos_diff)
439
463
440 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
464 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
441 """
465 """
442 Return a function suitable for inserting a indented newline after the cursor.
466 Return a function suitable for inserting a indented newline after the cursor.
443
467
444 Fancier version of deprecated ``newline_with_copy_margin`` which should
468 Fancier version of deprecated ``newline_with_copy_margin`` which should
445 compute the correct indentation of the inserted line. That is to say, indent
469 compute the correct indentation of the inserted line. That is to say, indent
446 by 4 extra space after a function definition, class definition, context
470 by 4 extra space after a function definition, class definition, context
447 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
471 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
448 """
472 """
449
473
450 def newline_autoindent(event):
474 def newline_autoindent(event):
451 """insert a newline after the cursor indented appropriately."""
475 """insert a newline after the cursor indented appropriately."""
452 b = event.current_buffer
476 b = event.current_buffer
453 d = b.document
477 d = b.document
454
478
455 if b.complete_state:
479 if b.complete_state:
456 b.cancel_completion()
480 b.cancel_completion()
457 text = d.text[:d.cursor_position] + '\n'
481 text = d.text[:d.cursor_position] + '\n'
458 _, indent = inputsplitter.check_complete(text)
482 _, indent = inputsplitter.check_complete(text)
459 b.insert_text('\n' + (' ' * (indent or 0)), move_cursor=False)
483 b.insert_text('\n' + (' ' * (indent or 0)), move_cursor=False)
460
484
461 return newline_autoindent
485 return newline_autoindent
462
486
463
487
464 def open_input_in_editor(event):
488 def open_input_in_editor(event):
465 event.app.current_buffer.open_in_editor()
489 event.app.current_buffer.open_in_editor()
466
490
467
491
468 if sys.platform == 'win32':
492 if sys.platform == 'win32':
469 from IPython.core.error import TryNext
493 from IPython.core.error import TryNext
470 from IPython.lib.clipboard import (ClipboardEmpty,
494 from IPython.lib.clipboard import (ClipboardEmpty,
471 win32_clipboard_get,
495 win32_clipboard_get,
472 tkinter_clipboard_get)
496 tkinter_clipboard_get)
473
497
474 @undoc
498 @undoc
475 def win_paste(event):
499 def win_paste(event):
476 try:
500 try:
477 text = win32_clipboard_get()
501 text = win32_clipboard_get()
478 except TryNext:
502 except TryNext:
479 try:
503 try:
480 text = tkinter_clipboard_get()
504 text = tkinter_clipboard_get()
481 except (TryNext, ClipboardEmpty):
505 except (TryNext, ClipboardEmpty):
482 return
506 return
483 except ClipboardEmpty:
507 except ClipboardEmpty:
484 return
508 return
485 event.current_buffer.insert_text(text.replace("\t", " " * 4))
509 event.current_buffer.insert_text(text.replace("\t", " " * 4))
General Comments 0
You need to be logged in to leave comments. Login now