Skip to content

Commit

Permalink
support display of arbitrary textual MIME types in REPL, throw better…
Browse files Browse the repository at this point in the history
… error if show(io, MIME, x) is not defined during display (JuliaLang#19993)
  • Loading branch information
stevengj committed Jan 21, 2017
1 parent b07b6dd commit 8950cf8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 21 deletions.
63 changes: 42 additions & 21 deletions base/multimedia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,23 @@ displayable(mime::AbstractString) = displayable(MIME(mime))
"""
TextDisplay(io::IO)
Returns a `TextDisplay <: Display`, which can display any object as the text/plain MIME type
(only), writing the text representation to the given I/O stream. (The text representation is
the same as the way an object is printed in the Julia REPL.)
Returns a `TextDisplay <: Display`, which displays any object as the text/plain MIME type
(by default), writing the text representation to the given I/O stream. (This is how
objects are printed in the Julia REPL.)
"""
immutable TextDisplay <: Display
io::IO
end
display(d::TextDisplay, M::MIME"text/plain", x) = show(d.io, M, x)
display(d::TextDisplay, x) = display(d, MIME"text/plain"(), x)

# if you explicitly call display("text/foo", x), it should work on a TextDisplay:
displayable(d::TextDisplay, M::MIME) = istextmime(M)
function display(d::TextDisplay, M::MIME, x)
displayable(d, M) || throw(MethodError(display, (d, M, x)))
show(d.io, M, x)
end

import Base: close, flush
flush(d::TextDisplay) = flush(d.io)
close(d::TextDisplay) = close(d.io)
Expand Down Expand Up @@ -178,30 +185,32 @@ function reinit_displays()
pushdisplay(TextDisplay(STDOUT))
end

macro try_display(expr)
quote
try $(esc(expr))
catch e
isa(e, MethodError) && e.f in (display, redisplay, show) ||
rethrow()
end
end
end

xdisplayable(D::Display, args...) = applicable(display, D, args...)

function display(x)
for i = length(displays):-1:1
xdisplayable(displays[i], x) &&
@try_display return display(displays[i], x)
if xdisplayable(displays[i], x)
try
return display(displays[i], x)
catch e
isa(e, MethodError) && e.f in (display, show) ||
rethrow()
end
end
end
throw(MethodError(display, (x,)))
end

function display(m::MIME, x)
for i = length(displays):-1:1
xdisplayable(displays[i], m, x) &&
@try_display return display(displays[i], m, x)
if xdisplayable(displays[i], m, x)
try
return display(displays[i], m, x)
catch e
isa(e, MethodError) && e.f == display ||
rethrow()
end
end
end
throw(MethodError(display, (m, x)))
end
Expand All @@ -226,16 +235,28 @@ end

function redisplay(x)
for i = length(displays):-1:1
xdisplayable(displays[i], x) &&
@try_display return redisplay(displays[i], x)
if xdisplayable(displays[i], x)
try
return redisplay(displays[i], x)
catch e
isa(e, MethodError) && e.f in (redisplay, display, show) ||
rethrow()
end
end
end
throw(MethodError(redisplay, (x,)))
end

function redisplay(m::Union{MIME,AbstractString}, x)
for i = length(displays):-1:1
xdisplayable(displays[i], m, x) &&
@try_display return redisplay(displays[i], m, x)
if xdisplayable(displays[i], m, x)
try
return redisplay(displays[i], m, x)
catch e
isa(e, MethodError) && e.f in (redisplay, display) ||
rethrow()
end
end
end
throw(MethodError(redisplay, (m, x)))
end
Expand Down
12 changes: 12 additions & 0 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -630,3 +630,15 @@ end

# don't use julia-specific `f` in Float32 printing (PR #18053)
@test sprint(print, 1f-7) == "1.0e-7"

# test that the REPL TextDisplay works for displaying arbitrary textual MIME types
let d = TextDisplay(IOBuffer())
display(d, "text/csv", [3 1 4])
@test String(take!(d.io)) == "3,1,4\n"
@test_throws MethodError display(d, "text/foobar", [3 1 4])
try
display(d, "text/foobar", [3 1 4])
catch e
@test e.f == show
end
end

0 comments on commit 8950cf8

Please sign in to comment.