##// END OF EJS Templates
Upgrade to prompt_toolkit 2.0
Jonathan Slenders -
Show More
@@ -8,15 +8,14 b' from .ptutils import IPythonPTCompleter'
8 from .shortcuts import suspend_to_bg, cursor_in_leading_ws
8 from .shortcuts import suspend_to_bg, cursor_in_leading_ws
9
9
10 from prompt_toolkit.enums import DEFAULT_BUFFER
10 from prompt_toolkit.enums import DEFAULT_BUFFER
11 from prompt_toolkit.filters import (Condition, HasFocus, HasSelection,
11 from prompt_toolkit.filters import (Condition, has_focus, has_selection,
12 ViInsertMode, EmacsInsertMode)
12 vi_insert_mode, emacs_insert_mode)
13 from prompt_toolkit.keys import Keys
13 from prompt_toolkit.key_binding import KeyBindings
14 from prompt_toolkit.key_binding.manager import KeyBindingManager
15 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
14 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
16 from prompt_toolkit.token import Token
15 from pygments.token import Token
17 from prompt_toolkit.shortcuts import create_prompt_application
16 from prompt_toolkit.shortcuts.prompt import PromptSession
18 from prompt_toolkit.interface import CommandLineInterface
19 from prompt_toolkit.enums import EditingMode
17 from prompt_toolkit.enums import EditingMode
18 from prompt_toolkit.formatted_text import PygmentsTokens
20
19
21
20
22 class TerminalPdb(Pdb):
21 class TerminalPdb(Pdb):
@@ -26,46 +25,40 b' class TerminalPdb(Pdb):'
26 self.pt_init()
25 self.pt_init()
27
26
28 def pt_init(self):
27 def pt_init(self):
29 def get_prompt_tokens(cli):
28 def get_prompt_tokens():
30 return [(Token.Prompt, self.prompt)]
29 return [(Token.Prompt, self.prompt)]
31
30
32 def patch_stdout(**kwargs):
33 return self.pt_cli.patch_stdout_context(**kwargs)
34
35 if self._ptcomp is None:
31 if self._ptcomp is None:
36 compl = IPCompleter(shell=self.shell,
32 compl = IPCompleter(shell=self.shell,
37 namespace={},
33 namespace={},
38 global_namespace={},
34 global_namespace={},
39 parent=self.shell,
35 parent=self.shell,
40 )
36 )
41 self._ptcomp = IPythonPTCompleter(compl, patch_stdout=patch_stdout)
37 self._ptcomp = IPythonPTCompleter(compl)
42
38
43 kbmanager = KeyBindingManager.for_prompt()
39 kb = KeyBindings()
44 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
40 supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
45 kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend
41 kb.add('c-z', filter=supports_suspend)(suspend_to_bg)
46 )(suspend_to_bg)
47
42
48 if self.shell.display_completions == 'readlinelike':
43 if self.shell.display_completions == 'readlinelike':
49 kbmanager.registry.add_binding(Keys.ControlI,
44 kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
50 filter=(HasFocus(DEFAULT_BUFFER)
45 & ~has_selection
51 & ~HasSelection()
46 & vi_insert_mode | emacs_insert_mode
52 & ViInsertMode() | EmacsInsertMode()
47 & ~cursor_in_leading_ws
53 & ~cursor_in_leading_ws
48 ))(display_completions_like_readline)
54 ))(display_completions_like_readline)
49
55 multicolumn = (self.shell.display_completions == 'multicolumn')
50 self.pt_app = PromptSession(
56
51 message=(lambda: PygmentsTokens(get_prompt_tokens())),
57 self._pt_app = create_prompt_application(
58 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
52 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
59 key_bindings_registry=kbmanager.registry,
53 key_bindings=kb,
60 history=self.shell.debugger_history,
54 history=self.shell.debugger_history,
61 completer= self._ptcomp,
55 completer=self._ptcomp,
62 enable_history_search=True,
56 enable_history_search=True,
63 mouse_support=self.shell.mouse_support,
57 mouse_support=self.shell.mouse_support,
64 get_prompt_tokens=get_prompt_tokens,
58 complete_style=self.shell.pt_complete_style,
65 display_completions_in_columns=multicolumn,
59 style=self.shell.style,
66 style=self.shell.style
60 inputhook=self.shell.inputhook,
67 )
61 )
68 self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
69
62
70 def cmdloop(self, intro=None):
63 def cmdloop(self, intro=None):
71 """Repeatedly issue a prompt, accept input, parse an initial prefix
64 """Repeatedly issue a prompt, accept input, parse an initial prefix
@@ -92,7 +85,7 b' class TerminalPdb(Pdb):'
92 self._ptcomp.ipy_completer.namespace = self.curframe_locals
85 self._ptcomp.ipy_completer.namespace = self.curframe_locals
93 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
86 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
94 try:
87 try:
95 line = self.pt_cli.run(reset_current_buffer=True).text
88 line = self.pt_app.prompt() # reset_current_buffer=True)
96 except EOFError:
89 except EOFError:
97 line = 'EOF'
90 line = 'EOF'
98 line = self.precmd(line)
91 line = self.precmd(line)
@@ -18,12 +18,15 b' from traitlets import ('
18 from prompt_toolkit.document import Document
18 from prompt_toolkit.document import Document
19 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
19 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
20 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
20 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
21 from prompt_toolkit.formatted_text import PygmentsTokens
21 from prompt_toolkit.history import InMemoryHistory
22 from prompt_toolkit.history import InMemoryHistory
22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
23 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle
23 from prompt_toolkit.interface import CommandLineInterface
24 from prompt_toolkit.output.defaults import create_output
24 from prompt_toolkit.key_binding.manager import KeyBindingManager
25 from prompt_toolkit.key_binding import KeyBindings
25 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
26 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
26 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
27 from prompt_toolkit.patch_stdout import patch_stdout
28 from prompt_toolkit.styles import DynamicStyle, merge_styles
29 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
27
30
28 from pygments.styles import get_style_by_name
31 from pygments.styles import get_style_by_name
29 from pygments.style import Style
32 from pygments.style import Style
@@ -34,7 +37,7 b' from .magics import TerminalMagics'
34 from .pt_inputhooks import get_inputhook_name_and_func
37 from .pt_inputhooks import get_inputhook_name_and_func
35 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
38 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
36 from .ptutils import IPythonPTCompleter, IPythonPTLexer
39 from .ptutils import IPythonPTCompleter, IPythonPTLexer
37 from .shortcuts import register_ipython_shortcuts
40 from .shortcuts import create_ipython_shortcuts
38
41
39 DISPLAY_BANNER_DEPRECATED = object()
42 DISPLAY_BANNER_DEPRECATED = object()
40
43
@@ -91,12 +94,11 b' class TerminalInteractiveShell(InteractiveShell):'
91 'to reserve for the completion menu'
94 'to reserve for the completion menu'
92 ).tag(config=True)
95 ).tag(config=True)
93
96
94 def _space_for_menu_changed(self, old, new):
97 # def _space_for_menu_changed(self, old, new):
95 self._update_layout()
98 # self._update_layout()
96
99
97 pt_cli = None
100 pt_app = None
98 debugger_history = None
101 debugger_history = None
99 _pt_app = None
100
102
101 simple_prompt = Bool(_use_simple_prompt,
103 simple_prompt = Bool(_use_simple_prompt,
102 help="""Use `raw_input` for the REPL, without completion and prompt colors.
104 help="""Use `raw_input` for the REPL, without completion and prompt colors.
@@ -167,9 +169,9 b' class TerminalInteractiveShell(InteractiveShell):'
167 def _prompts_default(self):
169 def _prompts_default(self):
168 return self.prompts_class(self)
170 return self.prompts_class(self)
169
171
170 @observe('prompts')
172 # @observe('prompts')
171 def _(self, change):
173 # def _(self, change):
172 self._update_layout()
174 # self._update_layout()
173
175
174 @default('displayhook_class')
176 @default('displayhook_class')
175 def _displayhook_class_default(self):
177 def _displayhook_class_default(self):
@@ -243,10 +245,7 b' class TerminalInteractiveShell(InteractiveShell):'
243 return
245 return
244
246
245 # Set up keyboard shortcuts
247 # Set up keyboard shortcuts
246 kbmanager = KeyBindingManager.for_prompt(
248 key_bindings = create_ipython_shortcuts(self)
247 enable_open_in_editor=self.extra_open_editor_shortcuts,
248 )
249 register_ipython_shortcuts(kbmanager.registry, self)
250
249
251 # Pre-populate history from IPython's history database
250 # Pre-populate history from IPython's history database
252 history = InMemoryHistory()
251 history = InMemoryHistory()
@@ -256,7 +255,7 b' class TerminalInteractiveShell(InteractiveShell):'
256 # Ignore blank lines and consecutive duplicates
255 # Ignore blank lines and consecutive duplicates
257 cell = cell.rstrip()
256 cell = cell.rstrip()
258 if cell and (cell != last_cell):
257 if cell and (cell != last_cell):
259 history.append(cell)
258 history.append_string(cell)
260 last_cell = cell
259 last_cell = cell
261
260
262 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
261 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
@@ -264,24 +263,18 b' class TerminalInteractiveShell(InteractiveShell):'
264
263
265 editing_mode = getattr(EditingMode, self.editing_mode.upper())
264 editing_mode = getattr(EditingMode, self.editing_mode.upper())
266
265
267 def patch_stdout(**kwargs):
266 self.pt_app = PromptSession(
268 return self.pt_cli.patch_stdout_context(**kwargs)
269
270 self._pt_app = create_prompt_application(
271 editing_mode=editing_mode,
267 editing_mode=editing_mode,
272 key_bindings_registry=kbmanager.registry,
268 key_bindings=key_bindings,
273 history=history,
269 history=history,
274 completer=IPythonPTCompleter(shell=self,
270 completer=IPythonPTCompleter(shell=self),
275 patch_stdout=patch_stdout),
271 enable_history_search = self.enable_history_search,
276 enable_history_search=self.enable_history_search,
277 style=self.style,
272 style=self.style,
273 include_default_pygments_style=False,
278 mouse_support=self.mouse_support,
274 mouse_support=self.mouse_support,
279 **self._layout_options()
275 enable_open_in_editor=self.extra_open_editor_shortcuts,
280 )
276 color_depth=(ColorDepth.TRUE_COLOR if self.true_color else None),
281 self._eventloop = create_eventloop(self.inputhook)
277 **self._extra_prompt_options())
282 self.pt_cli = CommandLineInterface(
283 self._pt_app, eventloop=self._eventloop,
284 output=create_output(true_color=self.true_color))
285
278
286 def _make_style_from_name_or_cls(self, name_or_cls):
279 def _make_style_from_name_or_cls(self, name_or_cls):
287 """
280 """
@@ -342,44 +335,60 b' class TerminalInteractiveShell(InteractiveShell):'
342 Token.OutPromptNum: '#ff0000 bold',
335 Token.OutPromptNum: '#ff0000 bold',
343 }
336 }
344 style_overrides.update(self.highlighting_style_overrides)
337 style_overrides.update(self.highlighting_style_overrides)
345 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
338 style = merge_styles([
346 style_dict=style_overrides)
339 style_from_pygments_cls(style_cls),
340 style_from_pygments_dict(style_overrides),
341 ])
347
342
348 return style
343 return style
349
344
350 def _layout_options(self):
345 @property
346 def pt_complete_style(self):
347 return {
348 'multicolumn': CompleteStyle.MULTI_COLUMN,
349 'column': CompleteStyle.COLUMN,
350 'readlinelike': CompleteStyle.READLINE_LIKE,
351 }[self.display_completions],
352
353 def _extra_prompt_options(self):
351 """
354 """
352 Return the current layout option for the current Terminal InteractiveShell
355 Return the current layout option for the current Terminal InteractiveShell
353 """
356 """
357 def get_message():
358 return PygmentsTokens(self.prompts.in_prompt_tokens())
359
354 return {
360 return {
361 'complete_in_thread': False,
355 'lexer':IPythonPTLexer(),
362 'lexer':IPythonPTLexer(),
356 'reserve_space_for_menu':self.space_for_menu,
363 'reserve_space_for_menu':self.space_for_menu,
357 'get_prompt_tokens':self.prompts.in_prompt_tokens,
364 'message': get_message,
358 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
365 'prompt_continuation': (
359 'multiline':True,
366 lambda width, lineno, is_soft_wrap:
360 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
367 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
368 'multiline': True,
369 'complete_style': self.pt_complete_style,
361
370
362 # Highlight matching brackets, but only when this setting is
371 # Highlight matching brackets, but only when this setting is
363 # enabled, and only when the DEFAULT_BUFFER has the focus.
372 # enabled, and only when the DEFAULT_BUFFER has the focus.
364 'extra_input_processors': [ConditionalProcessor(
373 'input_processors': [ConditionalProcessor(
365 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
374 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
366 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
375 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
367 Condition(lambda cli: self.highlight_matching_brackets))],
376 Condition(lambda: self.highlight_matching_brackets))],
368 }
377 }
369
378
370 def _update_layout(self):
371 """
372 Ask for a re computation of the application layout, if for example ,
373 some configuration options have changed.
374 """
375 if self._pt_app:
376 self._pt_app.layout = create_prompt_layout(**self._layout_options())
377
378 def prompt_for_code(self):
379 def prompt_for_code(self):
379 with self.pt_cli.patch_stdout_context(raw=True):
380 if self.rl_next_input:
380 document = self.pt_cli.run(
381 default = self.rl_next_input
381 pre_run=self.pre_prompt, reset_current_buffer=True)
382 self.rl_next_input = None
382 return document.text
383 else:
384 default = ''
385
386 with patch_stdout(raw=True):
387 text = self.pt_app.prompt(
388 default=default,
389 # pre_run=self.pre_prompt,# reset_current_buffer=True,
390 **self._extra_prompt_options())
391 return text
383
392
384 def enable_win_unicode_console(self):
393 def enable_win_unicode_console(self):
385 if sys.version_info >= (3, 6):
394 if sys.version_info >= (3, 6):
@@ -439,22 +448,6 b' class TerminalInteractiveShell(InteractiveShell):'
439
448
440 rl_next_input = None
449 rl_next_input = None
441
450
442 def pre_prompt(self):
443 if self.rl_next_input:
444 # We can't set the buffer here, because it will be reset just after
445 # this. Adding a callable to pre_run_callables does what we need
446 # after the buffer is reset.
447 s = self.rl_next_input
448 def set_doc():
449 self.pt_cli.application.buffer.document = Document(s)
450 if hasattr(self.pt_cli, 'pre_run_callables'):
451 self.pt_cli.pre_run_callables.append(set_doc)
452 else:
453 # Older version of prompt_toolkit; it's OK to set the document
454 # directly here.
455 set_doc()
456 self.rl_next_input = None
457
458 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
451 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
459
452
460 if display_banner is not DISPLAY_BANNER_DEPRECATED:
453 if display_banner is not DISPLAY_BANNER_DEPRECATED:
@@ -517,8 +510,8 b' class TerminalInteractiveShell(InteractiveShell):'
517 return
510 return
518
511
519 tokens = self.prompts.rewrite_prompt_tokens()
512 tokens = self.prompts.rewrite_prompt_tokens()
520 if self.pt_cli:
513 if self.pt_app:
521 self.pt_cli.print_tokens(tokens)
514 self.pt_app.print_tokens(tokens) # XXX
522 print(cmd)
515 print(cmd)
523 else:
516 else:
524 prompt = ''.join(s for t, s in tokens)
517 prompt = ''.join(s for t, s in tokens)
@@ -533,7 +526,7 b' class TerminalInteractiveShell(InteractiveShell):'
533 elif self._prompts_before:
526 elif self._prompts_before:
534 self.prompts = self._prompts_before
527 self.prompts = self._prompts_before
535 self._prompts_before = None
528 self._prompts_before = None
536 self._update_layout()
529 # self._update_layout()
537
530
538
531
539 InteractiveShellABC.register(TerminalInteractiveShell)
532 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -5,13 +5,15 b' import sys'
5
5
6 from IPython.core.displayhook import DisplayHook
6 from IPython.core.displayhook import DisplayHook
7
7
8 from prompt_toolkit.layout.utils import token_list_width
8 from prompt_toolkit.formatted_text import fragment_list_width, PygmentsTokens
9 from prompt_toolkit.shortcuts import print_formatted_text
10
9
11
10 class Prompts(object):
12 class Prompts(object):
11 def __init__(self, shell):
13 def __init__(self, shell):
12 self.shell = shell
14 self.shell = shell
13
15
14 def in_prompt_tokens(self, cli=None):
16 def in_prompt_tokens(self):
15 return [
17 return [
16 (Token.Prompt, 'In ['),
18 (Token.Prompt, 'In ['),
17 (Token.PromptNum, str(self.shell.execution_count)),
19 (Token.PromptNum, str(self.shell.execution_count)),
@@ -19,9 +21,9 b' class Prompts(object):'
19 ]
21 ]
20
22
21 def _width(self):
23 def _width(self):
22 return token_list_width(self.in_prompt_tokens())
24 return fragment_list_width(self.in_prompt_tokens())
23
25
24 def continuation_prompt_tokens(self, cli=None, width=None):
26 def continuation_prompt_tokens(self, width=None):
25 if width is None:
27 if width is None:
26 width = self._width()
28 width = self._width()
27 return [
29 return [
@@ -42,12 +44,12 b' class Prompts(object):'
42 ]
44 ]
43
45
44 class ClassicPrompts(Prompts):
46 class ClassicPrompts(Prompts):
45 def in_prompt_tokens(self, cli=None):
47 def in_prompt_tokens(self):
46 return [
48 return [
47 (Token.Prompt, '>>> '),
49 (Token.Prompt, '>>> '),
48 ]
50 ]
49
51
50 def continuation_prompt_tokens(self, cli=None, width=None):
52 def continuation_prompt_tokens(self, width=None):
51 return [
53 return [
52 (Token.Prompt, '... ')
54 (Token.Prompt, '... ')
53 ]
55 ]
@@ -73,7 +75,8 b' class RichPromptDisplayHook(DisplayHook):'
73 # Ask for a newline before multiline output
75 # Ask for a newline before multiline output
74 self.prompt_end_newline = False
76 self.prompt_end_newline = False
75
77
76 if self.shell.pt_cli:
78 if self.shell.pt_app:
77 self.shell.pt_cli.print_tokens(tokens)
79 print_formatted_text(
80 PygmentsTokens(tokens), style=self.shell.pt_app.app.style)
78 else:
81 else:
79 sys.stdout.write(prompt_txt)
82 sys.stdout.write(prompt_txt)
@@ -14,8 +14,9 b' from IPython.core.completer import ('
14 provisionalcompleter, cursor_to_position,
14 provisionalcompleter, cursor_to_position,
15 _deduplicate_completions)
15 _deduplicate_completions)
16 from prompt_toolkit.completion import Completer, Completion
16 from prompt_toolkit.completion import Completer, Completion
17 from prompt_toolkit.layout.lexers import Lexer
17 from prompt_toolkit.lexers import Lexer
18 from prompt_toolkit.layout.lexers import PygmentsLexer
18 from prompt_toolkit.lexers import PygmentsLexer
19 from prompt_toolkit.patch_stdout import patch_stdout
19
20
20 import pygments.lexers as pygments_lexers
21 import pygments.lexers as pygments_lexers
21
22
@@ -52,14 +53,11 b' def _adjust_completion_text_based_on_context(text, body, offset):'
52
53
53 class IPythonPTCompleter(Completer):
54 class IPythonPTCompleter(Completer):
54 """Adaptor to provide IPython completions to prompt_toolkit"""
55 """Adaptor to provide IPython completions to prompt_toolkit"""
55 def __init__(self, ipy_completer=None, shell=None, patch_stdout=None):
56 def __init__(self, ipy_completer=None, shell=None):
56 if shell is None and ipy_completer is None:
57 if shell is None and ipy_completer is None:
57 raise TypeError("Please pass shell=an InteractiveShell instance.")
58 raise TypeError("Please pass shell=an InteractiveShell instance.")
58 self._ipy_completer = ipy_completer
59 self._ipy_completer = ipy_completer
59 self.shell = shell
60 self.shell = shell
60 if patch_stdout is None:
61 raise TypeError("Please pass patch_stdout")
62 self.patch_stdout = patch_stdout
63
61
64 @property
62 @property
65 def ipy_completer(self):
63 def ipy_completer(self):
@@ -75,7 +73,7 b' class IPythonPTCompleter(Completer):'
75 # is imported). This context manager ensures that doesn't interfere with
73 # is imported). This context manager ensures that doesn't interfere with
76 # the prompt.
74 # the prompt.
77
75
78 with self.patch_stdout(), provisionalcompleter():
76 with patch_stdout(), provisionalcompleter():
79 body = document.text
77 body = document.text
80 cursor_row = document.cursor_position_row
78 cursor_row = document.cursor_position_row
81 cursor_col = document.cursor_position_col
79 cursor_col = document.cursor_position_col
@@ -143,7 +141,7 b' class IPythonPTLexer(Lexer):'
143 'latex': PygmentsLexer(l.TexLexer),
141 'latex': PygmentsLexer(l.TexLexer),
144 }
142 }
145
143
146 def lex_document(self, cli, document):
144 def lex_document(self, document):
147 text = document.text.lstrip()
145 text = document.text.lstrip()
148
146
149 lexer = self.python_lexer
147 lexer = self.python_lexer
@@ -157,4 +155,4 b' class IPythonPTLexer(Lexer):'
157 lexer = l
155 lexer = l
158 break
156 break
159
157
160 return lexer.lex_document(cli, document)
158 return lexer.lex_document(document)
@@ -12,91 +12,79 b' import sys'
12 from typing import Callable
12 from typing import Callable
13
13
14
14
15 from prompt_toolkit.application.current import get_app
15 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
16 from prompt_toolkit.filters import (HasFocus, HasSelection, Condition,
17 from prompt_toolkit.filters import (has_focus, has_selection, Condition,
17 ViInsertMode, EmacsInsertMode, HasCompletions)
18 vi_insert_mode, emacs_insert_mode, has_completions, vi_mode)
18 from prompt_toolkit.filters.cli import ViMode, ViNavigationMode
19 from prompt_toolkit.keys import Keys
20 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
19 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
20 from prompt_toolkit.key_binding import KeyBindings
21
21
22 from IPython.utils.decorators import undoc
22 from IPython.utils.decorators import undoc
23
23
24 @undoc
24 @undoc
25 @Condition
25 @Condition
26 def cursor_in_leading_ws(cli):
26 def cursor_in_leading_ws():
27 before = cli.application.buffer.document.current_line_before_cursor
27 before = get_app().current_buffer.document.current_line_before_cursor
28 return (not before) or before.isspace()
28 return (not before) or before.isspace()
29
29
30 def register_ipython_shortcuts(registry, shell):
30
31 def create_ipython_shortcuts(shell):
31 """Set up the prompt_toolkit keyboard shortcuts for IPython"""
32 """Set up the prompt_toolkit keyboard shortcuts for IPython"""
32 insert_mode = ViInsertMode() | EmacsInsertMode()
33
34 kb = KeyBindings()
35 insert_mode = vi_insert_mode | emacs_insert_mode
33
36
34 if getattr(shell, 'handle_return', None):
37 if getattr(shell, 'handle_return', None):
35 return_handler = shell.handle_return(shell)
38 return_handler = shell.handle_return(shell)
36 else:
39 else:
37 return_handler = newline_or_execute_outer(shell)
40 return_handler = newline_or_execute_outer(shell)
38
41
39 # Ctrl+J == Enter, seemingly
42 kb.add('enter', filter=(has_focus(DEFAULT_BUFFER)
40 registry.add_binding(Keys.ControlJ,
43 & ~has_selection
41 filter=(HasFocus(DEFAULT_BUFFER)
44 & insert_mode
42 & ~HasSelection()
43 & insert_mode
44 ))(return_handler)
45 ))(return_handler)
45
46
46 registry.add_binding(Keys.ControlBackslash)(force_exit)
47 kb.add('c-\\')(force_exit)
47
48
48 registry.add_binding(Keys.ControlP,
49 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
49 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
50 )(previous_history_or_previous_completion)
50 ))(previous_history_or_previous_completion)
51
51
52 registry.add_binding(Keys.ControlN,
52 kb.add('c-n', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
53 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
53 )(next_history_or_next_completion)
54 ))(next_history_or_next_completion)
55
54
56 registry.add_binding(Keys.ControlG,
55 kb.add('c-g', filter=(has_focus(DEFAULT_BUFFER) & has_completions)
57 filter=(HasFocus(DEFAULT_BUFFER) & HasCompletions()
56 )(dismiss_completion)
58 ))(dismiss_completion)
59
57
60 registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)
58 kb.add('c-c', filter=has_focus(DEFAULT_BUFFER))(reset_buffer)
61 )(reset_buffer)
62
59
63 registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)
60 kb.add('c-c', filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)
64 )(reset_search_buffer)
65
61
66 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
62 supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
67 registry.add_binding(Keys.ControlZ, filter=supports_suspend
63 kb.add('c-z', filter=supports_suspend)(suspend_to_bg)
68 )(suspend_to_bg)
69
64
70 # Ctrl+I == Tab
65 # Ctrl+I == Tab
71 registry.add_binding(Keys.ControlI,
66 kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
72 filter=(HasFocus(DEFAULT_BUFFER)
67 & ~has_selection
73 & ~HasSelection()
68 & insert_mode
74 & insert_mode
69 & cursor_in_leading_ws
75 & cursor_in_leading_ws
76 ))(indent_buffer)
70 ))(indent_buffer)
77
71
78 registry.add_binding(Keys.ControlO,
72 kb.add('c-o', filter=(has_focus(DEFAULT_BUFFER)
79 filter=(HasFocus(DEFAULT_BUFFER)
73 & emacs_insert_mode))(newline_autoindent_outer(shell.input_splitter))
80 & EmacsInsertMode()))(newline_autoindent_outer(shell.input_splitter))
81
74
82 registry.add_binding(Keys.F2,
75 kb.add('f2', filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
83 filter=HasFocus(DEFAULT_BUFFER)
84 )(open_input_in_editor)
85
76
86 if shell.display_completions == 'readlinelike':
77 if shell.display_completions == 'readlinelike':
87 registry.add_binding(Keys.ControlI,
78 kb.add('c-i', filter=(has_focus(DEFAULT_BUFFER)
88 filter=(HasFocus(DEFAULT_BUFFER)
79 & ~has_selection
89 & ~HasSelection()
80 & insert_mode
90 & insert_mode
81 & ~cursor_in_leading_ws
91 & ~cursor_in_leading_ws
82 ))(display_completions_like_readline)
92 ))(display_completions_like_readline)
93
83
94 if sys.platform == 'win32':
84 if sys.platform == 'win32':
95 registry.add_binding(Keys.ControlV,
85 kb.add('c-v', filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
96 filter=(
86
97 HasFocus(
87 return kb
98 DEFAULT_BUFFER) & ~ViMode()
99 ))(win_paste)
100
88
101
89
102 def newline_or_execute_outer(shell):
90 def newline_or_execute_outer(shell):
@@ -127,8 +115,8 b' def newline_or_execute_outer(shell):'
127 b.insert_text('\n' + (' ' * (indent or 0)))
115 b.insert_text('\n' + (' ' * (indent or 0)))
128 return
116 return
129
117
130 if (status != 'incomplete') and b.accept_action.is_returnable:
118 if (status != 'incomplete') and b.accept_handler:
131 b.accept_action.validate_and_handle(event.cli, b)
119 b.validate_and_handle()
132 else:
120 else:
133 b.insert_text('\n' + (' ' * (indent or 0)))
121 b.insert_text('\n' + (' ' * (indent or 0)))
134 return newline_or_execute
122 return newline_or_execute
@@ -170,10 +158,10 b' def reset_search_buffer(event):'
170 if event.current_buffer.document.text:
158 if event.current_buffer.document.text:
171 event.current_buffer.reset()
159 event.current_buffer.reset()
172 else:
160 else:
173 event.cli.push_focus(DEFAULT_BUFFER)
161 event.app.layout.focus(DEFAULT_BUFFER)
174
162
175 def suspend_to_bg(event):
163 def suspend_to_bg(event):
176 event.cli.suspend_to_background()
164 event.app.suspend_to_background()
177
165
178 def force_exit(event):
166 def force_exit(event):
179 """
167 """
@@ -232,8 +220,8 b' def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:'
232
220
233
221
234 def open_input_in_editor(event):
222 def open_input_in_editor(event):
235 event.cli.current_buffer.tempfile_suffix = ".py"
223 event.app.current_buffer.tempfile_suffix = ".py"
236 event.cli.current_buffer.open_in_editor(event.cli)
224 event.app.current_buffer.open_in_editor()
237
225
238
226
239 if sys.platform == 'win32':
227 if sys.platform == 'win32':
@@ -190,7 +190,7 b' install_requires = ['
190 'pickleshare',
190 'pickleshare',
191 'simplegeneric>0.8',
191 'simplegeneric>0.8',
192 'traitlets>=4.2',
192 'traitlets>=4.2',
193 'prompt_toolkit>=1.0.15,<2.0.0',
193 'prompt_toolkit>=2.0.0,<2.1.0',
194 'pygments',
194 'pygments',
195 'backcall',
195 'backcall',
196 ]
196 ]
General Comments 0
You need to be logged in to leave comments. Login now