tui_dispatch_debug/debug/
format.rs1use std::fmt::Debug;
2
3pub fn debug_string<T>(value: &T) -> String
4where
5 T: Debug,
6{
7 debug_string_compact(value)
8}
9
10pub fn debug_string_compact<T>(value: &T) -> String
11where
12 T: Debug,
13{
14 format!("{:?}", value)
15}
16
17pub fn debug_string_pretty<T>(value: &T) -> String
18where
19 T: Debug,
20{
21 format!("{:#?}", value)
22}
23
24pub fn pretty_reformat(input: &str) -> String {
37 let mut out = String::with_capacity(input.len() * 2);
38 let mut indent: usize = 0;
39 let mut chars = input.chars().peekable();
40 let indent_str = " ";
41
42 while let Some(ch) = chars.next() {
43 match ch {
44 '"' => {
46 out.push('"');
47 loop {
48 match chars.next() {
49 Some('\\') => {
50 out.push('\\');
51 if let Some(esc) = chars.next() {
52 out.push(esc);
53 }
54 }
55 Some('"') => {
56 out.push('"');
57 break;
58 }
59 Some(c) => out.push(c),
60 None => break,
61 }
62 }
63 }
64 '\'' => {
66 out.push('\'');
67 loop {
68 match chars.next() {
69 Some('\\') => {
70 out.push('\\');
71 if let Some(esc) = chars.next() {
72 out.push(esc);
73 }
74 }
75 Some('\'') => {
76 out.push('\'');
77 break;
78 }
79 Some(c) => out.push(c),
80 None => break,
81 }
82 }
83 }
84 '{' | '[' | '(' => {
85 let close = match ch {
87 '{' => '}',
88 '[' => ']',
89 _ => ')',
90 };
91 if chars.peek() == Some(&close) {
92 out.push(ch);
93 out.push(chars.next().unwrap());
94 } else {
95 indent += 1;
96 out.push(ch);
97 out.push('\n');
98 for _ in 0..indent {
99 out.push_str(indent_str);
100 }
101 }
102 }
103 '}' | ']' | ')' => {
104 indent = indent.saturating_sub(1);
105 let trimmed = out.trim_end_matches(' ');
107 out.truncate(trimmed.len());
108 if !out.ends_with('\n') {
109 out.push('\n');
110 }
111 for _ in 0..indent {
112 out.push_str(indent_str);
113 }
114 out.push(ch);
115 }
116 ',' => {
117 out.push(',');
118 if indent > 0 {
120 out.push('\n');
121 for _ in 0..indent {
122 out.push_str(indent_str);
123 }
124 } else {
125 out.push(' ');
126 }
127 }
128 ' ' if out.ends_with('\n') || out.ends_with(indent_str) => {}
130 _ => {
131 out.push(ch);
132 }
133 }
134 }
135
136 out
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn pretty_reformat_simple_set() {
145 let input = r#"{"a", "b", "c"}"#;
146 let result = pretty_reformat(input);
147 assert!(result.contains('\n'));
148 assert!(result.contains(" \"a\","));
149 assert!(result.contains(" \"b\","));
150 }
151
152 #[test]
153 fn pretty_reformat_nested() {
154 let input = "Foo{x: [1, 2], y: Bar{z: 3}}";
155 let result = pretty_reformat(input);
156 assert!(result.contains('\n'));
157 assert!(result.contains(" z: 3"));
159 }
160
161 #[test]
162 fn pretty_reformat_empty_containers() {
163 assert_eq!(pretty_reformat("{}"), "{}");
164 assert_eq!(pretty_reformat("[]"), "[]");
165 assert_eq!(pretty_reformat("()"), "()");
166 }
167
168 #[test]
169 fn pretty_reformat_preserves_strings() {
170 let input = r#"{"hello, world", "foo{bar}"}"#;
171 let result = pretty_reformat(input);
172 assert!(result.contains(r#""hello, world""#));
173 assert!(result.contains(r#""foo{bar}""#));
174 }
175
176 #[test]
177 fn pretty_reformat_plain_value() {
178 assert_eq!(pretty_reformat("42"), "42");
179 assert_eq!(pretty_reformat("true"), "true");
180 }
181
182 #[test]
183 fn pretty_reformat_preserves_char_literals() {
184 assert_eq!(pretty_reformat("Some('}')"), "Some(\n '}'\n)");
186
187 let input = "Foo { x: Some('}'), y: 2 }";
188 let result = pretty_reformat(input);
189 assert!(result.contains(" '}'"));
190 assert!(result.contains(" y: 2"));
191 }
192
193 #[test]
194 fn pretty_reformat_preserves_escaped_char() {
195 let input = r#"Foo { c: '\'', n: '\n' }"#;
196 let result = pretty_reformat(input);
197 assert!(result.contains(r#"'\''"#));
198 assert!(result.contains(r#"'\n'"#));
199 }
200}