Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce IOContext and ImmutableDict to fix some of show, print, & friends #13825

Merged
merged 6 commits into from
Dec 31, 2015
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
reimplement show context global/tls variables as local state containe…
…d in a new IOContext lightweight wrapper type
vtjnash committed Dec 24, 2015

Verified

This commit was signed with the committer’s verified signature.
targos Michaël Zasso
commit 4706184a424eda72aa802f465c7f45c5545143e0
7 changes: 5 additions & 2 deletions base/Enums.jl
Original file line number Diff line number Diff line change
@@ -93,9 +93,12 @@ macro enum(T,syms...)
end
end
function Base.show(io::IO,x::$(esc(typename)))
print(io, x, "::", $(esc(typename)), " = ", Int(x))
if Base.limit_output(io)
print(io, x)
else
print(io, x, "::", $(esc(typename)), " = ", Int(x))
end
end
Base.showcompact(io::IO,x::$(esc(typename))) = print(io, x)
function Base.writemime(io::IO,::MIME"text/plain",::Type{$(esc(typename))})
print(io, "Enum ", $(esc(typename)), ":")
for (sym, i) in $vals
11 changes: 5 additions & 6 deletions base/complex.jl
Original file line number Diff line number Diff line change
@@ -59,25 +59,24 @@ complex(x::Real, y::Real) = Complex(x, y)
complex(x::Real) = Complex(x)
complex(z::Complex) = z

function complex_show(io::IO, z::Complex, compact::Bool)
function show(io::IO, z::Complex)
r, i = reim(z)
compact ? showcompact(io,r) : show(io,r)
compact = limit_output(io)
showcompact_lim(io, r)
if signbit(i) && !isnan(i)
i = -i
print(io, compact ? "-" : " - ")
else
print(io, compact ? "+" : " + ")
end
compact ? showcompact(io, i) : show(io, i)
showcompact_lim(io, i)
if !(isa(i,Integer) && !isa(i,Bool) || isa(i,AbstractFloat) && isfinite(i))
print(io, "*")
end
print(io, "im")
end
complex_show(io::IO, z::Complex{Bool}, compact::Bool) =
show(io::IO, z::Complex{Bool}) =
print(io, z == im ? "im" : "Complex($(z.re),$(z.im))")
show(io::IO, z::Complex) = complex_show(io, z, false)
showcompact(io::IO, z::Complex) = complex_show(io, z, true)

function read{T<:Real}(s::IO, ::Type{Complex{T}})
r = read(s,T)
139 changes: 66 additions & 73 deletions base/dict.jl
Original file line number Diff line number Diff line change
@@ -61,87 +61,79 @@ function _truncate_at_width_or_chars(str, width, chars="", truncmark="…")
end

