Could Rust adding extra indent with format! macro?

I'm writting a program that generate C# code using Rust, For example I have:

namespace Generated
{
    public partial class Generated1
    {
        // things
    }
    public partial class Generated2
    {
        // things
    }
}

Since Generated1 and Generated2 are complex, there is a single function that generate classes like Generated*, which yields the class without indent:

// println!("{}", generating(1)) yields:
public partial class Generated1
{
    // things
}

I wonder is there some technique that allow formatting the generated items with extra indent. Since writting indent in the generating function seems a lot of chaos:

    // with indent
    format!(
r#"{space:width$}public partial class Generated1
{space:width$}{{
{space:width_plus_1$}// things
{space:width$}}}"#, space = "", width = indent_level * 4, width_plus_1 = indent_level * 4);
    // without indent
    format!(
r#"public partial class Generated1
{{
    // things
}}"#, space = "", width = indent_level * 4, width_plus_1 = indent_level * 4);

Is there some technique to format items with extra indent available in Rust?

When I must generate source code, I usually do that from a Vec<String> because it's easier to build.

Then I use something like this to generate the final source from all the parts (which is why it's a collection of Vec<String>). This one isn't really optimized, but that gives you an idea. Another advantages is that it can fix a few issues with strings, like the OS-specific line ending (not done here, except it breaks multiline strings that may include Windows EOLs), trimming, etc. If you're comparing the source code in your unit tests as I do, it's more robust.

pub fn indent_source(parts: Vec<Vec<String>>, indent: usize) -> String {
    let indent_str = String::from_utf8(vec![32; indent]).unwrap();
    let mut source = String::new();
    let mut first = true;
    for part in parts {
        if !first {
            source.push('\n');
        }
        first = false;
        for string in part {
            for line in string.split("\n") {
                let cured_line = line.trim_end();
                if cured_line.len() > 0 {
                    source.push_str(&indent_str);
                }
                source.push_str(cured_line);
                source.push('\n');
            }
        }
    }
    source
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.