summary refs log tree commit diff stats
path: root/rust/format/src/main.rs
blob: 0ec7d3aa5383a705767dcaf87e819b9122cf87df (plain) (blame)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use std::{env::args, fs::File, io::Read};

mod format_layer;

fn main() {
    let mode = args().nth(1).expect("Exists");

    let mut file_to_format = String::new();
    {
        File::open(args().skip(1).last().expect("Exists"))
            .expect("Should work")
            .read_to_string(&mut file_to_format)
            .expect("Failed to read file to format");

        let mut lines: Vec<_> = file_to_format.lines().collect();
        if lines[0] == "// clang-format off" {
            lines.remove(0);
        }
        if lines.last().expect("Exists") == &"// clang-format on" {
            lines.remove(lines.len() - 1);
        }

        file_to_format = lines.join("\n");
    }

    let output = match mode.as_str() {
        "keymap.h" => {
            let mut c_column_max = [0; 14];

            // The first run calculates the correct c_column_max values, and the second one
            // actually formats.
            let out = format_keymap_h(&mut c_column_max, file_to_format);
            format_keymap_h(&mut c_column_max, out)
        }
        "ledmap.h" => {
            let mut c_column_max = [0; 14];

            // We also need two passes here.
            let out = format_ledmap_h(&mut c_column_max, file_to_format);
            format_ledmap_h(&mut c_column_max, out)
        }
        other => unreachable!("Invalid mode: '{other}'"),
    };
    print!("// clang-format off\n{}// clang-format on\n", output);
}

fn format_ledmap_h(c_column_max: &mut [usize; 14], ledmap_h: String) -> String {
    let mut output: String = String::new();
    let mut c_layer: Vec<String> = vec![];

    ledmap_h
        .lines()
        .filter(|line| !line.trim().is_empty())
        .for_each(|line| {
            let line = line.trim();
            let first_char = line.chars().next().unwrap();
            let second_char = line.chars().nth(1).unwrap();

            if line.is_empty() {
                return;
            }

            match (first_char, second_char) {
                ('/', '/') => {
                    // Comment, don't touch.
                    output.push_str(line);
                    output.push('\n');
                }
                ('c', 'o') | ('}', ';') => {
                    // Start or end of the ledmap def, leave it alone
                    output.push_str(line);
                    output.push('\n');
                }
                ('[', '0'..='9') | ('/', '*') => {
                    // Start of a new layer
                    assert!(
                        c_layer.is_empty(),
                        "A new layer cannot start, when the current layer is not empty."
                    );
                    output.push_str(&format!("  {}", line));
                    output.push('\n');
                }
                ('}', ',') => {
                    // End of a layer
                    output.push_str(&format_layer::format_layer(
                        c_layer.join("\n"),
                        c_column_max,
                    ));
                    c_layer.clear();

                    output.push_str(&format!("  {}", line));
                    output.push('\n');
                }
                _ => {
                    // We are in a layer
                    c_layer.push(line.to_owned());
                }
            }
        });
    output
}

fn format_keymap_h(c_column_max: &mut [usize; 14], keymap_h: String) -> String {
    let mut output: String = String::new();
    let mut c_layer: Vec<String> = vec![];
    keymap_h
        .lines()
        .filter(|line| !line.trim().is_empty())
        .for_each(|line| {
            let line = line.trim();
            let first_char = line.chars().take(1).last().unwrap();

            if line.is_empty() {
                return;
            }

            match first_char {
                '/' => {
                    // Comment, don't touch
                    output.push_str(line);
                    output.push('\n');
                }
                'c' | '}' => {
                    // Start or end of the kemap def, leave it alone
                    output.push_str(line);
                    output.push('\n');
                }
                '[' => {
                    // Start of a new layer
                    assert!(
                        c_layer.is_empty(),
                        "A new layer cannot start, when the current layer is not empty."
                    );
                    output.push_str(&format!("  {}", line));
                    output.push('\n');
                }
                ')' => {
                    // End of a layer
                    output.push_str(&format_layer::format_layer(
                        c_layer.join("\n"),
                        c_column_max,
                    ));
                    c_layer.clear();

                    output.push_str(&format!("  {}", line));
                    output.push('\n');
                }
                _ => {
                    // We are in a layer
                    c_layer.push(line.to_owned());
                }
            }
        });
    output
}