Skip to content

Commit cfcfe8c

Browse files
committed
Fix syntax of generated CSS
Quoting and consistent semicolon separation weren't quite right, but should be now.
1 parent c82409c commit cfcfe8c

File tree

2 files changed

+55
-46
lines changed

2 files changed

+55
-46
lines changed

src/io.jl

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -361,17 +361,26 @@ const HTML_WEIGHT_MAP = Dict{Symbol, Int}(
361361
:extrabold => 800,
362362
:black => 900)
363363

364-
function htmlstyle(io::IO, face::Face, lastface::Face=getface())
365-
print(io, "<span style=\"")
364+
function cssattrs(io::IO, face::Face, lastface::Face=getface(), escapequotes::Bool=true)
365+
priorattr = false
366+
function printattr(io, attr, valparts...)
367+
if priorattr
368+
print(io, "; ")
369+
else
370+
priorattr = true
371+
end
372+
print(io, attr, ": ", valparts...)
373+
end
366374
face.font == lastface.font ||
367-
print(io, "font-family: \"",
368-
replace(face.font, '"' => "&quot;", ''' => "&#39;"), '"')
375+
printattr(io, "font-family", ifelse(escapequotes, "&quot;", "\""),
376+
replace(face.font, '"' => "\\&quot;", ''' => "&#39;"),
377+
ifelse(escapequotes, "&quot;", "\""))
369378
face.height == lastface.height ||
370-
print(io, "font-size: ", string(face.height ÷ 10), "pt;")
379+
printattr(io, "font-size", string(face.height ÷ 10), "pt")
371380
face.weight == lastface.weight ||
372-
print(io, "font-weight: ", get(HTML_WEIGHT_MAP, face.weight, 400), ';')
381+
printattr(io, "font-weight", get(HTML_WEIGHT_MAP, face.weight, 400))
373382
face.slant == lastface.slant ||
374-
print(io, "font-style: ", String(face.slant), ';')
383+
printattr(io, "font-style", String(face.slant))
375384
foreground, background =
376385
ifelse(face.inverse === true,
377386
(face.background, face.foreground),
@@ -381,19 +390,17 @@ function htmlstyle(io::IO, face::Face, lastface::Face=getface())
381390
(lastface.background, lastface.foreground),
382391
(lastface.foreground, lastface.background))
383392
if foreground != lastforeground
384-
print(io, "color: ")
393+
printattr(io, "color")
385394
htmlcolor(io, foreground)
386-
print(io, ';')
387395
end
388396
if background != lastbackground
389-
print(io, "background-color: ")
397+
printattr(io, "background-color")
390398
htmlcolor(io, background)
391-
print(io, ';')
392399
end
393400
face.underline == lastface.underline ||
394401
if face.underline isa Tuple # Color and style
395402
color, style = face.underline
396-
print(io, "text-decoration: ")
403+
printattr(io, "text-decoration")
397404
if !isnothing(color)
398405
htmlcolor(io, color)
399406
print(io, ' ')
@@ -403,17 +410,16 @@ function htmlstyle(io::IO, face::Face, lastface::Face=getface())
403410
elseif style == :curly "wavy "
404411
elseif style == :dotted "dotted "
405412
elseif style == :dashed "dashed "
406-
else "" end)
407-
print(io, "underline;")
413+
else "" end, "underline")
408414
elseif face.underline isa SimpleColor
409-
print(io, "text-decoration: ")
415+
printattr(io, "text-decoration")
410416
htmlcolor(io, face.underline)
411417
if lastface.underline isa Tuple && last(lastface.underline) != :straight
412418
print(io, " solid")
413419
end
414-
print(io, " underline;")
420+
print(io, " underline")
415421
else # must be a Bool
416-
print(io, "text-decoration: ")
422+
printattr(io, "text-decoration")
417423
if lastface.underline isa SimpleColor
418424
print(io, "currentcolor ")
419425
elseif lastface.underline isa Tuple
@@ -422,13 +428,16 @@ function htmlstyle(io::IO, face::Face, lastface::Face=getface())
422428
last(lastface.underline) != :straight &&
423429
print(io, "straight ")
424430
end
425-
print(io, ifelse(face.underline, "underline;", "none;"))
431+
print(io, ifelse(face.underline, "underline", "none"))
426432
end
427433
face.strikethrough == lastface.strikethrough ||
428-
print(io, ifelse(face.strikethrough,
429-
"text-decoration: line-through",
430-
ifelse(face.underline === false,
431-
"text-decoration: none", "")))
434+
!face.strikethrough && face.underline !== false ||
435+
printattr(io, "text-decoration", ifelse(face.strikethrough, "line-through", "none"))
436+
end
437+
438+
function htmlstyle(io::IO, face::Face, lastface::Face=getface())
439+
print(io, "<span style=\"")
440+
cssattrs(io, face, lastface, true)
432441
print(io, "\">")
433442
end
434443

