cairo_lang_formatter/
lib.rs1pub mod cairo_formatter;
5pub mod formatter_impl;
6pub mod node_properties;
7
8use cairo_lang_diagnostics::DiagnosticsBuilder;
9use cairo_lang_filesystem::ids::{FileKind, FileLongId, SmolStrId, VirtualFile};
10use cairo_lang_parser::parser::Parser;
11use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
12use cairo_lang_utils::Intern;
13use salsa::Database;
14use serde::{Deserialize, Serialize};
15
16pub use crate::cairo_formatter::{CairoFormatter, FormatOutcome, StdinFmt};
17use crate::formatter_impl::FormatterImpl;
18
19#[cfg(test)]
20mod test;
21
22pub const CAIRO_FMT_IGNORE: &str = ".cairofmtignore";
23
24pub fn get_formatted_file(
32 db: &dyn Database,
33 syntax_root: &SyntaxNode<'_>,
34 config: FormatterConfig,
35) -> String {
36 let mut formatter = FormatterImpl::new(db, config);
37 formatter.get_formatted_string(syntax_root)
38}
39
40pub fn format_string(db: &dyn Database, content: String) -> String {
47 let virtual_file = FileLongId::Virtual(VirtualFile {
48 parent: None,
49 name: SmolStrId::from(db, "string_to_format"),
50 content: SmolStrId::from(db, &content),
51 code_mappings: [].into(),
52 kind: FileKind::Module,
53 original_item_removed: false,
54 })
55 .intern(db);
56 let mut diagnostics = DiagnosticsBuilder::default();
57 let syntax_root =
58 Parser::parse_file(db, &mut diagnostics, virtual_file, content.as_str()).as_syntax_node();
59 get_formatted_file(db, &syntax_root, FormatterConfig::default())
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
66pub enum CollectionsBreakingBehavior {
67 SingleBreakPoint,
69 LineByLine,
71}
72
73impl From<bool> for CollectionsBreakingBehavior {
76 fn from(b: bool) -> Self {
77 if b {
78 CollectionsBreakingBehavior::LineByLine
79 } else {
80 CollectionsBreakingBehavior::SingleBreakPoint
81 }
82 }
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct BreakingBehaviorConfig {
87 pub tuple: CollectionsBreakingBehavior,
88 pub fixed_array: CollectionsBreakingBehavior,
89 pub macro_call: CollectionsBreakingBehavior,
90}
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "kebab-case")]
93pub struct FormatterConfig {
94 pub tab_size: usize,
95 pub max_line_length: usize,
96 pub sort_module_level_items: bool,
97 pub breaking_behavior: BreakingBehaviorConfig,
98 pub merge_use_items: bool,
99 pub allow_duplicate_uses: bool,
100}
101
102const TAB_SIZE: usize = 4;
105const MAX_LINE_LENGTH: usize = 100;
106
107impl FormatterConfig {
108 pub fn new(
109 tab_size: usize,
110 max_line_length: usize,
111 sort_module_level_items: bool,
112 breaking_behavior: BreakingBehaviorConfig,
113 merge_use_items: bool,
114 allow_duplicate_uses: bool,
115 ) -> Self {
116 Self {
117 tab_size,
118 max_line_length,
119 sort_module_level_items,
120 breaking_behavior,
121 merge_use_items,
122 allow_duplicate_uses,
123 }
124 }
125
126 pub fn sort_module_level_items(mut self, sort_module_level_items: Option<bool>) -> Self {
127 if let Some(sort) = sort_module_level_items {
128 self.sort_module_level_items = sort;
129 }
130 self
131 }
132
133 pub fn tuple_breaking_behavior(
134 mut self,
135 behavior: Option<CollectionsBreakingBehavior>,
136 ) -> Self {
137 if let Some(behavior) = behavior {
138 self.breaking_behavior.tuple = behavior;
139 }
140 self
141 }
142
143 pub fn fixed_array_breaking_behavior(
144 mut self,
145 behavior: Option<CollectionsBreakingBehavior>,
146 ) -> Self {
147 if let Some(behavior) = behavior {
148 self.breaking_behavior.fixed_array = behavior;
149 }
150 self
151 }
152
153 pub fn macro_call_breaking_behavior(
154 mut self,
155 behavior: Option<CollectionsBreakingBehavior>,
156 ) -> Self {
157 if let Some(behavior) = behavior {
158 self.breaking_behavior.macro_call = behavior;
159 }
160 self
161 }
162 pub fn merge_use_items(mut self, merge: Option<bool>) -> Self {
163 if let Some(merge) = merge {
164 self.merge_use_items = merge;
165 }
166 self
167 }
168 pub fn allow_duplicate_uses(mut self, allow: Option<bool>) -> Self {
169 if let Some(allow) = allow {
170 self.allow_duplicate_uses = allow;
171 }
172 self
173 }
174}
175impl Default for FormatterConfig {
176 fn default() -> Self {
177 Self {
178 tab_size: TAB_SIZE,
179 max_line_length: MAX_LINE_LENGTH,
180 sort_module_level_items: true,
181 breaking_behavior: BreakingBehaviorConfig {
182 tuple: CollectionsBreakingBehavior::LineByLine,
183 fixed_array: CollectionsBreakingBehavior::SingleBreakPoint,
184 macro_call: CollectionsBreakingBehavior::SingleBreakPoint,
185 },
186 merge_use_items: true,
187 allow_duplicate_uses: false,
188 }
189 }
190}