From 8950cf80586f691a3650204366450106afe350ee Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Sat, 21 Jan 2017 15:30:40 -0500 Subject: [PATCH] support display of arbitrary textual MIME types in REPL, throw better error if show(io, MIME, x) is not defined during display (#19993) --- base/multimedia.jl | 63 ++++++++++++++++++++++++++++++---------------- test/show.jl | 12 +++++++++ 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/base/multimedia.jl b/base/multimedia.jl index 6756adad54846..54b1101f67826 100644 --- a/base/multimedia.jl +++ b/base/multimedia.jl @@ -141,9 +141,9 @@ 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 @@ -151,6 +151,13 @@ 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) @@ -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 @@ -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 diff --git a/test/show.jl b/test/show.jl index 09f140bc88d58..5838cfc4d23f6 100644 --- a/test/show.jl +++ b/test/show.jl @@ -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