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