Skip to content

Can ImageInTerminal.disable_encoding() propagate to third-party packages? #78

@jwortmann

Description

@jwortmann

This package defines Base.displayable for the ::TerminalGraphicDisplay with MIME image/png:

Base.displayable(::TerminalGraphicDisplay, ::MIME"image/png", x::Any) =
showable("image/png", x)
Base.displayable(::TerminalGraphicDisplay, ::MIME"image/png", ::Vector{UInt8}) = true
Base.displayable(::TerminalGraphicDisplay, ::MIME"image/png", ::AbstractArray{<:Colorant}) =
true

The README mentions rendering for Colorant and for Latexify.jl, but we can also use it in a third-party package MyPackage to render custom types in form of an image if ImageInTerminal is loaded. For example:

module MyPackage

import Sixel

const SIXEL_SUPPORTED = Ref(false)

struct MyType end

# Base.summary(io::IO, x::MyType) = ...

function Base.show(io::IO, ::MIME"text/plain", x::MyType)
    println(io, summary(x), ":")
    # only render as image if terminal has Sixel support
    if SIXEL_SUPPORTED[] && displayable("image/png")
        display("image/png", x)
    else
        # println(...)
    end
end

function Base.show(io::IO, ::MIME"image/png", x::MyType)
    # ...
end

__init__() = SIXEL_SUPPORTED[] = Sixel.is_sixel_supported()

end

However, ImageInTerminal also defines functions disable_encoding() and enable_encoding() to toggle image rendering on/off during runtime. Currently there is no way for MyPackage to know whether the user has toggled image rendering, and therefore calling ImageInTerminal.disable_encoding() has no effect for the code shown above. I wonder whether the current state should be reflected in displayable, like this (here only the first line seems relevant for third-party packages):

Base.displayable(::TerminalGraphicDisplay, ::MIME"image/png", x::Any) = SHOULD_RENDER_IMAGE[] && showable("image/png", x)
Base.displayable(::TerminalGraphicDisplay, ::MIME"image/png", ::Vector{UInt8}) = SHOULD_RENDER_IMAGE[]
Base.displayable(::TerminalGraphicDisplay, ::MIME"image/png", ::AbstractArray{<:Colorant}) = SHOULD_RENDER_IMAGE[]

What do you think?


Edit: Actually I just realized that in the code above I call only displayable("image/png"), without the x::MyType, and the solution suggested here doesn't work. I'll try to find out where the single-argument displayable comes from and how it relates to the methods that are defined in this package (loading ImageInTerminal does have an effect for the single-argument displayable("image/png")).

Edit 2: Okay, I found it at https://github.com/JuliaLang/julia/blob/3076a9683609b5c587ae3cbc70b25b7332018c7f/base/multimedia.jl#L364-L372
In particular displayable("image/png") only checks if there is a method display("image/png", x::Any) defined for any display in the display stack. Indeed it is defined at

function Base.display(d::TerminalGraphicDisplay, ::MIME"image/png", x::Any)

This means that displayable("image/png") will unconditionally always return true if ImageInTerminal is loaded, and I will need to think of another way how the ImageInTerminal.disable_encoding() could propagate to third-party packages.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions