@@ -1059,3 +1059,178 @@ function show(io::IO, c::StyledChar)
1059
1059
show (io, c. char)
1060
1060
end
1061
1061
end
1062
+
1063
+ """
1064
+ A mapping between ANSI named colors and 8-bit colors for use in HTML
1065
+ representations.
1066
+ """
1067
+ const HTML_BASIC_COLORS = Dict {Symbol, SimpleColor} (
1068
+ :black => SimpleColor (0x00 , 0x00 , 0x00 ),
1069
+ :red => SimpleColor (0x80 , 0x00 , 0x00 ),
1070
+ :green => SimpleColor (0x00 , 0x80 , 0x00 ),
1071
+ :yellow => SimpleColor (0x80 , 0x80 , 0x00 ),
1072
+ :blue => SimpleColor (0x00 , 0x00 , 0x80 ),
1073
+ :magenta => SimpleColor (0x80 , 0x00 , 0x80 ),
1074
+ :cyan => SimpleColor (0x00 , 0x80 , 0x80 ),
1075
+ :white => SimpleColor (0xc0 , 0xc0 , 0xc0 ),
1076
+ :bright_black => SimpleColor (0x80 , 0x80 , 0x80 ),
1077
+ :grey => SimpleColor (0x80 , 0x80 , 0x80 ),
1078
+ :gray => SimpleColor (0x80 , 0x80 , 0x80 ),
1079
+ :bright_red => SimpleColor (0xff , 0x00 , 0x00 ),
1080
+ :bright_green => SimpleColor (0x00 , 0xff , 0x00 ),
1081
+ :bright_yellow => SimpleColor (0xff , 0xff , 0x00 ),
1082
+ :bright_blue => SimpleColor (0x00 , 0x00 , 0xff ),
1083
+ :bright_magenta => SimpleColor (0xff , 0x00 , 0xff ),
1084
+ :bright_cyan => SimpleColor (0x00 , 0xff , 0xff ),
1085
+ :bright_white => SimpleColor (0xff , 0xff , 0xff ))
1086
+
1087
+ function htmlcolor (io:: IO , color:: SimpleColor )
1088
+ if color. value isa Symbol
1089
+ if color. value === :default
1090
+ print (io, " initial" )
1091
+ elseif (fg = get (FACES. current[], color. value, getface ()). foreground) != SimpleColor (color. value)
1092
+ htmlcolor (io, fg)
1093
+ else
1094
+ htmlcolor (io, get (HTML_BASIC_COLORS, color. value, SimpleColor (:default )))
1095
+ end
1096
+ else
1097
+ (; r, g, b) = color. value
1098
+ print (io, ' #' )
1099
+ r < 0x10 && print (io, ' 0' )
1100
+ print (io, string (r, base= 16 ))
1101
+ g < 0x10 && print (io, ' 0' )
1102
+ print (io, string (g, base= 16 ))
1103
+ b < 0x10 && print (io, ' 0' )
1104
+ print (io, string (b, base= 16 ))
1105
+ end
1106
+ end
1107
+
1108
+ const HTML_WEIGHT_MAP = Dict {Symbol, Int} (
1109
+ :thin => 100 ,
1110
+ :extralight => 200 ,
1111
+ :light => 300 ,
1112
+ :semilight => 300 ,
1113
+ :normal => 400 ,
1114
+ :medium => 500 ,
1115
+ :semibold => 600 ,
1116
+ :bold => 700 ,
1117
+ :extrabold => 800 ,
1118
+ :black => 900 )
1119
+
1120
+ function htmlstyle (io:: IO , face:: Face , lastface:: Face = getface ())
1121
+ print (io, " <span style=\" " )
1122
+ face. font == lastface. font ||
1123
+ print (io, " font-family: \" " ,
1124
+ replace (face. font, ' "' => " "" , ' '' => " '" ), ' "' )
1125
+ face. height == lastface. height ||
1126
+ print (io, " font-size: " , string (face. height ÷ 10 ), " pt;" )
1127
+ face. weight == lastface. weight ||
1128
+ print (io, " font-weight: " , get (HTML_WEIGHT_MAP, face. weight, 400 ), ' ;' )
1129
+ face. slant == lastface. slant ||
1130
+ print (io, " font-style: " , String (face. slant), ' ;' )
1131
+ foreground, background =
1132
+ ifelse (face. inverse === true ,
1133
+ (face. background, face. foreground),
1134
+ (face. foreground, face. background))
1135
+ lastforeground, lastbackground =
1136
+ ifelse (lastface. inverse === true ,
1137
+ (lastface. background, lastface. foreground),
1138
+ (lastface. foreground, lastface. background))
1139
+ if foreground != lastforeground
1140
+ print (io, " color: " )
1141
+ htmlcolor (io, foreground)
1142
+ print (io, ' ;' )
1143
+ end
1144
+ if background != lastbackground
1145
+ print (io, " background-color: " )
1146
+ htmlcolor (io, background)
1147
+ print (io, ' ;' )
1148
+ end
1149
+ face. underline == lastface. underline ||
1150
+ if face. underline isa Tuple # Color and style
1151
+ color, style = face. underline
1152
+ print (io, " text-decoration: " )
1153
+ if ! isnothing (color)
1154
+ htmlcolor (io, color)
1155
+ print (io, ' ' )
1156
+ end
1157
+ print (io, if style == :straight " solid "
1158
+ elseif style == :double " double "
1159
+ elseif style == :curly " wavy "
1160
+ elseif style == :dotted " dotted "
1161
+ elseif style == :dashed " dashed "
1162
+ else " " end )
1163
+ print (io, " underline;" )
1164
+ elseif face. underline isa SimpleColor
1165
+ print (io, " text-decoration: " )
1166
+ htmlcolor (io, face. underline)
1167
+ if lastface. underline isa Tuple && last (lastface. underline) != :straight
1168
+ print (io, " solid" )
1169
+ end
1170
+ print (io, " underline;" )
1171
+ else # must be a Bool
1172
+ print (io, " text-decoration: " )
1173
+ if lastface. underline isa SimpleColor
1174
+ print (io, " currentcolor " )
1175
+ elseif lastface. underline isa Tuple
1176
+ first (lastface. underline) isa SimpleColor &&
1177
+ print (io, " currentcolor " )
1178
+ last (lastface. underline) != :straight &&
1179
+ print (io, " straight " )
1180
+ end
1181
+ print (io, ifelse (face. underline, " underline;" , " none;" ))
1182
+ end
1183
+ face. strikethrough == lastface. strikethrough ||
1184
+ print (io, ifelse (face. strikethrough,
1185
+ " text-decoration: line-through" ,
1186
+ ifelse (face. underline === false ,
1187
+ " text-decoration: none" , " " )))
1188
+ print (io, " \" >" )
1189
+ end
1190
+
1191
+ function show (io:: IO , :: MIME"text/html" , s:: Union{<:StyledString, SubString{<:StyledString}} ; wrap:: Symbol = :pre )
1192
+ htmlescape (str) = replace (str, ' &' => " &" , ' <' => " <" , ' >' => " >" )
1193
+ buf = IOBuffer () # Avoid potential overhead in repeatadly printing a more complex IO
1194
+ wrap == :none ||
1195
+ print (buf, ' <' , String (wrap), ' >' )
1196
+ lastface:: Face = getface ()
1197
+ stylestackdepth = 0
1198
+ for (str, styles) in eachstyle (s)
1199
+ face = getface (styles)
1200
+ link = let idx= findfirst (== (:link ) ∘ first, styles)
1201
+ if ! isnothing (idx)
1202
+ string (last (styles[idx])):: String
1203
+ end end
1204
+ ! isnothing (link) && print (buf, " <a href=\" " , link, " \" >" )
1205
+ if face == getface ()
1206
+ print (buf, " </span>" ^ stylestackdepth)
1207
+ stylestackdepth = 0
1208
+ elseif (lastface. inverse, lastface. foreground, lastface. background) !=
1209
+ (face. inverse, face. foreground, face. background)
1210
+ # We can't un-inherit colors well, so we just need to reset and apply
1211
+ print (buf, " </span>" ^ stylestackdepth)
1212
+ htmlstyle (buf, face, getface ())
1213
+ stylestackdepth = 1
1214
+ else
1215
+ htmlstyle (buf, face, lastface)
1216
+ stylestackdepth += 1
1217
+ end
1218
+ if wrap == :p
1219
+ newpara = false
1220
+ for para in eachsplit (str, " \n\n " )
1221
+ newpara && print (buf, " </p>\n <p>" )
1222
+ print (buf, htmlescape (para))
1223
+ newpara = true
1224
+ end
1225
+ else
1226
+ print (buf, htmlescape (str))
1227
+ end
1228
+ ! isnothing (link) && print (buf, " </a>" )
1229
+ lastface = face
1230
+ end
1231
+ print (buf, " </span>" ^ stylestackdepth)
1232
+ wrap == :none ||
1233
+ print (buf, " </" , String (wrap), ' >' )
1234
+ write (io, take! (buf))
1235
+ nothing
1236
+ end
0 commit comments