Skip to content

Commit 0d17a12

Browse files
committed
feat: Prepare HTML rendering
1 parent 94847b3 commit 0d17a12

1 file changed

Lines changed: 92 additions & 74 deletions

File tree

crates/anstyle-svg/src/lib.rs

Lines changed: 92 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,8 @@ impl Term {
9292

9393
let mut styled = adapter::AnsiBytes::new();
9494
let mut elements = styled.extract_next(ansi.as_bytes()).collect::<Vec<_>>();
95-
let mut effects_in_use = anstyle::Effects::new();
96-
for element in &mut elements {
97-
let style = &mut element.style;
98-
// Pre-process INVERT to make fg/bg calculations easier
99-
if style.get_effects().contains(anstyle::Effects::INVERT) {
100-
*style = style
101-
.fg_color(Some(style.get_bg_color().unwrap_or(self.bg_color)))
102-
.bg_color(Some(style.get_fg_color().unwrap_or(self.fg_color)))
103-
.effects(style.get_effects().remove(anstyle::Effects::INVERT));
104-
}
105-
effects_in_use |= style.get_effects();
106-
}
95+
preprocess_invert_style(&mut elements, self.bg_color, self.fg_color);
96+
10797
let styled_lines = split_lines(&elements);
10898

10999
let fg_color = rgb_value(self.fg_color, self.palette);
@@ -152,60 +142,7 @@ impl Term {
152142
writeln!(&mut buffer, r#" padding: 0 10px;"#).unwrap();
153143
writeln!(&mut buffer, r#" line-height: {line_height}px;"#).unwrap();
154144
writeln!(&mut buffer, r#" }}"#).unwrap();
155-
if effects_in_use.contains(anstyle::Effects::BOLD) {
156-
writeln!(&mut buffer, r#" .bold {{ font-weight: bold; }}"#).unwrap();
157-
}
158-
if effects_in_use.contains(anstyle::Effects::ITALIC) {
159-
writeln!(&mut buffer, r#" .italic {{ font-style: italic; }}"#).unwrap();
160-
}
161-
if effects_in_use.contains(anstyle::Effects::UNDERLINE) {
162-
writeln!(
163-
&mut buffer,
164-
r#" .underline {{ text-decoration-line: underline; }}"#
165-
)
166-
.unwrap();
167-
}
168-
if effects_in_use.contains(anstyle::Effects::DOUBLE_UNDERLINE) {
169-
writeln!(
170-
&mut buffer,
171-
r#" .double-underline {{ text-decoration-line: underline; text-decoration-style: double; }}"#
172-
)
173-
.unwrap();
174-
}
175-
if effects_in_use.contains(anstyle::Effects::CURLY_UNDERLINE) {
176-
writeln!(
177-
&mut buffer,
178-
r#" .curly-underline {{ text-decoration-line: underline; text-decoration-style: wavy; }}"#
179-
)
180-
.unwrap();
181-
}
182-
if effects_in_use.contains(anstyle::Effects::DOTTED_UNDERLINE) {
183-
writeln!(
184-
&mut buffer,
185-
r#" .dotted-underline {{ text-decoration-line: underline; text-decoration-style: dotted; }}"#
186-
)
187-
.unwrap();
188-
}
189-
if effects_in_use.contains(anstyle::Effects::DASHED_UNDERLINE) {
190-
writeln!(
191-
&mut buffer,
192-
r#" .dashed-underline {{ text-decoration-line: underline; text-decoration-style: dashed; }}"#
193-
)
194-
.unwrap();
195-
}
196-
if effects_in_use.contains(anstyle::Effects::STRIKETHROUGH) {
197-
writeln!(
198-
&mut buffer,
199-
r#" .strikethrough {{ text-decoration-line: line-through; }}"#
200-
)
201-
.unwrap();
202-
}
203-
if effects_in_use.contains(anstyle::Effects::DIMMED) {
204-
writeln!(&mut buffer, r#" .dimmed {{ opacity: 0.7; }}"#).unwrap();
205-
}
206-
if effects_in_use.contains(anstyle::Effects::HIDDEN) {
207-
writeln!(&mut buffer, r#" .hidden {{ opacity: 0; }}"#).unwrap();
208-
}
145+
write_effects_in_use(&mut buffer, &elements);
209146
writeln!(&mut buffer, r#" tspan {{"#).unwrap();
210147
writeln!(&mut buffer, r#" font: 14px {font_family};"#).unwrap();
211148
writeln!(&mut buffer, r#" white-space: pre;"#).unwrap();
@@ -237,7 +174,7 @@ impl Term {
237174
if element.text.is_empty() {
238175
continue;
239176
}
240-
write_bg_span(&mut buffer, &element.style, &element.text);
177+
write_bg_span(&mut buffer, "tspan", &element.style, &element.text);
241178
}
242179
// HACK: must close tspan on newline to include them in copy/paste
243180
writeln!(&mut buffer).unwrap();
@@ -249,7 +186,7 @@ impl Term {
249186
if element.text.is_empty() {
250187
continue;
251188
}
252-
write_fg_span(&mut buffer, element, &element.text);
189+
write_fg_span(&mut buffer, "tspan", element, &element.text);
253190
}
254191
// HACK: must close tspan on newline to include them in copy/paste
255192
writeln!(&mut buffer).unwrap();
@@ -268,7 +205,71 @@ impl Term {
268205
const FG_COLOR: anstyle::Color = anstyle::Color::Ansi(anstyle::AnsiColor::White);
269206
const BG_COLOR: anstyle::Color = anstyle::Color::Ansi(anstyle::AnsiColor::Black);
270207

271-
fn write_fg_span(buffer: &mut String, element: &adapter::Element, fragment: &str) {
208+
fn write_effects_in_use(buffer: &mut String, elements: &[adapter::Element]) {
209+
use std::fmt::Write as _;
210+
211+
let mut effects_in_use = anstyle::Effects::new();
212+
for element in elements {
213+
effects_in_use |= element.style.get_effects();
214+
}
215+
216+
if effects_in_use.contains(anstyle::Effects::BOLD) {
217+
writeln!(buffer, r#" .bold {{ font-weight: bold; }}"#).unwrap();
218+
}
219+
if effects_in_use.contains(anstyle::Effects::ITALIC) {
220+
writeln!(buffer, r#" .italic {{ font-style: italic; }}"#).unwrap();
221+
}
222+
if effects_in_use.contains(anstyle::Effects::UNDERLINE) {
223+
writeln!(
224+
buffer,
225+
r#" .underline {{ text-decoration-line: underline; }}"#
226+
)
227+
.unwrap();
228+
}
229+
if effects_in_use.contains(anstyle::Effects::DOUBLE_UNDERLINE) {
230+
writeln!(
231+
buffer,
232+
r#" .double-underline {{ text-decoration-line: underline; text-decoration-style: double; }}"#
233+
)
234+
.unwrap();
235+
}
236+
if effects_in_use.contains(anstyle::Effects::CURLY_UNDERLINE) {
237+
writeln!(
238+
buffer,
239+
r#" .curly-underline {{ text-decoration-line: underline; text-decoration-style: wavy; }}"#
240+
)
241+
.unwrap();
242+
}
243+
if effects_in_use.contains(anstyle::Effects::DOTTED_UNDERLINE) {
244+
writeln!(
245+
buffer,
246+
r#" .dotted-underline {{ text-decoration-line: underline; text-decoration-style: dotted; }}"#
247+
)
248+
.unwrap();
249+
}
250+
if effects_in_use.contains(anstyle::Effects::DASHED_UNDERLINE) {
251+
writeln!(
252+
buffer,
253+
r#" .dashed-underline {{ text-decoration-line: underline; text-decoration-style: dashed; }}"#
254+
)
255+
.unwrap();
256+
}
257+
if effects_in_use.contains(anstyle::Effects::STRIKETHROUGH) {
258+
writeln!(
259+
buffer,
260+
r#" .strikethrough {{ text-decoration-line: line-through; }}"#
261+
)
262+
.unwrap();
263+
}
264+
if effects_in_use.contains(anstyle::Effects::DIMMED) {
265+
writeln!(buffer, r#" .dimmed {{ opacity: 0.7; }}"#).unwrap();
266+
}
267+
if effects_in_use.contains(anstyle::Effects::HIDDEN) {
268+
writeln!(buffer, r#" .hidden {{ opacity: 0; }}"#).unwrap();
269+
}
270+
}
271+
272+
fn write_fg_span(buffer: &mut String, span: &str, element: &adapter::Element, fragment: &str) {
272273
use std::fmt::Write as _;
273274
let style = element.style;
274275
let fg_color = style.get_fg_color().map(|c| color_name(FG_PREFIX, c));
@@ -329,7 +330,7 @@ fn write_fg_span(buffer: &mut String, element: &adapter::Element, fragment: &str
329330

330331
let mut need_closing_a = false;
331332

332-
write!(buffer, r#"<tspan"#).unwrap();
333+
write!(buffer, r#"<{span}"#).unwrap();
333334
if !classes.is_empty() {
334335
let classes = classes.join(" ");
335336
write!(buffer, r#" class="{classes}""#).unwrap();
@@ -343,10 +344,10 @@ fn write_fg_span(buffer: &mut String, element: &adapter::Element, fragment: &str
343344
if need_closing_a {
344345
write!(buffer, r#"</a>"#).unwrap();
345346
}
346-
write!(buffer, r#"</tspan>"#).unwrap();
347+
write!(buffer, r#"</{span}>"#).unwrap();
347348
}
348349

349-
fn write_bg_span(buffer: &mut String, style: &anstyle::Style, fragment: &str) {
350+
fn write_bg_span(buffer: &mut String, span: &str, style: &anstyle::Style, fragment: &str) {
350351
use std::fmt::Write as _;
351352
use unicode_width::UnicodeWidthStr;
352353

@@ -361,14 +362,14 @@ fn write_bg_span(buffer: &mut String, style: &anstyle::Style, fragment: &str) {
361362
if let Some(class) = bg_color.as_deref() {
362363
classes.push(class);
363364
}
364-
write!(buffer, r#"<tspan"#).unwrap();
365+
write!(buffer, r#"<{span}"#).unwrap();
365366
if !classes.is_empty() {
366367
let classes = classes.join(" ");
367368
write!(buffer, r#" class="{classes}""#).unwrap();
368369
}
369370
write!(buffer, r#">"#).unwrap();
370371
write!(buffer, "{fragment}").unwrap();
371-
write!(buffer, r#"</tspan>"#).unwrap();
372+
write!(buffer, r#"</{span}>"#).unwrap();
372373
}
373374

374375
impl Default for Term {
@@ -449,6 +450,23 @@ fn color_styles(
449450
colors.into_iter()
450451
}
451452

453+
fn preprocess_invert_style(
454+
elements: &mut [adapter::Element],
455+
bg_color: anstyle::Color,
456+
fg_color: anstyle::Color,
457+
) {
458+
for element in elements {
459+
let style = &mut element.style;
460+
// Pre-process INVERT to make fg/bg calculations easier
461+
if style.get_effects().contains(anstyle::Effects::INVERT) {
462+
*style = style
463+
.fg_color(Some(style.get_bg_color().unwrap_or(bg_color)))
464+
.bg_color(Some(style.get_fg_color().unwrap_or(fg_color)))
465+
.effects(style.get_effects().remove(anstyle::Effects::INVERT));
466+
}
467+
}
468+
}
469+
452470
fn split_lines(styled: &[adapter::Element]) -> Vec<Vec<adapter::Element>> {
453471
let mut lines = Vec::new();
454472
let mut current_line = Vec::new();

0 commit comments

Comments
 (0)