##// END OF EJS Templates
Reformat for readability
Thomas Kluyver -
Show More
@@ -1,243 +1,243 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)
71 kb.add('c-o', filter=(has_focus(DEFAULT_BUFFER) & emacs_insert_mode)
72 & emacs_insert_mode))(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 def newline_or_execute(event):
90 def newline_or_execute(event):
91 """When the user presses return, insert a newline or execute the code."""
91 """When the user presses return, insert a newline or execute the code."""
92 b = event.current_buffer
92 b = event.current_buffer
93 d = b.document
93 d = b.document
94
94
95 if b.complete_state:
95 if b.complete_state:
96 cc = b.complete_state.current_completion
96 cc = b.complete_state.current_completion
97 if cc:
97 if cc:
98 b.apply_completion(cc)
98 b.apply_completion(cc)
99 else:
99 else:
100 b.cancel_completion()
100 b.cancel_completion()
101 return
101 return
102
102
103 # If there's only one line, treat it as if the cursor is at the end.
103 # 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
104 # See https://github.com/ipython/ipython/issues/10425
105 if d.line_count == 1:
105 if d.line_count == 1:
106 check_text = d.text
106 check_text = d.text
107 else:
107 else:
108 check_text = d.text[:d.cursor_position]
108 check_text = d.text[:d.cursor_position]
109 status, indent = shell.check_complete(check_text)
109 status, indent = shell.check_complete(check_text)
110
110
111 if not (d.on_last_line or
111 if not (d.on_last_line or
112 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
112 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
113 ):
113 ):
114 b.insert_text('\n' + indent)
114 b.insert_text('\n' + indent)
115 return
115 return
116
116
117 if (status != 'incomplete') and b.accept_handler:
117 if (status != 'incomplete') and b.accept_handler:
118 b.validate_and_handle()
118 b.validate_and_handle()
119 else:
119 else:
120 b.insert_text('\n' + indent)
120 b.insert_text('\n' + indent)
121 return newline_or_execute
121 return newline_or_execute
122
122
123
123
124 def previous_history_or_previous_completion(event):
124 def previous_history_or_previous_completion(event):
125 """
125 """
126 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
126 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
127
127
128 If completer is open this still select previous completion.
128 If completer is open this still select previous completion.
129 """
129 """
130 event.current_buffer.auto_up()
130 event.current_buffer.auto_up()
131
131
132
132
133 def next_history_or_next_completion(event):
133 def next_history_or_next_completion(event):
134 """
134 """
135 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
135 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
136
136
137 If completer is open this still select next completion.
137 If completer is open this still select next completion.
138 """
138 """
139 event.current_buffer.auto_down()
139 event.current_buffer.auto_down()
140
140
141
141
142 def dismiss_completion(event):
142 def dismiss_completion(event):
143 b = event.current_buffer
143 b = event.current_buffer
144 if b.complete_state:
144 if b.complete_state:
145 b.cancel_completion()
145 b.cancel_completion()
146
146
147
147
148 def reset_buffer(event):
148 def reset_buffer(event):
149 b = event.current_buffer
149 b = event.current_buffer
150 if b.complete_state:
150 if b.complete_state:
151 b.cancel_completion()
151 b.cancel_completion()
152 else:
152 else:
153 b.reset()
153 b.reset()
154
154
155
155
156 def reset_search_buffer(event):
156 def reset_search_buffer(event):
157 if event.current_buffer.document.text:
157 if event.current_buffer.document.text:
158 event.current_buffer.reset()
158 event.current_buffer.reset()
159 else:
159 else:
160 event.app.layout.focus(DEFAULT_BUFFER)
160 event.app.layout.focus(DEFAULT_BUFFER)
161
161
162 def suspend_to_bg(event):
162 def suspend_to_bg(event):
163 event.app.suspend_to_background()
163 event.app.suspend_to_background()
164
164
165 def force_exit(event):
165 def force_exit(event):
166 """
166 """
167 Force exit (with a non-zero return value)
167 Force exit (with a non-zero return value)
168 """
168 """
169 sys.exit("Quit")
169 sys.exit("Quit")
170
170
171 def indent_buffer(event):
171 def indent_buffer(event):
172 event.current_buffer.insert_text(' ' * 4)
172 event.current_buffer.insert_text(' ' * 4)
173
173
174 @undoc
174 @undoc
175 def newline_with_copy_margin(event):
175 def newline_with_copy_margin(event):
176 """
176 """
177 DEPRECATED since IPython 6.0
177 DEPRECATED since IPython 6.0
178
178
179 See :any:`newline_autoindent_outer` for a replacement.
179 See :any:`newline_autoindent_outer` for a replacement.
180
180
181 Preserve margin and cursor position when using
181 Preserve margin and cursor position when using
182 Control-O to insert a newline in EMACS mode
182 Control-O to insert a newline in EMACS mode
183 """
183 """
184 warnings.warn("`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
184 warnings.warn("`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
185 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
185 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
186 DeprecationWarning, stacklevel=2)
186 DeprecationWarning, stacklevel=2)
187
187
188 b = event.current_buffer
188 b = event.current_buffer
189 cursor_start_pos = b.document.cursor_position_col
189 cursor_start_pos = b.document.cursor_position_col
190 b.newline(copy_margin=True)
190 b.newline(copy_margin=True)
191 b.cursor_up(count=1)
191 b.cursor_up(count=1)
192 cursor_end_pos = b.document.cursor_position_col
192 cursor_end_pos = b.document.cursor_position_col
193 if cursor_start_pos != cursor_end_pos:
193 if cursor_start_pos != cursor_end_pos:
194 pos_diff = cursor_start_pos - cursor_end_pos
194 pos_diff = cursor_start_pos - cursor_end_pos
195 b.cursor_right(count=pos_diff)
195 b.cursor_right(count=pos_diff)
196
196
197 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
197 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
198 """
198 """
199 Return a function suitable for inserting a indented newline after the cursor.
199 Return a function suitable for inserting a indented newline after the cursor.
200
200
201 Fancier version of deprecated ``newline_with_copy_margin`` which should
201 Fancier version of deprecated ``newline_with_copy_margin`` which should
202 compute the correct indentation of the inserted line. That is to say, indent
202 compute the correct indentation of the inserted line. That is to say, indent
203 by 4 extra space after a function definition, class definition, context
203 by 4 extra space after a function definition, class definition, context
204 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
204 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
205 """
205 """
206
206
207 def newline_autoindent(event):
207 def newline_autoindent(event):
208 """insert a newline after the cursor indented appropriately."""
208 """insert a newline after the cursor indented appropriately."""
209 b = event.current_buffer
209 b = event.current_buffer
210 d = b.document
210 d = b.document
211
211
212 if b.complete_state:
212 if b.complete_state:
213 b.cancel_completion()
213 b.cancel_completion()
214 text = d.text[:d.cursor_position] + '\n'
214 text = d.text[:d.cursor_position] + '\n'
215 _, indent = inputsplitter.check_complete(text)
215 _, indent = inputsplitter.check_complete(text)
216 b.insert_text('\n' + (' ' * (indent or 0)), move_cursor=False)
216 b.insert_text('\n' + (' ' * (indent or 0)), move_cursor=False)
217
217
218 return newline_autoindent
218 return newline_autoindent
219
219
220
220
221 def open_input_in_editor(event):
221 def open_input_in_editor(event):
222 event.app.current_buffer.tempfile_suffix = ".py"
222 event.app.current_buffer.tempfile_suffix = ".py"
223 event.app.current_buffer.open_in_editor()
223 event.app.current_buffer.open_in_editor()
224
224
225
225
226 if sys.platform == 'win32':
226 if sys.platform == 'win32':
227 from IPython.core.error import TryNext
227 from IPython.core.error import TryNext
228 from IPython.lib.clipboard import (ClipboardEmpty,
228 from IPython.lib.clipboard import (ClipboardEmpty,
229 win32_clipboard_get,
229 win32_clipboard_get,
230 tkinter_clipboard_get)
230 tkinter_clipboard_get)
231
231
232 @undoc
232 @undoc
233 def win_paste(event):
233 def win_paste(event):
234 try:
234 try:
235 text = win32_clipboard_get()
235 text = win32_clipboard_get()
236 except TryNext:
236 except TryNext:
237 try:
237 try:
238 text = tkinter_clipboard_get()
238 text = tkinter_clipboard_get()
239 except (TryNext, ClipboardEmpty):
239 except (TryNext, ClipboardEmpty):
240 return
240 return
241 except ClipboardEmpty:
241 except ClipboardEmpty:
242 return
242 return
243 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
243 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
General Comments 0
You need to be logged in to leave comments. Login now