##// END OF EJS Templates
preserve margins when using Ctrl-O for newline...
Gil Forsyth -
Show More
@@ -1,167 +1,185 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.ControlP,
29 registry.add_binding(Keys.ControlP,
30 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
30 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
31 ))(previous_history_or_previous_completion)
31 ))(previous_history_or_previous_completion)
32
32
33 registry.add_binding(Keys.ControlN,
33 registry.add_binding(Keys.ControlN,
34 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
34 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
35 ))(next_history_or_next_completion)
35 ))(next_history_or_next_completion)
36
36
37 registry.add_binding(Keys.ControlG,
37 registry.add_binding(Keys.ControlG,
38 filter=(HasFocus(DEFAULT_BUFFER) & HasCompletions()
38 filter=(HasFocus(DEFAULT_BUFFER) & HasCompletions()
39 ))(dismiss_completion)
39 ))(dismiss_completion)
40
40
41 registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)
41 registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)
42 )(reset_buffer)
42 )(reset_buffer)
43
43
44 registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)
44 registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)
45 )(reset_search_buffer)
45 )(reset_search_buffer)
46
46
47 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
47 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
48 registry.add_binding(Keys.ControlZ, filter=supports_suspend
48 registry.add_binding(Keys.ControlZ, filter=supports_suspend
49 )(suspend_to_bg)
49 )(suspend_to_bg)
50
50
51 # Ctrl+I == Tab
51 # Ctrl+I == Tab
52 registry.add_binding(Keys.ControlI,
52 registry.add_binding(Keys.ControlI,
53 filter=(HasFocus(DEFAULT_BUFFER)
53 filter=(HasFocus(DEFAULT_BUFFER)
54 & ~HasSelection()
54 & ~HasSelection()
55 & insert_mode
55 & insert_mode
56 & cursor_in_leading_ws
56 & cursor_in_leading_ws
57 ))(indent_buffer)
57 ))(indent_buffer)
58
58
59 registry.add_binding(Keys.ControlO,
60 filter=(HasFocus(DEFAULT_BUFFER)
61 & insert_mode))(newline_with_copy_margin)
62
59 if shell.display_completions == 'readlinelike':
63 if shell.display_completions == 'readlinelike':
60 registry.add_binding(Keys.ControlI,
64 registry.add_binding(Keys.ControlI,
61 filter=(HasFocus(DEFAULT_BUFFER)
65 filter=(HasFocus(DEFAULT_BUFFER)
62 & ~HasSelection()
66 & ~HasSelection()
63 & insert_mode
67 & insert_mode
64 & ~cursor_in_leading_ws
68 & ~cursor_in_leading_ws
65 ))(display_completions_like_readline)
69 ))(display_completions_like_readline)
66
70
67 if sys.platform == 'win32':
71 if sys.platform == 'win32':
68 registry.add_binding(Keys.ControlV,
72 registry.add_binding(Keys.ControlV,
69 filter=(
73 filter=(
70 HasFocus(
74 HasFocus(
71 DEFAULT_BUFFER) & ~ViMode()
75 DEFAULT_BUFFER) & ~ViMode()
72 ))(win_paste)
76 ))(win_paste)
73
77
74
78
75 def newline_or_execute_outer(shell):
79 def newline_or_execute_outer(shell):
76 def newline_or_execute(event):
80 def newline_or_execute(event):
77 """When the user presses return, insert a newline or execute the code."""
81 """When the user presses return, insert a newline or execute the code."""
78 b = event.current_buffer
82 b = event.current_buffer
79 d = b.document
83 d = b.document
80
84
81 if b.complete_state:
85 if b.complete_state:
82 cc = b.complete_state.current_completion
86 cc = b.complete_state.current_completion
83 if cc:
87 if cc:
84 b.apply_completion(cc)
88 b.apply_completion(cc)
85 else:
89 else:
86 b.cancel_completion()
90 b.cancel_completion()
87 return
91 return
88
92
89 if not (d.on_last_line or d.cursor_position_row >= d.line_count
93 if not (d.on_last_line or d.cursor_position_row >= d.line_count
90 - d.empty_line_count_at_the_end()):
94 - d.empty_line_count_at_the_end()):
91 b.newline()
95 b.newline()
92 return
96 return
93
97
94 status, indent = shell.input_splitter.check_complete(d.text + '\n')
98 status, indent = shell.input_splitter.check_complete(d.text + '\n')
95
99
96 if (status != 'incomplete') and b.accept_action.is_returnable:
100 if (status != 'incomplete') and b.accept_action.is_returnable:
97 b.accept_action.validate_and_handle(event.cli, b)
101 b.accept_action.validate_and_handle(event.cli, b)
98 else:
102 else:
99 b.insert_text('\n' + (' ' * (indent or 0)))
103 b.insert_text('\n' + (' ' * (indent or 0)))
100 return newline_or_execute
104 return newline_or_execute
101
105
102
106
103 def previous_history_or_previous_completion(event):
107 def previous_history_or_previous_completion(event):
104 """
108 """
105 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
109 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
106
110
107 If completer is open this still select previous completion.
111 If completer is open this still select previous completion.
108 """
112 """
109 event.current_buffer.auto_up()
113 event.current_buffer.auto_up()
110
114
111
115
112 def next_history_or_next_completion(event):
116 def next_history_or_next_completion(event):
113 """
117 """
114 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
118 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
115
119
116 If completer is open this still select next completion.
120 If completer is open this still select next completion.
117 """
121 """
118 event.current_buffer.auto_down()
122 event.current_buffer.auto_down()
119
123
120
124
121 def dismiss_completion(event):
125 def dismiss_completion(event):
122 b = event.current_buffer
126 b = event.current_buffer
123 if b.complete_state:
127 if b.complete_state:
124 b.cancel_completion()
128 b.cancel_completion()
125
129
126
130
127 def reset_buffer(event):
131 def reset_buffer(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 else:
135 else:
132 b.reset()
136 b.reset()
133
137
134
138
135 def reset_search_buffer(event):
139 def reset_search_buffer(event):
136 if event.current_buffer.document.text:
140 if event.current_buffer.document.text:
137 event.current_buffer.reset()
141 event.current_buffer.reset()
138 else:
142 else:
139 event.cli.push_focus(DEFAULT_BUFFER)
143 event.cli.push_focus(DEFAULT_BUFFER)
140
144
141 def suspend_to_bg(event):
145 def suspend_to_bg(event):
142 event.cli.suspend_to_background()
146 event.cli.suspend_to_background()
143
147
144 def indent_buffer(event):
148 def indent_buffer(event):
145 event.current_buffer.insert_text(' ' * 4)
149 event.current_buffer.insert_text(' ' * 4)
146
150
151 def newline_with_copy_margin(event):
152 """
153 Preserve margin and cursor position when using
154 Control-O to insert a newline in EMACS mode
155 """
156 b = event.current_buffer
157 cursor_start_pos = b.document.cursor_position_col
158 b.newline(copy_margin=True)
159 b.cursor_up(count=1)
160 cursor_end_pos = b.document.cursor_position_col
161 if cursor_start_pos != cursor_end_pos:
162 pos_diff = cursor_start_pos - cursor_end_pos
163 b.cursor_right(count=pos_diff)
164
147
165
148
166
149
167
150 if sys.platform == 'win32':
168 if sys.platform == 'win32':
151 from IPython.core.error import TryNext
169 from IPython.core.error import TryNext
152 from IPython.lib.clipboard import (ClipboardEmpty,
170 from IPython.lib.clipboard import (ClipboardEmpty,
153 win32_clipboard_get,
171 win32_clipboard_get,
154 tkinter_clipboard_get)
172 tkinter_clipboard_get)
155
173
156 @undoc
174 @undoc
157 def win_paste(event):
175 def win_paste(event):
158 try:
176 try:
159 text = win32_clipboard_get()
177 text = win32_clipboard_get()
160 except TryNext:
178 except TryNext:
161 try:
179 try:
162 text = tkinter_clipboard_get()
180 text = tkinter_clipboard_get()
163 except (TryNext, ClipboardEmpty):
181 except (TryNext, ClipboardEmpty):
164 return
182 return
165 except ClipboardEmpty:
183 except ClipboardEmpty:
166 return
184 return
167 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
185 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
General Comments 0
You need to be logged in to leave comments. Login now