1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use std::path::Path;

#[derive(Debug, PartialEq, Clone)]
enum ConstructType {
    Begin,
    If,
    Proc,
    Repeat,
    While,
    End,
    Else,
    Export, // New enum variant for export
}

impl ConstructType {
    fn from_str(s: &str) -> Option<Self> {
        match s {
            "begin" => Some(Self::Begin),
            "if" => Some(Self::If),
            "else" => Some(Self::Else),
            "proc" => Some(Self::Proc),
            "export" => Some(Self::Export),
            "repeat" => Some(Self::Repeat),
            "while" => Some(Self::While),
            "end" => Some(Self::End),
            _ => None,
        }
    }
}

pub fn format_code(code: &str) -> String {
    let mut formatted_code = String::new();
    let mut indentation_level = 0;
    let mut construct_stack = Vec::new();
    let mut last_line_was_empty = false;

    for line in code.lines() {
        let trimmed_line = line.trim();
        let first_word = trimmed_line.split('.').next();

        if !trimmed_line.is_empty() {
            if let Some(word) = first_word {
                if let Some(construct) = ConstructType::from_str(word) {
                    match construct {
                        ConstructType::End => {
                            if let Some(last_construct) = construct_stack.pop() {
                                if last_construct != ConstructType::End && indentation_level > 0 {
                                    indentation_level -= 1;
                                }
                            }
                        }
                        ConstructType::Else => {
                            if let Some(last_construct) = construct_stack.last() {
                                if *last_construct == ConstructType::If && indentation_level > 0 {
                                    indentation_level -= 1;
                                }
                            }
                        }
                        _ => {
                            construct_stack.push(construct.clone());
                        }
                    }

                    formatted_code.push_str(&"    ".repeat(indentation_level)); // Use four spaces for indentation
                    formatted_code.push_str(trimmed_line);
                    formatted_code.push('\n');
                    last_line_was_empty = false;

                    match construct {
                        ConstructType::Begin
                        | ConstructType::If
                        | ConstructType::Proc
                        | ConstructType::Repeat
                        | ConstructType::While
                        | ConstructType::Else
                        | ConstructType::Export => {
                            indentation_level += 1;
                        }
                        _ => {}
                    }
                } else {
                    formatted_code.push_str(&"    ".repeat(indentation_level)); // Use four spaces for indentation
                    formatted_code.push_str(trimmed_line);
                    formatted_code.push('\n');
                    last_line_was_empty = false;
                }
            }
        } else {
            if !last_line_was_empty {
                formatted_code.push('\n'); // Only add a single empty line
                last_line_was_empty = true;
            }
        }
    }

    formatted_code
}

pub fn format_file(file_path: &Path) -> io::Result<()> {
    let file = File::open(&file_path)?;
    let mut input_code = String::new();

    let reader = BufReader::new(file);
    for line in reader.lines() {
        input_code.push_str(&line?);
        input_code.push('\n');
    }

    let formatted_code = format_code(&input_code);

    // Write the formatted code back to the file
    let mut file = File::create(file_path)?;
    file.write_all(formatted_code.as_bytes())?;

    Ok(())
}