##// END OF EJS Templates
Fix mypy job, fix issues detected by mypy
krassowski -
Show More
@@ -1,39 +1,41 b''
1 name: Run MyPy
1 name: Run MyPy
2
2
3 on:
3 on:
4 push:
4 push:
5 branches: [ main, 7.x]
5 branches: [ main, 7.x]
6 pull_request:
6 pull_request:
7 branches: [ main, 7.x]
7 branches: [ main, 7.x]
8
8
9 permissions:
9 permissions:
10 contents: read
10 contents: read
11
11
12 jobs:
12 jobs:
13 build:
13 build:
14
14
15 runs-on: ubuntu-latest
15 runs-on: ubuntu-latest
16 strategy:
16 strategy:
17 matrix:
17 matrix:
18 python-version: ["3.x"]
18 python-version: ["3.x"]
19
19
20 steps:
20 steps:
21 - uses: actions/checkout@v3
21 - uses: actions/checkout@v3
22 - name: Set up Python ${{ matrix.python-version }}
22 - name: Set up Python ${{ matrix.python-version }}
23 uses: actions/setup-python@v4
23 uses: actions/setup-python@v4
24 with:
24 with:
25 python-version: ${{ matrix.python-version }}
25 python-version: ${{ matrix.python-version }}
26 - name: Install dependencies
26 - name: Install dependencies
27 run: |
27 run: |
28 python -m pip install --upgrade pip
28 python -m pip install --upgrade pip
29 pip install mypy pyflakes flake8
29 pip install mypy pyflakes flake8
30 - name: Lint with mypy
30 - name: Lint with mypy
31 run: |
31 run: |
32 set -e
32 mypy -p IPython.terminal
33 mypy -p IPython.terminal
33 mypy -p IPython.core.magics
34 mypy -p IPython.core.magics
34 mypy -p IPython.core.guarded_eval
35 mypy -p IPython.core.guarded_eval
35 mypy -p IPython.core.completer
36 mypy -p IPython.core.completer
36 - name: Lint with pyflakes
37 - name: Lint with pyflakes
37 run: |
38 run: |
39 set -e
38 flake8 IPython/core/magics/script.py
40 flake8 IPython/core/magics/script.py
39 flake8 IPython/core/magics/packaging.py
41 flake8 IPython/core/magics/packaging.py
@@ -1,605 +1,605 b''
1 """
1 """
2 Module to define and register Terminal IPython shortcuts with
2 Module to define and register Terminal IPython shortcuts with
3 :mod:`prompt_toolkit`
3 :mod:`prompt_toolkit`
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 import warnings
9 import warnings
10 import signal
10 import signal
11 import sys
11 import sys
12 import re
12 import re
13 import os
13 import os
14 from typing import Callable
14 from typing import Callable, Dict, Union
15
15
16
16
17 from prompt_toolkit.application.current import get_app
17 from prompt_toolkit.application.current import get_app
18 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
18 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
19 from prompt_toolkit.filters import (
19 from prompt_toolkit.filters import (
20 has_focus as has_focus_impl,
20 has_focus as has_focus_impl,
21 has_selection,
21 has_selection,
22 Condition,
22 Condition,
23 vi_insert_mode,
23 vi_insert_mode,
24 emacs_insert_mode,
24 emacs_insert_mode,
25 has_completions,
25 has_completions,
26 vi_mode,
26 vi_mode,
27 )
27 )
28 from prompt_toolkit.key_binding.bindings.completion import (
28 from prompt_toolkit.key_binding.bindings.completion import (
29 display_completions_like_readline,
29 display_completions_like_readline,
30 )
30 )
31 from prompt_toolkit.key_binding import KeyBindings
31 from prompt_toolkit.key_binding import KeyBindings
32 from prompt_toolkit.key_binding.bindings import named_commands as nc
32 from prompt_toolkit.key_binding.bindings import named_commands as nc
33 from prompt_toolkit.key_binding.vi_state import InputMode, ViState
33 from prompt_toolkit.key_binding.vi_state import InputMode, ViState
34 from prompt_toolkit.layout.layout import FocusableElement
34 from prompt_toolkit.layout.layout import FocusableElement
35
35
36 from IPython.utils.decorators import undoc
36 from IPython.utils.decorators import undoc
37 from . import auto_match as match, autosuggestions
37 from . import auto_match as match, autosuggestions
38
38
39
39
40 __all__ = ["create_ipython_shortcuts"]
40 __all__ = ["create_ipython_shortcuts"]
41
41
42
42
43 @undoc
43 @undoc
44 @Condition
44 @Condition
45 def cursor_in_leading_ws():
45 def cursor_in_leading_ws():
46 before = get_app().current_buffer.document.current_line_before_cursor
46 before = get_app().current_buffer.document.current_line_before_cursor
47 return (not before) or before.isspace()
47 return (not before) or before.isspace()
48
48
49
49
50 def has_focus(value: FocusableElement):
50 def has_focus(value: FocusableElement):
51 """Wrapper around has_focus adding a nice `__name__` to tester function"""
51 """Wrapper around has_focus adding a nice `__name__` to tester function"""
52 tester = has_focus_impl(value).func
52 tester = has_focus_impl(value).func
53 tester.__name__ = f"is_focused({value})"
53 tester.__name__ = f"is_focused({value})"
54 return Condition(tester)
54 return Condition(tester)
55
55
56
56
57 def create_ipython_shortcuts(shell, for_all_platforms: bool = False):
57 def create_ipython_shortcuts(shell, for_all_platforms: bool = False):
58 """Set up the prompt_toolkit keyboard shortcuts for IPython."""
58 """Set up the prompt_toolkit keyboard shortcuts for IPython."""
59 # Warning: if possible, do NOT define handler functions in the locals
59 # Warning: if possible, do NOT define handler functions in the locals
60 # scope of this function, instead define functions in the global
60 # scope of this function, instead define functions in the global
61 # scope, or a separate module, and include a user-friendly docstring
61 # scope, or a separate module, and include a user-friendly docstring
62 # describing the action.
62 # describing the action.
63
63
64 kb = KeyBindings()
64 kb = KeyBindings()
65 insert_mode = vi_insert_mode | emacs_insert_mode
65 insert_mode = vi_insert_mode | emacs_insert_mode
66
66
67 if getattr(shell, "handle_return", None):
67 if getattr(shell, "handle_return", None):
68 return_handler = shell.handle_return(shell)
68 return_handler = shell.handle_return(shell)
69 else:
69 else:
70 return_handler = newline_or_execute_outer(shell)
70 return_handler = newline_or_execute_outer(shell)
71
71
72 kb.add("enter", filter=(has_focus(DEFAULT_BUFFER) & ~has_selection & insert_mode))(
72 kb.add("enter", filter=(has_focus(DEFAULT_BUFFER) & ~has_selection & insert_mode))(
73 return_handler
73 return_handler
74 )
74 )
75
75
76 @Condition
76 @Condition
77 def ebivim():
77 def ebivim():
78 return shell.emacs_bindings_in_vi_insert_mode
78 return shell.emacs_bindings_in_vi_insert_mode
79
79
80 @kb.add(
80 @kb.add(
81 "escape",
81 "escape",
82 "enter",
82 "enter",
83 filter=(has_focus(DEFAULT_BUFFER) & ~has_selection & insert_mode & ebivim),
83 filter=(has_focus(DEFAULT_BUFFER) & ~has_selection & insert_mode & ebivim),
84 )
84 )
85 def reformat_and_execute(event):
85 def reformat_and_execute(event):
86 """Reformat code and execute it"""
86 """Reformat code and execute it"""
87 reformat_text_before_cursor(
87 reformat_text_before_cursor(
88 event.current_buffer, event.current_buffer.document, shell
88 event.current_buffer, event.current_buffer.document, shell
89 )
89 )
90 event.current_buffer.validate_and_handle()
90 event.current_buffer.validate_and_handle()
91
91
92 kb.add("c-\\")(quit)
92 kb.add("c-\\")(quit)
93
93
94 kb.add("c-p", filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER)))(
94 kb.add("c-p", filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER)))(
95 previous_history_or_previous_completion
95 previous_history_or_previous_completion
96 )
96 )
97
97
98 kb.add("c-n", filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER)))(
98 kb.add("c-n", filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER)))(
99 next_history_or_next_completion
99 next_history_or_next_completion
100 )
100 )
101
101
102 kb.add("c-g", filter=(has_focus(DEFAULT_BUFFER) & has_completions))(
102 kb.add("c-g", filter=(has_focus(DEFAULT_BUFFER) & has_completions))(
103 dismiss_completion
103 dismiss_completion
104 )
104 )
105
105
106 kb.add("c-c", filter=has_focus(DEFAULT_BUFFER))(reset_buffer)
106 kb.add("c-c", filter=has_focus(DEFAULT_BUFFER))(reset_buffer)
107
107
108 kb.add("c-c", filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)
108 kb.add("c-c", filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)
109
109
110 supports_suspend = Condition(lambda: hasattr(signal, "SIGTSTP"))
110 supports_suspend = Condition(lambda: hasattr(signal, "SIGTSTP"))
111 kb.add("c-z", filter=supports_suspend)(suspend_to_bg)
111 kb.add("c-z", filter=supports_suspend)(suspend_to_bg)
112
112
113 # Ctrl+I == Tab
113 # Ctrl+I == Tab
114 kb.add(
114 kb.add(
115 "tab",
115 "tab",
116 filter=(
116 filter=(
117 has_focus(DEFAULT_BUFFER)
117 has_focus(DEFAULT_BUFFER)
118 & ~has_selection
118 & ~has_selection
119 & insert_mode
119 & insert_mode
120 & cursor_in_leading_ws
120 & cursor_in_leading_ws
121 ),
121 ),
122 )(indent_buffer)
122 )(indent_buffer)
123 kb.add("c-o", filter=(has_focus(DEFAULT_BUFFER) & emacs_insert_mode))(
123 kb.add("c-o", filter=(has_focus(DEFAULT_BUFFER) & emacs_insert_mode))(
124 newline_autoindent_outer(shell.input_transformer_manager)
124 newline_autoindent_outer(shell.input_transformer_manager)
125 )
125 )
126
126
127 kb.add("f2", filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
127 kb.add("f2", filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
128
128
129 @Condition
129 @Condition
130 def auto_match():
130 def auto_match():
131 return shell.auto_match
131 return shell.auto_match
132
132
133 def all_quotes_paired(quote, buf):
133 def all_quotes_paired(quote, buf):
134 paired = True
134 paired = True
135 i = 0
135 i = 0
136 while i < len(buf):
136 while i < len(buf):
137 c = buf[i]
137 c = buf[i]
138 if c == quote:
138 if c == quote:
139 paired = not paired
139 paired = not paired
140 elif c == "\\":
140 elif c == "\\":
141 i += 1
141 i += 1
142 i += 1
142 i += 1
143 return paired
143 return paired
144
144
145 focused_insert = (vi_insert_mode | emacs_insert_mode) & has_focus(DEFAULT_BUFFER)
145 focused_insert = (vi_insert_mode | emacs_insert_mode) & has_focus(DEFAULT_BUFFER)
146 _preceding_text_cache = {}
146 _preceding_text_cache: Dict[Union[str, Callable], Condition] = {}
147 _following_text_cache = {}
147 _following_text_cache: Dict[Union[str, Callable], Condition] = {}
148
148
149 def preceding_text(pattern):
149 def preceding_text(pattern: Union[str, Callable]):
150 if pattern in _preceding_text_cache:
150 if pattern in _preceding_text_cache:
151 return _preceding_text_cache[pattern]
151 return _preceding_text_cache[pattern]
152
152
153 if callable(pattern):
153 if callable(pattern):
154
154
155 def _preceding_text():
155 def _preceding_text():
156 app = get_app()
156 app = get_app()
157 before_cursor = app.current_buffer.document.current_line_before_cursor
157 before_cursor = app.current_buffer.document.current_line_before_cursor
158 return bool(pattern(before_cursor))
158 return bool(pattern(before_cursor))
159
159
160 else:
160 else:
161 m = re.compile(pattern)
161 m = re.compile(pattern)
162
162
163 def _preceding_text():
163 def _preceding_text():
164 app = get_app()
164 app = get_app()
165 before_cursor = app.current_buffer.document.current_line_before_cursor
165 before_cursor = app.current_buffer.document.current_line_before_cursor
166 return bool(m.match(before_cursor))
166 return bool(m.match(before_cursor))
167
167
168 _preceding_text.__name__ = f"preceding_text({pattern!r})"
168 _preceding_text.__name__ = f"preceding_text({pattern!r})"
169
169
170 condition = Condition(_preceding_text)
170 condition = Condition(_preceding_text)
171 _preceding_text_cache[pattern] = condition
171 _preceding_text_cache[pattern] = condition
172 return condition
172 return condition
173
173
174 def following_text(pattern):
174 def following_text(pattern):
175 try:
175 try:
176 return _following_text_cache[pattern]
176 return _following_text_cache[pattern]
177 except KeyError:
177 except KeyError:
178 pass
178 pass
179 m = re.compile(pattern)
179 m = re.compile(pattern)
180
180
181 def _following_text():
181 def _following_text():
182 app = get_app()
182 app = get_app()
183 return bool(m.match(app.current_buffer.document.current_line_after_cursor))
183 return bool(m.match(app.current_buffer.document.current_line_after_cursor))
184
184
185 _following_text.__name__ = f"following_text({pattern!r})"
185 _following_text.__name__ = f"following_text({pattern!r})"
186
186
187 condition = Condition(_following_text)
187 condition = Condition(_following_text)
188 _following_text_cache[pattern] = condition
188 _following_text_cache[pattern] = condition
189 return condition
189 return condition
190
190
191 @Condition
191 @Condition
192 def not_inside_unclosed_string():
192 def not_inside_unclosed_string():
193 app = get_app()
193 app = get_app()
194 s = app.current_buffer.document.text_before_cursor
194 s = app.current_buffer.document.text_before_cursor
195 # remove escaped quotes
195 # remove escaped quotes
196 s = s.replace('\\"', "").replace("\\'", "")
196 s = s.replace('\\"', "").replace("\\'", "")
197 # remove triple-quoted string literals
197 # remove triple-quoted string literals
198 s = re.sub(r"(?:\"\"\"[\s\S]*\"\"\"|'''[\s\S]*''')", "", s)
198 s = re.sub(r"(?:\"\"\"[\s\S]*\"\"\"|'''[\s\S]*''')", "", s)
199 # remove single-quoted string literals
199 # remove single-quoted string literals
200 s = re.sub(r"""(?:"[^"]*["\n]|'[^']*['\n])""", "", s)
200 s = re.sub(r"""(?:"[^"]*["\n]|'[^']*['\n])""", "", s)
201 return not ('"' in s or "'" in s)
201 return not ('"' in s or "'" in s)
202
202
203 # auto match
203 # auto match
204 auto_match_parens = {"(": match.parenthesis, "[": match.brackets, "{": match.braces}
204 auto_match_parens = {"(": match.parenthesis, "[": match.brackets, "{": match.braces}
205 for key, cmd in auto_match_parens.items():
205 for key, cmd in auto_match_parens.items():
206 kb.add(key, filter=focused_insert & auto_match & following_text(r"[,)}\]]|$"))(
206 kb.add(key, filter=focused_insert & auto_match & following_text(r"[,)}\]]|$"))(
207 cmd
207 cmd
208 )
208 )
209
209
210 kb.add(
210 kb.add(
211 '"',
211 '"',
212 filter=focused_insert
212 filter=focused_insert
213 & auto_match
213 & auto_match
214 & not_inside_unclosed_string
214 & not_inside_unclosed_string
215 & preceding_text(lambda line: all_quotes_paired('"', line))
215 & preceding_text(lambda line: all_quotes_paired('"', line))
216 & following_text(r"[,)}\]]|$"),
216 & following_text(r"[,)}\]]|$"),
217 )(match.double_quote)
217 )(match.double_quote)
218
218
219 kb.add(
219 kb.add(
220 "'",
220 "'",
221 filter=focused_insert
221 filter=focused_insert
222 & auto_match
222 & auto_match
223 & not_inside_unclosed_string
223 & not_inside_unclosed_string
224 & preceding_text(lambda line: all_quotes_paired("'", line))
224 & preceding_text(lambda line: all_quotes_paired("'", line))
225 & following_text(r"[,)}\]]|$"),
225 & following_text(r"[,)}\]]|$"),
226 )(match.single_quote)
226 )(match.single_quote)
227
227
228 kb.add(
228 kb.add(
229 '"',
229 '"',
230 filter=focused_insert
230 filter=focused_insert
231 & auto_match
231 & auto_match
232 & not_inside_unclosed_string
232 & not_inside_unclosed_string
233 & preceding_text(r'^.*""$'),
233 & preceding_text(r'^.*""$'),
234 )(match.docstring_double_quotes)
234 )(match.docstring_double_quotes)
235
235
236 kb.add(
236 kb.add(
237 "'",
237 "'",
238 filter=focused_insert
238 filter=focused_insert
239 & auto_match
239 & auto_match
240 & not_inside_unclosed_string
240 & not_inside_unclosed_string
241 & preceding_text(r"^.*''$"),
241 & preceding_text(r"^.*''$"),
242 )(match.docstring_single_quotes)
242 )(match.docstring_single_quotes)
243
243
244 # raw string
244 # raw string
245 auto_match_parens_raw_string = {
245 auto_match_parens_raw_string = {
246 "(": match.raw_string_parenthesis,
246 "(": match.raw_string_parenthesis,
247 "[": match.raw_string_bracket,
247 "[": match.raw_string_bracket,
248 "{": match.raw_string_braces,
248 "{": match.raw_string_braces,
249 }
249 }
250 for key, cmd in auto_match_parens_raw_string.items():
250 for key, cmd in auto_match_parens_raw_string.items():
251 kb.add(
251 kb.add(
252 key,
252 key,
253 filter=focused_insert & auto_match & preceding_text(r".*(r|R)[\"'](-*)$"),
253 filter=focused_insert & auto_match & preceding_text(r".*(r|R)[\"'](-*)$"),
254 )(cmd)
254 )(cmd)
255
255
256 # just move cursor
256 # just move cursor
257 kb.add(")", filter=focused_insert & auto_match & following_text(r"^\)"))(
257 kb.add(")", filter=focused_insert & auto_match & following_text(r"^\)"))(
258 match.skip_over
258 match.skip_over
259 )
259 )
260 kb.add("]", filter=focused_insert & auto_match & following_text(r"^\]"))(
260 kb.add("]", filter=focused_insert & auto_match & following_text(r"^\]"))(
261 match.skip_over
261 match.skip_over
262 )
262 )
263 kb.add("}", filter=focused_insert & auto_match & following_text(r"^\}"))(
263 kb.add("}", filter=focused_insert & auto_match & following_text(r"^\}"))(
264 match.skip_over
264 match.skip_over
265 )
265 )
266 kb.add('"', filter=focused_insert & auto_match & following_text('^"'))(
266 kb.add('"', filter=focused_insert & auto_match & following_text('^"'))(
267 match.skip_over
267 match.skip_over
268 )
268 )
269 kb.add("'", filter=focused_insert & auto_match & following_text("^'"))(
269 kb.add("'", filter=focused_insert & auto_match & following_text("^'"))(
270 match.skip_over
270 match.skip_over
271 )
271 )
272
272
273 kb.add(
273 kb.add(
274 "backspace",
274 "backspace",
275 filter=focused_insert
275 filter=focused_insert
276 & preceding_text(r".*\($")
276 & preceding_text(r".*\($")
277 & auto_match
277 & auto_match
278 & following_text(r"^\)"),
278 & following_text(r"^\)"),
279 )(match.delete_pair)
279 )(match.delete_pair)
280 kb.add(
280 kb.add(
281 "backspace",
281 "backspace",
282 filter=focused_insert
282 filter=focused_insert
283 & preceding_text(r".*\[$")
283 & preceding_text(r".*\[$")
284 & auto_match
284 & auto_match
285 & following_text(r"^\]"),
285 & following_text(r"^\]"),
286 )(match.delete_pair)
286 )(match.delete_pair)
287 kb.add(
287 kb.add(
288 "backspace",
288 "backspace",
289 filter=focused_insert
289 filter=focused_insert
290 & preceding_text(r".*\{$")
290 & preceding_text(r".*\{$")
291 & auto_match
291 & auto_match
292 & following_text(r"^\}"),
292 & following_text(r"^\}"),
293 )(match.delete_pair)
293 )(match.delete_pair)
294 kb.add(
294 kb.add(
295 "backspace",
295 "backspace",
296 filter=focused_insert
296 filter=focused_insert
297 & preceding_text('.*"$')
297 & preceding_text('.*"$')
298 & auto_match
298 & auto_match
299 & following_text('^"'),
299 & following_text('^"'),
300 )(match.delete_pair)
300 )(match.delete_pair)
301 kb.add(
301 kb.add(
302 "backspace",
302 "backspace",
303 filter=focused_insert
303 filter=focused_insert
304 & preceding_text(r".*'$")
304 & preceding_text(r".*'$")
305 & auto_match
305 & auto_match
306 & following_text(r"^'"),
306 & following_text(r"^'"),
307 )(match.delete_pair)
307 )(match.delete_pair)
308
308
309 if shell.display_completions == "readlinelike":
309 if shell.display_completions == "readlinelike":
310 kb.add(
310 kb.add(
311 "c-i",
311 "c-i",
312 filter=(
312 filter=(
313 has_focus(DEFAULT_BUFFER)
313 has_focus(DEFAULT_BUFFER)
314 & ~has_selection
314 & ~has_selection
315 & insert_mode
315 & insert_mode
316 & ~cursor_in_leading_ws
316 & ~cursor_in_leading_ws
317 ),
317 ),
318 )(display_completions_like_readline)
318 )(display_completions_like_readline)
319
319
320 if sys.platform == "win32" or for_all_platforms:
320 if sys.platform == "win32" or for_all_platforms:
321 kb.add("c-v", filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
321 kb.add("c-v", filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
322
322
323 focused_insert_vi = has_focus(DEFAULT_BUFFER) & vi_insert_mode
323 focused_insert_vi = has_focus(DEFAULT_BUFFER) & vi_insert_mode
324
324
325 # autosuggestions
325 # autosuggestions
326 kb.add("end", filter=has_focus(DEFAULT_BUFFER) & (ebivim | ~vi_insert_mode))(
326 kb.add("end", filter=has_focus(DEFAULT_BUFFER) & (ebivim | ~vi_insert_mode))(
327 autosuggestions.accept_in_vi_insert_mode
327 autosuggestions.accept_in_vi_insert_mode
328 )
328 )
329 kb.add("c-e", filter=focused_insert_vi & ebivim)(
329 kb.add("c-e", filter=focused_insert_vi & ebivim)(
330 autosuggestions.accept_in_vi_insert_mode
330 autosuggestions.accept_in_vi_insert_mode
331 )
331 )
332 kb.add("c-f", filter=focused_insert_vi)(autosuggestions.accept)
332 kb.add("c-f", filter=focused_insert_vi)(autosuggestions.accept)
333 kb.add("escape", "f", filter=focused_insert_vi & ebivim)(
333 kb.add("escape", "f", filter=focused_insert_vi & ebivim)(
334 autosuggestions.accept_word
334 autosuggestions.accept_word
335 )
335 )
336
336
337 # Simple Control keybindings
337 # Simple Control keybindings
338 key_cmd_dict = {
338 key_cmd_dict = {
339 "c-a": nc.beginning_of_line,
339 "c-a": nc.beginning_of_line,
340 "c-b": nc.backward_char,
340 "c-b": nc.backward_char,
341 "c-k": nc.kill_line,
341 "c-k": nc.kill_line,
342 "c-w": nc.backward_kill_word,
342 "c-w": nc.backward_kill_word,
343 "c-y": nc.yank,
343 "c-y": nc.yank,
344 "c-_": nc.undo,
344 "c-_": nc.undo,
345 }
345 }
346
346
347 for key, cmd in key_cmd_dict.items():
347 for key, cmd in key_cmd_dict.items():
348 kb.add(key, filter=focused_insert_vi & ebivim)(cmd)
348 kb.add(key, filter=focused_insert_vi & ebivim)(cmd)
349
349
350 # Alt and Combo Control keybindings
350 # Alt and Combo Control keybindings
351 keys_cmd_dict = {
351 keys_cmd_dict = {
352 # Control Combos
352 # Control Combos
353 ("c-x", "c-e"): nc.edit_and_execute,
353 ("c-x", "c-e"): nc.edit_and_execute,
354 ("c-x", "e"): nc.edit_and_execute,
354 ("c-x", "e"): nc.edit_and_execute,
355 # Alt
355 # Alt
356 ("escape", "b"): nc.backward_word,
356 ("escape", "b"): nc.backward_word,
357 ("escape", "c"): nc.capitalize_word,
357 ("escape", "c"): nc.capitalize_word,
358 ("escape", "d"): nc.kill_word,
358 ("escape", "d"): nc.kill_word,
359 ("escape", "h"): nc.backward_kill_word,
359 ("escape", "h"): nc.backward_kill_word,
360 ("escape", "l"): nc.downcase_word,
360 ("escape", "l"): nc.downcase_word,
361 ("escape", "u"): nc.uppercase_word,
361 ("escape", "u"): nc.uppercase_word,
362 ("escape", "y"): nc.yank_pop,
362 ("escape", "y"): nc.yank_pop,
363 ("escape", "."): nc.yank_last_arg,
363 ("escape", "."): nc.yank_last_arg,
364 }
364 }
365
365
366 for keys, cmd in keys_cmd_dict.items():
366 for keys, cmd in keys_cmd_dict.items():
367 kb.add(*keys, filter=focused_insert_vi & ebivim)(cmd)
367 kb.add(*keys, filter=focused_insert_vi & ebivim)(cmd)
368
368
369 def get_input_mode(self):
369 def get_input_mode(self):
370 app = get_app()
370 app = get_app()
371 app.ttimeoutlen = shell.ttimeoutlen
371 app.ttimeoutlen = shell.ttimeoutlen
372 app.timeoutlen = shell.timeoutlen
372 app.timeoutlen = shell.timeoutlen
373
373
374 return self._input_mode
374 return self._input_mode
375
375
376 def set_input_mode(self, mode):
376 def set_input_mode(self, mode):
377 shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
377 shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
378 cursor = "\x1b[{} q".format(shape)
378 cursor = "\x1b[{} q".format(shape)
379
379
380 sys.stdout.write(cursor)
380 sys.stdout.write(cursor)
381 sys.stdout.flush()
381 sys.stdout.flush()
382
382
383 self._input_mode = mode
383 self._input_mode = mode
384
384
385 if shell.editing_mode == "vi" and shell.modal_cursor:
385 if shell.editing_mode == "vi" and shell.modal_cursor:
386 ViState._input_mode = InputMode.INSERT
386 ViState._input_mode = InputMode.INSERT # type: ignore
387 ViState.input_mode = property(get_input_mode, set_input_mode)
387 ViState.input_mode = property(get_input_mode, set_input_mode) # type: ignore
388
388
389 return kb
389 return kb
390
390
391
391
392 def reformat_text_before_cursor(buffer, document, shell):
392 def reformat_text_before_cursor(buffer, document, shell):
393 text = buffer.delete_before_cursor(len(document.text[: document.cursor_position]))
393 text = buffer.delete_before_cursor(len(document.text[: document.cursor_position]))
394 try:
394 try:
395 formatted_text = shell.reformat_handler(text)
395 formatted_text = shell.reformat_handler(text)
396 buffer.insert_text(formatted_text)
396 buffer.insert_text(formatted_text)
397 except Exception as e:
397 except Exception as e:
398 buffer.insert_text(text)
398 buffer.insert_text(text)
399
399
400
400
401 def newline_or_execute_outer(shell):
401 def newline_or_execute_outer(shell):
402 def newline_or_execute(event):
402 def newline_or_execute(event):
403 """When the user presses return, insert a newline or execute the code."""
403 """When the user presses return, insert a newline or execute the code."""
404 b = event.current_buffer
404 b = event.current_buffer
405 d = b.document
405 d = b.document
406
406
407 if b.complete_state:
407 if b.complete_state:
408 cc = b.complete_state.current_completion
408 cc = b.complete_state.current_completion
409 if cc:
409 if cc:
410 b.apply_completion(cc)
410 b.apply_completion(cc)
411 else:
411 else:
412 b.cancel_completion()
412 b.cancel_completion()
413 return
413 return
414
414
415 # If there's only one line, treat it as if the cursor is at the end.
415 # If there's only one line, treat it as if the cursor is at the end.
416 # See https://github.com/ipython/ipython/issues/10425
416 # See https://github.com/ipython/ipython/issues/10425
417 if d.line_count == 1:
417 if d.line_count == 1:
418 check_text = d.text
418 check_text = d.text
419 else:
419 else:
420 check_text = d.text[: d.cursor_position]
420 check_text = d.text[: d.cursor_position]
421 status, indent = shell.check_complete(check_text)
421 status, indent = shell.check_complete(check_text)
422
422
423 # if all we have after the cursor is whitespace: reformat current text
423 # if all we have after the cursor is whitespace: reformat current text
424 # before cursor
424 # before cursor
425 after_cursor = d.text[d.cursor_position :]
425 after_cursor = d.text[d.cursor_position :]
426 reformatted = False
426 reformatted = False
427 if not after_cursor.strip():
427 if not after_cursor.strip():
428 reformat_text_before_cursor(b, d, shell)
428 reformat_text_before_cursor(b, d, shell)
429 reformatted = True
429 reformatted = True
430 if not (
430 if not (
431 d.on_last_line
431 d.on_last_line
432 or d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
432 or d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
433 ):
433 ):
434 if shell.autoindent:
434 if shell.autoindent:
435 b.insert_text("\n" + indent)
435 b.insert_text("\n" + indent)
436 else:
436 else:
437 b.insert_text("\n")
437 b.insert_text("\n")
438 return
438 return
439
439
440 if (status != "incomplete") and b.accept_handler:
440 if (status != "incomplete") and b.accept_handler:
441 if not reformatted:
441 if not reformatted:
442 reformat_text_before_cursor(b, d, shell)
442 reformat_text_before_cursor(b, d, shell)
443 b.validate_and_handle()
443 b.validate_and_handle()
444 else:
444 else:
445 if shell.autoindent:
445 if shell.autoindent:
446 b.insert_text("\n" + indent)
446 b.insert_text("\n" + indent)
447 else:
447 else:
448 b.insert_text("\n")
448 b.insert_text("\n")
449
449
450 newline_or_execute.__qualname__ = "newline_or_execute"
450 newline_or_execute.__qualname__ = "newline_or_execute"
451
451
452 return newline_or_execute
452 return newline_or_execute
453
453
454
454
455 def previous_history_or_previous_completion(event):
455 def previous_history_or_previous_completion(event):
456 """
456 """
457 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
457 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
458
458
459 If completer is open this still select previous completion.
459 If completer is open this still select previous completion.
460 """
460 """
461 event.current_buffer.auto_up()
461 event.current_buffer.auto_up()
462
462
463
463
464 def next_history_or_next_completion(event):
464 def next_history_or_next_completion(event):
465 """
465 """
466 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
466 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
467
467
468 If completer is open this still select next completion.
468 If completer is open this still select next completion.
469 """
469 """
470 event.current_buffer.auto_down()
470 event.current_buffer.auto_down()
471
471
472
472
473 def dismiss_completion(event):
473 def dismiss_completion(event):
474 """Dismiss completion"""
474 """Dismiss completion"""
475 b = event.current_buffer
475 b = event.current_buffer
476 if b.complete_state:
476 if b.complete_state:
477 b.cancel_completion()
477 b.cancel_completion()
478
478
479
479
480 def reset_buffer(event):
480 def reset_buffer(event):
481 """Reset buffer"""
481 """Reset buffer"""
482 b = event.current_buffer
482 b = event.current_buffer
483 if b.complete_state:
483 if b.complete_state:
484 b.cancel_completion()
484 b.cancel_completion()
485 else:
485 else:
486 b.reset()
486 b.reset()
487
487
488
488
489 def reset_search_buffer(event):
489 def reset_search_buffer(event):
490 """Reset search buffer"""
490 """Reset search buffer"""
491 if event.current_buffer.document.text:
491 if event.current_buffer.document.text:
492 event.current_buffer.reset()
492 event.current_buffer.reset()
493 else:
493 else:
494 event.app.layout.focus(DEFAULT_BUFFER)
494 event.app.layout.focus(DEFAULT_BUFFER)
495
495
496
496
497 def suspend_to_bg(event):
497 def suspend_to_bg(event):
498 """Suspend to background"""
498 """Suspend to background"""
499 event.app.suspend_to_background()
499 event.app.suspend_to_background()
500
500
501
501
502 def quit(event):
502 def quit(event):
503 """
503 """
504 Quit application with ``SIGQUIT`` if supported or ``sys.exit`` otherwise.
504 Quit application with ``SIGQUIT`` if supported or ``sys.exit`` otherwise.
505
505
506 On platforms that support SIGQUIT, send SIGQUIT to the current process.
506 On platforms that support SIGQUIT, send SIGQUIT to the current process.
507 On other platforms, just exit the process with a message.
507 On other platforms, just exit the process with a message.
508 """
508 """
509 sigquit = getattr(signal, "SIGQUIT", None)
509 sigquit = getattr(signal, "SIGQUIT", None)
510 if sigquit is not None:
510 if sigquit is not None:
511 os.kill(0, signal.SIGQUIT)
511 os.kill(0, signal.SIGQUIT)
512 else:
512 else:
513 sys.exit("Quit")
513 sys.exit("Quit")
514
514
515
515
516 def indent_buffer(event):
516 def indent_buffer(event):
517 """Indent buffer"""
517 """Indent buffer"""
518 event.current_buffer.insert_text(" " * 4)
518 event.current_buffer.insert_text(" " * 4)
519
519
520
520
521 @undoc
521 @undoc
522 def newline_with_copy_margin(event):
522 def newline_with_copy_margin(event):
523 """
523 """
524 DEPRECATED since IPython 6.0
524 DEPRECATED since IPython 6.0
525
525
526 See :any:`newline_autoindent_outer` for a replacement.
526 See :any:`newline_autoindent_outer` for a replacement.
527
527
528 Preserve margin and cursor position when using
528 Preserve margin and cursor position when using
529 Control-O to insert a newline in EMACS mode
529 Control-O to insert a newline in EMACS mode
530 """
530 """
531 warnings.warn(
531 warnings.warn(
532 "`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
532 "`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
533 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
533 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
534 DeprecationWarning,
534 DeprecationWarning,
535 stacklevel=2,
535 stacklevel=2,
536 )
536 )
537
537
538 b = event.current_buffer
538 b = event.current_buffer
539 cursor_start_pos = b.document.cursor_position_col
539 cursor_start_pos = b.document.cursor_position_col
540 b.newline(copy_margin=True)
540 b.newline(copy_margin=True)
541 b.cursor_up(count=1)
541 b.cursor_up(count=1)
542 cursor_end_pos = b.document.cursor_position_col
542 cursor_end_pos = b.document.cursor_position_col
543 if cursor_start_pos != cursor_end_pos:
543 if cursor_start_pos != cursor_end_pos:
544 pos_diff = cursor_start_pos - cursor_end_pos
544 pos_diff = cursor_start_pos - cursor_end_pos
545 b.cursor_right(count=pos_diff)
545 b.cursor_right(count=pos_diff)
546
546
547
547
548 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
548 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
549 """
549 """
550 Return a function suitable for inserting a indented newline after the cursor.
550 Return a function suitable for inserting a indented newline after the cursor.
551
551
552 Fancier version of deprecated ``newline_with_copy_margin`` which should
552 Fancier version of deprecated ``newline_with_copy_margin`` which should
553 compute the correct indentation of the inserted line. That is to say, indent
553 compute the correct indentation of the inserted line. That is to say, indent
554 by 4 extra space after a function definition, class definition, context
554 by 4 extra space after a function definition, class definition, context
555 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
555 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
556 """
556 """
557
557
558 def newline_autoindent(event):
558 def newline_autoindent(event):
559 """Insert a newline after the cursor indented appropriately."""
559 """Insert a newline after the cursor indented appropriately."""
560 b = event.current_buffer
560 b = event.current_buffer
561 d = b.document
561 d = b.document
562
562
563 if b.complete_state:
563 if b.complete_state:
564 b.cancel_completion()
564 b.cancel_completion()
565 text = d.text[: d.cursor_position] + "\n"
565 text = d.text[: d.cursor_position] + "\n"
566 _, indent = inputsplitter.check_complete(text)
566 _, indent = inputsplitter.check_complete(text)
567 b.insert_text("\n" + (" " * (indent or 0)), move_cursor=False)
567 b.insert_text("\n" + (" " * (indent or 0)), move_cursor=False)
568
568
569 newline_autoindent.__qualname__ = "newline_autoindent"
569 newline_autoindent.__qualname__ = "newline_autoindent"
570
570
571 return newline_autoindent
571 return newline_autoindent
572
572
573
573
574 def open_input_in_editor(event):
574 def open_input_in_editor(event):
575 """Open code from input in external editor"""
575 """Open code from input in external editor"""
576 event.app.current_buffer.open_in_editor()
576 event.app.current_buffer.open_in_editor()
577
577
578
578
579 if sys.platform == "win32":
579 if sys.platform == "win32":
580 from IPython.core.error import TryNext
580 from IPython.core.error import TryNext
581 from IPython.lib.clipboard import (
581 from IPython.lib.clipboard import (
582 ClipboardEmpty,
582 ClipboardEmpty,
583 win32_clipboard_get,
583 win32_clipboard_get,
584 tkinter_clipboard_get,
584 tkinter_clipboard_get,
585 )
585 )
586
586
587 @undoc
587 @undoc
588 def win_paste(event):
588 def win_paste(event):
589 try:
589 try:
590 text = win32_clipboard_get()
590 text = win32_clipboard_get()
591 except TryNext:
591 except TryNext:
592 try:
592 try:
593 text = tkinter_clipboard_get()
593 text = tkinter_clipboard_get()
594 except (TryNext, ClipboardEmpty):
594 except (TryNext, ClipboardEmpty):
595 return
595 return
596 except ClipboardEmpty:
596 except ClipboardEmpty:
597 return
597 return
598 event.current_buffer.insert_text(text.replace("\t", " " * 4))
598 event.current_buffer.insert_text(text.replace("\t", " " * 4))
599
599
600 else:
600 else:
601
601
602 @undoc
602 @undoc
603 def win_paste(event):
603 def win_paste(event):
604 """Stub used when auto-generating shortcuts for documentation"""
604 """Stub used when auto-generating shortcuts for documentation"""
605 pass
605 pass
@@ -1,90 +1,90 b''
1 import re
1 import re
2 from prompt_toolkit.key_binding import KeyPressEvent
2 from prompt_toolkit.key_binding import KeyPressEvent
3
3
4
4
5 def parenthesis(event: KeyPressEvent):
5 def parenthesis(event: KeyPressEvent):
6 """Auto-close parenthesis"""
6 """Auto-close parenthesis"""
7 event.current_buffer.insert_text("()")
7 event.current_buffer.insert_text("()")
8 event.current_buffer.cursor_left()
8 event.current_buffer.cursor_left()
9
9
10
10
11 def brackets(event: KeyPressEvent):
11 def brackets(event: KeyPressEvent):
12 """Auto-close brackets"""
12 """Auto-close brackets"""
13 event.current_buffer.insert_text("[]")
13 event.current_buffer.insert_text("[]")
14 event.current_buffer.cursor_left()
14 event.current_buffer.cursor_left()
15
15
16
16
17 def braces(event: KeyPressEvent):
17 def braces(event: KeyPressEvent):
18 """Auto-close braces"""
18 """Auto-close braces"""
19 event.current_buffer.insert_text("{}")
19 event.current_buffer.insert_text("{}")
20 event.current_buffer.cursor_left()
20 event.current_buffer.cursor_left()
21
21
22
22
23 def double_quote(event: KeyPressEvent):
23 def double_quote(event: KeyPressEvent):
24 """Auto-close double quotes"""
24 """Auto-close double quotes"""
25 event.current_buffer.insert_text('""')
25 event.current_buffer.insert_text('""')
26 event.current_buffer.cursor_left()
26 event.current_buffer.cursor_left()
27
27
28
28
29 def single_quote(event: KeyPressEvent):
29 def single_quote(event: KeyPressEvent):
30 """Auto-close single quotes"""
30 """Auto-close single quotes"""
31 event.current_buffer.insert_text("''")
31 event.current_buffer.insert_text("''")
32 event.current_buffer.cursor_left()
32 event.current_buffer.cursor_left()
33
33
34
34
35 def docstring_double_quotes(event: KeyPressEvent):
35 def docstring_double_quotes(event: KeyPressEvent):
36 """Auto-close docstring (double quotes)"""
36 """Auto-close docstring (double quotes)"""
37 event.current_buffer.insert_text('""""')
37 event.current_buffer.insert_text('""""')
38 event.current_buffer.cursor_left(3)
38 event.current_buffer.cursor_left(3)
39
39
40
40
41 def docstring_single_quotes(event: KeyPressEvent):
41 def docstring_single_quotes(event: KeyPressEvent):
42 """Auto-close docstring (single quotes)"""
42 """Auto-close docstring (single quotes)"""
43 event.current_buffer.insert_text("''''")
43 event.current_buffer.insert_text("''''")
44 event.current_buffer.cursor_left(3)
44 event.current_buffer.cursor_left(3)
45
45
46
46
47 def raw_string_parenthesis(event: KeyPressEvent):
47 def raw_string_parenthesis(event: KeyPressEvent):
48 """Auto-close parenthesis in raw strings"""
48 """Auto-close parenthesis in raw strings"""
49 matches = re.match(
49 matches = re.match(
50 r".*(r|R)[\"'](-*)",
50 r".*(r|R)[\"'](-*)",
51 event.current_buffer.document.current_line_before_cursor,
51 event.current_buffer.document.current_line_before_cursor,
52 )
52 )
53 dashes = matches.group(2) or ""
53 dashes = matches.group(2) if matches else ""
54 event.current_buffer.insert_text("()" + dashes)
54 event.current_buffer.insert_text("()" + dashes)
55 event.current_buffer.cursor_left(len(dashes) + 1)
55 event.current_buffer.cursor_left(len(dashes) + 1)
56
56
57
57
58 def raw_string_bracket(event: KeyPressEvent):
58 def raw_string_bracket(event: KeyPressEvent):
59 """Auto-close bracker in raw strings"""
59 """Auto-close bracker in raw strings"""
60 matches = re.match(
60 matches = re.match(
61 r".*(r|R)[\"'](-*)",
61 r".*(r|R)[\"'](-*)",
62 event.current_buffer.document.current_line_before_cursor,
62 event.current_buffer.document.current_line_before_cursor,
63 )
63 )
64 dashes = matches.group(2) or ""
64 dashes = matches.group(2) if matches else ""
65 event.current_buffer.insert_text("[]" + dashes)
65 event.current_buffer.insert_text("[]" + dashes)
66 event.current_buffer.cursor_left(len(dashes) + 1)
66 event.current_buffer.cursor_left(len(dashes) + 1)
67
67
68
68
69 def raw_string_braces(event: KeyPressEvent):
69 def raw_string_braces(event: KeyPressEvent):
70 """Auto-close braces in raw strings"""
70 """Auto-close braces in raw strings"""
71 matches = re.match(
71 matches = re.match(
72 r".*(r|R)[\"'](-*)",
72 r".*(r|R)[\"'](-*)",
73 event.current_buffer.document.current_line_before_cursor,
73 event.current_buffer.document.current_line_before_cursor,
74 )
74 )
75 dashes = matches.group(2) or ""
75 dashes = matches.group(2) if matches else ""
76 event.current_buffer.insert_text("{}" + dashes)
76 event.current_buffer.insert_text("{}" + dashes)
77 event.current_buffer.cursor_left(len(dashes) + 1)
77 event.current_buffer.cursor_left(len(dashes) + 1)
78
78
79
79
80 def skip_over(event: KeyPressEvent):
80 def skip_over(event: KeyPressEvent):
81 """Skip over automatically added parenthesis.
81 """Skip over automatically added parenthesis.
82
82
83 (rather than adding another parenthesis)"""
83 (rather than adding another parenthesis)"""
84 event.current_buffer.cursor_right()
84 event.current_buffer.cursor_right()
85
85
86
86
87 def delete_pair(event: KeyPressEvent):
87 def delete_pair(event: KeyPressEvent):
88 """Delete auto-closed parenthesis"""
88 """Delete auto-closed parenthesis"""
89 event.current_buffer.delete()
89 event.current_buffer.delete()
90 event.current_buffer.delete_before_cursor()
90 event.current_buffer.delete_before_cursor()
General Comments 0
You need to be logged in to leave comments. Login now