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

RFC: move stringmime to Base64, rename reprmime -> repr #25990

Merged
merged 14 commits into from
Feb 17, 2018
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ Language changes
backslashes and the end of the literal while 2n+1 backslashes followed by a quote encodes n
backslashes followed by a quote character ([#22926]).

* `reprmime(mime, x)` has been renamed to `repr(mime, x)`, and along with `repr(x)`
and `sprint` it now accepts an optional `context` keyword for `IOContext` attributes.
`stringmime` has been moved to the Base64 stdlib package ([#25990]).

* The syntax `(x...)` for constructing a tuple is deprecated; use `(x...,)` instead ([#24452]).

* Non-parenthesized interpolated variables in strings, e.g. `"$x"`, must be followed
Expand Down
2 changes: 2 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,8 @@ end
@deprecate IOBuffer(read::Bool, write::Bool) IOBuffer(read=read, write=write)
@deprecate IOBuffer(maxsize::Integer) IOBuffer(read=true, write=true, maxsize=maxsize)

@deprecate reprmime(mime, x) repr(mime, x)

# PR #23332
@deprecate ^(x, p::Integer) Base.power_by_squaring(x,p)

Expand Down
2 changes: 0 additions & 2 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -876,8 +876,6 @@ export
istextmime,
MIME,
@MIME_str,
reprmime,
stringmime,
mimewritable,
popdisplay,
pushdisplay,
Expand Down
64 changes: 30 additions & 34 deletions base/multimedia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Multimedia

export AbstractDisplay, display, pushdisplay, popdisplay, displayable, redisplay,
MIME, @MIME_str, reprmime, stringmime, istextmime,
MIME, @MIME_str, istextmime,
mimewritable, TextDisplay

###########################################################################
Expand All @@ -15,8 +15,7 @@ export AbstractDisplay, display, pushdisplay, popdisplay, displayable, redisplay
# struct MIME{mime} end
# macro MIME_str(s)
import Base: MIME, @MIME_str
import Base64
import Base: show, print, string, convert
import Base: show, print, string, convert, repr
MIME(s) = MIME{Symbol(s)}()
show(io::IO, ::MIME{mime}) where {mime} = print(io, "MIME type ", string(mime))
print(io::IO, ::MIME{mime}) where {mime} = print(io, mime)
Expand Down Expand Up @@ -79,59 +78,60 @@ show(stream, mime, x)
show(io::IO, m::AbstractString, x) = show(io, MIME(m), x)
mimewritable(m::AbstractString, x) = mimewritable(MIME(m), x)

verbose_show(io, m, x) = show(IOContext(io, :limit => false), m, x)

"""
reprmime(mime, x)
repr(mime, x; context=nothing)

Returns an `AbstractString` or `Vector{UInt8}` containing the representation of
`x` in the requested `mime` type, as written by [`show`](@ref) (throwing a
`x` in the requested `mime` type, as written by [`show(io, mime, x)`](@ref) (throwing a
[`MethodError`](@ref) if no appropriate `show` is available). An `AbstractString` is
returned for MIME types with textual representations (such as `"text/html"` or
`"application/postscript"`), whereas binary data is returned as
`Vector{UInt8}`. (The function `istextmime(mime)` returns whether or not Julia
treats a given `mime` type as text.)

The optional keyword argument `context` can be set to `:key=>value` pair
or an `IO` or [`IOContext`](@ref) object whose attributes are used for the I/O
stream passed to `show`.

As a special case, if `x` is an `AbstractString` (for textual MIME types) or a
`Vector{UInt8}` (for binary MIME types), the `reprmime` function assumes that
`Vector{UInt8}` (for binary MIME types), the `repr` function assumes that
`x` is already in the requested `mime` format and simply returns `x`. This
special case does not apply to the `"text/plain"` MIME type. This is useful so
that raw data can be passed to `display(m::MIME, x)`.

In particular, `repr("text/plain", x)` is typically a "pretty-printed" version
of `x` designed for human consumption. See also [`repr(x)`](@ref) to instead
return a string corresponding to [`show(x)`](@ref) that may be closer to how
the value of `x` would be entered in Julia.

# Examples
```jldoctest
julia> A = [1 2; 3 4];

julia> reprmime("text/plain", A)
julia> repr("text/plain", A)
"2×2 Array{Int64,2}:\\n 1 2\\n 3 4"
```
"""
reprmime(m::MIME, x) = istextmime(m) ? _textreprmime(m, x) : _binreprmime(m, x)
repr(m::MIME, x; context=nothing) = istextmime(m) ? _textrepr(m, x, context) : _binrepr(m, x, context)
repr(m::AbstractString, x; context=nothing) = repr(MIME(m), x; context=context)

# strings are shown escaped for text/plain
_textreprmime(m::MIME, x) = sprint(verbose_show, m, x)
_textreprmime(::MIME, x::AbstractString) = x
_textreprmime(m::MIME"text/plain", x::AbstractString) =
sprint(verbose_show, m, x)
_textrepr(m::MIME, x, context) = String(__binrepr(m, x, context))
_textrepr(::MIME, x::AbstractString, context) = x
_textrepr(m::MIME"text/plain", x::AbstractString, context) = String(__binrepr(m, x, context))

function _binreprmime(m::MIME, x)

function __binrepr(m::MIME, x, context)
s = IOBuffer()
verbose_show(s, m, x)
if context === nothing
show(s, m, x)
else
show(IOContext(s, context), m, x)
end
take!(s)
end
_binreprmime(m::MIME, x::Vector{UInt8}) = x

"""
stringmime(mime, x)

Returns an `AbstractString` containing the representation of `x` in the
requested `mime` type. This is similar to [`reprmime`](@ref) except
that binary data is base64-encoded as an ASCII string.
"""
stringmime(m::MIME, x) = istextmime(m) ? reprmime(m, x) : _binstringmime(m, x)

_binstringmime(m::MIME, x) = Base64.base64encode(verbose_show, m, x)
_binstringmime(m::MIME, x::Vector{UInt8}) = Base64.base64encode(write, x)
_binrepr(m::MIME, x, context) = __binrepr(m, x, context)
_binrepr(m::MIME, x::Vector{UInt8}, context) = x

"""
istextmime(m::MIME)
Expand All @@ -149,11 +149,7 @@ false
```
"""
istextmime(m::MIME) = startswith(string(m), "text/")

# it is convenient to accept strings instead of ::MIME
istextmime(m::AbstractString) = istextmime(MIME(m))
reprmime(m::AbstractString, x) = reprmime(MIME(m), x)
stringmime(m::AbstractString, x) = stringmime(MIME(m), x)

for mime in ["application/atom+xml", "application/ecmascript",
"application/javascript", "application/julia",
Expand All @@ -169,7 +165,7 @@ end
# We have an abstract AbstractDisplay class that can be subclassed in order to
# define new rich-display output devices. A typical subclass should
# overload display(d::AbstractDisplay, m::MIME, x) for supported MIME types m,
# (typically using reprmime or stringmime to get the MIME
# (typically using show, repr, ..., to get the MIME
# representation of x) and should also overload display(d::AbstractDisplay, x)
# to display x in whatever MIME type is preferred by the AbstractDisplay and
# is writable by x. display(..., x) should throw a MethodError if x
Expand Down
32 changes: 16 additions & 16 deletions base/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,16 @@ println(io::IO, xs...) = print(io, xs..., '\n')
## conversion of general objects to strings ##

"""
sprint(f::Function, args...)
sprint(f::Function, args...; context=nothing, sizehint=0)

Call the given function with an I/O stream and the supplied extra arguments.
Everything written to this I/O stream is returned as a string.

The optional keyword argument `context` can be set to `:key=>value` pair
or an `IO` or [`IOContext`](@ref) object whose attributes are used for the I/O
stream passed to `f`. The optional `sizehint` is a suggersted (in bytes)
to allocate for the buffer used to write the string.

# Examples
```jldoctest
julia> sprint(showcompact, 66.66666)
Expand Down Expand Up @@ -147,12 +152,17 @@ function print_quoted_literal(io, s::AbstractString)
end

"""
repr(x)
repr(x, context::Pair{Symbol,<:Any}...)
repr(x; context=nothing)

Create a string from any value using the [`show`](@ref) function.
If context pairs are given, the IO buffer used to capture `show` output
is wrapped in an `IOContext` object with those context pairs.

The optional keyword argument `context` can be set to an `IO` or [`IOContext`](@ref)
object whose attributes are used for the I/O stream passed to `show`.

Note that `repr(x)` is usually similar to how the value of `x` would
be entered in Julia. See also [`repr("text/plain", x)`](@ref) to instead
return a "pretty-printed" version of `x` designed more for human consumption,
equivalent to the REPL display of `x`.

# Examples
```jldoctest
Expand All @@ -164,17 +174,7 @@ julia> repr(zeros(3))

```
"""
function repr(x)
s = IOBuffer()
show(s, x)
String(take!(s))
end

function repr(x, context::Pair{Symbol}...)
s = IOBuffer()
show(IOContext(s, context...), x)
String(take!(s))
end
repr(x; context=nothing) = sprint(show, x; context=context)

# IOBuffer views of a (byte)string:

Expand Down
7 changes: 1 addition & 6 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -448,12 +448,6 @@ let BINDIR = ccall(:jl_get_julia_bindir, Any, ())
init_load_path(BINDIR)
end

INCLUDE_STATE = 3 # include = include_relative

import Base64

INCLUDE_STATE = 2

include("asyncmap.jl")

include("multimedia.jl")
Expand Down Expand Up @@ -575,6 +569,7 @@ Base.require(Base, :Markdown)
@deprecate_stdlib base64decode Base64 true
@deprecate_stdlib Base64EncodePipe Base64 true
@deprecate_stdlib Base64DecodePipe Base64 true
@deprecate_stdlib stringmime Base64 true

@deprecate_stdlib poll_fd FileWatching true
@deprecate_stdlib poll_file FileWatching true
Expand Down
8 changes: 4 additions & 4 deletions doc/src/base/io-network.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ Base.Multimedia.redisplay
Base.Multimedia.displayable
Base.show(::Any, ::Any, ::Any)
Base.Multimedia.mimewritable
Base.Multimedia.reprmime
Base.Multimedia.stringmime
Base.repr(::Any, ::Any)
```

As mentioned above, one can also define new display backends. For example, a module that can display
Expand All @@ -105,8 +104,9 @@ types with PNG representations will automatically display the image using the mo
In order to define a new display backend, one should first create a subtype `D` of the abstract
class `AbstractDisplay`. Then, for each MIME type (`mime` string) that can be displayed on `D`, one should
define a function `display(d::D, ::MIME"mime", x) = ...` that displays `x` as that MIME type,
usually by calling [`reprmime(mime, x)`](@ref). A `MethodError` should be thrown if `x` cannot be displayed
as that MIME type; this is automatic if one calls [`reprmime`](@ref). Finally, one should define a function
usually by calling [`show(io, mime, x)`](@ref) or [`repr(io, mime, x)`](@ref).
A `MethodError` should be thrown if `x` cannot be displayed
as that MIME type; this is automatic if one calls `show` or `repr`. Finally, one should define a function
`display(d::D, x)` that queries [`mimewritable(mime, x)`](@ref) for the `mime` types supported by `D`
and displays the "best" one; a `MethodError` should be thrown if no supported MIME types are found
for `x`. Similarly, some subtypes may wish to override [`redisplay(d::D, ...)`](@ref Base.Multimedia.redisplay). (Again, one should
Expand Down
2 changes: 1 addition & 1 deletion doc/src/base/strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Base.:^(::AbstractString, ::Integer)
Base.string
Base.repeat(::AbstractString, ::Integer)
Base.repeat(::Char, ::Integer)
Base.repr
Base.repr(::Any)
Core.String(::AbstractString)
Base.SubString
Base.transcode
Expand Down
1 change: 1 addition & 0 deletions stdlib/Base64/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Base64.Base64EncodePipe
Base64.base64encode
Base64.Base64DecodePipe
Base64.base64decode
Base64.stringmime
```
20 changes: 19 additions & 1 deletion stdlib/Base64/src/Base64.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export
Base64EncodePipe,
base64encode,
Base64DecodePipe,
base64decode
base64decode,
stringmime

# Base64EncodePipe is a pipe-like IO object, which converts into base64 data
# sent to a stream. (You must close the pipe to complete the encode, separate
Expand All @@ -23,4 +24,21 @@ include("buffer.jl")
include("encode.jl")
include("decode.jl")

"""
stringmime(mime, x; context=nothing)

Returns an `AbstractString` containing the representation of `x` in the
requested `mime` type. This is similar to [`repr(mime, x)`](@ref) except
that binary data is base64-encoded as an ASCII string.

The optional keyword argument `context` can be set to `:key=>value` pair
or an `IO` or [`IOContext`](@ref) object whose attributes are used for the I/O
stream passed to `show`.
"""
stringmime(m::MIME, x; context=nothing) = istextmime(m) ? Base._textrepr(m, x, context) : _binstringmime(m, x, context)
stringmime(m::AbstractString, x; context=nothing) = stringmime(MIME(m), x; context=context)

_binstringmime(m::MIME, x, context) = Base64.base64encode(show, m, x; context=IOContext)
_binstringmime(m::MIME, x::Vector{UInt8}, context) = Base64.base64encode(write, x; context=context)

end
18 changes: 13 additions & 5 deletions stdlib/Base64/src/encode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ function loadtriplet!(buffer::Buffer, ptr::Ptr{UInt8}, n::UInt)
end

"""
base64encode(writefunc, args...)
base64encode(args...)
base64encode(writefunc, args...; context=nothing)
base64encode(args...; context=nothing)

Given a [`write`](@ref)-like function `writefunc`, which takes an I/O stream as
its first argument, `base64encode(writefunc, args...)` calls `writefunc` to
Expand All @@ -193,13 +193,21 @@ write `args...` to a base64-encoded string, and returns the string.
converts its arguments into bytes using the standard [`write`](@ref) functions
and returns the base64-encoded string.

The optional keyword argument `context` can be set to `:key=>value` pair
or an `IO` or [`IOContext`](@ref) object whose attributes are used for the I/O
stream passed to `writefunc` or `write`.

See also [`base64decode`](@ref).
"""
function base64encode(f::Function, args...)
function base64encode(f::Function, args...; context=nothing)
s = IOBuffer()
b = Base64EncodePipe(s)
f(b, args...)
if context === nothing
f(b, args...)
else
f(IOContext(b, context), args...)
end
close(b)
return String(take!(s))
end
base64encode(args...) = base64encode(write, args...)
base64encode(args...; context=nothing) = base64encode(write, args...; context=context)
11 changes: 10 additions & 1 deletion stdlib/Base64/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import Base64:
Base64EncodePipe,
base64encode,
Base64DecodePipe,
base64decode
base64decode,
stringmime

const inputText = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."
const encodedMaxLine76 = """
Expand Down Expand Up @@ -75,3 +76,11 @@ end
@test hash(base64decode(base64encode(data))) == hash(data)
end
end

@testset "stringmime" begin
@test stringmime("text/plain", [1 2;3 4]) == repr("text/plain", [1 2;3 4])
@test stringmime("text/html", "raw html data") == "raw html data"
@test stringmime("text/plain", "string") == "\"string\""
@test stringmime("image/png", UInt8[2,3,4,7]) == "AgMEBw=="
@test stringmime("text/plain", 3.141592653589793, context=:compact=>true) == "3.14159"
end
2 changes: 2 additions & 0 deletions stdlib/Markdown/Project.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
name = "Markdown"
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
1 change: 1 addition & 0 deletions stdlib/Markdown/src/Markdown.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Tools for working with the Markdown file format. Mainly for documentation.
module Markdown

import Base: show, ==, with_output_color
using Base64: stringmime

include(joinpath("parse", "config.jl"))
include(joinpath("parse", "util.jl"))
Expand Down
4 changes: 2 additions & 2 deletions stdlib/REPL/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ When the cursor is at the beginning of the line, the prompt can be changed to a
julia> ? # upon typing ?, the prompt changes (in place) to: help?>

help?> string
search: string String stringmime Cstring Cwstring RevString randstring bytestring SubString
search: string String Cstring Cwstring RevString randstring bytestring SubString

string(xs...)

Expand Down Expand Up @@ -220,7 +220,7 @@ or type and then press the tab key to get a list all matches:

```julia-repl
julia> stri[TAB]
stride strides string stringmime strip
stride strides string strip

julia> Stri[TAB]
StridedArray StridedMatrix StridedVecOrMat StridedVector String
Expand Down
Loading