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