diff --git a/NEWS.md b/NEWS.md index 5f4a9cbb543cb..33ab22f5ef07e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -34,6 +34,7 @@ New library features is now a no-op ([#47979]). It previously exposed unsafe behavior ([#47977]). * `binomial(x, k)` now supports non-integer `x` ([#48124]). * A `CartesianIndex` is now treated as a "scalar" for broadcasting ([#47044]). +* `printstyled` now supports italic output ([#45164]). Standard library changes ------------------------ diff --git a/base/util.jl b/base/util.jl index 939ed9ae72bbb..f150ec6cd41d0 100644 --- a/base/util.jl +++ b/base/util.jl @@ -22,6 +22,7 @@ const text_colors = Dict{Union{Symbol,Int},String}( :normal => "\033[0m", :default => "\033[39m", :bold => "\033[1m", + :italic => "\033[3m", :underline => "\033[4m", :blink => "\033[5m", :reverse => "\033[7m", @@ -35,6 +36,7 @@ end const disable_text_style = Dict{Symbol,String}( :bold => "\033[22m", + :italic => "\033[23m", :underline => "\033[24m", :blink => "\033[25m", :reverse => "\033[27m", @@ -47,7 +49,7 @@ const disable_text_style = Dict{Symbol,String}( # Create a docstring with an automatically generated list # of colors. let color_syms = collect(Iterators.filter(x -> !isa(x, Integer), keys(text_colors))), - formatting_syms = [:normal, :bold, :default] + formatting_syms = [:normal, :bold, :italic, :default] global const available_text_colors = cat( sort!(intersect(color_syms, formatting_syms), rev=true), sort!(setdiff( color_syms, formatting_syms)); @@ -69,7 +71,7 @@ Printing with the color `:nothing` will print the string without modifications. text_colors function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol}, io::IO, args...; - bold::Bool = false, underline::Bool = false, blink::Bool = false, + bold::Bool = false, italic::Bool = false, underline::Bool = false, blink::Bool = false, reverse::Bool = false, hidden::Bool = false) buf = IOBuffer() iscolor = get(io, :color, false)::Bool @@ -80,12 +82,14 @@ function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol} print(io, str) else bold && color === :bold && (color = :nothing) + italic && color === :italic && (color = :nothing) underline && color === :underline && (color = :nothing) blink && color === :blink && (color = :nothing) reverse && color === :reverse && (color = :nothing) hidden && color === :hidden && (color = :nothing) enable_ansi = get(text_colors, color, text_colors[:default]) * (bold ? text_colors[:bold] : "") * + (italic ? text_colors[:italic] : "") * (underline ? text_colors[:underline] : "") * (blink ? text_colors[:blink] : "") * (reverse ? text_colors[:reverse] : "") * @@ -96,6 +100,7 @@ function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol} (blink ? disable_text_style[:blink] : "") * (underline ? disable_text_style[:underline] : "") * (bold ? disable_text_style[:bold] : "") * + (italic ? disable_text_style[:italic] : "") * get(disable_text_style, color, text_colors[:default]) first = true for line in eachsplit(str, '\n') @@ -110,27 +115,33 @@ function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol} end """ - printstyled([io], xs...; bold::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Symbol,Int}=:normal) + printstyled([io], xs...; bold::Bool=false, italic::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Symbol,Int}=:normal) Print `xs` in a color specified as a symbol or integer, optionally in bold. Keyword `color` may take any of the values $(Base.available_text_colors_docstring) or an integer between 0 and 255 inclusive. Note that not all terminals support 256 colors. -Keywords `bold=true`, `underline=true`, `blink=true` are self-explanatory. +Keywords `bold=true`, `italic=true`, `underline=true`, `blink=true` are self-explanatory. Keyword `reverse=true` prints with foreground and background colors exchanged, and `hidden=true` should be invisible in the terminal but can still be copied. These properties can be used in any combination. See also [`print`](@ref), [`println`](@ref), [`show`](@ref). +!!! note + Not all terminals support italic output. Some terminals interpret italic as reverse or + blink. + !!! compat "Julia 1.7" Keywords except `color` and `bold` were added in Julia 1.7. +!!! compat "Julia 1.9" + Support for italic output was added in Julia 1.9. """ -@constprop :none printstyled(io::IO, msg...; bold::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) = - with_output_color(print, color, io, msg...; bold=bold, underline=underline, blink=blink, reverse=reverse, hidden=hidden) -@constprop :none printstyled(msg...; bold::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) = - printstyled(stdout, msg...; bold=bold, underline=underline, blink=blink, reverse=reverse, hidden=hidden, color=color) +@constprop :none printstyled(io::IO, msg...; bold::Bool=false, italic::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) = + with_output_color(print, color, io, msg...; bold=bold, italic=italic, underline=underline, blink=blink, reverse=reverse, hidden=hidden) +@constprop :none printstyled(msg...; bold::Bool=false, italic::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) = + printstyled(stdout, msg...; bold=bold, italic=italic, underline=underline, blink=blink, reverse=reverse, hidden=hidden, color=color) """ Base.julia_cmd(juliapath=joinpath(Sys.BINDIR, julia_exename()); cpu_target) diff --git a/test/misc.jl b/test/misc.jl index 7c9fa3c1fbc41..03a17c84c3c66 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -859,6 +859,10 @@ let buf = IOBuffer() printstyled(buf_color, "foo"; bold=true, color=:red) @test String(take!(buf)) == "\e[31m\e[1mfoo\e[22m\e[39m" + # Check that italic is turned off + printstyled(buf_color, "foo"; italic=true, color=:red) + @test String(take!(buf)) == "\e[31m\e[3mfoo\e[23m\e[39m" + # Check that underline is turned off printstyled(buf_color, "foo"; color = :red, underline = true) @test String(take!(buf)) == "\e[31m\e[4mfoo\e[24m\e[39m" @@ -876,8 +880,8 @@ let buf = IOBuffer() @test String(take!(buf)) == "\e[31m\e[8mfoo\e[28m\e[39m" # Check that all options can be turned on simultaneously - printstyled(buf_color, "foo"; color = :red, bold = true, underline = true, blink = true, reverse = true, hidden = true) - @test String(take!(buf)) == "\e[31m\e[1m\e[4m\e[5m\e[7m\e[8mfoo\e[28m\e[27m\e[25m\e[24m\e[22m\e[39m" + printstyled(buf_color, "foo"; color = :red, bold = true, italic = true, underline = true, blink = true, reverse = true, hidden = true) + @test String(take!(buf)) == "\e[31m\e[1m\e[3m\e[4m\e[5m\e[7m\e[8mfoo\e[28m\e[27m\e[25m\e[24m\e[22m\e[23m\e[39m" end abstract type DA_19281{T, N} <: AbstractArray{T, N} end