@@ -95,9 +95,6 @@ impl Term {
9595 use std:: fmt:: Write as _;
9696 use unicode_width:: UnicodeWidthStr as _;
9797
98- const FG : & str = "fg" ;
99- const BG : & str = "bg" ;
100-
10198 let mut styled = adapter:: AnsiBytes :: new ( ) ;
10299 let mut elements = styled. extract_next ( ansi. as_bytes ( ) ) . collect :: < Vec < _ > > ( ) ;
103100 preprocess_invert_style ( & mut elements, self . bg_color , self . fg_color ) ;
@@ -108,8 +105,7 @@ impl Term {
108105 let bg_color = rgb_value ( self . bg_color , self . palette ) ;
109106 let font_family = self . font_family ;
110107
111- let line_height = 18 ;
112- let height = styled_lines. len ( ) * line_height + self . padding_px * 2 ;
108+ let height = styled_lines. len ( ) * LINE_HEIGHT + self . padding_px * 2 ;
113109 let max_width = styled_lines
114110 . iter ( )
115111 . map ( |l| l. iter ( ) . map ( |e| e. text . width ( ) ) . sum ( ) )
@@ -148,13 +144,13 @@ impl Term {
148144 }
149145 writeln ! ( & mut buffer, r#" .container {{"# ) . unwrap ( ) ;
150146 writeln ! ( & mut buffer, r#" padding: 0 10px;"# ) . unwrap ( ) ;
151- writeln ! ( & mut buffer, r#" line-height: {line_height }px;"# ) . unwrap ( ) ;
147+ writeln ! ( & mut buffer, r#" line-height: {LINE_HEIGHT }px;"# ) . unwrap ( ) ;
152148 writeln ! ( & mut buffer, r#" }}"# ) . unwrap ( ) ;
153149 write_effects_in_use ( & mut buffer, & elements) ;
154150 writeln ! ( & mut buffer, r#" tspan {{"# ) . unwrap ( ) ;
155151 writeln ! ( & mut buffer, r#" font: 14px {font_family};"# ) . unwrap ( ) ;
156152 writeln ! ( & mut buffer, r#" white-space: pre;"# ) . unwrap ( ) ;
157- writeln ! ( & mut buffer, r#" line-height: {line_height }px;"# ) . unwrap ( ) ;
153+ writeln ! ( & mut buffer, r#" line-height: {LINE_HEIGHT }px;"# ) . unwrap ( ) ;
158154 writeln ! ( & mut buffer, r#" }}"# ) . unwrap ( ) ;
159155 writeln ! ( & mut buffer, r#" </style>"# ) . unwrap ( ) ;
160156 writeln ! ( & mut buffer) . unwrap ( ) ;
@@ -169,7 +165,7 @@ impl Term {
169165 }
170166
171167 let text_x = self . padding_px ;
172- let mut text_y = self . padding_px + line_height ;
168+ let mut text_y = self . padding_px + LINE_HEIGHT ;
173169 writeln ! (
174170 & mut buffer,
175171 r#" <text xml:space="preserve" class="container {FG}">"#
@@ -200,7 +196,7 @@ impl Term {
200196 writeln ! ( & mut buffer) . unwrap ( ) ;
201197 writeln ! ( & mut buffer, r#"</tspan>"# ) . unwrap ( ) ;
202198
203- text_y += line_height ;
199+ text_y += LINE_HEIGHT ;
204200 }
205201 writeln ! ( & mut buffer, r#" </text>"# ) . unwrap ( ) ;
206202 writeln ! ( & mut buffer) . unwrap ( ) ;
@@ -216,21 +212,12 @@ impl Term {
216212 pub fn render_html ( & self , ansi : & str ) -> String {
217213 use std:: fmt:: Write as _;
218214
219- const FG : & str = "fg" ;
220- const BG : & str = "bg" ;
221-
222215 let mut styled = adapter:: AnsiBytes :: new ( ) ;
223216 let mut elements = styled. extract_next ( ansi. as_bytes ( ) ) . collect :: < Vec < _ > > ( ) ;
224217 preprocess_invert_style ( & mut elements, self . bg_color , self . fg_color ) ;
225218
226219 let styled_lines = split_lines ( & elements) ;
227220
228- let fg_color = rgb_value ( self . fg_color , self . palette ) ;
229- let bg_color = rgb_value ( self . bg_color , self . palette ) ;
230- let font_family = self . font_family ;
231-
232- let line_height = 18 ;
233-
234221 let mut buffer = String :: new ( ) ;
235222 writeln ! ( & mut buffer, r#"<!DOCTYPE html>"# ) . unwrap ( ) ;
236223 writeln ! ( & mut buffer, r#"<html>"# ) . unwrap ( ) ;
@@ -247,73 +234,123 @@ impl Term {
247234 )
248235 . unwrap ( ) ;
249236 writeln ! ( & mut buffer, r#" <style>"# ) . unwrap ( ) ;
250- writeln ! ( & mut buffer, r#" .{FG} {{ color: {fg_color} }}"# ) . unwrap ( ) ;
251- writeln ! ( & mut buffer, r#" .{BG} {{ background: {bg_color} }}"# ) . unwrap ( ) ;
252- for ( name, rgb) in color_styles ( & elements, self . palette ) {
237+ self . render_classes ( & mut buffer, & elements) ;
238+ writeln ! ( & mut buffer, r#" </style>"# ) . unwrap ( ) ;
239+ writeln ! ( & mut buffer, r#"</head>"# ) . unwrap ( ) ;
240+ writeln ! ( & mut buffer) . unwrap ( ) ;
241+
242+ if !self . background {
243+ writeln ! ( & mut buffer, r#"<body>"# ) . unwrap ( ) ;
244+ } else {
245+ writeln ! ( & mut buffer, r#"<body class="{BG}">"# ) . unwrap ( ) ;
246+ }
247+ writeln ! ( & mut buffer) . unwrap ( ) ;
248+
249+ self . render_content ( & mut buffer, styled_lines) ;
250+ writeln ! ( & mut buffer) . unwrap ( ) ;
251+
252+ writeln ! ( & mut buffer, r#"</body>"# ) . unwrap ( ) ;
253+ writeln ! ( & mut buffer, r#"</html>"# ) . unwrap ( ) ;
254+ buffer
255+ }
256+
257+ fn render_classes ( & self , buffer : & mut String , elements : & [ adapter:: Element ] ) {
258+ use std:: fmt:: Write as _;
259+
260+ let fg_color = rgb_value ( self . fg_color , self . palette ) ;
261+ let bg_color = rgb_value ( self . bg_color , self . palette ) ;
262+ let font_family = self . font_family ;
263+
264+ writeln ! ( buffer, r#" .{FG} {{ color: {fg_color} }}"# ) . unwrap ( ) ;
265+ writeln ! ( buffer, r#" .{BG} {{ background: {bg_color} }}"# ) . unwrap ( ) ;
266+ for ( name, rgb) in color_styles ( elements, self . palette ) {
253267 if name. starts_with ( FG_PREFIX ) {
254- writeln ! ( & mut buffer, r#" .{name} {{ color: {rgb} }}"# ) . unwrap ( ) ;
268+ writeln ! ( buffer, r#" .{name} {{ color: {rgb} }}"# ) . unwrap ( ) ;
255269 }
256270 if name. starts_with ( BG_PREFIX ) {
257271 writeln ! (
258- & mut buffer,
272+ buffer,
259273 r#" .{name} {{ background: {rgb}; user-select: none; }}"#
260274 )
261275 . unwrap ( ) ;
262276 }
263277 if name. starts_with ( UNDERLINE_PREFIX ) {
264278 writeln ! (
265- & mut buffer,
279+ buffer,
266280 r#" .{name} {{ text-decoration-line: underline; text-decoration-color: {rgb} }}"#
267281 )
268282 . unwrap ( ) ;
269283 }
270284 }
271- writeln ! ( & mut buffer, r#" .container {{"# ) . unwrap ( ) ;
272- writeln ! ( & mut buffer, r#" line-height: {line_height}px;"# ) . unwrap ( ) ;
273- writeln ! ( & mut buffer, r#" }}"# ) . unwrap ( ) ;
274- write_effects_in_use ( & mut buffer, & elements) ;
275- writeln ! ( & mut buffer, r#" span {{"# ) . unwrap ( ) ;
276- writeln ! ( & mut buffer, r#" font: 14px {font_family};"# ) . unwrap ( ) ;
277- writeln ! ( & mut buffer, r#" white-space: pre;"# ) . unwrap ( ) ;
278- writeln ! ( & mut buffer, r#" line-height: {line_height}px;"# ) . unwrap ( ) ;
279- writeln ! ( & mut buffer, r#" }}"# ) . unwrap ( ) ;
280- writeln ! ( & mut buffer, r#" </style>"# ) . unwrap ( ) ;
281- writeln ! ( & mut buffer, r#"</head>"# ) . unwrap ( ) ;
282- writeln ! ( & mut buffer) . unwrap ( ) ;
283-
284- if !self . background {
285- writeln ! ( & mut buffer, r#"<body>"# ) . unwrap ( ) ;
286- } else {
287- writeln ! ( & mut buffer, r#"<body class="{BG}">"# ) . unwrap ( ) ;
288- }
289- writeln ! ( & mut buffer) . unwrap ( ) ;
285+ writeln ! ( buffer, r#" .container {{"# ) . unwrap ( ) ;
286+ writeln ! ( buffer, r#" line-height: {LINE_HEIGHT}px;"# ) . unwrap ( ) ;
287+ writeln ! ( buffer, r#" }}"# ) . unwrap ( ) ;
288+ write_effects_in_use ( buffer, elements) ;
289+ writeln ! ( buffer, r#" span {{"# ) . unwrap ( ) ;
290+ writeln ! ( buffer, r#" font: 14px {font_family};"# ) . unwrap ( ) ;
291+ writeln ! ( buffer, r#" white-space: pre;"# ) . unwrap ( ) ;
292+ writeln ! ( buffer, r#" line-height: {LINE_HEIGHT}px;"# ) . unwrap ( ) ;
293+ writeln ! ( buffer, r#" }}"# ) . unwrap ( ) ;
294+ }
295+
296+ fn render_content ( & self , buffer : & mut String , styled_lines : Vec < Vec < adapter:: Element > > ) {
297+ use std:: fmt:: Write as _;
290298
291- writeln ! ( & mut buffer, r#" <div class="container {FG}">"# ) . unwrap ( ) ;
299+ writeln ! ( buffer, r#" <div class="container {FG}">"# ) . unwrap ( ) ;
292300 for line in & styled_lines {
293301 if line. iter ( ) . any ( |e| e. style . get_bg_color ( ) . is_some ( ) ) {
294302 for element in line {
295303 if element. text . is_empty ( ) {
296304 continue ;
297305 }
298- write_bg_span ( & mut buffer, "span" , & element. style , & element. text ) ;
306+ write_bg_span ( buffer, "span" , & element. style , & element. text ) ;
299307 }
300- writeln ! ( & mut buffer, r#"<br />"# ) . unwrap ( ) ;
308+ writeln ! ( buffer, r#"<br />"# ) . unwrap ( ) ;
301309 }
302310
303311 for element in line {
304312 if element. text . is_empty ( ) {
305313 continue ;
306314 }
307- write_fg_span ( & mut buffer, "span" , element, & element. text ) ;
315+ write_fg_span ( buffer, "span" , element, & element. text ) ;
308316 }
309- writeln ! ( & mut buffer, r#"<br />"# ) . unwrap ( ) ;
317+ writeln ! ( buffer, r#"<br />"# ) . unwrap ( ) ;
310318 }
311- writeln ! ( & mut buffer, r#" </div>"# ) . unwrap ( ) ;
312- writeln ! ( & mut buffer ) . unwrap ( ) ;
319+ writeln ! ( buffer, r#" </div>"# ) . unwrap ( ) ;
320+ }
313321
314- writeln ! ( & mut buffer, r#"</body>"# ) . unwrap ( ) ;
315- writeln ! ( & mut buffer, r#"</html>"# ) . unwrap ( ) ;
316- buffer
322+ /// Returns the various parts needed to create an HTML page.
323+ pub fn render_html_fragments ( & self , ansi : & str ) -> HtmlFragments {
324+ let mut styled = adapter:: AnsiBytes :: new ( ) ;
325+ let mut elements = styled. extract_next ( ansi. as_bytes ( ) ) . collect :: < Vec < _ > > ( ) ;
326+ preprocess_invert_style ( & mut elements, self . bg_color , self . fg_color ) ;
327+
328+ let styled_lines = split_lines ( & elements) ;
329+
330+ let mut style = String :: new ( ) ;
331+ let mut body = String :: new ( ) ;
332+
333+ self . render_classes ( & mut style, & elements) ;
334+ self . render_content ( & mut body, styled_lines) ;
335+ HtmlFragments { style, body }
336+ }
337+ }
338+
339+ /// Contains the different parts of a HTML rendered page.
340+ pub struct HtmlFragments {
341+ style : String ,
342+ body : String ,
343+ }
344+
345+ impl HtmlFragments {
346+ /// Content that can be used directly in a `<style>` tag.
347+ pub fn style ( & self ) -> & str {
348+ & self . style
349+ }
350+
351+ /// Content that can be put in the HTML body or any tag inside the `<body>`.
352+ pub fn body ( & self ) -> & str {
353+ & self . body
317354 }
318355}
319356
@@ -518,9 +555,12 @@ fn rgb_value(color: anstyle::Color, palette: Palette) -> String {
518555 format ! ( "#{r:02X}{g:02X}{b:02X}" )
519556}
520557
558+ const FG : & str = "fg" ;
559+ const BG : & str = "bg" ;
521560const FG_PREFIX : & str = "fg" ;
522561const BG_PREFIX : & str = "bg" ;
523562const UNDERLINE_PREFIX : & str = "underline" ;
563+ const LINE_HEIGHT : usize = 18 ;
524564
525565fn color_name ( prefix : & str , color : anstyle:: Color ) -> String {
526566 match color {
0 commit comments