Skip to content

Commit

Permalink
Support italic output in printstyled (#45164)
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikekre authored Feb 13, 2023
1 parent 8a927d1 commit 488ec2c
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 10 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------------------
Expand Down
27 changes: 19 additions & 8 deletions base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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));
Expand All @@ -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
Expand All @@ -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] : "") *
Expand All @@ -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')
Expand All @@ -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)
Expand Down
8 changes: 6 additions & 2 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down

0 comments on commit 488ec2c

Please sign in to comment.