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