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