1use std::fmt;
8use std::fmt::{Display, Formatter};
9
10use colored::Colorize as _;
11use encoding_rs::UTF_8;
12use mozjs::jsval::StringValue;
13
14use crate::format::Config;
15use crate::{Context, Local, Value};
16
17pub fn format_string<'cx>(cx: &'cx Context, cfg: Config, string: &'cx crate::String<'cx>) -> StringDisplay<'cx> {
18 StringDisplay { cx, string, cfg }
19}
20
21#[must_use]
22pub struct StringDisplay<'cx> {
23 cx: &'cx Context,
24 string: &'cx crate::String<'cx>,
25 cfg: Config,
26}
27
28impl Display for StringDisplay<'_> {
29 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
30 let colour = self.cfg.colours.string;
31 if self.cfg.quoted {
32 if let Ok(str) = self.string.to_owned(self.cx) {
33 write!(f, "{0}{1}{0}", r#"""#.color(colour), str.color(colour))
34 } else {
35 let value = StringValue(unsafe { &*self.string.get() });
36 let value = Value::from(unsafe { Local::from_marked(&raw const value) });
37 let str = value.to_source(self.cx).to_owned(self.cx).unwrap();
38 str.color(colour).fmt(f)
39 }
40 } else if let Ok(str) = self.string.to_owned(self.cx) {
41 str.fmt(f)
42 } else {
43 let input = self.string.as_wtf16(self.cx).unwrap();
44 let mut encoder = UTF_8.new_encoder();
45 let buf_len = encoder.max_buffer_length_from_utf16_if_no_unmappables(input.len()).unwrap();
46 let mut buf = Vec::with_capacity(buf_len);
47 let (_, _, _, _) = encoder.encode_from_utf16(input, &mut buf, true);
48 let str = unsafe { String::from_utf8_unchecked(buf) };
49 str.fmt(f)
50 }
51 }
52}