1#![warn(missing_docs)]
2#![cfg_attr(not(test), warn(clippy::unwrap_used))]
3
4#[allow(missing_docs)]
9mod buffer;
10#[allow(missing_docs)]
11mod format_element;
12#[allow(missing_docs)]
13mod formatter;
14#[allow(missing_docs)]
15mod macros;
16#[allow(missing_docs)]
18pub mod prelude;
19#[allow(missing_docs)]
20mod printer;
21
22pub use crate::buffer::{Buffer, VecBuffer};
24pub use crate::format_element::{
26 Document, FormatElement, LineMode, best_fit, group, hard_line_break, indent, soft_line_break,
27 soft_line_break_or_space, space, text, token, verbatim,
28};
29pub use crate::formatter::{
31 Format, FormatContext, FormatError, FormatOptions, FormatResult, Formatted, Formatter,
32 SimpleFormatContext, SimpleFormatOptions,
33};
34pub use crate::printer::{IndentStyle, LineEnding, PrintError, Printed, Printer, PrinterOptions};
36
37#[cfg(test)]
38mod tests {
39 use crate::prelude::*;
40 use crate::{SimpleFormatContext, SimpleFormatOptions, format};
41
42 #[test]
43 fn prints_indented_hard_lines() {
44 let context = SimpleFormatContext::new(SimpleFormatOptions::default());
45 let doc = Document::from_elements(vec![
46 text("if"),
47 hard_line_break(),
48 indent(Document::from_elements(vec![
49 text("echo hi"),
50 hard_line_break(),
51 text("echo bye"),
52 ])),
53 ]);
54
55 let printed = format!(context, [doc]).unwrap().print().unwrap();
56 assert_eq!(printed.as_code(), "if\n\techo hi\n\techo bye");
57 }
58
59 #[test]
60 fn group_flattens_when_content_fits() {
61 let context = SimpleFormatContext::new(SimpleFormatOptions::default());
62 let doc = Document::from_element(group(Document::from_elements(vec![
63 text("echo"),
64 soft_line_break_or_space(),
65 text("hello"),
66 ])));
67
68 let printed = format!(context, [doc]).unwrap().print().unwrap();
69 assert_eq!(printed.as_code(), "echo hello");
70 }
71
72 #[test]
73 fn group_expands_when_content_overflows() {
74 let mut options = SimpleFormatOptions::default();
75 options.printer_options.line_width = 8;
76 let context = SimpleFormatContext::new(options);
77 let doc = Document::from_element(group(Document::from_elements(vec![
78 text("echo"),
79 soft_line_break_or_space(),
80 text("long-value"),
81 ])));
82
83 let printed = format!(context, [doc]).unwrap().print().unwrap();
84 assert_eq!(printed.as_code(), "echo\nlong-value");
85 }
86
87 #[test]
88 fn best_fit_chooses_expanded_variant() {
89 let mut options = SimpleFormatOptions::default();
90 options.printer_options.line_width = 6;
91 let context = SimpleFormatContext::new(options);
92 let doc = Document::from_element(best_fit(
93 Document::from_elements(vec![text("alpha"), space(), text("beta")]),
94 Document::from_elements(vec![text("alpha"), hard_line_break(), text("beta")]),
95 ));
96
97 let printed = format!(context, [doc]).unwrap().print().unwrap();
98 assert_eq!(printed.as_code(), "alpha\nbeta");
99 }
100
101 #[test]
102 fn group_expands_for_wide_unicode_text() {
103 let mut options = SimpleFormatOptions::default();
104 options.printer_options.line_width = 3;
105 let context = SimpleFormatContext::new(options);
106 let doc = Document::from_element(group(Document::from_elements(vec![
107 text("a"),
108 soft_line_break_or_space(),
109 text("界"),
110 ])));
111
112 let printed = format!(context, [doc]).unwrap().print().unwrap();
113 assert_eq!(printed.as_code(), "a\n界");
114 }
115
116 #[test]
117 fn hard_lines_use_configured_crlf_endings() {
118 let mut options = SimpleFormatOptions::default();
119 options.printer_options.line_ending = LineEnding::CrLf;
120 let context = SimpleFormatContext::new(options);
121 let doc = Document::from_elements(vec![token("a"), hard_line_break(), token("b")]);
122
123 let printed = format!(context, [doc]).unwrap().print().unwrap();
124 assert_eq!(printed.as_code(), "a\r\nb");
125 }
126
127 #[test]
128 fn verbatim_preserves_source_text() {
129 let context = SimpleFormatContext::new(SimpleFormatOptions::default());
130 let doc = Document::from_elements(vec![
131 text("begin"),
132 hard_line_break(),
133 verbatim(" raw\ntext"),
134 ]);
135
136 let printed = format!(context, [doc]).unwrap().print().unwrap();
137 assert_eq!(printed.as_code(), "begin\n raw\ntext");
138 }
139
140 #[test]
141 fn nested_groups_and_indents_expand_consistently() {
142 let mut options = SimpleFormatOptions::default();
143 options.printer_options.line_width = 8;
144 let context = SimpleFormatContext::new(options);
145 let doc = Document::from_element(group(Document::from_elements(vec![
146 token("if"),
147 soft_line_break_or_space(),
148 token("true"),
149 token(";"),
150 soft_line_break(),
151 indent(Document::from_elements(vec![
152 token("echo"),
153 soft_line_break_or_space(),
154 token("long-value"),
155 ])),
156 ])));
157
158 let printed = format!(context, [doc]).unwrap().print().unwrap();
159 assert_eq!(printed.as_code(), "if\ntrue;\n\techo\n\tlong-value");
160 }
161
162 #[test]
163 fn indents_with_spaces_when_configured() {
164 let mut options = SimpleFormatOptions::default();
165 options.printer_options.indent_style = IndentStyle::Space;
166 options.printer_options.indent_width = 2;
167 let context = SimpleFormatContext::new(options);
168 let doc = Document::from_elements(vec![
169 token("if"),
170 hard_line_break(),
171 indent(Document::from_elements(vec![
172 token("echo hi"),
173 hard_line_break(),
174 token("echo bye"),
175 ])),
176 ]);
177
178 let printed = format!(context, [doc]).unwrap().print().unwrap();
179 assert_eq!(printed.as_code(), "if\n echo hi\n echo bye");
180 }
181}