diff --git a/Project.toml b/Project.toml index 99d26f6d4a1..da137470901 100644 --- a/Project.toml +++ b/Project.toml @@ -3,6 +3,7 @@ uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" version = "0.27.3" [deps] +ANSIColoredPrinters = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" @@ -17,6 +18,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" [compat] +ANSIColoredPrinters = "0.0.1" DocStringExtensions = "0.4, 0.5, 0.6, 0.7, 0.8" IOCapture = "0.2" JSON = "0.19, 0.20, 0.21" diff --git a/assets/html/scss/documenter-dark.scss b/assets/html/scss/documenter-dark.scss index 4c9c86d058e..873274d4a6a 100644 --- a/assets/html/scss/documenter-dark.scss +++ b/assets/html/scss/documenter-dark.scss @@ -91,6 +91,8 @@ html.theme--#{$themename} { // } // } + @import "documenter/ansicolors"; + // FIXME: Hack to get a proper theme for highlight.js in the Darkly theme @import "highlightjs/a11y-dark"; // Also, a11y-dark does not highlight string interpolation properly. diff --git a/assets/html/scss/documenter-light.scss b/assets/html/scss/documenter-light.scss index 3b80a695d80..ede5a679466 100644 --- a/assets/html/scss/documenter-light.scss +++ b/assets/html/scss/documenter-light.scss @@ -19,6 +19,8 @@ @import "documenter/patches"; @import "documenter/layout/all"; +@import "documenter/ansicolors"; + // Workaround to compile in highlightjs theme, so that we could have different // themes for both @import "highlightjs/default" diff --git a/assets/html/scss/documenter/_ansicolors.scss b/assets/html/scss/documenter/_ansicolors.scss new file mode 100644 index 00000000000..13796a37d91 --- /dev/null +++ b/assets/html/scss/documenter/_ansicolors.scss @@ -0,0 +1,216 @@ +$ansi-black: $black-ter !default; +$ansi-red: null !default; +$ansi-green: null !default; +$ansi-yellow: null !default; +$ansi-blue: null !default; +$ansi-magenta: null !default; +$ansi-cyan: null !default; +$ansi-white: $grey-lighter !default; + +$ansi-light-black: null !default; +$ansi-light-red: null !default; +$ansi-light-green: null !default; +$ansi-light-yellow: null !default; +$ansi-light-blue: null !default; +$ansi-light-magenta: null !default; +$ansi-light-cyan: null !default; +$ansi-light-white: $white-ter !default; + +@if $documenter-is-dark-theme { + $ansi-red: $red !default; + $ansi-green: $green !default; + $ansi-yellow: $yellow !default; + $ansi-blue: $blue !default; + $ansi-magenta: $purple !default; + $ansi-cyan: $turquoise !default; + + $ansi-light-black: $grey-light !default; + + $ansi-light-red: lighten($ansi-red, 15) !default; + $ansi-light-green: lighten($ansi-green, 15) !default; + $ansi-light-yellow: lighten($ansi-yellow, 10) !default; + $ansi-light-blue: lighten($ansi-blue, 15) !default; + $ansi-light-magenta: lighten($ansi-magenta, 10) !default; + $ansi-light-cyan: lighten($ansi-cyan, 15) !default; +} + +@else { + $ansi-light-red: $red !default; + $ansi-light-green: $green !default; + $ansi-light-yellow: $yellow !default; + $ansi-light-blue: $blue !default; + $ansi-light-magenta: $purple !default; + $ansi-light-cyan: $turquoise !default; + + $ansi-light-black: $grey !default; + + $ansi-red: darken($ansi-light-red, 10) !default; + $ansi-green: darken($ansi-light-green, 10) !default; + $ansi-yellow: darken($ansi-light-yellow, 18) !default; + $ansi-blue: darken($ansi-light-blue, 10) !default; + $ansi-magenta: darken($ansi-light-magenta, 15) !default; + $ansi-cyan: darken($ansi-light-cyan, 10) !default; +} + +.ansi span { + &.sgr1 { + font-weight: bolder; + } + + &.sgr2 { + font-weight: lighter; + } + + &.sgr3 { + font-style: italic; + } + + &.sgr4 { + text-decoration: underline; + } + + &.sgr7 { + color: $body-background-color; + background-color: $text; + } + + &.sgr8 { + color: transparent; + + span { + color: transparent; + } + } + + &.sgr9 { + text-decoration: line-through; + } + + &.sgr30 { + color: $ansi-black; + } + + &.sgr31 { + color: $ansi-red; + } + + &.sgr32 { + color: $ansi-green; + } + + &.sgr33 { + color: $ansi-yellow; + } + + &.sgr34 { + color: $ansi-blue; + } + + &.sgr35 { + color: $ansi-magenta; + } + + &.sgr36 { + color: $ansi-cyan; + } + + &.sgr37 { + color: $ansi-white; + } + + &.sgr40 { + background-color: $ansi-black; + } + + &.sgr41 { + background-color: $ansi-red; + } + + &.sgr42 { + background-color: $ansi-green; + } + + &.sgr43 { + background-color: $ansi-yellow; + } + + &.sgr44 { + background-color: $ansi-blue; + } + + &.sgr45 { + background-color: $ansi-magenta; + } + + &.sgr46 { + background-color: $ansi-cyan; + } + + &.sgr47 { + background-color: $ansi-white; + } + + &.sgr90 { + color: $ansi-light-black; + } + + &.sgr91 { + color: $ansi-light-red; + } + + &.sgr92 { + color: $ansi-light-green; + } + + &.sgr93 { + color: $ansi-light-yellow; + } + + &.sgr94 { + color: $ansi-light-blue; + } + + &.sgr95 { + color: $ansi-light-magenta; + } + + &.sgr96 { + color: $ansi-light-cyan; + } + + &.sgr97 { + color: $ansi-light-white; + } + + &.sgr100 { + background-color: $ansi-light-black; + } + + &.sgr101 { + background-color: $ansi-light-red; + } + + &.sgr102 { + background-color: $ansi-light-green; + } + + &.sgr103 { + background-color: $ansi-light-yellow; + } + + &.sgr104 { + background-color: $ansi-light-blue; + } + + &.sgr105 { + background-color: $ansi-light-magenta; + } + + &.sgr106 { + background-color: $ansi-light-cyan; + } + + &.sgr107 { + background-color: $ansi-light-white; + } +} diff --git a/assets/html/themes/documenter-dark.css b/assets/html/themes/documenter-dark.css index c6db4fae570..0357c3bd3b2 100644 --- a/assets/html/themes/documenter-dark.css +++ b/assets/html/themes/documenter-dark.css @@ -7604,6 +7604,87 @@ html.theme--documenter-dark { overflow-y: scroll; text-rendering: optimizeLegibility; text-size-adjust: 100%; } + html.theme--documenter-dark .ansi span.sgr1 { + font-weight: bolder; } + html.theme--documenter-dark .ansi span.sgr2 { + font-weight: lighter; } + html.theme--documenter-dark .ansi span.sgr3 { + font-style: italic; } + html.theme--documenter-dark .ansi span.sgr4 { + text-decoration: underline; } + html.theme--documenter-dark .ansi span.sgr7 { + color: #1f2424; + background-color: #fff; } + html.theme--documenter-dark .ansi span.sgr8 { + color: transparent; } + html.theme--documenter-dark .ansi span.sgr8 span { + color: transparent; } + html.theme--documenter-dark .ansi span.sgr9 { + text-decoration: line-through; } + html.theme--documenter-dark .ansi span.sgr30 { + color: #242424; } + html.theme--documenter-dark .ansi span.sgr31 { + color: #e74c3c; } + html.theme--documenter-dark .ansi span.sgr32 { + color: #2ecc71; } + html.theme--documenter-dark .ansi span.sgr33 { + color: #f1b70e; } + html.theme--documenter-dark .ansi span.sgr34 { + color: #3498db; } + html.theme--documenter-dark .ansi span.sgr35 { + color: #8e44ad; } + html.theme--documenter-dark .ansi span.sgr36 { + color: #137886; } + html.theme--documenter-dark .ansi span.sgr37 { + color: #dbdee0; } + html.theme--documenter-dark .ansi span.sgr40 { + background-color: #242424; } + html.theme--documenter-dark .ansi span.sgr41 { + background-color: #e74c3c; } + html.theme--documenter-dark .ansi span.sgr42 { + background-color: #2ecc71; } + html.theme--documenter-dark .ansi span.sgr43 { + background-color: #f1b70e; } + html.theme--documenter-dark .ansi span.sgr44 { + background-color: #3498db; } + html.theme--documenter-dark .ansi span.sgr45 { + background-color: #8e44ad; } + html.theme--documenter-dark .ansi span.sgr46 { + background-color: #137886; } + html.theme--documenter-dark .ansi span.sgr47 { + background-color: #dbdee0; } + html.theme--documenter-dark .ansi span.sgr90 { + color: #8c9b9d; } + html.theme--documenter-dark .ansi span.sgr91 { + color: #ef8b80; } + html.theme--documenter-dark .ansi span.sgr92 { + color: #69dd9a; } + html.theme--documenter-dark .ansi span.sgr93 { + color: #f4c53e; } + html.theme--documenter-dark .ansi span.sgr94 { + color: #75b9e7; } + html.theme--documenter-dark .ansi span.sgr95 { + color: #a563c1; } + html.theme--documenter-dark .ansi span.sgr96 { + color: #1db4c9; } + html.theme--documenter-dark .ansi span.sgr97 { + color: #ecf0f1; } + html.theme--documenter-dark .ansi span.sgr100 { + background-color: #8c9b9d; } + html.theme--documenter-dark .ansi span.sgr101 { + background-color: #ef8b80; } + html.theme--documenter-dark .ansi span.sgr102 { + background-color: #69dd9a; } + html.theme--documenter-dark .ansi span.sgr103 { + background-color: #f4c53e; } + html.theme--documenter-dark .ansi span.sgr104 { + background-color: #75b9e7; } + html.theme--documenter-dark .ansi span.sgr105 { + background-color: #a563c1; } + html.theme--documenter-dark .ansi span.sgr106 { + background-color: #1db4c9; } + html.theme--documenter-dark .ansi span.sgr107 { + background-color: #ecf0f1; } html.theme--documenter-dark .hljs { background: #2b2b2b; color: #f8f8f2; } diff --git a/assets/html/themes/documenter-light.css b/assets/html/themes/documenter-light.css index b3291bc3e19..f193e5bdc12 100644 --- a/assets/html/themes/documenter-light.css +++ b/assets/html/themes/documenter-light.css @@ -7582,6 +7582,126 @@ html { #documenter .docs-main #documenter-search-results .docs-highlight { background-color: yellow; } +.ansi span.sgr1 { + font-weight: bolder; } + +.ansi span.sgr2 { + font-weight: lighter; } + +.ansi span.sgr3 { + font-style: italic; } + +.ansi span.sgr4 { + text-decoration: underline; } + +.ansi span.sgr7 { + color: white; + background-color: #222222; } + +.ansi span.sgr8 { + color: transparent; } + .ansi span.sgr8 span { + color: transparent; } + +.ansi span.sgr9 { + text-decoration: line-through; } + +.ansi span.sgr30 { + color: #242424; } + +.ansi span.sgr31 { + color: #a70800; } + +.ansi span.sgr32 { + color: #1a9847; } + +.ansi span.sgr33 { + color: #fac800; } + +.ansi span.sgr34 { + color: #244d8f; } + +.ansi span.sgr35 { + color: #931fff; } + +.ansi span.sgr36 { + color: #178d9c; } + +.ansi span.sgr37 { + color: #dbdbdb; } + +.ansi span.sgr40 { + background-color: #242424; } + +.ansi span.sgr41 { + background-color: #a70800; } + +.ansi span.sgr42 { + background-color: #1a9847; } + +.ansi span.sgr43 { + background-color: #fac800; } + +.ansi span.sgr44 { + background-color: #244d8f; } + +.ansi span.sgr45 { + background-color: #931fff; } + +.ansi span.sgr46 { + background-color: #178d9c; } + +.ansi span.sgr47 { + background-color: #dbdbdb; } + +.ansi span.sgr90 { + color: #7a7a7a; } + +.ansi span.sgr91 { + color: #da0b00; } + +.ansi span.sgr92 { + color: #22c35b; } + +.ansi span.sgr93 { + color: #ffdd57; } + +.ansi span.sgr94 { + color: #2e63b8; } + +.ansi span.sgr95 { + color: #b86bff; } + +.ansi span.sgr96 { + color: #1db5c9; } + +.ansi span.sgr97 { + color: whitesmoke; } + +.ansi span.sgr100 { + background-color: #7a7a7a; } + +.ansi span.sgr101 { + background-color: #da0b00; } + +.ansi span.sgr102 { + background-color: #22c35b; } + +.ansi span.sgr103 { + background-color: #ffdd57; } + +.ansi span.sgr104 { + background-color: #2e63b8; } + +.ansi span.sgr105 { + background-color: #b86bff; } + +.ansi span.sgr106 { + background-color: #1db5c9; } + +.ansi span.sgr107 { + background-color: whitesmoke; } + /*! Theme: Default Description: Original highlight.js style diff --git a/docs/src/showcase.md b/docs/src/showcase.md index f68c140c38b..c462bd88dcd 100644 --- a/docs/src/showcase.md +++ b/docs/src/showcase.md @@ -67,7 +67,7 @@ Finally, admonitions for notes, warnings and such: #### Heading 4 ##### Heading 5 ###### Heading 6 - + ###### Info admonition !!! info "'info' admonition" This is a `!!! info`-type admonition. This is the same as a `!!! note`-type. @@ -360,6 +360,49 @@ println("Hello World") 42 ``` +**TODO:** `ansicolor` keyword argument. +````markdown +```@example ; ansicolor = true +code_typed(sqrt, (Float64,)) +``` +```` + +```@example ; ansicolor = true +code_typed(sqrt, (Float64,)) +``` + +```` +```@example ; ansicolor = true +be = get(stdout, :color, false) ? "be" : "NOT be" +printstyled("This should $be in light cyan.\n", color=:light_cyan) +``` +```` +```@example ; ansicolor = true +be = get(stdout, :color, false) ? "be" : "NOT be" +printstyled("This should $be in light cyan.\n", color=:light_cyan) +``` + +On Julia v1.5 or earlier, the following workaround can be used to enforce coloring. However, +since this is a type piracy, its use should be limited to the document generation and not +within the package code itself. + +```@example ; ansicolor = true +Base.get(::Base.PipeEndpoint, key::Symbol, default) = key === :color ? true : default +printstyled("This should be in light magenta.\n", color=:light_magenta) +Base.get(::Base.PipeEndpoint, key::Symbol, default) = default; # hide +``` + +Regardless of the color setting, when you print the ANSI escape codes directly, coloring is +enabled. +```@example +for color in 0:15 + print("\e[38;5;$color;48;5;$(color)m ") + print("\e[49m", lpad(color, 3), " ") + color % 8 == 7 && println() +end +print("\e[m") +``` + ### REPL-type [`@repl` block](@ref) can be used to simulate the REPL evaluation of code blocks. For example, the following block @@ -382,6 +425,18 @@ median(xs) sum(xs) ``` +```@repl ; ansicolor = true +println("This is in normal color.") +be = get(stdout, :color, false) ? "be" : "NOT be" +printstyled("This should $be in light cyan.\n", color=:light_cyan) + +Base.get(::Base.PipeEndpoint, key::Symbol, default) = key === :color ? true : default + +@warn "It is a type piracy to define `Base.get(::Base.PipeEndpoint, key, default)`." + +Base.get(::Base.PipeEndpoint, key::Symbol, default) = default; # reset +``` + ## Doctest showcase Currently exists just so that there would be doctests to run in manual pages of Documenter's diff --git a/src/Expanders.jl b/src/Expanders.jl index c83dd6b311b..6a087a2506d 100644 --- a/src/Expanders.jl +++ b/src/Expanders.jl @@ -530,14 +530,24 @@ end # -------- function Selectors.runner(::Type{ExampleBlocks}, x, page, doc) + matched = match(r"^@example(?:\s+([^\s;]+))?\s*(;.*)?$", x.language) + matched === nothing && error("invalid '@example' syntax: $(x.language)") + name, kwargs = matched.captures # The sandboxed module -- either a new one or a cached one from this page. - name = match(r"^@example[ ]?(.*)$", first(split(x.language, ';', limit = 2)))[1] mod = Utilities.get_sandbox_module!(page.globals.meta, "atexample", name) sym = nameof(mod) lines = Utilities.find_block_in_file(x.code, page.source) - # "parse" keyword arguments to example (we only need to look for continued = true) - continued = occursin(r"continued\s*=\s*true", x.language) + # "parse" keyword arguments to example + continued = false + ansicolor = get(stdout, :color, false)::Bool + if kwargs !== nothing + continued = occursin(r"\bcontinued\s*=\s*true\b", kwargs) + matched = match(r"\bansicolor\s*=\s*(true|false)\b", kwargs) + if matched !== nothing + ansicolor = matched[1] == "true" + end + end # Evaluate the code block. We redirect stdout/stderr to `buffer`. result, buffer = nothing, IOBuffer() @@ -550,7 +560,7 @@ function Selectors.runner(::Type{ExampleBlocks}, x, page, doc) code = x.code end for (ex, str) in Utilities.parseblock(code, doc, page; keywords = false) - c = IOCapture.capture(rethrow = InterruptException) do + c = IOCapture.capture(rethrow = InterruptException, color = ansicolor) do cd(page.workdir) do Core.eval(mod, ex) end @@ -579,10 +589,10 @@ function Selectors.runner(::Type{ExampleBlocks}, x, page, doc) input = droplines(x.code) # Generate different in different formats and let each writer select - output = Base.invokelatest(Utilities.display_dict, result) + output = Base.invokelatest(Utilities.display_dict, result, context = :color => ansicolor) # Only add content when there's actually something to add. - isempty(input) || push!(content, Markdown.Code("julia", input)) + isempty(input) || push!(content, Markdown.Code("julia", input)) if result === nothing code = Documenter.DocTests.sanitise(buffer) isempty(code) || push!(content, Dict{MIME,Any}(MIME"text/plain"() => code)) @@ -597,10 +607,21 @@ end # ----- function Selectors.runner(::Type{REPLBlocks}, x, page, doc) - matched = match(r"^@repl[ ]?(.*)$", x.language) + matched = match(r"^@repl(?:\s+([^\s;]+))?\s*(;.*)?$", x.language) matched === nothing && error("invalid '@repl' syntax: $(x.language)") - name = matched[1] + name, kwargs = matched.captures + # The sandboxed module -- either a new one or a cached one from this page. mod = Utilities.get_sandbox_module!(page.globals.meta, "atexample", name) + + # "parse" keyword arguments to repl + ansicolor = get(stdout, :color, false)::Bool + if kwargs !== nothing + matched = match(r"\bansicolor\s*=\s*(true|false)\b", kwargs) + if matched !== nothing + ansicolor = matched[1] == "true" + end + end + code = split(x.code, '\n'; limit = 2)[end] result, out = nothing, IOBuffer() for (ex, str) in Utilities.parseblock(x.code, doc, page; keywords = false) @@ -611,7 +632,7 @@ function Selectors.runner(::Type{REPLBlocks}, x, page, doc) # see https://github.com/JuliaLang/julia/pull/33864 ex = REPL.softscope!(ex) end - c = IOCapture.capture(rethrow = InterruptException) do + c = IOCapture.capture(rethrow = InterruptException, color = ansicolor) do cd(page.workdir) do Core.eval(mod, ex) end @@ -639,10 +660,10 @@ end # ------ function Selectors.runner(::Type{SetupBlocks}, x, page, doc) - matched = match(r"^@setup[ ](.+)$", x.language) + matched = match(r"^@setup(?:\s+([^\s;]+))?\s*$", x.language) matched === nothing && error("invalid '@setup ' syntax: $(x.language)") - # The sandboxed module -- either a new one or a cached one from this page. name = matched[1] + # The sandboxed module -- either a new one or a cached one from this page. mod = Utilities.get_sandbox_module!(page.globals.meta, "atexample", name) # Evaluate whole @setup block at once instead of piecewise diff --git a/src/Utilities/Utilities.jl b/src/Utilities/Utilities.jl index 0a905ba6474..b8b07b04169 100644 --- a/src/Utilities/Utilities.jl +++ b/src/Utilities/Utilities.jl @@ -611,20 +611,21 @@ function mdparse(s::AbstractString; mode=:single) end # Capturing output in different representations similar to IJulia.jl -function limitstringmime(m::MIME"text/plain", x) +function limitstringmime(m::MIME"text/plain", x; context = nothing) io = IOBuffer() - show(IOContext(io, :limit=> true), m, x) + ioc = IOContext(context === nothing ? io : IOContext(io, context), :limit => true) + show(ioc, m, x) return String(take!(io)) end -function display_dict(x) +function display_dict(x; context = nothing) out = Dict{MIME,Any}() x === nothing && return out # Always generate text/plain - out[MIME"text/plain"()] = limitstringmime(MIME"text/plain"(), x) + out[MIME"text/plain"()] = limitstringmime(MIME"text/plain"(), x, context = context) for m in [MIME"text/html"(), MIME"image/svg+xml"(), MIME"image/png"(), MIME"image/webp"(), MIME"image/gif"(), MIME"image/jpeg"(), MIME"text/latex"(), MIME"text/markdown"()] - showable(m, x) && (out[m] = stringmime(m, x)) + showable(m, x) && (out[m] = stringmime(m, x, context = context)) end return out end @@ -661,8 +662,8 @@ function codelang(infostring::AbstractString) return m[1] end -function get_sandbox_module!(meta, prefix, name = "") - sym = if isempty(name) +function get_sandbox_module!(meta, prefix, name = nothing) + sym = if name === nothing || isempty(name) Symbol("__", prefix, "__", lstrip(string(gensym()), '#')) else Symbol("__", prefix, "__named__", name) diff --git a/src/Writers/HTMLWriter.jl b/src/Writers/HTMLWriter.jl index 4f52d9b6a8f..f720692f03e 100644 --- a/src/Writers/HTMLWriter.jl +++ b/src/Writers/HTMLWriter.jl @@ -58,6 +58,8 @@ using ...Utilities.JSDependencies: JSDependencies, json_jsescape import ...Utilities.DOM: DOM, Tag, @tags using ...Utilities.MDFlatten +import ANSIColoredPrinters + export HTML "Data attribute for the script inserting a wraning for outdated docs." @@ -493,6 +495,8 @@ module RD ["\$"], raw""" $(document).ready(function() { + hljs.configure({ignoreUnescapedHTML: true}); // for ANSI color support + /* TODO: add a plugin for unescaped HTML */ hljs.highlightAll(); }) """ @@ -1622,6 +1626,28 @@ function collect_subsections(page::Documents.Page) return sections end +function domify_ansicoloredtext(text::AbstractString, class = "") + @tags pre + stack = DOM.Node[pre()] # this `pre` is dummy + function cb(io::IO, printer, tag::String, attrs::Dict{Symbol, String}) + text = String(take!(io)) + children = stack[end].nodes + isempty(text) || push!(children, Tag(Symbol("#RAW#"))(text)) + if startswith(tag, "/") + pop!(stack) + else + parent = Tag(Symbol(tag))[attrs] + push!(children, parent) + push!(stack, parent) + end + return true + end + ansiclass = isempty(class) ? "ansi" : class * " ansi" + printer = ANSIColoredPrinters.HTMLPrinter(IOBuffer(text), callback = cb, + root_tag = "code", root_class = ansiclass) + show(IOBuffer(), MIME"text/html"(), printer) + return stack[1].nodes +end # mdconvert # ------------------------------------------------------------------------------ @@ -1660,7 +1686,11 @@ function mdconvert(c::Markdown.Code, parent::MDBlockContext; kwargs...) @tags pre code language = Utilities.codelang(c.language) class = isempty(language) ? "nohighlight" : "language-$(language)" - pre(code[".$class"](c.code)) + if language == "julia-repl" + return pre(domify_ansicoloredtext(c.code, class)) + else + return pre(code[".$class"](c.code)) + end end mdconvert(c::Markdown.Code, parent; kwargs...) = Tag(:code)(c.code) @@ -1855,7 +1885,8 @@ function mdconvert(d::Dict{MIME,Any}, parent; kwargs...) out = Markdown.parse(d[MIME"text/markdown"()]) elseif haskey(d, MIME"text/plain"()) @tags pre - return pre[".documenter-example-output"](d[MIME"text/plain"()]) + text = d[MIME"text/plain"()] + return pre[".documenter-example-output"](domify_ansicoloredtext(text, "nohighlight")) else error("this should never happen.") end diff --git a/src/Writers/LaTeXWriter.jl b/src/Writers/LaTeXWriter.jl index 03fe3d495e5..55b516728c8 100644 --- a/src/Writers/LaTeXWriter.jl +++ b/src/Writers/LaTeXWriter.jl @@ -59,6 +59,8 @@ import ...Documenter: import Markdown +import ANSIColoredPrinters + mutable struct Context{I <: IO} <: IO io::I in_header::Bool @@ -400,7 +402,9 @@ function latex(io::IO, d::Dict{MIME,Any}) elseif haskey(d, MIME"text/markdown"()) latex(io, Markdown.parse(d[MIME"text/markdown"()])) elseif haskey(d, MIME"text/plain"()) - latex(io, Markdown.Code(d[MIME"text/plain"()])) + text = d[MIME"text/plain"()] + out = repr(MIME"text/plain"(), ANSIColoredPrinters.PlainTextPrinter(IOBuffer(text))) + latex(io, Markdown.Code(out)) else error("this should never happen.") end @@ -446,6 +450,8 @@ function latex(io::IO, code::Markdown.Code) language = isempty(language) ? "none" : (language == "julia-repl") ? "jlcon" : # the julia-repl is called "jlcon" in Pygments language + text = IOBuffer(code.code) + code.code = repr(MIME"text/plain"(), ANSIColoredPrinters.PlainTextPrinter(text)) escape = '⊻' ∈ code.code if language in LEXER _print(io, "\n\\begin{minted}") diff --git a/src/Writers/MarkdownWriter.jl b/src/Writers/MarkdownWriter.jl index ed6fa9ac5a5..69a90ba331a 100644 --- a/src/Writers/MarkdownWriter.jl +++ b/src/Writers/MarkdownWriter.jl @@ -11,6 +11,8 @@ import ...Documenter: Documenter, Utilities +import ANSIColoredPrinters + # import Markdown as MarkdownStdlib module _Markdown import Markdown @@ -181,7 +183,9 @@ function render(io::IO, mime::MIME"text/plain", d::Dict{MIME,Any}, page, doc) ![]($(filename).gif) """) elseif haskey(d, MIME"text/plain"()) - render(io, mime, MarkdownStdlib.Code(d[MIME"text/plain"()]), page, doc) + text = d[MIME"text/plain"()] + out = repr(MIME"text/plain"(), ANSIColoredPrinters.PlainTextPrinter(IOBuffer(text))) + render(io, mime, MarkdownStdlib.Code(out), page, doc) else error("this should never happen.") end