##// END OF EJS Templates
Backport PR #10489: Prefer execution when there's only a single line entered...
meeseeksdev[bot] -
Show More
@@ -1,201 +1,206 b''
1 1 import signal
2 2 import sys
3 3
4 4 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
5 5 from prompt_toolkit.filters import (HasFocus, HasSelection, Condition,
6 6 ViInsertMode, EmacsInsertMode, HasCompletions)
7 7 from prompt_toolkit.filters.cli import ViMode
8 8 from prompt_toolkit.keys import Keys
9 9 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
10 10
11 11 from IPython.utils.decorators import undoc
12 12
13 13 @Condition
14 14 def cursor_in_leading_ws(cli):
15 15 before = cli.application.buffer.document.current_line_before_cursor
16 16 return (not before) or before.isspace()
17 17
18 18 def register_ipython_shortcuts(registry, shell):
19 19 """Set up the prompt_toolkit keyboard shortcuts for IPython"""
20 20 insert_mode = ViInsertMode() | EmacsInsertMode()
21 21
22 22 # Ctrl+J == Enter, seemingly
23 23 registry.add_binding(Keys.ControlJ,
24 24 filter=(HasFocus(DEFAULT_BUFFER)
25 25 & ~HasSelection()
26 26 & insert_mode
27 27 ))(newline_or_execute_outer(shell))
28 28
29 29 registry.add_binding(Keys.ControlBackslash)(force_exit)
30 30
31 31 registry.add_binding(Keys.ControlP,
32 32 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
33 33 ))(previous_history_or_previous_completion)
34 34
35 35 registry.add_binding(Keys.ControlN,
36 36 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
37 37 ))(next_history_or_next_completion)
38 38
39 39 registry.add_binding(Keys.ControlG,
40 40 filter=(HasFocus(DEFAULT_BUFFER) & HasCompletions()
41 41 ))(dismiss_completion)
42 42
43 43 registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)
44 44 )(reset_buffer)
45 45
46 46 registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)
47 47 )(reset_search_buffer)
48 48
49 49 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
50 50 registry.add_binding(Keys.ControlZ, filter=supports_suspend
51 51 )(suspend_to_bg)
52 52
53 53 # Ctrl+I == Tab
54 54 registry.add_binding(Keys.ControlI,
55 55 filter=(HasFocus(DEFAULT_BUFFER)
56 56 & ~HasSelection()
57 57 & insert_mode
58 58 & cursor_in_leading_ws
59 59 ))(indent_buffer)
60 60
61 61 registry.add_binding(Keys.ControlO,
62 62 filter=(HasFocus(DEFAULT_BUFFER)
63 63 & EmacsInsertMode()))(newline_with_copy_margin)
64 64
65 65 registry.add_binding(Keys.F2,
66 66 filter=HasFocus(DEFAULT_BUFFER)
67 67 )(open_input_in_editor)
68 68
69 69 if shell.display_completions == 'readlinelike':
70 70 registry.add_binding(Keys.ControlI,
71 71 filter=(HasFocus(DEFAULT_BUFFER)
72 72 & ~HasSelection()
73 73 & insert_mode
74 74 & ~cursor_in_leading_ws
75 75 ))(display_completions_like_readline)
76 76
77 77 if sys.platform == 'win32':
78 78 registry.add_binding(Keys.ControlV,
79 79 filter=(
80 80 HasFocus(
81 81 DEFAULT_BUFFER) & ~ViMode()
82 82 ))(win_paste)
83 83
84 84
85 85 def newline_or_execute_outer(shell):
86 86 def newline_or_execute(event):
87 87 """When the user presses return, insert a newline or execute the code."""
88 88 b = event.current_buffer
89 89 d = b.document
90 90
91 91 if b.complete_state:
92 92 cc = b.complete_state.current_completion
93 93 if cc:
94 94 b.apply_completion(cc)
95 95 else:
96 96 b.cancel_completion()
97 97 return
98 98
99 before_text = d.text[:d.cursor_position]
100 status, indent = shell.input_splitter.check_complete(before_text + '\n')
99 # If there's only one line, treat it as if the cursor is at the end.
100 # See https://github.com/ipython/ipython/issues/10425
101 if d.line_count == 1:
102 check_text = d.text
103 else:
104 check_text = d.text[:d.cursor_position]
105 status, indent = shell.input_splitter.check_complete(check_text + '\n')
101 106
102 107 if not (d.on_last_line or
103 108 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
104 109 ):
105 110 b.insert_text('\n' + (' ' * (indent or 0)))
106 111 return
107 112
108 113 if (status != 'incomplete') and b.accept_action.is_returnable:
109 114 b.accept_action.validate_and_handle(event.cli, b)
110 115 else:
111 116 b.insert_text('\n' + (' ' * (indent or 0)))
112 117 return newline_or_execute
113 118
114 119
115 120 def previous_history_or_previous_completion(event):
116 121 """
117 122 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
118 123
119 124 If completer is open this still select previous completion.
120 125 """
121 126 event.current_buffer.auto_up()
122 127
123 128
124 129 def next_history_or_next_completion(event):
125 130 """
126 131 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
127 132
128 133 If completer is open this still select next completion.
129 134 """
130 135 event.current_buffer.auto_down()
131 136
132 137
133 138 def dismiss_completion(event):
134 139 b = event.current_buffer
135 140 if b.complete_state:
136 141 b.cancel_completion()
137 142
138 143
139 144 def reset_buffer(event):
140 145 b = event.current_buffer
141 146 if b.complete_state:
142 147 b.cancel_completion()
143 148 else:
144 149 b.reset()
145 150
146 151
147 152 def reset_search_buffer(event):
148 153 if event.current_buffer.document.text:
149 154 event.current_buffer.reset()
150 155 else:
151 156 event.cli.push_focus(DEFAULT_BUFFER)
152 157
153 158 def suspend_to_bg(event):
154 159 event.cli.suspend_to_background()
155 160
156 161 def force_exit(event):
157 162 """
158 163 Force exit (with a non-zero return value)
159 164 """
160 165 sys.exit("Quit")
161 166
162 167 def indent_buffer(event):
163 168 event.current_buffer.insert_text(' ' * 4)
164 169
165 170 def newline_with_copy_margin(event):
166 171 """
167 172 Preserve margin and cursor position when using
168 173 Control-O to insert a newline in EMACS mode
169 174 """
170 175 b = event.current_buffer
171 176 cursor_start_pos = b.document.cursor_position_col
172 177 b.newline(copy_margin=True)
173 178 b.cursor_up(count=1)
174 179 cursor_end_pos = b.document.cursor_position_col
175 180 if cursor_start_pos != cursor_end_pos:
176 181 pos_diff = cursor_start_pos - cursor_end_pos
177 182 b.cursor_right(count=pos_diff)
178 183
179 184 def open_input_in_editor(event):
180 185 event.cli.current_buffer.tempfile_suffix = ".py"
181 186 event.cli.current_buffer.open_in_editor(event.cli)
182 187
183 188
184 189 if sys.platform == 'win32':
185 190 from IPython.core.error import TryNext
186 191 from IPython.lib.clipboard import (ClipboardEmpty,
187 192 win32_clipboard_get,
188 193 tkinter_clipboard_get)
189 194
190 195 @undoc
191 196 def win_paste(event):
192 197 try:
193 198 text = win32_clipboard_get()
194 199 except TryNext:
195 200 try:
196 201 text = tkinter_clipboard_get()
197 202 except (TryNext, ClipboardEmpty):
198 203 return
199 204 except ClipboardEmpty:
200 205 return
201 206 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
General Comments 0
You need to be logged in to leave comments. Login now