diff --git a/base/markdown/render/html.jl b/base/markdown/render/html.jl index 770d4cbd86bc0..f8b738892be5d 100644 --- a/base/markdown/render/html.jl +++ b/base/markdown/render/html.jl @@ -5,7 +5,11 @@ include("rich.jl") function withtag(f, io::IO, tag, attrs...) print(io, "<$tag") for (attr, value) in attrs - print(io, " $attr=\"$value\"") + print(io, " ") + htmlesc(io, attr) + print(io, "=\"") + htmlesc(io, value) + print(io, "\"") end f == nothing && return print(io, " />") @@ -16,6 +20,32 @@ end tag(io::IO, tag, attrs...) = withtag(nothing, io, tag, attrs...) +const _htmlescape_chars = Dict('<'=>"<", '>'=>">", + '"'=>""", '&'=>"&", + # ' '=>" ", + ) +for ch in "'`!@\$\%()=+{}[]" + _htmlescape_chars[ch] = "&#$(Int(ch));" +end + +function htmlesc(io::IO, s::String) + # s1 = replace(s, r"&(?!(\w+|\#\d+);)", "&") + for ch in s + print(io, get(_htmlescape_chars, ch, ch)) + end +end +function htmlesc(io::IO, s::Symbol) + htmlesc(io, string(s)) +end +function htmlesc(io::IO, xs::Union(String, Symbol)...) + for s in xs + htmlesc(io, s) + end +end +function htmlesc(s::Union(String, Symbol)) + sprint(htmlesc, s) +end + # Block elements function html(io::IO, content::Vector) @@ -36,7 +66,7 @@ end function html(io::IO, code::Code) withtag(io, :pre) do withtag(io, :code) do - print(io, code.code) + htmlesc(io, code.code) end end end @@ -80,12 +110,12 @@ end function htmlinline(io::IO, code::Code) withtag(io, :code) do - print(io, code.code) + htmlesc(io, code.code) end end -function htmlinline(io::IO, md::String) - print(io, md) +function htmlinline(io::IO, md::Union(Symbol, String)) + htmlesc(io, md) end function htmlinline(io::IO, md::Bold) diff --git a/base/markdown/render/plain.jl b/base/markdown/render/plain.jl index ab60ae678547b..67176f699c231 100644 --- a/base/markdown/render/plain.jl +++ b/base/markdown/render/plain.jl @@ -40,8 +40,6 @@ function plain(io::IO, md::HorizontalRule) println(io, "ā€“" ^ 3) end -plain(io::IO, x) = tohtml(io, x) - # Inline elements plaininline(x) = sprint(plaininline, x) diff --git a/base/markdown/render/rich.jl b/base/markdown/render/rich.jl index 54e582aba2830..9a229688c3252 100644 --- a/base/markdown/render/rich.jl +++ b/base/markdown/render/rich.jl @@ -3,7 +3,7 @@ function tohtml(io::IO, m::MIME"text/html", x) end function tohtml(io::IO, m::MIME"text/plain", x) - writemime(io, m, x) + htmlesc(io, sprint(writemime, m, x)) end function tohtml(io::IO, m::MIME"image/png", img) diff --git a/test/markdown.jl b/test/markdown.jl index cc0166b7a5249..6a3b252fbdeda 100644 --- a/test/markdown.jl +++ b/test/markdown.jl @@ -58,6 +58,7 @@ World""" |> plain == "Hello\n\nā€“ā€“ā€“\n\nWorld\n" --- World""" |> html == "

Hello

\n
\n

World

\n" +@test md"`escape`" |> html == "

escape</code>

\n" # Latex output book = md""" @@ -89,7 +90,20 @@ ref(fft) writemime(io::IO, m::MIME"text/plain", r::Reference) = print(io, "$(r.ref) (see Julia docs)") -@test md"Behaves like $(ref(fft))" == md"Behaves like fft (see Julia docs)" +#writemime(io::IO, m::MIME"text/html", r::Reference) = +# Markdown.withtag(io, :a, :href=>"test") do +# Markdown.htmlesc(io, Markdown.plaininline(r)) +# end + +fft_ref = md"Behaves like $(ref(fft))" +@test plain(fft_ref) == "Behaves like fft (see Julia docs)\n" +@test html(fft_ref) == "

Behaves like fft (see Julia docs)

\n" + +writemime(io::IO, m::MIME"text/html", r::Reference) = + Markdown.withtag(io, :a, :href=>"test") do + Markdown.htmlesc(io, Markdown.plaininline(r)) + end +@test html(fft_ref) == "

Behaves like fft (see Julia docs)

\n" @test md"""