1use super::code_builder::CodeBuilder;
2use crate::traversal::{traverse_for_changes, Change};
3use ropey::Rope;
4use std::sync::Arc;
5use sway_core::BuildConfig;
6
7pub fn get_formatted_data(
14 file: Arc<str>,
15 formatting_options: FormattingOptions,
16 build_config: Option<&BuildConfig>,
17) -> Result<(usize, String), Vec<String>> {
18 let parsed_res = sway_core::parse(file.clone(), build_config);
19
20 match parsed_res.value {
21 Some(parse_program) => {
22 let changes = traverse_for_changes(&parse_program.root.tree);
24 let mut rope_file = Rope::from_str(&file);
25
26 let mut offset: i32 = 0;
27 for change in changes {
28 let (new_offset, start, end) = calculate_offset(offset, &change);
31 offset = new_offset;
32
33 rope_file.remove(start..end);
34 rope_file.insert(start, &change.text);
35 }
36
37 let mut code_builder = CodeBuilder::new(formatting_options.tab_size);
39
40 let file = rope_file.to_string();
41 let lines: Vec<&str> = file.split('\n').collect();
42
43 for line in lines {
45 code_builder.format_and_add(line);
46 }
47
48 Ok(code_builder.get_final_edits())
49 }
50 None => Err(parsed_res
51 .errors
52 .iter()
53 .map(|e| format!("{} at line: {}", e, e.line_col().0.line,))
54 .collect()),
55 }
56}
57
58fn calculate_offset(current_offset: i32, change: &Change) -> (i32, usize, usize) {
59 let start = change.start as i32 + current_offset;
60 let end = change.end as i32 + current_offset;
61 let offset = current_offset + (start + change.text.len() as i32) - end;
62
63 (offset, start as usize, end as usize)
64}
65
66#[derive(Debug, Clone, Copy)]
67pub struct FormattingOptions {
68 pub align_fields: bool,
69 pub tab_size: u32,
70}
71
72impl FormattingOptions {
73 pub fn default() -> Self {
74 Self {
75 align_fields: true,
76 tab_size: 4,
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::FormattingOptions;
84
85 use super::get_formatted_data;
86 const OPTIONS: FormattingOptions = FormattingOptions {
87 align_fields: false,
88 tab_size: 4,
89 };
90
91 #[test]
92 fn test_indentation() {
93 let correct_sway_code = r#"script;
94
95fn main() {
96 // this is a comment
97 let o = 123;
98
99 let p = {
100 /* this is some
101 multi line stuff t
102
103 */
104 123;
105 };
106
107 add(1, 2);
108}
109
110pub fn add(a: u32, b: u32) -> u32 {
111 a + b
112}
113"#;
114 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
115 assert!(result.is_ok());
116 let (_, formatted_code) = result.unwrap();
117 assert_eq!(correct_sway_code, formatted_code);
118
119 let sway_code = r#"script;
120
121fn main() {
122 // this is a comment
123 let o = 123;
124
125 let
126p
127
128
129 =
130
131
132 {
133 /* this is some
134 multi line stuff t
135
136 */
137 123
138
139
140 ;
141
142
143 };
144
145 add( 1,
146
147 2
148
149
150 ) ;
151}
152
153pub
154fn
155add
156 (
157 a:u32 ,
158 b: u32) ->u32{
159 a +b}
160
161"#;
162
163 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
164 assert!(result.is_ok());
165 let (_, formatted_code) = result.unwrap();
166 assert_eq!(correct_sway_code, formatted_code);
167 }
168
169 #[test]
170 fn test_multiline_string() {
171 let correct_sway_code = r#"script;
172
173fn main() {
174 let multiline_string = " sadsa
175 sadsad
176 sadasd sadsdsa
177 sadasd
178 sadasd sadasd
179 ";
180
181 storage {
182 foo: u64 = 0,
183 bar: i32 = 0,
184 }
185 storage.foo;
186}
187"#;
188
189 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
190 assert!(result.is_ok());
191 let (_, formatted_code) = result.unwrap();
192 assert_eq!(correct_sway_code, formatted_code);
193
194 let sway_code = r#"script;
195
196fn main(){
197 let multiline_string=" sadsa
198 sadsad
199 sadasd sadsdsa
200 sadasd
201 sadasd sadasd
202 "
203 ;
204
205storage {
206 foo: u64 = 0, bar:i32 = 0,
207 }
208 storage.foo ;
209}
210"#;
211
212 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
213 assert!(result.is_ok());
214 let (_, formatted_code) = result.unwrap();
215 assert_eq!(correct_sway_code, formatted_code);
216 }
217
218 #[test]
219 fn test_whitespace_handling() {
220 let correct_sway_code = r#"script;
221
222fn main() {
223 let word = "word";
224 let num = 12;
225
226 let multi = {
227 let k = 12;
228 k
229 };
230}
231"#;
232
233 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
234 assert!(result.is_ok());
235 let (_, formatted_code) = result.unwrap();
236 assert_eq!(correct_sway_code, formatted_code);
237
238 let sway_code = r#"script;
239
240fn main() {
241 let word="word";
242 let num= 12 ;
243
244 let multi = {
245 let k = 12;
246 k
247 }
248
249
250 ;
251}
252"#;
253
254 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
255 assert!(result.is_ok());
256 let (_, formatted_code) = result.unwrap();
257 assert_eq!(correct_sway_code, formatted_code);
258 }
259
260 #[test]
261 fn test_comments() {
262 let correct_sway_code = r#"script;
263
264fn main() {
265 // this is a comment
266 let o = 123; // this is an inline comment
267 /*
268 asdasd
269 asdasdsad asdasdasd */
270
271 /* multiline closed on the same line */
272 let p = {
273 /* this is some
274 multi line stuff t
275
276 */
277 123;
278 }; // comment here as well
279} // comment here too
280
281// example struct with comments
282struct Example { // first comment
283 prop: bool, // second comment
284 age: u32, // another comment
285} // comment as well
286"#;
287
288 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
289 assert!(result.is_ok());
290 let (_, formatted_code) = result.unwrap();
291 assert_eq!(correct_sway_code, formatted_code);
292
293 let sway_code = r#"script;
294
295fn main() {
296 // this is a comment
297 let o = 123; // this is an inline comment
298 /*
299 asdasd
300 asdasdsad asdasdasd */
301
302 /* multiline closed on the same line */
303 let p = {
304 /* this is some
305 multi line stuff t
306
307 */
308 123;
309 }; // comment here as well
310} // comment here too
311
312 // example struct with comments
313struct Example { // first comment
314 prop: bool,// second comment
315 age: u32// another comment
316} // comment as well
317"#;
318
319 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
320 assert!(result.is_ok());
321 let (_, formatted_code) = result.unwrap();
322 assert_eq!(correct_sway_code, formatted_code);
323 }
324
325 #[test]
326 fn test_data_types() {
327 let correct_sway_code = r#"script;
328
329fn main() {
330 let rgb: Rgb = Rgb {
331 red: 255,
332 blue: 0,
333 green: 0,
334 };
335
336 if (true) {
337 let rgb: Rgb = Rgb {
338 red: 255,
339 blue: 0,
340 green: 0,
341 };
342 }
343}
344
345struct Rgb {
346 red: u64,
347 green: u64,
348 blue: u64,
349}
350
351struct Structure {
352 age: u32,
353
354 name: string,
355}
356
357struct Structure {
358 age: u32, /* completely meaningless multiline comment
359 not sure why would anyone write this but let's deal with it as well!
360 */
361 name: string,
362}
363
364struct Structure {
365 age: u32,
366 name: string, // super comment
367}
368
369struct Structure {
370 age: u32,
371 name: string, // super comment
372}
373
374struct Vehicle {
375 age: u32,
376 name: string, // some comment middle of nowhere
377}
378
379struct Environment {
380 age: u32,
381 name: string,
382} // lost my train of thought
383
384struct Person { // first comment
385 age: u32, // second comment
386 name: string, // third comment
387} // fourth comment
388
389pub fn get_age() -> u32 {
390 99
391}
392
393pub fn read_example() -> Example {
394 Example {
395 age: get_age(),
396 name: "Example face",
397 }
398}
399
400struct Example {
401 age: u32,
402 name: string,
403}
404
405struct C {
406 /// a docstring
407 a: A,
408 /// b docstring
409 b: byte,
410}
411
412struct A {
413 a: u64,
414 b: u64,
415}
416
417fn get_gas() -> A {
418 A {
419 a: asm() {
420 ggas
421 },
422 b: asm() {
423 cgas
424 },
425 }
426}
427"#;
428
429 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
430 assert!(result.is_ok());
431 let (_, formatted_code) = result.unwrap();
432 assert_eq!(correct_sway_code, formatted_code);
433
434 let sway_code = r#"script;
435
436fn main() {
437 let rgb:Rgb=Rgb {
438 red: 255,
439 blue: 0,
440 green: 0,
441 };
442
443 if(true){
444 let rgb: Rgb = Rgb {
445 red:255, blue: 0,
446 green: 0,
447 };
448 }
449}
450
451struct Rgb {
452 red: u64,
453 green: u64,
454 blue: u64,
455}
456
457struct Structure {
458
459 age: u32,
460
461 name: string,
462
463}
464
465struct Structure {
466 age: u32, /* completely meaningless multiline comment
467 not sure why would anyone write this but let's deal with it as well!
468 */
469 name: string
470}
471
472struct Structure {
473 age: u32,
474 name: string// super comment
475}
476
477struct Structure {
478 age: u32,
479 name: string, // super comment
480}
481
482struct Vehicle
483 { age: u32, name: string , // some comment middle of nowhere
484}
485
486struct Environment{age:u32,name:string} // lost my train of thought
487
488struct Person {// first comment
489 age: u32,// second comment
490 name: string, // third comment
491} // fourth comment
492
493pub fn get_age() -> u32 {
494 99
495}
496
497pub fn read_example() -> Example {
498 Example {
499 age: get_age() ,name: "Example face"
500 }
501}
502
503struct Example {age: u32, name: string}
504
505struct C {
506/// a docstring
507a: A,
508/// b docstring
509b: byte,
510}
511
512struct A {
513a: u64,
514b: u64,
515}
516
517fn get_gas() -> A {
518A {
519a: asm() {
520ggas
521},
522b: asm() {
523cgas
524}
525}
526}
527"#;
528
529 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
530 assert!(result.is_ok());
531 let (_, formatted_code) = result.unwrap();
532 assert_eq!(correct_sway_code, formatted_code);
533 }
534
535 #[test]
536 fn test_enums() {
537 let correct_sway_code = r#"script;
538
539pub fn main() {
540 let k = Story::Pain;
541}
542
543enum Story {
544 Pain: (),
545 Gain: (),
546}
547
548enum StoryA {
549 Pain: (),
550 Gain: (),
551}
552
553pub fn tell_a_story() -> Story {
554 Story::Gain
555}
556"#;
557
558 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
559 assert!(result.is_ok());
560 let (_, formatted_code) = result.unwrap();
561 assert_eq!(correct_sway_code, formatted_code);
562
563 let sway_code = r#"script;
564
565 pub fn main() {
566 let k =
567 Story :: Pain;
568
569
570
571 }
572
573
574 enum Story {
575 Pain:(),
576 Gain:()
577 }
578
579 enum StoryA {Pain:(),Gain:()}
580
581 pub fn tell_a_story() ->Story {
582 Story :: Gain
583 }
584"#;
585
586 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
587 assert!(result.is_ok());
588 let (_, formatted_code) = result.unwrap();
589 assert_eq!(correct_sway_code, formatted_code);
590 }
591
592 #[test]
593 fn test_comparison_operators() {
594 let correct_sway_code = r#"script;
595
596fn main() {
597 if 1 >= 0 {
598 } else if 4 <= 0 {
599 } else if 5 == 0 {
600 } else if 4 != 4 {
601 } else {
602 }
603}
604
605fn one_liner() -> bool {
606 if 1 >= 0 {
607 true
608 } else if 1 <= 0 {
609 true
610 } else {
611 true
612 }
613}
614"#;
615
616 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
617 assert!(result.is_ok());
618 let (_, formatted_code) = result.unwrap();
619 assert_eq!(correct_sway_code, formatted_code);
620
621 let sway_code = r#"script;
622
623 fn main() {
624 if 1 >= 0 {
625
626 } else if 4 <= 0
627
628 {
629
630 }
631 else if 5 == 0 { } else if 4 != 4
632
633 {
634
635 }
636 else {
637
638 }
639 }
640
641 fn one_liner() -> bool {
642 if 1 >= 0 { true } else if 1 <= 0 { true } else { true }
643 }
644"#;
645
646 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
647 assert!(result.is_ok());
648 let (_, formatted_code) = result.unwrap();
649 assert_eq!(correct_sway_code, formatted_code);
650 }
651
652 #[test]
653 fn test_use_statement() {
655 let test_sway = r#"script;
656use std::chain::{panic,log_u8};
657use std::chain::assert;
658use std::hash::{sha256, keccak256 };
659use a::b::{c,d::{f,e}};
660use a::b::{c,d::{f,self}};
661
662fn main() {
663}
664"#;
665 let expected_sway = r#"script;
666use std::chain::{log_u8, panic};
667use std::chain::assert;
668use std::hash::{keccak256, sha256};
669use a::b::{c, d::{e, f}};
670use a::b::{c, d::{self, f}};
671
672fn main() {
673}
674"#;
675 let result = get_formatted_data(test_sway.into(), OPTIONS, None);
676 assert!(result.is_ok());
677 let (_, formatted_code) = result.unwrap();
678 println!("{}\n{}", formatted_code, expected_sway);
679 assert_eq!(formatted_code, expected_sway);
680 }
681
682 #[test]
683 fn test_logical_not_operator() {
684 let correct_sway_code = r#"script;
685fn main() {
686 let a = true;
687 let b = false;
688
689 if (!a) {
690 } else if !(!a) {
691 } else if !(a == b) {
692 }
693}
694"#;
695
696 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
697 assert!(result.is_ok());
698 let (_, formatted_code) = result.unwrap();
699 assert_eq!(correct_sway_code, formatted_code);
700
701 let sway_code = r#"script;
702fn main() {
703 let a = true;
704 let b = false;
705
706 if ( ! a ) {
707 } else if ! ( !
708 a ) {
709 } else if ! ( a == b) {}
710}
711"#;
712
713 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
714 assert!(result.is_ok());
715 let (_, formatted_code) = result.unwrap();
716 assert_eq!(correct_sway_code, formatted_code);
717 }
718
719 #[test]
720 fn test_string_in_brackets() {
721 let correct_sway_code = r#"script;
722fn main() {
723 let sha_hashed_str = sha256("Fastest Modular Execution Layer!");
724}
725"#;
726
727 let result = get_formatted_data(correct_sway_code.into(), OPTIONS, None);
728 assert!(result.is_ok());
729 let (_, formatted_code) = result.unwrap();
730 assert_eq!(correct_sway_code, formatted_code);
731
732 let sway_code = r#"script;
733fn main() {
734 let sha_hashed_str = sha256( "Fastest Modular Execution Layer!" );
735}
736"#;
737
738 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
739 assert!(result.is_ok());
740 let (_, formatted_code) = result.unwrap();
741 assert_eq!(correct_sway_code, formatted_code);
742 }
743
744 #[test]
745 fn test_op_equal() {
746 let correct_sway_code = r#"script;
747fn main() {
748 let mut a = 1;
749 a += 1;
750 a -= 1;
751 a /= 1;
752 a *= 1;
753 a <<= 1;
754 a >>= 1;
755}
756"#;
757 let sway_code = r#"script;
758fn main() {
759 let mut a = 1;
760 a += 1;
761 a -= 1;
762 a /= 1;
763 a *= 1;
764 a <<= 1;
765 a >>= 1;
766}
767"#;
768 let result = get_formatted_data(sway_code.into(), OPTIONS, None);
769 assert!(result.is_ok());
770 let (_, formatted_code) = result.unwrap();
771 assert_eq!(correct_sway_code, formatted_code);
772 }
773}