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