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