15
15
from trio ._util import final
16
16
17
17
18
+ class SuppressDecorator (contextlib .ContextDecorator , contextlib .suppress ):
19
+ pass
20
+
21
+
18
22
@final
19
23
class TrioInteractiveConsole (InteractiveConsole ):
20
24
# code.InteractiveInterpreter defines locals as Mapping[str, Any]
@@ -24,6 +28,7 @@ class TrioInteractiveConsole(InteractiveConsole):
24
28
25
29
def __init__ (self , repl_locals : dict [str , object ] | None = None ) -> None :
26
30
super ().__init__ (locals = repl_locals )
31
+ self .token : trio .lowlevel .TrioToken | None = None
27
32
self .compile .compiler .flags |= ast .PyCF_ALLOW_TOP_LEVEL_AWAIT
28
33
29
34
def runcode (self , code : types .CodeType ) -> None :
@@ -70,17 +75,27 @@ def raw_input(self, prompt: str = "") -> str:
70
75
else :
71
76
72
77
def raw_input (self , prompt : str = "" ) -> str :
73
- import fcntl
74
- import termios
75
78
from signal import SIGINT , signal
76
79
77
80
interrupted = False
81
+
82
+ if self .token is None :
83
+ self .token = trio .from_thread .run_sync (trio .lowlevel .current_trio_token )
84
+
85
+ @SuppressDecorator (KeyboardInterrupt )
86
+ @trio .lowlevel .disable_ki_protection
87
+ def newline ():
88
+ import fcntl
89
+ import termios
90
+
91
+ # Fake up a newline char as if user had typed it at
92
+ # os.write(sys.stdin.buffer.fileno(), b"\n")
93
+ fcntl .ioctl (sys .stdin , termios .TIOCSTI , b"\n " )
78
94
79
95
def handler (sig : int , frame : types .FrameType | None ) -> None :
80
96
nonlocal interrupted
81
97
interrupted = True
82
- # Fake up a newline char as if user had typed it at terminal
83
- fcntl .ioctl (sys .stdin , termios .TIOCSTI , b"\n " )
98
+ self .token .run_sync_soon (newline , idempotent = True )
84
99
85
100
prev_handler = trio .from_thread .run_sync (signal , SIGINT , handler )
86
101
try :
0 commit comments