test/runtests.jl

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -609,39 +609,39 @@ end
609609
face = getface(Face(; attrs...))
610610
sprint(StyledStrings.htmlstyle, face)
611611
end
612-
@test html_change(foreground=:cyan) == "<span style=\"color: #0097a7;\">"
613-
@test html_change(background=:cyan) == "<span style=\"background-color: #0097a7;\">"
614-
@test html_change(weight=:bold) == "<span style=\"font-weight: 700;\">"
615-
@test html_change(weight=:extrabold) == "<span style=\"font-weight: 800;\">"
616-
@test html_change(weight=:light) == "<span style=\"font-weight: 300;\">"
612+
@test html_change(foreground=:cyan) == "<span style=\"color: #0097a7\">"
613+
@test html_change(background=:cyan) == "<span style=\"background-color: #0097a7\">"
614+
@test html_change(weight=:bold) == "<span style=\"font-weight: 700\">"
615+
@test html_change(weight=:extrabold) == "<span style=\"font-weight: 800\">"
616+
@test html_change(weight=:light) == "<span style=\"font-weight: 300\">"
617617
@test html_change(foreground=:blue, background=:red, inverse=true) ==
618-
"<span style=\"color: #a51c2c;background-color: #195eb3;\">"
619-
@test html_change(slant=:italic) == "<span style=\"font-style: italic;\">"
620-
@test html_change(height=180) == "<span style=\"font-size: 18pt;\">"
621-
@test html_change(underline=true) == "<span style=\"text-decoration: underline;\">"
622-
@test html_change(underline=:green) == "<span style=\"text-decoration: #25a268 underline;\">"
623-
@test html_change(underline=:straight) == "<span style=\"text-decoration: solid underline;\">"
624-
@test html_change(underline=:double) == "<span style=\"text-decoration: double underline;\">"
625-
@test html_change(underline=:curly) == "<span style=\"text-decoration: wavy underline;\">"
626-
@test html_change(underline=:dotted) == "<span style=\"text-decoration: dotted underline;\">"
627-
@test html_change(underline=:dashed) == "<span style=\"text-decoration: dashed underline;\">"
628-
@test html_change(underline=(:cyan, :double)) == "<span style=\"text-decoration: #0097a7 double underline;\">"
618+
"<span style=\"color: #a51c2c; background-color: #195eb3\">"
619+
@test html_change(slant=:italic) == "<span style=\"font-style: italic\">"
620+
@test html_change(height=180) == "<span style=\"font-size: 18pt\">"
621+
@test html_change(underline=true) == "<span style=\"text-decoration: underline\">"
622+
@test html_change(underline=:green) == "<span style=\"text-decoration: #25a268 underline\">"
623+
@test html_change(underline=:straight) == "<span style=\"text-decoration: solid underline\">"
624+
@test html_change(underline=:double) == "<span style=\"text-decoration: double underline\">"
625+
@test html_change(underline=:curly) == "<span style=\"text-decoration: wavy underline\">"
626+
@test html_change(underline=:dotted) == "<span style=\"text-decoration: dotted underline\">"
627+
@test html_change(underline=:dashed) == "<span style=\"text-decoration: dashed underline\">"
628+
@test html_change(underline=(:cyan, :double)) == "<span style=\"text-decoration: #0097a7 double underline\">"
629629
@test html_change(strikethrough=true) == "<span style=\"text-decoration: line-through\">"
630630
# Might as well put everything together for a final test
631631
fancy_string = styled"The {magenta:`{green:StyledStrings}`} package {italic:builds}\
632632
{bold: on top} of the {magenta:`{green:AnnotatedString}`} {link={https://en.wikipedia.org/wiki/Type_system}:type} \
633633
to provide a {(underline=(red,curly)):full-fledged} textual {(bg=#4063d8,fg=#adbdf8,inherit=[bold,strikethrough]):styling} \
634634
system, suitable for {inverse:terminal} and graphical displays."
635635
@test sprint(show, MIME("text/html"), fancy_string[1:27]) ==
636-
"The <span style=\"color: #803d9b;\">`</span><span style=\"color: #25a268;\">StyledStrings</span>\
637-
<span style=\"color: #803d9b;\">`</span> package"
636+
"The <span style=\"color: #803d9b\">`</span><span style=\"color: #25a268\">StyledStrings</span>\
637+
<span style=\"color: #803d9b\">`</span> package"
638638
@test sprint(show, MIME("text/html"), fancy_string) ==
639-
"The <span style=\"color: #803d9b;\">`</span><span style=\"color: #25a268;\">StyledStrings</span><span style=\"color: #803d9b;\">\
640-
`</span> package <span style=\"font-style: italic;\">builds<span style=\"font-weight: 700;font-style: normal;\"> on top</span></span> \
641-
of the <span style=\"color: #803d9b;\">`</span><span style=\"color: #25a268;\">AnnotatedString</span><span style=\"color: #803d9b;\">\
642-
`</span> <a href=\"https://en.wikipedia.org/wiki/Type_system\">type</a> to provide a <span style=\"text-decoration: #a51c2c wavy underline;\">\
643-
full-fledged</span> textual <span style=\"font-weight: 700;color: #adbdf8;background-color: #4063d8;text-decoration: line-through\">styling</span> \
644-
system, suitable for <span style=\"\">terminal</span> and graphical displays."
639+
"The <span style=\"color: #803d9b\">`</span><span style=\"color: #25a268\">StyledStrings</span><span style=\"color: #803d9b\">`</span> \
640+
package <span style=\"font-style: italic\">builds<span style=\"font-weight: 700; font-style: normal\"> on top</span></span> of the \
641+
<span style=\"color: #803d9b\">`</span><span style=\"color: #25a268\">AnnotatedString</span><span style=\"color: #803d9b\">`</span> \
642+
<a href=\"https://en.wikipedia.org/wiki/Type_system\">type</a> to provide a <span style=\"text-decoration: #a51c2c wavy underline\">\
643+
full-fledged</span> textual <span style=\"font-weight: 700; color: #adbdf8; background-color: #4063d8; text-decoration: line-through\">\
644+
styling</span> system, suitable for <span style=\"\">terminal</span> and graphical displays."
645645
end
646646

647647
@testset "Legacy" begin

0 commit comments

Comments
 (0)