##// END OF EJS Templates
Add shortcut to edit cell
Carl Smith -
Show More
@@ -1,193 +1,199 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,
66 filter=HasFocus(DEFAULT_BUFFER)
67 )(open_input_in_editor)
68
65 if shell.display_completions == 'readlinelike':
69 if shell.display_completions == 'readlinelike':
66 registry.add_binding(Keys.ControlI,
70 registry.add_binding(Keys.ControlI,
67 filter=(HasFocus(DEFAULT_BUFFER)
71 filter=(HasFocus(DEFAULT_BUFFER)
68 & ~HasSelection()
72 & ~HasSelection()
69 & insert_mode
73 & insert_mode
70 & ~cursor_in_leading_ws
74 & ~cursor_in_leading_ws
71 ))(display_completions_like_readline)
75 ))(display_completions_like_readline)
72
76
73 if sys.platform == 'win32':
77 if sys.platform == 'win32':
74 registry.add_binding(Keys.ControlV,
78 registry.add_binding(Keys.ControlV,
75 filter=(
79 filter=(
76 HasFocus(
80 HasFocus(
77 DEFAULT_BUFFER) & ~ViMode()
81 DEFAULT_BUFFER) & ~ViMode()
78 ))(win_paste)
82 ))(win_paste)
79
83
80
84
81 def newline_or_execute_outer(shell):
85 def newline_or_execute_outer(shell):
82 def newline_or_execute(event):
86 def newline_or_execute(event):
83 """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."""
84 b = event.current_buffer
88 b = event.current_buffer
85 d = b.document
89 d = b.document
86
90
87 if b.complete_state:
91 if b.complete_state:
88 cc = b.complete_state.current_completion
92 cc = b.complete_state.current_completion
89 if cc:
93 if cc:
90 b.apply_completion(cc)
94 b.apply_completion(cc)
91 else:
95 else:
92 b.cancel_completion()
96 b.cancel_completion()
93 return
97 return
94
98
95 if not (d.on_last_line or d.cursor_position_row >= d.line_count
99 if not (d.on_last_line or d.cursor_position_row >= d.line_count
96 - d.empty_line_count_at_the_end()):
100 - d.empty_line_count_at_the_end()):
97 b.newline()
101 b.newline()
98 return
102 return
99
103
100 status, indent = shell.input_splitter.check_complete(d.text + '\n')
104 status, indent = shell.input_splitter.check_complete(d.text + '\n')
101
105
102 if (status != 'incomplete') and b.accept_action.is_returnable:
106 if (status != 'incomplete') and b.accept_action.is_returnable:
103 b.accept_action.validate_and_handle(event.cli, b)
107 b.accept_action.validate_and_handle(event.cli, b)
104 else:
108 else:
105 b.insert_text('\n' + (' ' * (indent or 0)))
109 b.insert_text('\n' + (' ' * (indent or 0)))
106 return newline_or_execute
110 return newline_or_execute
107
111
108
112
109 def previous_history_or_previous_completion(event):
113 def previous_history_or_previous_completion(event):
110 """
114 """
111 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
115 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
112
116
113 If completer is open this still select previous completion.
117 If completer is open this still select previous completion.
114 """
118 """
115 event.current_buffer.auto_up()
119 event.current_buffer.auto_up()
116
120
117
121
118 def next_history_or_next_completion(event):
122 def next_history_or_next_completion(event):
119 """
123 """
120 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
124 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
121
125
122 If completer is open this still select next completion.
126 If completer is open this still select next completion.
123 """
127 """
124 event.current_buffer.auto_down()
128 event.current_buffer.auto_down()
125
129
126
130
127 def dismiss_completion(event):
131 def dismiss_completion(event):
128 b = event.current_buffer
132 b = event.current_buffer
129 if b.complete_state:
133 if b.complete_state:
130 b.cancel_completion()
134 b.cancel_completion()
131
135
132
136
133 def reset_buffer(event):
137 def reset_buffer(event):
134 b = event.current_buffer
138 b = event.current_buffer
135 if b.complete_state:
139 if b.complete_state:
136 b.cancel_completion()
140 b.cancel_completion()
137 else:
141 else:
138 b.reset()
142 b.reset()
139
143
140
144
141 def reset_search_buffer(event):
145 def reset_search_buffer(event):
142 if event.current_buffer.document.text:
146 if event.current_buffer.document.text:
143 event.current_buffer.reset()
147 event.current_buffer.reset()
144 else:
148 else:
145 event.cli.push_focus(DEFAULT_BUFFER)
149 event.cli.push_focus(DEFAULT_BUFFER)
146
150
147 def suspend_to_bg(event):
151 def suspend_to_bg(event):
148 event.cli.suspend_to_background()
152 event.cli.suspend_to_background()
149
153
150 def force_exit(event):
154 def force_exit(event):
151 """
155 """
152 Force exit (with a non-zero return value)
156 Force exit (with a non-zero return value)
153 """
157 """
154 sys.exit("Quit")
158 sys.exit("Quit")
155
159
156 def indent_buffer(event):
160 def indent_buffer(event):
157 event.current_buffer.insert_text(' ' * 4)
161 event.current_buffer.insert_text(' ' * 4)
158
162
159 def newline_with_copy_margin(event):
163 def newline_with_copy_margin(event):
160 """
164 """
161 Preserve margin and cursor position when using
165 Preserve margin and cursor position when using
162 Control-O to insert a newline in EMACS mode
166 Control-O to insert a newline in EMACS mode
163 """
167 """
164 b = event.current_buffer
168 b = event.current_buffer
165 cursor_start_pos = b.document.cursor_position_col
169 cursor_start_pos = b.document.cursor_position_col
166 b.newline(copy_margin=True)
170 b.newline(copy_margin=True)
167 b.cursor_up(count=1)
171 b.cursor_up(count=1)
168 cursor_end_pos = b.document.cursor_position_col
172 cursor_end_pos = b.document.cursor_position_col
169 if cursor_start_pos != cursor_end_pos:
173 if cursor_start_pos != cursor_end_pos:
170 pos_diff = cursor_start_pos - cursor_end_pos
174 pos_diff = cursor_start_pos - cursor_end_pos
171 b.cursor_right(count=pos_diff)
175 b.cursor_right(count=pos_diff)
172
176
173
177 def open_input_in_editor(event):
178 event.cli.current_buffer.tempfile_suffix = ".py"
179 event.cli.current_buffer.open_in_editor(event.cli)
174
180
175
181
176 if sys.platform == 'win32':
182 if sys.platform == 'win32':
177 from IPython.core.error import TryNext
183 from IPython.core.error import TryNext
178 from IPython.lib.clipboard import (ClipboardEmpty,
184 from IPython.lib.clipboard import (ClipboardEmpty,
179 win32_clipboard_get,
185 win32_clipboard_get,
180 tkinter_clipboard_get)
186 tkinter_clipboard_get)
181
187
182 @undoc
188 @undoc
183 def win_paste(event):
189 def win_paste(event):
184 try:
190 try:
185 text = win32_clipboard_get()
191 text = win32_clipboard_get()
186 except TryNext:
192 except TryNext:
187 try:
193 try:
188 text = tkinter_clipboard_get()
194 text = tkinter_clipboard_get()
189 except (TryNext, ClipboardEmpty):
195 except (TryNext, ClipboardEmpty):
190 return
196 return
191 except ClipboardEmpty:
197 except ClipboardEmpty:
192 return
198 return
193 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
199 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
General Comments 0
You need to be logged in to leave comments. Login now