##// END OF EJS Templates
Backport PR #10261: Add Ctrl-Z shortcut (suspend) in terminal debugger...
Matthias Bussonnier -
Show More
@@ -0,0 +1,2 b''
1 Pressing Ctrl-Z in the terminal debugger now suspends IPython, as it already
2 does in the main terminal prompt.
@@ -1,88 +1,100 b''
1 import signal
2 import sys
3
1 from IPython.core.debugger import Pdb
4 from IPython.core.debugger import Pdb
2
5
3 from IPython.core.completer import IPCompleter
6 from IPython.core.completer import IPCompleter
4 from .ptutils import IPythonPTCompleter
7 from .ptutils import IPythonPTCompleter
8 from .shortcuts import suspend_to_bg
5
9
10 from prompt_toolkit.filters import Condition
11 from prompt_toolkit.keys import Keys
12 from prompt_toolkit.key_binding.manager import KeyBindingManager
6 from prompt_toolkit.token import Token
13 from prompt_toolkit.token import Token
7 from prompt_toolkit.shortcuts import create_prompt_application
14 from prompt_toolkit.shortcuts import create_prompt_application
8 from prompt_toolkit.interface import CommandLineInterface
15 from prompt_toolkit.interface import CommandLineInterface
9 from prompt_toolkit.enums import EditingMode
16 from prompt_toolkit.enums import EditingMode
10 import sys
11
17
12
18
13 class TerminalPdb(Pdb):
19 class TerminalPdb(Pdb):
14 def __init__(self, *args, **kwargs):
20 def __init__(self, *args, **kwargs):
15 Pdb.__init__(self, *args, **kwargs)
21 Pdb.__init__(self, *args, **kwargs)
16 self._ptcomp = None
22 self._ptcomp = None
17 self.pt_init()
23 self.pt_init()
18
24
19 def pt_init(self):
25 def pt_init(self):
20 def get_prompt_tokens(cli):
26 def get_prompt_tokens(cli):
21 return [(Token.Prompt, self.prompt)]
27 return [(Token.Prompt, self.prompt)]
22
28
23 def patch_stdout(**kwargs):
29 def patch_stdout(**kwargs):
24 return self.pt_cli.patch_stdout_context(**kwargs)
30 return self.pt_cli.patch_stdout_context(**kwargs)
25
31
26 if self._ptcomp is None:
32 if self._ptcomp is None:
27 compl = IPCompleter(shell=self.shell,
33 compl = IPCompleter(shell=self.shell,
28 namespace={},
34 namespace={},
29 global_namespace={},
35 global_namespace={},
30 use_readline=False,
36 use_readline=False,
31 parent=self.shell,
37 parent=self.shell,
32 )
38 )
33 self._ptcomp = IPythonPTCompleter(compl, patch_stdout=patch_stdout)
39 self._ptcomp = IPythonPTCompleter(compl, patch_stdout=patch_stdout)
34
40
41 kbmanager = KeyBindingManager.for_prompt()
42 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
43 kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend
44 )(suspend_to_bg)
45
35 self._pt_app = create_prompt_application(
46 self._pt_app = create_prompt_application(
36 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
47 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
48 key_bindings_registry=kbmanager.registry,
37 history=self.shell.debugger_history,
49 history=self.shell.debugger_history,
38 completer= self._ptcomp,
50 completer= self._ptcomp,
39 enable_history_search=True,
51 enable_history_search=True,
40 mouse_support=self.shell.mouse_support,
52 mouse_support=self.shell.mouse_support,
41 get_prompt_tokens=get_prompt_tokens
53 get_prompt_tokens=get_prompt_tokens
42 )
54 )
43 self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
55 self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
44
56
45 def cmdloop(self, intro=None):
57 def cmdloop(self, intro=None):
46 """Repeatedly issue a prompt, accept input, parse an initial prefix
58 """Repeatedly issue a prompt, accept input, parse an initial prefix
47 off the received input, and dispatch to action methods, passing them
59 off the received input, and dispatch to action methods, passing them
48 the remainder of the line as argument.
60 the remainder of the line as argument.
49
61
50 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
62 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
51 """
63 """
52 if not self.use_rawinput:
64 if not self.use_rawinput:
53 raise ValueError('Sorry ipdb does not support use_rawinput=False')
65 raise ValueError('Sorry ipdb does not support use_rawinput=False')
54
66
55 self.preloop()
67 self.preloop()
56
68
57 try:
69 try:
58 if intro is not None:
70 if intro is not None:
59 self.intro = intro
71 self.intro = intro
60 if self.intro:
72 if self.intro:
61 self.stdout.write(str(self.intro)+"\n")
73 self.stdout.write(str(self.intro)+"\n")
62 stop = None
74 stop = None
63 while not stop:
75 while not stop:
64 if self.cmdqueue:
76 if self.cmdqueue:
65 line = self.cmdqueue.pop(0)
77 line = self.cmdqueue.pop(0)
66 else:
78 else:
67 self._ptcomp.ipy_completer.namespace = self.curframe_locals
79 self._ptcomp.ipy_completer.namespace = self.curframe_locals
68 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
80 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
69 try:
81 try:
70 line = self.pt_cli.run(reset_current_buffer=True).text
82 line = self.pt_cli.run(reset_current_buffer=True).text
71 except EOFError:
83 except EOFError:
72 line = 'EOF'
84 line = 'EOF'
73 line = self.precmd(line)
85 line = self.precmd(line)
74 stop = self.onecmd(line)
86 stop = self.onecmd(line)
75 stop = self.postcmd(stop, line)
87 stop = self.postcmd(stop, line)
76 self.postloop()
88 self.postloop()
77 except Exception:
89 except Exception:
78 raise
90 raise
79
91
80
92
81 def set_trace(frame=None):
93 def set_trace(frame=None):
82 """
94 """
83 Start debugging from `frame`.
95 Start debugging from `frame`.
84
96
85 If frame is not specified, debugging starts from caller's frame.
97 If frame is not specified, debugging starts from caller's frame.
86 """
98 """
87 TerminalPdb().set_trace(frame or sys._getframe().f_back)
99 TerminalPdb().set_trace(frame or sys._getframe().f_back)
88
100
General Comments 0
You need to be logged in to leave comments. Login now