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