blob: fd2cc06bc28603454002e67a46da4434d24a2829 [file] [log] [blame]
Stephen Hinesc6ca60f2023-05-09 02:19:22 -07001import sys
2if sys.version_info[0] < 3:
3 import __builtin__ as builtins
4else:
5 import builtins
6import code
7import lldb
8import traceback
9
10try:
11 import readline
12 import rlcompleter
13except ImportError:
14 have_readline = False
15except AttributeError:
16 # This exception gets hit by the rlcompleter when Linux is using
17 # the readline suppression import.
18 have_readline = False
19else:
20 have_readline = True
21 if 'libedit' in readline.__doc__:
22 readline.parse_and_bind('bind ^I rl_complete')
23 else:
24 readline.parse_and_bind('tab: complete')
25
26# When running one line, we might place the string to run in this string
27# in case it would be hard to correctly escape a string's contents
28
29g_run_one_line_str = None
30
31
32def get_terminal_size(fd):
33 try:
34 import fcntl
35 import termios
36 import struct
37 hw = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
38 except:
39 hw = (0, 0)
40 return hw
41
42
43class LLDBExit(SystemExit):
44 pass
45
46
47def strip_and_check_exit(line):
48 line = line.rstrip()
49 if line in ('exit', 'quit'):
50 raise LLDBExit
51 return line
52
53
54def readfunc(prompt):
55 line = input(prompt)
56 return strip_and_check_exit(line)
57
58
59def readfunc_stdio(prompt):
60 sys.stdout.write(prompt)
61 sys.stdout.flush()
62 line = sys.stdin.readline()
63 # Readline always includes a trailing newline character unless the file
64 # ends with an incomplete line. An empty line indicates EOF.
65 if not line:
66 raise EOFError
67 return strip_and_check_exit(line)
68
69
70def run_python_interpreter(local_dict):
71 # Pass in the dictionary, for continuity from one session to the next.
72 try:
73 fd = sys.stdin.fileno()
74 interacted = False
75 if get_terminal_size(fd)[1] == 0:
76 try:
77 import termios
78 old = termios.tcgetattr(fd)
79 if old[3] & termios.ECHO:
80 # Need to turn off echoing and restore
81 new = termios.tcgetattr(fd)
82 new[3] = new[3] & ~termios.ECHO
83 try:
84 termios.tcsetattr(fd, termios.TCSADRAIN, new)
85 interacted = True
86 code.interact(
87 banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()'.",
88 readfunc=readfunc_stdio,
89 local=local_dict)
90 finally:
91 termios.tcsetattr(fd, termios.TCSADRAIN, old)
92 except:
93 pass
94 # Don't need to turn off echoing
95 if not interacted:
96 code.interact(
97 banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.",
98 readfunc=readfunc_stdio,
99 local=local_dict)
100 else:
101 # We have a real interactive terminal
102 code.interact(
103 banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.",
104 readfunc=readfunc,
105 local=local_dict)
106 except LLDBExit:
107 pass
108 except SystemExit as e:
109 if e.code:
110 print('Script exited with code %s' % e.code)
111
112
113def run_one_line(local_dict, input_string):
114 global g_run_one_line_str
115 try:
116 input_string = strip_and_check_exit(input_string)
117 repl = code.InteractiveConsole(local_dict)
118 if input_string:
119 # A newline is appended to support one-line statements containing
120 # control flow. For example "if True: print(1)" silently does
121 # nothing, but works with a newline: "if True: print(1)\n".
122 input_string += "\n"
123 repl.runsource(input_string)
124 elif g_run_one_line_str:
125 repl.runsource(g_run_one_line_str)
126 except LLDBExit:
127 pass
128 except SystemExit as e:
129 if e.code:
130 print('Script exited with code %s' % e.code)