Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some small optimizations (helping type inference, avoid eager int to string conversion) #75

Merged
merged 3 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions src/faces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,12 +495,16 @@ later faces taking priority.
"""
function Base.merge(a::Face, b::Face)
if isempty(b.inherit)
# Extract the heights to help type inference a bit to be able
# to narrow the types in e.g. `aheight * bheight`
aheight = a.height
bheight = b.height
Face(ifelse(isnothing(b.font), a.font, b.font),
if isnothing(b.height) a.height
elseif isnothing(a.height) b.height
elseif b.height isa Int b.height
elseif a.height isa Int round(Int, a.height * b.height)
else a.height * b.height end,
if isnothing(bheight) aheight
elseif isnothing(aheight) bheight
elseif bheight isa Int bheight
elseif aheight isa Int round(Int, aheight * bheight)
else aheight * bheight end,
ifelse(isnothing(b.weight), a.weight, b.weight),
ifelse(isnothing(b.slant), a.slant, b.slant),
ifelse(isnothing(b.foreground), a.foreground, b.foreground),
Expand All @@ -523,6 +527,11 @@ Base.merge(a::Face, b::Face, others::Face...) = merge(merge(a, b), others...)

## Getting the combined face from a set of properties ##

# Putting these inside `getface` causes the julia compiler to box it
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't actually know why this happens, it's just that doing this change fixes the issue reported by @code_warntype... I'm kind of scared of closures for reasons like this :(

_mergedface(face::Face) = face
_mergedface(face::Symbol) = get(FACES.current[], face, Face())
_mergedface(faces::Vector) = mapfoldl(_mergedface, merge, Iterators.reverse(faces))

"""
getface(faces)

Expand All @@ -531,10 +540,7 @@ Obtain the final merged face from `faces`, an iterator of
"""
function getface(faces)
isempty(faces) && return FACES.current[][:default]
mergedface(face::Face) = face
mergedface(face::Symbol) = get(FACES.current[], face, Face())
mergedface(faces::Vector) = mapfoldl(mergedface, merge, Iterators.reverse(faces))
combined = mapfoldl(mergedface, merge, faces)::Face
combined = mapfoldl(_mergedface, merge, faces)::Face
if !isempty(combined.inherit)
combined = merge(Face(), combined)
end
Expand Down
30 changes: 16 additions & 14 deletions src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ const ANSI_4BIT_COLORS = Dict{Symbol, Int}(
"""
ansi_4bit_color_code(color::Symbol, background::Bool=false)

Provide the color code (30-37, 40-47, 90-97, 100-107) for `color`, as a string.
Provide the color code (30-37, 40-47, 90-97, 100-107) for `color`, as an integer.
When `background` is set the background variant will be provided, otherwise
the provided code is for setting the foreground color.
"""
function ansi_4bit_color_code(color::Symbol, background::Bool=false)
if haskey(ANSI_4BIT_COLORS, color)
code = ANSI_4BIT_COLORS[color]
code = get(ANSI_4BIT_COLORS, color, nothing)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern avoids doing the dict lookup twice.

if code !== nothing
code >= 8 && (code += 52)
background && (code += 10)
string(code + 30)
code + 30
else
ifelse(background, "49", "39")
ifelse(background, 49, 39)
end
end

Expand Down Expand Up @@ -123,15 +123,17 @@ function termcolor(io::IO, color::SimpleColor, category::Char)
elseif (fg = get(FACES.current[], color.value, getface()).foreground) != SimpleColor(color.value)
termcolor(io, fg, category)
else
print(io, "\e[",
if category == '3' || category == '4'
ansi_4bit_color_code(color.value, category == '4')
elseif category == '5'
if haskey(ANSI_4BIT_COLORS, color.value)
string("58;5;", ANSI_4BIT_COLORS[color.value])
else "59" end
end,
'm')
print(io, "\e[")
if category == '3' || category == '4'
print(io, ansi_4bit_color_code(color.value, category == '4'))
elseif category == '5'
if haskey(ANSI_4BIT_COLORS, color.value)
print(io, "58;5;", ANSI_4BIT_COLORS[color.value])
else
print(io, "59")
end
end
print(io, "m")
end
end

Expand Down
10 changes: 5 additions & 5 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,11 @@ end

@testset "ANSI encoding" begin
# 4-bit color
@test StyledStrings.ansi_4bit_color_code(:cyan, false) == "36"
@test StyledStrings.ansi_4bit_color_code(:cyan, true) == "46"
@test StyledStrings.ansi_4bit_color_code(:bright_cyan, false) == "96"
@test StyledStrings.ansi_4bit_color_code(:bright_cyan, true) == "106"
@test StyledStrings.ansi_4bit_color_code(:nonexistant) == "39"
@test StyledStrings.ansi_4bit_color_code(:cyan, false) == 36
@test StyledStrings.ansi_4bit_color_code(:cyan, true) == 46
@test StyledStrings.ansi_4bit_color_code(:bright_cyan, false) == 96
@test StyledStrings.ansi_4bit_color_code(:bright_cyan, true) == 106
@test StyledStrings.ansi_4bit_color_code(:nonexistant) == 39
# 8-bit color
@test sprint(StyledStrings.termcolor8bit, (r=0x40, g=0x63, b=0xd8), '3') == "\e[38;5;26m"
@test sprint(StyledStrings.termcolor8bit, (r=0x38, g=0x98, b=0x26), '3') == "\e[38;5;28m"
Expand Down
Loading