showdict(t::Associative; kw...) = showdict(STDOUT, t; kw...)
function showdict{K,V}(io::IO, t::Associative{K,V}; limit::Bool = false, compact = false,
function showdict{K,V}(io::IO, t::Associative{K,V}; compact = false,
sz=(s = tty_size(); (s[1]-3, s[2])))
shown_set = get(task_local_storage(), :SHOWNSET, nothing)
if shown_set === nothing
shown_set = ObjectIdDict()
task_local_storage(:SHOWNSET, shown_set)
end
t in keys(shown_set) && (print(io, "#= circular reference =#"); return)

try
shown_set[t] = true
if compact
# show in a Julia-syntax-like form: Dict(k=>v, ...)
if isempty(t)
print(io, typeof(t), "()")
(:SHOWN_SET => t) in io && (print(io, "#= circular reference =#"); return)

recur_io = IOContext(io, :SHOWN_SET => t)
limit::Bool = limit_output(io)
if compact
# show in a Julia-syntax-like form: Dict(k=>v, ...)
if isempty(t)
print(io, typeof(t), "()")
else
if isleaftype(K) && isleaftype(V)
print(io, typeof(t).name)
else
if isleaftype(K) && isleaftype(V)
print(io, typeof(t).name)
else
print(io, typeof(t))
end
print(io, '(')
first = true
n = 0
for (k, v) in t
first || print(io, ',')
first = false
show(io, k)
print(io, "=>")
show(io, v)
n+=1
limit && n >= 10 && (print(io, "…"); break)
end
print(io, ')')
print(io, typeof(t))
end
print(io, '(')
first = true
n = 0
for (k, v) in t
first || print(io, ',')
first = false
show(recur_io, k)
print(io, "=>")
show(recur_io, v)
n+=1
limit && n >= 10 && (print(io, "…"); break)
end
return
print(io, ')')
end
return
end

# Otherwise show more descriptively, with one line per key/value pair
rows, cols = sz
print(io, summary(t))
isempty(t) && return
print(io, ":")
if limit
rows < 2 && (print(io, " …"); return)
cols < 12 && (cols = 12) # Minimum widths of 2 for key, 4 for value
cols -= 6 # Subtract the widths of prefix " " separator " => "
rows -= 2 # Subtract the summary and final ⋮ continuation lines

# determine max key width to align the output, caching the strings
ks = Array(AbstractString, min(rows, length(t)))
keylen = 0
for (i, k) in enumerate(keys(t))
i > rows && break
ks[i] = sprint(show, k)
keylen = clamp(length(ks[i]), keylen, div(cols, 3))
end
# Otherwise show more descriptively, with one line per key/value pair
rows, cols = sz
print(io, summary(t))
isempty(t) && return
print(io, ":")
if limit
rows < 2 && (print(io, " …"); return)
cols < 12 && (cols = 12) # Minimum widths of 2 for key, 4 for value
cols -= 6 # Subtract the widths of prefix " " separator " => "
rows -= 2 # Subtract the summary and final ⋮ continuation lines

# determine max key width to align the output, caching the strings
ks = Array(AbstractString, min(rows, length(t)))
keylen = 0
for (i, k) in enumerate(keys(t))
i > rows && break
ks[i] = sprint(0, show, k, env=recur_io)
keylen = clamp(length(ks[i]), keylen, div(cols, 3))
end
end

for (i, (k, v)) in enumerate(t)
print(io, "\n ")
limit && i > rows && (print(io, rpad("⋮", keylen), " => ⋮"); break)
for (i, (k, v)) in enumerate(t)
print(io, "\n ")
limit && i > rows && (print(io, rpad("⋮", keylen), " => ⋮"); break)

if limit
key = rpad(_truncate_at_width_or_chars(ks[i], keylen, "\r\n"), keylen)
else
key = sprint(show, k)
end
print(io, key)
print(io, " => ")
if limit
key = rpad(_truncate_at_width_or_chars(ks[i], keylen, "\r\n"), keylen)
else
key = sprint(0, show, k, env=recur_io)
end
print(recur_io, key)
print(io, " => ")

if limit
val = with_output_limit(()->sprint(show, v))
val = _truncate_at_width_or_chars(val, cols - keylen, "\r\n")
print(io, val)
else
show(io, v)
end
if limit
val = sprint(0, show, v, env=recur_io)
val = _truncate_at_width_or_chars(val, cols - keylen, "\r\n")
print(io, val)
else
show(recur_io, v)
end
finally
delete!(shown_set, t)
end
end

@@ -158,8 +150,9 @@ summary{T<:Union{KeyIterator,ValueIterator}}(iter::T) =
show(io::IO, iter::Union{KeyIterator,ValueIterator}) = show(io, collect(iter))

showkv(iter::Union{KeyIterator,ValueIterator}; kw...) = showkv(STDOUT, iter; kw...)
function showkv{T<:Union{KeyIterator,ValueIterator}}(io::IO, iter::T; limit::Bool = false,
function showkv{T<:Union{KeyIterator,ValueIterator}}(io::IO, iter::T;
sz=(s = tty_size(); (s[1]-3, s[2])))
limit::Bool = limit_output(io)
rows, cols = sz
print(io, summary(iter))
isempty(iter) && return
@@ -176,7 +169,7 @@ function showkv{T<:Union{KeyIterator,ValueIterator}}(io::IO, iter::T; limit::Boo
limit && i >= rows && (print(io, "⋮"); break)

if limit
str = with_output_limit(()->sprint(show, v))
str = sprint(0, show, v, env=io)
str = _truncate_at_width_or_chars(str, cols, "\r\n")
print(io, str)
else
5 changes: 3 additions & 2 deletions base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
@@ -3043,9 +3043,10 @@ Show an expression and result, returning the result.
"""
showcompact(x)


Show a more compact representation of a value. This is used for printing array elements. If
a new type has a different compact representation, it should overload `showcompact(io, x)`
where the first argument is a stream.
a new type has a different compact representation,
it should test `Base.limit_output(io)` in its normal `show` method.
"""
showcompact

2 changes: 1 addition & 1 deletion base/grisu.jl
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ function _show(io::IO, x::AbstractFloat, mode, n::Int, typed, nanstr, infstr)
nothing
end

Base.show(io::IO, x::AbstractFloat) = _show(io, x, SHORTEST, 0, true)
Base.show(io::IO, x::AbstractFloat) = Base.limit_output(io) ? showcompact(io, x) : _show(io, x, SHORTEST, 0, true)

Base.print(io::IO, x::Float32) = _show(io, x, SHORTEST, 0, false)
Base.print(io::IO, x::Float16) = _show(io, x, SHORTEST, 0, false)
28 changes: 12 additions & 16 deletions base/interactiveutil.jl
Original file line number Diff line number Diff line change
@@ -220,23 +220,19 @@ versioninfo(verbose::Bool) = versioninfo(STDOUT,verbose)
# displaying type-ambiguity warnings

function code_warntype(io::IO, f, t::ANY)
task_local_storage(:TYPEEMPHASIZE, true)
try
ct = code_typed(f, t)
for ast in ct
println(io, "Variables:")
vars = ast.args[2][1]
for v in vars
print(io, " ", v[1])
show_expr_type(io, v[2])
print(io, '\n')
end
print(io, "\nBody:\n ")
show_unquoted(io, ast.args[3], 2)
print(io, '\n')
emph_io = IOContext(io, :TYPEEMPHASIZE => true)
ct = code_typed(f, t)
for ast in ct
println(emph_io, "Variables:")
vars = ast.args[2][1]
for v in vars
print(emph_io, " ", v[1])
show_expr_type(emph_io, v[2])
print(emph_io, '\n')
end
finally
task_local_storage(:TYPEEMPHASIZE, false)
print(emph_io, "\nBody:\n ")
show_unquoted(emph_io, ast.args[3], 2)
print(emph_io, '\n')
end
nothing
end
33 changes: 33 additions & 0 deletions base/io.jl
Original file line number Diff line number Diff line change
@@ -27,6 +27,39 @@ function eof end
read(s::IO, ::Type{UInt8}) = error(typeof(s)," does not support byte I/O")
write(s::IO, x::UInt8) = error(typeof(s)," does not support byte I/O")

# Generic wrappers around other IO objects
abstract AbstractPipe <: IO
function pipe_reader end
function pipe_writer end

write(io::AbstractPipe, byte::UInt8) = write(pipe_writer(io), byte)
write(io::AbstractPipe, bytes::Vector{UInt8}) = write(pipe_writer(io), bytes)
write{T<:AbstractPipe}(io::T, args...) = write(pipe_writer(io), args...)
write{S<:AbstractPipe}(io::S, a::Array) = write(pipe_writer(io), a)
buffer_or_write(io::AbstractPipe, p::Ptr, n::Integer) = buffer_or_write(pipe_writer(io), p, n)
buffer_writes(io::AbstractPipe, args...) = buffer_writes(pipe_writer(io), args...)
flush(io::AbstractPipe) = flush(pipe_writer(io))

read(io::AbstractPipe, byte::Type{UInt8}) = read(pipe_reader(io), byte)
read!(io::AbstractPipe, bytes::Vector{UInt8}) = read!(pipe_reader(io), bytes)
read{T<:AbstractPipe}(io::T, args...) = read(pipe_reader(io), args...)
read!{T<:AbstractPipe}(io::T, args...) = read!(pipe_reader(io), args...)
readuntil{T<:AbstractPipe}(io::T, args...) = readuntil(pipe_reader(io), args...)
readbytes(io::AbstractPipe) = readbytes(pipe_reader(io))
readavailable(io::AbstractPipe) = readavailable(pipe_reader(io))

isreadable(io::AbstractPipe) = isreadable(pipe_reader(io))
iswritable(io::AbstractPipe) = iswritable(pipe_writer(io))
isopen(io::AbstractPipe) = isopen(pipe_writer(io)) || isopen(pipe_reader(io))
close(io::AbstractPipe) = (close(pipe_writer(io)); close(pipe_reader(io)))
wait_readnb(io::AbstractPipe, nb::Int) = wait_readnb(pipe_reader(io), nb)
wait_readbyte(io::AbstractPipe, byte::UInt8) = wait_readbyte(pipe_reader(io), byte)
wait_close(io::AbstractPipe) = (wait_close(pipe_writer(io)); wait_close(pipe_reader(io)))
nb_available(io::AbstractPipe) = nb_available(pipe_reader(io))
eof(io::AbstractPipe) = eof(pipe_reader(io))
reseteof(io::AbstractPipe) = reseteof(pipe_reader(io))


## byte-order mark, ntoh & hton ##

const ENDIAN_BOM = reinterpret(UInt32,UInt8[1:4;])[1]
9 changes: 0 additions & 9 deletions base/iostream.jl
Original file line number Diff line number Diff line change
@@ -200,15 +200,6 @@ function takebuf_raw(s::IOStream)
return buf, sz
end

function sprint(size::Integer, f::Function, args...)
s = IOBuffer(Array(UInt8,size), true, true)
truncate(s,0)
f(s, args...)
takebuf_string(s)
end

sprint(f::Function, args...) = sprint(0, f, args...)

write(x) = write(STDOUT::IO, x)

function readuntil(s::IOStream, delim::UInt8)
6 changes: 3 additions & 3 deletions base/irrationals.jl
Original file line number Diff line number Diff line change
@@ -130,8 +130,8 @@ log(::Irrational{:e}) = 1 # use 1 to correctly promote expressions like log(x)/l
log(::Irrational{:e}, x) = log(x)

# align along = for nice Array printing
function alignment(x::Irrational)
m = match(r"^(.*?)(=.*)$", sprint(showcompact_lim, x))
m === nothing ? (length(sprint(showcompact_lim, x)), 0) :
function alignment(io::IO, x::Irrational)
m = match(r"^(.*?)(=.*)$", sprint(0, showcompact_lim, x, env=io))
m === nothing ? (length(sprint(0, showcompact_lim, x, env=io)), 0) :
(length(m.captures[1]), length(m.captures[2]))
end
2 changes: 1 addition & 1 deletion base/methodshow.jl
Original file line number Diff line number Diff line change
@@ -181,4 +181,4 @@ end

# override usual show method for Vector{Method}: don't abbreviate long lists
writemime(io::IO, mime::MIME"text/plain", mt::AbstractVector{Method}) =
showarray(io, mt, limit=false)
showarray(IOContext(io, :limit_output => false), mt)
3 changes: 1 addition & 2 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ import
exp, exp2, exponent, factorial, floor, fma, hypot, isinteger,
isfinite, isinf, isnan, ldexp, log, log2, log10, max, min, mod, modf,
nextfloat, prevfloat, promote_rule, rem, round, show,
showcompact, sum, sqrt, string, print, trunc, precision, exp10, expm1,
sum, sqrt, string, print, trunc, precision, exp10, expm1,
gamma, lgamma, digamma, erf, erfc, zeta, eta, log1p, airyai,
eps, signbit, sin, cos, tan, sec, csc, cot, acos, asin, atan,
cosh, sinh, tanh, sech, csch, coth, acosh, asinh, atanh, atan2,
@@ -863,7 +863,6 @@ end

print(io::IO, b::BigFloat) = print(io, string(b))
show(io::IO, b::BigFloat) = print(io, string(b))
showcompact(io::IO, b::BigFloat) = print(io, string(b))

# get/set exponent min/max
get_emax() = ccall((:mpfr_get_emax, :libmpfr), Clong, ())
4 changes: 2 additions & 2 deletions base/precompile.jl
Original file line number Diff line number Diff line change
@@ -172,7 +172,7 @@ precompile(Base.abspath, (UTF8String, UTF8String))
precompile(Base.abspath, (UTF8String,))
precompile(Base.abspath, (ASCIIString, ASCIIString))
precompile(Base.abspath, (ASCIIString,))
precompile(Base.alignment, (Float64,))
precompile(Base.alignment, (Base.IOContext, Float64,))
precompile(Base.any, (Function, Array{Any,1}))
precompile(Base.arg_gen, (ASCIIString,))
precompile(Base.associate_julia_struct, (Ptr{Void}, Base.TTY))
@@ -379,7 +379,7 @@ precompile(Base.setindex!, (Vector{Any}, Vector{Any}, Int))
precompile(Base.show, (Base.Terminals.TTYTerminal, Int))
precompile(Base.show, (Float64,))
precompile(Base.show, (IOStream, Int32))
precompile(Base.showlimited, (Base.Terminals.TTYTerminal, Int))
precompile(Base.showcompact, (Base.Terminals.TTYTerminal, Int))
precompile(Base.similar, (Array{Base.LineEdit.Prompt, 1}, Type{Base.LineEdit.TextInterface}, Tuple{Int}))
precompile(Base.size, (Base.Terminals.TTYTerminal,))
precompile(Base.sizehint!, (Base.Dict{Symbol, Any}, Int))
Loading