/
githubmirror
/
julia
Обзор
Документация
Войти
/
githubmirror
/
julia
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
stdlib/Markdown/src/render/html.jl
259 строк
7 KB
Max Horn
Markdown: add support for "Raw" or "Inline" HTML (#60732)
19 фев 2026, 17:32
Не верифицирован
19 фев 2026, 17:32
c5f4ca8
Код
Авторство
О чём код?
# This file is a part of Julia. License is MIT: https://julialang.org/license include("rich.jl") # Utils # Handle URI encoding, poorly. The code here was initially copied from # Base.Filesystem, then modified. The original code implements RFC3986 Section # 2.1 and 2.2. # # We changed encode_uri_component to not encode characters declared as # "reserved" by RFC3986 Section 2.2 (i.e., those from the gen-delims and # sub-delims sets). Instead the user is expected to percent encode these (or # not) as needed -- the alternative would be implement full URI parsing, which # is non-trivial. That said, it would be better to do that, by e.g. using the # URIs.jl package, but that is not an option for us, as it is not a stdlib... # # As a special affordance, we deviate from the "reserved" list in one way: we # do *not* exclude '[' and ']' from percent encoding, even though they are in # the gen-delims set. They are only used to encode IPv6 literal addresses in # the URI, which is (still) rare. But they do occur in query strings and # indeed in the CommonMark spec tests. percent_escape(s) = '%' * join(map(b -> uppercase(string(b, base=16)), codeunits(s)), '%') encode_uri_component(s::AbstractString) = replace(s, r"[^A-Za-z0-9\-_.~/:?#@!$&'()*+,;=]+" => percent_escape) encode_uri_component(s::Symbol) = encode_uri_component(string(s)) function withtag(f, io::IO, tag, attrs...) print(io, "<$tag") for (attr, value) in attrs print(io, " ", attr, "=\"") htmlesc(io, value) print(io, "\"") end f === nothing && return print(io, " />") print(io, ">") f() print(io, "</$tag>") end tag(io::IO, tag, attrs...) = withtag(nothing, io, tag, attrs...) function htmlesc(io::IO, s::AbstractString) replace(io, s, '<'=>"<", '>'=>">", '"'=>""", '&'=>"&") end function htmlesc(io::IO, s::Symbol) htmlesc(io, string(s)) end function htmlesc(io::IO, xs::Union{AbstractString,Symbol}...) for s in xs htmlesc(io, s) end end function htmlesc(s::Union{AbstractString,Symbol}) sprint(htmlesc, s) end # Block elements function html(io::IO, content::Vector) for md in content html(io, md) println(io) end end html(io::IO, md::MD) = html(io, md.content) function html(io::IO, header::Header{l}) where l withtag(io, "h$l") do htmlinline(io, header.text) end end function html(io::IO, code′::Code) if code′.language == "styled" code′ = Code("", String(styled(code′.code))) end code = code′ withtag(io, :pre) do maybe_lang = !isempty(code.language) ? Any[:class=>"language-$(code.language)"] : [] withtag(io, :code, maybe_lang...) do htmlesc(io, code.code) !isempty(code.code) && println(io) end end end function html(io::IO, md::Paragraph) withtag(io, :p) do htmlinline(io, md.content) end end function html(io::IO, md::HTMLBlock) for line in md.content[1:end-1] println(io, line) end print(io, md.content[end]) end function html(io::IO, md::BlockQuote) withtag(io, :blockquote) do println(io) html(io, md.content) end end function html(io::IO, f::Footnote) withtag(io, :div, :class => "footnote", :id => "footnote-$(f.id)") do withtag(io, :p, :class => "footnote-title") do print(io, f.id) end html(io, f.text) end end function html(io::IO, md::Admonition) withtag(io, :div, :class => "admonition $(md.category)") do withtag(io, :p, :class => "admonition-title") do print(io, md.title) end html(io, md.content) end end function html(io::IO, md::List) maybe_attr = md.ordered > 1 ? Any[:start => string(md.ordered)] : [] withtag(io, isordered(md) ? :ol : :ul, maybe_attr...) do for item in md.items println(io) withtag(io, :li) do if md.loose println(io) html(io, item) else htmltight(io, item) end end end println(io) end end htmltight(io::IO, md) = html(io, md) htmltight(io::IO, md::Paragraph) = htmlinline(io, md.content) function htmltight(io::IO, content::Vector) for md in content htmltight(io, md) end end function html(io::IO, md::HorizontalRule) tag(io, :hr) end html(io::IO, x) = tohtml(io, x) # Inline elements function htmlinline(io::IO, content::Vector) for x in content htmlinline(io, x) end end function htmlinline(io::IO, code′::Code) if code′.language == "styled" code′ = Code("", String(styled(code′.code))) end code = code′ withtag(io, :code) do htmlesc(io, code.code) end end function htmlinline(io::IO, md::Union{Symbol,AbstractString}) htmlinline(io, String(md)) end function htmlinline(io::IO, s::String) # Spaces at the end of the line and beginning of the next line are removed s = replace(s, r"[ \t]+\n" => "\n") s = replace(s, r"\n[ \t]+" => "\n") htmlesc(io, s) end function htmlinline(io::IO, md::Bold) withtag(io, :strong) do htmlinline(io, md.text) end end function htmlinline(io::IO, md::Italic) withtag(io, :em) do htmlinline(io, md.text) end end function htmlinline(io::IO, md::Strikethrough) withtag(io, :s) do htmlinline(io, md.text) end end function htmlinline(io::IO, md::Image) tag(io, :img, :src=>encode_uri_component(md.url), :alt=>md.alt) end function htmlinline(io::IO, f::Footnote) withtag(io, :a, :href => "#footnote-$(f.id)", :class => "footnote") do print(io, "[", f.id, "]") end end function htmlinline(io::IO, link::Link) withtag(io, :a, :href=>encode_uri_component(link.url)) do htmlinline(io, link.text) end end function htmlinline(io::IO, br::LineBreak) tag(io, :br) println(io) end htmlinline(io::IO, md::HTMLInline) = print(io, md.content) htmlinline(io::IO, x) = tohtml(io, x) # API export html """ html([io::IO], md) Output the contents of the Markdown object `md` in HTML format, either writing to an (optional) `io` stream or returning a string. One can alternatively use `show(io, "text/html", md)` or `repr("text/html", md)`, which differ in that they wrap the output in a `<div class="markdown"> ... </div>` element. # Examples ```jldoctest julia> html(md"hello _world_") "<p>hello <em>world</em></p>\\n" ``` """ html(md) = sprint(html, md) function show(io::IO, ::MIME"text/html", md::MD) withtag(io, :div, :class=>"markdown") do html(io, md) end end