##// END OF EJS Templates
Use default shortcuts with terminal debugger...
Daniel Hahler -
Show More
@@ -1,147 +1,136 b''
1 1 import asyncio
2 2 import signal
3 3 import sys
4 4
5 5 from IPython.core.debugger import Pdb
6 6
7 7 from IPython.core.completer import IPCompleter
8 8 from .ptutils import IPythonPTCompleter
9 from .shortcuts import suspend_to_bg, cursor_in_leading_ws
9 from .shortcuts import create_ipython_shortcuts, suspend_to_bg, cursor_in_leading_ws
10 10
11 11 from prompt_toolkit.enums import DEFAULT_BUFFER
12 12 from prompt_toolkit.filters import (Condition, has_focus, has_selection,
13 13 vi_insert_mode, emacs_insert_mode)
14 14 from prompt_toolkit.key_binding import KeyBindings
15 15 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
16 16 from pygments.token import Token
17 17 from prompt_toolkit.shortcuts.prompt import PromptSession
18 18 from prompt_toolkit.enums import EditingMode
19 19 from prompt_toolkit.formatted_text import PygmentsTokens
20 20
21 21 from prompt_toolkit import __version__ as ptk_version
22 22 PTK3 = ptk_version.startswith('3.')
23 23
24 24
25 25 class TerminalPdb(Pdb):
26 26 """Standalone IPython debugger."""
27 27
28 28 def __init__(self, *args, **kwargs):
29 29 Pdb.__init__(self, *args, **kwargs)
30 30 self._ptcomp = None
31 31 self.pt_init()
32 32
33 33 def pt_init(self):
34 34 def get_prompt_tokens():
35 35 return [(Token.Prompt, self.prompt)]
36 36
37 37 if self._ptcomp is None:
38 38 compl = IPCompleter(shell=self.shell,
39 39 namespace={},
40 40 global_namespace={},
41 41 parent=self.shell,
42 42 )
43 43 self._ptcomp = IPythonPTCompleter(compl)
44 44
45 kb = KeyBindings()
46 supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
47 kb.add('c-z', filter=supports_suspend)(suspend_to_bg)
48
49 if self.shell.display_completions == 'readlinelike':
50 kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
51 & ~has_selection
52 & vi_insert_mode | emacs_insert_mode
53 & ~cursor_in_leading_ws
54 ))(display_completions_like_readline)
55
56 45 options = dict(
57 46 message=(lambda: PygmentsTokens(get_prompt_tokens())),
58 47 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
59 key_bindings=kb,
48 key_bindings=create_ipython_shortcuts(self.shell),
60 49 history=self.shell.debugger_history,
61 50 completer=self._ptcomp,
62 51 enable_history_search=True,
63 52 mouse_support=self.shell.mouse_support,
64 53 complete_style=self.shell.pt_complete_style,
65 54 style=self.shell.style,
66 55 color_depth=self.shell.color_depth,
67 56 )
68 57
69 58 if not PTK3:
70 59 options['inputhook'] = self.shell.inputhook
71 60 self.pt_loop = asyncio.new_event_loop()
72 61 self.pt_app = PromptSession(**options)
73 62
74 63 def cmdloop(self, intro=None):
75 64 """Repeatedly issue a prompt, accept input, parse an initial prefix
76 65 off the received input, and dispatch to action methods, passing them
77 66 the remainder of the line as argument.
78 67
79 68 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
80 69 """
81 70 if not self.use_rawinput:
82 71 raise ValueError('Sorry ipdb does not support use_rawinput=False')
83 72
84 73 # In order to make sure that asyncio code written in the
85 74 # interactive shell doesn't interfere with the prompt, we run the
86 75 # prompt in a different event loop.
87 76 # If we don't do this, people could spawn coroutine with a
88 77 # while/true inside which will freeze the prompt.
89 78
90 79 try:
91 80 old_loop = asyncio.get_event_loop()
92 81 except RuntimeError:
93 82 # This happens when the user used `asyncio.run()`.
94 83 old_loop = None
95 84
96 85
97 86 self.preloop()
98 87
99 88 try:
100 89 if intro is not None:
101 90 self.intro = intro
102 91 if self.intro:
103 92 self.stdout.write(str(self.intro)+"\n")
104 93 stop = None
105 94 while not stop:
106 95 if self.cmdqueue:
107 96 line = self.cmdqueue.pop(0)
108 97 else:
109 98 self._ptcomp.ipy_completer.namespace = self.curframe_locals
110 99 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
111 100
112 101 asyncio.set_event_loop(self.pt_loop)
113 102 try:
114 103 line = self.pt_app.prompt()
115 104 except EOFError:
116 105 line = 'EOF'
117 106 finally:
118 107 # Restore the original event loop.
119 108 asyncio.set_event_loop(old_loop)
120 109
121 110 line = self.precmd(line)
122 111 stop = self.onecmd(line)
123 112 stop = self.postcmd(stop, line)
124 113 self.postloop()
125 114 except Exception:
126 115 raise
127 116
128 117
129 118 def set_trace(frame=None):
130 119 """
131 120 Start debugging from `frame`.
132 121
133 122 If frame is not specified, debugging starts from caller's frame.
134 123 """
135 124 TerminalPdb().set_trace(frame or sys._getframe().f_back)
136 125
137 126
138 127 if __name__ == '__main__':
139 128 import pdb
140 129 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
141 130 # bdb.BdbQuit. When started through __main__ and an exception
142 131 # happened after hitting "c", this is needed in order to
143 132 # be able to quit the debugging session (see #9950).
144 133 old_trace_dispatch = pdb.Pdb.trace_dispatch
145 134 pdb.Pdb = TerminalPdb
146 135 pdb.Pdb.trace_dispatch = old_trace_dispatch
147 136 pdb.main()
General Comments 0
You need to be logged in to leave comments. Login now