##// END OF EJS Templates
Merge pull request #11177 from takluyver/prompt-toolkit-2...
Min RK -
r24390:42353287 merge
parent child Browse files
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)
@@ -15,15 +15,16 b' from traitlets import ('
15 Any,
15 Any,
16 )
16 )
17
17
18 from prompt_toolkit.document import Document
19 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
18 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
20 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
19 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
20 from prompt_toolkit.formatted_text import PygmentsTokens
21 from prompt_toolkit.history import InMemoryHistory
21 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.interface import CommandLineInterface
24 from prompt_toolkit.key_binding.manager import KeyBindingManager
25 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
22 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
26 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
23 from prompt_toolkit.output import ColorDepth
24 from prompt_toolkit.patch_stdout import patch_stdout
25 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
26 from prompt_toolkit.styles import DynamicStyle, merge_styles
27 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
27
28
28 from pygments.styles import get_style_by_name
29 from pygments.styles import get_style_by_name
29 from pygments.style import Style
30 from pygments.style import Style
@@ -34,7 +35,7 b' from .magics import TerminalMagics'
34 from .pt_inputhooks import get_inputhook_name_and_func
35 from .pt_inputhooks import get_inputhook_name_and_func
35 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
36 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
36 from .ptutils import IPythonPTCompleter, IPythonPTLexer
37 from .ptutils import IPythonPTCompleter, IPythonPTLexer
37 from .shortcuts import register_ipython_shortcuts
38 from .shortcuts import create_ipython_shortcuts
38
39
39 DISPLAY_BANNER_DEPRECATED = object()
40 DISPLAY_BANNER_DEPRECATED = object()
40
41
@@ -88,15 +89,11 b" _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)"
88
89
89 class TerminalInteractiveShell(InteractiveShell):
90 class TerminalInteractiveShell(InteractiveShell):
90 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
91 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
91 'to reserve for the completion menu'
92 'to reserve for the completion menu'
92 ).tag(config=True)
93 ).tag(config=True)
93
94
94 def _space_for_menu_changed(self, old, new):
95 pt_app = None
95 self._update_layout()
96
97 pt_cli = None
98 debugger_history = None
96 debugger_history = None
99 _pt_app = None
100
97
101 simple_prompt = Bool(_use_simple_prompt,
98 simple_prompt = Bool(_use_simple_prompt,
102 help="""Use `raw_input` for the REPL, without completion and prompt colors.
99 help="""Use `raw_input` for the REPL, without completion and prompt colors.
@@ -167,9 +164,9 b' class TerminalInteractiveShell(InteractiveShell):'
167 def _prompts_default(self):
164 def _prompts_default(self):
168 return self.prompts_class(self)
165 return self.prompts_class(self)
169
166
170 @observe('prompts')
167 # @observe('prompts')
171 def _(self, change):
168 # def _(self, change):
172 self._update_layout()
169 # self._update_layout()
173
170
174 @default('displayhook_class')
171 @default('displayhook_class')
175 def _displayhook_class_default(self):
172 def _displayhook_class_default(self):
@@ -243,10 +240,7 b' class TerminalInteractiveShell(InteractiveShell):'
243 return
240 return
244
241
245 # Set up keyboard shortcuts
242 # Set up keyboard shortcuts
246 kbmanager = KeyBindingManager.for_prompt(
243 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
244
251 # Pre-populate history from IPython's history database
245 # Pre-populate history from IPython's history database
252 history = InMemoryHistory()
246 history = InMemoryHistory()
@@ -256,7 +250,7 b' class TerminalInteractiveShell(InteractiveShell):'
256 # Ignore blank lines and consecutive duplicates
250 # Ignore blank lines and consecutive duplicates
257 cell = cell.rstrip()
251 cell = cell.rstrip()
258 if cell and (cell != last_cell):
252 if cell and (cell != last_cell):
259 history.append(cell)
253 history.append_string(cell)
260 last_cell = cell
254 last_cell = cell
261
255
262 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
256 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
@@ -264,24 +258,18 b' class TerminalInteractiveShell(InteractiveShell):'
264
258
265 editing_mode = getattr(EditingMode, self.editing_mode.upper())
259 editing_mode = getattr(EditingMode, self.editing_mode.upper())
266
260
267 def patch_stdout(**kwargs):
261 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,
262 editing_mode=editing_mode,
272 key_bindings_registry=kbmanager.registry,
263 key_bindings=key_bindings,
273 history=history,
264 history=history,
274 completer=IPythonPTCompleter(shell=self,
265 completer=IPythonPTCompleter(shell=self),
275 patch_stdout=patch_stdout),
266 enable_history_search = self.enable_history_search,
276 enable_history_search=self.enable_history_search,
277 style=self.style,
267 style=self.style,
268 include_default_pygments_style=False,
278 mouse_support=self.mouse_support,
269 mouse_support=self.mouse_support,
279 **self._layout_options()
270 enable_open_in_editor=self.extra_open_editor_shortcuts,
280 )
271 color_depth=(ColorDepth.TRUE_COLOR if self.true_color else None),
281 self._eventloop = create_eventloop(self.inputhook)
272 **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
273
286 def _make_style_from_name_or_cls(self, name_or_cls):
274 def _make_style_from_name_or_cls(self, name_or_cls):
287 """
275 """
@@ -342,44 +330,60 b' class TerminalInteractiveShell(InteractiveShell):'
342 Token.OutPromptNum: '#ff0000 bold',
330 Token.OutPromptNum: '#ff0000 bold',
343 }
331 }
344 style_overrides.update(self.highlighting_style_overrides)
332 style_overrides.update(self.highlighting_style_overrides)
345 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
333 style = merge_styles([
346 style_dict=style_overrides)
334 style_from_pygments_cls(style_cls),
335 style_from_pygments_dict(style_overrides),
336 ])
347
337
348 return style
338 return style
349
339
350 def _layout_options(self):
340 @property
341 def pt_complete_style(self):
342 return {
343 'multicolumn': CompleteStyle.MULTI_COLUMN,
344 'column': CompleteStyle.COLUMN,
345 'readlinelike': CompleteStyle.READLINE_LIKE,
346 }[self.display_completions],
347
348 def _extra_prompt_options(self):
351 """
349 """
352 Return the current layout option for the current Terminal InteractiveShell
350 Return the current layout option for the current Terminal InteractiveShell
353 """
351 """
352 def get_message():
353 return PygmentsTokens(self.prompts.in_prompt_tokens())
354
354 return {
355 return {
356 'complete_in_thread': False,
355 'lexer':IPythonPTLexer(),
357 'lexer':IPythonPTLexer(),
356 'reserve_space_for_menu':self.space_for_menu,
358 'reserve_space_for_menu':self.space_for_menu,
357 'get_prompt_tokens':self.prompts.in_prompt_tokens,
359 'message': get_message,
358 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
360 'prompt_continuation': (
359 'multiline':True,
361 lambda width, lineno, is_soft_wrap:
360 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
362 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
363 'multiline': True,
364 'complete_style': self.pt_complete_style,
361
365
362 # Highlight matching brackets, but only when this setting is
366 # Highlight matching brackets, but only when this setting is
363 # enabled, and only when the DEFAULT_BUFFER has the focus.
367 # enabled, and only when the DEFAULT_BUFFER has the focus.
364 'extra_input_processors': [ConditionalProcessor(
368 'input_processors': [ConditionalProcessor(
365 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
369 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
366 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
370 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
367 Condition(lambda cli: self.highlight_matching_brackets))],
371 Condition(lambda: self.highlight_matching_brackets))],
368 }
372 }
369
373
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):
374 def prompt_for_code(self):
379 with self.pt_cli.patch_stdout_context(raw=True):
375 if self.rl_next_input:
380 document = self.pt_cli.run(
376 default = self.rl_next_input
381 pre_run=self.pre_prompt, reset_current_buffer=True)
377 self.rl_next_input = None
382 return document.text
378 else:
379 default = ''
380
381 with patch_stdout(raw=True):
382 text = self.pt_app.prompt(
383 default=default,
384 # pre_run=self.pre_prompt,# reset_current_buffer=True,
385 **self._extra_prompt_options())
386 return text
383
387
384 def enable_win_unicode_console(self):
388 def enable_win_unicode_console(self):
385 if sys.version_info >= (3, 6):
389 if sys.version_info >= (3, 6):
@@ -439,22 +443,6 b' class TerminalInteractiveShell(InteractiveShell):'
439
443
440 rl_next_input = None
444 rl_next_input = None
441
445
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):
446 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
459
447
460 if display_banner is not DISPLAY_BANNER_DEPRECATED:
448 if display_banner is not DISPLAY_BANNER_DEPRECATED:
@@ -517,8 +505,9 b' class TerminalInteractiveShell(InteractiveShell):'
517 return
505 return
518
506
519 tokens = self.prompts.rewrite_prompt_tokens()
507 tokens = self.prompts.rewrite_prompt_tokens()
520 if self.pt_cli:
508 if self.pt_app:
521 self.pt_cli.print_tokens(tokens)
509 print_formatted_text(PygmentsTokens(tokens), end='',
510 style=self.pt_app.app.style)
522 print(cmd)
511 print(cmd)
523 else:
512 else:
524 prompt = ''.join(s for t, s in tokens)
513 prompt = ''.join(s for t, s in tokens)
@@ -533,7 +522,7 b' class TerminalInteractiveShell(InteractiveShell):'
533 elif self._prompts_before:
522 elif self._prompts_before:
534 self.prompts = self._prompts_before
523 self.prompts = self._prompts_before
535 self._prompts_before = None
524 self._prompts_before = None
536 self._update_layout()
525 # self._update_layout()
537
526
538
527
539 InteractiveShellABC.register(TerminalInteractiveShell)
528 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,9 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(PygmentsTokens(tokens),
80 style=self.shell.pt_app.app.style, end='',
81 )
78 else:
82 else:
79 sys.stdout.write(prompt_txt)
83 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':
@@ -1,7 +1,6 b''
1 from os.path import abspath, dirname, join
1 from os.path import abspath, dirname, join
2
2
3 from IPython.terminal.interactiveshell import KeyBindingManager
3 from IPython.terminal.shortcuts import create_ipython_shortcuts
4
5
4
6 def name(c):
5 def name(c):
7 s = c.__class__.__name__
6 s = c.__class__.__name__
@@ -42,8 +41,14 b' def multi_filter_str(flt):'
42 log_filters = {'_AndList': 'And', '_OrList': 'Or'}
41 log_filters = {'_AndList': 'And', '_OrList': 'Or'}
43 log_invert = {'_Invert'}
42 log_invert = {'_Invert'}
44
43
45 kbm = KeyBindingManager.for_prompt()
44 class _DummyTerminal(object):
46 ipy_bindings = kbm.registry.key_bindings
45 """Used as a buffer to get prompt_toolkit bindings
46 """
47 handle_return = None
48 input_splitter = None
49 display_completions = None
50
51 ipy_bindings = create_ipython_shortcuts(_DummyTerminal()).bindings
47
52
48 dummy_docs = [] # ignore bindings without proper documentation
53 dummy_docs = [] # ignore bindings without proper documentation
49
54
@@ -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