##// END OF EJS Templates
Backport PR #10225: Add 'v' binding in vi-navigation-mode to %edit....
Thomas Kluyver -
r23347:f7867ad3 auto-backport-of-...
parent child Browse files
Show More
@@ -1,201 +1,205 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 before_text = d.text[:d.cursor_position]
103 before_text = d.text[:d.cursor_position]
100 status, indent = shell.input_splitter.check_complete(before_text + '\n')
104 status, indent = shell.input_splitter.check_complete(before_text + '\n')
101
105
102 if not (d.on_last_line or
106 if not (d.on_last_line or
103 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
107 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
104 ):
108 ):
105 b.insert_text('\n' + (' ' * (indent or 0)))
109 b.insert_text('\n' + (' ' * (indent or 0)))
106 return
110 return
107
111
108 if (status != 'incomplete') and b.accept_action.is_returnable:
112 if (status != 'incomplete') and b.accept_action.is_returnable:
109 b.accept_action.validate_and_handle(event.cli, b)
113 b.accept_action.validate_and_handle(event.cli, b)
110 else:
114 else:
111 b.insert_text('\n' + (' ' * (indent or 0)))
115 b.insert_text('\n' + (' ' * (indent or 0)))
112 return newline_or_execute
116 return newline_or_execute
113
117
114
118
115 def previous_history_or_previous_completion(event):
119 def previous_history_or_previous_completion(event):
116 """
120 """
117 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
121 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
118
122
119 If completer is open this still select previous completion.
123 If completer is open this still select previous completion.
120 """
124 """
121 event.current_buffer.auto_up()
125 event.current_buffer.auto_up()
122
126
123
127
124 def next_history_or_next_completion(event):
128 def next_history_or_next_completion(event):
125 """
129 """
126 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
130 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
127
131
128 If completer is open this still select next completion.
132 If completer is open this still select next completion.
129 """
133 """
130 event.current_buffer.auto_down()
134 event.current_buffer.auto_down()
131
135
132
136
133 def dismiss_completion(event):
137 def dismiss_completion(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
141
138
142
139 def reset_buffer(event):
143 def reset_buffer(event):
140 b = event.current_buffer
144 b = event.current_buffer
141 if b.complete_state:
145 if b.complete_state:
142 b.cancel_completion()
146 b.cancel_completion()
143 else:
147 else:
144 b.reset()
148 b.reset()
145
149
146
150
147 def reset_search_buffer(event):
151 def reset_search_buffer(event):
148 if event.current_buffer.document.text:
152 if event.current_buffer.document.text:
149 event.current_buffer.reset()
153 event.current_buffer.reset()
150 else:
154 else:
151 event.cli.push_focus(DEFAULT_BUFFER)
155 event.cli.push_focus(DEFAULT_BUFFER)
152
156
153 def suspend_to_bg(event):
157 def suspend_to_bg(event):
154 event.cli.suspend_to_background()
158 event.cli.suspend_to_background()
155
159
156 def force_exit(event):
160 def force_exit(event):
157 """
161 """
158 Force exit (with a non-zero return value)
162 Force exit (with a non-zero return value)
159 """
163 """
160 sys.exit("Quit")
164 sys.exit("Quit")
161
165
162 def indent_buffer(event):
166 def indent_buffer(event):
163 event.current_buffer.insert_text(' ' * 4)
167 event.current_buffer.insert_text(' ' * 4)
164
168
165 def newline_with_copy_margin(event):
169 def newline_with_copy_margin(event):
166 """
170 """
167 Preserve margin and cursor position when using
171 Preserve margin and cursor position when using
168 Control-O to insert a newline in EMACS mode
172 Control-O to insert a newline in EMACS mode
169 """
173 """
170 b = event.current_buffer
174 b = event.current_buffer
171 cursor_start_pos = b.document.cursor_position_col
175 cursor_start_pos = b.document.cursor_position_col
172 b.newline(copy_margin=True)
176 b.newline(copy_margin=True)
173 b.cursor_up(count=1)
177 b.cursor_up(count=1)
174 cursor_end_pos = b.document.cursor_position_col
178 cursor_end_pos = b.document.cursor_position_col
175 if cursor_start_pos != cursor_end_pos:
179 if cursor_start_pos != cursor_end_pos:
176 pos_diff = cursor_start_pos - cursor_end_pos
180 pos_diff = cursor_start_pos - cursor_end_pos
177 b.cursor_right(count=pos_diff)
181 b.cursor_right(count=pos_diff)
178
182
179 def open_input_in_editor(event):
183 def open_input_in_editor(event):
180 event.cli.current_buffer.tempfile_suffix = ".py"
184 event.cli.current_buffer.tempfile_suffix = ".py"
181 event.cli.current_buffer.open_in_editor(event.cli)
185 event.cli.current_buffer.open_in_editor(event.cli)
182
186
183
187
184 if sys.platform == 'win32':
188 if sys.platform == 'win32':
185 from IPython.core.error import TryNext
189 from IPython.core.error import TryNext
186 from IPython.lib.clipboard import (ClipboardEmpty,
190 from IPython.lib.clipboard import (ClipboardEmpty,
187 win32_clipboard_get,
191 win32_clipboard_get,
188 tkinter_clipboard_get)
192 tkinter_clipboard_get)
189
193
190 @undoc
194 @undoc
191 def win_paste(event):
195 def win_paste(event):
192 try:
196 try:
193 text = win32_clipboard_get()
197 text = win32_clipboard_get()
194 except TryNext:
198 except TryNext:
195 try:
199 try:
196 text = tkinter_clipboard_get()
200 text = tkinter_clipboard_get()
197 except (TryNext, ClipboardEmpty):
201 except (TryNext, ClipboardEmpty):
198 return
202 return
199 except ClipboardEmpty:
203 except ClipboardEmpty:
200 return
204 return
201 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
205 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
General Comments 0
You need to be logged in to leave comments. Login now