dprint_core/formatting/
print.rs1use std::cell::RefCell;
2
3use self::thread_state::BumpAllocator;
4
5use super::*;
6
7pub struct PrintOptions {
9 pub max_width: u32,
11 pub indent_width: u8,
13 pub use_tabs: bool,
15 pub new_line_text: &'static str,
17}
18
19impl PrintOptions {
20 pub(super) fn to_printer_options(&self) -> PrinterOptions {
21 PrinterOptions {
22 indent_width: self.indent_width,
23 max_width: self.max_width,
24 #[cfg(feature = "tracing")]
25 enable_tracing: false,
26 }
27 }
28}
29
30pub fn format(get_print_items: impl FnOnce() -> PrintItems, options: PrintOptions) -> String {
36 increment_formatting_count();
37 let old_counts = thread_state::take_counts();
38 let print_items = get_print_items();
39
40 let result = thread_state::with_bump_allocator(|bump| {
41 let result = print_with_allocator(bump, &print_items, &options);
42 if decrement_formatting_count() {
43 bump.reset();
44 }
45 result
46 });
47 thread_state::set_counts(old_counts);
48 result
49}
50
51pub fn print(print_items: PrintItems, options: PrintOptions) -> String {
56 panic_if_not_formatting();
59
60 let old_counts = thread_state::take_counts();
61 let result = thread_state::with_bump_allocator(|bump| print_with_allocator(bump, &print_items, &options));
62 thread_state::set_counts(old_counts);
63 result
64}
65
66fn print_with_allocator(bump: &mut BumpAllocator, print_items: &PrintItems, options: &PrintOptions) -> String {
67 match Printer::new(bump, print_items.first_node, options.to_printer_options()).print() {
68 Some(write_items) => WriteItemsPrinter::from(options).print(write_items),
69 None => String::new(),
70 }
71}
72
73#[cfg(feature = "tracing")]
74#[derive(serde::Serialize)]
75#[serde(rename_all = "camelCase")]
76pub struct TracingResult {
77 pub traces: Vec<Trace>,
78 pub writer_nodes: Vec<TraceWriterNode>,
79 pub print_nodes: Vec<TracePrintNode>,
80}
81
82#[cfg(feature = "tracing")]
84pub fn trace_printing(get_print_items: impl FnOnce() -> PrintItems, options: PrintOptions) -> TracingResult {
85 use std::iter;
86
87 increment_formatting_count();
88 let print_items = get_print_items();
89
90 thread_state::with_bump_allocator(|bump| {
91 let tracing_result = Printer::new(bump, print_items.first_node, {
92 let mut printer_options = options.to_printer_options();
93 printer_options.enable_tracing = true;
94 printer_options
95 })
96 .print_for_tracing();
97 let writer_items_printer = WriteItemsPrinter::from(&options);
98
99 let result = TracingResult {
100 traces: tracing_result.traces,
101 writer_nodes: tracing_result
102 .writer_nodes
103 .into_iter()
104 .map(|node| {
105 let text = writer_items_printer.print(iter::once(node.item));
106 TraceWriterNode {
107 writer_node_id: node.graph_node_id,
108 previous_node_id: node.previous.map(|n| n.graph_node_id),
109 text,
110 }
111 })
112 .collect(),
113 print_nodes: super::get_trace_print_nodes(print_items.first_node),
114 };
115
116 if decrement_formatting_count() {
117 bump.reset();
118 }
119 result
120 })
121}
122
123thread_local! {
124 static FORMATTING_COUNT: RefCell<u32> = const { RefCell::new(0) };
125}
126
127fn increment_formatting_count() {
128 FORMATTING_COUNT.with(|formatting_count_cell| {
129 let mut formatting_count = formatting_count_cell.borrow_mut();
130 *formatting_count += 1;
131 })
132}
133
134fn decrement_formatting_count() -> bool {
135 FORMATTING_COUNT.with(|formatting_count_cell| {
136 let mut formatting_count = formatting_count_cell.borrow_mut();
137 *formatting_count -= 1;
138 *formatting_count == 0
139 })
140}
141
142fn panic_if_not_formatting() {
143 FORMATTING_COUNT.with(|formatting_count_cell| {
144 if *formatting_count_cell.borrow() == 0 {
145 panic!("dprint_core::formatting::print cannot be called except within the provided closure to dprint_core::formatting::format");
146 }
147 })
148}
149
150#[cfg(test)]
151mod test {
152 use crate::formatting::LineNumber;
153
154 use super::super::PrintItems;
155 use super::format;
156 use super::PrintOptions;
157
158 #[test]
159 fn test_format_in_format() {
160 assert_eq!(
161 format(
162 || {
163 let mut items = PrintItems::new();
164 assert_eq!(LineNumber::new("").unique_id(), 0);
165 assert_eq!(LineNumber::new("").unique_id(), 1);
166 assert_eq!(LineNumber::new("").unique_id(), 2);
167 items.push_str_runtime_width_computed("test");
168 items.push_string(format(
169 || {
170 assert_eq!(LineNumber::new("").unique_id(), 0);
175 assert_eq!(LineNumber::new("").unique_id(), 1);
176 "test".into()
177 },
178 get_print_options(),
179 ));
180 assert_eq!(LineNumber::new("").unique_id(), 3);
182 items
183 },
184 get_print_options(),
185 ),
186 "testtest"
187 );
188 }
189
190 fn get_print_options() -> PrintOptions {
191 PrintOptions {
192 max_width: 40,
193 indent_width: 2,
194 use_tabs: false,
195 new_line_text: "\n",
196 }
197 }
198}