Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ function showerror(io::IO, ex::MethodError)
f_is_function = true
end
print(io, "no method matching ")
iob = IOContext(IOBuffer(), io) # for type abbreviation as in #49795; some, like `convert(T, x)`, should not abbreviate
buf = IOBuffer()
iob = IOContext(buf, io) # for type abbreviation as in #49795; some, like `convert(T, x)`, should not abbreviate
show_signature_function(iob, isa(f, Type) ? Type{f} : typeof(f))
print(iob, "(")
for (i, typ) in enumerate(arg_types_param)
Expand All @@ -293,7 +294,7 @@ function showerror(io::IO, ex::MethodError)
end
end
print(iob, ")")
str = String(take!(unwrapcontext(iob)[1]))
str = String(take!(buf))
str = type_limited_string_from_context(io, str)
print(io, str)
end
Expand Down
9 changes: 8 additions & 1 deletion base/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,14 @@ end
"""
AbstractPipe

`AbstractPipe` is the abstract supertype for IO pipes that provide for communication between processes.
`AbstractPipe` is an abstract supertype that exists for the convenience of creating
pass-through wrappers for other IO objects, so that you only need to implement the
additional methods relevant to your type. A subtype only needs to implement one or both of
these methods:

struct P <: AbstractPipe; ...; end
pipe_reader(io::P) = io.out
pipe_writer(io::P) = io.in

If `pipe isa AbstractPipe`, it must obey the following interface:

Expand Down
35 changes: 22 additions & 13 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -294,35 +294,43 @@ struct IOContext{IO_t <: IO} <: AbstractPipe
dict::ImmutableDict{Symbol, Any}

function IOContext{IO_t}(io::IO_t, dict::ImmutableDict{Symbol, Any}) where IO_t<:IO
@assert !(IO_t <: IOContext) "Cannot create `IOContext` from another `IOContext`."
io isa IOContext && (io = io.io) # implicitly unwrap, since the io.dict field is not useful anymore, and could confuse pipe_reader consumers
return new(io, dict)
end
end

# (Note that TTY and TTYTerminal io types have a :color property.)
unwrapcontext(io::IO) = io, get(io,:color,false) ? ImmutableDict{Symbol,Any}(:color, true) : ImmutableDict{Symbol,Any}()
unwrapcontext(io::IOContext) = io.io, io.dict
# (Note that TTY and TTYTerminal io types have an implied :color property.)
ioproperties(io::IO) = get(io, :color, false) ? ImmutableDict{Symbol,Any}(:color, true) : ImmutableDict{Symbol,Any}()
ioproperties(io::IOContext) = io.dict
# these can probably be deprecated, but there is a use in the ecosystem for them
unwrapcontext(io::IO) = (io,)
unwrapcontext(io::IOContext) = (io.io,)

function IOContext(io::IO, dict::ImmutableDict)
io0 = unwrapcontext(io)[1]
IOContext{typeof(io0)}(io0, dict)
function IOContext(io::IO, dict::ImmutableDict{Symbol, Any})
return IOContext{typeof(io)}(io, dict)
end

convert(::Type{IOContext}, io::IO) = IOContext(unwrapcontext(io)...)::IOContext
function IOContext(io::IOContext, dict::ImmutableDict{Symbol, Any})
return typeof(io)(io.io, dict)
end


convert(::Type{IOContext}, io::IOContext) = io
convert(::Type{IOContext}, io::IO) = IOContext(io, ioproperties(io))::IOContext

IOContext(io::IO) = convert(IOContext, io)

function IOContext(io::IO, KV::Pair)
io0, d = unwrapcontext(io)
IOContext(io0, ImmutableDict{Symbol,Any}(d, KV[1], KV[2]))
d = ioproperties(io)
return IOContext(io, ImmutableDict{Symbol,Any}(d, KV[1], KV[2]))
end

"""
IOContext(io::IO, context::IOContext)

Create an `IOContext` that wraps an alternate `IO` but inherits the properties of `context`.
"""
IOContext(io::IO, context::IO) = IOContext(unwrapcontext(io)[1], unwrapcontext(context)[2])
IOContext(io::IO, context::IO) = IOContext(io, ioproperties(context))

"""
IOContext(io::IO, KV::Pair...)
Expand Down Expand Up @@ -2548,7 +2556,8 @@ function show_tuple_as_call(out::IO, name::Symbol, sig::Type;
return
end
tv = Any[]
io = IOContext(IOBuffer(), out)
buf = IOBuffer()
io = IOContext(buf, out)
env_io = io
while isa(sig, UnionAll)
push!(tv, sig.var)
Expand Down Expand Up @@ -2591,7 +2600,7 @@ function show_tuple_as_call(out::IO, name::Symbol, sig::Type;
end
print_within_stacktrace(io, ")", bold=true)
show_method_params(io, tv)
str = String(take!(unwrapcontext(io)[1]))
str = String(take!(buf))
str = type_limited_string_from_context(out, str)
print(out, str)
nothing
Expand Down
19 changes: 14 additions & 5 deletions base/stream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -743,19 +743,28 @@ mutable struct Pipe <: AbstractPipe
end

"""
Construct an uninitialized Pipe object.
Pipe()

The appropriate end of the pipe will be automatically initialized if
the object is used in process spawning. This can be useful to easily
obtain references in process pipelines, e.g.:
Construct an uninitialized Pipe object, especially for IO communication between multiple processes.

The appropriate end of the pipe will be automatically initialized if the object is used in
process spawning. This can be useful to easily obtain references in process pipelines, e.g.:

```
julia> err = Pipe()

# After this `err` will be initialized and you may read `foo`'s
# stderr from the `err` pipe.
# stderr from the `err` pipe, or pass `err` to other pipelines.
julia> run(pipeline(pipeline(`foo`, stderr=err), `cat`), wait=false)

# Now destroy the write half of the pipe, so that the read half will get EOF
julia> closewrite(err)

julia> read(err, String)
"stderr messages"
```

See also `Base.link_pipe!`.
"""
Pipe() = Pipe(PipeEndpoint(), PipeEndpoint())
pipe_reader(p::Pipe) = p.out
Expand Down