-
-
Notifications
You must be signed in to change notification settings - Fork 414
/
stdio.jl
98 lines (92 loc) · 2.94 KB
/
stdio.jl
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
# During handling of an execute_request (when execute_msg is !nothing),
# we redirect STDOUT and STDERR into "stream" messages sent to the IPython
# front-end.
# logging in verbose mode goes to original stdio streams. Use macros
# so that we do not even evaluate the arguments in no-verbose modes
macro vprintln(x...)
quote
if verbose::Bool
println(orig_STDOUT, $(x...))
end
end
end
macro verror_show(e, bt)
quote
if verbose::Bool
showerror(orig_STDERR, $e, $bt)
end
end
end
function send_stream(rd::IO, name::AbstractString)
nb = nb_available(rd)
if nb > 0
d = readbytes(rd, nb)
s = try
bytestring(d)
catch
# FIXME: what should we do here?
string("<ERROR: invalid UTF8 data ", d, ">")
end
send_ipython(publish,
msg_pub(execute_msg, "stream",
@compat Dict("name" => name, "text" => s)))
end
end
function watch_stream(rd::IO, name::AbstractString)
try
while !eof(rd) # blocks until something is available
send_stream(rd, name)
sleep(0.1) # a little delay to accumulate output
end
catch e
# the IPython manager may send us a SIGINT if the user
# chooses to interrupt the kernel; don't crash on this
if isa(e, InterruptException)
watch_stream(rd, name)
else
rethrow()
end
end
end
# IJulia issue #42: there doesn't seem to be a good way to make a task
# that blocks until there is a read request from STDIN ... this makes
# it very hard to properly redirect all reads from STDIN to pyin messages.
# In the meantime, however, we can just hack it so that readline works:
import Base.readline
function readline(io::Base.Pipe)
if io == STDIN
if !execute_msg.content["allow_stdin"]
error("IJulia: this front-end does not implement stdin")
end
send_ipython(raw_input,
msg_reply(execute_msg, "input_request",
@compat Dict("prompt"=>"STDIN> ", "password"=>false)))
while true
msg = recv_ipython(raw_input)
if msg.header["msg_type"] == "input_reply"
return msg.content["value"]
else
error("IJulia error: unknown stdin reply")
end
end
else
invoke(readline, (Base.AsyncStream,), io)
end
end
function watch_stdio()
@async watch_stream(read_stdout, "stdout")
if capture_stderr
@async watch_stream(read_stderr, "stderr")
end
end
import Base.flush
function flush(io::Base.Pipe)
invoke(flush, (super(Base.Pipe),), io)
# send any available bytes to IPython (don't use readavailable,
# since we don't want to block).
if io == STDOUT
send_stream(read_stdout, "stdout")
elseif io == STDERR
send_stream(read_stderr, "stderr")
end
end