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