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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions