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