forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathpythonrc.py
More file actions
137 lines (113 loc) · 5.29 KB
/
Copy pathpythonrc.py
File metadata and controls
137 lines (113 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def _initialize():
import platform
import sys
if sys.platform != "win32":
import readline
# Override regex to support OSC codes
if sys.version_info >= (3, 13):
import re
import _pyrepl.utils
_pyrepl.utils.ANSI_ESCAPE_SEQUENCE = re.compile(
r"\x1b(?:\[[ -@]*[A-~]|\][^\x1b\x07]*(?:\x07|\x1b\\))"
)
original_ps1 = ">>> "
# PYTHONSTARTUP executes this file's code inside the user's __main__
# namespace, so PS1.__str__'s globals are the user's globals. If the
# user later shadows a name we rely on at prompt-render time (e.g.
# `int = 20`, `sys = 1`), a plain lookup would resolve to the user's
# value instead of ours and raise, silently killing the prompt.
#
# Capturing these as locals of _initialize (rather than as names left
# sitting in __main__) means PS1's methods reach them through closure
# cells, not global lookup - so there's no alias name in __main__ for
# user code to reassign and break in the first place.
_int = int
_bool = bool
_str = str
# https://code.visualstudio.com/docs/terminal/shell-integration#_supported-escape-sequences
class ShellIntegrationSequence:
soh = "\001"
stx = "\002"
template = "\x1b]633;{}\x07"
# Before the prompt (>>>) is displayed
@classmethod
def prompt_start(cls) -> str:
return cls.template.format("A")
# After the prompt (>>>) is displayed
@classmethod
def prompt_end(cls) -> str:
return cls.template.format("B")
# After the user has typed a command but before it is executed
@classmethod
def pre_execution(cls) -> str:
return cls.template.format("C")
@classmethod
def execution_finished(cls, exit_code: int) -> str:
"""Mark execution as finished with its exit code."""
return cls.template.format(f"D;{exit_code}")
@classmethod
def command_line(cls, command: object) -> str:
"""Explicitly set the command line interpreted by the shell."""
return cls.template.format(f"E;{command}")
class REPLHooks:
def __init__(self):
self.global_exit = None
self.last_failure_flag = False
self.original_excepthook = sys.excepthook
self.original_displayhook = sys.displayhook
sys.excepthook = self.vscode_excepthook
sys.displayhook = self.vscode_displayhook
def vscode_displayhook(self, value):
if value is None:
self.last_failure_flag = False
self.original_displayhook(value)
def vscode_excepthook(self, type_, value, traceback):
self.global_exit = value
self.last_failure_flag = True
self.original_excepthook(type_, value, traceback)
def get_last_command():
# Get the last history item
last_command = ""
if sys.platform != "win32":
last_command = readline.get_history_item(readline.get_current_history_length())
return last_command
class PS1:
hooks = REPLHooks()
# str will get called for every prompt with exit code to show success/failure
def __str__(self):
last_exit_code = _int(_bool(self.hooks.last_failure_flag))
self.hooks.last_failure_flag = False
# Guide following official VS Code doc for shell integration sequence:
result = ""
# For non-windows allow recent_command history.
# fmt: off
if sys.platform != "win32":
result = "{soh}{pre_execution}{command_line}{execution_finished}{prompt_start}{stx}{prompt}{soh}{prompt_end}{stx}".format( # noqa: UP032
soh=ShellIntegrationSequence.soh,
pre_execution=ShellIntegrationSequence.pre_execution(),
command_line=ShellIntegrationSequence.command_line(get_last_command()),
execution_finished=ShellIntegrationSequence.execution_finished(last_exit_code),
prompt_start=ShellIntegrationSequence.prompt_start(),
stx=ShellIntegrationSequence.stx,
prompt=original_ps1,
prompt_end=ShellIntegrationSequence.prompt_end(),
)
else:
result = "{execution_finished}{prompt_start}{prompt}{prompt_end}{pre_execution}".format( # noqa: UP032
execution_finished=ShellIntegrationSequence.execution_finished(last_exit_code),
prompt_start=ShellIntegrationSequence.prompt_start(),
prompt=original_ps1,
prompt_end=ShellIntegrationSequence.prompt_end(),
pre_execution=ShellIntegrationSequence.pre_execution(),
)
# fmt: on
return result
def __repr__(self):
return "<Custom PS1 for VS Code Python Shell Integration>"
is_wsl = "microsoft-standard-WSL" in platform.release()
if not is_wsl and (sys.platform != "win32" or sys.version_info >= (3, 13)):
sys.ps1 = PS1()
ctrl_key = "Cmd" if sys.platform == "darwin" else "Ctrl"
print(f"{ctrl_key} click to launch VS Code Native REPL (https://aka.ms/python-native-repl)")
_initialize()
del _initialize